|
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