Skip to content

Commit 3046778

Browse files
committed
fix(keywordsInsertText): don't include space to some keywords (e.g. const, void) in type contexts
1 parent 43fae3d commit 3046778

File tree

2 files changed

+56
-28
lines changed

2 files changed

+56
-28
lines changed
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
export default (entries: ts.CompletionEntry[], scriptSnapshot: ts.IScriptSnapshot, position: number, node) => {
2+
const charAhead = scriptSnapshot.getText(position, position + 1)
3+
if (charAhead === ' ') return entries
4+
const bannedKeywords = [
5+
'true',
6+
'false',
7+
'undefined',
8+
'null',
9+
'never',
10+
'unknown',
11+
'any',
12+
'symbol',
13+
'string',
14+
'number',
15+
'boolean',
16+
'object',
17+
'this',
18+
'catch',
19+
'constructor',
20+
'continue',
21+
'break',
22+
'debugger',
23+
'default',
24+
'super',
25+
'import',
26+
]
27+
const bannedKeywordsWhenInType = ['const', 'void', 'import']
28+
const inType = isTypeNode(node)
29+
return entries.map(entry => {
30+
if (entry.kind !== ts.ScriptElementKind.keyword || bannedKeywords.includes(entry.name) || (inType && bannedKeywordsWhenInType.includes(entry.name)))
31+
return entry
32+
return { ...entry, insertText: `${entry.name} ` }
33+
})
34+
}
35+
36+
const isTypeNode = (node: ts.Node) => {
37+
if (ts.isTypeNode(node)) {
38+
// built-in types
39+
return true
40+
}
41+
42+
if (inTypeReference(node)) return true
43+
44+
return false
45+
46+
function inTypeReference(node: ts.Node) {
47+
if (ts.isTypeReferenceNode(node)) {
48+
return true
49+
}
50+
51+
return node.parent && inTypeReference(node.parent)
52+
}
53+
}

typescript/src/completionsAtPosition.ts

Lines changed: 3 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import switchCaseExcludeCovered from './completions/switchCaseExcludeCovered'
1515
import additionalTypesSuggestions from './completions/additionalTypesSuggestions'
1616
import boostKeywordSuggestions from './completions/boostKeywordSuggestions'
1717
import boostTextSuggestions from './completions/boostNameSuggestions'
18+
import keywordsSpace from './completions/keywordsSpace'
1819

1920
export type PrevCompletionMap = Record<string, { originalName?: string; documentationOverride?: string | ts.SymbolDisplayPart[] }>
2021

@@ -48,6 +49,7 @@ export const getCompletionsAtPosition = (
4849
/** node that is one character behind
4950
* useful as in most cases we work with node that is behind the cursor */
5051
const leftNode = findChildContainingPosition(ts, sourceFile, position - 1)
52+
const tokenAtPosition = tsFull.getTokenAtPosition(sourceFile as any, position) as ts.Node
5153
if (['.jsx', '.tsx'].some(ext => fileName.endsWith(ext))) {
5254
// #region JSX tag improvements
5355
if (node) {
@@ -158,34 +160,7 @@ export const getCompletionsAtPosition = (
158160
})
159161

160162
if (c('suggestions.keywordsInsertText') === 'space') {
161-
const charAhead = scriptSnapshot.getText(position, position + 1)
162-
const bannedKeywords = [
163-
'true',
164-
'false',
165-
'undefined',
166-
'null',
167-
'never',
168-
'unknown',
169-
'any',
170-
'symbol',
171-
'string',
172-
'number',
173-
'boolean',
174-
'object',
175-
'this',
176-
'catch',
177-
'constructor',
178-
'continue',
179-
'break',
180-
'debugger',
181-
'default',
182-
'super',
183-
'import',
184-
]
185-
prior.entries = prior.entries.map(entry => {
186-
if (entry.kind !== ts.ScriptElementKind.keyword || charAhead === ' ' || bannedKeywords.includes(entry.name)) return entry
187-
return { ...entry, insertText: `${entry.name} ` }
188-
})
163+
prior.entries = keywordsSpace(prior.entries, scriptSnapshot, position, tokenAtPosition)
189164
}
190165

191166
if (leftNode && c('switchExcludeCoveredCases')) prior.entries = switchCaseExcludeCovered(prior.entries, position, sourceFile, leftNode) ?? prior.entries

0 commit comments

Comments
 (0)