blob: 01f9c245a3ef98cf35c6bca357ea8b48e845dc35 [file] [log] [blame]
Blink Reformat4c46d092018-04-07 15:32:371// 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/**
6 * @param {!Object} config
7 * @param {{diffRows: !Array<!Changes.ChangesView.Row>, baselineLines: !Array<string>, currentLines: !Array<string>, mimeType: string}} parserConfig
8 * @return {{
9 * startState: function():!Changes.ChangesHighlighter.DiffState,
10 * token: function(!CodeMirror.StringStream, !Changes.ChangesHighlighter.DiffState):string,
11 * blankLine: function(!Changes.ChangesHighlighter.DiffState):string,
12 * copyState: function(!Changes.ChangesHighlighter.DiffState):Changes.ChangesHighlighter.DiffState
13 * }}
14 */
15Changes.ChangesHighlighter = function(config, parserConfig) {
16 const diffRows = parserConfig.diffRows;
17 const baselineLines = parserConfig.baselineLines;
18 const currentLines = parserConfig.currentLines;
19 const syntaxHighlightMode = CodeMirror.getMode({}, parserConfig.mimeType);
20
21 /**
22 * @param {!Changes.ChangesHighlighter.DiffState} state
23 * @param {number} baselineLineNumber
24 * @param {number} currentLineNumber
25 */
26 function fastForward(state, baselineLineNumber, currentLineNumber) {
27 if (baselineLineNumber > state.baselineLineNumber) {
28 fastForwardSyntaxHighlighter(state.baselineSyntaxState, state.baselineLineNumber, baselineLineNumber, baselineLines);
29 state.baselineLineNumber = baselineLineNumber;
30 }
31 if (currentLineNumber > state.currentLineNumber) {
32 fastForwardSyntaxHighlighter(state.currentSyntaxState, state.currentLineNumber, currentLineNumber, currentLines);
33 state.currentLineNumber = currentLineNumber;
34 }
35 }
36
37 /**
38 * @param {!Object} syntaxState
39 * @param {number} from
40 * @param {number} to
41 * @param {!Array<string>} lines
42 */
43 function fastForwardSyntaxHighlighter(syntaxState, from, to, lines) {
44 let lineNumber = from;
45 while (lineNumber < to && lineNumber < lines.length) {
46 const stream = new CodeMirror.StringStream(lines[lineNumber]);
47 if (stream.eol() && syntaxHighlightMode.blankLine)
48 syntaxHighlightMode.blankLine(syntaxState);
49 while (!stream.eol()) {
50 syntaxHighlightMode.token(stream, syntaxState);
51 stream.start = stream.pos;
52 }
53 lineNumber++;
54 }
55 }
56
57 return {
58 /**
59 * @return {!Changes.ChangesHighlighter.DiffState}
60 */
61 startState: function() {
62 return {
63 rowNumber: 0,
64 diffTokenIndex: 0,
65 currentLineNumber: 0,
66 baselineLineNumber: 0,
67 currentSyntaxState: CodeMirror.startState(syntaxHighlightMode),
68 baselineSyntaxState: CodeMirror.startState(syntaxHighlightMode),
69 syntaxPosition: 0,
70 diffPosition: 0,
71 syntaxStyle: '',
72 diffStyle: ''
73 };
74 },
75
76 /**
77 * @param {!CodeMirror.StringStream} stream
78 * @param {!Changes.ChangesHighlighter.DiffState} state
79 * @return {string}
80 */
81 token: function(stream, state) {
82 const diffRow = diffRows[state.rowNumber];
83 if (!diffRow) {
84 stream.next();
85 return '';
86 }
87 fastForward(state, diffRow.baselineLineNumber - 1, diffRow.currentLineNumber - 1);
88 let classes = '';
89 if (stream.pos === 0)
90 classes += ' line-background-' + diffRow.type + ' line-' + diffRow.type;
91
92 const syntaxHighlighterNeedsRefresh = state.diffPosition >= state.syntaxPosition;
93 if (state.diffPosition <= state.syntaxPosition) {
94 state.diffPosition += diffRow.tokens[state.diffTokenIndex].text.length;
95 state.diffStyle = diffRow.tokens[state.diffTokenIndex].className;
96 state.diffTokenIndex++;
97 }
98
99 if (syntaxHighlighterNeedsRefresh) {
100 if (diffRow.type === Changes.ChangesView.RowType.Deletion || diffRow.type === Changes.ChangesView.RowType.Addition ||
101 diffRow.type === Changes.ChangesView.RowType.Equal) {
102 state.syntaxStyle = syntaxHighlightMode.token(
103 stream, diffRow.type === Changes.ChangesView.RowType.Deletion ? state.baselineSyntaxState : state.currentSyntaxState);
104 state.syntaxPosition = stream.pos;
105 } else {
106 state.syntaxStyle = '';
107 state.syntaxPosition = Infinity;
108 }
109 }
110
111 stream.pos = Math.min(state.syntaxPosition, state.diffPosition);
112 classes += ' ' + state.syntaxStyle;
113 classes += ' ' + state.diffStyle;
114
115 if (stream.eol()) {
116 state.rowNumber++;
117 if (diffRow.type === Changes.ChangesView.RowType.Deletion)
118 state.baselineLineNumber++;
119 else
120 state.currentLineNumber++;
121 state.diffPosition = 0;
122 state.syntaxPosition = 0;
123 state.diffTokenIndex = 0;
124 }
125 return classes;
126 },
127
128 /**
129 * @param {!Changes.ChangesHighlighter.DiffState} state
130 * @return {string}
131 */
132 blankLine: function(state) {
133 const diffRow = diffRows[state.rowNumber];
134 state.rowNumber++;
135 state.syntaxPosition = 0;
136 state.diffPosition = 0;
137 state.diffTokenIndex = 0;
138 if (!diffRow)
139 return '';
140
141 let style = '';
142 if (syntaxHighlightMode.blankLine) {
143 if (diffRow.type === Changes.ChangesView.RowType.Equal || diffRow.type === Changes.ChangesView.RowType.Addition) {
144 style = syntaxHighlightMode.blankLine(state.currentSyntaxState);
145 state.currentLineNumber++;
146 } else if (diffRow.type === Changes.ChangesView.RowType.Deletion) {
147 style = syntaxHighlightMode.blankLine(state.baselineSyntaxState);
148 state.baselineLineNumber++;
149 }
150 }
151 return style + ' line-background-' + diffRow.type + ' line-' + diffRow.type;
152 },
153
154 /**
155 * @param {!Changes.ChangesHighlighter.DiffState} state
156 * @return {!Changes.ChangesHighlighter.DiffState}
157 */
158 copyState: function(state) {
159 const newState = Object.assign({}, state);
160 newState.currentSyntaxState = CodeMirror.copyState(syntaxHighlightMode, state.currentSyntaxState);
161 newState.baselineSyntaxState = CodeMirror.copyState(syntaxHighlightMode, state.baselineSyntaxState);
162 return /** @type {!Changes.ChangesHighlighter.DiffState} */ (newState);
163 }
164 };
165};
166
167/**
168 * @typedef {!{
169 * rowNumber: number,
170 * diffTokenIndex: number,
171 * currentLineNumber: number,
172 * baselineLineNumber: number,
173 * currentSyntaxState: !Object,
174 * baselineSyntaxState: !Object,
175 * syntaxPosition: number,
176 * diffPosition: number,
177 * syntaxStyle: string,
178 * diffStyle: string
179 * }}
180 */
181Changes.ChangesHighlighter.DiffState;
182
183CodeMirror.defineMode('devtools-diff', Changes.ChangesHighlighter);