vim9script var SnipList: dict>> = {} final CursorPlaceholder = '<+CURSOR+>' export def vimrc#pinsnip#expand(): string var comparison = trim(getline('.')) if comparison ==# '' Warning('Empty pattern') return '' endif var snip = copy(FindSnip(&filetype, comparison)) if empty(snip) Error('Snippet not found: ' .. string(comparison)) return '' endif final current_indent = getline('.')->matchstr('^\s*') snip->map((_: number, line: string) => current_indent .. substitute(line, "^\t*\t", GetOneIndentString(), 'g')) add(snip, current_indent) # Add a new line if there's no `CursorPlaceholder` var cursor_line = -1 var cursor_col = strlen(snip[-1]) for line in snip var idx = stridx(line, CursorPlaceholder) cursor_line += 1 if idx >= 0 cursor_col = idx snip[cursor_line] = strpart(line, 0, idx) .. line[idx + strlen(CursorPlaceholder) :] remove(snip, -1) # Remove the new line; It's not needed. break endif endfor if mode() ==# 'i' cursor_col += 1 endif append('.', snip) delete _ cursor(line('.') + cursor_line, cursor_col) return '' enddef def GetOneIndentString(): string if &l:expandtab || strdisplaywidth("\t") != shiftwidth() return repeat(' ', shiftwidth()) endif return "\t" enddef def FindSnip(filetype: string, comparison: string): list var snipdict = get(SnipList, filetype, {}) if empty(snipdict) return [] endif # Exact matching of dict-key if has_key(snipdict, comparison) return snipdict[comparison] endif final keys = keys(snipdict) final comparison_reg = '\V' .. comparison # Literal matching of dict-key { var candidates: list = copy(keys)->filter((_, key) => (stridx(key, comparison) != -1)) if !empty(candidates) return snipdict[candidates[0]] endif } # Fuzzy matching of dict-key { var candidates: list = matchfuzzy(keys, comparison, {matchseq: true}) if !empty(candidates) return snipdict[candidates[0]] endif } final snips = values(snipdict) # Literal matching of the first line of snippet { var idx: number = -1 var candidate: list for snip in snips var idx_ = stridx(snip[0], comparison) if idx_ == -1 continue endif if idx_ < idx || idx < 0 idx = idx_ candidate = snip endif endfor if idx != -1 return candidate endif } # Fuzzy matching of the first line of snippet { var snipmap: dict> for snip in snips snipmap[snip[0]] = snip endfor var candidates: list = keys(snipmap) ->matchfuzzy(comparison, {matchseq: true}) if !empty(candidates) return snipmap[candidates[0]] endif } return [] enddef def Error(msg: string) echohl ErrorMsg echomsg '[pinsnip] ' .. msg echohl NONE enddef def Warning(msg: string) echohl WarningMsg echomsg '[pinsnip] ' .. msg echohl NONE enddef def SnipFiletype(filetype: string): dict> if !has_key(SnipList, filetype) SnipList[filetype] = {} endif return SnipList[filetype] enddef def AddSnip( snips: dict>, name: string, snip: list, ): dict> snips[name] = snip return snips enddef SnipFiletype('go') ->AddSnip('iferr', [ 'if err != nil {', "\t<+CURSOR+>", "}" ]) ->AddSnip('iferrreturn', [ 'if err != nil {', "\treturn err", '}', ]) ->AddSnip('iferrprint', [ 'if err != nil {', "\tfmt.Println(err)", '}', ]) ->AddSnip('iferrlog', [ 'if err != nil {', "\tlog.Fatal(err)", '}', ]) ->AddSnip('iferrpanic', [ 'if err != nil {', "\tpanic(err)", '}', ]) SnipFiletype('cpp') ->AddSnip('std::cout', ['std::cout << "<+CURSOR+>" << std::endl;']) ->AddSnip('std::cerr', ['std::cerr << "<+CURSOR+>" << std::endl;']) ->AddSnip('template', ['template ']) SnipFiletype('vim') ->AddSnip('cpoptions', [ 'let s:cpoptions_save = &cpoptions', 'set cpoptions&vim', '', '<+CURSOR+>', '', 'let &cpoptions = s:cpoptions_save', 'unlet s:cpoptions_save' ])