|  | // Copyright 2017 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | /** | 
|  | * @param {!Object} config | 
|  | * @param {{diffRows: !Array<!Changes.ChangesView.Row>, baselineLines: !Array<string>, currentLines: !Array<string>, mimeType: string}} parserConfig | 
|  | * @return {{ | 
|  | *  startState: function():!Changes.ChangesHighlighter.DiffState, | 
|  | *  token: function(!CodeMirror.StringStream, !Changes.ChangesHighlighter.DiffState):string, | 
|  | *  blankLine: function(!Changes.ChangesHighlighter.DiffState):string, | 
|  | *  copyState: function(!Changes.ChangesHighlighter.DiffState):Changes.ChangesHighlighter.DiffState | 
|  | * }} | 
|  | */ | 
|  | export default function ChangesHighlighter(config, parserConfig) { | 
|  | const diffRows = parserConfig.diffRows; | 
|  | const baselineLines = parserConfig.baselineLines; | 
|  | const currentLines = parserConfig.currentLines; | 
|  | const syntaxHighlightMode = CodeMirror.getMode({}, parserConfig.mimeType); | 
|  |  | 
|  | /** | 
|  | * @param {!Changes.ChangesHighlighter.DiffState} state | 
|  | * @param {number} baselineLineNumber | 
|  | * @param {number} currentLineNumber | 
|  | */ | 
|  | function fastForward(state, baselineLineNumber, currentLineNumber) { | 
|  | if (baselineLineNumber > state.baselineLineNumber) { | 
|  | fastForwardSyntaxHighlighter(state.baselineSyntaxState, state.baselineLineNumber, baselineLineNumber, baselineLines); | 
|  | state.baselineLineNumber = baselineLineNumber; | 
|  | } | 
|  | if (currentLineNumber > state.currentLineNumber) { | 
|  | fastForwardSyntaxHighlighter(state.currentSyntaxState, state.currentLineNumber, currentLineNumber, currentLines); | 
|  | state.currentLineNumber = currentLineNumber; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @param {!Object} syntaxState | 
|  | * @param {number} from | 
|  | * @param {number} to | 
|  | * @param {!Array<string>} lines | 
|  | */ | 
|  | function fastForwardSyntaxHighlighter(syntaxState, from, to, lines) { | 
|  | let lineNumber = from; | 
|  | while (lineNumber < to && lineNumber < lines.length) { | 
|  | const stream = new CodeMirror.StringStream(lines[lineNumber]); | 
|  | if (stream.eol() && syntaxHighlightMode.blankLine) { | 
|  | syntaxHighlightMode.blankLine(syntaxState); | 
|  | } | 
|  | while (!stream.eol()) { | 
|  | syntaxHighlightMode.token(stream, syntaxState); | 
|  | stream.start = stream.pos; | 
|  | } | 
|  | lineNumber++; | 
|  | } | 
|  | } | 
|  |  | 
|  | return { | 
|  | /** | 
|  | * @return {!Changes.ChangesHighlighter.DiffState} | 
|  | */ | 
|  | startState: function() { | 
|  | return { | 
|  | rowNumber: 0, | 
|  | diffTokenIndex: 0, | 
|  | currentLineNumber: 0, | 
|  | baselineLineNumber: 0, | 
|  | currentSyntaxState: CodeMirror.startState(syntaxHighlightMode), | 
|  | baselineSyntaxState: CodeMirror.startState(syntaxHighlightMode), | 
|  | syntaxPosition: 0, | 
|  | diffPosition: 0, | 
|  | syntaxStyle: '', | 
|  | diffStyle: '' | 
|  | }; | 
|  | }, | 
|  |  | 
|  | /** | 
|  | * @param {!CodeMirror.StringStream} stream | 
|  | * @param {!Changes.ChangesHighlighter.DiffState} state | 
|  | * @return {string} | 
|  | */ | 
|  | token: function(stream, state) { | 
|  | const diffRow = diffRows[state.rowNumber]; | 
|  | if (!diffRow) { | 
|  | stream.next(); | 
|  | return ''; | 
|  | } | 
|  | fastForward(state, diffRow.baselineLineNumber - 1, diffRow.currentLineNumber - 1); | 
|  | let classes = ''; | 
|  | if (stream.pos === 0) { | 
|  | classes += ' line-background-' + diffRow.type + ' line-' + diffRow.type; | 
|  | } | 
|  |  | 
|  | const syntaxHighlighterNeedsRefresh = state.diffPosition >= state.syntaxPosition; | 
|  | if (state.diffPosition <= state.syntaxPosition) { | 
|  | state.diffPosition += diffRow.tokens[state.diffTokenIndex].text.length; | 
|  | state.diffStyle = diffRow.tokens[state.diffTokenIndex].className; | 
|  | state.diffTokenIndex++; | 
|  | } | 
|  |  | 
|  | if (syntaxHighlighterNeedsRefresh) { | 
|  | if (diffRow.type === Changes.ChangesView.RowType.Deletion || diffRow.type === Changes.ChangesView.RowType.Addition || | 
|  | diffRow.type === Changes.ChangesView.RowType.Equal) { | 
|  | state.syntaxStyle = syntaxHighlightMode.token( | 
|  | stream, diffRow.type === Changes.ChangesView.RowType.Deletion ? state.baselineSyntaxState : state.currentSyntaxState); | 
|  | state.syntaxPosition = stream.pos; | 
|  | } else { | 
|  | state.syntaxStyle = ''; | 
|  | state.syntaxPosition = Infinity; | 
|  | } | 
|  | } | 
|  |  | 
|  | stream.pos = Math.min(state.syntaxPosition, state.diffPosition); | 
|  | classes += ' ' + state.syntaxStyle; | 
|  | classes += ' ' + state.diffStyle; | 
|  |  | 
|  | if (stream.eol()) { | 
|  | state.rowNumber++; | 
|  | if (diffRow.type === Changes.ChangesView.RowType.Deletion) { | 
|  | state.baselineLineNumber++; | 
|  | } else { | 
|  | state.currentLineNumber++; | 
|  | } | 
|  | state.diffPosition = 0; | 
|  | state.syntaxPosition = 0; | 
|  | state.diffTokenIndex = 0; | 
|  | } | 
|  | return classes; | 
|  | }, | 
|  |  | 
|  | /** | 
|  | * @param {!Changes.ChangesHighlighter.DiffState} state | 
|  | * @return {string} | 
|  | */ | 
|  | blankLine: function(state) { | 
|  | const diffRow = diffRows[state.rowNumber]; | 
|  | state.rowNumber++; | 
|  | state.syntaxPosition = 0; | 
|  | state.diffPosition = 0; | 
|  | state.diffTokenIndex = 0; | 
|  | if (!diffRow) { | 
|  | return ''; | 
|  | } | 
|  |  | 
|  | let style = ''; | 
|  | if (syntaxHighlightMode.blankLine) { | 
|  | if (diffRow.type === Changes.ChangesView.RowType.Equal || diffRow.type === Changes.ChangesView.RowType.Addition) { | 
|  | style = syntaxHighlightMode.blankLine(state.currentSyntaxState); | 
|  | state.currentLineNumber++; | 
|  | } else if (diffRow.type === Changes.ChangesView.RowType.Deletion) { | 
|  | style = syntaxHighlightMode.blankLine(state.baselineSyntaxState); | 
|  | state.baselineLineNumber++; | 
|  | } | 
|  | } | 
|  | return style + ' line-background-' + diffRow.type + ' line-' + diffRow.type; | 
|  | }, | 
|  |  | 
|  | /** | 
|  | * @param {!Changes.ChangesHighlighter.DiffState} state | 
|  | * @return {!Changes.ChangesHighlighter.DiffState} | 
|  | */ | 
|  | copyState: function(state) { | 
|  | const newState = Object.assign({}, state); | 
|  | newState.currentSyntaxState = CodeMirror.copyState(syntaxHighlightMode, state.currentSyntaxState); | 
|  | newState.baselineSyntaxState = CodeMirror.copyState(syntaxHighlightMode, state.baselineSyntaxState); | 
|  | return /** @type {!Changes.ChangesHighlighter.DiffState} */ (newState); | 
|  | } | 
|  | }; | 
|  | } | 
|  |  | 
|  | CodeMirror.defineMode('devtools-diff', ChangesHighlighter); | 
|  |  | 
|  | /* Legacy exported object */ | 
|  | self.Changes = self.Changes || {}; | 
|  |  | 
|  | /* Legacy exported object */ | 
|  | Changes = Changes || {}; | 
|  |  | 
|  | Changes.ChangesHighlighter = ChangesHighlighter; | 
|  |  | 
|  | /** | 
|  | * @typedef {!{ | 
|  | *  rowNumber: number, | 
|  | *  diffTokenIndex: number, | 
|  | *  currentLineNumber: number, | 
|  | *  baselineLineNumber: number, | 
|  | *  currentSyntaxState: !Object, | 
|  | *  baselineSyntaxState: !Object, | 
|  | *  syntaxPosition: number, | 
|  | *  diffPosition: number, | 
|  | *  syntaxStyle: string, | 
|  | *  diffStyle: string | 
|  | * }} | 
|  | */ | 
|  | Changes.ChangesHighlighter.DiffState; |