From a8812f5f183047f2c6b59eeb09b428bb44402c4b Mon Sep 17 00:00:00 2001 From: baabelfish Date: Sat, 30 Jan 2016 15:26:11 +0200 Subject: [PATCH] Refactor everything to smaller libs + autoload --- README.md | 5 +- autoload/features/debug.vim | 15 ++ autoload/features/definition.vim | 20 ++ autoload/features/info.vim | 23 +++ autoload/features/outline.vim | 31 +++ autoload/features/rename.vim | 41 ++++ autoload/features/usages.vim | 43 ++++ autoload/highlighter.vim | 96 +++++++++ autoload/suggest.vim | 40 ++++ autoload/util.vim | 42 ++++ ftdetect/nim.vim | 6 + ftplugin/nim.vim | 15 ++ plugin/nim.vim | 328 +------------------------------ 13 files changed, 382 insertions(+), 323 deletions(-) create mode 100644 autoload/features/debug.vim create mode 100644 autoload/features/definition.vim create mode 100644 autoload/features/info.vim create mode 100644 autoload/features/outline.vim create mode 100644 autoload/features/rename.vim create mode 100644 autoload/features/usages.vim create mode 100644 autoload/highlighter.vim create mode 100644 autoload/suggest.vim create mode 100644 autoload/util.vim diff --git a/README.md b/README.md index cdf7f29..20a23b8 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Attempt at writing an async outline/structure listing/navigator for files/module - [x] NimInfo - [x] NimUsages - [x] NimUsagesProject - - [ ] NimRenameSymbol + - [x] NimRenameSymbol - [ ] NimRenameSymbolProject # TODO For advanced @@ -30,3 +30,6 @@ Attempt at writing an async outline/structure listing/navigator for files/module - [ ] Usages with unite - [ ] Autocompletion with ycm - [ ] Autocompletion with deoplete + +# BUGS +- [ ] Not all lines are read from stdin for some reason with job-control diff --git a/autoload/features/debug.vim b/autoload/features/debug.vim new file mode 100644 index 0000000..fb67f11 --- /dev/null +++ b/autoload/features/debug.vim @@ -0,0 +1,15 @@ +if exists("s:loaded") + finish +endif +let s:loaded = 1 + + +function! features#debug#run() + echo "Nim tools debugging info" + echo "------------------------" + echo "\n" + echo "-------- Tools ---------" + echo "Nim: " . g:nvim_nim_exec_nim + echo "Nimble: " . g:nvim_nim_exec_nimble + echo "Nimsuggest: " . g:nvim_nim_exec_nimsuggest +endfunction diff --git a/autoload/features/definition.vim b/autoload/features/definition.vim new file mode 100644 index 0000000..8f02463 --- /dev/null +++ b/autoload/features/definition.vim @@ -0,0 +1,20 @@ +if exists("s:loaded") + finish +endif +let s:loaded = 1 + + +let s:DefinitionImpl = {} + + +function! s:DefinitionImpl.run(data) + if len(a:data.lines) > 0 + let [_, _, _, _, filename, l, c, _] = split(a:data.lines[0], " ") + call util#JumpToLocation(filename, l, c + 2) + endif +endfunction + + +function! features#definition#run() + call suggest#New("def", 0, s:DefinitionImpl) +endfunction diff --git a/autoload/features/info.vim b/autoload/features/info.vim new file mode 100644 index 0000000..3cc51c3 --- /dev/null +++ b/autoload/features/info.vim @@ -0,0 +1,23 @@ +if exists("s:loaded") + finish +endif +let s:loaded = 1 + + +let s:InfoImpl = {} + +function! s:InfoImpl.run(data) + if len(a:data.lines) == 0 + echo "No information found" + else + let [_, ctype, name, type, filename, l, c, doc] = split(a:data.lines[0], " ") + echohl Function | echon "Type" + echohl Comment | echon ": " + echohl Statement | echon type + endif +endfunction + + +function! feature#info#run() + call suggest#New("def", 0, s:InfoImpl) +endfunction diff --git a/autoload/features/outline.vim b/autoload/features/outline.vim new file mode 100644 index 0000000..2a52c85 --- /dev/null +++ b/autoload/features/outline.vim @@ -0,0 +1,31 @@ +if exists("s:loaded") + finish +endif +let s:loaded = 1 + + +let s:OutlineImpl = {} +function! s:OutlineImpl.run(data) + for line in a:data.lines + if len(line) == 0 + continue + endif + let [_, node, fullname, type, filename, line, column, doc, random] = split(line, " ") + let name = join(split(fullname, "\\.")[1:], ".") + call setqflist([{ + \ 'filename': filename, + \ 'lnum': line, + \ 'col': column + 1, + \ 'text': node . " : " . name }], + \ 'a') + endfor + copen + nnoremap :call util#JumpFromQuickfix(0) + nnoremap o :call util#JumpFromQuickfix(1) +endfunction + +function! features#outline#run() + cclose + call setqflist([]) + call suggest#New("outline", 1, s:OutlineImpl) +endfunction diff --git a/autoload/features/rename.vim b/autoload/features/rename.vim new file mode 100644 index 0000000..bfcc696 --- /dev/null +++ b/autoload/features/rename.vim @@ -0,0 +1,41 @@ +if exists("s:loaded") + finish +endif +let s:loaded = 1 + +let s:RenameImpl = {} + + +function! s:RenameImpl.run(data) + if len(a:data.lines) == 1 + return + endif + + let oldName = split(split(util#FirstNonEmpty(a:data.lines), " ")[2], "\\.")[-1] + let newName = input("Rename symbol: ", oldName) + + for line in a:data.lines + if len(line) == 0 + continue + endif + + let [_, _, _, _, filename, line, column, _, _] = split(line, " ") + if !s:findInProject && filename != expand("%:p") + continue + endif + + if filename != expand("%:p") + execute ":e " . expand("%:p") + endif + + let left = getline(line)[0:column - 1] + let right = getline(line)[column + len(oldName):-1] + call setline(line, left . newName . right) + endfor +endfunction + + +function! features#rename#run(inProject) + let s:findInProject = a:inProject + call suggest#New("use", 1, s:RenameImpl) +endfunction diff --git a/autoload/features/usages.vim b/autoload/features/usages.vim new file mode 100644 index 0000000..7ff8cfc --- /dev/null +++ b/autoload/features/usages.vim @@ -0,0 +1,43 @@ +if exists("s:loaded") + finish +endif +let s:loaded = 1 + + +let s:UsagesImpl = {} + +function! s:UsagesImpl.run(data) + for line in a:data.lines + if len(line) == 0 + continue + endif + + let [ctype, context, fullname, type, filename, line, column, doc, random] = split(line, " ") + if !s:findInProject && filename != expand("%:p") + continue + endif + + let module = split(fullname, '\.')[0] + let name = split(fullname, '\.')[-1] + call setqflist([{ + \ 'filename': filename, + \ 'lnum': line, + \ 'col': column + 1, + \ 'text': ctype . ": " . name . " (" . fullname . ")"}], + \ 'a') + endfor + copen + nnoremap :call util#JumpFromQuickfix(0) + nnoremap o :call util#JumpFromQuickfix(1) +endfunction + + +function! features#usages#run(findInProject) + cclose + call setqflist([]) + let s:findInProject = a:findInProject + call suggest#New("use", 1, s:UsagesImpl) +endfunction + + + diff --git a/autoload/highlighter.vim b/autoload/highlighter.vim new file mode 100644 index 0000000..62efe00 --- /dev/null +++ b/autoload/highlighter.vim @@ -0,0 +1,96 @@ +if exists("s:loaded") + finish +endif +let s:loaded = 1 + +let s:NimHighlighter = {} + +function! s:NimHighlighter.on_stdout(job, chunk) + if len(a:chunk[0]) != 0 && !(a:chunk[0] =~ "^usage") + call extend(self.lines, a:chunk) + endif +endfunction + +function! s:NimHighlighter.on_stderr(job, chunk) +endfunction + +function! s:NimHighlighter.on_exit() + if self.file != expand("%:p") + return + endif + let highlights = { + \ 'skProc': ["Function", []], + \ 'skTemplate': ["PreProc", []], + \ 'skType': ["Type", []], + \ 'skMacro': ["Macro", []], + \ 'skMethod': ["Function", []], + \ 'skField': ["Identifier", []], + \ 'skAlias': ["Type", []], + \ 'skConditional': ["Conditional", []], + \ 'skConst': ["Constant", []], + \ 'skConverter': ["Function", []], + \ 'skDynLib': ["Include", []], + \ 'skEnumField': ["Identifier", []], + \ 'skForVar': ["Special", []], + \ 'skGenericParam': ["Typedef", []], + \ 'skGlobalVar': ["Constant", []], + \ 'skGlobalLet': ["Constant", []], + \ 'skIterator': ["Keyword", []], + \ 'skLabel': ["Identifier", []], + \ 'skLet': ["Constant", []], + \ 'skModule': ["Include", []], + \ 'skPackage': ["Define", []], + \ 'skParam': ["Identifier", []], + \ 'skResult': ["Keyword", []], + \ 'skStub': ["PreCondit", []], + \ 'skTemp': ["Identifier", []], + \ 'skUnknown': ["Error", []], + \ 'skVar': ["Constant", []] + \ } + + for line in self.lines + if len(line) == 0 + continue + endif + let p = split(line, " ") + let line = p[2] + 0 + let c = p[3] + 1 + let s = p[4] + 0 + if getline(line)[c - 1] == '*' + let c -= s + endif + call add(highlights[p[1]][1], [line, c, s]) + endfor + + let new_highlights = [] + for [k, v] in items(highlights) + call add(new_highlights, matchaddpos(v[0], v[1])) + endfor + + for m in b:old_highlights + call matchdelete(m) + endfor + + let b:old_highlights = new_highlights +endfunction + +function highlighter#New() + let result = copy(s:NimHighlighter) + let result.lines = [] + let result.job = jobstart([g:nvim_nim_exec_nimsuggest, '--v2', '--stdin', expand("%:p")], result) + let result.file = expand("%:p") + let tempfile = result.file . ".temp" + call writefile(getline(1, '$'), tempfile) + call jobsend(result.job, "highlight " . result.file . ";" . tempfile . ":1:1\nquit\n") + if !exists("b:old_highlights") + let b:old_highlights = [] + endif + return result +endfunction + + +function! highlighter#guard() + if line("$") + 0 < 500 + call highlighter#New() + endif +endfunction diff --git a/autoload/suggest.vim b/autoload/suggest.vim new file mode 100644 index 0000000..2d9b962 --- /dev/null +++ b/autoload/suggest.vim @@ -0,0 +1,40 @@ +if exists("s:loaded") + finish +endif +let s:loaded = 1 + + +let s:findInProject = 1 + +" 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 +endfunction + +function! s:NimSuggest.on_stderr() +endfunction + +function! s:NimSuggest.on_exit() + call self.handler.run(self) +endfunction + +function! suggest#New(command, useV2, handler) + let result = copy(s:NimSuggest) + let result.lines = [] + let result.file = expand("%:p") + let result.tempfile = result.file . ".temp" + let result.line = line(".") + let result.col = col(".") + let result.handler = a:handler + " if a:useTempFile + " call writefile(getline(1, '$'), result.tempfile) + " endif + " let nimcom = completion . " " . file . (a:useTempFile ? (";" . result.tempfile) : "") . ":" . line . ":" . col + let result.job = jobstart([g:nvim_nim_exec_nimsuggest, (a:useV2 ? '--v2' : ''), '--stdin', result.file], result) + call jobsend(result.job, a:command . " " . result.file . ":" . result.line . ":" . result.col . "\nquit\n") + return result +endfunction diff --git a/autoload/util.vim b/autoload/util.vim new file mode 100644 index 0000000..834b188 --- /dev/null +++ b/autoload/util.vim @@ -0,0 +1,42 @@ +if exists("s:loaded") + finish +endif +let s:loaded = 1 + + +function! util#FirstNonEmpty(lines) + for line in a:lines + if len(line) > 0 + return line + endif + endfor +endfunction + + +function! util#CheckDependency(command) + if !executable(a:command) + echoerr "Not found: " . a:command + finish + endif + return exepath(a:command) +endfunction + + +function! util#JumpToLocation(file, line, col) + if expand("%:p") != a:file + execute ":e " . a:file + endif + execute ":" . a:line + execute ":norm " . a:col . "|" +endfunction + + +function! util#JumpFromQuickfix(shouldReturn) + let [file, location, _] = split(getline(line(".")), "|") + let [l, c] = split(location, " col ") + wincmd p + call s:JumpToLocation(file, l, c) + if a:shouldReturn + wincmd p + endif +endfunction diff --git a/ftdetect/nim.vim b/ftdetect/nim.vim index 053f8c2..674a627 100644 --- a/ftdetect/nim.vim +++ b/ftdetect/nim.vim @@ -1,2 +1,8 @@ +if exists("s:loaded") + finish +endif +let s:loaded = 1 + + au BufNewFile,BufRead *.nim set filetype=nim au BufNewFile,BufRead *.nims set filetype=nims diff --git a/ftplugin/nim.vim b/ftplugin/nim.vim index cbee180..c2502f0 100644 --- a/ftplugin/nim.vim +++ b/ftplugin/nim.vim @@ -1,3 +1,18 @@ + +command! NimDefinition :call features#definition#run() +command! NimInfo :call features#info#run() +command! NimUsages :call features#usages#run(0) +command! NimUsagesProject :call features#usages#run(1) +command! NimRenameSymbol :call features#rename#run(0) +command! NimRenameSymbolProject :call features#rename#run(1) +command! NimDebug :call features#debug#run() +command! NimOutline :call features#outline#run() + nnoremap :NimDefinition nnoremap gd :NimDefinition nnoremap gt :NimInfo + +autocmd! CursorHold,InsertLeave,TextChanged,InsertEnter *.nim call highlighter#guard() +autocmd! BufReadPost,BufWritePost *.nim call highlighter#guard() + +call highlighter#guard() diff --git a/plugin/nim.vim b/plugin/nim.vim index 76360c6..2488e16 100644 --- a/plugin/nim.vim +++ b/plugin/nim.vim @@ -1,326 +1,10 @@ -if exists("b:loaded") +if exists("s:loaded") finish endif -let b:loaded = 1 +let s:loaded = 1 -" Check dependedncies -function! s:CheckDependency(command) - if !executable(a:command) - echoerr "Not found: " . a:command - finish - endif - return exepath(a:command) -endfunction - -let s:nim = s:CheckDependency("nim") -let s:nimble = s:CheckDependency("nimble") -let s:nimsuggest = s:CheckDependency("nimsuggest") -let s:bash = s:CheckDependency("bash") -let s:findInProject = 1 - - -" Nim highlighter -let s:NimHighlighter = {} - -function! s:NimHighlighter.New() - let result = copy(self) - let result.lines = [] - let result.job = jobstart([s:nimsuggest, '--v2', '--stdin', expand("%:p")], result) - let result.file = expand("%:p") - let tempfile = result.file . ".temp" - call writefile(getline(1, '$'), tempfile) - call jobsend(result.job, "highlight " . result.file . ";" . tempfile . ":1:1\nquit\n") - if !exists("b:old_highlights") - let b:old_highlights = [] - endif - return result -endfunction - -function! s:NimHighlighter.on_stdout(job, chunk) - if len(a:chunk[0]) != 0 && !(a:chunk[0] =~ "^usage") - call extend(self.lines, a:chunk) - endif -endfunction - -function! s:NimHighlighter.on_stderr(job, chunk) -endfunction - -function! s:NimHighlighter.on_exit() - if self.file != expand("%:p") - return - endif - let highlights = { - \ 'skProc': ["Function", []], - \ 'skTemplate': ["PreProc", []], - \ 'skType': ["Type", []], - \ 'skMacro': ["Macro", []], - \ 'skMethod': ["Function", []], - \ 'skField': ["Identifier", []], - \ 'skAlias': ["Type", []], - \ 'skConditional': ["Conditional", []], - \ 'skConst': ["Constant", []], - \ 'skConverter': ["Function", []], - \ 'skDynLib': ["Include", []], - \ 'skEnumField': ["Identifier", []], - \ 'skForVar': ["Special", []], - \ 'skGenericParam': ["Typedef", []], - \ 'skGlobalVar': ["Constant", []], - \ 'skGlobalLet': ["Constant", []], - \ 'skIterator': ["Keyword", []], - \ 'skLabel': ["Identifier", []], - \ 'skLet': ["Constant", []], - \ 'skModule': ["Include", []], - \ 'skPackage': ["Define", []], - \ 'skParam': ["Identifier", []], - \ 'skResult': ["Keyword", []], - \ 'skStub': ["PreCondit", []], - \ 'skTemp': ["Identifier", []], - \ 'skUnknown': ["Error", []], - \ 'skVar': ["Constant", []] - \ } - - for line in self.lines - if len(line) == 0 - continue - endif - let p = split(line, " ") - let line = p[2] + 0 - let c = p[3] + 1 - let s = p[4] + 0 - if getline(line)[c - 1] == '*' - let c -= s - endif - call add(highlights[p[1]][1], [line, c, s]) - endfor - - let new_highlights = [] - for [k, v] in items(highlights) - call add(new_highlights, matchaddpos(v[0], v[1])) - endfor - - for m in b:old_highlights - call matchdelete(m) - endfor - - let b:old_highlights = new_highlights -endfunction - - -" NimSuggest -let s:NimSuggest = {} - -function! s:NimSuggest.New(command, useV2, handler) - let result = copy(self) - let result.lines = [] - let result.file = expand("%:p") - let result.tempfile = result.file . ".temp" - let result.line = line(".") - let result.col = col(".") - let result.handler = a:handler - " if a:useTempFile - " call writefile(getline(1, '$'), result.tempfile) - " endif - " let nimcom = completion . " " . file . (a:useTempFile ? (";" . result.tempfile) : "") . ":" . line . ":" . col - - let result.job = jobstart([s:nimsuggest, (a:useV2 ? '--v2' : ''), '--stdin', result.file], result) - call jobsend(result.job, a:command . " " . result.file . ":" . result.line . ":" . result.col . "\n") - call jobsend(result.job, "quit\n") - return result -endfunction - -function! s:NimSuggest.on_stdout(job, chunk) - if len(a:chunk[0]) != 0 && !(a:chunk[0] =~ "^usage") - call extend(self.lines, a:chunk) - endif -endfunction - -function! s:NimSuggest.on_stderr() -endfunction - -function! s:NimSuggest.on_exit() - call self.handler.run(self) -endfunction - - -function! s:JumpToLocation(file, line, col) - if expand("%:p") != a:file - execute ":e " . a:file - endif - execute ":" . a:line - execute ":norm " . a:col . "|" -endfunction - -function! s:JumpFromQuickfix(shouldReturn) - let [file, location, _] = split(getline(line(".")), "|") - let [l, c] = split(location, " col ") - wincmd p - call s:JumpToLocation(file, l, c) - if a:shouldReturn - wincmd p - endif -endfunction - - -" Definitions -let s:DefinitionImpl = {} -function! s:DefinitionImpl.run(data) - if len(a:data.lines) > 0 - let [_, _, _, _, filename, l, c, _] = split(a:data.lines[0], " ") - call s:JumpToLocation(filename, l, c + 1) - endif -endfunction -function! s:NimGoToDefinition() - call s:NimSuggest.New("def", 0, s:DefinitionImpl) -endfunction - - -" Outline -let s:OutlineImpl = {} -function! s:OutlineImpl.run(data) - for line in a:data.lines - if len(line) == 0 - continue - endif - let [_, node, fullname, type, filename, line, column, doc, random] = split(line, " ") - let name = join(split(fullname, "\\.")[1:], ".") - call setqflist([{ - \ 'filename': filename, - \ 'lnum': line, - \ 'col': column + 1, - \ 'text': node . " : " . name }], - \ 'a') - endfor - copen - nnoremap :call JumpFromQuickfix(0) - nnoremap o :call JumpFromQuickfix(1) -endfunction -function! s:NimOutline() - cclose - call setqflist([]) - call s:NimSuggest.New("outline", 1, s:OutlineImpl) -endfunction - - -" Usage -let s:UsagesImpl = {} -function! s:UsagesImpl.run(data) - for line in a:data.lines - if len(line) == 0 - continue - endif - - let [ctype, context, fullname, type, filename, line, column, doc, random] = split(line, " ") - if !s:findInProject && filename != expand("%:p") - continue - endif - - let module = split(fullname, '\.')[0] - let name = split(fullname, '\.')[-1] - call setqflist([{ - \ 'filename': filename, - \ 'lnum': line, - \ 'col': column + 1, - \ 'text': ctype . ": " . name . " (" . fullname . ")"}], - \ 'a') - endfor - copen - nnoremap :call JumpFromQuickfix(0) - nnoremap o :call JumpFromQuickfix(1) -endfunction -function! s:NimUsages(findInProject) - cclose - call setqflist([]) - let s:findInProject = a:findInProject - call s:NimSuggest.New("use", 1, s:UsagesImpl) -endfunction - - -function! s:FirstNonEmpty(lines) - for line in a:lines - if len(line) > 0 - return line - endif - endfor -endfunction - - -let s:RenameImpl = {} -function! s:RenameImpl.run(data) - if len(a:data.lines) == 0 - return - endif - - let oldName = split(split(s:FirstNonEmpty(a:data.lines), " ")[2], "\\.")[-1] - let newName = input("Rename symbol: ", oldName) - - for line in a:data.lines - if len(line) == 0 - continue - endif - - let [_, _, _, _, filename, line, column, _, _] = split(line, " ") - if !s:findInProject && filename != expand("%:p") - continue - endif - - if filename != expand("%:p") - execute ":e " . expand("%:p") - endif - - let left = getline(line)[0:column - 1] - let right = getline(line)[column + len(oldName):-1] - call setline(line, left . newName . right) - endfor -endfunction -function! s:NimRenameSymbol(inProject) - let s:findInProject = a:inProject - call s:NimSuggest.New("use", 1, s:RenameImpl) -endfunction - - -" Info -let s:InfoImpl = {} -function! s:InfoImpl.run(data) - if len(a:data.lines) == 0 - echo "No information found" - else - let [_, ctype, name, type, filename, l, c, doc] = split(a:data.lines[0], " ") - echohl Function | echon "Type" - echohl Comment | echon ": " - echohl Statement | echon type - endif -endfunction -function! s:NimInfo() - call s:NimSuggest.New("def", 0, s:InfoImpl) -endfunction - - -" Config -function! s:NimDebug() - echo "Nim tools debugging info" - echo "------------------------" - echo "\n" - echo "-------- Tools ---------" - echo "Nim: " . s:nim - echo "Nimble: " . s:nimble - echo "Nimsuggest: " . s:nimsuggest -endfunction - -command! NimDefinition :call s:NimGoToDefinition() -command! NimInfo :call s:NimInfo() -command! NimUsages :call s:NimUsages(0) -command! NimUsagesProject :call s:NimUsages(1) -command! NimOutline :call s:NimOutline() -command! NimRenameSymbol :call s:NimRenameSymbol(0) -command! NimRenameSymbolProject :call s:NimRenameSymbol(1) -command! NimDebug :call s:NimDebug() - -function! s:hlGuard() - if line("$") + 0 < 500 - call s:NimHighlighter.New() - endif -endfunction - -autocmd! CursorHold,InsertLeave,TextChanged,InsertEnter *.nim call s:hlGuard() -autocmd! BufReadPost,BufWritePost *.nim call s:hlGuard() +let g:nvim_nim_exec_nim = util#CheckDependency("nim") +let g:nvim_nim_exec_nimble = util#CheckDependency("nimble") +let g:nvim_nim_exec_nimsuggest = util#CheckDependency("nimsuggest") +let g:nvim_nim_exec_bash = util#CheckDependency("bash")