Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 Changes.ChangesView = class extends UI.VBox { | |
| 6 constructor() { | |
| 7 super(true); | |
| 8 this.registerRequiredCSS('changes/changesView.css'); | |
| 9 var splitWidget = new UI.SplitWidget(true /* vertical */, false /* sidebar o n left */); | |
| 10 var mainWidget = new UI.Widget(); | |
| 11 splitWidget.setMainWidget(mainWidget); | |
| 12 splitWidget.show(this.contentElement); | |
| 13 mainWidget.element.classList.add('diff-area'); | |
| 14 | |
| 15 this._emptyWidget = new UI.EmptyWidget(Common.UIString('No changes')); | |
| 16 this._emptyWidget.show(mainWidget.element); | |
| 17 | |
| 18 this._workspaceDiff = WorkspaceDiff.workspaceDiff(); | |
| 19 this._uiSourceCodeList = new Changes.UISourceCodeList(this._workspaceDiff); | |
| 20 this._uiSourceCodeList.on( | |
| 21 Changes.UISourceCodeList.SelectedUISourceCodeChanged, this._selectedUISo urceCodeChanged, this); | |
| 22 splitWidget.setSidebarWidget(this._uiSourceCodeList); | |
| 23 | |
| 24 /** @type {?Workspace.UISourceCode} */ | |
| 25 this._selectedUISourceCode = null; | |
| 26 | |
| 27 /** @type {!Array<!Changes.ChangesView.Row>} */ | |
| 28 this._rows = []; | |
| 29 | |
| 30 this._maxLineDigits = 1; | |
| 31 | |
| 32 this._editor = new TextEditor.CodeMirrorTextEditor({ | |
| 33 lineNumbers: true, | |
| 34 lineWrapping: false, | |
| 35 maxHighlightLength: Infinity // This is to avoid CodeMirror bailing out o f highlighting big diffs | |
|
lushnikov
2017/03/28 03:32:10
nit: '.' in the end
einbinder
2017/03/28 23:51:04
Done.
| |
| 36 }); | |
| 37 this._editor.setReadOnly(true); | |
| 38 this._editor.show(mainWidget.element); | |
| 39 this._editor.hideWidget(); | |
| 40 | |
| 41 this._editor.element.addEventListener('click', this._click.bind(this), false ); | |
| 42 | |
| 43 this._toolbar = new UI.Toolbar('changes-toolbar', mainWidget.element); | |
| 44 var revertButton = new UI.ToolbarButton(Common.UIString('Revert all changes' ), 'largeicon-undo'); | |
| 45 revertButton.addEventListener(UI.ToolbarButton.Events.Click, this._revert.bi nd(this)); | |
| 46 this._toolbar.appendToolbarItem(revertButton); | |
| 47 this._diffStats = new UI.ToolbarText(''); | |
| 48 this._toolbar.appendToolbarItem(this._diffStats); | |
| 49 this._toolbar.setEnabled(false); | |
| 50 | |
| 51 this._selectedUISourceCodeChanged(); | |
| 52 } | |
| 53 | |
| 54 _selectedUISourceCodeChanged() { | |
| 55 this._revealUISourceCode(this._uiSourceCodeList.selectedUISourceCode()); | |
| 56 } | |
| 57 | |
| 58 _revert() { | |
| 59 var uiSourceCode = this._selectedUISourceCode; | |
| 60 if (!uiSourceCode) | |
| 61 return; | |
| 62 uiSourceCode.requestOriginalContent().then(original => uiSourceCode.addRevis ion(original || '')); | |
| 63 } | |
| 64 | |
| 65 /** | |
| 66 * @param {!Event} event | |
| 67 */ | |
| 68 _click(event) { | |
| 69 var selection = this._editor.selection(); | |
| 70 if (!selection.isEmpty()) | |
| 71 return; | |
| 72 var row = this._rows[selection.startLine]; | |
| 73 Common.Revealer.reveal( | |
| 74 this._selectedUISourceCode.uiLocation(row.currentLineNumber - 1, selecti on.startColumn), false); | |
| 75 event.consume(true); | |
| 76 } | |
| 77 | |
| 78 /** | |
| 79 * @param {?Workspace.UISourceCode} uiSourceCode | |
| 80 */ | |
| 81 _revealUISourceCode(uiSourceCode) { | |
| 82 if (this._selectedUISourceCode === uiSourceCode) | |
| 83 return; | |
| 84 | |
| 85 if (this._selectedUISourceCode) | |
| 86 this._workspaceDiff.unsubscribeFromDiffChange(this._selectedUISourceCode, this._refreshDiff, this); | |
| 87 if (uiSourceCode && this.isShowing()) | |
| 88 this._workspaceDiff.subscribeToDiffChange(uiSourceCode, this._refreshDiff, this); | |
| 89 | |
| 90 this._selectedUISourceCode = uiSourceCode; | |
| 91 this._refreshDiff(); | |
| 92 } | |
| 93 | |
| 94 /** | |
| 95 * @override | |
| 96 */ | |
| 97 wasShown() { | |
| 98 this._refreshDiff(); | |
| 99 } | |
| 100 | |
| 101 _refreshDiff() { | |
| 102 if (!this.isShowing()) | |
| 103 return; | |
| 104 | |
| 105 if (!this._selectedUISourceCode) { | |
| 106 this._renderRows(null); | |
| 107 return; | |
| 108 } | |
| 109 var uiSourceCode = this._selectedUISourceCode; | |
| 110 this._workspaceDiff.requestDiff(uiSourceCode).then(diff => { | |
| 111 if (this._selectedUISourceCode !== uiSourceCode) | |
| 112 return; | |
| 113 this._renderRows(diff); | |
| 114 }); | |
| 115 } | |
| 116 | |
| 117 /** | |
| 118 * @param {?Diff.Diff.DiffArray} diff | |
| 119 */ | |
| 120 _renderRows(diff) { | |
| 121 this._rows = []; | |
| 122 | |
| 123 if (!diff || (diff.length === 1 && diff[0][0] === Diff.Diff.Operation.Equal) ) { | |
| 124 this._diffStats.setText(''); | |
| 125 this._toolbar.setEnabled(false); | |
| 126 this._editor.hideWidget(); | |
| 127 this._emptyWidget.showWidget(); | |
| 128 return; | |
| 129 } | |
| 130 | |
| 131 var insertions = 0; | |
| 132 var deletions = 0; | |
| 133 var currentLineNumber = 0; | |
| 134 var baselineLineNumber = 0; | |
| 135 var paddingLines = 3; | |
| 136 | |
| 137 for (var i = 0; i < diff.length; ++i) { | |
| 138 var token = diff[i]; | |
| 139 switch (token[0]) { | |
| 140 case Diff.Diff.Operation.Equal: | |
| 141 this._rows.pushAll(createEqualRows(token[1], i === 0, i === diff.lengt h - 1)); | |
| 142 break; | |
| 143 case Diff.Diff.Operation.Insert: | |
| 144 for (var line of token[1]) | |
| 145 this._rows.push(createRow(line, Changes.ChangesView.RowType.Addition )); | |
| 146 insertions += token[1].length; | |
| 147 break; | |
| 148 case Diff.Diff.Operation.Delete: | |
| 149 deletions += token[1].length; | |
| 150 if (diff[i + 1] && diff[i + 1][0] === Diff.Diff.Operation.Insert) { | |
| 151 i++; | |
| 152 this._rows.pushAll(createModifyRows(token[1].join('\n'), diff[i][1]. join('\n'))); | |
| 153 insertions += diff[i][1].length; | |
| 154 } else { | |
| 155 for (var line of token[1]) | |
| 156 this._rows.push(createRow(line, Changes.ChangesView.RowType.Deleti on)); | |
| 157 } | |
| 158 break; | |
| 159 } | |
| 160 } | |
| 161 | |
| 162 this._maxLineDigits = Math.ceil(Math.log10(Math.max(currentLineNumber, basel ineLineNumber))); | |
| 163 | |
| 164 this._editor.operation(() => { | |
| 165 this._editor.setHighlightMode({name: 'devtools-diff', rows: this._rows}); | |
| 166 this._editor.setText(this._rows.map(row => row.content.map(t => t.text).jo in('')).join('\n')); | |
| 167 this._editor.setLineNumberFormatter(this._lineFormatter.bind(this)); | |
| 168 }); | |
| 169 | |
| 170 this._diffStats.setText(Common.UIString( | |
| 171 '%d insertion%s (+), %d deletion%s (-)', insertions, insertions !== 1 ? 's' : '', deletions, | |
| 172 deletions !== 1 ? 's' : '')); | |
| 173 this._toolbar.setEnabled(true); | |
| 174 this._emptyWidget.hideWidget(); | |
| 175 this._editor.showWidget(); | |
| 176 | |
| 177 /** | |
| 178 * @param {!Array<string>} lines | |
| 179 * @param {boolean} atStart | |
| 180 * @param {boolean} atEnd | |
| 181 * @return {!Array<!Changes.ChangesView.Row>}} | |
| 182 */ | |
| 183 function createEqualRows(lines, atStart, atEnd) { | |
| 184 var equalRows = []; | |
| 185 if (!atStart) { | |
| 186 for (var i = 0; i < paddingLines && i < lines.length; i++) | |
| 187 equalRows.push(createRow(lines[i], Changes.ChangesView.RowType.Equal)) ; | |
| 188 if (lines.length > paddingLines * 2 + 1 && !atEnd) { | |
| 189 equalRows.push(createRow( | |
| 190 Common.UIString('( \u2026 Skipping ') + (lines.length - paddingLin es * 2) + | |
| 191 Common.UIString(' matching lines \u2026 )'), | |
| 192 Changes.ChangesView.RowType.Spacer)); | |
| 193 } | |
| 194 } | |
| 195 if (!atEnd) { | |
| 196 var start = Math.max(lines.length - paddingLines - 1, atStart ? 0 : padd ingLines); | |
| 197 var skip = lines.length - paddingLines - 1; | |
| 198 if (!atStart) | |
| 199 skip -= paddingLines; | |
| 200 if (skip > 0) { | |
| 201 baselineLineNumber += skip; | |
| 202 currentLineNumber += skip; | |
| 203 } | |
| 204 | |
| 205 for (var i = start; i < lines.length; i++) | |
| 206 equalRows.push(createRow(lines[i], Changes.ChangesView.RowType.Equal)) ; | |
| 207 } | |
| 208 return equalRows; | |
| 209 } | |
| 210 | |
| 211 /** | |
| 212 * @param {string} before | |
| 213 * @param {string} after | |
| 214 * @return {!Array<!Changes.ChangesView.Row>}} | |
| 215 */ | |
| 216 function createModifyRows(before, after) { | |
| 217 var internalDiff = Diff.Diff.charDiff(before, after, true /* cleanup diff */); | |
| 218 var deletionRows = [createRow('', Changes.ChangesView.RowType.Deletion)]; | |
| 219 var insertionRows = [createRow('', Changes.ChangesView.RowType.Addition)]; | |
| 220 | |
| 221 for (var token of internalDiff) { | |
| 222 var text = token[1]; | |
| 223 var type = token[0]; | |
| 224 var className = type === Diff.Diff.Operation.Equal ? '' : 'inner-diff'; | |
| 225 var lines = text.split('\n'); | |
| 226 for (var i = 0; i < lines.length; i++) { | |
| 227 if (i > 0 && type !== Diff.Diff.Operation.Insert) | |
| 228 deletionRows.push(createRow('', Changes.ChangesView.RowType.Deletion )); | |
| 229 if (i > 0 && type !== Diff.Diff.Operation.Delete) | |
| 230 insertionRows.push(createRow('', Changes.ChangesView.RowType.Additio n)); | |
| 231 if (!lines[i]) | |
| 232 continue; | |
| 233 if (type !== Diff.Diff.Operation.Insert) | |
| 234 deletionRows[deletionRows.length - 1].content.push({text: lines[i], className: className}); | |
| 235 if (type !== Diff.Diff.Operation.Delete) | |
| 236 insertionRows[insertionRows.length - 1].content.push({text: lines[i] , className: className}); | |
| 237 } | |
| 238 } | |
| 239 return deletionRows.concat(insertionRows); | |
| 240 } | |
| 241 | |
| 242 /** | |
| 243 * @param {string} text | |
| 244 * @param {!Changes.ChangesView.RowType} type | |
| 245 * @return {!Changes.ChangesView.Row} | |
| 246 */ | |
| 247 function createRow(text, type) { | |
| 248 if (type === Changes.ChangesView.RowType.Addition) | |
| 249 currentLineNumber++; | |
| 250 if (type === Changes.ChangesView.RowType.Deletion) | |
| 251 baselineLineNumber++; | |
| 252 if (type === Changes.ChangesView.RowType.Equal) { | |
| 253 baselineLineNumber++; | |
| 254 currentLineNumber++; | |
| 255 } | |
| 256 | |
| 257 return {baselineLineNumber, currentLineNumber, content: text ? [{text, cla ssName: 'inner-diff'}] : [], type}; | |
| 258 } | |
| 259 } | |
| 260 | |
| 261 /** | |
| 262 * @param {number} lineNumber | |
| 263 * @return {string} | |
| 264 */ | |
| 265 _lineFormatter(lineNumber) { | |
| 266 var row = this._rows[lineNumber - 1]; | |
| 267 var showBaseNumber = row.type === Changes.ChangesView.RowType.Deletion; | |
| 268 var showCurrentNumber = row.type === Changes.ChangesView.RowType.Addition; | |
| 269 if (row.type === Changes.ChangesView.RowType.Equal) { | |
| 270 showBaseNumber = true; | |
| 271 showCurrentNumber = true; | |
| 272 } | |
| 273 var base = showBaseNumber ? numberToStringWithSpacesPadding(row.baselineLine Number, this._maxLineDigits) : | |
| 274 spacesPadding(this._maxLineDigits); | |
| 275 var current = showCurrentNumber ? numberToStringWithSpacesPadding(row.curren tLineNumber, this._maxLineDigits) : | |
| 276 spacesPadding(this._maxLineDigits); | |
| 277 return base + spacesPadding(1) + current; | |
| 278 } | |
| 279 }; | |
| 280 | |
| 281 /** | |
| 282 * @typedef {!{ | |
| 283 * baselineLineNumber: number, | |
| 284 * currentLineNumber: number, | |
| 285 * content: !Array<!{text: string, className: string}>, | |
| 286 * type: !Changes.ChangesView.RowType | |
| 287 * }} | |
| 288 */ | |
| 289 Changes.ChangesView.Row; | |
| 290 | |
| 291 /** @enum {string} */ | |
| 292 Changes.ChangesView.RowType = { | |
| 293 Deletion: 'deletion', | |
| 294 Addition: 'addition', | |
| 295 Equal: 'equal', | |
| 296 Spacer: 'spacer' | |
| 297 }; | |
| OLD | NEW |