@@ -3,6 +3,7 @@ import type tslib from 'typescript/lib/tsserverlibrary'
33import * as emmet from '@vscode/emmet-helper'
44import isInBannedPosition from './isInBannedPosition'
55import { GetConfig } from './types'
6+ import { findChildContainingPosition } from './utils'
67
78export type PrevCompletionMap = Record < string , { originalName ?: string ; documentationOverride ?: string | tslib . SymbolDisplayPart [ ] } >
89
@@ -14,7 +15,12 @@ export const getCompletionsAtPosition = (
1415 languageService : ts . LanguageService ,
1516 scriptSnapshot : ts . IScriptSnapshot ,
1617 ts : typeof tslib ,
17- ) => {
18+ ) :
19+ | {
20+ completions : tslib . CompletionInfo
21+ prevCompletionsMap : PrevCompletionMap
22+ }
23+ | undefined => {
1824 const prevCompletionsMap : PrevCompletionMap = { }
1925 const program = languageService . getProgram ( )
2026 const sourceFile = program ?. getSourceFile ( fileName )
@@ -25,6 +31,10 @@ export const getCompletionsAtPosition = (
2531 // 'raw prior',
2632 // prior?.entries.map(entry => entry.name),
2733 // )
34+ const ensurePrior = ( ) => {
35+ if ( ! prior ) prior = { entries : [ ] , isGlobalCompletion : false , isMemberCompletion : false , isNewIdentifierLocation : false }
36+ return true
37+ }
2838 const node = findChildContainingPosition ( ts , sourceFile , position )
2939 if ( [ '.jsx' , '.tsx' ] . some ( ext => fileName . endsWith ( ext ) ) ) {
3040 // JSX Features
@@ -54,55 +64,56 @@ export const getCompletionsAtPosition = (
5464 // const { textSpan } = proxy.getSmartSelectionRange(fileName, position)
5565 // let existing = scriptSnapshot.getText(textSpan.start, textSpan.start + textSpan.length)
5666 // 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+ }
106117 }
107118 }
108119 }
@@ -235,16 +246,3 @@ const arrayMoveItemToFrom = <T>(array: T[], originalItem: ArrayPredicate<T>, ite
235246}
236247
237248const 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