-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathPostfixCompletionProvider.ts
82 lines (72 loc) · 2.96 KB
/
PostfixCompletionProvider.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
import type {CompletionProvider} from "@server/completion/CompletionProvider"
import {CompletionItemKind, InsertTextFormat} from "vscode-languageserver-types"
import type {CompletionContext} from "@server/completion/CompletionContext"
import {CompletionResult, CompletionWeight} from "@server/completion/WeightedCompletionItem"
import {asLspRange} from "@server/utils/position"
import type {Node as SyntaxNode} from "web-tree-sitter"
export class PostfixCompletionProvider implements CompletionProvider {
public isAvailable(ctx: CompletionContext): boolean {
return ctx.afterDot
}
public addCompletion(ctx: CompletionContext, result: CompletionResult): void {
this.postfix(ctx, "not", "Negate expression", "!$expr", result)
this.postfix(ctx, "call", "Use as function argument", "($expr)", result)
if (ctx.isSelectorExpressionInStatement) {
this.postfix(ctx, "if", "Create if statement", "if ($expr) {}", result)
this.postfix(ctx, "let", "Create variable", "let name = $expr;", result)
this.postfix(ctx, "repeat", "Create repeat loop", "repeat($expr) {}", result)
this.postfix(ctx, "do", "Create do-until loop", "do {} until ($expr);", result)
}
}
private postfix(
ctx: CompletionContext,
selector: string,
description: string,
snippet: string,
result: CompletionResult,
): void {
const expr = ctx.element.node.parent
if (expr?.type !== "field_access_expression") return
const object = expr.childForFieldName("object")
if (!object) return
const finalObject = this.unwrapParens(object)
if (!finalObject) return
const objectRange = asLspRange(object)
const replacedSnippet = snippet.replace("$expr", finalObject.text)
const preparedSnippet =
ctx.beforeSemicolon && snippet.endsWith(";")
? replacedSnippet.slice(0, -1)
: replacedSnippet
const realRange = {
start: objectRange.start,
end: {
line: objectRange.end.line,
character: objectRange.end.character + 1, // + `.`
},
}
result.add({
label: selector,
labelDetails: {
description: description,
},
insertText: "$0",
insertTextFormat: InsertTextFormat.Snippet,
kind: CompletionItemKind.Snippet,
additionalTextEdits: [
{
newText: preparedSnippet,
range: realRange,
},
],
textEditText: preparedSnippet,
weight: CompletionWeight.SNIPPET,
})
}
private unwrapParens(object: SyntaxNode | null): SyntaxNode | null {
if (!object) return null
if (object.type === "parenthesized_expression") {
return object.children[1] ?? null
}
return object
}
}