Skip to content

Commit f2c9bcd

Browse files
committed
feat(lsp): add completion method to LSPManager
Add code completion support with textDocument/completion: - completion(): Get code completion suggestions at a position - CompletionItemKind enum for completion item types - CompletionItem and CompletionList types Follows LSP 3.17 specification with support for: - CompletionList and CompletionItem[] response formats - Type guards for runtime checking Closes #15
1 parent 8117688 commit f2c9bcd

1 file changed

Lines changed: 125 additions & 0 deletions

File tree

packages/lsp/src/index.ts

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,64 @@ export const LocationLinkSchema = z.object({
5959
})
6060
export type LocationLink = z.infer<typeof LocationLinkSchema>
6161

62+
/**
63+
* Completion item kind mapping
64+
* @see https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#completionItemKind
65+
*/
66+
export enum CompletionItemKind {
67+
Text = 1,
68+
Method = 2,
69+
Function = 3,
70+
Constructor = 4,
71+
Field = 5,
72+
Variable = 6,
73+
Class = 7,
74+
Interface = 8,
75+
Module = 9,
76+
Property = 10,
77+
Unit = 11,
78+
Value = 12,
79+
Enum = 13,
80+
Keyword = 14,
81+
Snippet = 15,
82+
Color = 16,
83+
File = 17,
84+
Reference = 18,
85+
Folder = 19,
86+
EnumMember = 20,
87+
Constant = 21,
88+
Struct = 22,
89+
Event = 23,
90+
Operator = 24,
91+
TypeParameter = 25,
92+
}
93+
94+
/**
95+
* LSP CompletionItem schema
96+
* A completion item represents a text snippet that is proposed to complete text being typed.
97+
*/
98+
export const CompletionItemSchema = z.object({
99+
label: z.string(),
100+
kind: z.number().optional(),
101+
detail: z.string().optional(),
102+
documentation: z.union([z.string(), z.object({ kind: z.string(), value: z.string() })]).optional(),
103+
sortText: z.string().optional(),
104+
filterText: z.string().optional(),
105+
insertText: z.string().optional(),
106+
insertTextFormat: z.number().optional(),
107+
})
108+
export type CompletionItem = z.infer<typeof CompletionItemSchema>
109+
110+
/**
111+
* LSP CompletionList schema
112+
* Represents a collection of completion items to be presented in the editor.
113+
*/
114+
export const CompletionListSchema = z.object({
115+
isIncomplete: z.boolean(),
116+
items: z.array(CompletionItemSchema),
117+
})
118+
export type CompletionList = z.infer<typeof CompletionListSchema>
119+
62120
/**
63121
* LSP Symbol schema
64122
*/
@@ -459,6 +517,73 @@ export class LSPManager {
459517
return results.flat()
460518
}
461519

520+
/**
521+
* Get code completion suggestions at the given position
522+
*
523+
* @see https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
524+
*/
525+
async completion(input: {
526+
file: string
527+
line: number
528+
character: number
529+
}): Promise<CompletionItem[]> {
530+
const clients = await this.getClients(input.file)
531+
532+
const results = await Promise.all(
533+
clients.map(client =>
534+
client.connection
535+
.sendRequest('textDocument/completion', {
536+
textDocument: {
537+
uri: pathToFileURL(input.file).href,
538+
},
539+
position: {
540+
line: input.line,
541+
character: input.character,
542+
},
543+
})
544+
.then((result: unknown) => this.normalizeCompletions(result))
545+
.catch(() => []),
546+
),
547+
)
548+
549+
return results.flat()
550+
}
551+
552+
/**
553+
* Normalize completion response to CompletionItem[]
554+
* Handles CompletionList and CompletionItem[] responses
555+
*/
556+
private normalizeCompletions(result: unknown): CompletionItem[] {
557+
if (!result)
558+
return []
559+
560+
// CompletionList format
561+
if (this.isCompletionList(result)) {
562+
return result.items
563+
}
564+
565+
// Direct CompletionItem[] format
566+
if (Array.isArray(result)) {
567+
return result.filter((item): item is CompletionItem =>
568+
typeof item === 'object' && item !== null && 'label' in item,
569+
)
570+
}
571+
572+
return []
573+
}
574+
575+
/**
576+
* Type guard for CompletionList
577+
*/
578+
private isCompletionList(obj: unknown): obj is CompletionList {
579+
return (
580+
typeof obj === 'object'
581+
&& obj !== null
582+
&& 'items' in obj
583+
&& Array.isArray((obj as CompletionList).items)
584+
)
585+
}
586+
462587
/**
463588
* Normalize definition response to Location[]
464589
* Handles Location, Location[], and LocationLink[] responses

0 commit comments

Comments
 (0)