@gravitee/ui-components 3.24.4-migrate-codemirror-0dec695 → 3.24.4-migrate-codemirror-6bf640d

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gravitee/ui-components",
3
- "version": "3.24.4-migrate-codemirror-0dec695",
3
+ "version": "3.24.4-migrate-codemirror-6bf640d",
4
4
  "description": "Gravitee.io UI Components library, based on Web Components",
5
5
  "repository": {
6
6
  "type": "git",
@@ -64,6 +64,7 @@
64
64
  "@codemirror/language-data": "^0.19.1",
65
65
  "@codemirror/matchbrackets": "^0.19.3",
66
66
  "@codemirror/state": "^0.19.6",
67
+ "@codemirror/stream-parser": "^0.19.3",
67
68
  "@codemirror/view": "^0.19.32",
68
69
  "@formatjs/intl-locale": "^2.4.40",
69
70
  "@formatjs/intl-relativetimeformat": "^9.3.2",
@@ -111,8 +111,12 @@ export class GvInput extends InputElement(LitElement) {
111
111
  --gv-icon--s: 22px;
112
112
  }
113
113
 
114
- .box-icon.copied gv-icon {
115
- --gv-icon--c: #339900;
114
+ .copied {
115
+ --gv-input--bdc: var(--gv-theme-color-success-light, #81c784);
116
+ }
117
+
118
+ .copied .box-icon gv-icon {
119
+ --gv-icon--c: var(--gv-theme-color-success-dark, #388e3c);
116
120
  }
117
121
 
118
122
  div.box-icon gv-icon.loading,
@@ -497,7 +501,6 @@ export class GvInput extends InputElement(LitElement) {
497
501
  'box-icon': true,
498
502
  'box-icon-left': this.iconLeft != null || this.clearable,
499
503
  'box-icon-bgc': this.hasBackground,
500
- copied: this.hasClipboard && this._copied,
501
504
  };
502
505
 
503
506
  const iconClasses = {
@@ -540,6 +543,7 @@ export class GvInput extends InputElement(LitElement) {
540
543
  'icon-left': !!this.iconLeft || (!!this.icon && this.clearable),
541
544
  clipboard: this.hasClipboard,
542
545
  required: this.required,
546
+ copied: this.hasClipboard && this._copied,
543
547
  };
544
548
 
545
549
  return html`
@@ -0,0 +1,642 @@
1
+ /*
2
+ * Copyright (C) 2021 The Gravitee team (http://gravitee.io)
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ // Ace highlight rules function imported below.
17
+ const HighlightRules = function () {
18
+ const identifierRe = '[a-zA-Z\u00a1-\uffff]+\\b';
19
+ /* eslint no-useless-escape: "off" */
20
+ this.$rules = {
21
+ start: [
22
+ { token: 'empty', regex: /$/ },
23
+ { token: 'literal', regex: /^\.{4,}\s*$/, next: 'listingBlock' },
24
+ { token: 'literal', regex: /^-{4,}\s*$/, next: 'literalBlock' },
25
+ { token: 'literal', regex: /^\+{4,}\s*$/, next: 'passthroughBlock' },
26
+ { token: 'keyword', regex: /^={4,}\s*$/ },
27
+ { token: 'text', regex: /^\s*$/ },
28
+ // immediately return to the start mode without matching anything
29
+ { token: 'empty', regex: '', next: 'dissallowDelimitedBlock' },
30
+ ],
31
+
32
+ dissallowDelimitedBlock: [
33
+ { include: 'paragraphEnd' },
34
+ { token: 'comment', regex: '^//.+$' },
35
+ { token: 'keyword', regex: '^(?:NOTE|TIP|IMPORTANT|WARNING|CAUTION):\\s' },
36
+
37
+ { include: 'listStart' },
38
+ { token: 'literal', regex: /^\s+.+$/, next: 'indentedBlock' },
39
+ { token: 'empty', regex: '', next: 'text' },
40
+ ],
41
+
42
+ paragraphEnd: [
43
+ { token: 'doc.comment', regex: /^\/{4,}\s*$/, next: 'commentBlock' },
44
+ { token: 'tableBlock', regex: /^\s*[|!]=+\s*$/, next: 'tableBlock' },
45
+ // open block, ruler
46
+ { token: 'keyword', regex: /^(?:--|''')\s*$/, next: 'start' },
47
+ { token: 'option', regex: /^\[.*\]\s*$/, next: 'start' },
48
+ { token: 'pageBreak', regex: /^>{3,}$/, next: 'start' },
49
+ { token: 'literal', regex: /^\.{4,}\s*$/, next: 'listingBlock' },
50
+ { token: 'titleUnderline', regex: /^(?:={2,}|-{2,}|~{2,}|\^{2,}|\+{2,})\s*$/, next: 'start' },
51
+ { token: 'singleLineTitle', regex: /^={1,6}\s+\S.*$/, next: 'start' },
52
+
53
+ { token: 'otherBlock', regex: /^(?:\*{2,}|_{2,})\s*$/, next: 'start' },
54
+ // .optional title
55
+ { token: 'optionalTitle', regex: /^\.[^.\s].+$/, next: 'start' },
56
+ ],
57
+
58
+ listStart: [
59
+ {
60
+ token: 'keyword',
61
+ regex: /^\s*(?:\d+\.|[a-zA-Z]\.|[ixvmIXVM]+\)|\*{1,5}|-|\.{1,5})\s/,
62
+ next: 'listText',
63
+ },
64
+ { token: 'meta.tag', regex: /^.+(?::{2,4}|;;)(?: |$)/, next: 'listText' },
65
+ // continuation
66
+ { token: 'keyword', regex: /^\+\s*$/, next: 'start' },
67
+ ],
68
+
69
+ text: [
70
+ {
71
+ token: ['link', 'link'],
72
+ regex: /((?:https?:\/\/|ftp:\/\/|file:\/\/|mailto:|callto:)[^\s\[]+)(\[.*?\])/,
73
+ },
74
+ { token: ['link', 'link'], regex: /(?:https?:\/\/|ftp:\/\/|file:\/\/|mailto:|callto:)[^\s\[]+/ },
75
+ { token: 'link', regex: /\b[\w\.\/\-]+@[\w\.\/\-]+\b/ },
76
+ { include: 'macros' },
77
+ { include: 'paragraphEnd' },
78
+ { token: 'literal', regex: /\+{3,}/, next: 'smallPassthrough' },
79
+ {
80
+ token: 'escape',
81
+ regex: /\((?:C|TM|R)\)|\.{3}|->|<-|=>|<=|&#(?:\d+|x[a-fA-F\d]+);|(?: |^)--(?=\s+\S)/,
82
+ },
83
+ { token: 'escape', regex: /\\[_*'`+#]|\\{2}[_*'`+#]{2}/ },
84
+ { token: 'keyword', regex: /\s\+$/ },
85
+ // any word
86
+ { token: 'text', regex: identifierRe },
87
+ {
88
+ token: ['keyword', 'string', 'keyword'],
89
+ regex: /(<<[\w\d\-$]+,)(.*?)(>>|$)/,
90
+ },
91
+ { token: 'keyword', regex: /<<[\w\d\-$]+,?|>>/ },
92
+ { token: 'constant.character', regex: /\({2,3}.*?\){2,3}/ },
93
+ // List of callouts
94
+ { token: 'support.function.list.callout', regex: /^(?:<\d+>|\d+>|>) /, next: 'text' },
95
+ // Anchor
96
+ { token: 'keyword', regex: /\[\[.+?\]\]/ },
97
+ // bibliography
98
+ { token: 'support', regex: /^\[{3}[\w\d =\-]+\]{3}/ },
99
+
100
+ { include: 'quotes' },
101
+ // text block end
102
+ { token: 'empty', regex: /^\s*$/, next: 'start' },
103
+ ],
104
+
105
+ listText: [{ include: 'listStart' }, { include: 'text' }],
106
+
107
+ indentedBlock: [
108
+ { token: 'literal', regex: /^[\s\w].+$/, next: 'indentedBlock' },
109
+ { token: 'literal', regex: '', next: 'start' },
110
+ ],
111
+
112
+ listingBlock: [
113
+ { token: 'literal', regex: /^\.{4,}\s*$/, next: 'dissallowDelimitedBlock' },
114
+ { token: 'constant.numeric', regex: '<\\d+>' },
115
+ { token: 'literal', regex: '[^<]+' },
116
+ { token: 'literal', regex: '<' },
117
+ ],
118
+ literalBlock: [
119
+ { token: 'literal', regex: /^-{4,}\s*$/, next: 'dissallowDelimitedBlock' },
120
+ { token: 'constant.numeric', regex: '<\\d+>' },
121
+ { token: 'literal', regex: '[^<]+' },
122
+ { token: 'literal', regex: '<' },
123
+ ],
124
+ passthroughBlock: [
125
+ { token: 'literal', regex: /^\+{4,}\s*$/, next: 'dissallowDelimitedBlock' },
126
+ { token: 'literal', regex: identifierRe + '|\\d+' },
127
+ { include: 'macros' },
128
+ { token: 'literal', regex: '.' },
129
+ ],
130
+
131
+ smallPassthrough: [
132
+ { token: 'literal', regex: /[+]{3,}/, next: 'dissallowDelimitedBlock' },
133
+ { token: 'literal', regex: /^\s*$/, next: 'dissallowDelimitedBlock' },
134
+ { token: 'literal', regex: identifierRe + '|\\d+' },
135
+ { include: 'macros' },
136
+ ],
137
+
138
+ commentBlock: [
139
+ { token: 'doc.comment', regex: /^\/{4,}\s*$/, next: 'dissallowDelimitedBlock' },
140
+ { token: 'doc.comment', regex: '^.*$' },
141
+ ],
142
+ tableBlock: [
143
+ { token: 'tableBlock', regex: /^\s*\|={3,}\s*$/, next: 'dissallowDelimitedBlock' },
144
+ { token: 'tableBlock', regex: /^\s*!={3,}\s*$/, next: 'innerTableBlock' },
145
+ { token: 'tableBlock', regex: /\|/ },
146
+ { include: 'text', noEscape: true },
147
+ ],
148
+ innerTableBlock: [
149
+ { token: 'tableBlock', regex: /^\s*!={3,}\s*$/, next: 'tableBlock' },
150
+ { token: 'tableBlock', regex: /^\s*|={3,}\s*$/, next: 'dissallowDelimitedBlock' },
151
+ { token: 'tableBlock', regex: /\!/ },
152
+ ],
153
+ macros: [
154
+ { token: 'macro', regex: /{[\w\-$]+}/ },
155
+ {
156
+ token: ['text', 'string', 'text', 'constant.character', 'text'],
157
+ regex: /({)([\w\-$]+)(:)?(.+)?(})/,
158
+ },
159
+ {
160
+ token: ['text', 'markup.list.macro', 'keyword', 'string'],
161
+ regex: /(\w+)(footnote(?:ref)?::?)([^\s\[]+)?(\[.*?\])?/,
162
+ },
163
+ {
164
+ token: ['markup.list.macro', 'keyword', 'string'],
165
+ regex: /([a-zA-Z\-][\w\.\/\-]*::?)([^\s\[]+)(\[.*?\])?/,
166
+ },
167
+ { token: ['markup.list.macro', 'keyword'], regex: /([a-zA-Z\-][\w\.\/\-]+::?)(\[.*?\])/ },
168
+ { token: 'keyword', regex: /^:.+?:(?= |$)/ },
169
+ ],
170
+
171
+ quotes: [
172
+ { token: 'string.italic', regex: /__[^_\s].*?__/ },
173
+ { token: 'string.italic', regex: quoteRule('_') },
174
+
175
+ { token: 'keyword.bold', regex: /\*\*[^*\s].*?\*\*/ },
176
+ { token: 'keyword.bold', regex: quoteRule('\\*') },
177
+
178
+ { token: 'literal', regex: /\+\+[^+\s].*?\+\+/ },
179
+ { token: 'literal', regex: quoteRule('\\+') },
180
+
181
+ { token: 'literal', regex: /\$\$.+?\$\$/ },
182
+ { token: 'literal', regex: quoteRule('\\$') },
183
+
184
+ { token: 'literal', regex: /``[^`\s].*?``/ },
185
+ { token: 'literal', regex: quoteRule('`') },
186
+
187
+ { token: 'keyword', regex: /\^[^\^].*?\^/ },
188
+ { token: 'keyword', regex: quoteRule('\\^') },
189
+ { token: 'keyword', regex: /~[^~].*?~/ },
190
+ { token: 'keyword', regex: quoteRule('~') },
191
+
192
+ { token: 'keyword', regex: /##?/ },
193
+ { token: 'keyword', regex: /(?:\B|^)``|\b''/ },
194
+ ],
195
+ };
196
+
197
+ function quoteRule(ch) {
198
+ const prefix = /\w/.test(ch) ? '\\b' : '(?:\\B|^)';
199
+ return prefix + ch + '[^' + ch + '].*?' + ch + '(?![\\w*])';
200
+ }
201
+
202
+ // addQuoteBlock("text")
203
+
204
+ const tokenMap = {
205
+ macro: 'constant.character',
206
+ tableBlock: 'doc.comment',
207
+ titleUnderline: 'markup.heading',
208
+ singleLineTitle: 'markup.heading',
209
+ pageBreak: 'string',
210
+ option: 'string.regexp',
211
+ otherBlock: 'markup.list',
212
+ literal: 'support.function',
213
+ optionalTitle: 'constant.numeric',
214
+ escape: 'constant.language.escape',
215
+ link: 'markup.underline.list',
216
+ };
217
+
218
+ for (const state in this.$rules) {
219
+ const stateRules = this.$rules[state];
220
+ for (let i = stateRules.length; i--; ) {
221
+ const rule = stateRules[i];
222
+ if (rule.include || typeof rule === 'string') {
223
+ let args = [i, 1].concat(this.$rules[rule.include || rule]);
224
+ if (rule.noEscape) {
225
+ args = args.filter(function (x) {
226
+ return !x.next;
227
+ });
228
+ }
229
+ stateRules.splice.apply(stateRules, args);
230
+ } else if (rule.token in tokenMap) {
231
+ rule.token = tokenMap[rule.token];
232
+ }
233
+ }
234
+ }
235
+ };
236
+
237
+ // Ace's Syntax Tokenizer.
238
+
239
+ // tokenizing lines longer than this makes editor very slow
240
+ let MAX_TOKEN_COUNT = 1000;
241
+ const Tokenizer = function (rules) {
242
+ this.states = rules;
243
+
244
+ this.regExps = {};
245
+ this.matchMappings = {};
246
+ for (const key in this.states) {
247
+ const state = this.states[key];
248
+ const ruleRegExps = [];
249
+ let matchTotal = 0;
250
+ const mapping = (this.matchMappings[key] = { defaultToken: 'text' });
251
+ let flag = 'g';
252
+
253
+ const splitterRurles = [];
254
+ for (let i = 0; i < state.length; i++) {
255
+ const rule = state[i];
256
+ if (rule.defaultToken) mapping.defaultToken = rule.defaultToken;
257
+ if (rule.caseInsensitive) flag = 'gi';
258
+ if (rule.regex == null) continue;
259
+
260
+ if (rule.regex instanceof RegExp) rule.regex = rule.regex.toString().slice(1, -1);
261
+
262
+ // Count number of matching groups. 2 extra groups from the full match
263
+ // And the catch-all on the end (used to force a match);
264
+ let adjustedregex = rule.regex;
265
+ let matchcount = new RegExp('(?:(' + adjustedregex + ')|(.))').exec('a').length - 2;
266
+ if (Array.isArray(rule.token)) {
267
+ if (rule.token.length === 1 || matchcount === 1) {
268
+ rule.token = rule.token[0];
269
+ } else if (matchcount - 1 !== rule.token.length) {
270
+ throw new Error(
271
+ "number of classes and regexp groups in '" +
272
+ rule.token +
273
+ "'\n'" +
274
+ rule.regex +
275
+ "' doesn't match\n" +
276
+ (matchcount - 1) +
277
+ '!=' +
278
+ rule.token.length,
279
+ );
280
+ } else {
281
+ rule.tokenArray = rule.token;
282
+ rule.token = null;
283
+ rule.onMatch = this.$arrayTokens;
284
+ }
285
+ } else if (typeof rule.token === 'function' && !rule.onMatch) {
286
+ if (matchcount > 1) rule.onMatch = this.$applyToken;
287
+ else rule.onMatch = rule.token;
288
+ }
289
+
290
+ if (matchcount > 1) {
291
+ if (/\\\d/.test(rule.regex)) {
292
+ // Replace any backreferences and offset appropriately.
293
+ adjustedregex = rule.regex.replace(/\\([0-9]+)/g, function (match, digit) {
294
+ return '\\' + (parseInt(digit, 10) + matchTotal + 1);
295
+ });
296
+ } else {
297
+ matchcount = 1;
298
+ adjustedregex = this.removeCapturingGroups(rule.regex);
299
+ }
300
+ if (!rule.splitRegex && typeof rule.token !== 'string')
301
+ // flag will be known only at the very end
302
+ splitterRurles.push(rule);
303
+ }
304
+
305
+ mapping[matchTotal] = i;
306
+ matchTotal += matchcount;
307
+
308
+ ruleRegExps.push(adjustedregex);
309
+
310
+ // makes property access faster
311
+ if (!rule.onMatch) rule.onMatch = null;
312
+ }
313
+
314
+ splitterRurles.forEach(function (rule) {
315
+ rule.splitRegex = this.createSplitterRegexp(rule.regex, flag);
316
+ }, this);
317
+
318
+ this.regExps[key] = new RegExp('(' + ruleRegExps.join(')|(') + ')|($)', flag);
319
+ }
320
+ };
321
+
322
+ (function () {
323
+ this.$setMaxTokenCount = function (m) {
324
+ MAX_TOKEN_COUNT = m | 0;
325
+ };
326
+
327
+ this.$applyToken = function (str) {
328
+ const values = this.splitRegex.exec(str).slice(1);
329
+ const types = this.token.apply(this, values);
330
+
331
+ // required for compatibility with old modes
332
+ if (typeof types === 'string') return [{ type: types, value: str }];
333
+
334
+ const tokens = [];
335
+ for (let i = 0, l = types.length; i < l; i++) {
336
+ if (values[i])
337
+ tokens[tokens.length] = {
338
+ type: types[i],
339
+ value: values[i],
340
+ };
341
+ }
342
+ return tokens;
343
+ };
344
+
345
+ this.$arrayTokens = function (str) {
346
+ if (!str) return [];
347
+ const values = this.splitRegex.exec(str);
348
+ if (!values) return 'text';
349
+ const tokens = [];
350
+ const types = this.tokenArray;
351
+ for (let i = 0, l = types.length; i < l; i++) {
352
+ if (values[i + 1])
353
+ tokens[tokens.length] = {
354
+ type: types[i],
355
+ value: values[i + 1],
356
+ };
357
+ }
358
+ return tokens;
359
+ };
360
+
361
+ this.removeCapturingGroups = function (src) {
362
+ const r = src.replace(/\[(?:\\.|[^\]])*?\]|\\.|\(\?[:=!]|(\()/g, function (x, y) {
363
+ return y ? '(?:' : x;
364
+ });
365
+ return r;
366
+ };
367
+
368
+ this.createSplitterRegexp = function (src, flag) {
369
+ if (src.indexOf('(?=') !== -1) {
370
+ let stack = 0;
371
+ let inChClass = false;
372
+ const lastCapture = {};
373
+ src.replace(/(\\.)|(\((?:\?[=!])?)|(\))|([\[\]])/g, function (m, esc, parenOpen, parenClose, square, index) {
374
+ if (inChClass) {
375
+ inChClass = square !== ']';
376
+ } else if (square) {
377
+ inChClass = true;
378
+ } else if (parenClose) {
379
+ if (stack === lastCapture.stack) {
380
+ lastCapture.end = index + 1;
381
+ lastCapture.stack = -1;
382
+ }
383
+ stack--;
384
+ } else if (parenOpen) {
385
+ stack++;
386
+ if (parenOpen.length !== 1) {
387
+ lastCapture.stack = stack;
388
+ lastCapture.start = index;
389
+ }
390
+ }
391
+ return m;
392
+ });
393
+
394
+ if (lastCapture.end != null && /^\)*$/.test(src.substr(lastCapture.end)))
395
+ src = src.substring(0, lastCapture.start) + src.substr(lastCapture.end);
396
+ }
397
+ return new RegExp(src, (flag || '').replace('g', ''));
398
+ };
399
+
400
+ /**
401
+ * Returns an object containing two properties: `tokens`, which contains all the tokens; and `state`, the current state.
402
+ * @returns {Object}
403
+ **/
404
+ this.getLineTokens = function (line, startState) {
405
+ let stack = [];
406
+ if (startState && typeof startState !== 'string') {
407
+ stack = startState.slice(0);
408
+ startState = stack[0];
409
+ }
410
+
411
+ let currentState = startState || 'start';
412
+ let state = this.states[currentState];
413
+ if (!state) {
414
+ currentState = 'start';
415
+ state = this.states[currentState];
416
+ }
417
+ let mapping = this.matchMappings[currentState];
418
+ let re = this.regExps[currentState];
419
+ re.lastIndex = 0;
420
+
421
+ let match;
422
+ const tokens = [];
423
+ let lastIndex = 0;
424
+
425
+ let token = { type: null, value: '' };
426
+
427
+ /* eslint no-cond-assign: "off" */
428
+ while ((match = re.exec(line))) {
429
+ let type = mapping.defaultToken;
430
+ let rule = null;
431
+ const value = match[0];
432
+ const index = re.lastIndex;
433
+
434
+ if (index - value.length > lastIndex) {
435
+ const skipped = line.substring(lastIndex, index - value.length);
436
+ if (token.type === type) {
437
+ token.value += skipped;
438
+ } else {
439
+ if (token.type) tokens.push(token);
440
+ token = { type: type, value: skipped };
441
+ }
442
+ }
443
+
444
+ for (let i = 0; i < match.length - 2; i++) {
445
+ if (match[i + 1] === undefined) continue;
446
+
447
+ rule = state[mapping[i]];
448
+
449
+ if (rule.onMatch) type = rule.onMatch(value, currentState, stack);
450
+ else type = rule.token;
451
+
452
+ if (rule.next) {
453
+ if (typeof rule.next === 'string') currentState = rule.next;
454
+ else currentState = rule.next(currentState, stack);
455
+
456
+ state = this.states[currentState];
457
+ if (!state) {
458
+ window.console && console.error && console.error(currentState, "doesn't exist");
459
+ currentState = 'start';
460
+ state = this.states[currentState];
461
+ }
462
+ mapping = this.matchMappings[currentState];
463
+ lastIndex = index;
464
+ re = this.regExps[currentState];
465
+ re.lastIndex = index;
466
+ }
467
+ break;
468
+ }
469
+
470
+ if (value) {
471
+ if (typeof type === 'string') {
472
+ if ((!rule || rule.merge !== false) && token.type === type) {
473
+ token.value += value;
474
+ } else {
475
+ if (token.type) tokens.push(token);
476
+ token = { type: type, value: value };
477
+ }
478
+ } else if (type) {
479
+ if (token.type) tokens.push(token);
480
+ token = { type: null, value: '' };
481
+ for (let i = 0; i < type.length; i++) tokens.push(type[i]);
482
+ }
483
+ }
484
+
485
+ if (lastIndex === line.length) break;
486
+
487
+ lastIndex = index;
488
+
489
+ if (tokens.length > MAX_TOKEN_COUNT) {
490
+ // chrome doens't show contents of text nodes with very long text
491
+ while (lastIndex < line.length) {
492
+ if (token.type) tokens.push(token);
493
+ token = {
494
+ value: line.substring(lastIndex, (lastIndex += 2000)),
495
+ type: 'overflow',
496
+ };
497
+ }
498
+ currentState = 'start';
499
+ stack = [];
500
+ break;
501
+ }
502
+ }
503
+
504
+ if (token.type) tokens.push(token);
505
+
506
+ if (stack.length > 1) {
507
+ if (stack[0] !== currentState) stack.unshift(currentState);
508
+ }
509
+ return {
510
+ tokens: tokens,
511
+ state: stack.length ? stack : currentState,
512
+ };
513
+ };
514
+ }.call(Tokenizer.prototype));
515
+
516
+ // Token conversion.
517
+ // See <https://github.com/ajaxorg/ace/wiki/Creating-or-Extending-an-Edit-Mode#common-tokens>
518
+ // This is not an exact match nor the best match that can be made.
519
+ const tokenFromAceToken = {
520
+ empty: null,
521
+ text: null,
522
+
523
+ // Keyword
524
+ keyword: 'keyword',
525
+ control: 'keyword',
526
+ operator: 'operator',
527
+
528
+ // Constants
529
+ constant: 'atom',
530
+ numeric: 'number',
531
+ character: 'atom',
532
+ escape: 'atom',
533
+
534
+ // Variables
535
+ variable: 'variable',
536
+ parameter: 'variable-3',
537
+ // Python's `self` uses that.
538
+ language: 'variable-2',
539
+
540
+ // Comments
541
+ comment: 'comment',
542
+ line: 'comment',
543
+ 'double-slash': 'comment',
544
+ 'double-dash': 'comment',
545
+ 'number-sign': 'comment',
546
+ percentage: 'comment',
547
+ block: 'comment',
548
+ doc: 'comment',
549
+
550
+ // String
551
+ string: 'string',
552
+ quoted: 'string',
553
+ single: 'string',
554
+ double: 'string',
555
+ triple: 'string',
556
+ unquoted: 'string',
557
+ interpolated: 'string',
558
+ regexp: 'string-2',
559
+
560
+ meta: 'keyword',
561
+ literal: 'qualifier',
562
+ support: 'builtin',
563
+
564
+ // Markup
565
+ markup: 'tag',
566
+ underline: 'link',
567
+ link: 'link',
568
+ strong: 'strong',
569
+ heading: 'header',
570
+ em: 'em',
571
+ list: 'variable-2',
572
+ numbered: 'variable-2',
573
+ unnumbered: 'variable-2',
574
+ quote: 'quote',
575
+ // Markdown's raw block uses that.
576
+ raw: 'variable-2',
577
+
578
+ // Invalid
579
+ invalid: 'error',
580
+ illegal: 'invalidchar',
581
+ deprecated: 'error',
582
+ };
583
+
584
+ // Takes a list of Ace tokens, returns a (string) CodeMirror token.
585
+ const cmTokenFromAceTokens = function (tokens) {
586
+ let token = null;
587
+ for (let i = 0; i < tokens.length; i++) {
588
+ // Find the most specific token.
589
+ if (tokenFromAceToken[tokens[i]] !== undefined) {
590
+ token = tokenFromAceToken[tokens[i]];
591
+ }
592
+ }
593
+ return token;
594
+ };
595
+
596
+ // Consume a token from plannedTokens.
597
+ const consumeToken = function (stream, state) {
598
+ const plannedToken = state.plannedTokens.shift();
599
+ if (plannedToken === undefined) {
600
+ return null;
601
+ }
602
+ stream.match(plannedToken.value);
603
+ const tokens = plannedToken.type.split('.');
604
+ return cmTokenFromAceTokens(tokens);
605
+ };
606
+
607
+ const matchToken = function (stream, state) {
608
+ // Anormal start: we already have planned tokens to consume.
609
+ if (state.plannedTokens.length > 0) {
610
+ return consumeToken(stream, state);
611
+ }
612
+
613
+ // Normal start.
614
+ const currentState = state.current;
615
+ const currentLine = stream.match(/.*$/, false)[0];
616
+ const tokenized = tokenizer.getLineTokens(currentLine, currentState);
617
+ // We got a {tokens, state} object.
618
+ // Each token is a {value, type} object.
619
+ state.plannedTokens = tokenized.tokens;
620
+ state.current = tokenized.state;
621
+
622
+ // Consume a token.
623
+ return consumeToken(stream, state);
624
+ };
625
+
626
+ // Initialize all state.
627
+ const aceHighlightRules = new HighlightRules();
628
+ const tokenizer = new Tokenizer(aceHighlightRules.$rules);
629
+
630
+ export const asciidoc = {
631
+ startState: function () {
632
+ return {
633
+ current: 'start',
634
+ // List of {value, type}, with type being an Ace token string.
635
+ plannedTokens: [],
636
+ };
637
+ },
638
+ blankLine: function (state) {
639
+ matchToken('', state);
640
+ },
641
+ token: matchToken,
642
+ };
@@ -31,22 +31,6 @@ import { skeleton } from '../styles/skeleton';
31
31
  import { empty } from '../styles/empty';
32
32
  import { input } from '../styles/input';
33
33
 
34
- const languageCompartment = new Compartment();
35
- const readonlyCompartment = new Compartment();
36
- const placeholderCompartment = new Compartment();
37
-
38
- const overrideTheme = EditorView.theme({
39
- '&.cm-editor.cm-focused': {
40
- outline: 'none',
41
- },
42
- '.cm-gutters': {
43
- backgroundColor: 'var(--gv-input-icon--bgc, var(--gv-theme-neutral-color, #f5f5f5))',
44
- color: 'var(--gv-theme-font-color-dark, #262626)',
45
- borderLeft: '5px solid',
46
- borderColor: 'var(--gv-input--bdc, var(--gv-theme-neutral-color-dark, #d9d9d9))',
47
- },
48
- });
49
-
50
34
  /**
51
35
  * Code component
52
36
  *
@@ -88,6 +72,9 @@ export class GvCode extends GvInput {
88
72
  this.autofocus = false;
89
73
  this.clipboard = false;
90
74
  this._clipboardIcon = shapeClipboard;
75
+ this.languageCompartment = new Compartment();
76
+ this.readonlyCompartment = new Compartment();
77
+ this.placeholderCompartment = new Compartment();
91
78
  }
92
79
 
93
80
  render() {
@@ -97,6 +84,7 @@ export class GvCode extends GvInput {
97
84
  large: this.large,
98
85
  medium: this.medium || (!this.large && !this.small),
99
86
  small: this.small,
87
+ copied: this.hasClipboard && this._copied,
100
88
  };
101
89
  const inputClasses = {
102
90
  content: true,
@@ -149,11 +137,11 @@ export class GvCode extends GvInput {
149
137
  _getExtensions() {
150
138
  return [
151
139
  basicSetup,
152
- overrideTheme,
153
- languageCompartment.of(json()),
154
- placeholderCompartment.of(placeholder(this.placeholder || '')),
140
+ GvCode.codemirrorTheme,
141
+ this.languageCompartment.of(json()),
142
+ this.placeholderCompartment.of(placeholder(this.placeholder || '')),
155
143
  EditorState.transactionFilter.of((tr) => (this.hasInputStyle && tr.newDoc.lines > 1 ? [] : tr)),
156
- readonlyCompartment.of(EditorView.editable.of(!this.readonly && !this.disabled)),
144
+ this.readonlyCompartment.of(EditorView.editable.of(!this.readonly && !this.disabled)),
157
145
  EditorView.updateListener.of((viewUpdate) => {
158
146
  if (viewUpdate.docChanged) {
159
147
  this.value = this._editorView.state.doc.toString();
@@ -211,7 +199,7 @@ export class GvCode extends GvInput {
211
199
 
212
200
  _reflectPlaceholder() {
213
201
  this._editorView.dispatch({
214
- effects: placeholderCompartment.reconfigure(placeholder(this.placeholder)),
202
+ effects: this.placeholderCompartment.reconfigure(placeholder(this.placeholder)),
215
203
  });
216
204
  }
217
205
 
@@ -228,32 +216,61 @@ export class GvCode extends GvInput {
228
216
 
229
217
  _reflectReadonlyDisabled() {
230
218
  this._editorView.dispatch({
231
- effects: readonlyCompartment.reconfigure(EditorView.editable.of(!this.readonly && !this.disabled)),
219
+ effects: this.readonlyCompartment.reconfigure(EditorView.editable.of(!this.readonly && !this.disabled)),
232
220
  });
233
221
  }
234
222
 
235
- async _reflectOptions() {
236
- if (this.options.mode) {
237
- const language = languages.find((languageDescription) => {
238
- return (
239
- languageDescription.name.toUpperCase() === this.options.mode.toUpperCase() ||
240
- languageDescription.alias.includes(this.options.mode)
241
- );
242
- });
243
- if (language != null) {
244
- if (language.support == null) {
245
- await language.load();
246
- }
247
- this._editorView.dispatch({
248
- effects: languageCompartment.reconfigure(language.support.extension),
249
- });
223
+ static async findLanguage(mode) {
224
+ if (mode) {
225
+ const modeOnly = mode.split('/').pop();
226
+ if (modeOnly === 'asciidoc') {
227
+ const [{ asciidoc }, { StreamLanguage }] = await Promise.all([import('../lib/asciidoc-lang'), import('@codemirror/stream-parser')]);
228
+ return {
229
+ name: 'asciidoc',
230
+ support: {
231
+ extension: StreamLanguage.define(asciidoc),
232
+ },
233
+ };
250
234
  } else {
251
- console.warn(
252
- `Cannot find language ${this.options.mode}, please use language supported by CodeMirror 6`,
253
- languages.map((l) => l.name),
254
- );
235
+ const language = languages.find((languageDescription) => {
236
+ return languageDescription.name.toUpperCase() === modeOnly.toUpperCase() || languageDescription.alias.includes(modeOnly);
237
+ });
238
+ if (language == null) {
239
+ console.warn(
240
+ `Cannot find language ${mode}, please use language supported by CodeMirror 6`,
241
+ languages.map((l) => l.name),
242
+ );
243
+ }
244
+ return language;
255
245
  }
256
246
  }
247
+ return null;
248
+ }
249
+
250
+ async _reflectOptions() {
251
+ const language = await GvCode.findLanguage(this.options.mode);
252
+ if (language != null) {
253
+ if (language.support == null) {
254
+ await language.load();
255
+ }
256
+ this._editorView.dispatch({
257
+ effects: this.languageCompartment.reconfigure(language.support.extension),
258
+ });
259
+ }
260
+ }
261
+
262
+ static get codemirrorTheme() {
263
+ return EditorView.theme({
264
+ '&.cm-editor.cm-focused': {
265
+ outline: 'none',
266
+ },
267
+ '.cm-gutters': {
268
+ backgroundColor: 'var(--gv-input-icon--bgc, var(--gv-theme-neutral-color, #f5f5f5))',
269
+ color: 'var(--gv-theme-font-color-dark, #262626)',
270
+ borderLeft: '5px solid',
271
+ borderColor: 'var(--gv-input--bdc, var(--gv-theme-neutral-color-dark, #d9d9d9))',
272
+ },
273
+ });
257
274
  }
258
275
 
259
276
  static get styles() {
@@ -272,6 +289,12 @@ export class GvCode extends GvInput {
272
289
 
273
290
  .content {
274
291
  position: relative;
292
+ border: var(--gv-input--bdw, 1px) var(--gv-input--bds, solid) var(--gv-input--bdc, var(--gv-theme-neutral-color-dark, #d9d9d9));
293
+ box-sizing: border-box;
294
+ border-radius: 4px;
295
+ }
296
+
297
+ .btn_copy {
275
298
  }
276
299
 
277
300
  .box-icon {
@@ -281,11 +304,10 @@ export class GvCode extends GvInput {
281
304
  }
282
305
 
283
306
  .code .box-icon {
284
- border-radius: 0;
285
- top: 0;
307
+ border-radius: 3px;
286
308
  }
287
309
 
288
- /** Override Codemirror style */
310
+ /** Override Codemirror theme */
289
311
  .input .cm-gutters {
290
312
  display: none;
291
313
  }
@@ -294,7 +316,8 @@ export class GvCode extends GvInput {
294
316
  overflow: hidden;
295
317
  }
296
318
 
297
- .input .cm-activeLine {
319
+ .input .cm-activeLine,
320
+ :host([readonly]) .cm-activeLine {
298
321
  background-color: transparent;
299
322
  }
300
323
 
@@ -122,6 +122,7 @@ export const input = css`
122
122
  ::slotted(.input),
123
123
  .input {
124
124
  border: var(--gv-input--bdw, 1px) var(--gv-input--bds, solid) var(--gv-input--bdc, var(--gv-theme-neutral-color-dark, #d9d9d9));
125
+ transition: border 10ms ease-in-out;
125
126
  box-sizing: border-box;
126
127
  border-radius: 4px;
127
128
  font-style: normal;