diff --git a/README.md b/README.md index 55e423e..74cb7d4 100644 --- a/README.md +++ b/README.md @@ -42,14 +42,17 @@ Nim support for Neovim - [x] NimRenameSymbol - [ ] NimRenameSymbolProject +- [ ] Misc + - [ ] Airline integration + - [ ] IDE features - [x] Neomake + - [x] View online documentation + - [x] Outline with a proper tagbar - [ ] Search and view online documentation - [ ] Usages with unite - [ ] Outline with unite - - [ ] Outline with a proper tagbar - [ ] Parse proc parameter types for parameter completion - - [ ] Airline integration - [ ] When lines are added or removed use cached highlighter results - [ ] When editing line, remove highlighter results from that line @@ -122,8 +125,6 @@ Nim support for Neovim ## v0.2 ## v0.3 -## v0.1 -## v0.1 # TASKS diff --git a/autoload/features/info.vim b/autoload/features/info.vim index 39990ef..65c8779 100644 --- a/autoload/features/info.vim +++ b/autoload/features/info.vim @@ -6,12 +6,23 @@ let s:loaded = 1 let s:InfoImpl = {} +function! s:New(useWeb) + let result = copy(s:InfoImpl) + let result.useWeb = a:useWeb + return result +endfunction + function! s:InfoImpl.run(data) if len(a:data.lines) == 0 echo "No information found" - else - let res = util#ParseV1(a:data.lines[0]) + return + endif + let res = util#ParseV1(a:data.lines[0]) + + if self.useWeb + call util#open_module_doc(res.location, res.lname) + else echohl None echohl Function | echon res.lname echohl Comment | echon "\n » " @@ -37,6 +48,11 @@ function! s:InfoImpl.run(data) endfunction -function! features#info#run() - call suggest#New("def", 0, 0, s:InfoImpl) +function! features#info#web() + call suggest#New("def", 1, 0, s:New(1)) +endfunction + + +function! features#info#run() + call suggest#New("def", 1, 0, s:New(0)) endfunction diff --git a/autoload/features/outline.vim b/autoload/features/outline.vim index 3815603..63e3302 100644 --- a/autoload/features/outline.vim +++ b/autoload/features/outline.vim @@ -3,33 +3,193 @@ if exists("s:loaded") endif let s:loaded = 1 +function! features#outline#renderable(parsed) + return { + \ 'line': a:parsed.line, + \ 'col': a:parsed.col, + \ 'name': a:parsed.lname, + \ 'kind': a:parsed.kind } +endfunction -let s:OutlineImpl = { - \ 'pty': 1, +let s:window = -1 +let s:goto_table = {} +let s:groups = {} +let s:group_order = ["Types", "Callables", "Constants", "Globals", "Imports"] +let s:symbols = { + \ 'skProc': "proc", + \ 'skTemplate': "template", + \ 'skType': "", + \ 'skMacro': "macro", + \ 'skMethod': "function", + \ 'skField': "field", + \ 'skAlias': "alias", + \ 'skConst': "constant", + \ 'skConverter': "converter", + \ 'skDynLib': "dynlib", + \ 'skEnumField': "enum", + \ 'skGlobalVar': "var", + \ 'skGlobalLet': "let", + \ 'skIterator': "iterator", + \ 'skLabel': "label", + \ 'skLet': "constant", + \ 'skModule': "module", + \ 'skPackage': "package", \ } -function! s:OutlineImpl.run(data) - for line in a:data.lines - if len(line) == 0 + " \ 'skField': "Fields", +let s:group_aliases = { + \ 'skType': "Types", + \ 'skProc': "Callables", + \ 'skTemplate': "Callables", + \ 'skMacro': "Callables", + \ 'skMethod': "Callables", + \ 'skConverter': "Callables", + \ 'skIterator': "Callables", + \ 'skConst': "Constants", + \ 'skLet': "Constants", + \ 'skGlobalVar': "Globals", + \ 'skGlobalLet': "Globals", + \ 'skDynLib': "Imports", + \ 'skModule': "Imports", + \ 'skPackage': "Imports", + \ } + +function! s:CreateSymbolRow(symbol) + let result = " » " . a:symbol.name + if len(s:symbols[a:symbol.kind]) > 0 + let result .= " (" . s:symbols[a:symbol.kind] . ")" + endif + return result +endfunction + +function! s:ConfigureOutlineBuffer() + if s:IsOpen() + return + endif + + let s:window = winnr() + vsplit __nim_outline__ + setlocal filetype=nimoutline + setlocal buftype=nofile + setlocal nonumber + setlocal nowrap + nnoremap :call features#outline#JumpToSymbol(0) + nnoremap o :call features#outline#JumpToSymbol(1) +endfunction + +function! features#outline#JumpToSymbol(stay) + if !s:IsFocused() + return + endif + + let l = line(".") + if !has_key(s:goto_table, l) + return + endif + + let [jl, jc] = s:goto_table[l] + call util#JumpToWindow(s:window, jl, jc) + normal! ^ + + if a:stay + normal! zt + wincmd p + endif +endfunction + +function! s:UpdateOutline(groups) + let s:goto_table = {} + let s:groups = a:groups + call s:ConfigureOutlineBuffer() + call s:RenderOutline() +endfunction + +function! s:RenderOutline() + let wasFocused = s:IsFocused() + + call s:Focus() + if !s:IsFocused() + return + endif + + exec "silent vertical resize " . g:nvim_nim_outline_buffer_width + + let rlines = [] + + for groupname in s:group_order + if len(s:groups[groupname]) == 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') + + call add(rlines, groupname) + + for symbol in s:groups[groupname] + let s:goto_table[len(rlines) + 1] = [symbol.line, symbol.col] + call add(rlines, s:CreateSymbolRow(symbol)) + endfor + call add(rlines, "") endfor - copen - nnoremap :call util#JumpFromQuickfix(0) - nnoremap o :call util#JumpFromQuickfix(1) + + let idx = 1 + for line in rlines + call setline(idx, line) + let idx += 1 + endfor + + exec ":" . len(rlines) + normal! dG + if !wasFocused + wincmd p + endif endfunction -function! features#outline#run() - cclose - call setqflist([]) - call suggest#New("outline", 0, 1, s:OutlineImpl) +function! s:Window() + return bufwinnr("__nim_outline__") +endfunction + +function! s:IsOpen() + return s:Window() != -1 +endfunction + +function! s:IsFocused() + return s:IsOpen() && s:Window() == winnr() +endfunction + +function! s:Focus() + if s:IsOpen() + exec ":" . s:Window() . "wincmd w" + endif +endfunction + +function! features#outline#render() + call s:RenderOutline() +endfunction + +let s:OutlineImpl = {} +function! s:OutlineImpl.run(data) + let s:groups = { + \ "Types": [], + \ "Callables": [], + \ "Fields": [], + \ "Constants": [], + \ "Globals": [], + \ "Imports": [], + \ } + + for line in a:data.lines + let p = util#ParseV2(line) + if has_key(s:group_aliases, p.kind) + let renderable = features#outline#renderable(p) + call add(s:groups[s:group_aliases[p.kind]], renderable) + endif + endfor + + call s:UpdateOutline(s:groups) +endfunction + +function! features#outline#run(isUpdating) + if !a:isUpdating || s:IsOpen() + call suggest#New("outline", 1, 1, s:OutlineImpl) + endif endfunction diff --git a/autoload/util.vim b/autoload/util.vim index 6903299..075ad03 100644 --- a/autoload/util.vim +++ b/autoload/util.vim @@ -53,6 +53,13 @@ function! util#CheckDependency(command) endfunction +function! util#JumpToWindow(window, line, col) + execute ":" . a:window . "wincmd w" + execute ":" . a:line + execute ":norm " . (a:col) . "|" +endfunction + + function! util#JumpToLocation(file, line, col) if expand("%:p") != a:file execute ":e " . a:file @@ -195,3 +202,7 @@ function! util#djb(str) endfor return float2nr(hash) endfunction + +function! util#open_module_doc(module, symbol) + call system("$BROWSER " . "http://nim-lang.org/docs/" . a:module . ".html#" . a:symbol) +endfunction diff --git a/ftdetect/nim.vim b/ftdetect/nim.vim index d349598..69bff37 100644 --- a/ftdetect/nim.vim +++ b/ftdetect/nim.vim @@ -14,4 +14,7 @@ let g:nvim_nim_highlight_use_unite = 0 let g:nvim_nim_autocomplete = "omni" " omni, deoplete, ycm let g:nvim_nim_outline = "quickfix" " quickfix, outline +let g:nvim_nim_outline_buffer = 1 +let g:nvim_nim_outline_buffer_width = 30 + let g:nvim_nim_highlighter_semantics = ["skConst", "skForVar", "skGlobalVar", "skGlobalLet", "skLet", "skModule", "skParam", "skTemp", "skVar"] diff --git a/ftplugin/nim.vim b/ftplugin/nim.vim index b60c26a..c8278db 100644 --- a/ftplugin/nim.vim +++ b/ftplugin/nim.vim @@ -1,6 +1,6 @@ -" if exists("b:loaded") -" finish -" endif +if exists("b:loaded") + finish +endif let b:loaded = 1 setlocal formatoptions-=t formatoptions+=l @@ -11,31 +11,30 @@ setlocal omnifunc=omni#nim command! NimDefinition :call features#definition#run() command! NimInfo :call features#info#run() +command! NimWeb :call features#info#web() 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() +command! NimOutline :call features#outline#run(0) -command! NimEdb :call features#debugger#run() -command! NimEdbStop :call features#debugger#stop() -command! NimEdbContinue :call features#debugger#continue() -command! NimEdbStepInto :call features#debugger#stepinto() -command! NimEdbStepOver :call features#debugger#stepover() -command! NimEdbSkipCurrent :call features#debugger#skipcurrent() -command! NimEdbIgonore :call features#debugger#ignore() -command! NimEdbContinue :call features#debugger#continue() -command! NimEdbToggleBP :call features#debugger#togglebp() +command! NimEdb :call features#debugger#run() +command! NimEdbStop :call features#debugger#stop() +command! NimEdbContinue :call features#debugger#continue() +command! NimEdbStepInto :call features#debugger#stepinto() +command! NimEdbStepOver :call features#debugger#stepover() +command! NimEdbSkipCurrent :call features#debugger#skipcurrent() +command! NimEdbIgonore :call features#debugger#ignore() +command! NimEdbContinue :call features#debugger#continue() +command! NimEdbToggleBP :call features#debugger#togglebp() nnoremap :NimDefinition -nnoremap gd :NimDefinition -nnoremap gt :NimInfo -nnoremap gT :NimInfoVerbose - -autocmd! CursorHold,InsertLeave,TextChanged,InsertEnter *.nim call highlighter#guard() -autocmd! BufReadPost,BufWritePost *.nim call highlighter#guard() -" autocmd! BufWinEnter quickfix let g:qfix_win = bufnr("$") -" autocmd! BufWinLeave * if exists("g:qfix_win") && expand("") == g:qfix_win | call features#usages#clear_matches() | unlet! g:qfix_win | endif +nnoremap gd :NimDefinition +nnoremap gt :NimInfo +nnoremap gT :NimWeb +autocmd! BufReadPost,BufWritePost,CursorHold,InsertLeave,TextChanged,InsertEnter *.nim call highlighter#guard() +autocmd! BufWinEnter,BufWritePost,FileWritePost *.nim call features#outline#run(1) +autocmd! VimResized,WinEnter * call features#outline#render() call highlighter#guard() diff --git a/other/pic1.png b/other/pic1.png new file mode 100644 index 0000000..4df41f8 Binary files /dev/null and b/other/pic1.png differ diff --git a/plugin/nim.vim b/plugin/nim.vim index cf2bb5e..896b584 100644 --- a/plugin/nim.vim +++ b/plugin/nim.vim @@ -3,8 +3,6 @@ " endif " let s:loaded = 1 -" echom join(util#ParseSignature("proc (dest:string,sep:string; startLen:Natural):string{.moro.}"), " -> ") - 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") diff --git a/syntax/nimoutline.vim b/syntax/nimoutline.vim new file mode 100644 index 0000000..3677f5d --- /dev/null +++ b/syntax/nimoutline.vim @@ -0,0 +1,30 @@ +syntax keyword nimoTypes Types +syntax keyword nimoCallables Callables +syntax keyword nimoConstants Constants +syntax keyword nimoGlobals Globals +syntax keyword nimoImports Imports + +syntax match nimoSeparator "[»()<>\[\]]" +syntax match nimoDetail "(\(\w\+\))" + +hi link nimoConstants Constant +hi link nimoConverters Function +hi link nimoFields Type +hi link nimoGlobals Constant +hi link nimoInclude Include +hi link nimoIterators Function +hi link nimoMacros Macro +hi link nimoMethods Function +hi link nimoModules Include +hi link nimoPackages Include +hi link nimoProcs Function +hi link nimoTemplates Function +hi link nimoTypes Type +hi link nimoSeparator Comment + +hi link nimoTypes Type +hi link nimoCallables Function +hi link nimoConstants Constant +hi link nimoGlobals Identifier +hi link nimoImports Include +hi link nimoDetail Identifier