From d07c351677d903308f7e30e841b9243c2ad1e039 Mon Sep 17 00:00:00 2001 From: baabelfish Date: Mon, 1 Feb 2016 09:16:57 +0200 Subject: [PATCH] Autocompleiton and friends --- README.md | 20 ++++++----- autoload/features/definition.vim | 3 +- autoload/features/info.vim | 58 +++++++++----------------------- autoload/features/outline.vim | 3 +- autoload/features/rename.vim | 3 +- autoload/features/usages.vim | 8 +++-- autoload/omni.vim | 40 ++++++++++++++++++++++ autoload/suggest.vim | 54 ++++++++++++++++++++--------- autoload/util.vim | 46 +++++++++++++++++++++++-- compiler/nim.vim | 4 +++ ftdetect/nim.vim | 2 +- ftplugin/nim.vim | 1 + syntax/nim.vim | 4 +-- 13 files changed, 167 insertions(+), 79 deletions(-) create mode 100644 autoload/omni.vim diff --git a/README.md b/README.md index ee2bc84..6e263ec 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,13 @@ Nim support for Neovim - [x] Keywords - [x] Operator precedence different colors - [x] Numbers - - [ ] String + - [x] String - [ ] Multiline comments - [ ] Highlight variable names semantically - [ ] Indendation - [ ] Compiler support + - [x] Omnicomplete - [ ] Make for errors - - [ ] Omnicomplete - [x] Nimsuggest - [x] Usages - [x] Jump to definition @@ -34,14 +34,16 @@ Nim support for Neovim - [x] NimRenameSymbol - [ ] NimRenameSymbolProject - [ ] IDE features - - [ ] Parse proc parameter types for parameter completion - - [ ] Auto complete modules + - [x] Neomake + - [x] Autocompletion with ycm + - [ ] Search and view online documentation + - [ ] Usages with unite - [ ] Outline with unite - [ ] Outline with a proper tagbar - - [ ] Usages with unite - - [ ] Autocompletion with ycm - - [ ] Autocompletion with deoplete + - [ ] Auto complete modules + - [ ] Parse proc parameter types for parameter completion - [ ] REPL interaction + - [ ] Airline integration - [ ] Add tests - [x] CI integration - [x] Test nimsuggest for surprises @@ -61,9 +63,9 @@ Nim support for Neovim # TASKS - [x] Sync version communicating with nimsuggest -- [ ] Test the user's versions +- [ ] Test dependency versions - [ ] Add roadmap # BUGS -- [ ] Not all lines are read from stdin for some reason with job-control +- [x] Not all lines are read from stdin for some reason with job-control diff --git a/autoload/features/definition.vim b/autoload/features/definition.vim index a529a26..19a5ea1 100644 --- a/autoload/features/definition.vim +++ b/autoload/features/definition.vim @@ -18,6 +18,7 @@ endfunction function! features#definition#run() - call suggest#New("def", 0, s:DefinitionImpl) + call suggest#New("def", 1, 0, s:DefinitionImpl) endfunction + diff --git a/autoload/features/info.vim b/autoload/features/info.vim index 09434f8..46f0ce7 100644 --- a/autoload/features/info.vim +++ b/autoload/features/info.vim @@ -6,66 +6,38 @@ let s:loaded = 1 let s:InfoImpl = {} -let s:idtypes = { - \ 'skProc': "Function", - \ 'skTemplate': "Template", - \ 'skType': "Type", - \ 'skMacro': "Macro", - \ 'skMethod': "Method", - \ 'skField': "Field", - \ 'skAlias': "Alias", - \ 'skConditional': "Conditional", - \ 'skConst': "Constant", - \ 'skConverter': "Converter", - \ 'skDynLib': "Dynamic library", - \ 'skEnumField': "Enum field", - \ 'skForVar': "Loop variable", - \ 'skGenericParam': "Generic parameter", - \ 'skGlobalVar': "Global variable", - \ 'skGlobalLet': "Global constant", - \ 'skIterator': "Iterator", - \ 'skLabel': "Label", - \ 'skLet': "Runtime constant", - \ 'skModule': "Module", - \ 'skPackage': "Package", - \ 'skParam': "Parameter", - \ 'skResult': "Result", - \ 'skStub': "Stub", - \ 'skTemp': "Temporary", - \ 'skUnknown': "Unknown", - \ 'skVar': "Variable" - \ } - function! s:InfoImpl.run(data) if len(a:data.lines) == 0 echo "No information found" else + let res = util#ParseV1(a:data.lines[0]) + echohl None - let [_, ctype, name, type, filename, l, c, doc] = split(a:data.lines[0], "\\t") - let path = join(split(name, '\.')[0:-2], ".") - let module = split(name, '\.')[0] - let name = split(name, '\.')[-1] - let node_type = s:idtypes[ctype] - - echohl Function | echon name + echohl Function | echon res.lname echohl Comment | echon "\n » " - echohl Type | echon node_type + echohl Type | echon res.kindstr - if len(type) > 0 && name != type + if len(res.name) > 0 && res.lname != res.name echon "\n" echohl Comment | echon " » " - echohl Typedef | echon type + echohl Typedef | echon res.name end echohl Comment | echon "\n » " - echohl Include | echon path + echohl Include | echon res.location echohl Comment | echon " (" - echohl String | echon filename + echohl String | echon res.file echohl Comment | echon ")" + + if res.doc != "\"\"" + echohl Comment | echon "\n » " + echohl Normal | echon res.doc + endif endif endfunction function! features#info#run() - call suggest#New("def", 0, s:InfoImpl) + call suggest#New("def", 1, 0, s:InfoImpl) endfunction + diff --git a/autoload/features/outline.vim b/autoload/features/outline.vim index 2a52c85..54facbf 100644 --- a/autoload/features/outline.vim +++ b/autoload/features/outline.vim @@ -27,5 +27,6 @@ endfunction function! features#outline#run() cclose call setqflist([]) - call suggest#New("outline", 1, s:OutlineImpl) + call suggest#New("outline", 1, 1, s:OutlineImpl) endfunction + diff --git a/autoload/features/rename.vim b/autoload/features/rename.vim index bfcc696..42758bd 100644 --- a/autoload/features/rename.vim +++ b/autoload/features/rename.vim @@ -37,5 +37,6 @@ endfunction function! features#rename#run(inProject) let s:findInProject = a:inProject - call suggest#New("use", 1, s:RenameImpl) + call suggest#New("use", 1, 1, s:RenameImpl) endfunction + diff --git a/autoload/features/usages.vim b/autoload/features/usages.vim index c955bc5..7224d58 100644 --- a/autoload/features/usages.vim +++ b/autoload/features/usages.vim @@ -46,13 +46,15 @@ endfunction let s:UsagesDefinitionImpl = {} function! s:UsagesDefinitionImpl.run(data) - let res = util#ParseV1(a:data.lines[0]) - call suggest#NewKnown("use", 1, res.file, res.line, res.col + 1, s:UsagesImpl) + " let res = util#ParseV1(a:data.lines[0]) + " call suggest#NewKnown("use", 1, res.file, res.line, res.col + 1, s:UsagesImpl) + call suggest#New("use", 1, 1, s:UsagesImpl) endfunction function! features#usages#run(findInProject) cclose call setqflist([]) let s:findInProject = a:findInProject - call suggest#New("def", 0, s:UsagesDefinitionImpl) + call suggest#New("def", 1, 0, s:UsagesDefinitionImpl) endfunction + diff --git a/autoload/omni.vim b/autoload/omni.vim new file mode 100644 index 0000000..209df9e --- /dev/null +++ b/autoload/omni.vim @@ -0,0 +1,40 @@ +" if exists("s:loaded") +" finish +" endif +" let s:loaded = 1 + + +function! omni#item(parsed) + return { + \ 'word': a:parsed.lname, + \ 'menu': a:parsed.module, + \ 'kind': a:parsed.kindshort . " » " . a:parsed.type, + \ 'info': a:parsed.doc, + \ } +endfunction + +function! omni#nim(findstart, base) + if a:findstart && empty(a:base) + return col('.') + else + + let file = expand("%:p") + let tempfile = file . ".temp" + let l = line(".") + let c = col(".") + call writefile(getline(1, '$'), tempfile) + + let query = "sug " . file . ";" . tempfile . ":" . l . ":" . c + let jobcmdstr = g:nvim_nim_exec_nimsuggest . " --v2 --stdin " . file + let fullcmd = 'echo -e ' . shellescape(query, 1) . '|' . jobcmdstr + let completions_raw = split(system(fullcmd), "\n")[4:-2] + let completions = [] + + for line in completions_raw + call add(completions, omni#item(util#ParseV2(line))) + endfor + + return { + \ 'words': completions, + \ 'refresh': 'always' } +endfunction diff --git a/autoload/suggest.vim b/autoload/suggest.vim index b18a497..00117b6 100644 --- a/autoload/suggest.vim +++ b/autoload/suggest.vim @@ -5,29 +5,44 @@ let s:loaded = 1 let s:findInProject = 1 +let s:NimSuggestServer = {} +function! s:NimSuggestServer.on_stdout(job, chunk) + " echoerr join(a:chunk, "\n") +endfunction +function! s:NimSuggestServer.on_stderr(job, chunk) + " echoerr join(a:chunk, "\n") +endfunction +function! s:NimSuggestServer.on_exit() + " call jobstop(self.job_server) +endfunction + + " NimSuggest let s:NimSuggest = {} function! s:NimSuggest.on_stdout(job, chunk) - if len(a:chunk[0]) != 0 && !(a:chunk[0] =~ "^usage") - call extend(self.lines, a:chunk) - endif + call extend(self.lines, a:chunk) endfunction -function! s:NimSuggest.on_stderr() +function! s:NimSuggest.on_stderr(job, chunk) endfunction function! s:NimSuggest.on_exit() + if self.isAsync + let self.lines = self.lines[5:-1] + else + let self.lines = self.lines[4:-1] + endif + if len(self.lines) > 0 call self.handler.run(self) else - " Clear cli - echo "" + echo "" endif endfunction -function! suggest#NewKnown(command, useV2, file, line, col, handler) +function! suggest#NewKnown(command, sync, useV2, file, line, col, handler) let result = copy(s:NimSuggest) let result.lines = [] let result.file = a:file @@ -35,28 +50,35 @@ function! suggest#NewKnown(command, useV2, file, line, col, handler) let result.line = a:line let result.col = a:col let result.handler = a:handler + let result.isAsync = has("nvim") && !a:sync && g:nvim_nim_enable_async + " if a:useTempFile " call writefile(getline(1, '$'), result.tempfile) " endif " let nimcom = completion . " " . file . (a:useTempFile ? (";" . result.tempfile) : "") . ":" . line . ":" . col - let jobcmd = [g:nvim_nim_exec_nimsuggest, (a:useV2 ? '--v2' : ''), '--stdin', result.file] - let jobcmdstr = g:nvim_nim_exec_nimsuggest . " " . (a:useV2 ? '--v2' : '') . " " . '--stdin' . " " . result.file - let jobstdin = a:command . " " . result.file . ":" . result.line . ":" . result.col + let query = a:command . " " . result.file . ":" . result.line . ":" . result.col - if !g:nvim_nim_enable_async || !has("nvim") - let fullcmd = 'echo -e ' . shellescape(jobstdin, 1) . '|' . jobcmdstr + if !result.isAsync + let jobcmdstr = g:nvim_nim_exec_nimsuggest . " " . (a:useV2 ? '--v2' : '') . " " . '--stdin' . " " . result.file + let fullcmd = 'echo -e ' . shellescape(query, 1) . '|' . jobcmdstr let result.lines = split(system(fullcmd), "\n")[4:-2] call a:handler.run(result) else call util#StartQuery() - let result.job = jobstart([g:nvim_nim_exec_nimsuggest, (a:useV2 ? '--v2' : ''), '--stdin', result.file], result) - call jobsend(result.job, jobcmd) + let result.job_server = jobstart([g:nvim_nim_exec_nimsuggest, '--port:5999', '--address:localhost', (a:useV2 ? '--v2' : ''), result.file], s:NimSuggestServer) + if result.job_server < 1 + echoerr "Unable to start server" + else + " FIXME: Telnet is not possibly the best way to communicate :S + let result.job_suggest = jobstart(['telnet', 'localhost', '5999'], result) + call jobsend(result.job_suggest, query . "\n") + endif endif return result endfunction -function! suggest#New(command, useV2, handler) - return suggest#NewKnown(a:command, a:useV2, expand("%:p"), line("."), col("."), a:handler) +function! suggest#New(command, sync, useV2, handler) + return suggest#NewKnown(a:command, a:sync, a:useV2, expand("%:p"), line("."), col("."), a:handler) endfunction diff --git a/autoload/util.vim b/autoload/util.vim index 2f9815c..4724e5c 100644 --- a/autoload/util.vim +++ b/autoload/util.vim @@ -4,6 +4,37 @@ endif let s:loaded = 1 +let s:idtypes = { + \ 'skProc': ["p", "Function"], + \ 'skTemplate': ["t", "Template"], + \ 'skType': ["T", "Type"], + \ 'skMacro': ["M", "Macro"], + \ 'skMethod': ["m", "Method"], + \ 'skField': ["field", "Field"], + \ 'skAlias': ["a", "Alias"], + \ 'skConditional': ["c", "Conditional"], + \ 'skConst': ["C", "Constant"], + \ 'skConverter': ["c", "Converter"], + \ 'skDynLib': ["d", "Dynamic library"], + \ 'skEnumField': ["e", "Enum field"], + \ 'skForVar': ["l", "Loop variable"], + \ 'skGenericParam': ["g", "Generic parameter"], + \ 'skGlobalVar': ["g", "Global variable"], + \ 'skGlobalLet': ["g", "Global constant"], + \ 'skIterator': ["i", "Iterator"], + \ 'skLabel': ["l", "Label"], + \ 'skLet': ["r", "Runtime constant"], + \ 'skModule': ["m", "Module"], + \ 'skPackage': ["p", "Package"], + \ 'skParam': ["p", "Parameter"], + \ 'skResult': ["r", "Result"], + \ 'skStub': ["s", "Stub"], + \ 'skTemp': ["t", "Temporary"], + \ 'skUnknown': ["u", "Unknown"], + \ 'skVar': ["v", "Variable"], + \ } + + function! util#FirstNonEmpty(lines) for line in a:lines if len(line) > 0 @@ -48,9 +79,15 @@ function! util#StartQuery() endfunction +function! s:GetModule(path) + return a:path[0] +endfunction + + function! util#ParseV1(line) let res = split(a:line, " ") let path = split(res[2], "\\.") + let result = { \ "ctype": res[0], \ "kind": res[1], @@ -60,9 +97,11 @@ function! util#ParseV1(line) \ "line": res[5], \ "col": res[6], \ "doc": res[7], - \ "module": join(path[0:-3], "."), + \ "module": s:GetModule(path), \ "location": join(path[0:-2], "."), \ "lname": path[-1], + \ "kindstr": s:idtypes[res[1]][1], + \ "kindshort": s:idtypes[res[1]][0], \ } return result endfunction @@ -80,10 +119,13 @@ function! util#ParseV2(line) \ "line": res[5], \ "col": res[6], \ "doc": res[7], - \ "module": join(path[0:-3], "."), + \ "quality": res[8], + \ "module": s:GetModule(path), \ "location": join(path[0:-2], "."), \ "name": path[-1], \ "lname": path[-1], + \ "kindstr": s:idtypes[res[1]][1], + \ "kindshort": s:idtypes[res[1]][0], \ } return result endfunction diff --git a/compiler/nim.vim b/compiler/nim.vim index e69de29..632501e 100644 --- a/compiler/nim.vim +++ b/compiler/nim.vim @@ -0,0 +1,4 @@ +if exists("s:loaded") + finish +endif +let s:loaded = 1 diff --git a/ftdetect/nim.vim b/ftdetect/nim.vim index eb00eef..848f863 100644 --- a/ftdetect/nim.vim +++ b/ftdetect/nim.vim @@ -7,7 +7,7 @@ au BufNewFile,BufRead *.nim set filetype=nim au BufNewFile,BufRead *.nims set filetype=nims let g:nvim_nim_enable_highlighter = 0 -let g:nvim_nim_enable_async = 0 +let g:nvim_nim_enable_async = 1 let g:nvim_nim_highlight_builtin = 1 let g:nvim_nim_highlight_use_unite = 0 let g:nvim_nim_autocomplete = "omni" " omni, deoplete, ycm diff --git a/ftplugin/nim.vim b/ftplugin/nim.vim index 79caba0..604be49 100644 --- a/ftplugin/nim.vim +++ b/ftplugin/nim.vim @@ -7,6 +7,7 @@ setlocal formatoptions-=t formatoptions+=l setlocal comments=s1:#[,mb:#,ex:]#,:# setlocal commentstring=#\ %s setlocal expandtab +setlocal omnifunc=omni#nim command! NimDefinition :call features#definition#run() command! NimInfo :call features#info#run() diff --git a/syntax/nim.vim b/syntax/nim.vim index 7a8c927..867f91c 100644 --- a/syntax/nim.vim +++ b/syntax/nim.vim @@ -13,7 +13,7 @@ syntax keyword nimKeyword let const var static syntax keyword nimKeyword addr asm atomic bind cast defer discard syntax keyword nimKeyword do expr stmt end generic mixin iterator syntax keyword nimKeyword typedesc openarray out ptr ref return using -syntax keyword nimKeyword varargs with without yield +syntax keyword nimKeyword varargs with without yield nil syntax keyword nimRepeat for while syntax keyword nimBoolean true false @@ -144,7 +144,7 @@ highlight link nimConditional Conditional highlight link nimConstant Constant highlight link nimDefine Define highlight link nimException Exception -highlight link nimGlobal Constant +highlight link nimGlobals Constant highlight link nimInclude Include highlight link nimLabel Label highlight link nimMacro Macro