Files
echo-nexus/node_modules/@codemirror/lang-go/dist/index.js
T

233 lines
8.0 KiB
JavaScript

import { parser } from '@lezer/go';
import { syntaxTree, LRLanguage, indentNodeProp, continuedIndent, flatIndent, delimitedIndent, foldNodeProp, foldInside, LanguageSupport } from '@codemirror/language';
import { snippetCompletion, ifNotIn, completeFromList } from '@codemirror/autocomplete';
import { NodeWeakMap, IterMode } from '@lezer/common';
/**
A collection of Go-related [snippets](https://codemirror.net/6/docs/ref/#autocomplete.snippet).
*/
const snippets = [
/*@__PURE__*/snippetCompletion("func ${name}(${params}) ${type} {\n\t${}\n}", {
label: "func",
detail: "declaration",
type: "keyword"
}),
/*@__PURE__*/snippetCompletion("func (${receiver}) ${name}(${params}) ${type} {\n\t${}\n}", {
label: "func",
detail: "method declaration",
type: "keyword"
}),
/*@__PURE__*/snippetCompletion("var ${name} = ${value}", {
label: "var",
detail: "declaration",
type: "keyword"
}),
/*@__PURE__*/snippetCompletion("type ${name} ${type}", {
label: "type",
detail: "declaration",
type: "keyword"
}),
/*@__PURE__*/snippetCompletion("const ${name} = ${value}", {
label: "const",
detail: "declaration",
type: "keyword"
}),
/*@__PURE__*/snippetCompletion("type ${name} = ${type}", {
label: "type",
detail: "alias declaration",
type: "keyword"
}),
/*@__PURE__*/snippetCompletion("for ${init}; ${test}; ${update} {\n\t${}\n}", {
label: "for",
detail: "loop",
type: "keyword"
}),
/*@__PURE__*/snippetCompletion("for ${i} := range ${value} {\n\t${}\n}", {
label: "for",
detail: "range",
type: "keyword"
}),
/*@__PURE__*/snippetCompletion("select {\n\t${}\n}", {
label: "select",
detail: "statement",
type: "keyword"
}),
/*@__PURE__*/snippetCompletion("case ${}:\n${}", {
label: "case",
type: "keyword"
}),
/*@__PURE__*/snippetCompletion("switch ${} {\n\t${}\n}", {
label: "switch",
detail: "statement",
type: "keyword"
}),
/*@__PURE__*/snippetCompletion("switch ${}.(${type}) {\n\t${}\n}", {
label: "switch",
detail: "type statement",
type: "keyword"
}),
/*@__PURE__*/snippetCompletion("if ${} {\n\t${}\n}", {
label: "if",
detail: "block",
type: "keyword"
}),
/*@__PURE__*/snippetCompletion("if ${} {\n\t${}\n} else {\n\t${}\n}", {
label: "if",
detail: "/ else block",
type: "keyword"
}),
/*@__PURE__*/snippetCompletion("import ${name} \"${module}\"\n${}", {
label: "import",
detail: "declaration",
type: "keyword"
}),
];
const cache = /*@__PURE__*/new NodeWeakMap();
const ScopeNodes = /*@__PURE__*/new Set([
"SourceFile", "Block",
"FunctionDecl", "MethodDecl", "FunctionLiteral",
"ForStatement", "SwitchStatement", "TypeSwitchStatement", "IfStatement",
]);
function defIDs(type, spec) {
return (node, def) => {
outer: for (let cur = node.node.firstChild, depth = 0, parent = null;;) {
while (!cur) {
if (!depth)
break outer;
depth--;
cur = parent.nextSibling;
parent = parent.parent;
}
if (spec && cur.name == spec || cur.name == "SpecList") {
depth++;
parent = cur;
cur = cur.firstChild;
}
else {
if (cur.name == "DefName")
def(cur, type);
cur = cur.nextSibling;
}
}
return true;
};
}
const gatherCompletions = {
FunctionDecl: /*@__PURE__*/defIDs("function"),
VarDecl: /*@__PURE__*/defIDs("var", "VarSpec"),
ConstDecl: /*@__PURE__*/defIDs("constant", "ConstSpec"),
TypeDecl: /*@__PURE__*/defIDs("type", "TypeSpec"),
ImportDecl: /*@__PURE__*/defIDs("constant", "ImportSpec"),
Parameter: /*@__PURE__*/defIDs("var"),
__proto__: null
};
function getScope(doc, node) {
let cached = cache.get(node);
if (cached)
return cached;
let completions = [], top = true;
function def(node, type) {
let name = doc.sliceString(node.from, node.to);
completions.push({ label: name, type });
}
node.cursor(IterMode.IncludeAnonymous).iterate(node => {
if (top) {
top = false;
}
else if (node.name) {
let gather = gatherCompletions[node.name];
if (gather && gather(node, def) || ScopeNodes.has(node.name))
return false;
}
else if (node.to - node.from > 8192) {
// Allow caching for bigger internal nodes
for (let c of getScope(doc, node.node))
completions.push(c);
return false;
}
});
cache.set(node, completions);
return completions;
}
const Identifier = /^[\w$\xa1-\uffff][\w$\d\xa1-\uffff]*$/;
const dontComplete = [
"String", "LineComment", "BlockComment",
"DefName", "LabelName", "FieldName",
".", "?."
];
/**
Completion source that looks up locally defined names in Go code.
*/
const localCompletionSource = context => {
let inner = syntaxTree(context.state).resolveInner(context.pos, -1);
if (dontComplete.indexOf(inner.name) > -1)
return null;
let isWord = inner.name == "VariableName" ||
inner.to - inner.from < 20 && Identifier.test(context.state.sliceDoc(inner.from, inner.to));
if (!isWord && !context.explicit)
return null;
let options = [];
for (let pos = inner; pos; pos = pos.parent) {
if (ScopeNodes.has(pos.name))
options = options.concat(getScope(context.state.doc, pos));
}
return {
options,
from: isWord ? inner.from : context.pos,
validFor: Identifier
};
};
/**
A language provider based on the [Lezer Go
parser](https://github.com/lezer-parser/go), extended with
folding and indentation information.
*/
const goLanguage = /*@__PURE__*/LRLanguage.define({
name: "go",
parser: /*@__PURE__*/parser.configure({
props: [
/*@__PURE__*/indentNodeProp.add({
IfStatement: /*@__PURE__*/continuedIndent({ except: /^\s*({|else\b)/ }),
LabeledStatement: flatIndent,
"SwitchBlock SelectBlock": context => {
let after = context.textAfter, closed = /^\s*\}/.test(after), isCase = /^\s*(case|default)\b/.test(after);
return context.baseIndent + (closed || isCase ? 0 : context.unit);
},
Block: /*@__PURE__*/delimitedIndent({ closing: "}" }),
BlockComment: () => null,
Statement: /*@__PURE__*/continuedIndent({ except: /^{/ }),
}),
/*@__PURE__*/foldNodeProp.add({
"Block SwitchBlock SelectBlock LiteralValue InterfaceType StructType SpecList": foldInside,
BlockComment(tree) { return { from: tree.from + 2, to: tree.to - 2 }; }
})
]
}),
languageData: {
closeBrackets: { brackets: ["(", "[", "{", "'", '"', "`"] },
commentTokens: { line: "//", block: { open: "/*", close: "*/" } },
indentOnInput: /^\s*(?:case\b|default\b|\})$/
}
});
let kwCompletion = (name) => ({ label: name, type: "keyword" });
const keywords = /*@__PURE__*/"interface struct chan map package go return break continue goto fallthrough else defer range true false nil".split(" ").map(kwCompletion);
/**
Go support. Includes [snippet](https://codemirror.net/6/docs/ref/#lang-go.snippets) and local
variable completion.
*/
function go() {
let completions = snippets.concat(keywords);
return new LanguageSupport(goLanguage, [
goLanguage.data.of({
autocomplete: ifNotIn(dontComplete, completeFromList(completions))
}),
goLanguage.data.of({
autocomplete: localCompletionSource
})
]);
}
export { go, goLanguage, localCompletionSource, snippets };