Skip to content

Commit 238ff90

Browse files
committed
fix: correctly pass range of string completions from plugin (affects completions with space)
1 parent 65a27ae commit 238ff90

File tree

6 files changed

+48
-33
lines changed

6 files changed

+48
-33
lines changed

typescript/src/completions/additionalTypesSuggestions.ts

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
import { buildStringCompletion } from '../utils'
2+
13
export default (entries: ts.CompletionEntry[], program: ts.Program, node: ts.Node) => {
24
if (!ts.isStringLiteral(node)) return
5+
const stringNode = node
36
const typeChecker = program.getTypeChecker()
47
if (ts.isLiteralTypeNode(node.parent)) {
58
node = node.parent
@@ -17,11 +20,12 @@ export default (entries: ts.CompletionEntry[], program: ts.Program, node: ts.Nod
1720
const type = typeChecker.getTypeFromTypeNode(node.parent.typeArguments[0]!)
1821
type.getProperties().forEach(({ name }) => {
1922
if (previousValues.includes(name)) return
20-
entries.push({
21-
name,
22-
kind: ts.ScriptElementKind.string,
23-
sortText: '',
24-
})
23+
entries.push(
24+
buildStringCompletion(stringNode, {
25+
name,
26+
sortText: '',
27+
}),
28+
)
2529
})
2630
return
2731
}
@@ -34,10 +38,10 @@ export default (entries: ts.CompletionEntry[], program: ts.Program, node: ts.Nod
3438
const { types } = (type as any) ?? {}
3539
const values: string[] = types.map(({ value }) => (typeof value === 'string' ? value : undefined)).filter(Boolean)
3640
return values.map(
37-
(value): ts.CompletionEntry => ({
38-
name: value,
39-
kind: ts.ScriptElementKind.string,
40-
sortText: '',
41-
}),
41+
(value): ts.CompletionEntry =>
42+
buildStringCompletion(stringNode, {
43+
name: value,
44+
sortText: '',
45+
}),
4246
)
4347
}

typescript/src/inKeywordCompletions.ts renamed to typescript/src/completions/inKeywordCompletions.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1-
export default (position: number, node: ts.Node | undefined, sourceFile: ts.SourceFile, program: ts.Program, languageService: ts.LanguageService) => {
1+
import { sharedCompletionContext } from './sharedContext'
2+
import { buildStringCompletion } from '../utils'
3+
4+
export default () => {
5+
const { node, program } = sharedCompletionContext
26
if (!node) return
37
function isBinaryExpression(node: ts.Node): node is ts.BinaryExpression {
48
return node.kind === ts.SyntaxKind.BinaryExpression
59
}
610
const typeChecker = program.getTypeChecker()
7-
// TODO info diagnostic if used that doesn't exist
811
if (
912
ts.isStringLiteralLike(node) &&
1013
isBinaryExpression(node.parent) &&
@@ -48,14 +51,15 @@ export default (position: number, node: ts.Node | undefined, sourceFile: ts.Sour
4851
.map(([originaName, { insertText, usingDisplayIndexes, documentations }], i) => {
4952
const name = types.length > 1 && usingDisplayIndexes.length === 1 ? `☆${originaName}` : originaName
5053
docPerCompletion[name] = documentations.join('\n\n')
51-
return {
54+
return buildStringCompletion(node, {
5255
// ⚀ ⚁ ⚂ ⚃ ⚄ ⚅
5356
name,
54-
kind: ts.ScriptElementKind.string,
57+
labelDetails: {
58+
description: usingDisplayIndexes.join(', '),
59+
},
5560
insertText,
56-
sourceDisplay: [{ kind: 'text', text: usingDisplayIndexes.join(', ') }],
5761
sortText: `${maxUsingDisplayIndex - usingDisplayIndexes.length}_${i}`,
58-
}
62+
})
5963
})
6064
.sort((a, b) => a.sortText.localeCompare(b.sortText))
6165
return {

typescript/src/completions/indexSignatureAccess.ts

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
export default (
2-
position: number,
3-
node: ts.Node | undefined,
4-
scriptSnapshot: ts.IScriptSnapshot,
5-
sourceFile: ts.SourceFile,
6-
program: ts.Program,
7-
): ts.CompletionEntry[] => {
1+
import { buildStringCompletion } from '../utils'
2+
import { sharedCompletionContext } from './sharedContext'
3+
4+
export default (): ts.CompletionEntry[] => {
5+
const { node, program } = sharedCompletionContext
86
if (!node || !ts.isStringLiteralLike(node)) return []
97
const isConditionalExpression = ts.isConditionalExpression(node.parent)
108
// optimize?
@@ -24,11 +22,10 @@ export default (
2422
}
2523
}
2624
return (type.getProperties?.() ?? []).map((prop, i) => {
27-
return {
28-
kind: ts.ScriptElementKind.string,
25+
return buildStringCompletion(node, {
2926
name: prop.name,
3027
// derang completions used on other side
3128
sortText: prop.name === usedProp ? '9999' : '',
32-
}
29+
})
3330
})
3431
}

typescript/src/completions/stringTemplateType.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import { compact } from '@zardoy/utils'
22
import { sharedCompletionContext } from './sharedContext'
3+
import { buildStringCompletion } from '../utils'
34

45
export default (): ts.CompletionEntry[] | void => {
56
const { program } = sharedCompletionContext
67
let { node } = sharedCompletionContext
78
if (!node || !ts.isStringLiteralLike(node)) return
9+
const stringNode = node
810
const checker = program.getTypeChecker()!
911
let type: ts.Type
1012
let objType: ts.Type | undefined
@@ -31,13 +33,12 @@ export default (): ts.CompletionEntry[] | void => {
3133
} = type as ts.TemplateLiteralType
3234
const texts = [head!, ...spans.flatMap(span => (span === '' ? [''] : ['', span]))]
3335
let tabStop = 1
34-
return {
35-
kind: ts.ScriptElementKind.string,
36+
return buildStringCompletion(stringNode, {
3637
name: texts.map(text => (text === '' ? '|' : text)).join(''),
3738
sortText: '07',
3839
insertText: texts.map(text => (text === '' ? `$${tabStop++}` : text.replace(/\$/g, '\\$'))).join(''),
3940
isSnippet: true,
40-
}
41+
})
4142
}),
4243
)
4344
}

typescript/src/completionsAtPosition.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import _ from 'lodash'
2-
import inKeywordCompletions from './inKeywordCompletions'
2+
import inKeywordCompletions from './completions/inKeywordCompletions'
33
// import * as emmet from '@vscode/emmet-helper'
44
import isInBannedPosition from './completions/isInBannedPosition'
55
import { GetConfig } from './types'
@@ -138,7 +138,7 @@ export const getCompletionsAtPosition = (
138138
if (node && !hasSuggestions && ensurePrior() && prior) {
139139
prior.entries = additionalTypesSuggestions(prior.entries, program, node) ?? prior.entries
140140
}
141-
const addSignatureAccessCompletions = hasSuggestions ? [] : indexSignatureAccessCompletions(position, node, scriptSnapshot, sourceFile, program)
141+
const addSignatureAccessCompletions = hasSuggestions ? [] : indexSignatureAccessCompletions()
142142
if (addSignatureAccessCompletions.length && ensurePrior() && prior) {
143143
prior.entries = [...prior.entries, ...addSignatureAccessCompletions]
144144
}
@@ -235,7 +235,7 @@ export const getCompletionsAtPosition = (
235235
// 90%
236236
prior.entries = adjustAutoImports(prior.entries)
237237

238-
const inKeywordCompletionsResult = inKeywordCompletions(position, node, sourceFile, program, languageService)
238+
const inKeywordCompletionsResult = inKeywordCompletions()
239239
if (inKeywordCompletionsResult) {
240240
prior.entries.push(...inKeywordCompletionsResult.completions)
241241
Object.assign(

typescript/src/utils.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { SetOptional } from 'type-fest'
1+
import { Except, SetOptional } from 'type-fest'
22
import * as semver from 'semver'
33

44
export function findChildContainingPosition(typescript: typeof ts, sourceFile: ts.SourceFile, position: number): ts.Node | undefined {
@@ -117,6 +117,15 @@ export const boostExistingSuggestions = (entries: ts.CompletionEntry[], predicat
117117
})
118118
}
119119

120+
export const buildStringCompletion = (node: ts.StringLiteralLike, completion: Except<ts.CompletionEntry, 'kind'>): ts.CompletionEntry => {
121+
const start = node.pos + node.getLeadingTriviaWidth() + 1
122+
return {
123+
...completion,
124+
kind: ts.ScriptElementKind.string,
125+
replacementSpan: ts.createTextSpanFromBounds(start, node.end - 1),
126+
}
127+
}
128+
120129
// semver: can't use compare as it incorrectly works with build postfix
121130
export const isTs5 = () => semver.major(ts.version) >= 5
122131

0 commit comments

Comments
 (0)