@@ -3,6 +3,7 @@ import { Disposable } from '@/utils/disposable'
33import Emitter from '@/utils/emitter'
44import { insertSpaces , tabSize } from '@/utils/spx/highlighter'
55import type { I18n } from '@/utils/i18n'
6+ import { packageSpx } from '@/utils/spx'
67import type { Runtime } from '@/models/runtime'
78import type { Project } from '@/models/project'
89import { Copilot } from './copilot'
@@ -24,15 +25,19 @@ import {
2425 type IContextMenuProvider ,
2526 type IHoverProvider ,
2627 builtInCommandRename ,
27- type MenuItem
28+ type MenuItem ,
29+ type ICompletionProvider ,
30+ type CompletionContext ,
31+ type CompletionItem ,
32+ InsertTextFormat ,
33+ CompletionItemKind
2834} from './ui/code-editor-ui'
2935import {
3036 type Action ,
3137 type DefinitionDocumentationItem ,
3238 type DefinitionDocumentationString ,
3339 type Diagnostic ,
3440 makeAdvancedMarkdownString ,
35- stringifyDefinitionId ,
3641 selection2Range ,
3742 toLSPPosition ,
3843 fromLSPRange ,
@@ -49,19 +54,12 @@ import {
4954 type Selection ,
5055 type CommandArgs ,
5156 getTextDocumentId ,
52- containsPosition
57+ containsPosition ,
58+ makeBasicMarkdownString
5359} from './common'
54- import * as spxDocumentationItems from './document-base/spx'
55- import * as gopDocumentationItems from './document-base/gop'
5660import { TextDocument , createTextDocument } from './text-document'
5761import { type Monaco } from './monaco'
5862
59- // mock data for test
60- const allItems = Object . values ( {
61- ...spxDocumentationItems ,
62- ...gopDocumentationItems
63- } )
64-
6563class ResourceReferencesProvider
6664 extends Emitter < {
6765 didChangeResourceReferences : [ ] // TODO
@@ -226,6 +224,94 @@ class HoverProvider implements IHoverProvider {
226224 }
227225}
228226
227+ class CompletionProvider implements ICompletionProvider {
228+ constructor (
229+ private lspClient : SpxLSPClient ,
230+ private documentBase : DocumentBase
231+ ) { }
232+
233+ private getCompletionItemKind ( kind : lsp . CompletionItemKind | undefined ) : CompletionItemKind {
234+ switch ( kind ) {
235+ case lsp . CompletionItemKind . Method :
236+ case lsp . CompletionItemKind . Function :
237+ case lsp . CompletionItemKind . Constructor :
238+ return CompletionItemKind . Function
239+ case lsp . CompletionItemKind . Field :
240+ case lsp . CompletionItemKind . Variable :
241+ case lsp . CompletionItemKind . Property :
242+ return CompletionItemKind . Variable
243+ case lsp . CompletionItemKind . Interface :
244+ case lsp . CompletionItemKind . Enum :
245+ case lsp . CompletionItemKind . Struct :
246+ case lsp . CompletionItemKind . TypeParameter :
247+ return CompletionItemKind . Type
248+ case lsp . CompletionItemKind . Module :
249+ return CompletionItemKind . Package
250+ case lsp . CompletionItemKind . Keyword :
251+ case lsp . CompletionItemKind . Operator :
252+ return CompletionItemKind . Statement
253+ case lsp . CompletionItemKind . EnumMember :
254+ case lsp . CompletionItemKind . Text :
255+ case lsp . CompletionItemKind . Constant :
256+ return CompletionItemKind . Constant
257+ default :
258+ return CompletionItemKind . Unknown
259+ }
260+ }
261+
262+ private getInsertTextFormat ( insertTextFormat : lsp . InsertTextFormat | undefined ) : InsertTextFormat {
263+ switch ( insertTextFormat ) {
264+ case lsp . InsertTextFormat . Snippet :
265+ return InsertTextFormat . Snippet
266+ default :
267+ return InsertTextFormat . PlainText
268+ }
269+ }
270+
271+ async provideCompletion ( ctx : CompletionContext , position : Position ) : Promise < CompletionItem [ ] > {
272+ const items = await this . lspClient . getCompletionItems ( {
273+ textDocument : ctx . textDocument . id ,
274+ position : toLSPPosition ( position )
275+ } )
276+ const maybeItems = await Promise . all (
277+ items . map ( async ( item ) => {
278+ const result : CompletionItem = {
279+ label : item . label ,
280+ kind : this . getCompletionItemKind ( item . kind ) ,
281+ insertText : item . label ,
282+ insertTextFormat : InsertTextFormat . PlainText ,
283+ documentation : null
284+ }
285+
286+ const defId = item . data ?. definition
287+ const definition = defId != null ? await this . documentBase . getDocumentation ( defId ) : null
288+
289+ // Skip APIs from spx while without documentation, they are assumed not recommended
290+ if ( defId != null && defId . package === packageSpx && definition == null ) return null
291+
292+ if ( definition != null ) {
293+ result . kind = definition . kind
294+ result . insertText = definition . insertText
295+ result . insertTextFormat = InsertTextFormat . Snippet
296+ result . documentation = makeBasicMarkdownString ( definition . overview )
297+ }
298+
299+ if ( item . documentation != null ) {
300+ const docStr = lsp . MarkupContent . is ( item . documentation ) ? item . documentation . value : item . documentation
301+ result . documentation = makeAdvancedMarkdownString ( docStr )
302+ }
303+
304+ if ( item . insertText != null ) {
305+ result . insertText = item . insertText
306+ result . insertTextFormat = this . getInsertTextFormat ( item . insertTextFormat )
307+ }
308+ return result
309+ } )
310+ )
311+ return maybeItems . filter ( ( item ) => item != null ) as CompletionItem [ ]
312+ }
313+ }
314+
229315class ContextMenuProvider implements IContextMenuProvider {
230316 constructor (
231317 private lspClient : SpxLSPClient ,
@@ -435,26 +521,7 @@ export class CodeEditor extends Disposable {
435521 }
436522 } )
437523
438- ui . registerCompletionProvider ( {
439- async provideCompletion ( ctx , position ) {
440- console . warn ( 'TODO' , ctx , position )
441- await new Promise < void > ( ( resolve ) => setTimeout ( resolve , 100 ) )
442- ctx . signal . throwIfAborted ( )
443- return allItems . map ( ( item ) => ( {
444- label : item . definition
445- . name ! . split ( '.' )
446- . pop ( ) !
447- . replace ( / ^ ./ , ( c ) => c . toLowerCase ( ) ) ,
448- kind : item . kind ,
449- insertText : item . insertText ,
450- documentation : makeAdvancedMarkdownString ( `
451- <definition-item overview="${ item . overview } " def-id="${ stringifyDefinitionId ( item . definition ) } ">
452- </definition-item>
453- ` )
454- } ) )
455- }
456- } )
457-
524+ ui . registerCompletionProvider ( new CompletionProvider ( this . lspClient , documentBase ) )
458525 ui . registerContextMenuProvider ( new ContextMenuProvider ( lspClient , documentBase ) )
459526 ui . registerCopilot ( copilot )
460527 ui . registerDiagnosticsProvider ( this . diagnosticsProvider )
0 commit comments