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