@@ -3,6 +3,7 @@ import type tslib from 'typescript/lib/tsserverlibrary'
3
3
import * as emmet from '@vscode/emmet-helper'
4
4
import isInBannedPosition from './isInBannedPosition'
5
5
import { GetConfig } from './types'
6
+ import { findChildContainingPosition } from './utils'
6
7
7
8
export type PrevCompletionMap = Record < string , { originalName ?: string ; documentationOverride ?: string | tslib . SymbolDisplayPart [ ] } >
8
9
@@ -14,7 +15,12 @@ export const getCompletionsAtPosition = (
14
15
languageService : ts . LanguageService ,
15
16
scriptSnapshot : ts . IScriptSnapshot ,
16
17
ts : typeof tslib ,
17
- ) => {
18
+ ) :
19
+ | {
20
+ completions : tslib . CompletionInfo
21
+ prevCompletionsMap : PrevCompletionMap
22
+ }
23
+ | undefined => {
18
24
const prevCompletionsMap : PrevCompletionMap = { }
19
25
const program = languageService . getProgram ( )
20
26
const sourceFile = program ?. getSourceFile ( fileName )
@@ -25,6 +31,10 @@ export const getCompletionsAtPosition = (
25
31
// 'raw prior',
26
32
// prior?.entries.map(entry => entry.name),
27
33
// )
34
+ const ensurePrior = ( ) => {
35
+ if ( ! prior ) prior = { entries : [ ] , isGlobalCompletion : false , isMemberCompletion : false , isNewIdentifierLocation : false }
36
+ return true
37
+ }
28
38
const node = findChildContainingPosition ( ts , sourceFile , position )
29
39
if ( [ '.jsx' , '.tsx' ] . some ( ext => fileName . endsWith ( ext ) ) ) {
30
40
// JSX Features
@@ -54,55 +64,56 @@ export const getCompletionsAtPosition = (
54
64
// const { textSpan } = proxy.getSmartSelectionRange(fileName, position)
55
65
// let existing = scriptSnapshot.getText(textSpan.start, textSpan.start + textSpan.length)
56
66
// if (existing.includes('\n')) existing = ''
57
- if ( ! prior ) prior = { entries : [ ] , isGlobalCompletion : false , isMemberCompletion : false , isNewIdentifierLocation : false }
58
- // if (existing.startsWith('.')) {
59
- // const className = existing.slice(1)
60
- // prior.entries.push({
61
- // kind: typescript.ScriptElementKind.label,
62
- // name: className,
63
- // sortText: '!5',
64
- // insertText: `<div className="${className}">$1</div>`,
65
- // isSnippet: true,
66
- // })
67
- // } else if (!existing[0] || existing[0].match(/\w/)) {
68
- if ( c ( 'jsxEmmet.type' ) === 'realEmmet' ) {
69
- const sendToEmmet = nodeText . split ( ' ' ) . at ( - 1 ) !
70
- const emmetCompletions = emmet . doComplete (
71
- {
72
- getText : ( ) => sendToEmmet ,
73
- languageId : 'html' ,
74
- lineCount : 1 ,
75
- offsetAt : position => position . character ,
76
- positionAt : offset => ( { line : 0 , character : offset } ) ,
77
- uri : '/' ,
78
- version : 1 ,
79
- } ,
80
- { line : 0 , character : sendToEmmet . length } ,
81
- 'html' ,
82
- { } ,
83
- ) ?? { items : [ ] }
84
- for ( const completion of emmetCompletions . items )
85
- prior . entries . push ( {
86
- kind : ts . ScriptElementKind . label ,
87
- name : completion . label . slice ( 1 ) ,
88
- sortText : '!5' ,
89
- // insertText: `${completion.label.slice(1)} ${completion.textEdit?.newText}`,
90
- insertText : completion . textEdit ?. newText ,
91
- isSnippet : true ,
92
- sourceDisplay : completion . detail !== undefined ? [ { kind : 'text' , text : completion . detail } ] : undefined ,
93
- // replacementSpan: { start: position - 5, length: 5 },
94
- } )
95
- } else {
96
- const tags = c ( 'jsxPseudoEmmet.tags' )
97
- for ( let [ tag , value ] of Object . entries ( tags ) ) {
98
- if ( value === true ) value = `<${ tag } >$1</${ tag } >`
99
- prior . entries . push ( {
100
- kind : ts . ScriptElementKind . label ,
101
- name : tag ,
102
- sortText : '!5' ,
103
- insertText : value ,
104
- isSnippet : true ,
105
- } )
67
+ if ( ensurePrior ( ) && prior ) {
68
+ // if (existing.startsWith('.')) {
69
+ // const className = existing.slice(1)
70
+ // prior.entries.push({
71
+ // kind: typescript.ScriptElementKind.label,
72
+ // name: className,
73
+ // sortText: '!5',
74
+ // insertText: `<div className="${className}">$1</div>`,
75
+ // isSnippet: true,
76
+ // })
77
+ // } else if (!existing[0] || existing[0].match(/\w/)) {
78
+ if ( c ( 'jsxEmmet.type' ) === 'realEmmet' ) {
79
+ const sendToEmmet = nodeText . split ( ' ' ) . at ( - 1 ) !
80
+ const emmetCompletions = emmet . doComplete (
81
+ {
82
+ getText : ( ) => sendToEmmet ,
83
+ languageId : 'html' ,
84
+ lineCount : 1 ,
85
+ offsetAt : position => position . character ,
86
+ positionAt : offset => ( { line : 0 , character : offset } ) ,
87
+ uri : '/' ,
88
+ version : 1 ,
89
+ } ,
90
+ { line : 0 , character : sendToEmmet . length } ,
91
+ 'html' ,
92
+ { } ,
93
+ ) ?? { items : [ ] }
94
+ for ( const completion of emmetCompletions . items )
95
+ prior . entries . push ( {
96
+ kind : ts . ScriptElementKind . label ,
97
+ name : completion . label . slice ( 1 ) ,
98
+ sortText : '!5' ,
99
+ // insertText: `${completion.label.slice(1)} ${completion.textEdit?.newText}`,
100
+ insertText : completion . textEdit ?. newText ,
101
+ isSnippet : true ,
102
+ sourceDisplay : completion . detail !== undefined ? [ { kind : 'text' , text : completion . detail } ] : undefined ,
103
+ // replacementSpan: { start: position - 5, length: 5 },
104
+ } )
105
+ } else {
106
+ const tags = c ( 'jsxPseudoEmmet.tags' )
107
+ for ( let [ tag , value ] of Object . entries ( tags ) ) {
108
+ if ( value === true ) value = `<${ tag } >$1</${ tag } >`
109
+ prior . entries . push ( {
110
+ kind : ts . ScriptElementKind . label ,
111
+ name : tag ,
112
+ sortText : '!5' ,
113
+ insertText : value ,
114
+ isSnippet : true ,
115
+ } )
116
+ }
106
117
}
107
118
}
108
119
}
@@ -235,16 +246,3 @@ const arrayMoveItemToFrom = <T>(array: T[], originalItem: ArrayPredicate<T>, ite
235
246
}
236
247
237
248
const patchText = ( input : string , start : number , end : number , newText : string ) => input . slice ( 0 , start ) + newText + input . slice ( end )
238
-
239
- function findChildContainingPosition (
240
- typescript : typeof import ( 'typescript/lib/tsserverlibrary' ) ,
241
- sourceFile : tslib . SourceFile ,
242
- position : number ,
243
- ) : tslib . Node | undefined {
244
- function find ( node : ts . Node ) : ts . Node | undefined {
245
- if ( position >= node . getStart ( ) && position < node . getEnd ( ) ) return typescript . forEachChild ( node , find ) || node
246
-
247
- return
248
- }
249
- return find ( sourceFile )
250
- }
0 commit comments