@theia/monaco 1.76.0-next.7 → 1.76.0

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.
@@ -12,7 +12,8 @@ export declare class TokenizerState implements monaco.languages.IState {
12
12
  export interface TokenizerOption {
13
13
  /**
14
14
  * Maximum line length that will be handled by the TextMate tokenizer. If the length of the actual line exceeds this
15
- * limit, the tokenizer terminates and the tokenization of any subsequent lines might be broken.
15
+ * limit, the line is skipped and tokenization continues from the preceding state. Constructs opened on a skipped
16
+ * line (e.g. a block comment) are therefore not accounted for.
16
17
  *
17
18
  * If the `lineLimit` is not defined, it means, there are no line length limits. Otherwise, it must be a positive
18
19
  * integer or an error will be thrown.
@@ -1 +1 @@
1
- {"version":3,"file":"textmate-tokenizer.d.ts","sourceRoot":"","sources":["../../../src/browser/textmate/textmate-tokenizer.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAW,QAAQ,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAChE,OAAO,KAAK,MAAM,MAAM,2BAA2B,CAAC;AAEpD,qBAAa,cAAe,YAAW,MAAM,CAAC,SAAS,CAAC,MAAM;aAGtC,UAAU,EAAE,UAAU;gBAAtB,UAAU,EAAE,UAAU;IAG1C,KAAK,IAAI,MAAM,CAAC,SAAS,CAAC,MAAM;IAIhC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,SAAS,CAAC,MAAM,GAAG,OAAO;CAIlD;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAE5B;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CAEtB;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,eAAe,GAAG,MAAM,CAAC,SAAS,CAAC,qBAAqB,GAAG,MAAM,CAAC,SAAS,CAAC,cAAc,CAgC7J"}
1
+ {"version":3,"file":"textmate-tokenizer.d.ts","sourceRoot":"","sources":["../../../src/browser/textmate/textmate-tokenizer.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAW,QAAQ,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAChE,OAAO,KAAK,MAAM,MAAM,2BAA2B,CAAC;AAEpD,qBAAa,cAAe,YAAW,MAAM,CAAC,SAAS,CAAC,MAAM;aAGtC,UAAU,EAAE,UAAU;gBAAtB,UAAU,EAAE,UAAU;IAG1C,KAAK,IAAI,MAAM,CAAC,SAAS,CAAC,MAAM;IAIhC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,SAAS,CAAC,MAAM,GAAG,OAAO;CAIlD;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAE5B;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CAEtB;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,eAAe,GAAG,MAAM,CAAC,SAAS,CAAC,qBAAqB,GAAG,MAAM,CAAC,SAAS,CAAC,cAAc,CAkC7J"}
@@ -38,8 +38,10 @@ function createTextmateTokenizer(grammar, options) {
38
38
  getInitialState: () => new TokenizerState(vscode_textmate_1.INITIAL),
39
39
  tokenizeEncoded(line, state) {
40
40
  if (options.lineLimit !== undefined && line.length > options.lineLimit) {
41
- // Skip tokenizing the line if it exceeds the line limit.
42
- return { endState: state.stateStack, tokens: new Uint32Array() };
41
+ // Skip tokenizing the line if it exceeds the line limit. The state must be
42
+ // handed back as-is: `state.stateStack` is the raw `vscode-textmate` stack, and
43
+ // Monaco passes whatever is returned here straight into the next line.
44
+ return { endState: state, tokens: new Uint32Array() };
43
45
  }
44
46
  const result = grammar.tokenizeLine2(line, state.stateStack, 500);
45
47
  return {
@@ -49,8 +51,8 @@ function createTextmateTokenizer(grammar, options) {
49
51
  },
50
52
  tokenize(line, state) {
51
53
  if (options.lineLimit !== undefined && line.length > options.lineLimit) {
52
- // Skip tokenizing the line if it exceeds the line limit.
53
- return { endState: state.stateStack, tokens: [] };
54
+ // Skip tokenizing the line if it exceeds the line limit. See `tokenizeEncoded`.
55
+ return { endState: state, tokens: [] };
54
56
  }
55
57
  const result = grammar.tokenizeLine(line, state.stateStack, 500);
56
58
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"textmate-tokenizer.js","sourceRoot":"","sources":["../../../src/browser/textmate/textmate-tokenizer.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,0CAA0C;AAC1C,EAAE;AACF,2EAA2E;AAC3E,mEAAmE;AACnE,wCAAwC;AACxC,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,yDAAyD;AACzD,uDAAuD;AACvD,EAAE;AACF,gFAAgF;AAChF,gFAAgF;;;AAqChF,0DAgCC;AAnED,qDAAgE;AAGhE,MAAa,cAAc;IAEvB,YACoB,UAAsB;QAAtB,eAAU,GAAV,UAAU,CAAY;IACtC,CAAC;IAEL,KAAK;QACD,OAAO,IAAI,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC/C,CAAC;IAED,MAAM,CAAC,KAA8B;QACjC,OAAO,KAAK,YAAY,cAAc,IAAI,CAAC,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,UAAU,KAAK,IAAI,CAAC,UAAU,CAAC,CAAC;IACvG,CAAC;CAEJ;AAdD,wCAcC;AAkBD,SAAgB,uBAAuB,CAAC,OAAiB,EAAE,OAAwB;IAC/E,IAAI,OAAO,CAAC,SAAS,KAAK,SAAS,IAAI,CAAC,OAAO,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;QACtG,MAAM,IAAI,KAAK,CAAC,sDAAsD,OAAO,CAAC,SAAS,GAAG,CAAC,CAAC;IAChG,CAAC;IACD,OAAO;QACH,eAAe,EAAE,GAAG,EAAE,CAAC,IAAI,cAAc,CAAC,yBAAO,CAAC;QAClD,eAAe,CAAC,IAAY,EAAE,KAAqB;YAC/C,IAAI,OAAO,CAAC,SAAS,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;gBACrE,yDAAyD;gBACzD,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,WAAW,EAAE,EAAE,CAAC;YACrE,CAAC;YACD,MAAM,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,IAAI,EAAE,KAAK,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;YAClE,OAAO;gBACH,QAAQ,EAAE,IAAI,cAAc,CAAC,MAAM,CAAC,SAAS,CAAC;gBAC9C,MAAM,EAAE,MAAM,CAAC,MAAM;aACxB,CAAC;QACN,CAAC;QACD,QAAQ,CAAC,IAAY,EAAE,KAAqB;YACxC,IAAI,OAAO,CAAC,SAAS,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;gBACrE,yDAAyD;gBACzD,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;YACtD,CAAC;YACD,MAAM,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;YACjE,OAAO;gBACH,QAAQ,EAAE,IAAI,cAAc,CAAC,MAAM,CAAC,SAAS,CAAC;gBAC9C,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;oBAC5B,UAAU,EAAE,CAAC,CAAC,UAAU;oBACxB,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC;iBACvC,CAAC,CAAC;aACN,CAAC;QACN,CAAC;KACJ,CAAC;AACN,CAAC"}
1
+ {"version":3,"file":"textmate-tokenizer.js","sourceRoot":"","sources":["../../../src/browser/textmate/textmate-tokenizer.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,0CAA0C;AAC1C,EAAE;AACF,2EAA2E;AAC3E,mEAAmE;AACnE,wCAAwC;AACxC,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,yDAAyD;AACzD,uDAAuD;AACvD,EAAE;AACF,gFAAgF;AAChF,gFAAgF;;;AAsChF,0DAkCC;AAtED,qDAAgE;AAGhE,MAAa,cAAc;IAEvB,YACoB,UAAsB;QAAtB,eAAU,GAAV,UAAU,CAAY;IACtC,CAAC;IAEL,KAAK;QACD,OAAO,IAAI,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC/C,CAAC;IAED,MAAM,CAAC,KAA8B;QACjC,OAAO,KAAK,YAAY,cAAc,IAAI,CAAC,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,UAAU,KAAK,IAAI,CAAC,UAAU,CAAC,CAAC;IACvG,CAAC;CAEJ;AAdD,wCAcC;AAmBD,SAAgB,uBAAuB,CAAC,OAAiB,EAAE,OAAwB;IAC/E,IAAI,OAAO,CAAC,SAAS,KAAK,SAAS,IAAI,CAAC,OAAO,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;QACtG,MAAM,IAAI,KAAK,CAAC,sDAAsD,OAAO,CAAC,SAAS,GAAG,CAAC,CAAC;IAChG,CAAC;IACD,OAAO;QACH,eAAe,EAAE,GAAG,EAAE,CAAC,IAAI,cAAc,CAAC,yBAAO,CAAC;QAClD,eAAe,CAAC,IAAY,EAAE,KAAqB;YAC/C,IAAI,OAAO,CAAC,SAAS,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;gBACrE,2EAA2E;gBAC3E,gFAAgF;gBAChF,uEAAuE;gBACvE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,WAAW,EAAE,EAAE,CAAC;YAC1D,CAAC;YACD,MAAM,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,IAAI,EAAE,KAAK,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;YAClE,OAAO;gBACH,QAAQ,EAAE,IAAI,cAAc,CAAC,MAAM,CAAC,SAAS,CAAC;gBAC9C,MAAM,EAAE,MAAM,CAAC,MAAM;aACxB,CAAC;QACN,CAAC;QACD,QAAQ,CAAC,IAAY,EAAE,KAAqB;YACxC,IAAI,OAAO,CAAC,SAAS,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;gBACrE,gFAAgF;gBAChF,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;YAC3C,CAAC;YACD,MAAM,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;YACjE,OAAO;gBACH,QAAQ,EAAE,IAAI,cAAc,CAAC,MAAM,CAAC,SAAS,CAAC;gBAC9C,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;oBAC5B,UAAU,EAAE,CAAC,CAAC,UAAU;oBACxB,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC;iBACvC,CAAC,CAAC;aACN,CAAC;QACN,CAAC;KACJ,CAAC;AACN,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=textmate-tokenizer.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"textmate-tokenizer.spec.d.ts","sourceRoot":"","sources":["../../../src/browser/textmate/textmate-tokenizer.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ // *****************************************************************************
3
+ // Copyright (C) 2026 Matthew Farrow and others.
4
+ //
5
+ // This program and the accompanying materials are made available under the
6
+ // terms of the Eclipse Public License v. 2.0 which is available at
7
+ // http://www.eclipse.org/legal/epl-2.0.
8
+ //
9
+ // This Source Code may also be made available under the following Secondary
10
+ // Licenses when the conditions for such availability set forth in the Eclipse
11
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
12
+ // with the GNU Classpath Exception which is available at
13
+ // https://www.gnu.org/software/classpath/license.html.
14
+ //
15
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
16
+ // *****************************************************************************
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ const chai_1 = require("chai");
19
+ const textmate_tokenizer_1 = require("./textmate-tokenizer");
20
+ describe('createTextmateTokenizer', () => {
21
+ // A grammar that hands back the rule stack it was given, so the tests only observe
22
+ // what the tokenizer itself does with the state.
23
+ const grammar = {
24
+ tokenizeLine: (line, ruleStack) => ({ tokens: [], ruleStack }),
25
+ tokenizeLine2: (line, ruleStack) => ({ tokens: new Uint32Array(), ruleStack })
26
+ };
27
+ const tokenizer = (0, textmate_tokenizer_1.createTextmateTokenizer)(grammar, { lineLimit: 8 });
28
+ const longLine = 'x'.repeat(16);
29
+ // Monaco stores the end state and passes it into the next line. Returning anything
30
+ // other than a `TokenizerState` breaks the line after the skipped one: a short line
31
+ // silently restarts the grammar, and a second skipped line returns `undefined`,
32
+ // which Monaco rejects with 'Cannot set null/undefined state', stopping tokenization
33
+ // for the whole model.
34
+ it('should keep the state when tokenizeEncoded skips a line over the limit', () => {
35
+ const state = tokenizer.getInitialState();
36
+ const { endState } = tokenizer.tokenizeEncoded(longLine, state);
37
+ (0, chai_1.expect)(endState).to.be.an.instanceOf(textmate_tokenizer_1.TokenizerState);
38
+ (0, chai_1.expect)(endState).to.equal(state);
39
+ });
40
+ it('should keep the state when tokenize skips a line over the limit', () => {
41
+ const state = tokenizer.getInitialState();
42
+ const { endState } = tokenizer.tokenize(longLine, state);
43
+ (0, chai_1.expect)(endState).to.be.an.instanceOf(textmate_tokenizer_1.TokenizerState);
44
+ (0, chai_1.expect)(endState).to.equal(state);
45
+ });
46
+ it('should tokenize the line after a skipped one from the same state', () => {
47
+ const initial = tokenizer.getInitialState();
48
+ const afterSkipped = tokenizer.tokenizeEncoded(longLine, initial).endState;
49
+ // Two skipped lines in a row is where the broken state surfaced as an exception.
50
+ const afterSecondSkipped = tokenizer.tokenizeEncoded(longLine, afterSkipped).endState;
51
+ (0, chai_1.expect)(afterSecondSkipped).to.be.an.instanceOf(textmate_tokenizer_1.TokenizerState);
52
+ const { endState } = tokenizer.tokenizeEncoded('short', afterSecondSkipped);
53
+ (0, chai_1.expect)(endState).to.be.an.instanceOf(textmate_tokenizer_1.TokenizerState);
54
+ (0, chai_1.expect)(endState.stateStack).to.equal(initial.stateStack);
55
+ });
56
+ });
57
+ //# sourceMappingURL=textmate-tokenizer.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"textmate-tokenizer.spec.js","sourceRoot":"","sources":["../../../src/browser/textmate/textmate-tokenizer.spec.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "@theia/monaco",
3
- "version": "1.76.0-next.7+7c303b183",
3
+ "version": "1.76.0",
4
4
  "description": "Theia - Monaco Extension",
5
5
  "dependencies": {
6
- "@theia/core": "1.76.0-next.7+7c303b183",
7
- "@theia/editor": "1.76.0-next.7+7c303b183",
8
- "@theia/filesystem": "1.76.0-next.7+7c303b183",
9
- "@theia/markers": "1.76.0-next.7+7c303b183",
6
+ "@theia/core": "1.76.0",
7
+ "@theia/editor": "1.76.0",
8
+ "@theia/filesystem": "1.76.0",
9
+ "@theia/markers": "1.76.0",
10
10
  "@theia/monaco-editor-core": "1.108.201",
11
- "@theia/outline-view": "1.76.0-next.7+7c303b183",
12
- "@theia/workspace": "1.76.0-next.7+7c303b183",
11
+ "@theia/outline-view": "1.76.0",
12
+ "@theia/workspace": "1.76.0",
13
13
  "fast-plist": "^0.1.3",
14
14
  "idb": "^4.0.5",
15
15
  "jsonc-parser": "^3.3.1",
@@ -52,10 +52,10 @@
52
52
  "watch": "theiaext watch"
53
53
  },
54
54
  "devDependencies": {
55
- "@theia/ext-scripts": "1.75.0"
55
+ "@theia/ext-scripts": "1.76.0"
56
56
  },
57
57
  "nyc": {
58
58
  "extends": "../../configs/nyc.json"
59
59
  },
60
- "gitHead": "7c303b1836421183d7013f0bd679a9a30ff0b5dc"
60
+ "gitHead": "b9b54c500b46515512e2b44371bc0c7122947bed"
61
61
  }
@@ -0,0 +1,63 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2026 Matthew Farrow and others.
3
+ //
4
+ // This program and the accompanying materials are made available under the
5
+ // terms of the Eclipse Public License v. 2.0 which is available at
6
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+
17
+ import { expect } from 'chai';
18
+ import { IGrammar, StateStack } from 'vscode-textmate';
19
+ import { createTextmateTokenizer, TokenizerState } from './textmate-tokenizer';
20
+
21
+ describe('createTextmateTokenizer', () => {
22
+
23
+ // A grammar that hands back the rule stack it was given, so the tests only observe
24
+ // what the tokenizer itself does with the state.
25
+ const grammar = <IGrammar><unknown>{
26
+ tokenizeLine: (line: string, ruleStack: StateStack) => ({ tokens: [], ruleStack }),
27
+ tokenizeLine2: (line: string, ruleStack: StateStack) => ({ tokens: new Uint32Array(), ruleStack })
28
+ };
29
+
30
+ const tokenizer = createTextmateTokenizer(grammar, { lineLimit: 8 });
31
+ const longLine = 'x'.repeat(16);
32
+
33
+ // Monaco stores the end state and passes it into the next line. Returning anything
34
+ // other than a `TokenizerState` breaks the line after the skipped one: a short line
35
+ // silently restarts the grammar, and a second skipped line returns `undefined`,
36
+ // which Monaco rejects with 'Cannot set null/undefined state', stopping tokenization
37
+ // for the whole model.
38
+ it('should keep the state when tokenizeEncoded skips a line over the limit', () => {
39
+ const state = tokenizer.getInitialState();
40
+ const { endState } = tokenizer.tokenizeEncoded(longLine, state);
41
+ expect(endState).to.be.an.instanceOf(TokenizerState);
42
+ expect(endState).to.equal(state);
43
+ });
44
+
45
+ it('should keep the state when tokenize skips a line over the limit', () => {
46
+ const state = tokenizer.getInitialState();
47
+ const { endState } = tokenizer.tokenize(longLine, state);
48
+ expect(endState).to.be.an.instanceOf(TokenizerState);
49
+ expect(endState).to.equal(state);
50
+ });
51
+
52
+ it('should tokenize the line after a skipped one from the same state', () => {
53
+ const initial = tokenizer.getInitialState();
54
+ const afterSkipped = tokenizer.tokenizeEncoded(longLine, initial).endState;
55
+ // Two skipped lines in a row is where the broken state surfaced as an exception.
56
+ const afterSecondSkipped = tokenizer.tokenizeEncoded(longLine, afterSkipped).endState;
57
+ expect(afterSecondSkipped).to.be.an.instanceOf(TokenizerState);
58
+ const { endState } = tokenizer.tokenizeEncoded('short', afterSecondSkipped);
59
+ expect(endState).to.be.an.instanceOf(TokenizerState);
60
+ expect((<TokenizerState>endState).stateStack).to.equal((<TokenizerState>initial).stateStack);
61
+ });
62
+
63
+ });
@@ -40,7 +40,8 @@ export interface TokenizerOption {
40
40
 
41
41
  /**
42
42
  * Maximum line length that will be handled by the TextMate tokenizer. If the length of the actual line exceeds this
43
- * limit, the tokenizer terminates and the tokenization of any subsequent lines might be broken.
43
+ * limit, the line is skipped and tokenization continues from the preceding state. Constructs opened on a skipped
44
+ * line (e.g. a block comment) are therefore not accounted for.
44
45
  *
45
46
  * If the `lineLimit` is not defined, it means, there are no line length limits. Otherwise, it must be a positive
46
47
  * integer or an error will be thrown.
@@ -57,8 +58,10 @@ export function createTextmateTokenizer(grammar: IGrammar, options: TokenizerOpt
57
58
  getInitialState: () => new TokenizerState(INITIAL),
58
59
  tokenizeEncoded(line: string, state: TokenizerState): monaco.languages.IEncodedLineTokens {
59
60
  if (options.lineLimit !== undefined && line.length > options.lineLimit) {
60
- // Skip tokenizing the line if it exceeds the line limit.
61
- return { endState: state.stateStack, tokens: new Uint32Array() };
61
+ // Skip tokenizing the line if it exceeds the line limit. The state must be
62
+ // handed back as-is: `state.stateStack` is the raw `vscode-textmate` stack, and
63
+ // Monaco passes whatever is returned here straight into the next line.
64
+ return { endState: state, tokens: new Uint32Array() };
62
65
  }
63
66
  const result = grammar.tokenizeLine2(line, state.stateStack, 500);
64
67
  return {
@@ -68,8 +71,8 @@ export function createTextmateTokenizer(grammar: IGrammar, options: TokenizerOpt
68
71
  },
69
72
  tokenize(line: string, state: TokenizerState): monaco.languages.ILineTokens {
70
73
  if (options.lineLimit !== undefined && line.length > options.lineLimit) {
71
- // Skip tokenizing the line if it exceeds the line limit.
72
- return { endState: state.stateStack, tokens: [] };
74
+ // Skip tokenizing the line if it exceeds the line limit. See `tokenizeEncoded`.
75
+ return { endState: state, tokens: [] };
73
76
  }
74
77
  const result = grammar.tokenizeLine(line, state.stateStack, 500);
75
78
  return {