| 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 Changes.ChangesView.SharedInstance = this; |
| 9 this.registerRequiredCSS('changes/changesView.css'); |
| 10 var splitWidget = new UI.SplitWidget(true, false); |
| 11 var mainWidget = new UI.Widget(); |
| 12 splitWidget.setMainWidget(mainWidget); |
| 13 |
| 14 /** @type {?Workspace.UISourceCode} */ |
| 15 this._uiSourceCode = null; |
| 16 |
| 17 /** @type {!Array<!Changes.ChangesView.Row>} */ |
| 18 this._rows = []; |
| 19 |
| 20 this._maxLineDigits = 1; |
| 21 |
| 22 var code = mainWidget.element.createChild('div', 'code'); |
| 23 this._editor = |
| 24 new TextEditor.CodeMirrorTextEditor({lineNumbers: true, lineWrapping: fa
lse, maxHighlightLength: Infinity}); |
| 25 this._editor.setReadOnly(true); |
| 26 this._editor.show(code); |
| 27 this._editor.hideWidget(); |
| 28 this._editor.setLineNumberFormatter(() => ''); |
| 29 |
| 30 this._emptyWidget = new UI.EmptyWidget(Common.UIString('No changes')); |
| 31 this._emptyWidget.show(code); |
| 32 |
| 33 this._editor.element.addEventListener('mouseup', e => { |
| 34 var selection = this._editor.selection(); |
| 35 if (!selection.isEmpty()) |
| 36 return; |
| 37 var row = this._rows[selection.startLine]; |
| 38 if (!row) |
| 39 return; |
| 40 |
| 41 setTimeout( |
| 42 () => Common.Revealer.reveal(this._uiSourceCode.uiLocation(row.current
- 1, selection.startColumn), false)); |
| 43 }, false); |
| 44 |
| 45 this._toolbar = new UI.Toolbar('changes-toolbar', mainWidget.element); |
| 46 var revertButton = new UI.ToolbarButton(Common.UIString('Revert all changes'
), 'largeicon-undo'); |
| 47 revertButton.addEventListener(UI.ToolbarButton.Events.Click, this._revert.bi
nd(this)); |
| 48 this._toolbar.appendToolbarItem(revertButton); |
| 49 this._diffStats = new UI.ToolbarText(''); |
| 50 this._toolbar.appendToolbarItem(this._diffStats); |
| 51 this._toolbar.setEnabled(false); |
| 52 |
| 53 this._navigator = new Changes.ChangesNavigator(); |
| 54 splitWidget.setSidebarWidget(this._navigator); |
| 55 splitWidget.show(this.contentElement); |
| 56 |
| 57 this._workspaceDiff = WorkspaceDiff.workspaceDiff(); |
| 58 Workspace.workspace.addEventListener( |
| 59 Workspace.Workspace.Events.WorkingCopyCommittedByUser, this._refreshUISo
urceCode, this); |
| 60 Workspace.workspace.addEventListener( |
| 61 Workspace.Workspace.Events.WorkingCopyChanged, this._refreshUISourceCode
, this); |
| 62 } |
| 63 |
| 64 /** |
| 65 * @param {!Workspace.UISourceCode} uiSourceCode |
| 66 */ |
| 67 static showChanges(uiSourceCode) { |
| 68 UI.viewManager.showView('changes.changes'); |
| 69 var changesView = |
| 70 /** @type {!Changes.ChangesView} */ (self.runtime.sharedInstance(Changes
.ChangesView)); |
| 71 changesView._revealUISourceCode(uiSourceCode); |
| 72 } |
| 73 |
| 74 _revert() { |
| 75 var uiSourceCode = this._uiSourceCode; |
| 76 if (!uiSourceCode) |
| 77 return; |
| 78 uiSourceCode.requestOriginalContent().then(original => uiSourceCode.addRevis
ion(original || '')); |
| 79 } |
| 80 |
| 81 /** |
| 82 * @param {!Common.Event} event |
| 83 */ |
| 84 _refreshUISourceCode(event) { |
| 85 var uiSourceCode = /** @type !Workspace.UISourceCode */ (event.data.uiSource
Code); |
| 86 this._navigator.refreshUISourceCode(uiSourceCode); |
| 87 } |
| 88 |
| 89 _refreshEmpty(empty) { |
| 90 if (empty) { |
| 91 this._diffStats.setText(''); |
| 92 this._toolbar.setEnabled(false); |
| 93 this._editor.hideWidget(); |
| 94 this._emptyWidget.showWidget(); |
| 95 } else { |
| 96 this._toolbar.setEnabled(true); |
| 97 this._emptyWidget.hideWidget(); |
| 98 this._editor.showWidget(); |
| 99 } |
| 100 } |
| 101 |
| 102 /** |
| 103 * @param {?Workspace.UISourceCode} uiSourceCode |
| 104 * @param {boolean=} refresh |
| 105 */ |
| 106 _revealUISourceCode(uiSourceCode, refresh) { |
| 107 if (this._uiSourceCode === uiSourceCode && !refresh) |
| 108 return; |
| 109 |
| 110 if (this._uiSourceCode) |
| 111 this._workspaceDiff.unsubscribeFromDiffChange(this._uiSourceCode, this._re
freshDiff, this); |
| 112 |
| 113 this._diffStats.setText(''); |
| 114 this._editor.setText(''); |
| 115 this._uiSourceCode = uiSourceCode; |
| 116 this._rows = []; |
| 117 this._refreshEmpty(!uiSourceCode); |
| 118 |
| 119 if (!uiSourceCode || !this.isShowing()) |
| 120 return; |
| 121 |
| 122 this._workspaceDiff.subscribeToDiffChange(uiSourceCode, this._refreshDiff, t
his); |
| 123 this._navigator.revealUISourceCode(uiSourceCode, true); |
| 124 this._refreshDiff(); |
| 125 } |
| 126 |
| 127 /** |
| 128 * @override |
| 129 */ |
| 130 wasShown() { |
| 131 this._revealUISourceCode(this._uiSourceCode, true); |
| 132 } |
| 133 |
| 134 /** |
| 135 * @override |
| 136 */ |
| 137 willHide() { |
| 138 if (this._uiSourceCode) |
| 139 this._workspaceDiff.unsubscribeFromDiffChange(this._uiSourceCode, this._re
freshDiff, this); |
| 140 } |
| 141 |
| 142 _refreshDiff() { |
| 143 if (!this._uiSourceCode) |
| 144 return; |
| 145 var uiSourceCode = this._uiSourceCode; |
| 146 this._workspaceDiff.requestDiff(uiSourceCode).then(diff => { |
| 147 if (this._uiSourceCode !== uiSourceCode) |
| 148 return; |
| 149 this._renderRows(diff); |
| 150 }); |
| 151 } |
| 152 |
| 153 /** |
| 154 * @param {?Diff.Diff.DiffArray} diff |
| 155 */ |
| 156 _renderRows(diff) { |
| 157 if (!diff || (diff.length === 1 && diff[0][0] === Diff.Diff.Operation.Equal)
) { |
| 158 this._refreshEmpty(true); |
| 159 return; |
| 160 } |
| 161 this._refreshEmpty(false); |
| 162 |
| 163 var insertions = 0; |
| 164 var deletions = 0; |
| 165 var currentLineNumber = 0; |
| 166 var baselineLineNumber = 0; |
| 167 var paddingLines = 3; |
| 168 var originalLines = []; |
| 169 var currentLines = []; |
| 170 this._rows = []; |
| 171 |
| 172 for (var i = 0; i < diff.length; ++i) { |
| 173 var token = diff[i]; |
| 174 switch (token[0]) { |
| 175 case Diff.Diff.Operation.Equal: |
| 176 this._rows.pushAll(createEqualRows(token[1], i === 0, i === diff.lengt
h - 1)); |
| 177 originalLines.pushAll(token[1]); |
| 178 currentLines.pushAll(token[1]); |
| 179 break; |
| 180 case Diff.Diff.Operation.Insert: |
| 181 for (var line of token[1]) |
| 182 this._rows.push(createRow(line, 'addition')); |
| 183 currentLines.pushAll(token[1]); |
| 184 break; |
| 185 case Diff.Diff.Operation.Delete: |
| 186 originalLines.pushAll(token[1]); |
| 187 if (diff[i + 1] && diff[i + 1][0] === Diff.Diff.Operation.Insert) { |
| 188 this._rows.pushAll(createModifyRows(token[1].join('\n'), diff[i + 1]
[1].join('\n'))); |
| 189 i++; |
| 190 currentLines.pushAll(diff[i + 1][1]); |
| 191 } else { |
| 192 for (var line of token[1]) |
| 193 this._rows.push(createRow(line, 'deletion')); |
| 194 } |
| 195 break; |
| 196 } |
| 197 } |
| 198 |
| 199 this._maxLineDigits = Math.max(Math.ceil(Math.log10(Math.max(currentLineNumb
er, baselineLineNumber))), 1); |
| 200 |
| 201 this._editor.operation(() => { |
| 202 this._editor.setHighlightMode({ |
| 203 name: 'devtools-diff', |
| 204 rows: this._rows, |
| 205 mimeType: |
| 206 Bindings.NetworkProject.uiSourceCodeMimeType(/** @type {!Workspace.U
ISourceCode} */ (this._uiSourceCode)), |
| 207 baselineLines: originalLines, |
| 208 currentLines: currentLines |
| 209 }); |
| 210 this._editor.setText(this._rows.map(row => row.content.map(t => t.text).jo
in('')).join('\n')); |
| 211 this._editor.setLineNumberFormatter(this._lineFormatter.bind(this)); |
| 212 }); |
| 213 |
| 214 this._diffStats.setText(Common.UIString( |
| 215 '%d insertion%s (+), %d deletion%s (-)', insertions, insertions > 1 ? 's
' : '', deletions, |
| 216 deletions > 1 ? 's' : '')); |
| 217 |
| 218 /** |
| 219 * @param {!Array<string>} lines |
| 220 * @param {boolean} atStart |
| 221 * @param {boolean} atEnd |
| 222 * @return {!Array<!Changes.ChangesView.Row>}} |
| 223 */ |
| 224 function createEqualRows(lines, atStart, atEnd) { |
| 225 var equalRows = []; |
| 226 if (!atStart) { |
| 227 for (var i = 0; i < paddingLines && i < lines.length; i++) |
| 228 equalRows.push(createRow(lines[i], 'equal')); |
| 229 if (lines.length > paddingLines * 2 + 1 && !atEnd) { |
| 230 equalRows.push(createRow( |
| 231 Common.UIString('( \u2026 Skipping ') + (lines.length - paddingLin
es * 2) + |
| 232 Common.UIString(' matching lines \u2026 )'), |
| 233 'spacer')); |
| 234 } |
| 235 } |
| 236 if (!atEnd) { |
| 237 var start = Math.max(lines.length - paddingLines - 1, atStart ? 0 : padd
ingLines); |
| 238 var skip = lines.length - paddingLines - 1; |
| 239 if (!atStart) |
| 240 skip -= paddingLines; |
| 241 if (skip > 0) { |
| 242 baselineLineNumber += skip; |
| 243 currentLineNumber += skip; |
| 244 } |
| 245 |
| 246 for (var i = start; i < lines.length; i++) |
| 247 equalRows.push(createRow(lines[i], 'equal')); |
| 248 } |
| 249 return equalRows; |
| 250 } |
| 251 |
| 252 /** |
| 253 * @param {string} before |
| 254 * @param {string} after |
| 255 * @return {!Array<!Changes.ChangesView.Row>}} |
| 256 */ |
| 257 function createModifyRows(before, after) { |
| 258 var internalDiff = Diff.Diff.charDiff(before, after, true); |
| 259 var deletionRows = [createRow('', 'deletion')]; |
| 260 var insertionRows = [createRow('', 'addition')]; |
| 261 |
| 262 for (var token of internalDiff) { |
| 263 var text = token[1]; |
| 264 var type = token[0]; |
| 265 var className = type === Diff.Diff.Operation.Equal ? '' : 'double'; |
| 266 var first = true; |
| 267 for (var line of text.split('\n')) { |
| 268 if (first) { |
| 269 first = false; |
| 270 } else { |
| 271 if (type !== Diff.Diff.Operation.Insert) |
| 272 deletionRows.push(createRow('', 'deletion')); |
| 273 if (type !== Diff.Diff.Operation.Delete) |
| 274 insertionRows.push(createRow('', 'addition')); |
| 275 } |
| 276 if (line) { |
| 277 if (type !== Diff.Diff.Operation.Insert) |
| 278 deletionRows[deletionRows.length - 1].content.push({text: line, cl
assName: className}); |
| 279 |
| 280 if (type !== Diff.Diff.Operation.Delete) |
| 281 insertionRows[insertionRows.length - 1].content.push({text: line,
className: className}); |
| 282 } |
| 283 } |
| 284 } |
| 285 return deletionRows.concat(insertionRows); |
| 286 } |
| 287 |
| 288 /** |
| 289 * @param {string} text |
| 290 * @param {string} className |
| 291 * @return {!Changes.ChangesView.Row} |
| 292 */ |
| 293 function createRow(text, className) { |
| 294 if (className === 'addition') { |
| 295 currentLineNumber++; |
| 296 insertions++; |
| 297 } |
| 298 if (className === 'deletion') { |
| 299 baselineLineNumber++; |
| 300 deletions++; |
| 301 } |
| 302 if (className === 'equal') { |
| 303 baselineLineNumber++; |
| 304 currentLineNumber++; |
| 305 } |
| 306 return { |
| 307 base: baselineLineNumber, |
| 308 current: currentLineNumber, |
| 309 content: text ? [{text: text, className: 'double'}] : [], |
| 310 className: className, |
| 311 loc: currentLineNumber |
| 312 }; |
| 313 } |
| 314 } |
| 315 |
| 316 /** |
| 317 * @param {number} lineNumber |
| 318 * @return {string} |
| 319 */ |
| 320 _lineFormatter(lineNumber) { |
| 321 var row = this._rows[lineNumber - 1]; |
| 322 if (!row) |
| 323 return spacesPadding(this._maxLineDigits * 2 + 1); |
| 324 var showBaseNumber = row.className === 'deletion'; |
| 325 var showCurrentNumber = row.className === 'addition'; |
| 326 if (row.className === 'equal') { |
| 327 showBaseNumber = true; |
| 328 showCurrentNumber = true; |
| 329 } |
| 330 var base = showBaseNumber ? numberToStringWithSpacesPadding(row.base, this._
maxLineDigits) : |
| 331 spacesPadding(this._maxLineDigits); |
| 332 var current = showCurrentNumber ? numberToStringWithSpacesPadding(row.curren
t, this._maxLineDigits) : |
| 333 spacesPadding(this._maxLineDigits); |
| 334 return base + spacesPadding(1) + current; |
| 335 } |
| 336 |
| 337 /** |
| 338 * @param {number} baselineLineNumber |
| 339 * @param {number} currentLineNumber |
| 340 * @param {string} text |
| 341 * @param {string=} className |
| 342 * @return {!Element} |
| 343 */ |
| 344 _createRow(baselineLineNumber, currentLineNumber, text, className) { |
| 345 var element = createElementWithClass('div', className); |
| 346 element.createChild('span', 'number').textContent = baselineLineNumber ? |
| 347 numberToStringWithSpacesPadding(baselineLineNumber, this._maxLineDigits)
: |
| 348 spacesPadding(this._maxLineDigits); |
| 349 element.createChild('span', 'number').textContent = currentLineNumber ? |
| 350 numberToStringWithSpacesPadding(currentLineNumber, this._maxLineDigits)
: |
| 351 spacesPadding(this._maxLineDigits); |
| 352 element.createChild('span', 'double').textContent = text; |
| 353 return element; |
| 354 } |
| 355 }; |
| 356 |
| 357 /** @typedef {!{base: number, current: number, content: !Array<!{text: string, c
lassName: string}>, className: string, loc: number}} */ |
| 358 Changes.ChangesView.Row; |
| 359 |
| 360 Changes.ChangesNavigator = class extends Sources.NavigatorView { |
| 361 constructor() { |
| 362 super(); |
| 363 this.dontGroup(); |
| 364 this.element.classList.add('changes-navigator'); |
| 365 } |
| 366 |
| 367 /** |
| 368 * @override |
| 369 * @param {!Workspace.UISourceCode} uiSourceCode |
| 370 * @return {boolean} |
| 371 */ |
| 372 accept(uiSourceCode) { |
| 373 if (uiSourceCode.project().type() !== Workspace.projectTypes.Network) |
| 374 return false; |
| 375 |
| 376 if (uiSourceCode.isDirty()) |
| 377 return true; |
| 378 |
| 379 if (!uiSourceCode.mightHaveChanges) |
| 380 return false; |
| 381 |
| 382 uiSourceCode.hasChanges().then(hasChanges => { |
| 383 if (!hasChanges) |
| 384 this.refreshUISourceCode(uiSourceCode); |
| 385 }); |
| 386 return true; |
| 387 } |
| 388 |
| 389 /** |
| 390 * @override |
| 391 * @param {?Workspace.UISourceCode} uiSourceCode |
| 392 * @param {boolean} focusSource |
| 393 */ |
| 394 revealSource(uiSourceCode, focusSource) { |
| 395 Changes.ChangesView.SharedInstance._revealUISourceCode(uiSourceCode); |
| 396 if (focusSource) |
| 397 Changes.ChangesView.SharedInstance._editor.focus(); |
| 398 } |
| 399 |
| 400 /** |
| 401 * @override |
| 402 * @param {!Workspace.UISourceCode} uiSourceCode |
| 403 */ |
| 404 uiSourceCodeAdded(uiSourceCode) { |
| 405 if (!Changes.ChangesView.SharedInstance._uiSourceCode) |
| 406 this.revealSource(uiSourceCode, false); |
| 407 } |
| 408 |
| 409 /** |
| 410 * @override |
| 411 * @param {!Workspace.UISourceCode} uiSourceCode |
| 412 */ |
| 413 uiSourceCodeRemoved(uiSourceCode) { |
| 414 if (Changes.ChangesView.SharedInstance._uiSourceCode !== uiSourceCode) |
| 415 return; |
| 416 this.revealSource(this.anyUISourceCode(), false); |
| 417 } |
| 418 }; |
| 419 |
| 420 Changes.UISourceCodeChange = class { |
| 421 /** |
| 422 * @param {!Workspace.UISourceCode} uiSourceCode |
| 423 */ |
| 424 constructor(uiSourceCode) { |
| 425 this.uiSourceCode = uiSourceCode; |
| 426 } |
| 427 }; |
| 428 |
| 429 /** |
| 430 * @implements {Common.Revealer} |
| 431 */ |
| 432 Changes.UISourceCodeChangeRevealer = class { |
| 433 /** |
| 434 * @override |
| 435 * @param {!Object} uiSourceCodeChange |
| 436 * @param {boolean=} omitFocus |
| 437 * @return {!Promise} |
| 438 */ |
| 439 reveal(uiSourceCodeChange, omitFocus) { |
| 440 if (!(uiSourceCodeChange instanceof Changes.UISourceCodeChange)) |
| 441 return Promise.reject(new Error('Changes.UISourceCodeChange')); |
| 442 Changes.ChangesView.showChanges(uiSourceCodeChange.uiSourceCode); |
| 443 return Promise.resolve(); |
| 444 } |
| 445 }; |
| 446 |
| 447 /** @typedef {!{lineNumber: number, index: number}} */ |
| 448 Changes.ChangesView.DiffState; |
| 449 |
| 450 CodeMirror.defineMode('devtools-diff', function(config, parserConfig) { |
| 451 var rows = parserConfig.rows || []; |
| 452 var baselineLines = parserConfig.baselineLines; |
| 453 var currentLines = parserConfig.currentLines; |
| 454 var innerMode = CodeMirror.getMode({indentUnit: 2}, parserConfig.mimeType); |
| 455 |
| 456 function fastForward(state, baselineLineNumber, currentLineNumber) { |
| 457 if (baselineLineNumber > state.baselineLineNumber) { |
| 458 fastForwardState(state.baselineState, state.baselineLineNumber, baselineLi
neNumber, baselineLines); |
| 459 state.baselineLineNumber = baselineLineNumber; |
| 460 } |
| 461 if (currentLineNumber > state.currentLineNumber) { |
| 462 fastForwardState(state.currentState, state.currentLineNumber, currentLineN
umber, currentLines); |
| 463 state.currentLineNumber = currentLineNumber; |
| 464 } |
| 465 } |
| 466 |
| 467 function fastForwardState(state, from, to, lines) { |
| 468 var lineNumber = from; |
| 469 while (lineNumber < to && lineNumber < lines.length) { |
| 470 var stream = new CodeMirror.StringStream(lines[lineNumber]); |
| 471 while (!stream.eol()) { |
| 472 innerMode.token(stream, state); |
| 473 stream.start = stream.pos; |
| 474 } |
| 475 lineNumber++; |
| 476 } |
| 477 } |
| 478 |
| 479 return { |
| 480 /** |
| 481 * @return {!Changes.ChangesView.DiffState} |
| 482 */ |
| 483 startState: function() { |
| 484 return { |
| 485 lineNumber: 0, |
| 486 index: 0, |
| 487 currentLineNumber: 0, |
| 488 baselineLineNumber: 0, |
| 489 currentState: CodeMirror.startState(innerMode), |
| 490 baselineState: CodeMirror.startState(innerMode), |
| 491 mismatch: 0 |
| 492 }; |
| 493 }, |
| 494 |
| 495 /** |
| 496 * @param {!{next: function()}} stream |
| 497 * @param {!Changes.ChangesView.DiffState} state |
| 498 * @return {string} |
| 499 */ |
| 500 token: function(stream, state) { |
| 501 var row = rows[state.lineNumber]; |
| 502 if (!row) { |
| 503 stream.next(); |
| 504 return ''; |
| 505 } |
| 506 fastForward(state, row.base - 1, row.current - 1); |
| 507 var classes = ''; |
| 508 if (state.index === 0) |
| 509 classes += ' line-background-' + row.className + ' line-' + row.classNam
e; |
| 510 var chars = row.content[state.index].text.length; |
| 511 if (state.mismatch > 0) |
| 512 chars = state.mismatch; |
| 513 var pos = stream.pos; |
| 514 var innerStyle = state.lastInnerStyle; |
| 515 var innerPos = pos - state.mismatch; |
| 516 if (state.mismatch >= 0) { |
| 517 if (row.className === 'deletion' || row.className === 'addition' || row.
className === 'equal') { |
| 518 innerStyle = innerMode.token(stream, row.className === 'deletion' ? st
ate.baselineState : state.currentState); |
| 519 innerPos = stream.pos; |
| 520 } else { |
| 521 innerStyle = ''; |
| 522 innerPos = pos + chars; |
| 523 } |
| 524 } |
| 525 stream.pos = Math.min(innerPos, pos + chars); |
| 526 if (innerStyle) |
| 527 classes += ' ' + innerStyle; |
| 528 classes += ' ' + row.content[state.index].className; |
| 529 state.mismatch = pos + chars - innerPos; |
| 530 if (state.mismatch <= 0) { |
| 531 state.index++; |
| 532 state.lastInnerStyle = innerStyle; |
| 533 } |
| 534 if (state.index >= row.content.length) { |
| 535 state.lineNumber++; |
| 536 if (row.className === 'deletion') |
| 537 state.baselineLineNumber++; |
| 538 else |
| 539 state.currentLineNumber++; |
| 540 state.index = 0; |
| 541 } |
| 542 return classes; |
| 543 }, |
| 544 |
| 545 /** |
| 546 * @param {!Changes.ChangesView.DiffState} state |
| 547 * @return {string} |
| 548 */ |
| 549 blankLine: function(state) { |
| 550 var row = rows[state.lineNumber]; |
| 551 state.lineNumber++; |
| 552 state.mismatch = 0; |
| 553 state.index = 0; |
| 554 if (!row) |
| 555 return ''; |
| 556 if (row.className === 'deletion') |
| 557 state.baselineLineNumber++; |
| 558 else |
| 559 state.currentLineNumber++; |
| 560 var style = ''; |
| 561 if (innerMode.blankLine) |
| 562 style = innerMode.blankLine(row.className === 'deletion' ? state.baselin
eState : state.currentState); |
| 563 return style + ' line-background-' + row.className + ' line-' + row.classN
ame; |
| 564 }, |
| 565 |
| 566 /** |
| 567 * @param {!Changes.ChangesView.DiffState} state |
| 568 * @return {!Changes.ChangesView.DiffState} |
| 569 */ |
| 570 copyState: function(state) { |
| 571 var newState = /** @type {!Changes.ChangesView.DiffState} */ ({}); |
| 572 for (var i in state) |
| 573 newState[i] = state[i]; |
| 574 newState.currentState = CodeMirror.copyState(innerMode, state.currentState
); |
| 575 newState.baselineState = CodeMirror.copyState(innerMode, state.baselineSta
te); |
| 576 return newState; |
| 577 } |
| 578 }; |
| 579 }); |
| OLD | NEW |