diff options
| author | Adam Stankiewicz <sheerun@sher.pl> | 2020-08-24 10:56:09 +0200 | 
|---|---|---|
| committer | Adam Stankiewicz <sheerun@sher.pl> | 2020-08-24 10:56:09 +0200 | 
| commit | 63a175357a139ebbecf724b5d8229d383a08afef (patch) | |
| tree | d338eeedf6ba4271c1a6d74b470815c8b1cf6424 /autoload | |
| parent | 25db54573ad9d436ffff97124887c68a74b07e66 (diff) | |
| download | vim-polyglot-63a175357a139ebbecf724b5d8229d383a08afef.tar.gz vim-polyglot-63a175357a139ebbecf724b5d8229d383a08afef.zip | |
Remove some custom dirs config
Diffstat (limited to 'autoload')
| -rw-r--r-- | autoload/fsharp.vim | 517 | ||||
| -rw-r--r-- | autoload/ledger.vim | 744 | ||||
| -rw-r--r-- | autoload/nim.vim | 244 | 
3 files changed, 1505 insertions, 0 deletions
| diff --git a/autoload/fsharp.vim b/autoload/fsharp.vim new file mode 100644 index 00000000..6816d822 --- /dev/null +++ b/autoload/fsharp.vim @@ -0,0 +1,517 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'fsharp') == -1 + +" Vim autoload functions + +if exists('g:loaded_autoload_fsharp') +    finish +endif +let g:loaded_autoload_fsharp = 1 + +let s:cpo_save = &cpo +set cpo&vim + +function! s:prompt(msg) +    let height = &cmdheight +    if height < 2 +        set cmdheight=2 +    endif +    echom a:msg +    let &cmdheight = height +endfunction + +function! s:PlainNotification(content) +    return { 'Content': a:content } +endfunction + +function! s:TextDocumentIdentifier(path) +    let usr_ss_opt = &shellslash +    set shellslash +    let uri = fnamemodify(a:path, ":p") +    if uri[0] == "/" +        let uri = "file://" . uri +    else +        let uri = "file:///" . uri +    endif +    let &shellslash = usr_ss_opt +    return { 'Uri': uri } +endfunction + +function! s:Position(line, character) +    return { 'Line': a:line, 'Character': a:character } +endfunction + +function! s:TextDocumentPositionParams(documentUri, line, character) +    return { +        \ 'TextDocument': s:TextDocumentIdentifier(a:documentUri), +        \ 'Position':     s:Position(a:line, a:character) +        \ } +endfunction + +function! s:DocumentationForSymbolRequest(xmlSig, assembly) +    return { +        \ 'XmlSig': a:xmlSig, +        \ 'Assembly': a:assembly +        \ } +endfunction + +function! s:ProjectParms(projectUri) +    return { 'Project': s:TextDocumentIdentifier(a:projectUri) } +endfunction + +function! s:WorkspacePeekRequest(directory, deep, excludedDirs) +    return { +        \ 'Directory': fnamemodify(a:directory, ":p"), +        \ 'Deep': a:deep, +        \ 'ExcludedDirs': a:excludedDirs +        \ } +endfunction + +function! s:WorkspaceLoadParms(files) +    let prm = [] +    for file in a:files +        call add(prm, s:TextDocumentIdentifier(file)) +    endfor +    return { 'TextDocuments': prm } +endfunction + +function! s:FsdnRequest(query) +    return { 'Query': a:query } +endfunction + +function! s:call(method, params, cont) +    call LanguageClient#Call(a:method, a:params, a:cont) +endfunction + +function! s:signature(filePath, line, character, cont) +    return s:call('fsharp/signature', s:TextDocumentPositionParams(a:filePath, a:line, a:character), a:cont) +endfunction +function! s:signatureData(filePath, line, character, cont) +    return s:call('fsharp/signatureData', s:TextDocumentPositionParams(a:filePath, a:line, a:character), a:cont) +endfunction +function! s:lineLens(projectPath, cont) +    return s:call('fsharp/lineLens', s:ProjectParms(a:projectPath), a:cont) +endfunction +function! s:compilerLocation(cont) +    return s:call('fsharp/compilerLocation', {}, a:cont) +endfunction +function! s:compile(projectPath, cont) +    return s:call('fsharp/compile', s:ProjectParms(a:projectPath), a:cont) +endfunction +function! s:workspacePeek(directory, depth, excludedDirs, cont) +    return s:call('fsharp/workspacePeek', s:WorkspacePeekRequest(a:directory, a:depth, a:excludedDirs), a:cont) +endfunction +function! s:workspaceLoad(files, cont) +    return s:call('fsharp/workspaceLoad', s:WorkspaceLoadParms(a:files), a:cont) +endfunction +function! s:project(projectPath, cont) +    return s:call('fsharp/project', s:ProjectParms(a:projectPath), a:cont) +endfunction +function! s:fsdn(signature, cont) +    return s:call('fsharp/fsdn', s:FsdnRequest(a:signature), a:cont) +endfunction +function! s:f1Help(filePath, line, character, cont) +    return s:call('fsharp/f1Help', s:TextDocumentPositionParams(a:filePath, a:line, a:character), a:cont) +endfunction +function! fsharp#documentation(filePath, line, character, cont) +    return s:call('fsharp/documentation', s:TextDocumentPositionParams(a:filePath, a:line, a:character), a:cont) +endfunction +function! s:documentationSymbol(xmlSig, assembly, cont) +    return s:call('fsharp/documentationSymbol', s:DocumentationForSymbolRequest(a:xmlSig, a:assembly), a:cont) +endfunction + +" FSharpConfigDto from https://github.com/fsharp/FsAutoComplete/blob/master/src/FsAutoComplete/LspHelpers.fs +"  +" * The following options seems not working with workspace/didChangeConfiguration +"   since the initialization has already completed? +"     'AutomaticWorkspaceInit', +"     'WorkspaceModePeekDeepLevel', +" +" * Changes made to linter/unused analyzer settings seems not reflected after sending them to FSAC? +" +let s:config_keys_camel = +    \ [ +    \     {'key': 'AutomaticWorkspaceInit', 'default': 1}, +    \     {'key': 'WorkspaceModePeekDeepLevel', 'default': 2}, +    \     {'key': 'ExcludeProjectDirectories', 'default': []}, +    \     {'key': 'keywordsAutocomplete', 'default': 1}, +    \     {'key': 'ExternalAutocomplete', 'default': 0}, +    \     {'key': 'Linter', 'default': 1}, +    \     {'key': 'UnionCaseStubGeneration', 'default': 1}, +    \     {'key': 'UnionCaseStubGenerationBody'}, +    \     {'key': 'RecordStubGeneration', 'default': 1}, +    \     {'key': 'RecordStubGenerationBody'}, +    \     {'key': 'InterfaceStubGeneration', 'default': 1}, +    \     {'key': 'InterfaceStubGenerationObjectIdentifier', 'default': 'this'}, +    \     {'key': 'InterfaceStubGenerationMethodBody'}, +    \     {'key': 'UnusedOpensAnalyzer', 'default': 1}, +    \     {'key': 'UnusedDeclarationsAnalyzer', 'default': 1}, +    \     {'key': 'SimplifyNameAnalyzer', 'default': 0}, +    \     {'key': 'ResolveNamespaces', 'default': 1}, +    \     {'key': 'EnableReferenceCodeLens', 'default': 1}, +    \     {'key': 'EnableAnalyzers', 'default': 0}, +    \     {'key': 'AnalyzersPath'}, +    \     {'key': 'DisableInMemoryProjectReferences', 'default': 0}, +    \     {'key': 'LineLens', 'default': {'enabled': 'replaceCodeLens', 'prefix': '//'}}, +    \     {'key': 'UseSdkScripts', 'default': 1}, +    \     {'key': 'dotNetRoot'}, +    \     {'key': 'fsiExtraParameters', 'default': []}, +    \ ] +let s:config_keys = [] + +function! fsharp#toSnakeCase(str) +    let sn = substitute(a:str, '\(\<\u\l\+\|\l\+\)\(\u\)', '\l\1_\l\2', 'g') +    if sn == a:str | return tolower(a:str) | endif +    return sn +endfunction + +function! s:buildConfigKeys() +    if len(s:config_keys) == 0 +        for key_camel in s:config_keys_camel +            let key = {} +            let key.snake = fsharp#toSnakeCase(key_camel.key) +            let key.camel = key_camel.key +            if has_key(key_camel, 'default') +                let key.default = key_camel.default +            endif +            call add(s:config_keys, key) +        endfor +    endif +endfunction + +function! g:fsharp#getServerConfig() +    let fsharp = {} +    call s:buildConfigKeys()  +    for key in s:config_keys +        if exists('g:fsharp#' . key.snake) +            let fsharp[key.camel] = g:fsharp#{key.snake} +        elseif exists('g:fsharp#' . key.camel) +            let fsharp[key.camel] = g:fsharp#{key.camel} +        elseif has_key(key, 'default') && g:fsharp#use_recommended_server_config +            let g:fsharp#{key.snake} = key.default +            let fsharp[key.camel] = key.default +        endif +    endfor +    return fsharp +endfunction + +function! g:fsharp#updateServerConfig() +    let fsharp = fsharp#getServerConfig() +    let settings = {'settings': {'FSharp': fsharp}} +    call LanguageClient#Notify('workspace/didChangeConfiguration', settings) +endfunction + +function! s:findWorkspace(dir, cont) +    let s:cont_findWorkspace = a:cont +    function! s:callback_findWorkspace(result) +        let result = a:result +        let content = json_decode(result.result.content) +        if len(content.Data.Found) < 1 +            return [] +        endif +        let workspace = { 'Type': 'none' } +        for found in content.Data.Found +            if workspace.Type == 'none' +                let workspace = found +            elseif found.Type == 'solution' +                if workspace.Type == 'project' +                    let workspace = found +                else +                    let curLen = len(workspace.Data.Items) +                    let newLen = len(found.Data.Items) +                    if newLen > curLen +                        let workspace = found +                    endif +                endif +            endif +        endfor +        if workspace.Type == 'solution' +            call s:cont_findWorkspace([workspace.Data.Path]) +        else +            call s:cont_findWorkspace(workspace.Data.Fsprojs) +        endif +    endfunction +    call s:workspacePeek(a:dir, g:fsharp#workspace_mode_peek_deep_level, g:fsharp#exclude_project_directories, function("s:callback_findWorkspace")) +endfunction + +let s:workspace = [] + +function! s:load(arg) +    let s:loading_workspace = a:arg +    function! s:callback_load(_) +        echo "[FSAC] Workspace loaded: " . join(s:loading_workspace, ', ') +        let s:workspace = s:workspace + s:loading_workspace +    endfunction +    call s:workspaceLoad(a:arg, function("s:callback_load")) +endfunction + +function! fsharp#loadProject(...) +    let prjs = [] +    for proj in a:000 +        call add(prjs, fnamemodify(proj, ':p')) +    endfor +    call s:load(prjs) +endfunction + +function! fsharp#loadWorkspaceAuto() +    if &ft == 'fsharp' +        call fsharp#updateServerConfig() +        if g:fsharp#automatic_workspace_init +            echom "[FSAC] Loading workspace..." +            let bufferDirectory = fnamemodify(resolve(expand('%:p')), ':h') +            call s:findWorkspace(bufferDirectory, function("s:load")) +        endif +    endif +endfunction + +function! fsharp#reloadProjects() +    if len(s:workspace) > 0 +        function! s:callback_reloadProjects(_) +            call s:prompt("[FSAC] Workspace reloaded.") +        endfunction +        call s:workspaceLoad(s:workspace, function("s:callback_reloadProjects")) +    else +        echom "[FSAC] Workspace is empty" +    endif +endfunction + +function! fsharp#OnFSProjSave() +    if &ft == "fsharp_project" && exists('g:fsharp#automatic_reload_workspace') && g:fsharp#automatic_reload_workspace +        call fsharp#reloadProjects() +    endif +endfunction + +function! fsharp#showSignature() +    function! s:callback_showSignature(result) +        let result = a:result +        if exists('result.result.content') +            let content = json_decode(result.result.content) +            if exists('content.Data') +                echom substitute(content.Data, '\n\+$', ' ', 'g') +            endif +        endif +    endfunction +    call s:signature(expand('%:p'), line('.') - 1, col('.') - 1, function("s:callback_showSignature")) +endfunction + +function! fsharp#OnCursorMove() +    if g:fsharp#show_signature_on_cursor_move +        call fsharp#showSignature() +    endif +endfunction + +function! fsharp#showF1Help() +    let result = s:f1Help(expand('%:p'), line('.') - 1, col('.') - 1) +    echo result +endfunction + +function! fsharp#showTooltip() +    function! s:callback_showTooltip(result) +        let result = a:result +        if exists('result.result.content') +            let content = json_decode(result.result.content) +            if exists('content.Data') +                call LanguageClient#textDocument_hover() +            endif +        endif +    endfunction +    " show hover only if signature exists for the current position +    call s:signature(expand('%:p'), line('.') - 1, col('.') - 1, function("s:callback_showTooltip")) +endfunction + +let s:script_root_dir = expand('<sfile>:p:h') . "/../" +let s:fsac = fnamemodify(s:script_root_dir . "fsac/fsautocomplete.dll", ":p") +let g:fsharp#languageserver_command = +    \ ['dotnet', s:fsac,  +        \ '--background-service-enabled' +    \ ] + +function! s:download(branch) +    echom "[FSAC] Downloading FSAC. This may take a while..." +    let zip = s:script_root_dir . "fsac.zip" +    call system( +        \ 'curl -fLo ' . zip .  ' --create-dirs ' . +        \ '"https://ci.appveyor.com/api/projects/fsautocomplete/fsautocomplete/artifacts/bin/pkgs/fsautocomplete.netcore.zip?branch=' . a:branch . '"' +        \ ) +    if v:shell_error == 0 +        call system('unzip -o -d ' . s:script_root_dir . "/fsac " . zip) +        echom "[FSAC] Updated FsAutoComplete to version " . a:branch . ""  +    else +        echom "[FSAC] Failed to update FsAutoComplete" +    endif +endfunction + +function! fsharp#updateFSAC(...) +    if len(a:000) == 0 +        let branch = "master" +    else +        let branch = a:000[0] +    endif +    call s:download(branch) +endfunction + +let s:fsi_buffer = -1 +let s:fsi_job    = -1 +let s:fsi_width  = 0 +let s:fsi_height = 0 + +function! s:win_gotoid_safe(winid) +    function! s:vimReturnFocus(window) +        call win_gotoid(a:window) +        redraw! +    endfunction +    if has('nvim') +        call win_gotoid(a:winid) +    else +        call timer_start(1, { -> s:vimReturnFocus(a:winid) }) +    endif +endfunction + +function! s:get_fsi_command() +    let cmd = g:fsharp#fsi_command +    for prm in g:fsharp#fsi_extra_parameters +        let cmd = cmd . " " . prm +    endfor +    return cmd +endfunction + +function! fsharp#openFsi(returnFocus) +    if bufwinid(s:fsi_buffer) <= 0 +        let fsi_command = s:get_fsi_command() +        " Neovim +        if exists('*termopen') || exists('*term_start') +            let current_win = win_getid() +            execute g:fsharp#fsi_window_command +            if s:fsi_width  > 0 | execute 'vertical resize' s:fsi_width | endif +            if s:fsi_height > 0 | execute 'resize' s:fsi_height | endif +            " if window is closed but FSI is still alive then reuse it +            if s:fsi_buffer >= 0 && bufexists(str2nr(s:fsi_buffer)) +                exec 'b' s:fsi_buffer +                normal G +                if !has('nvim') && mode() == 'n' | execute "normal A" | endif +                if a:returnFocus | call s:win_gotoid_safe(current_win) | endif +            " open FSI: Neovim +            elseif has('nvim') +                let s:fsi_job = termopen(fsi_command) +                if s:fsi_job > 0 +                    let s:fsi_buffer = bufnr("%") +                else +                    close +                    echom "[FSAC] Failed to open FSI." +                    return -1 +                endif +            " open FSI: Vim +            else +                let options = { +                \ "term_name": "F# Interactive", +                \ "curwin": 1, +                \ "term_finish": "close" +                \ } +                let s:fsi_buffer = term_start(fsi_command, options) +                if s:fsi_buffer != 0 +                    if exists('*term_setkill') | call term_setkill(s:fsi_buffer, "term") | endif +                    let s:fsi_job = term_getjob(s:fsi_buffer) +                else +                    close +                    echom "[FSAC] Failed to open FSI." +                    return -1 +                endif +            endif +            setlocal bufhidden=hide +            normal G +            if a:returnFocus | call s:win_gotoid_safe(current_win) | endif +            return s:fsi_buffer +        else +            echom "[FSAC] Your Vim does not support terminal". +            return 0 +        endif +    endif +    return s:fsi_buffer +endfunction + +function! fsharp#toggleFsi() +    let fsiWindowId = bufwinid(s:fsi_buffer) +    if fsiWindowId > 0 +        let current_win = win_getid() +        call win_gotoid(fsiWindowId) +        let s:fsi_width = winwidth('%') +        let s:fsi_height = winheight('%') +        close +        call win_gotoid(current_win) +    else +        call fsharp#openFsi(0) +    endif +endfunction + +function! fsharp#quitFsi() +    if s:fsi_buffer >= 0 && bufexists(str2nr(s:fsi_buffer)) +        if has('nvim') +            let winid = bufwinid(s:fsi_buffer) +            if winid > 0 | execute "close " . winid | endif +            call jobstop(s:fsi_job) +        else +            call job_stop(s:fsi_job, "term") +        endif +        let s:fsi_buffer = -1 +        let s:fsi_job = -1 +    endif +endfunction + +function! fsharp#resetFsi() +    call fsharp#quitFsi() +    return fsharp#openFsi(1) +endfunction + +function! fsharp#sendFsi(text) +    if fsharp#openFsi(!g:fsharp#fsi_focus_on_send) > 0 +        " Neovim +        if has('nvim') +            call chansend(s:fsi_job, a:text . ";;". "\n") +        " Vim 8 +        else +            call term_sendkeys(s:fsi_buffer, a:text . ";;" . "\<cr>") +            call term_wait(s:fsi_buffer) +        endif +    endif +endfunction + +" https://stackoverflow.com/a/6271254 +function! s:get_visual_selection() +    let [line_start, column_start] = getpos("'<")[1:2] +    let [line_end, column_end] = getpos("'>")[1:2] +    let lines = getline(line_start, line_end) +    if len(lines) == 0 +        return '' +    endif +    let lines[-1] = lines[-1][: column_end - (&selection == 'inclusive' ? 1 : 2)] +    let lines[0] = lines[0][column_start - 1:] +    return lines +endfunction + +function! s:get_complete_buffer() +    return join(getline(1, '$'), "\n") +endfunction + +function! fsharp#sendSelectionToFsi() range +    let lines = s:get_visual_selection() +    exec 'normal' len(lines) . 'j' +    let text = join(lines, "\n") +    return fsharp#sendFsi(text) +endfunction + +function! fsharp#sendLineToFsi() +    let text = getline('.') +    exec 'normal j' +    return fsharp#sendFsi(text) +endfunction + +function! fsharp#sendAllToFsi() +    let text = s:get_complete_buffer() +    return fsharp#sendFsi(text) +endfunction + +let &cpo = s:cpo_save +unlet s:cpo_save + +" vim: sw=4 et sts=4 + +endif diff --git a/autoload/ledger.vim b/autoload/ledger.vim new file mode 100644 index 00000000..225f96a3 --- /dev/null +++ b/autoload/ledger.vim @@ -0,0 +1,744 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'ledger') == -1 + +scriptencoding utf-8 +" vim:ts=2:sw=2:sts=2:foldmethod=marker +function! ledger#transaction_state_toggle(lnum, ...) abort +  if a:0 == 1 +    let chars = a:1 +  else +    let chars = ' *' +  endif +  let trans = s:transaction.from_lnum(a:lnum) +  if empty(trans) || has_key(trans, 'expr') +    return +  endif + +  let old = has_key(trans, 'state') ? trans['state'] : ' ' +  let i = stridx(chars, old) + 1 +  let new = chars[i >= len(chars) ? 0 : i] + +  call trans.set_state(new) + +  call setline(trans['head'], trans.format_head()) +endf + +function! ledger#transaction_state_set(lnum, char) abort +  " modifies or sets the state of the transaction at the cursor, +  " removing the state altogether if a:char is empty +  let trans = s:transaction.from_lnum(a:lnum) +  if empty(trans) || has_key(trans, 'expr') +    return +  endif + +  call trans.set_state(a:char) + +  call setline(trans['head'], trans.format_head()) +endf + +function! ledger#transaction_date_set(lnum, type, ...) abort +  let time = a:0 == 1 ? a:1 : localtime() +  let trans = s:transaction.from_lnum(a:lnum) +  if empty(trans) || has_key(trans, 'expr') +    return +  endif + +  let formatted = strftime(g:ledger_date_format, time) +  if has_key(trans, 'date') && ! empty(trans['date']) +    let date = split(trans['date'], '=') +  else +    let date = [formatted] +  endif + +  if a:type =~? 'effective\|actual' +    echoerr 'actual/effective arguments were replaced by primary/auxiliary' +    return +  endif + +  if a:type ==? 'primary' +    let date[0] = formatted +  elseif a:type ==? 'auxiliary' +    if time < 0 +      " remove auxiliary date +      let date = [date[0]] +    else +      " set auxiliary date +      if len(date) >= 2 +        let date[1] = formatted +      else +        call add(date, formatted) +      endif +    endif +  elseif a:type ==? 'unshift' +    let date = [formatted, date[0]] +  endif + +  let trans['date'] = join(date[0:1], '=') + +  call setline(trans['head'], trans.format_head()) +endf + +" == get transactions == + +function! ledger#transaction_from_lnum(lnum) abort +  return s:transaction.from_lnum(a:lnum) +endf + +function! ledger#transactions(...) abort +  if a:0 == 2 +    let lnum = a:1 +    let end = a:2 +  elseif a:0 == 0 +    let lnum = 1 +    let end = line('$') +  else +    throw 'wrong number of arguments for get_transactions()' +    return [] +  endif + +  " safe view / position +  let view = winsaveview() +  let fe = &foldenable +  set nofoldenable + +  let transactions = [] +  call cursor(lnum, 0) +  while lnum && lnum < end +    let trans = s:transaction.from_lnum(lnum) +    if ! empty(trans) +      call add(transactions, trans) +      call cursor(trans['tail'], 0) +    endif +    let lnum = search('^[~=[:digit:]]', 'cW') +  endw + +  " restore view / position +  let &foldenable = fe +  call winrestview(view) + +  return transactions +endf + +" == transaction object implementation == + +let s:transaction = {} "{{{1 +function! s:transaction.new() abort dict +  return copy(s:transaction) +endf + +function! s:transaction.from_lnum(lnum) abort dict "{{{2 +  let [head, tail] = s:get_transaction_extents(a:lnum) +  if ! head +    return {} +  endif + +  let trans = copy(s:transaction) +  let trans['head'] = head +  let trans['tail'] = tail + +  " split off eventual comments at the end of line +  let line = split(getline(head), '\ze\s*\%(\t\|  \);', 1) +  if len(line) > 1 +    let trans['appendix'] = join(line[1:], '') +  endif + +  " parse rest of line +  " FIXME (minor): will not preserve spacing (see 'join(parts)') +  let parts = split(line[0], '\s\+') +  if parts[0] ==# '~' +    let trans['expr'] = join(parts[1:]) +    return trans +  elseif parts[0] ==# '=' +    let trans['auto'] = join(parts[1:]) +    return trans +  elseif parts[0] !~# '^\d' +    " this case is avoided in s:get_transaction_extents(), +    " but we'll check anyway. +    return {} +  endif + +  for part in parts +    if     ! has_key(trans, 'date')  && part =~# '^\d' +      let trans['date'] = part +    elseif ! has_key(trans, 'code')  && part =~# '^([^)]*)$' +      let trans['code'] = part[1:-2] +    elseif ! has_key(trans, 'state') && part =~# '^[[:punct:]]$' +      " the first character by itself is assumed to be the state of the transaction. +      let trans['state'] = part +    else +      " everything after date/code or state belongs to the description +      break +    endif +    call remove(parts, 0) +  endfor + +  let trans['description'] = join(parts) +  return trans +endf "}}} + +function! s:transaction.set_state(char) abort dict "{{{2 +  if has_key(self, 'state') && a:char =~# '^\s*$' +    call remove(self, 'state') +  else +    let self['state'] = a:char +  endif +endf "}}} + +function! s:transaction.parse_body(...) abort dict "{{{2 +  if a:0 == 2 +    let head = a:1 +    let tail = a:2 +  elseif a:0 == 0 +    let head = self['head'] +    let tail = self['tail'] +  else +    throw 'wrong number of arguments for parse_body()' +    return [] +  endif + +  if ! head || tail <= head +    return [] +  endif + +  let lnum = head +  let tags = {} +  let postings = [] +  while lnum <= tail +    let line = split(getline(lnum), '\s*\%(\t\|  \);', 1) + +    if line[0] =~# '^\s\+[^[:blank:];]' +      " posting +      let [state, rest] = matchlist(line[0], '^\s\+\([*!]\?\)\s*\(.*\)$')[1:2] +      if rest =~# '\t\|  ' +        let [account, amount] = matchlist(rest, '^\(.\{-}\)\%(\t\|  \)\s*\(.\{-}\)\s*$')[1:2] +      else +        let amount = '' +        let account = matchstr(rest, '^\s*\zs.\{-}\ze\s*$') +      endif +      call add(postings, {'account': account, 'amount': amount, 'state': state}) +    end + +    " where are tags to be stored? +    if empty(postings) +      " they belong to the transaction +      let tag_container = tags +    else +      " they belong to last posting +      if ! has_key(postings[-1], 'tags') +        let postings[-1]['tags'] = {} +      endif +      let tag_container = postings[-1]['tags'] +    endif + +    let comment = join(line[1:], '  ;') +    if comment =~# '^\s*:' +      " tags without values +      for t in s:findall(comment, ':\zs[^:[:blank:]]\([^:]*[^:[:blank:]]\)\?\ze:') +        let tag_container[t] = '' +      endfor +    elseif comment =~# '^\s*[^:[:blank:]][^:]\+:' +      " tag with value +      let key = matchstr(comment, '^\s*\zs[^:]\+\ze:') +      if ! empty(key) +        let val = matchstr(comment, ':\s*\zs.*\ze\s*$') +        let tag_container[key] = val +      endif +    endif +    let lnum += 1 +  endw +  return [tags, postings] +endf "}}} + +function! s:transaction.format_head() abort dict "{{{2 +  if has_key(self, 'expr') +    return '~ '.self['expr'] +  elseif has_key(self, 'auto') +    return '= '.self['auto'] +  endif + +  let parts = [] +  if has_key(self, 'date') | call add(parts, self['date']) | endif +  if has_key(self, 'state') | call add(parts, self['state']) | endif +  if has_key(self, 'code') | call add(parts, '('.self['code'].')') | endif +  if has_key(self, 'description') | call add(parts, self['description']) | endif + +  let line = join(parts) +  if has_key(self, 'appendix') | let line .= self['appendix'] | endif + +  return line +endf "}}} +"}}} + +" == helper functions == + +" get a list of declared accounts in the buffer +function! ledger#declared_accounts(...) abort +  if a:0 == 2 +    let lnum = a:1 +    let lend = a:2 +  elseif a:0 == 0 +    let lnum = 1 +    let lend = line('$') +  else +    throw 'wrong number of arguments for ledger#declared_accounts()' +    return [] +  endif + +  " save view / position +  let view = winsaveview() +  let fe = &foldenable +  set nofoldenable + +  let accounts = [] +  call cursor(lnum, 0) +  while 1 +    let lnum = search('^account\s', 'cW', lend) +    if !lnum || lnum > lend +      break +    endif + +    " remove comments at the end and "account" at the front +    let line = split(getline(lnum), '\s\+;')[0] +    let line = matchlist(line, 'account\s\+\(.\+\)')[1] + +    if len(line) > 1 +      call add(accounts, line) +    endif + +    call cursor(lnum+1,0) +  endw + +  " restore view / position +  let &foldenable = fe +  call winrestview(view) + +  return accounts +endf + +function! s:get_transaction_extents(lnum) abort +  if ! (indent(a:lnum) || getline(a:lnum) =~# '^[~=[:digit:]]') +    " only do something if lnum is in a transaction +    return [0, 0] +  endif + +  " safe view / position +  let view = winsaveview() +  let fe = &foldenable +  set nofoldenable + +  call cursor(a:lnum, 0) +  let head = search('^[~=[:digit:]]', 'bcnW') +  let tail = search('^[^;[:blank:]]\S\+', 'nW') +  let tail = tail > head ? tail - 1 : line('$') + +  " restore view / position +  let &foldenable = fe +  call winrestview(view) + +  return head ? [head, tail] : [0, 0] +endf + +function! ledger#find_in_tree(tree, levels) abort +  if empty(a:levels) +    return [] +  endif +  let results = [] +  let currentlvl = a:levels[0] +  let nextlvls = a:levels[1:] +  let branches = ledger#filter_items(keys(a:tree), currentlvl) +  for branch in branches +    let exact = empty(nextlvls) +    call add(results, [branch, exact]) +    if ! empty(nextlvls) +      for [result, exact] in ledger#find_in_tree(a:tree[branch], nextlvls) +        call add(results, [branch.':'.result, exact]) +      endfor +    endif +  endfor +  return results +endf + +function! ledger#filter_items(list, keyword) abort +  " return only those items that start with a specified keyword +  return filter(copy(a:list), 'v:val =~ ''^\V'.substitute(a:keyword, '\\', '\\\\', 'g').'''') +endf + +function! s:findall(text, rx) abort +  " returns all the matches in a string, +  " there will be overlapping matches according to :help match() +  let matches = [] + +  while 1 +    let m = matchstr(a:text, a:rx, 0, len(matches)+1) +    if empty(m) +      break +    endif + +    call add(matches, m) +  endw + +  return matches +endf + +" Move the cursor to the specified column, filling the line with spaces if necessary. +" Ensure that at least min_spaces are added, and go to the end of the line if +" the line is already too long +function! s:goto_col(pos, min_spaces) abort +  exec 'normal!' '$' +  let diff = max([a:min_spaces, a:pos - virtcol('.')]) +  if diff > 0 | exec 'normal!' diff . 'a ' | endif +endf + +" Return character position of decimal separator (multibyte safe) +function! s:decimalpos(expr) abort +  let pos = match(a:expr, '\V' . g:ledger_decimal_sep) +  if pos > 0 +    let pos = strchars(a:expr[:pos]) - 1 +  endif +  return pos +endf + +" Align the amount expression after an account name at the decimal point. +" +" This function moves the amount expression of a posting so that the decimal +" separator is aligned at the column specified by g:ledger_align_at. +" +" For example, after selecting: +" +"   2015/05/09 Some Payee +"     Expenses:Other    $120,23  ; Tags here +"     Expenses:Something  $-4,99 +"     Expenses:More                 ($12,34 + $16,32) +" +"  :'<,'>call ledger#align_commodity() produces: +" +"   2015/05/09 Some Payee +"      Expenses:Other                                    $120,23  ; Tags here +"      Expenses:Something                                 $-4,99 +"      Expenses:More                                     ($12,34 + $16,32) +" +function! ledger#align_commodity() abort +  " Extract the part of the line after the account name (excluding spaces): +  let l:line = getline('.') +  let rhs = matchstr(l:line, '\m^\s\+[^;[:space:]].\{-}\(\t\|  \)\s*\zs.*$') +  if rhs !=# '' +    " Remove everything after the account name (including spaces): +    call setline('.', substitute(l:line, '\m^\s\+[^[:space:]].\{-}\zs\(\t\|  \).*$', '', '')) +    let pos = -1 +    if g:ledger_decimal_sep !=# '' +      " Find the position of the first decimal separator: +      let pos = s:decimalpos(rhs) +    endif +    if pos < 0 +      " Find the position after the first digits +      let pos = matchend(rhs, '\m\d[^[:space:]]*') +    endif +    " Go to the column that allows us to align the decimal separator at g:ledger_align_at: +    if pos > 0 +      call s:goto_col(g:ledger_align_at - pos - 1, 2) +    else +      call s:goto_col(g:ledger_align_at - strdisplaywidth(rhs) - 2, 2) +    endif " Append the part of the line that was previously removed: +    exe 'normal! a' . rhs +  endif +endf + +" Align the amount under the cursor and append/prepend the default currency. +function! ledger#align_amount_at_cursor() abort +  " Select and cut text: +  normal! viWd +  " Find the position of the decimal separator +  let pos = s:decimalpos(@") " Returns zero when the separator is the empty string +  if pos <= 0 +    let pos = len(@") +  endif +  " Paste text at the correct column and append/prepend default commodity: +  if g:ledger_commodity_before +    call s:goto_col(g:ledger_align_at - pos - len(g:ledger_default_commodity) - len(g:ledger_commodity_sep) - 1, 2) +    exe 'normal! a' . g:ledger_default_commodity . g:ledger_commodity_sep +    normal! p +  else +    call s:goto_col(g:ledger_align_at - pos - 1, 2) +    exe 'normal! pa' . g:ledger_commodity_sep . g:ledger_default_commodity +  endif +endf + +" Report generation {{{1 + +" Helper functions and variables {{{2 +" Position of report windows +let s:winpos_map = { +      \ 'T': 'to new',  't': 'abo new', 'B': 'bo new',  'b': 'bel new', +      \ 'L': 'to vnew', 'l': 'abo vnew', 'R': 'bo vnew', 'r': 'bel vnew' +      \ } + +function! s:error_message(msg) abort +  redraw  " See h:echo-redraw +  echohl ErrorMsg +  echo "\r" +  echomsg a:msg +  echohl NONE +endf + +function! s:warning_message(msg) abort +  redraw  " See h:echo-redraw +  echohl WarningMsg +  echo "\r" +  echomsg a:msg +  echohl NONE +endf + +" Open the quickfix/location window when it is not empty, +" closes it if it is empty. +" +" Optional parameters: +" a:1  Quickfix window title. +" a:2  Message to show when the window is empty. +" +" Returns 0 if the quickfix window is empty, 1 otherwise. +function! s:quickfix_toggle(...) abort +  if g:ledger_use_location_list +    let l:list = 'l' +    let l:open = (len(getloclist(winnr())) > 0) +  else +    let l:list = 'c' +    let l:open = (len(getqflist()) > 0) +  endif + +  if l:open +    execute (g:ledger_qf_vertical ? 'vert' : 'botright') l:list.'open' g:ledger_qf_size +    " Set local mappings to quit the quickfix window  or lose focus. +    nnoremap <silent> <buffer> <tab> <c-w><c-w> +    execute 'nnoremap <silent> <buffer> q :' l:list.'close<CR>' +    " Note that the following settings do not persist (e.g., when you close and re-open the quickfix window). +    " See: https://superuser.com/questions/356912/how-do-i-change-the-quickix-title-status-bar-in-vim +    if g:ledger_qf_hide_file +      setl conceallevel=2 +      setl concealcursor=nc +      syntax match qfFile /^[^|]*/ transparent conceal +    endif +    if a:0 > 0 +      let w:quickfix_title = a:1 +    endif +    return 1 +  endif + +  execute l:list.'close' +  call s:warning_message((a:0 > 1) ? a:2 : 'No results') +  return 0 +endf + +" Populate a quickfix/location window with data. The argument must be a String +" or a List. +function! s:quickfix_populate(data) abort +  " Note that cexpr/lexpr always uses the global value of errorformat +  let l:efm = &errorformat  " Save global errorformat +  set errorformat=%EWhile\ parsing\ file\ \"%f\"\\,\ line\ %l:,%ZError:\ %m,%-C%.%# +  set errorformat+=%tarning:\ \"%f\"\\,\ line\ %l:\ %m +  " Format to parse command-line errors: +  set errorformat+=Error:\ %m +  " Format to parse reports: +  set errorformat+=%f:%l\ %m +  set errorformat+=%-G%.%# +  execute (g:ledger_use_location_list ? 'l' : 'c').'getexpr' 'a:data' +  let &errorformat = l:efm  " Restore global errorformat +  return +endf + +" Build a ledger command to process the given file. +function! s:ledger_cmd(file, args) abort +  let l:options = g:ledger_extra_options +  if len(g:ledger_date_format) > 0 && !g:ledger_is_hledger +    let l:options = join([l:options, '--date-format', g:ledger_date_format, +      \ '--input-date-format', g:ledger_date_format]) +  endif +  return join([g:ledger_bin, l:options, '-f', shellescape(expand(a:file)), a:args]) +endf +" }}} + +function! ledger#autocomplete_and_align() abort +  if pumvisible() +    return "\<c-n>" +  endif +  " Align an amount only if there is a digit immediately before the cursor and +  " such digit is preceded by at least one space (the latter condition is +  " necessary to avoid situations where a date starting at the first column is +  " confused with a commodity to be aligned). +  if match(getline('.'), '\s.*\d\%'.col('.').'c') > -1 +    normal! h +    call ledger#align_amount_at_cursor() +    return "\<c-o>A" +  endif +  return "\<c-x>\<c-o>" +endf + +" Use current line as input to ledger entry and replace with output. If there +" are errors, they are echoed instead. +function! ledger#entry() abort +  let l:output = systemlist(s:ledger_cmd(g:ledger_main, join(['entry', getline('.')]))) +  " Filter out warnings +  let l:output = filter(l:output, "v:val !~? '^Warning: '") +  " Errors may occur +  if v:shell_error +    echomsg join(l:output) +    return +  endif +  " Append output so we insert instead of overwrite, then delete line +  call append('.', l:output) +  normal! "_dd +endfunc + +" Run an arbitrary ledger command and show the output in a new buffer. If +" there are errors, no new buffer is opened: the errors are displayed in a +" quickfix window instead. +" +" Parameters: +" file  The file to be processed. +" args  A string of Ledger command-line arguments. +" +" Returns: +" Ledger's output as a String. +function! ledger#report(file, args) abort +  let l:output = systemlist(s:ledger_cmd(a:file, a:args)) +  if v:shell_error  " If there are errors, show them in a quickfix/location list. +    call s:quickfix_populate(l:output) +    call s:quickfix_toggle('Errors', 'Unable to parse errors') +  endif +  return l:output +endf + +" Open the output of a Ledger's command in a new buffer. +" +" Parameters: +" report  A String containing the output of a Ledger's command. +" +" Returns: +" 1 if a new buffer is created; 0 otherwise. +function! ledger#output(report) abort +  if empty(a:report) +    call s:warning_message('No results') +    return 0 +  endif +  " Open a new buffer to show Ledger's output. +  execute get(s:winpos_map, g:ledger_winpos, 'bo new') +  setlocal buftype=nofile bufhidden=wipe modifiable nobuflisted noswapfile nowrap +  call append(0, a:report) +  setlocal nomodifiable +  " Set local mappings to quit window or lose focus. +  nnoremap <silent> <buffer> <tab> <c-w><c-p> +  nnoremap <silent> <buffer> q <c-w><c-p>@=winnr('#')<cr><c-w>c +  " Add some coloring to the report +  syntax match LedgerNumber /-\@1<!\d\+\([,.]\d\+\)*/ +  syntax match LedgerNegativeNumber /-\d\+\([,.]\d\+\)*/ +  syntax match LedgerImproperPerc /\d\d\d\+%/ +  return 1 +endf + +" Show an arbitrary register report in a quickfix list. +" +" Parameters: +" file  The file to be processed +" args  A string of Ledger command-line arguments. +function! ledger#register(file, args) abort +  let l:cmd = s:ledger_cmd(a:file, join([ +        \ 'register', +        \ "--format='" . g:ledger_qf_register_format . "'", +        \ "--prepend-format='%(filename):%(beg_line) '", +        \ a:args +        \ ])) +  call s:quickfix_populate(systemlist(l:cmd)) +  call s:quickfix_toggle('Register report') +endf + +" Reconcile the given account. +" This function accepts a file path as a third optional argument. +" The default is to use the value of g:ledger_main. +" +" Parameters: +" file  The file to be processed +" account  An account name (String) +" target_amount The target amount (Float) +function! ledger#reconcile(file, account, target_amount) abort +  let l:cmd = s:ledger_cmd(a:file, join([ +        \ 'register', +        \ '--uncleared', +        \ "--format='" . g:ledger_qf_reconcile_format . "'", +        \ "--prepend-format='%(filename):%(beg_line) %(pending ? \"P\" : \"U\") '", +        \ shellescape(a:account) +        \ ])) +  let l:file = expand(a:file) " Needed for #show_balance() later +  call s:quickfix_populate(systemlist(l:cmd)) +  if s:quickfix_toggle('Reconcile ' . a:account, 'Nothing to reconcile') +    let g:ledger_target_amount = a:target_amount +    " Show updated account balance upon saving, as long as the quickfix window is open +    augroup reconcile +      autocmd! +      execute "autocmd BufWritePost *.ldg,*.ledger call ledger#show_balance('" . l:file . "','" . a:account . "')" +      autocmd BufWipeout <buffer> call <sid>finish_reconciling() +    augroup END +    " Add refresh shortcut +    execute "nnoremap <silent> <buffer> <c-l> :<c-u>call ledger#reconcile('" +          \ . l:file . "','" . a:account . "'," . string(a:target_amount) . ')<cr>' +    call ledger#show_balance(l:file, a:account) +  endif +endf + +function! s:finish_reconciling() abort +  unlet g:ledger_target_amount +  augroup reconcile +    autocmd! +  augroup END +  augroup! reconcile +endf + +" Show the pending/cleared balance of an account. +" This function has an optional parameter: +" +" a:1  An account name +" +" If no account if given, the account in the current line is used. +function! ledger#show_balance(file, ...) abort +  let l:account = a:0 > 0 && !empty(a:1) ? a:1 : matchstr(getline('.'), '\m\(  \|\t\)\zs\S.\{-}\ze\(  \|\t\|$\)') +  if empty(l:account) +    call s:error_message('No account found') +    return +  endif +  let l:cmd = s:ledger_cmd(a:file, join([ +        \ 'cleared', +        \ shellescape(l:account), +        \ '--empty', +        \ '--collapse', +        \ "--format='%(scrub(get_at(display_total, 0)))|%(scrub(get_at(display_total, 1)))|%(quantity(scrub(get_at(display_total, 1))))'", +        \ (empty(g:ledger_default_commodity) ? '' : '-X ' . shellescape(g:ledger_default_commodity)) +        \ ])) +  let l:output = systemlist(l:cmd) +  " Errors may occur, for example,  when the account has multiple commodities +  " and g:ledger_default_commodity is empty. +  if v:shell_error +    call s:quickfix_populate(l:output) +    call s:quickfix_toggle('Errors', 'Unable to parse errors') +    return +  endif +  let l:amounts = split(l:output[-1], '|') +  redraw  " Necessary in some cases to overwrite previous messages. See :h echo-redraw +  if len(l:amounts) < 3 +    call s:error_message('Could not determine balance. Did you use a valid account?') +    return +  endif +  echo g:ledger_pending_string +  echohl LedgerPending +  echon l:amounts[0] +  echohl NONE +  echon ' ' g:ledger_cleared_string +  echohl LedgerCleared +  echon l:amounts[1] +  echohl NONE +  if exists('g:ledger_target_amount') +    echon ' ' g:ledger_target_string +    echohl LedgerTarget +    echon printf('%.2f', (g:ledger_target_amount - str2float(l:amounts[2]))) +    echohl NONE +  endif +endf +" }}} + +endif diff --git a/autoload/nim.vim b/autoload/nim.vim new file mode 100644 index 00000000..59f9122d --- /dev/null +++ b/autoload/nim.vim @@ -0,0 +1,244 @@ +if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'nim') == -1 + +let g:nim_log = [] +let s:plugin_path = escape(expand('<sfile>:p:h'), '\') + +if !exists("g:nim_caas_enabled") +  let g:nim_caas_enabled = 0 +endif + +if !executable('nim') +  echoerr "the Nim compiler must be in your system's PATH" +endif + +if has("python3") +  exe 'py3file ' . fnameescape(s:plugin_path) . '/nim_vim.py' +elseif has("python") +  exe 'pyfile ' . fnameescape(s:plugin_path) . '/nim_vim.py' +endif + +fun! nim#init() +  let cmd = printf("nim --dump.format:json --verbosity:0 dump %s", s:CurrentNimFile()) +  let raw_dumpdata = system(cmd) +  if !v:shell_error && expand("%:e") == "nim" +    let false = 0 " Needed for eval of json +    let true = 1 " Needed for eval of json +    let dumpdata = eval(substitute(raw_dumpdata, "\n", "", "g")) +     +    let b:nim_project_root = dumpdata['project_path'] +    let b:nim_defined_symbols = dumpdata['defined_symbols'] +    let b:nim_caas_enabled = g:nim_caas_enabled || index(dumpdata['defined_symbols'], 'forcecaas') != -1 + +    for path in dumpdata['lib_paths'] +      if finddir(path) == path +        let &l:path = path . "," . &l:path +      endif +    endfor +  else +    let b:nim_caas_enabled = 0 +  endif +endf + +fun! s:UpdateNimLog() +  setlocal buftype=nofile +  setlocal bufhidden=hide +  setlocal noswapfile + +  for entry in g:nim_log +    call append(line('$'), split(entry, "\n")) +  endfor + +  let g:nim_log = [] + +  match Search /^nim\ .*/ +endf + +augroup NimVim +  au! +  au BufEnter log://nim call s:UpdateNimLog() +  if has("python3") || has("python") +    " au QuitPre * :py nimTerminateAll() +    au VimLeavePre * :py nimTerminateAll() +  endif +augroup END + +command! NimLog :e log://nim + +command! NimTerminateService +  \ :exe printf("py nimTerminateService('%s')", b:nim_project_root) + +command! NimRestartService +  \ :exe printf("py nimRestartService('%s')", b:nim_project_root) + +fun! s:CurrentNimFile() +  let save_cur = getpos('.') +  call cursor(0, 0, 0) +   +  let PATTERN = "\\v^\\#\\s*included from \\zs.*\\ze" +  let l = search(PATTERN, "n") + +  if l != 0 +    let f = matchstr(getline(l), PATTERN) +    let l:to_check = expand('%:h') . "/" . f +  else +    let l:to_check = expand("%") +  endif + +  call setpos('.', save_cur) +  return l:to_check +endf + +let g:nim_symbol_types = { +  \ 'skParam': 'v', +  \ 'skVar': 'v', +  \ 'skLet': 'v', +  \ 'skTemp': 'v', +  \ 'skForVar': 'v', +  \ 'skConst': 'v', +  \ 'skResult': 'v', +  \ 'skGenericParam': 't', +  \ 'skType': 't', +  \ 'skField': 'm', +  \ 'skProc': 'f', +  \ 'skMethod': 'f', +  \ 'skIterator': 'f', +  \ 'skConverter': 'f', +  \ 'skMacro': 'f', +  \ 'skTemplate': 'f', +  \ 'skEnumField': 'v', +  \ } + +fun! NimExec(op) +  let isDirty = getbufvar(bufnr('%'), "&modified") +  if isDirty +    let tmp = tempname() . bufname("%") . "_dirty.nim" +    silent! exe ":w " . tmp + +    let cmd = printf("idetools %s --trackDirty:\"%s,%s,%d,%d\" \"%s\"", +      \ a:op, tmp, expand('%:p'), line('.'), col('.')-1, s:CurrentNimFile()) +  else +    let cmd = printf("idetools %s --track:\"%s,%d,%d\" \"%s\"", +      \ a:op, expand('%:p'), line('.'), col('.')-1, s:CurrentNimFile()) +  endif + +  if b:nim_caas_enabled +    exe printf("py nimExecCmd('%s', '%s', False)", b:nim_project_root, cmd) +    let output = l:py_res +  else +    let output = system("nim " . cmd) +  endif + +  call add(g:nim_log, "nim " . cmd . "\n" . output) +  return output +endf + +fun! NimExecAsync(op, Handler) +  let result = NimExec(a:op) +  call a:Handler(result) +endf + +fun! NimComplete(findstart, base) +  if b:nim_caas_enabled == 0 +    return -1 +  endif + +  if a:findstart +    if synIDattr(synIDtrans(synID(line("."),col("."),1)), "name") == 'Comment' +      return -1 +    endif +    let line = getline('.') +    let start = col('.') - 1 +    while start > 0 && line[start - 1] =~? '\w' +      let start -= 1 +    endwhile +    return start +  else +    let result = [] +    let sugOut = NimExec("--suggest") +    for line in split(sugOut, '\n') +      let lineData = split(line, '\t') +      if len(lineData) > 0 && lineData[0] == "sug" +        let word = split(lineData[2], '\.')[-1] +        if a:base ==? '' || word =~# '^' . a:base +          let kind = get(g:nim_symbol_types, lineData[1], '') +          let c = { 'word': word, 'kind': kind, 'menu': lineData[3], 'dup': 1 } +          call add(result, c) +        endif +      endif +    endfor +    return result +  endif +endf + +if !exists("g:neocomplcache_omni_patterns") +  let g:neocomplcache_omni_patterns = {} +endif +let g:neocomplcache_omni_patterns['nim'] = '[^. *\t]\.\w*' + +if !exists('g:neocomplete#sources#omni#input_patterns') +  let g:neocomplete#sources#omni#input_patterns = {} +endif +let g:neocomplete#sources#omni#input_patterns['nim'] = '[^. *\t]\.\w*' + +let g:nim_completion_callbacks = {} + +fun! NimAsyncCmdComplete(cmd, output) +  call add(g:nim_log, a:output) +  echom g:nim_completion_callbacks +  if has_key(g:nim_completion_callbacks, a:cmd) +    let Callback = get(g:nim_completion_callbacks, a:cmd) +    call Callback(a:output) +    " remove(g:nim_completion_callbacks, a:cmd) +  else +    echom "ERROR, Unknown Command: " . a:cmd +  endif +  return 1 +endf + +fun! GotoDefinition_nim_ready(def_output) +  if v:shell_error +    echo "nim was unable to locate the definition. exit code: " . v:shell_error +    " echoerr a:def_output +    return 0 +  endif +   +  let rawDef = matchstr(a:def_output, 'def\t\([^\n]*\)') +  if rawDef == "" +    echo "the current cursor position does not match any definitions" +    return 0 +  endif +   +  let defBits = split(rawDef, '\t') +  let file = defBits[4] +  let line = defBits[5] +  exe printf("e +%d %s", line, file) +  return 1 +endf + +fun! GotoDefinition_nim() +  call NimExecAsync("--def", function("GotoDefinition_nim_ready")) +endf + +fun! FindReferences_nim() +  setloclist() +endf + +" Syntastic syntax checking +fun! SyntaxCheckers_nim_nim_GetLocList() +  let makeprg = 'nim check --hints:off --listfullpaths ' . s:CurrentNimFile() +  let errorformat = &errorformat +   +  return SyntasticMake({ 'makeprg': makeprg, 'errorformat': errorformat }) +endf + +function! SyntaxCheckers_nim_nim_IsAvailable() +  return executable("nim") +endfunction + +if exists("g:SyntasticRegistry") +  call g:SyntasticRegistry.CreateAndRegisterChecker({ +      \ 'filetype': 'nim', +      \ 'name': 'nim'}) +endif + +endif | 
