|
1 |
| -import { ParserRuleContext } from 'antlr4ng'; |
| 1 | +import { ParserRuleContext, Token } from 'antlr4ng'; |
2 | 2 | import { EntityContextType } from './types';
|
3 | 3 | import { WordPosition, TextPosition } from './textAndWord';
|
4 | 4 | import { ctxToText, ctxToWord } from './textAndWord';
|
@@ -96,15 +96,17 @@ export function toEntityContext(
|
96 | 96 | * @todo: [may be need] Combine the entities in each clause.
|
97 | 97 | */
|
98 | 98 | export abstract class EntityCollector {
|
99 |
| - constructor(input: string, caretTokenIndex?: number) { |
| 99 | + constructor(input: string, allTokens?: Token[], caretTokenIndex?: number) { |
100 | 100 | this._input = input;
|
| 101 | + this._allTokens = allTokens || []; |
101 | 102 | this._caretTokenIndex = caretTokenIndex ?? -1;
|
102 | 103 | this._entitiesSet = new Set();
|
103 | 104 | this._stmtStack = new SimpleStack();
|
104 | 105 | this._entityStack = new SimpleStack();
|
105 | 106 | this._rootStmt = null;
|
106 | 107 | }
|
107 | 108 | private readonly _input: string;
|
| 109 | + private readonly _allTokens: Token[]; |
108 | 110 | private readonly _caretTokenIndex: number;
|
109 | 111 | private readonly _entitiesSet: Set<EntityContext>;
|
110 | 112 | /** Staging statements that have already entered. */
|
@@ -136,14 +138,31 @@ export abstract class EntityCollector {
|
136 | 138 | this._rootStmt = null;
|
137 | 139 | }
|
138 | 140 |
|
| 141 | + /** |
| 142 | + * The antlr4 will ignore hidden tokens, if we type whitespace at the end of a statement, |
| 143 | + * the whitespace token will not as stop token, so we consider the whitespace token as a part of the nonhidden token in front of it |
| 144 | + */ |
| 145 | + protected getPrevNonHiddenTokenIndex(caretTokenIndex: number) { |
| 146 | + if (this._allTokens[caretTokenIndex].channel !== Token.HIDDEN_CHANNEL) |
| 147 | + return caretTokenIndex; |
| 148 | + for (let i = caretTokenIndex - 1; i >= 0; i--) { |
| 149 | + const token = this._allTokens[i]; |
| 150 | + if (token.channel !== Token.HIDDEN_CHANNEL) { |
| 151 | + // If prev nonhidden token is ';', the current token does not belong to any statement. |
| 152 | + return token.text === ';' ? Infinity : token.tokenIndex; |
| 153 | + } |
| 154 | + } |
| 155 | + return Infinity; |
| 156 | + } |
| 157 | + |
139 | 158 | protected pushStmt(ctx: ParserRuleContext, type: StmtContextType) {
|
140 | 159 | let isContainCaret: boolean | undefined;
|
141 | 160 | if (this._caretTokenIndex >= 0) {
|
142 | 161 | isContainCaret =
|
143 | 162 | !!ctx.start &&
|
144 | 163 | !!ctx.stop &&
|
145 | 164 | ctx.start.tokenIndex <= this._caretTokenIndex &&
|
146 |
| - ctx.stop.tokenIndex >= this._caretTokenIndex; |
| 165 | + ctx.stop.tokenIndex >= this.getPrevNonHiddenTokenIndex(this._caretTokenIndex); |
147 | 166 | }
|
148 | 167 | const stmtContext = toStmtContext(
|
149 | 168 | ctx,
|
|
0 commit comments