reslop 0.2.4 → 0.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/CHANGELOG.md +25 -1
  2. package/LICENSE +1 -1
  3. package/README.md +12 -13
  4. package/bin/reslop.js +3 -8
  5. package/lib/ansi.js +32 -19
  6. package/lib/capabilities.js +8 -12
  7. package/lib/cli.js +40 -74
  8. package/lib/clipboard.js +48 -18
  9. package/lib/dashboard/git.js +128 -0
  10. package/lib/dashboard/model.js +332 -0
  11. package/lib/dashboard/npm.js +193 -0
  12. package/lib/dashboard/tree.js +278 -0
  13. package/lib/deps-diff.js +196 -404
  14. package/lib/deps.js +240 -399
  15. package/lib/detect.js +8 -18
  16. package/lib/diff/align.js +41 -113
  17. package/lib/diff/diff.js +12 -43
  18. package/lib/diff/display.js +25 -36
  19. package/lib/diff/edit.js +6 -20
  20. package/lib/diff/inline.js +138 -141
  21. package/lib/diff/items.js +33 -47
  22. package/lib/diff/parse.js +28 -56
  23. package/lib/diff/patch.js +12 -33
  24. package/lib/diff/unit.js +90 -206
  25. package/lib/editor.js +98 -55
  26. package/lib/files.js +86 -103
  27. package/lib/git-branches.js +254 -416
  28. package/lib/git-deps.js +182 -344
  29. package/lib/git-reword-todo.js +5 -13
  30. package/lib/git-worktree.js +141 -212
  31. package/lib/git.js +21 -49
  32. package/lib/github.js +67 -181
  33. package/lib/gitlab.js +40 -90
  34. package/lib/highlight/bash.js +55 -177
  35. package/lib/highlight/core.js +157 -132
  36. package/lib/highlight/css.js +25 -58
  37. package/lib/highlight/csv.js +19 -37
  38. package/lib/highlight/dart.js +72 -213
  39. package/lib/highlight/dot.js +16 -26
  40. package/lib/highlight/html.js +42 -63
  41. package/lib/highlight/js.js +177 -506
  42. package/lib/highlight/json.js +17 -37
  43. package/lib/highlight/log.js +22 -35
  44. package/lib/highlight/txt.js +9 -22
  45. package/lib/highlight.js +17 -46
  46. package/lib/keys.js +62 -85
  47. package/lib/manifest.js +67 -130
  48. package/lib/npm-commands.js +119 -189
  49. package/lib/remote.js +141 -197
  50. package/lib/render/branches.js +66 -73
  51. package/lib/render/chrome.js +264 -323
  52. package/lib/render/commits.js +187 -500
  53. package/lib/render/dash-activity.js +212 -0
  54. package/lib/render/dash-blocks.js +245 -0
  55. package/lib/render/dash-table.js +290 -0
  56. package/lib/render/dashboard.js +62 -0
  57. package/lib/render/diff.js +123 -228
  58. package/lib/render/files.js +45 -99
  59. package/lib/render/frame.js +129 -183
  60. package/lib/render/notes.js +144 -160
  61. package/lib/render/npm.js +234 -112
  62. package/lib/render/present.js +4 -11
  63. package/lib/render/primitives.js +131 -170
  64. package/lib/render/render.js +5 -14
  65. package/lib/render/report.js +43 -0
  66. package/lib/render/tiles.js +260 -0
  67. package/lib/render/unit.js +15 -28
  68. package/lib/report-model.js +110 -33
  69. package/lib/report-parse.js +56 -38
  70. package/lib/report-render.js +102 -59
  71. package/lib/report-run.js +87 -78
  72. package/lib/report-test.js +256 -141
  73. package/lib/report-tools.js +96 -161
  74. package/lib/review-merge.js +114 -152
  75. package/lib/review.js +115 -189
  76. package/lib/runs.js +225 -0
  77. package/lib/select.js +89 -75
  78. package/lib/session/accessors.js +14 -21
  79. package/lib/session/actions.js +82 -63
  80. package/lib/session/branches.js +193 -247
  81. package/lib/session/change-actions.js +171 -214
  82. package/lib/session/commit.js +280 -342
  83. package/lib/session/compose.js +559 -674
  84. package/lib/session/dashboard.js +385 -0
  85. package/lib/session/dispatch.js +164 -157
  86. package/lib/session/edit-click.js +57 -0
  87. package/lib/session/files-pane.js +85 -53
  88. package/lib/session/items.js +73 -104
  89. package/lib/session/lifecycle.js +403 -541
  90. package/lib/session/load.js +48 -68
  91. package/lib/session/navigation.js +96 -87
  92. package/lib/session/npm.js +409 -345
  93. package/lib/session/ops.js +196 -63
  94. package/lib/session/pointer.js +23 -15
  95. package/lib/session/progress.js +33 -21
  96. package/lib/session/review.js +33 -54
  97. package/lib/session/tasks.js +333 -0
  98. package/lib/session/templates.js +51 -59
  99. package/lib/session/terminal.js +85 -136
  100. package/lib/session/unit.js +3 -4
  101. package/lib/session/update.js +76 -97
  102. package/lib/session/view.js +52 -83
  103. package/lib/session/watch.js +208 -204
  104. package/lib/session.js +112 -237
  105. package/lib/update.js +45 -116
  106. package/lib/utilities.js +67 -89
  107. package/lib/wrap.js +33 -44
  108. package/package.json +1 -1
  109. package/lib/session/todos.js +0 -293
@@ -1,71 +1,38 @@
1
1
  'use strict';
2
2
 
3
3
  const core = require('./core.js');
4
- const { QUOTES, emit, readBlockComment, readString } = core;
4
+ const { QUOTES, emit, scanWhile, blockCommentEnd, stringEnd } = core;
5
5
 
6
- const CSS_NEXT_STYLE = {
7
- ':': 'property',
8
- '{': 'tag',
9
- };
6
+ const CSS_NEXT_STYLE = { ':': 'property', '{': 'tag' };
7
+ const CSS_NAME = /[A-Za-z0-9_-]/;
10
8
 
11
9
  const highlight = (source) => {
12
10
  const out = [];
13
11
  let i = 0;
14
- const n = source.length;
15
- while (i < n) {
12
+ const take = (style, end) => {
13
+ emit(out, style, source.slice(i, end));
14
+ i = end;
15
+ };
16
+ while (i < source.length) {
16
17
  const ch = source[i];
17
- const next = source[i + 1];
18
- if (ch === '/' && next === '*') {
19
- const { text, end } = readBlockComment(source, i);
20
- emit(out, 'comment', text);
21
- i = end;
22
- continue;
23
- }
24
- if (QUOTES.includes(ch)) {
25
- const { text, end } = readString(source, i);
26
- emit(out, 'string', text);
27
- i = end;
28
- continue;
29
- }
30
- if (ch === '@') {
31
- let j = i + 1;
32
- while (j < n && /[A-Za-z0-9-]/.test(source[j])) j += 1;
33
- emit(out, 'keyword', source.slice(i, j));
34
- i = j;
35
- continue;
36
- }
37
- if ('#.'.includes(ch)) {
38
- let j = i + 1;
39
- while (j < n && /[A-Za-z0-9_-]/.test(source[j])) j += 1;
40
- const kind = ch === '#' ? 'constant' : 'className';
41
- emit(out, kind, source.slice(i, j));
42
- i = j;
43
- continue;
44
- }
45
- if (/[0-9]/.test(ch)) {
46
- let j = i;
47
- while (j < n && /[0-9.%]/.test(source[j])) j += 1;
48
- emit(out, 'number', source.slice(i, j));
49
- i = j;
50
- continue;
51
- }
52
- if (/[A-Za-z_-]/.test(ch)) {
53
- let j = i + 1;
54
- while (j < n && /[A-Za-z0-9_-]/.test(source[j])) j += 1;
55
- const word = source.slice(i, j);
56
- let k = j;
57
- while (k < n && /\s/.test(source[k])) k += 1;
58
- emit(out, CSS_NEXT_STYLE[source[k]] ?? 'plain', word);
59
- i = j;
60
- continue;
61
- }
62
- if (/[{};:,]/.test(ch)) {
63
- emit(out, 'punct', ch);
64
- i += 1;
65
- continue;
18
+ if (ch === '/' && source[i + 1] === '*') {
19
+ take('comment', blockCommentEnd(source, i));
20
+ } else if (QUOTES.includes(ch)) {
21
+ take('string', stringEnd(source, i));
22
+ } else if (ch === '@') {
23
+ take('keyword', scanWhile(source, i + 1, /[A-Za-z0-9-]/));
24
+ } else if (ch === '#' || ch === '.') {
25
+ const style = ch === '#' ? 'constant' : 'className';
26
+ take(style, scanWhile(source, i + 1, CSS_NAME));
27
+ } else if (/[0-9]/.test(ch)) {
28
+ take('number', scanWhile(source, i, /[0-9.%]/));
29
+ } else if (/[A-Za-z_-]/.test(ch)) {
30
+ const end = scanWhile(source, i + 1, CSS_NAME);
31
+ const after = source[scanWhile(source, end, /\s/)];
32
+ take(CSS_NEXT_STYLE[after] ?? 'plain', end);
33
+ } else {
34
+ take(/[{};:,]/.test(ch) ? 'punct' : 'plain', i + 1);
66
35
  }
67
- emit(out, 'plain', ch);
68
- i += 1;
69
36
  }
70
37
  return out;
71
38
  };
@@ -1,65 +1,47 @@
1
1
  'use strict';
2
2
 
3
3
  const core = require('./core.js');
4
- const { emit } = core;
4
+ const { emit, highlightLines } = core;
5
5
 
6
6
  const splitCsv = (line) => {
7
7
  const cells = [];
8
8
  let cur = '';
9
- let inQ = false;
9
+ let inQuotes = false;
10
10
  for (let i = 0; i < line.length; i += 1) {
11
11
  const ch = line[i];
12
- if (ch === '"') {
13
- if (inQ && line[i + 1] === '"') {
14
- cur += '"';
15
- i += 1;
16
- } else {
17
- inQ = !inQ;
18
- cur += ch;
19
- }
20
- continue;
21
- }
22
- if (ch === ',' && !inQ) {
12
+ if (ch === '"' && inQuotes && line[i + 1] === '"') {
13
+ cur += '"';
14
+ i += 1;
15
+ } else if (ch === '"') {
16
+ inQuotes = !inQuotes;
17
+ cur += ch;
18
+ } else if (ch === ',' && !inQuotes) {
23
19
  cells.push(cur);
24
20
  cur = '';
25
- continue;
21
+ } else {
22
+ cur += ch;
26
23
  }
27
- cur += ch;
28
24
  }
29
25
  cells.push(cur);
30
26
  return cells;
31
27
  };
32
28
 
33
- const highlightCsvCell = (cell, row, col) => {
34
- if (row === 0) return { text: cell, style: 'function' };
35
- const num = /^-?\d+(\.\d+)?$/.test(cell.trim());
36
- if (num) return { text: cell, style: 'number' };
37
- if (col % 2 === 0) return { text: cell, style: 'string' };
38
- return { text: cell, style: 'variable' };
29
+ const cellStyle = (cell, col) => {
30
+ if (/^-?\d+(\.\d+)?$/.test(cell.trim())) return 'number';
31
+ return col % 2 === 0 ? 'string' : 'variable';
39
32
  };
40
33
 
41
- const highlightCsvLine = (line, row) => {
42
- if (!line) return [];
34
+ const highlightCsvLine = (line) => {
43
35
  const cells = splitCsv(line);
44
36
  const out = [];
45
37
  for (let col = 0; col < cells.length; col += 1) {
46
38
  if (col) emit(out, 'punct', ',');
47
- const cell = highlightCsvCell(cells[col], row, col);
48
- emit(out, cell.style, cell.text);
39
+ emit(out, cellStyle(cells[col], col), cells[col]);
49
40
  }
50
41
  return out;
51
42
  };
52
43
 
53
- const highlight = (source) => {
54
- const lines = source.split(/\r?\n/);
55
- const out = [];
56
- for (let row = 0; row < lines.length; row += 1) {
57
- if (row) emit(out, 'plain', '\n');
58
- for (const t of highlightCsvLine(lines[row], row === 0 ? 1 : row)) {
59
- out.push(t);
60
- }
61
- }
62
- return out;
44
+ module.exports = {
45
+ langs: ['csv'],
46
+ highlight: highlightLines(highlightCsvLine, /\r?\n/),
63
47
  };
64
-
65
- module.exports = { langs: ['csv'], highlight };
@@ -1,245 +1,104 @@
1
1
  'use strict';
2
2
 
3
- const hl = require('./core.js');
4
- const { SQUOTE, QUOTES, EXPECT_STYLE, emit, wordStyle } = hl;
5
- const { peekIdent, skipWs, readUntilNl, readBlockComment } = hl;
6
- const { readJsNumber, readJsOperator, readTemplateInterp } = hl;
7
- const { styleConstant, stylePascal, styleCall } = hl;
3
+ const core = require('./core.js');
4
+ const { QUOTES, IDENT_START, IDENT_CHAR, EXPECT_STYLE } = core;
5
+ const { words, emit, wordStyles, appendNode, scanWhile } = core;
6
+ const { lineEnd, blockCommentEnd, numberEnd, operatorEnd } = core;
7
+ const { highlightInterpolated, nameStyle } = core;
8
8
 
9
- const STORAGE = [
10
- 'abstract',
11
- 'as',
12
- 'base',
13
- 'class',
14
- 'const',
15
- 'covariant',
16
- 'deferred',
17
- 'enum',
18
- 'export',
19
- 'extends',
20
- 'extension',
21
- 'external',
22
- 'factory',
23
- 'final',
24
- 'get',
25
- 'hide',
26
- 'implements',
27
- 'import',
28
- 'interface',
29
- 'late',
30
- 'library',
31
- 'mixin',
32
- 'on',
33
- 'operator',
34
- 'part',
35
- 'required',
36
- 'sealed',
37
- 'set',
38
- 'show',
39
- 'static',
40
- 'typedef',
41
- 'var',
42
- 'with',
43
- ];
9
+ const STORAGE = words(`
10
+ abstract as base class const covariant deferred enum export extends
11
+ extension external factory final get hide implements import interface late
12
+ library mixin on operator part required sealed set show static typedef var
13
+ with
14
+ `);
44
15
 
45
- const CONTROL = [
46
- 'assert',
47
- 'async',
48
- 'await',
49
- 'break',
50
- 'case',
51
- 'catch',
52
- 'continue',
53
- 'default',
54
- 'do',
55
- 'else',
56
- 'for',
57
- 'if',
58
- 'in',
59
- 'is',
60
- 'new',
61
- 'rethrow',
62
- 'return',
63
- 'switch',
64
- 'sync',
65
- 'throw',
66
- 'try',
67
- 'when',
68
- 'while',
69
- 'yield',
70
- ];
16
+ const CONTROL = words(`
17
+ assert async await break case catch continue default do else for if in is
18
+ new rethrow return switch sync throw try when while yield
19
+ `);
71
20
 
72
- const LITERALS = ['true', 'false', 'null', 'this', 'super'];
21
+ const LITERALS = words('true false null this super');
73
22
 
74
- const TYPES = ['void', 'dynamic', 'Never', 'int', 'double', 'num', 'bool'];
23
+ const TYPES = words('void dynamic Never int double num bool');
75
24
 
76
- const NEXT_EXPECT = {
77
- class: 'class',
78
- mixin: 'class',
79
- enum: 'class',
80
- extension: 'class',
81
- typedef: 'type',
82
- };
25
+ const NEXT_EXPECT = wordStyles({
26
+ class: ['class', 'mixin', 'enum', 'extension'],
27
+ type: ['typedef'],
28
+ });
83
29
 
84
- const WORD_STYLE = {
85
- ...wordStyle(CONTROL, 'control'),
86
- ...wordStyle(LITERALS, 'literal'),
87
- ...wordStyle(STORAGE, 'storage'),
88
- ...wordStyle(TYPES, 'type'),
89
- };
30
+ const WORD_STYLE = wordStyles({
31
+ control: CONTROL,
32
+ literal: LITERALS,
33
+ storage: STORAGE,
34
+ type: TYPES,
35
+ });
90
36
 
91
- const dartStringOpen = (source, i) => {
92
- let at = i;
37
+ const stringOpen = (source, i) => {
93
38
  const raw = source[i] === 'r';
94
- if (raw) at = i + 1;
39
+ const at = raw ? i + 1 : i;
95
40
  let quote = '';
96
- const triple = SQUOTE.repeat(3);
97
- const dtriple = '"'.repeat(3);
98
- if (source.startsWith(triple, at) || source.startsWith(dtriple, at)) {
41
+ if (source.startsWith(`'''`, at) || source.startsWith('"""', at)) {
99
42
  quote = source.slice(at, at + 3);
100
43
  } else if (QUOTES.includes(source[at] || '')) {
101
44
  quote = source[at];
102
45
  }
103
46
  if (!quote) return null;
104
- return { raw, quote, body: at + quote.length };
105
- };
106
-
107
- const dartIdentStyle = (ctx) => {
108
- const known = WORD_STYLE[ctx.word];
109
- if (known) return known;
110
- if (EXPECT_STYLE[ctx.expectName]) return EXPECT_STYLE[ctx.expectName];
111
- if (styleConstant(ctx)) return 'constant';
112
- if (stylePascal(ctx)) return 'className';
113
- if (styleCall(ctx)) return 'function';
114
- return 'variable';
115
- };
116
-
117
- const highlightDartString = (source, i, inner) => {
118
- const open = dartStringOpen(source, i);
119
- const n = source.length;
120
- const parts = [];
121
- emit(parts, 'string', source.slice(i, open.body));
122
- let j = open.body;
123
- let buf = '';
124
- const flush = () => {
125
- if (!buf) return;
126
- emit(parts, 'string', buf);
127
- buf = '';
128
- };
129
- const quote = open.quote;
130
- while (j < n) {
131
- if (!open.raw && source[j] === '\\') {
132
- flush();
133
- emit(parts, 'escape', source.slice(j, j + 2));
134
- j += 2;
135
- continue;
136
- }
137
- if (source.startsWith(quote, j)) {
138
- flush();
139
- emit(parts, 'string', quote);
140
- j += quote.length;
141
- break;
142
- }
143
- if (!open.raw && source[j] === '$') {
144
- const next = source[j + 1];
145
- if (next === '{') {
146
- flush();
147
- emit(parts, 'interpolation', '${');
148
- j += 2;
149
- const interp = readTemplateInterp(source, j);
150
- for (const t of inner(interp.expr)) parts.push(t);
151
- j = interp.end;
152
- if (source[j] === '}') {
153
- emit(parts, 'interpolation', '}');
154
- j += 1;
155
- }
156
- continue;
157
- }
158
- if (/[A-Za-z_$]/.test(next || '')) {
159
- flush();
160
- const ident = peekIdent(source, j + 1);
161
- emit(parts, 'interpolation', `$${ident}`);
162
- j += 1 + ident.length;
163
- continue;
164
- }
165
- }
166
- if (quote.length === 1 && source[j] === '\n') break;
167
- buf += source[j];
168
- j += 1;
169
- }
170
- flush();
171
- return { tokens: parts, end: j };
47
+ const multiline = quote.length === 3;
48
+ const kind = { style: 'string', quote, raw, multiline, dollarIdent: true };
49
+ return { body: at + quote.length, kind };
172
50
  };
173
51
 
174
52
  const highlight = (source) => {
175
- const inner = (expr) => highlight(expr);
176
53
  const out = [];
177
54
  let i = 0;
178
- const n = source.length;
179
55
  let expectName = null;
180
- while (i < n) {
56
+ const take = (style, end) => {
57
+ emit(out, style, source.slice(i, end));
58
+ i = end;
59
+ };
60
+ while (i < source.length) {
181
61
  const ch = source[i];
182
62
  const next = source[i + 1];
63
+ const open = stringOpen(source, i);
183
64
  if (ch === '/' && next === '/') {
184
- const { text, end } = readUntilNl(source, i);
185
- emit(out, 'comment', text);
186
- i = end;
187
- continue;
188
- }
189
- if (ch === '/' && next === '*') {
190
- const { text, end } = readBlockComment(source, i);
191
- emit(out, 'comment', text);
192
- i = end;
193
- continue;
194
- }
195
- if (dartStringOpen(source, i)) {
196
- const node = highlightDartString(source, i, inner);
197
- for (const t of node.tokens) out.push(t);
198
- i = node.end;
65
+ take('comment', lineEnd(source, i));
66
+ } else if (ch === '/' && next === '*') {
67
+ take('comment', blockCommentEnd(source, i));
68
+ } else if (open) {
69
+ const node = highlightInterpolated(
70
+ source,
71
+ i,
72
+ open.body,
73
+ open.kind,
74
+ highlight,
75
+ );
76
+ i = appendNode(out, node);
199
77
  expectName = null;
200
- continue;
201
- }
202
- if (/[0-9]/.test(ch) || (ch === '.' && /[0-9]/.test(next || ''))) {
203
- const { text, end } = readJsNumber(source, i);
204
- emit(out, 'number', text);
205
- i = end;
206
- continue;
207
- }
208
- if (ch === '@' || ch === '#') {
209
- let j = i + 1;
210
- while (j < n && /[A-Za-z0-9_$]/.test(source[j])) j += 1;
211
- const kind = ch === '@' ? 'decorator' : 'constant';
212
- emit(out, kind, source.slice(i, j));
213
- i = j;
78
+ } else if (/[0-9]/.test(ch) || (ch === '.' && /[0-9]/.test(next || ''))) {
79
+ take('number', numberEnd(source, i));
80
+ } else if (ch === '@' || ch === '#') {
81
+ const style = ch === '@' ? 'decorator' : 'constant';
82
+ take(style, scanWhile(source, i + 1, IDENT_CHAR));
214
83
  expectName = null;
215
- continue;
216
- }
217
- if (/[A-Za-z_$]/.test(ch)) {
218
- const word = peekIdent(source, i);
219
- const end = i + word.length;
220
- const k = skipWs(source, end);
221
- const after = source[k];
222
- const ctx = { word, after, expectName };
223
- emit(out, dartIdentStyle(ctx), word);
224
- if (EXPECT_STYLE[expectName]) expectName = null;
225
- else expectName = NEXT_EXPECT[word] ?? null;
226
- i = end;
227
- continue;
228
- }
229
- if (/[=<>!+\-*/%&|^~?:]/.test(ch)) {
230
- const { text, end } = readJsOperator(source, i);
231
- emit(out, 'operator', text);
232
- i = end;
84
+ } else if (IDENT_START.test(ch)) {
85
+ const end = scanWhile(source, i + 1, IDENT_CHAR);
86
+ const word = source.slice(i, end);
87
+ const after = source[scanWhile(source, end, /\s/)];
88
+ const style =
89
+ WORD_STYLE[word] ||
90
+ EXPECT_STYLE[expectName] ||
91
+ nameStyle(word, after) ||
92
+ 'variable';
93
+ const nextExpect = NEXT_EXPECT[word] ?? null;
94
+ take(style, end);
95
+ expectName = EXPECT_STYLE[expectName] ? null : nextExpect;
96
+ } else if (/[=<>!+\-*/%&|^~?:]/.test(ch)) {
97
+ take('operator', operatorEnd(source, i));
233
98
  expectName = null;
234
- continue;
235
- }
236
- if (/[{}()[\];,.]/.test(ch)) {
237
- emit(out, 'punct', ch);
238
- i += 1;
239
- continue;
99
+ } else {
100
+ take(/[{}()[\];,.]/.test(ch) ? 'punct' : 'plain', i + 1);
240
101
  }
241
- emit(out, 'plain', ch);
242
- i += 1;
243
102
  }
244
103
  return out;
245
104
  };
@@ -1,42 +1,32 @@
1
1
  'use strict';
2
2
 
3
3
  const core = require('./core.js');
4
- const { emit } = core;
4
+ const { emit, highlightLines } = core;
5
+
6
+ const ASSIGN_RE = /^(\s*)([A-Za-z_][A-Za-z0-9_.-]*)(\s*=\s*)(.*)$/;
5
7
 
6
8
  const highlightDotLine = (line) => {
7
- if (!line) return [];
8
9
  const out = [];
9
- const t = line.trimStart();
10
- if (t.startsWith('#') || t.startsWith(';')) {
10
+ const trimmed = line.trimStart();
11
+ if (trimmed.startsWith('#') || trimmed.startsWith(';')) {
11
12
  emit(out, 'comment', line);
12
13
  return out;
13
14
  }
14
- if (t.startsWith('!')) {
15
- const lead = line.slice(0, line.length - t.length);
16
- emit(out, 'plain', lead);
15
+ if (trimmed.startsWith('!')) {
16
+ emit(out, 'plain', line.slice(0, line.length - trimmed.length));
17
17
  emit(out, 'operator', '!');
18
- emit(out, 'plain', t.slice(1));
18
+ emit(out, 'plain', trimmed.slice(1));
19
19
  return out;
20
20
  }
21
- const eq = line.match(/^(\s*)([A-Za-z_][A-Za-z0-9_.-]*)(\s*=\s*)(.*)$/);
22
- if (eq) {
23
- emit(out, 'plain', eq[1]);
24
- emit(out, 'variable', eq[2]);
25
- emit(out, 'operator', eq[3]);
26
- emit(out, 'string', eq[4]);
21
+ const assign = ASSIGN_RE.exec(line);
22
+ if (!assign) {
23
+ emit(out, 'plain', line);
27
24
  return out;
28
25
  }
29
- emit(out, 'plain', line);
30
- return out;
31
- };
32
-
33
- const highlight = (source) => {
34
- const lines = source.split('\n');
35
- const out = [];
36
- for (let i = 0; i < lines.length; i += 1) {
37
- if (i) emit(out, 'plain', '\n');
38
- for (const t of highlightDotLine(lines[i])) out.push(t);
39
- }
26
+ emit(out, 'plain', assign[1]);
27
+ emit(out, 'variable', assign[2]);
28
+ emit(out, 'operator', assign[3]);
29
+ emit(out, 'string', assign[4]);
40
30
  return out;
41
31
  };
42
32
 
@@ -51,5 +41,5 @@ module.exports = {
51
41
  yml: 'dot',
52
42
  toml: 'dot',
53
43
  },
54
- highlight,
44
+ highlight: highlightLines(highlightDotLine),
55
45
  };