notes/coc/extensions/node_modules/coc-snippets/lib/index.js

2901 lines
92 KiB
JavaScript

var __create = Object.create;
var __defProp = Object.defineProperty;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __markAsModule = (target) => __defProp(target, "__esModule", {value: true});
var __commonJS = (callback, module2) => () => {
if (!module2) {
module2 = {exports: {}};
callback(module2.exports, module2);
}
return module2.exports;
};
var __export = (target, all) => {
__markAsModule(target);
for (var name in all)
__defProp(target, name, {get: all[name], enumerable: true});
};
var __exportStar = (target, module2, desc) => {
__markAsModule(target);
if (module2 && typeof module2 === "object" || typeof module2 === "function") {
for (let key of __getOwnPropNames(module2))
if (!__hasOwnProp.call(target, key) && key !== "default")
__defProp(target, key, {get: () => module2[key], enumerable: !(desc = __getOwnPropDesc(module2, key)) || desc.enumerable});
}
return target;
};
var __toModule = (module2) => {
if (module2 && module2.__esModule)
return module2;
return __exportStar(__defProp(module2 != null ? __create(__getProtoOf(module2)) : {}, "default", {value: module2, enumerable: true}), module2);
};
// node_modules/pify/index.js
var require_pify = __commonJS((exports2, module2) => {
"use strict";
var processFn = (fn, options, proxy, unwrapped) => function(...arguments_) {
const P = options.promiseModule;
return new P((resolve, reject) => {
if (options.multiArgs) {
arguments_.push((...result) => {
if (options.errorFirst) {
if (result[0]) {
reject(result);
} else {
result.shift();
resolve(result);
}
} else {
resolve(result);
}
});
} else if (options.errorFirst) {
arguments_.push((error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
}
});
} else {
arguments_.push(resolve);
}
const self = this === proxy ? unwrapped : this;
Reflect.apply(fn, self, arguments_);
});
};
var filterCache = new WeakMap();
module2.exports = (input, options) => {
options = {
exclude: [/.+(?:Sync|Stream)$/],
errorFirst: true,
promiseModule: Promise,
...options
};
const objectType = typeof input;
if (!(input !== null && (objectType === "object" || objectType === "function"))) {
throw new TypeError(`Expected \`input\` to be a \`Function\` or \`Object\`, got \`${input === null ? "null" : objectType}\``);
}
const filter = (target, key) => {
let cached = filterCache.get(target);
if (!cached) {
cached = {};
filterCache.set(target, cached);
}
if (key in cached) {
return cached[key];
}
const match = (pattern) => typeof pattern === "string" || typeof key === "symbol" ? key === pattern : pattern.test(key);
const desc = Reflect.getOwnPropertyDescriptor(target, key);
const writableOrConfigurableOwn = desc === void 0 || desc.writable || desc.configurable;
const included = options.include ? options.include.some(match) : !options.exclude.some(match);
const shouldFilter = included && writableOrConfigurableOwn;
cached[key] = shouldFilter;
return shouldFilter;
};
const cache = new WeakMap();
const proxy = new Proxy(input, {
apply(target, thisArg, args) {
const cached = cache.get(target);
if (cached) {
return Reflect.apply(cached, thisArg, args);
}
const pified = options.excludeMain ? target : processFn(target, options, proxy, target);
cache.set(target, pified);
return Reflect.apply(pified, thisArg, args);
},
get(target, key) {
const property = target[key];
if (!filter(target, key) || property === Function.prototype[key]) {
return property;
}
const cached = cache.get(property);
if (cached) {
return cached;
}
if (typeof property === "function") {
const pified = processFn(property, options, proxy, target);
cache.set(property, pified);
return pified;
}
return property;
}
});
return proxy;
};
});
// src/index.ts
__export(exports, {
activate: () => activate
});
var import_coc10 = __toModule(require("coc.nvim"));
var import_fs6 = __toModule(require("fs"));
var import_os4 = __toModule(require("os"));
var import_path5 = __toModule(require("path"));
var import_util9 = __toModule(require("util"));
// src/languages.ts
var import_coc = __toModule(require("coc.nvim"));
// src/util.ts
var import_pify = __toModule(require_pify());
var import_fs = __toModule(require("fs"));
var import_crypto = __toModule(require("crypto"));
var BASE64 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_";
function tostr(bytes) {
let r = [];
let i;
for (i = 0; i < bytes.length; i++) {
r.push(BASE64[bytes[i] % 64]);
}
return r.join("");
}
function uid() {
return tostr(import_crypto.default.randomBytes(10));
}
async function statAsync(filepath) {
try {
return await import_pify.default(import_fs.default.stat)(filepath);
} catch (e) {
return null;
}
}
async function readFileAsync(fullpath, encoding = "utf8") {
return await import_pify.default(import_fs.default.readFile)(fullpath, encoding);
}
async function readdirAsync(filepath) {
try {
return await import_pify.default(import_fs.default.readdir)(filepath);
} catch (e) {
return null;
}
}
function headTail(line) {
line = line.trim();
let ms = line.match(/^(\S+)\s+(.*)/);
if (!ms)
return [line, ""];
return [ms[1], ms[2]];
}
function distinct(array, keyFn) {
if (!keyFn) {
return array.filter((element, position) => {
return array.indexOf(element) === position;
});
}
const seen = Object.create(null);
return array.filter((elem) => {
const key = keyFn(elem);
if (seen[key]) {
return false;
}
seen[key] = true;
return true;
});
}
var conditionRe = /\(\?\(\?:\w+\).+\|/;
var bellRe = /\\a/;
var commentRe = /\(\?#.*?\)/;
var stringStartRe = /\\A/;
var namedCaptureRe = /\(\?P<\w+>.*?\)/;
var namedReferenceRe = /\(\?P=(\w+)\)/;
var braceRe = /\^\]/;
var regex = new RegExp(`${bellRe.source}|${commentRe.source}|${stringStartRe.source}|${namedCaptureRe.source}|${namedReferenceRe.source}|${braceRe}`, "g");
function convertRegex(str) {
if (str.indexOf("\\z") !== -1) {
throw new Error("pattern \\z not supported");
}
if (str.indexOf("(?s)") !== -1) {
throw new Error("pattern (?s) not supported");
}
if (str.indexOf("(?x)") !== -1) {
throw new Error("pattern (?x) not supported");
}
if (str.indexOf("\n") !== -1) {
throw new Error("multiple line pattern not supported");
}
if (conditionRe.test(str)) {
throw new Error("condition pattern not supported");
}
return str.replace(regex, (match, p1) => {
if (match == "^]")
return "^\\]";
if (match == "\\a")
return "";
if (match.startsWith("(?#"))
return "";
if (match == "\\A")
return "^";
if (match.startsWith("(?P<"))
return "(?" + match.slice(3);
if (match.startsWith("(?P="))
return `\\k<${p1}>`;
return "";
});
}
function getRegexText(prefix) {
if (prefix.startsWith("^"))
prefix = prefix.slice(1);
if (prefix.endsWith("$"))
prefix = prefix.slice(0, -1);
let content = prefix.replace(/\(.*\)\??/g, "");
content = content.replace(/\\/g, "");
return content;
}
function markdownBlock(code, filetype) {
filetype = filetype == "javascriptreact" ? "javascript" : filetype;
filetype = filetype == "typescriptreact" ? "typescript" : filetype;
return "``` " + filetype + "\n" + code + "\n```";
}
// src/languages.ts
var codesMap = new Map();
codesMap.set(1, "invalid snippet line, trigger requried.");
codesMap.set(2, 'invalid snippet option, option "$1" not supported.');
codesMap.set(3, "invalid python expression, $1");
codesMap.set(4, "invalid code interpolation, #! not supported.");
var validOptions = ["b", "i", "w", "r", "e", "A"];
var LanguageProvider = class {
constructor(channel, trace = "error") {
this.channel = channel;
this.trace = trace;
this.disposables = [];
this.collection = import_coc.languages.createDiagnosticCollection("snippets");
for (let doc of import_coc.workspace.documents) {
if (this.shouldValidate(doc.uri)) {
this.validate(doc.uri, doc.getDocumentContent()).catch((e) => {
channel.appendLine(`[Error ${new Date().toLocaleTimeString()}]: ${e.message}`);
});
}
}
import_coc.workspace.onDidOpenTextDocument(async (textDocument) => {
let doc = import_coc.workspace.getDocument(textDocument.uri);
if (!this.shouldValidate(doc.uri))
return;
await this.validate(doc.uri, doc.getDocumentContent());
}, null, this.disposables);
import_coc.workspace.onDidChangeTextDocument(async (ev) => {
let doc = import_coc.workspace.getDocument(ev.textDocument.uri);
if (!doc || !this.shouldValidate(doc.uri))
return;
await this.validate(doc.uri, doc.getDocumentContent());
}, null, this.disposables);
import_coc.workspace.onDidCloseTextDocument((e) => {
this.collection.delete(e.uri);
}, null, this.disposables);
}
shouldValidate(uri) {
return uri.endsWith(".snippets");
}
async validate(uri, content) {
let lines = content.split("\n");
let diagnostics = [];
let curr = 0;
for (let line of lines) {
if (/^snippet\s*$/.test(line)) {
let range = import_coc.Range.create(curr, 0, curr, line.length);
diagnostics.push(import_coc.Diagnostic.create(range, codesMap.get(1), import_coc.DiagnosticSeverity.Error, 1));
continue;
}
if (line.startsWith("snippet ")) {
let content2 = headTail(line)[1];
let ms = content2.match(/^(.+?)(?:\s+(?:"(.*?)")?(?:\s+"(.*?)")?(?:\s+(\w+))?)?$/);
let prefix = ms[1];
if (prefix.length > 2 && prefix[0] == prefix[prefix.length - 1] && !/\w/.test(prefix[0])) {
prefix = prefix.slice(1, prefix.length - 1);
}
let option = ms[4] || "";
let isExpression = option.indexOf("r") !== -1;
let startCharacter = line.length - option.length;
for (let ch of option) {
if (validOptions.indexOf(ch) == -1) {
let range = import_coc.Range.create(curr, startCharacter, curr, startCharacter + 1);
let message = codesMap.get(2).replace("$1", ch);
diagnostics.push(import_coc.Diagnostic.create(range, message, import_coc.DiagnosticSeverity.Error, 2));
}
startCharacter = startCharacter + 1;
}
if (isExpression) {
try {
convertRegex(prefix);
} catch (e) {
let start = line.indexOf(prefix);
let range = import_coc.Range.create(curr, start, curr, start + prefix.length);
let message = codesMap.get(3).replace("$1", e.message);
diagnostics.push(import_coc.Diagnostic.create(range, message, import_coc.DiagnosticSeverity.Error, 3));
}
}
} else {
let idx = line.indexOf("`#!");
if (idx !== -1) {
let range = import_coc.Range.create(curr, idx, curr, idx + 3);
let message = codesMap.get(4);
diagnostics.push(import_coc.Diagnostic.create(range, message, import_coc.DiagnosticSeverity.Error, 4));
}
}
curr++;
}
if (this.trace == "verbose") {
this.channel.appendLine(`[Debug ${new Date().toLocaleTimeString()}] diagnostics of ${uri} -> ${JSON.stringify(diagnostics)}`);
}
this.collection.set(uri, diagnostics);
}
provideCompletionItems(_document, position, _token, context) {
let {input, col} = context.option;
if (context.triggerCharacter == "$") {
return [{
label: "$VISUAL",
kind: import_coc.CompletionItemKind.Snippet,
detail: "${VISUAL}",
insertTextFormat: import_coc.InsertTextFormat.Snippet,
textEdit: {
range: import_coc.Range.create(position.line, position.character - 1, position.line, position.character),
newText: "\\${VISUAL${1::default}\\}"
}
}];
}
if (col == 0 && "snippet".startsWith(input)) {
return [{
label: "snippet",
kind: import_coc.CompletionItemKind.Snippet,
detail: "Snippet definition",
insertTextFormat: import_coc.InsertTextFormat.Snippet,
insertText: 'snippet ${1:Tab_trigger} "${2:Description}" ${3:b}\n$0\nendsnippet'
}];
}
return [];
}
async resolveCompletionItem(item) {
let text = item.insertText || item.textEdit.newText;
let snip = await Promise.resolve(import_coc.snippetManager.resolveSnippet(text));
item.documentation = {
kind: "markdown",
value: markdownBlock(snip.toString(), "snippets")
};
return item;
}
};
var languages_default = LanguageProvider;
// src/list/snippet.ts
var import_coc2 = __toModule(require("coc.nvim"));
var import_os = __toModule(require("os"));
var SnippetsList = class extends import_coc2.BasicList {
constructor(nvim, manager, mru) {
super(nvim);
this.manager = manager;
this.mru = mru;
this.name = "snippets";
this.description = "snippets list";
this.addLocationActions();
}
async loadItems(context) {
let {window: window4} = context;
let valid = await window4.valid;
if (!valid)
return;
let buf = await window4.buffer;
let doc = import_coc2.workspace.getDocument(buf.id);
if (!doc)
return [];
let snippets = await this.manager.getSnippets(doc.filetype);
let res = [];
for (let snip of snippets) {
let pos = import_coc2.Position.create(snip.lnum, 0);
let location = import_coc2.Location.create(import_coc2.Uri.file(snip.filepath).toString(), import_coc2.Range.create(pos, pos));
let prefix = snip.prefix;
if (prefix.length < 20) {
prefix = `${prefix}${" ".repeat(20 - prefix.length)}`;
}
res.push({
label: `${prefix} ${snip.description} ${snip.filepath.replace(import_os.default.homedir(), "~")}`,
filterText: `${snip.prefix} ${snip.description}`,
location
});
}
return res;
}
async doHighlight() {
let {nvim} = import_coc2.workspace;
nvim.pauseNotification();
nvim.command("syntax match CocSnippetsPrefix /\\v^\\S+/ contained containedin=CocSnippetsLine", true);
nvim.command("syntax match CocSnippetsFile /\\v\\t\\S+$/ contained containedin=CocSnippetsLine", true);
nvim.command("highlight default link CocSnippetsPrefix Identifier", true);
nvim.command("highlight default link CocSnippetsFile Comment", true);
await nvim.resumeNotification();
}
};
var snippet_default = SnippetsList;
// src/provider.ts
var import_coc3 = __toModule(require("coc.nvim"));
var import_path = __toModule(require("path"));
// src/types.ts
var TriggerKind;
(function(TriggerKind2) {
TriggerKind2[TriggerKind2["SpaceBefore"] = 0] = "SpaceBefore";
TriggerKind2[TriggerKind2["LineBegin"] = 1] = "LineBegin";
TriggerKind2[TriggerKind2["WordBoundary"] = 2] = "WordBoundary";
TriggerKind2[TriggerKind2["InWord"] = 3] = "InWord";
})(TriggerKind || (TriggerKind = {}));
// src/provider.ts
var ProviderManager = class {
constructor(channel) {
this.channel = channel;
this.providers = new Map();
}
regist(provider, name) {
this.providers.set(name, provider);
return import_coc3.Disposable.create(() => {
this.providers.delete(name);
});
}
get hasProvider() {
return this.providers.size > 0;
}
async init() {
let providers = Array.from(this.providers.values());
await Promise.all(providers.map((provider) => {
return provider.init();
})).catch((e) => {
this.appendError("init", e);
});
}
async getSnippets(filetype) {
let names = Array.from(this.providers.keys());
let list = [];
for (let name of names) {
let provider = this.providers.get(name);
try {
let snippets = await provider.getSnippets(filetype);
snippets.map((s) => s.provider = name);
list.push(...snippets);
} catch (e) {
this.appendError(`getSnippets of ${name}`, e);
}
}
return list;
}
async getSnippetFiles(filetype) {
let files = [];
for (let [name, provider] of this.providers.entries()) {
try {
let res = await provider.getSnippetFiles(filetype);
files = files.concat(res);
} catch (e) {
this.appendError(`getSnippetFiles of ${name}`, e);
}
}
return files;
}
async getTriggerSnippets(bufnr, autoTrigger = false) {
let doc = import_coc3.workspace.getDocument(bufnr);
if (!doc)
return [];
let position = await import_coc3.window.getCursorPosition();
let names = Array.from(this.providers.keys());
let list = [];
for (let name of names) {
let provider = this.providers.get(name);
try {
let items = await provider.getTriggerSnippets(doc, position, autoTrigger);
for (let item of items) {
if (list.findIndex((o) => o.prefix == item.prefix) == -1) {
list.push(item);
}
}
} catch (e) {
this.appendError(`getTriggerSnippets of ${name}`, e);
}
}
list.sort((a, b) => b.priority - a.priority);
if (list.length > 1 && list[0].priority > 0) {
list = list.filter((o) => o.priority > 0);
}
return list;
}
appendError(name, e) {
this.channel.appendLine(`[Error ${new Date().toLocaleTimeString()}] Error on ${name}: ${typeof e === "string" ? e : e.message}`);
if (e instanceof Error) {
this.channel.appendLine(e.stack);
}
}
async provideCompletionItems(document, position, _token, context) {
let doc = import_coc3.workspace.getDocument(document.uri);
if (!doc)
return [];
let snippets = await this.getSnippets(doc.filetype);
let currline = doc.getline(position.line, true);
let {input, col} = context.option;
let character = characterIndex(currline, col);
let before_content = currline.slice(0, character);
let res = [];
let contextPrefixes = [];
for (let snip of snippets) {
let contentBehind = before_content;
if (contextPrefixes.indexOf(snip.prefix) !== -1)
continue;
if (snip.regex != null && snip.prefix == "")
continue;
if (snip.context) {
let provider = this.providers.get(snip.provider);
let valid;
try {
valid = await provider.checkContext(snip.context);
} catch (e) {
this.appendError(`checkContext of ${snip.provider}`, e);
valid = false;
}
if (!valid)
continue;
contextPrefixes.push(snip.prefix);
}
let head = this.getPrefixHead(doc, snip.prefix);
if (input.length == 0 && !before_content.endsWith(snip.prefix))
continue;
let item = {
label: snip.prefix,
kind: import_coc3.CompletionItemKind.Snippet,
filterText: snip.prefix,
detail: snip.description,
insertTextFormat: import_coc3.InsertTextFormat.Snippet
};
item.data = {
snip,
provider: snip.provider,
filepath: `${import_path.default.basename(snip.filepath)}:${snip.lnum}`
};
if (snip.regex) {
if (!input.length || snip.prefix && input[0] != snip.prefix[0])
continue;
let content = before_content + snip.prefix;
let ms = content.match(snip.regex);
if (!ms)
continue;
} else if (head && before_content.endsWith(head)) {
contentBehind = before_content.slice(0, -head.length);
let prefix = snip.prefix.slice(head.length);
Object.assign(item, {
textEdit: {
range: import_coc3.Range.create({line: position.line, character: character - head.length}, position),
newText: prefix
}
});
} else if (input.length == 0) {
let {prefix} = snip;
contentBehind = before_content.slice(0, -prefix.length);
Object.assign(item, {
preselect: true,
textEdit: {
range: import_coc3.Range.create({line: position.line, character: character - prefix.length}, position),
newText: prefix
}
});
}
if (snip.triggerKind == TriggerKind.LineBegin && contentBehind.trim().length)
continue;
if (snip.triggerKind == TriggerKind.SpaceBefore) {
if (contentBehind.length && !/\s/.test(contentBehind[contentBehind.length - 1])) {
continue;
}
}
if (!item.textEdit) {
item.textEdit = {
range: import_coc3.Range.create({line: position.line, character}, position),
newText: item.label
};
}
item.data.location = `${snip.filepath}:${snip.lnum}`;
item.data.line = contentBehind + snip.prefix;
res.push(item);
}
return res;
}
async resolveCompletionItem(item) {
let provider = this.providers.get(item.data.provider);
if (provider) {
let filetype = await import_coc3.workspace.nvim.eval("&filetype");
let insertSnippet;
try {
insertSnippet = await provider.resolveSnippetBody(item.data.snip, item.textEdit.range, item.data.line);
} catch (e) {
this.appendError(`resolveSnippetBody of ${item.data.provider}`, e);
return item;
}
item.textEdit.newText = insertSnippet;
if (import_coc3.snippetManager) {
let snip = await Promise.resolve(import_coc3.snippetManager.resolveSnippet(insertSnippet));
item.documentation = {
kind: "markdown",
value: markdownBlock(snip.toString(), filetype.match(/^\w+/)[0])
};
}
}
return item;
}
getPrefixHead(doc, prefix) {
let res = 0;
for (let idx = prefix.length - 1; idx >= 0; idx--) {
if (!doc.isWord(prefix[idx])) {
res = idx;
break;
}
}
return res == 0 ? "" : prefix.slice(0, res + 1);
}
};
function characterIndex(content, byteIndex) {
let buf = Buffer.from(content, "utf8");
return buf.slice(0, byteIndex).toString("utf8").length;
}
// src/snipmateProvider.ts
var import_coc5 = __toModule(require("coc.nvim"));
var import_fs2 = __toModule(require("fs"));
var import_path2 = __toModule(require("path"));
var import_readline = __toModule(require("readline"));
// src/baseProvider.ts
var import_coc4 = __toModule(require("coc.nvim"));
var BaseProvider = class {
constructor(config) {
this.config = config;
}
async checkContext(_context) {
return true;
}
getExtendsFiletypes(filetype, exists = new Set()) {
if (exists.has(filetype))
return [];
let extend = this.config.extends ? this.config.extends[filetype] : null;
exists.add(filetype);
if (!extend || extend.length == 0)
return [];
return extend.reduce((arr, curr) => {
return arr.concat([curr], this.getExtendsFiletypes(curr, exists));
}, []);
}
getFiletypes(filetype) {
let filetypes = [filetype];
if (filetype.indexOf(".") !== -1) {
filetypes.push(...filetype.split("."));
}
if (filetype == "javascript.jsx")
filetypes.push("javascriptreact");
if (filetype == "typescript.jsx" || filetype == "typescript.tsx")
filetypes.push("typescriptreact");
let map = import_coc4.workspace.env.filetypeMap;
if (map && map[filetype]) {
filetypes.push(map[filetype]);
}
if (filetype == "javascriptreact" && !filetypes.includes("javascript")) {
filetypes.push("javascript");
}
if (filetype == "typescriptreact" && !filetypes.includes("typescript")) {
filetypes.push("typescript");
}
let extendFiletypes = filetypes.reduce((arr, curr) => {
return arr.concat(this.getExtendsFiletypes(curr));
}, []);
filetypes.push(...extendFiletypes);
filetypes.reverse();
return distinct(filetypes);
}
};
var baseProvider_default = BaseProvider;
// src/parser.ts
var Parser = class {
constructor(_content) {
this._content = _content;
this._curr = 0;
}
eof() {
return this._curr >= this._content.length;
}
skipSpaces() {
for (let i = this._curr; i <= this._content.length; i++) {
let ch = this._content[i];
if (!ch || /\S/.test(ch)) {
this._curr = i;
break;
}
}
}
get index() {
return this._curr;
}
get curr() {
return this._content[this._curr] || "";
}
get len() {
return this._content.length;
}
next(count = 1) {
return this._content.slice(this._curr + 1, this._curr + 1 + count);
}
nextIndex(character, checkEscape = true, allowEnd = true) {
if (this._curr >= this.len - 1)
return allowEnd ? this.len - 1 : -1;
let i = this._curr + 1;
let pre = this.curr || "";
while (i != this.len - 1) {
let ch = this._content[i];
if (ch == character && (!checkEscape || pre !== "\\")) {
break;
}
pre = ch;
i = i + 1;
}
if (!allowEnd && i == this.len - 1 && character != this._content[i]) {
return -1;
}
return i;
}
prev() {
return this._content[this._curr - 1] || "";
}
iterate(fn) {
while (this._curr < this._content.length) {
let fine = fn(this.curr, this._curr);
if (fine === false) {
break;
}
this._curr = this._curr + 1;
}
}
eat(count) {
let end = this._curr + count;
end = Math.min(end, this.len);
let str = this._content.slice(this._curr, end);
this._curr = end;
return str;
}
eatTo(index) {
if (index == this._curr)
return "";
let str = this._content.slice(this._curr, index);
this._curr = index;
return str;
}
};
var parser_default = Parser;
// src/snipmateProvider.ts
var SnipmateProvider = class extends baseProvider_default {
constructor(channel, trace, config) {
super(config);
this.channel = channel;
this.trace = trace;
this.snippetFiles = [];
this.disposables = [];
import_coc5.workspace.onDidSaveTextDocument(async (doc) => {
let uri = import_coc5.Uri.parse(doc.uri);
if (uri.scheme != "file")
return;
let filepath = uri.fsPath;
if (!import_fs2.default.existsSync(filepath))
return;
let snippetFile = this.snippetFiles.find((s) => s.filepath == filepath);
if (snippetFile)
await this.loadSnippetsFromFile(snippetFile.filetype, snippetFile.directory, filepath);
}, null, this.disposables);
}
async init() {
let arr = await this.getAllSnippetFiles();
let {nvim} = import_coc5.workspace;
let author = await nvim.getVar("snips_author");
if (!author)
await nvim.setVar("snips_author", this.config.author);
await Promise.all(arr.map(({filepath, directory, filetype}) => {
return this.loadSnippetsFromFile(filetype, directory, filepath);
}));
}
async loadSnippetsFromFile(filetype, directory, filepath) {
let snippets = await this.parseSnippetsFile(filepath);
let idx = this.snippetFiles.findIndex((o) => o.filepath == filepath);
if (idx !== -1)
this.snippetFiles.splice(idx, 1);
this.snippetFiles.push({
directory,
filepath,
filetype,
snippets
});
this.channel.appendLine(`[Info ${new Date().toISOString()}] Loaded ${snippets.length} snipmate snippets from: ${filepath}`);
}
async resolveSnippetBody(snippet, _range, _line) {
let parser2 = new parser_default(snippet.body);
let resolved = "";
let {nvim} = import_coc5.workspace;
while (!parser2.eof()) {
if (parser2.curr == "`") {
let idx = parser2.nextIndex("`", true, false);
if (idx == -1) {
resolved = resolved + parser2.eatTo(parser2.len);
break;
}
let code = parser2.eatTo(idx + 1);
code = code.slice(1, -1);
if (code.startsWith("Filename")) {
resolved = resolved + await nvim.call("expand", "%:p:t");
} else {
try {
resolved = resolved + await nvim.eval(code);
} catch (e) {
this.channel.appendLine(`[Error ${new Date().toLocaleTimeString()}] Error on eval: ${code}`);
}
}
continue;
}
parser2.iterate((ch) => {
if (ch == "`") {
return false;
} else {
resolved = resolved + ch;
}
return true;
});
}
return resolved;
}
parseSnippetsFile(filepath) {
let res = [];
const rl = import_readline.default.createInterface({
input: import_fs2.default.createReadStream(filepath, "utf8"),
crlfDelay: Infinity
});
let lnum = 0;
let lines = [];
let prefix = "";
let description = "";
rl.on("line", (line) => {
lnum += 1;
if (line.startsWith("#"))
return;
if (line.startsWith("snippet")) {
line = line.replace(/\s*$/, "");
if (lines.length && prefix) {
res.push({
filepath,
lnum: lnum - lines.length - 1,
body: lines.join("\n").replace(/\s+$/, ""),
prefix,
description,
triggerKind: TriggerKind.SpaceBefore
});
lines = [];
}
let ms = line.match(/^snippet\s+(\S+)(?:\s(.+))?$/);
if (!ms) {
prefix = "";
this.channel.appendLine(`[Error ${new Date().toLocaleTimeString()}] Broken line on ${filepath}:${lnum}`);
return;
}
prefix = ms[1];
description = ms[2] || "";
return;
}
if (prefix) {
if (line.indexOf("VISUAL") !== -1) {
line = line.replace(/\$(\{?)VISUAL\b(:[^\}])?(\}?)/g, "$$$1TM_SELECTED_TEXT$2$3");
}
if (line.startsWith(" ")) {
lines.push(line.slice(1));
} else {
lines.push(line);
}
}
});
return new Promise((resolve) => {
rl.on("close", async () => {
if (lines.length) {
res.push({
filepath,
lnum: lnum - lines.length - 1,
body: lines.join("\n"),
prefix,
description,
triggerKind: TriggerKind.SpaceBefore
});
}
resolve(res);
});
});
}
async getTriggerSnippets(document, position, autoTrigger) {
if (autoTrigger)
return [];
let snippets = await this.getSnippets(document.filetype);
let line = document.getline(position.line);
line = line.slice(0, position.character);
if (!line || line[line.length - 1] == " ")
return [];
snippets = snippets.filter((s) => {
let {prefix} = s;
if (!line.endsWith(prefix))
return false;
let pre = line.slice(0, line.length - prefix.length);
return pre.length == 0 || /\s/.test(pre[pre.length - 1]);
});
let edits = [];
for (let s of snippets) {
let character = position.character - s.prefix.length;
let range = import_coc5.Range.create(position.line, character, position.line, position.character);
let newText = await this.resolveSnippetBody(s, range, line);
edits.push({
prefix: s.prefix,
description: s.description,
location: s.filepath,
range,
newText,
priority: -1
});
}
return edits;
}
async getSnippetFiles(filetype) {
let filetypes = this.getFiletypes(filetype);
let res = [];
for (let s of this.snippetFiles) {
if (filetypes.indexOf(s.filetype) !== -1) {
res.push(s.filepath);
}
}
return res;
}
async getSnippets(filetype) {
let filetypes = this.getFiletypes(filetype);
filetypes.push("_");
let snippetFiles = this.snippetFiles.filter((o) => filetypes.indexOf(o.filetype) !== -1);
let result = [];
snippetFiles.sort((a, b) => {
if (a.filetype == b.filetype)
return 1;
if (a.filetype == filetype)
return -1;
return 1;
});
for (let file of snippetFiles) {
let {snippets} = file;
for (let snip of snippets) {
result.push(snip);
}
}
return result;
}
async getAllSnippetFiles() {
let {nvim} = import_coc5.workspace;
let opt = await nvim.eval("&rtp");
let rtps = opt.split(",");
let res = [];
for (let rtp of rtps) {
let items = await this.getSnippetFileItems(import_path2.default.join(rtp, "snippets"));
res.push(...items);
}
return res;
}
async getSnippetFileItems(directory) {
let res = [];
let stat = await statAsync(directory);
if (stat && stat.isDirectory()) {
let files = await readdirAsync(directory);
if (files.length) {
for (let f of files) {
let file = import_path2.default.join(directory, f);
if (file.endsWith(".snippets")) {
let basename = import_path2.default.basename(f, ".snippets");
let filetype = basename.split("-", 2)[0];
res.push({filepath: file, directory, filetype});
} else {
let stat2 = await statAsync(file);
if (stat2 && stat2.isDirectory()) {
let files2 = await readdirAsync(file);
for (let filename of files2) {
if (filename.endsWith(".snippets")) {
res.push({filepath: import_path2.default.join(file, filename), directory, filetype: f});
}
}
}
}
}
}
}
return res;
}
};
// src/textmateProvider.ts
var import_coc6 = __toModule(require("coc.nvim"));
var import_fs3 = __toModule(require("fs"));
// node_modules/jsonc-parser/lib/esm/impl/scanner.js
"use strict";
function createScanner(text, ignoreTrivia) {
if (ignoreTrivia === void 0) {
ignoreTrivia = false;
}
var len = text.length;
var pos = 0, value = "", tokenOffset = 0, token = 16, lineNumber = 0, lineStartOffset = 0, tokenLineStartOffset = 0, prevTokenLineStartOffset = 0, scanError = 0;
function scanHexDigits(count, exact) {
var digits = 0;
var value2 = 0;
while (digits < count || !exact) {
var ch = text.charCodeAt(pos);
if (ch >= 48 && ch <= 57) {
value2 = value2 * 16 + ch - 48;
} else if (ch >= 65 && ch <= 70) {
value2 = value2 * 16 + ch - 65 + 10;
} else if (ch >= 97 && ch <= 102) {
value2 = value2 * 16 + ch - 97 + 10;
} else {
break;
}
pos++;
digits++;
}
if (digits < count) {
value2 = -1;
}
return value2;
}
function setPosition(newPosition) {
pos = newPosition;
value = "";
tokenOffset = 0;
token = 16;
scanError = 0;
}
function scanNumber() {
var start = pos;
if (text.charCodeAt(pos) === 48) {
pos++;
} else {
pos++;
while (pos < text.length && isDigit(text.charCodeAt(pos))) {
pos++;
}
}
if (pos < text.length && text.charCodeAt(pos) === 46) {
pos++;
if (pos < text.length && isDigit(text.charCodeAt(pos))) {
pos++;
while (pos < text.length && isDigit(text.charCodeAt(pos))) {
pos++;
}
} else {
scanError = 3;
return text.substring(start, pos);
}
}
var end = pos;
if (pos < text.length && (text.charCodeAt(pos) === 69 || text.charCodeAt(pos) === 101)) {
pos++;
if (pos < text.length && text.charCodeAt(pos) === 43 || text.charCodeAt(pos) === 45) {
pos++;
}
if (pos < text.length && isDigit(text.charCodeAt(pos))) {
pos++;
while (pos < text.length && isDigit(text.charCodeAt(pos))) {
pos++;
}
end = pos;
} else {
scanError = 3;
}
}
return text.substring(start, end);
}
function scanString() {
var result = "", start = pos;
while (true) {
if (pos >= len) {
result += text.substring(start, pos);
scanError = 2;
break;
}
var ch = text.charCodeAt(pos);
if (ch === 34) {
result += text.substring(start, pos);
pos++;
break;
}
if (ch === 92) {
result += text.substring(start, pos);
pos++;
if (pos >= len) {
scanError = 2;
break;
}
var ch2 = text.charCodeAt(pos++);
switch (ch2) {
case 34:
result += '"';
break;
case 92:
result += "\\";
break;
case 47:
result += "/";
break;
case 98:
result += "\b";
break;
case 102:
result += "\f";
break;
case 110:
result += "\n";
break;
case 114:
result += "\r";
break;
case 116:
result += " ";
break;
case 117:
var ch3 = scanHexDigits(4, true);
if (ch3 >= 0) {
result += String.fromCharCode(ch3);
} else {
scanError = 4;
}
break;
default:
scanError = 5;
}
start = pos;
continue;
}
if (ch >= 0 && ch <= 31) {
if (isLineBreak(ch)) {
result += text.substring(start, pos);
scanError = 2;
break;
} else {
scanError = 6;
}
}
pos++;
}
return result;
}
function scanNext() {
value = "";
scanError = 0;
tokenOffset = pos;
lineStartOffset = lineNumber;
prevTokenLineStartOffset = tokenLineStartOffset;
if (pos >= len) {
tokenOffset = len;
return token = 17;
}
var code = text.charCodeAt(pos);
if (isWhiteSpace(code)) {
do {
pos++;
value += String.fromCharCode(code);
code = text.charCodeAt(pos);
} while (isWhiteSpace(code));
return token = 15;
}
if (isLineBreak(code)) {
pos++;
value += String.fromCharCode(code);
if (code === 13 && text.charCodeAt(pos) === 10) {
pos++;
value += "\n";
}
lineNumber++;
tokenLineStartOffset = pos;
return token = 14;
}
switch (code) {
case 123:
pos++;
return token = 1;
case 125:
pos++;
return token = 2;
case 91:
pos++;
return token = 3;
case 93:
pos++;
return token = 4;
case 58:
pos++;
return token = 6;
case 44:
pos++;
return token = 5;
case 34:
pos++;
value = scanString();
return token = 10;
case 47:
var start = pos - 1;
if (text.charCodeAt(pos + 1) === 47) {
pos += 2;
while (pos < len) {
if (isLineBreak(text.charCodeAt(pos))) {
break;
}
pos++;
}
value = text.substring(start, pos);
return token = 12;
}
if (text.charCodeAt(pos + 1) === 42) {
pos += 2;
var safeLength = len - 1;
var commentClosed = false;
while (pos < safeLength) {
var ch = text.charCodeAt(pos);
if (ch === 42 && text.charCodeAt(pos + 1) === 47) {
pos += 2;
commentClosed = true;
break;
}
pos++;
if (isLineBreak(ch)) {
if (ch === 13 && text.charCodeAt(pos) === 10) {
pos++;
}
lineNumber++;
tokenLineStartOffset = pos;
}
}
if (!commentClosed) {
pos++;
scanError = 1;
}
value = text.substring(start, pos);
return token = 13;
}
value += String.fromCharCode(code);
pos++;
return token = 16;
case 45:
value += String.fromCharCode(code);
pos++;
if (pos === len || !isDigit(text.charCodeAt(pos))) {
return token = 16;
}
case 48:
case 49:
case 50:
case 51:
case 52:
case 53:
case 54:
case 55:
case 56:
case 57:
value += scanNumber();
return token = 11;
default:
while (pos < len && isUnknownContentCharacter(code)) {
pos++;
code = text.charCodeAt(pos);
}
if (tokenOffset !== pos) {
value = text.substring(tokenOffset, pos);
switch (value) {
case "true":
return token = 8;
case "false":
return token = 9;
case "null":
return token = 7;
}
return token = 16;
}
value += String.fromCharCode(code);
pos++;
return token = 16;
}
}
function isUnknownContentCharacter(code) {
if (isWhiteSpace(code) || isLineBreak(code)) {
return false;
}
switch (code) {
case 125:
case 93:
case 123:
case 91:
case 34:
case 58:
case 44:
case 47:
return false;
}
return true;
}
function scanNextNonTrivia() {
var result;
do {
result = scanNext();
} while (result >= 12 && result <= 15);
return result;
}
return {
setPosition,
getPosition: function() {
return pos;
},
scan: ignoreTrivia ? scanNextNonTrivia : scanNext,
getToken: function() {
return token;
},
getTokenValue: function() {
return value;
},
getTokenOffset: function() {
return tokenOffset;
},
getTokenLength: function() {
return pos - tokenOffset;
},
getTokenStartLine: function() {
return lineStartOffset;
},
getTokenStartCharacter: function() {
return tokenOffset - prevTokenLineStartOffset;
},
getTokenError: function() {
return scanError;
}
};
}
function isWhiteSpace(ch) {
return ch === 32 || ch === 9 || ch === 11 || ch === 12 || ch === 160 || ch === 5760 || ch >= 8192 && ch <= 8203 || ch === 8239 || ch === 8287 || ch === 12288 || ch === 65279;
}
function isLineBreak(ch) {
return ch === 10 || ch === 13 || ch === 8232 || ch === 8233;
}
function isDigit(ch) {
return ch >= 48 && ch <= 57;
}
// node_modules/jsonc-parser/lib/esm/impl/format.js
"use strict";
// node_modules/jsonc-parser/lib/esm/impl/parser.js
"use strict";
var ParseOptions;
(function(ParseOptions2) {
ParseOptions2.DEFAULT = {
allowTrailingComma: false
};
})(ParseOptions || (ParseOptions = {}));
function parse(text, errors, options) {
if (errors === void 0) {
errors = [];
}
if (options === void 0) {
options = ParseOptions.DEFAULT;
}
var currentProperty = null;
var currentParent = [];
var previousParents = [];
function onValue(value) {
if (Array.isArray(currentParent)) {
currentParent.push(value);
} else if (currentProperty !== null) {
currentParent[currentProperty] = value;
}
}
var visitor = {
onObjectBegin: function() {
var object = {};
onValue(object);
previousParents.push(currentParent);
currentParent = object;
currentProperty = null;
},
onObjectProperty: function(name) {
currentProperty = name;
},
onObjectEnd: function() {
currentParent = previousParents.pop();
},
onArrayBegin: function() {
var array = [];
onValue(array);
previousParents.push(currentParent);
currentParent = array;
currentProperty = null;
},
onArrayEnd: function() {
currentParent = previousParents.pop();
},
onLiteralValue: onValue,
onError: function(error, offset, length) {
errors.push({error, offset, length});
}
};
visit(text, visitor, options);
return currentParent[0];
}
function visit(text, visitor, options) {
if (options === void 0) {
options = ParseOptions.DEFAULT;
}
var _scanner = createScanner(text, false);
function toNoArgVisit(visitFunction) {
return visitFunction ? function() {
return visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter());
} : function() {
return true;
};
}
function toOneArgVisit(visitFunction) {
return visitFunction ? function(arg) {
return visitFunction(arg, _scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter());
} : function() {
return true;
};
}
var onObjectBegin = toNoArgVisit(visitor.onObjectBegin), onObjectProperty = toOneArgVisit(visitor.onObjectProperty), onObjectEnd = toNoArgVisit(visitor.onObjectEnd), onArrayBegin = toNoArgVisit(visitor.onArrayBegin), onArrayEnd = toNoArgVisit(visitor.onArrayEnd), onLiteralValue = toOneArgVisit(visitor.onLiteralValue), onSeparator = toOneArgVisit(visitor.onSeparator), onComment = toNoArgVisit(visitor.onComment), onError = toOneArgVisit(visitor.onError);
var disallowComments = options && options.disallowComments;
var allowTrailingComma = options && options.allowTrailingComma;
function scanNext() {
while (true) {
var token = _scanner.scan();
switch (_scanner.getTokenError()) {
case 4:
handleError(14);
break;
case 5:
handleError(15);
break;
case 3:
handleError(13);
break;
case 1:
if (!disallowComments) {
handleError(11);
}
break;
case 2:
handleError(12);
break;
case 6:
handleError(16);
break;
}
switch (token) {
case 12:
case 13:
if (disallowComments) {
handleError(10);
} else {
onComment();
}
break;
case 16:
handleError(1);
break;
case 15:
case 14:
break;
default:
return token;
}
}
}
function handleError(error, skipUntilAfter, skipUntil) {
if (skipUntilAfter === void 0) {
skipUntilAfter = [];
}
if (skipUntil === void 0) {
skipUntil = [];
}
onError(error);
if (skipUntilAfter.length + skipUntil.length > 0) {
var token = _scanner.getToken();
while (token !== 17) {
if (skipUntilAfter.indexOf(token) !== -1) {
scanNext();
break;
} else if (skipUntil.indexOf(token) !== -1) {
break;
}
token = scanNext();
}
}
}
function parseString(isValue) {
var value = _scanner.getTokenValue();
if (isValue) {
onLiteralValue(value);
} else {
onObjectProperty(value);
}
scanNext();
return true;
}
function parseLiteral() {
switch (_scanner.getToken()) {
case 11:
var tokenValue = _scanner.getTokenValue();
var value = Number(tokenValue);
if (isNaN(value)) {
handleError(2);
value = 0;
}
onLiteralValue(value);
break;
case 7:
onLiteralValue(null);
break;
case 8:
onLiteralValue(true);
break;
case 9:
onLiteralValue(false);
break;
default:
return false;
}
scanNext();
return true;
}
function parseProperty() {
if (_scanner.getToken() !== 10) {
handleError(3, [], [2, 5]);
return false;
}
parseString(false);
if (_scanner.getToken() === 6) {
onSeparator(":");
scanNext();
if (!parseValue()) {
handleError(4, [], [2, 5]);
}
} else {
handleError(5, [], [2, 5]);
}
return true;
}
function parseObject() {
onObjectBegin();
scanNext();
var needsComma = false;
while (_scanner.getToken() !== 2 && _scanner.getToken() !== 17) {
if (_scanner.getToken() === 5) {
if (!needsComma) {
handleError(4, [], []);
}
onSeparator(",");
scanNext();
if (_scanner.getToken() === 2 && allowTrailingComma) {
break;
}
} else if (needsComma) {
handleError(6, [], []);
}
if (!parseProperty()) {
handleError(4, [], [2, 5]);
}
needsComma = true;
}
onObjectEnd();
if (_scanner.getToken() !== 2) {
handleError(7, [2], []);
} else {
scanNext();
}
return true;
}
function parseArray() {
onArrayBegin();
scanNext();
var needsComma = false;
while (_scanner.getToken() !== 4 && _scanner.getToken() !== 17) {
if (_scanner.getToken() === 5) {
if (!needsComma) {
handleError(4, [], []);
}
onSeparator(",");
scanNext();
if (_scanner.getToken() === 4 && allowTrailingComma) {
break;
}
} else if (needsComma) {
handleError(6, [], []);
}
if (!parseValue()) {
handleError(4, [], [4, 5]);
}
needsComma = true;
}
onArrayEnd();
if (_scanner.getToken() !== 4) {
handleError(8, [4], []);
} else {
scanNext();
}
return true;
}
function parseValue() {
switch (_scanner.getToken()) {
case 3:
return parseArray();
case 1:
return parseObject();
case 10:
return parseString(true);
default:
return parseLiteral();
}
}
scanNext();
if (_scanner.getToken() === 17) {
if (options.allowEmptyContent) {
return true;
}
handleError(4, [], []);
return false;
}
if (!parseValue()) {
handleError(4, [], []);
return false;
}
if (_scanner.getToken() !== 17) {
handleError(9, [], []);
}
return true;
}
// node_modules/jsonc-parser/lib/esm/impl/edit.js
"use strict";
// node_modules/jsonc-parser/lib/esm/main.js
"use strict";
var parse2 = parse;
// src/textmateProvider.ts
var import_os2 = __toModule(require("os"));
var import_path3 = __toModule(require("path"));
var import_util5 = __toModule(require("util"));
var TextmateProvider = class extends baseProvider_default {
constructor(channel, trace, config) {
super(config);
this.channel = channel;
this.trace = trace;
this._snippetCache = {};
this._userSnippets = {};
if (config.loadFromExtensions) {
import_coc6.extensions.onDidLoadExtension((extension) => {
this.loadSnippetsFromExtension(extension).catch((e) => {
channel.appendLine(`[Error] ${e.message}`);
});
});
import_coc6.extensions.onDidUnloadExtension((id) => {
delete this._snippetCache[id];
});
}
}
async init() {
if (this.config.loadFromExtensions) {
for (let extension of import_coc6.extensions.all) {
await this.loadSnippetsFromExtension(extension);
}
}
let paths = this.config.snippetsRoots;
if (paths && paths.length) {
for (let dir of paths) {
await this.loadSnippetsFromRoot(dir);
}
}
}
async getSnippetFiles(filetype) {
let filetypes = this.getFiletypes(filetype);
let filepaths = [];
if (this.config.loadFromExtensions) {
for (let key of Object.keys(this._snippetCache)) {
let cache = this._snippetCache[key];
for (let filetype2 of filetypes) {
let snippets = cache[filetype2];
if (snippets && snippets.length) {
filepaths.push(snippets[0].filepath);
}
}
}
}
for (let filetype2 of filetypes) {
let snippets = this._userSnippets[filetype2];
if (snippets && snippets.length) {
for (let snip of snippets) {
let {filepath} = snip;
if (filepaths.indexOf(filepath) == -1) {
filepaths.push(filepath);
}
}
}
}
return distinct(filepaths);
}
async getTriggerSnippets(document, position, autoTrigger) {
if (autoTrigger)
return [];
let line = document.getline(position.line);
line = line.slice(0, position.character);
let snippets = await this.getSnippets(document.filetype);
if (!snippets || !snippets.length)
return [];
let edits = [];
for (let snip of snippets) {
let {prefix} = snip;
if (!line.endsWith(prefix))
continue;
let pre = line.slice(0, line.length - prefix.length);
if (pre.length && /\w/.test(pre[pre.length - 1]))
continue;
edits.push({
prefix,
range: import_coc6.Range.create(position.line, position.character - prefix.length, position.line, position.character),
newText: snip.body,
location: snip.filepath,
description: snip.description,
priority: -1
});
}
return edits;
}
async getSnippets(filetype) {
let res = [];
let filetypes = this.getFiletypes(filetype);
let added = new Set();
for (let key of Object.keys(this._snippetCache)) {
let cache = this._snippetCache[key];
for (let filetype2 of filetypes) {
let snippets = cache[filetype2];
if (snippets) {
for (let snip of snippets) {
if (!added.has(snip.prefix)) {
added.add(snip.prefix);
res.push(snip);
}
}
}
}
}
for (let filetype2 of filetypes) {
let snippets = this._userSnippets[filetype2];
if (snippets && snippets.length) {
for (let snip of snippets) {
if (!added.has(snip.prefix)) {
added.add(snip.prefix);
res.push(snip);
}
}
}
}
return res;
}
async resolveSnippetBody(snip, _range) {
return snip.body;
}
async loadSnippetsFromExtension(extension) {
let {packageJSON} = extension;
if (packageJSON.contributes && packageJSON.contributes.snippets) {
let {snippets} = packageJSON.contributes;
let def = {
extensionId: extension.id,
snippets: []
};
for (let item of snippets) {
let p = import_path3.default.join(extension.extensionPath, item.path);
let {language} = item;
def.snippets.push({
languageId: language,
filepath: p
});
}
if (snippets && snippets.length) {
await this.loadSnippetsFromDefinition(def);
}
}
}
async loadSnippetsFromRoot(root) {
let {_userSnippets} = this;
if (root.startsWith("~"))
root = root.replace(/^~/, import_os2.default.homedir());
let files = await import_util5.default.promisify(import_fs3.default.readdir)(root, "utf8");
files = files.filter((f) => f.endsWith(".json") || f.endsWith(".code-snippets"));
await Promise.all(files.map((file) => {
file = import_path3.default.join(root, file);
let basename = import_path3.default.basename(file, ".json");
basename = basename.replace(/\.code-snippets$/, "");
return this.loadSnippetsFromFile(file).then((snippets) => {
_userSnippets[basename] = snippets;
});
}));
}
async loadSnippetsFromDefinition(def) {
let {extensionId, snippets} = def;
let cache = this._snippetCache[extensionId] = {};
for (let item of snippets) {
let {languageId} = item;
if (!import_fs3.default.existsSync(item.filepath))
continue;
let arr = await this.loadSnippetsFromFile(item.filepath);
let exists = cache[languageId] || [];
cache[languageId] = [...exists, ...arr];
}
}
async loadSnippetsFromFile(snippetFilePath) {
const contents = await new Promise((resolve, reject) => {
import_fs3.default.readFile(snippetFilePath, "utf8", (err, data) => {
if (err)
return reject(err);
resolve(data);
});
});
const snippets = this.loadSnippetsFromText(snippetFilePath, contents);
this.channel.appendLine(`[Info ${new Date().toISOString()}] Loaded ${snippets.length} textmate snippets from ${snippetFilePath}`);
return snippets;
}
loadSnippetsFromText(filepath, contents) {
let snippets = [];
try {
let errors = [];
let snippetObject = parse2(contents, errors, {allowTrailingComma: true});
if (errors.length) {
this.channel.appendLine(`[Error ${new Date().toLocaleDateString()}] parser error of ${filepath}: ${JSON.stringify(errors, null, 2)}`);
}
if (snippetObject) {
for (let key of Object.keys(snippetObject)) {
snippets.push(snippetObject[key]);
}
}
} catch (ex) {
this.channel.appendLine(`[Error ${new Date().toLocaleDateString()}] ${ex.stack}`);
snippets = [];
}
const normalizedSnippets = snippets.map((snip) => {
let prefix = Array.isArray(snip.prefix) ? snip.prefix[0] : snip.prefix;
return {
filepath,
lnum: 0,
body: typeof snip.body === "string" ? snip.body : snip.body.join("\n"),
prefix,
description: typeof snip.description === "string" ? snip.description : typeof snip.description !== "undefined" ? snip.description.join("\n") : "",
triggerKind: TriggerKind.WordBoundary
};
});
return normalizedSnippets;
}
};
// src/ultisnipsProvider.ts
var import_coc8 = __toModule(require("coc.nvim"));
var import_fs5 = __toModule(require("fs"));
var import_os3 = __toModule(require("os"));
var import_path4 = __toModule(require("path"));
var import_coc9 = __toModule(require("coc.nvim"));
// src/ultisnipsParser.ts
var import_child_process = __toModule(require("child_process"));
var import_coc7 = __toModule(require("coc.nvim"));
var import_fs4 = __toModule(require("fs"));
var import_pify2 = __toModule(require_pify());
var import_readline2 = __toModule(require("readline"));
var UltiSnipsParser = class {
constructor(pyMethod, channel, trace = "error") {
this.pyMethod = pyMethod;
this.channel = channel;
this.trace = trace;
}
parseUltisnipsFile(filepath) {
const rl = import_readline2.default.createInterface({
input: import_fs4.default.createReadStream(filepath, "utf8"),
crlfDelay: Infinity
});
let pycodes = [];
let snippets = [];
let block;
let preLines = [];
let first;
let priority = 0;
let lnum = 0;
let clearsnippets = null;
let parsedContext = null;
let extendFiletypes = [];
rl.on("line", (line) => {
lnum += 1;
if (!block && (line.startsWith("#") || line.length == 0))
return;
const [head, tail] = headTail(line);
if (!block) {
switch (head) {
case "priority":
let n = parseInt(tail.trim(), 10);
if (!isNaN(n))
priority = n;
break;
case "extends":
let fts = tail.trim().split(/,\s+/);
for (let ft of fts) {
if (extendFiletypes.indexOf(ft) == -1) {
extendFiletypes.push(ft);
}
}
break;
case "clearsnippets":
clearsnippets = priority;
break;
case "context":
parsedContext = tail.replace(/^"(.+)"$/, "$1");
break;
case "snippet":
case "global":
block = head;
first = tail;
break;
}
return;
}
if (head == "endglobal" && block == "global") {
block = null;
pycodes.push(...preLines);
preLines = [];
return;
}
if (head == "endsnippet" && block == "snippet") {
block = null;
try {
let originRegex;
let body = preLines.join("\n");
body = body.replace(/((?:[^\\]?\$\{\w+?)\/)([^\n]*?[^\\])(?=\/)/g, (_match, p1, p2) => {
return p1 + convertRegex(p2);
});
let ms = first.match(/^(.+?)(?:\s+(?:"(.*?)")?(?:\s+"(.*?)")?(?:\s+(\w+))?)?\s*$/);
let prefix = ms[1];
let description = ms[2] || "";
let context = ms[3];
let option = ms[4] || "";
if (prefix.length > 2 && prefix[1] != prefix[0] && prefix[0] == prefix[prefix.length - 1] && !/\w/.test(prefix[0])) {
prefix = prefix.slice(1, prefix.length - 1);
}
let isExpression = option.indexOf("r") !== -1;
let regex2 = null;
if (isExpression) {
originRegex = prefix;
prefix = convertRegex(prefix);
prefix = prefix.endsWith("$") ? prefix : prefix + "$";
try {
regex2 = new RegExp(prefix);
prefix = getRegexText(prefix);
} catch (e) {
this.error(`Convert regex error for: ${prefix}`);
}
}
if (parsedContext) {
context = parsedContext;
} else if (option.indexOf("e") == -1) {
context = null;
}
let snippet = {
filepath,
context,
originRegex,
autoTrigger: option.indexOf("A") !== -1,
lnum: lnum - preLines.length - 2,
triggerKind: getTriggerKind(option),
prefix,
description,
regex: regex2,
body,
priority
};
snippets.push(snippet);
} catch (e) {
this.error(`Create snippet error on: ${filepath}:${lnum - preLines.length - 1} ${e.message}`);
} finally {
parsedContext = null;
preLines = [];
}
}
if (block == "snippet" || block == "global") {
preLines.push(line);
return;
}
});
return new Promise((resolve) => {
rl.on("close", async () => {
resolve({snippets, clearsnippets, pythonCode: pycodes.join("\n"), extendFiletypes});
});
});
}
async resolveUltisnipsBody(body) {
let {pyMethod} = this;
let parser2 = new parser_default(body);
let resolved = "";
while (!parser2.eof()) {
let p = parser2.prev();
if (parser2.curr == "`" && (!p || p != "\\")) {
let idx = parser2.nextIndex("`", true, false);
if (idx == -1) {
resolved = resolved + parser2.eatTo(parser2.len);
break;
}
let code = parser2.eatTo(idx + 1);
code = code.slice(1, -1);
let indent = resolved.split(/\n/).slice(-1)[0].match(/^\s*/)[0];
resolved = resolved + await this.execute(code, pyMethod, indent);
continue;
} else if (parser2.curr == "$") {
let text = parser2.next(7);
if (text.startsWith("VISUAL") || text.startsWith("{VISUAL")) {
parser2.eat(8);
resolved += "$" + text.replace("VISUAL", "TM_SELECTED_TEXT");
} else if (!/^\d/.test(text) && !text.startsWith("{") && p != "\\") {
resolved += "\\" + parser2.eat(1);
} else {
resolved += parser2.eat(1);
}
}
let prev = parser2.prev() || "";
parser2.iterate((ch) => {
if (prev !== "\\" && (ch == "`" || ch == "$")) {
return false;
} else {
resolved = resolved + ch;
}
prev = ch;
return true;
});
}
resolved = decode(resolved);
this.debug(`resolved: ${resolved}`);
return resolved;
}
async execute(code, pyMethod, indent) {
let {nvim} = import_coc7.workspace;
let res = "";
if (code.startsWith("!")) {
code = code.trim().slice(1);
if (code.startsWith("p")) {
code = code.slice(1).trim();
let lines = [
"import traceback",
"try:",
' snip._reset("")'
];
lines.push(...code.split("\n").map((line) => " " + line.replace(/\t/g, " ")));
lines.push("except Exception as e:");
lines.push(" snip.rv = traceback.format_exc()");
await nvim.command(`${pyMethod} ${lines.join("\n")}`);
res = await nvim.call(`${pyMethod}eval`, "snip.rv");
} else if (code.startsWith("v")) {
code = code.replace(/^v\s*/, "");
try {
res = await nvim.eval(code);
} catch (e) {
res = `Error: ${e.message}`;
this.error(e.stack);
}
}
} else {
try {
res = await import_pify2.default(import_child_process.exec)(code);
} catch (e) {
res = `Error: ${e.message}`;
this.error(`Error on eval ${code}: ` + e.stack);
}
}
res = res.toString();
res = res.replace(/\r?\n$/, "");
let parts = res.split(/\r?\n/);
if (parts.length > 1) {
res = parts.map((s, idx) => {
if (idx == 0 || s.length == 0)
return s;
return `${indent}${s}`;
}).join("\n");
}
return res;
}
error(str) {
if (!this.channel)
return;
this.channel.appendLine(`[Error ${new Date().toLocaleTimeString()}] ${str}`);
}
debug(str) {
if (!this.channel || this.trace == "error")
return;
this.channel.appendLine(`[Debug ${new Date().toLocaleTimeString()}] ${str}`);
}
};
var ultisnipsParser_default = UltiSnipsParser;
function decode(str) {
return str.replace(/\\`/g, "`").replace(/\\{/g, "{");
}
function getTriggerKind(option) {
if (option.indexOf("w") !== -1) {
return TriggerKind.WordBoundary;
}
if (option.indexOf("b") !== -1) {
return TriggerKind.LineBegin;
}
if (option.indexOf("i") !== -1) {
return TriggerKind.InWord;
}
return TriggerKind.SpaceBefore;
}
// src/ultisnipsProvider.ts
var pythonCodes = new Map();
var UltiSnippetsProvider = class extends baseProvider_default {
constructor(channel, trace, config, context) {
super(config);
this.channel = channel;
this.trace = trace;
this.config = config;
this.context = context;
this.snippetFiles = [];
this.disposables = [];
this.directories = [];
this.runtimeDirs = [];
this.runtimeDirs = import_coc8.workspace.env.runtimepath.split(",");
import_coc8.workspace.watchOption("runtimepath", async (_, newValue) => {
let parts = newValue.split(",");
let subFolders = await this.getSubFolders();
let items = [];
for (let dir of parts) {
if (this.runtimeDirs.indexOf(dir) == -1) {
this.runtimeDirs.push(dir);
let res = await this.getSnippetsFromPlugin(dir, subFolders);
items.push(...res);
}
}
if (items.length) {
await Promise.all(items.map(({filepath, directory, filetype}) => {
return this.loadSnippetsFromFile(filetype, directory, filepath);
}));
let files = items.map((o) => o.filepath);
let pythonCode = "";
for (let file of files) {
let code = pythonCodes.get(file);
if (code) {
pythonCode += `# ${file}
` + code + "\n";
}
}
if (pythonCode) {
pythonCodes.clear();
await this.executePythonCode(pythonCode);
}
}
}, this.disposables);
}
checkLoaded(filepath) {
return this.snippetFiles.findIndex((o) => o.filepath == filepath) !== -1;
}
async init() {
let {nvim, env} = import_coc8.workspace;
let {runtimepath} = env;
let {config} = this;
for (let dir of config.directories) {
if (dir.startsWith("~") || dir.indexOf("$") !== -1) {
let res = await import_coc8.workspace.nvim.call("expand", [dir]);
this.directories.push(res);
} else {
this.directories.push(dir);
}
}
this.channel.appendLine(`[Info ${new Date().toISOString()}] Using ultisnips directories: ${this.directories.join(" ")}`);
let hasPythonx = await nvim.call("has", ["pythonx"]);
let pythonCode = await readFileAsync(this.context.asAbsolutePath("python/ultisnips.py"), "utf8");
if (hasPythonx && config.usePythonx) {
this.pyMethod = "pyx";
} else {
this.pyMethod = config.pythonVersion == 3 ? "py3" : "py";
}
this.channel.appendLine(`[Info ${new Date().toLocaleTimeString()}] Using ultisnips python command: ${this.pyMethod}`);
this.parser = new ultisnipsParser_default(this.pyMethod, this.channel, this.trace);
let arr = await this.getAllSnippetFiles(runtimepath);
let files = arr.map((o) => o.filepath);
await Promise.all(arr.map(({filepath, directory, filetype}) => {
return this.loadSnippetsFromFile(filetype, directory, filepath);
}));
for (let file of files) {
let code = pythonCodes.get(file);
if (code) {
pythonCode += `
# ${file}
` + code + "\n";
}
}
await this.executePythonCode(pythonCode);
import_coc8.workspace.onDidSaveTextDocument(async (doc) => {
let uri = import_coc8.Uri.parse(doc.uri);
if (uri.scheme != "file" || !doc.uri.endsWith(".snippets"))
return;
let filepath = uri.fsPath;
if (!import_fs5.default.existsSync(filepath))
return;
let snippetFile = this.snippetFiles.find((s) => s.filepath == filepath);
if (snippetFile) {
await this.loadSnippetsFromFile(snippetFile.filetype, snippetFile.directory, filepath);
} else {
let filetype = import_path4.default.basename(filepath, ".snippets");
await this.loadSnippetsFromFile(filetype, import_path4.default.dirname(filepath), filepath);
}
}, null, this.disposables);
}
async loadSnippetsFromFile(filetype, directory, filepath) {
let {snippets, pythonCode, extendFiletypes, clearsnippets} = await this.parser.parseUltisnipsFile(filepath);
let idx = this.snippetFiles.findIndex((o) => o.filepath == filepath);
if (idx !== -1)
this.snippetFiles.splice(idx, 1);
this.snippetFiles.push({
extendFiletypes,
clearsnippets,
directory,
filepath,
filetype,
snippets
});
if (extendFiletypes) {
let filetypes = this.config.extends[filetype] || [];
filetypes = filetypes.concat(extendFiletypes);
this.config.extends[filetype] = distinct(filetypes);
}
this.channel.appendLine(`[Info ${new Date().toISOString()}] Loaded ${snippets.length} UltiSnip snippets from: ${filepath}`);
pythonCodes.set(filepath, pythonCode);
}
async resolveSnippetBody(snippet, range, line) {
let {nvim} = import_coc8.workspace;
let {body, context, originRegex} = snippet;
let indentCount = await nvim.call("indent", ".");
let ind = " ".repeat(indentCount);
if (body.indexOf("`!p") !== -1) {
let values = new Map();
let re = /\$\{(\d+)(?::([^}]+))?\}/g;
let r;
while (r = re.exec(body)) {
let idx = parseInt(r[1], 10);
let val = r[2] || "";
let exists = values.get(idx);
if (exists == null || val && exists == "''") {
if (/^`!\w/.test(val) && val.endsWith("`")) {
let code = val.slice(1).slice(0, -1);
if (code.startsWith("!p")) {
val = "";
} else {
val = await this.parser.execute(code, this.pyMethod, ind);
}
}
val = val.replace(/'/g, "\\'").replace(/\n/g, "\\n");
values.set(idx, "r'" + val + "'");
}
}
re = /\$(\d+)/g;
while (r = re.exec(body)) {
let idx = parseInt(r[1], 10);
if (!values.has(idx)) {
values.set(idx, "''");
}
}
let len = values.size == 0 ? 0 : Math.max.apply(null, Array.from(values.keys()));
let vals = new Array(len).fill('""');
for (let [idx, val] of values.entries()) {
vals[idx] = val;
}
let pyCodes = [
"import re, os, vim, string, random",
`t = (${vals.join(",")})`,
`fn = vim.eval('expand("%:t")') or ""`,
`path = vim.eval('expand("%:p")') or ""`
];
if (context) {
pyCodes.push(`snip = ContextSnippet()`);
pyCodes.push(`context = ${context}`);
} else {
pyCodes.push(`context = {}`);
}
let start = `(${range.start.line},${Buffer.byteLength(line.slice(0, range.start.character))})`;
let end = `(${range.end.line},${Buffer.byteLength(line.slice(0, range.end.character))})`;
pyCodes.push(`snip = SnippetUtil('${ind}', ${start}, ${end}, context)`);
if (originRegex) {
pyCodes.push(`pattern = re.compile(r"${originRegex.replace(/"/g, '\\"')}")`);
pyCodes.push(`match = pattern.search("${line.replace(/"/g, '\\"')}")`);
}
await nvim.command(`${this.pyMethod} ${this.addPythonTryCatch(pyCodes.join("\n"))}`);
}
return this.parser.resolveUltisnipsBody(body);
}
addPythonTryCatch(code) {
if (!import_coc8.workspace.isVim)
return code;
let lines = [
"import traceback, vim",
`vim.vars['errmsg'] = ''`,
"try:"
];
lines.push(...code.split("\n").map((line) => " " + line));
lines.push("except Exception as e:");
lines.push(` vim.vars['errmsg'] = traceback.format_exc()`);
return lines.join("\n");
}
async checkContext(context) {
let {nvim} = import_coc8.workspace;
let pyCodes = [
"import re, os, vim, string, random",
"snip = ContextSnippet()",
`context = ${context}`
];
await nvim.command(`${this.pyMethod} ${this.addPythonTryCatch(pyCodes.join("\n"))}`);
return await nvim.call(`${this.pyMethod}eval`, "True if context else False");
}
async getTriggerSnippets(document, position, autoTrigger) {
let snippets = await this.getSnippets(document.filetype);
let line = document.getline(position.line);
line = line.slice(0, position.character);
if (!line || line[line.length - 1] == " ")
return [];
snippets = snippets.filter((s) => {
let {prefix, regex: regex2} = s;
if (autoTrigger && !s.autoTrigger)
return false;
if (regex2) {
let ms = line.match(regex2);
if (!ms)
return false;
prefix = ms[0];
}
if (!line.endsWith(prefix))
return false;
if (s.triggerKind == TriggerKind.InWord)
return true;
let pre = line.slice(0, line.length - prefix.length);
if (s.triggerKind == TriggerKind.LineBegin)
return pre.trim() == "";
if (s.triggerKind == TriggerKind.SpaceBefore)
return pre.length == 0 || /\s/.test(pre[pre.length - 1]);
if (s.triggerKind == TriggerKind.WordBoundary)
return pre.length == 0 || !document.isWord(pre[pre.length - 1]);
return false;
});
snippets.sort((a, b) => {
if (a.context && !b.context)
return -1;
if (b.context && !a.context)
return 1;
return 0;
});
let edits = [];
let contextPrefixes = [];
for (let s of snippets) {
let character;
if (s.context) {
let valid = await this.checkContext(s.context);
if (!valid)
continue;
contextPrefixes.push(s.context);
} else if (contextPrefixes.indexOf(s.prefix) !== -1) {
continue;
}
if (s.regex == null) {
character = position.character - s.prefix.length;
} else {
let len = line.match(s.regex)[0].length;
character = position.character - len;
}
let range = import_coc9.Range.create(position.line, character, position.line, position.character);
let newText = await this.resolveSnippetBody(s, range, line);
edits.push({
prefix: s.prefix,
description: s.description,
location: s.filepath,
priority: s.priority,
range,
newText
});
}
return edits;
}
async getSnippetFiles(filetype) {
let filetypes = this.getFiletypes(filetype);
let res = [];
for (let s of this.snippetFiles) {
if (filetypes.indexOf(s.filetype) !== -1) {
res.push(s.filepath);
}
}
return res;
}
async getSnippets(filetype) {
let filetypes = this.getFiletypes(filetype);
filetypes.push("all");
let snippetFiles = this.snippetFiles.filter((o) => filetypes.indexOf(o.filetype) !== -1);
let min = null;
let result = [];
snippetFiles.sort((a, b) => {
if (a.filetype == b.filetype)
return 1;
if (a.filetype == filetype)
return -1;
return 1;
});
for (let file of snippetFiles) {
let {snippets, clearsnippets} = file;
if (typeof clearsnippets == "number") {
min = min ? Math.max(min, clearsnippets) : clearsnippets;
}
for (let snip of snippets) {
if (snip.regex || snip.context) {
result.push(snip);
} else {
let idx = result.findIndex((o) => o.prefix == snip.prefix && o.triggerKind == snip.triggerKind);
if (idx == -1) {
result.push(snip);
} else {
let item = result[idx];
if (snip.priority > item.priority) {
result[idx] = item;
}
}
}
}
}
if (min != null)
result = result.filter((o) => o.priority >= min);
result.sort((a, b) => {
if (a.context && !b.context)
return -1;
if (b.context && !a.context)
return 1;
return 0;
});
return result;
}
async getAllSnippetFiles(runtimepath) {
let {directories} = this;
let res = [];
for (let directory of directories) {
if (import_path4.default.isAbsolute(directory)) {
let items = await this.getSnippetFileItems(directory);
res.push(...items);
}
}
let subFolders = await this.getSubFolders();
let rtps = runtimepath.split(",");
this.runtimeDirs = rtps;
for (let rtp of rtps) {
let items = await this.getSnippetsFromPlugin(rtp, subFolders);
res.push(...items);
}
return res;
}
async getSubFolders() {
let {directories} = this;
directories = directories.filter((s) => !import_path4.default.isAbsolute(s));
let dirs = await import_coc8.workspace.nvim.eval('get(g:, "UltiSnipsSnippetDirectories", [])');
for (let dir of dirs) {
if (directories.indexOf(dir) == -1) {
directories.push(dir);
}
}
return directories;
}
async getSnippetsFromPlugin(directory, subFolders) {
let res = [];
for (let folder of subFolders) {
let items = await this.getSnippetFileItems(import_path4.default.join(directory, folder));
res.push(...items);
}
return res;
}
async getSnippetFileItems(directory) {
let res = [];
let stat = await statAsync(directory);
if (stat && stat.isDirectory()) {
let files = await readdirAsync(directory);
if (files.length) {
for (let f of files) {
let file = import_path4.default.join(directory, f);
if (file.endsWith(".snippets")) {
let basename = import_path4.default.basename(f, ".snippets");
let filetype = basename.split("_", 2)[0];
res.push({filepath: file, directory, filetype});
} else {
let stat2 = await statAsync(file);
if (stat2 && stat2.isDirectory()) {
let files2 = await readdirAsync(file);
for (let filename of files2) {
if (filename.endsWith(".snippets")) {
res.push({filepath: import_path4.default.join(file, filename), directory, filetype: f});
}
}
}
}
}
}
}
return res;
}
async executePythonCode(pythonCode) {
try {
let dir = import_path4.default.join(import_os3.default.tmpdir(), `coc.nvim-${process.pid}`);
if (!import_fs5.default.existsSync(dir))
import_fs5.default.mkdirSync(dir);
let tmpfile = import_path4.default.join(import_os3.default.tmpdir(), `coc.nvim-${process.pid}`, `coc-ultisnips-${uid()}.py`);
let code = this.addPythonTryCatch(pythonCode);
import_fs5.default.writeFileSync(tmpfile, "# -*- coding: utf-8 -*-\n" + code, "utf8");
await import_coc8.workspace.nvim.command(`exe '${this.pyMethod}file '.fnameescape('${tmpfile}')`);
pythonCodes.clear();
} catch (e) {
this.channel.appendLine(`Error on execute python script:`);
this.channel.append(e.message);
import_coc8.window.showMessage(`Error on execute python script: ${e.message}`, "error");
}
}
dispose() {
import_coc8.disposeAll(this.disposables);
}
};
// src/index.ts
var documentation = `# A valid snippet should starts with:
#
# snippet trigger_word [ "description" [ options ] ]
#
# and end with:
#
# endsnippet
#
# Snippet options:
#
# b - Beginning of line.
# i - In-word expansion.
# w - Word boundary.
# r - Regular expression
# e - Custom context snippet
# A - Snippet will be triggered automatically, when condition matches.
#
# Basic example:
#
# snippet emitter "emitter properties" b
# private readonly \${1} = new Emitter<$2>()
# public readonly \${1/^_(.*)/$1/}: Event<$2> = this.$1.event
# endsnippet
#
# Online reference: https://github.com/SirVer/ultisnips/blob/master/doc/UltiSnips.txt
`;
async function waitDocument(doc, changedtick) {
if (import_coc10.workspace.isNvim)
return true;
return new Promise((resolve) => {
let timeout = setTimeout(() => {
disposable.dispose();
resolve(doc.changedtick == changedtick);
}, 200);
let disposable = doc.onDocumentChange(() => {
clearTimeout(timeout);
disposable.dispose();
if (doc.changedtick == changedtick) {
resolve(true);
} else {
resolve(false);
}
});
});
}
async function activate(context) {
let {subscriptions} = context;
const {nvim} = import_coc10.workspace;
const configuration = import_coc10.workspace.getConfiguration("snippets");
const filetypeExtends = configuration.get("extends", {});
const trace = configuration.get("trace", "error");
let mru = import_coc10.workspace.createMru("snippets-mru");
const channel = import_coc10.window.createOutputChannel("snippets");
const manager = new ProviderManager(channel);
let snippetsDir = configuration.get("userSnippetsDirectory");
if (snippetsDir) {
snippetsDir = snippetsDir.replace(/^~/, import_os4.default.homedir());
if (snippetsDir.indexOf("$") !== -1) {
snippetsDir = snippetsDir.replace(/\$(\w+)/g, (match, p1) => {
var _a;
return (_a = process.env[p1]) != null ? _a : match;
});
}
if (!import_path5.default.isAbsolute(snippetsDir)) {
import_coc10.window.showMessage(`snippets.userSnippetsDirectory => ${snippetsDir} should be absolute path`, "warning");
snippetsDir = null;
}
}
if (!snippetsDir)
snippetsDir = import_path5.default.join(import_path5.default.dirname(import_coc10.workspace.env.extensionRoot), "ultisnips");
if (!import_fs6.default.existsSync(snippetsDir)) {
await import_util9.default.promisify(import_fs6.default.mkdir)(snippetsDir);
}
import_coc10.events.on("CompleteDone", async (item) => {
if (typeof item.user_data === "string" && item.user_data.indexOf("snippets") !== -1) {
await mru.add(item.word);
}
}, null, subscriptions);
import_coc10.workspace.onDidOpenTextDocument(async (document) => {
if (document.uri.endsWith(".snippets")) {
let doc = import_coc10.workspace.getDocument(document.uri);
if (!doc)
return;
let {buffer} = doc;
await buffer.setOption("filetype", "snippets");
}
}, null, subscriptions);
if (configuration.get("ultisnips.enable", true)) {
let config2 = configuration.get("ultisnips", {});
let c = Object.assign({}, config2, {
extends: Object.assign({}, filetypeExtends)
});
c.directories = c.directories ? c.directories.slice() : [];
if (c.directories.indexOf(snippetsDir) == -1) {
c.directories.push(snippetsDir);
}
let provider2 = new UltiSnippetsProvider(channel, trace, c, context);
manager.regist(provider2, "ultisnips");
subscriptions.push(provider2);
nvim.getOption("runtimepath").then(async (rtp) => {
let paths = rtp.split(",");
let idx = paths.findIndex((s) => /^ultisnips$/i.test(import_path5.default.basename(s)));
if (idx !== -1)
return;
let directory = import_path5.default.resolve(__dirname, "..");
nvim.command("autocmd BufNewFile,BufRead *.snippets setf snippets", true);
nvim.command(`execute 'noa set rtp+='.fnameescape('${directory.replace(/'/g, "''")}')`, true);
import_coc10.workspace.documents.forEach((doc) => {
if (doc.uri.endsWith(".snippets")) {
doc.buffer.setOption("filetype", "snippets", true);
}
});
}, (_e) => {
});
}
let config = {
loadFromExtensions: configuration.get("loadFromExtensions", true),
snippetsRoots: configuration.get("textmateSnippetsRoots", []),
extends: Object.assign({}, filetypeExtends)
};
let provider = new TextmateProvider(channel, trace, config);
manager.regist(provider, "snippets");
if (configuration.get("snipmate.enable", true)) {
let config2 = {
author: configuration.get("snipmate.author", ""),
extends: Object.assign({}, filetypeExtends)
};
let provider2 = new SnipmateProvider(channel, trace, config2);
manager.regist(provider2, "snipmate");
}
if (configuration.get("autoTrigger", true)) {
let insertTs;
let insertLeaveTs;
let lastInsert;
import_coc10.events.on("InsertCharPre", (character) => {
insertTs = Date.now();
lastInsert = character;
}, null, subscriptions);
import_coc10.events.on("InsertLeave", () => {
insertLeaveTs = Date.now();
}, null, subscriptions);
let inserting = false;
const handleTextChange = async (bufnr, pre, changedtick) => {
let lastInsertTs = insertTs;
if (inserting)
return;
let doc = import_coc10.workspace.getDocument(bufnr);
if (!doc || doc.isCommandLine || !doc.attached)
return;
let now = Date.now();
if (!lastInsertTs || now - lastInsertTs > 100 || !pre.endsWith(lastInsert))
return;
let res = await waitDocument(doc, changedtick);
if (!res)
return;
let edits = await manager.getTriggerSnippets(bufnr, true);
if (edits.length == 0)
return;
if (edits.length > 1) {
channel.appendLine(`Multiple snippet found for auto trigger: ${edits.map((s) => s.prefix).join(", ")}`);
import_coc10.window.showMessage("Multiple snippet found for auto trigger, check output by :CocCommand workspace.showOutput", "warning");
}
if (insertLeaveTs > now || insertTs > now || inserting)
return;
inserting = true;
try {
await import_coc10.commands.executeCommand("editor.action.insertSnippet", edits[0]);
await mru.add(edits[0].prefix);
} catch (e) {
console.error(e);
}
inserting = false;
};
import_coc10.events.on("TextChangedI", async (bufnr, info) => {
await handleTextChange(bufnr, info.pre, info.changedtick);
}, null, subscriptions);
import_coc10.events.on("TextChangedP", async (bufnr, info) => {
await handleTextChange(bufnr, info.pre, info.changedtick);
}, null, subscriptions);
}
let statusItem;
if (configuration.get("enableStatusItem", true)) {
statusItem = import_coc10.window.createStatusBarItem(90, {progress: true});
statusItem.text = "loading snippets";
statusItem.show();
}
manager.init().then(() => {
statusItem == null ? void 0 : statusItem.hide();
});
if (manager.hasProvider) {
let disposable = import_coc10.languages.registerCompletionItemProvider("snippets", configuration.get("shortcut", "S"), null, manager, configuration.get("triggerCharacters", []), configuration.get("priority", 90));
subscriptions.push(disposable);
}
async function fallback() {
await nvim.call("coc#start", [{source: "snippets"}]);
}
async function doExpand(bufnr) {
let edits = await manager.getTriggerSnippets(bufnr);
if (edits.length == 0)
return false;
if (edits.length == 1) {
await import_coc10.commands.executeCommand("editor.action.insertSnippet", edits[0]);
await mru.add(edits[0].prefix);
} else {
let idx = await import_coc10.window.showQuickpick(edits.map((e) => e.description || e.prefix), "choose snippet:");
if (idx == -1)
return;
await import_coc10.commands.executeCommand("editor.action.insertSnippet", edits[idx]);
await mru.add(edits[idx].prefix);
}
return true;
}
subscriptions.push(import_coc10.workspace.registerKeymap(["x"], "convert-snippet", async () => {
let mode = await import_coc10.workspace.nvim.call("visualmode");
if (!mode)
return;
let doc = await import_coc10.workspace.document;
if (!doc)
return;
let range = await import_coc10.workspace.getSelectedRange(mode, doc);
let text = doc.textDocument.getText(range);
if (text)
await import_coc10.commands.executeCommand("snippets.editSnippets", text);
}, {sync: false}));
subscriptions.push(import_coc10.commands.registerCommand("snippets.editSnippets", async (text) => {
let buf = await nvim.buffer;
let doc = import_coc10.workspace.getDocument(buf.id);
if (!doc) {
import_coc10.window.showMessage("Document not found", "error");
return;
}
let file = import_path5.default.join(snippetsDir, `${doc.filetype}.snippets`);
if (!import_fs6.default.existsSync(file)) {
await import_util9.default.promisify(import_fs6.default.writeFile)(file, documentation, "utf8");
}
let uri = import_coc10.Uri.file(file).toString();
await import_coc10.workspace.jumpTo(uri, null, configuration.get("editSnippetsCommand"));
if (text) {
await nvim.command("normal! G");
await nvim.command("normal! 2o");
let position = await import_coc10.window.getCursorPosition();
let indent = text.match(/^\s*/)[0];
text = text.split(/\r?\n/).map((s) => s.startsWith(indent) ? s.slice(indent.length) : s).join("\n");
let escaped = text.replace(/([$}\]])/g, "\\$1");
let snippet = 'snippet ${1:Tab_trigger} "${2:Description}" ${3:b}\n' + escaped + "\nendsnippet";
let edit2 = import_coc10.TextEdit.insert(position, snippet);
await import_coc10.commands.executeCommand("editor.action.insertSnippet", edit2);
}
}));
subscriptions.push(import_coc10.commands.registerCommand("snippets.openSnippetFiles", async () => {
let buf = await nvim.buffer;
let doc = import_coc10.workspace.getDocument(buf.id);
if (!doc) {
import_coc10.window.showMessage("Document not found", "error");
return;
}
let files = await manager.getSnippetFiles(doc.filetype);
if (!files.length) {
import_coc10.window.showMessage("No related snippet file found", "warning");
return;
}
let idx = await import_coc10.window.showQuickpick(files, "choose snippet file:");
if (idx == -1)
return;
let uri = import_coc10.Uri.file(files[idx]).toString();
await import_coc10.workspace.jumpTo(uri, null, configuration.get("editSnippetsCommand"));
}));
subscriptions.push(import_coc10.workspace.registerKeymap(["i"], "snippets-expand", async () => {
let bufnr = await nvim.eval('bufnr("%")');
let expanded = await doExpand(bufnr);
if (!expanded)
await fallback();
}, {silent: true, sync: true, cancel: true}));
subscriptions.push(import_coc10.workspace.registerKeymap(["i"], "snippets-expand-jump", async () => {
let bufnr = await nvim.eval('bufnr("%")');
let expanded = await doExpand(bufnr);
if (!expanded) {
let session = import_coc10.snippetManager.getSession(bufnr);
if (session && session.isActive) {
await nvim.call("coc#_cancel", []);
await import_coc10.snippetManager.nextPlaceholder();
return;
}
await fallback();
}
}, {silent: true, sync: true, cancel: true}));
subscriptions.push(import_coc10.workspace.registerKeymap(["v"], "snippets-select", async () => {
let doc = await import_coc10.workspace.document;
if (!doc)
return;
let mode = await nvim.call("visualmode");
if (["v", "V"].indexOf(mode) == -1) {
import_coc10.window.showMessage(`visual mode ${mode} not supported`, "warning");
return;
}
await nvim.command("normal! `<");
let start = await import_coc10.window.getCursorPosition();
await nvim.command("normal! `>");
let end = await import_coc10.window.getCursorPosition();
end = import_coc10.Position.create(end.line, end.character + 1);
let range = import_coc10.Range.create(start, end);
let text = doc.textDocument.getText(range);
await nvim.call("feedkeys", ["i", "in"]);
if (mode == "v") {
await doc.applyEdits([{range, newText: ""}]);
} else {
let currline = doc.getline(start.line);
let indent = currline.match(/^\s*/)[0];
let lines = text.split(/\r?\n/);
lines = lines.map((s) => s.startsWith(indent) ? s.slice(indent.length) : s);
text = lines.join("\n");
range = import_coc10.Range.create(import_coc10.Position.create(start.line, indent.length), end);
await doc.applyEdits([{range, newText: ""}]);
}
await nvim.setVar("coc_selected_text", text);
await import_coc10.window.moveTo(range.start);
}, {silent: true, sync: false, cancel: true}));
let languageProvider = new languages_default(channel, trace);
subscriptions.push(import_coc10.languages.registerCompletionItemProvider("snippets-source", configuration.get("shortcut", "S"), ["snippets"], languageProvider, ["$"], configuration.get("priority", 90)));
subscriptions.push(statusItem);
subscriptions.push(channel);
subscriptions.push(import_coc10.listManager.registerList(new snippet_default(import_coc10.workspace.nvim, manager, mru)));
return {
expandable: async () => {
let bufnr = await nvim.eval('bufnr("%")');
let edits = await manager.getTriggerSnippets(bufnr);
return edits && edits.length > 0;
}
};
}
//# sourceMappingURL=index.js.map