diff options
Diffstat (limited to 'autoload/unison.vim')
-rw-r--r-- | autoload/unison.vim | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/autoload/unison.vim b/autoload/unison.vim new file mode 100644 index 00000000..cdc2efe5 --- /dev/null +++ b/autoload/unison.vim @@ -0,0 +1,108 @@ +if polyglot#init#is_disabled(expand('<sfile>:p'), 'unison', 'autoload/unison.vim') + finish +endif + +" Unison functionality for Vim, including type/term omnicompletion. +" +" Maintainer: Unison Computing +" Original Author: Cody Allen (ceedubs) + +if exists('g:autoloaded_unison') + finish +endif +let g:autoloaded_unison = 1 + +let s:required_config_value = "!REQUIRED!" + +" adapted from https://github.com/rust-lang/rust.vim/blob/4aa69b84c8a58fcec6b6dad6fe244b916b1cf830/autoload/rust.vim#L9-L18 +function! s:config(name, default) abort + let name = 'unison_' . a:name + " Local buffer variable with same name takes predeence over global + if has_key(b:, name) + return get(b:, name) + elseif has_key(g:, name) + return get(g:, name) + elseif a:default == s:required_config_value + throw 'Missing required configuration value: ' . name + else + return a:default + endif +endfunction + +function! s:curl_path() abort + return s:config('curl_path', "curl") +endfunction + +function! s:jq_path() abort + return s:config('jq_path', "jq") +endfunction + +function! unison#SetBufferDefaults() abort + if s:config('set_buffer_defaults', 1) + " Since Unison completion is fuzzy and not prefix-based, 'longest' doesn't + " work well, and 'noinsert' behaves a little better. + setlocal completeopt=menuone,noinsert,preview + + setlocal omnifunc=unison#Complete + endif +endfunction + +" Unison completion satisfying the standard vim completion signature, such +" that it can be assigned to omnifunc. +" vim will first call this to find the base input that should be completed, +" and then will call it again with the base input. +function! unison#Complete(findstart, base) abort + if a:findstart + " locate the start of the word + let line = getline('.') + let start = col('.') - 1 + while start > 0 && line[start - 1] !~ '\s' && line[start - 1] != '(' && line[start - 1] != ')' + let start -= 1 + endwhile + return start + else + return unison#CompleteForBase(a:base) + endif +endfunction + +" Return an array of completion items for the provided base input. For example +" base could be 'List.foldL', in which case the top result would probably be +" 'List.foldLeft'. +function! unison#CompleteForBase(base) abort + let resultLimit = s:config('complete_result_limit', 20) + let apiHost = s:config('api_host', 'localhost') + let apiPort = s:config('api_port', s:required_config_value) + let apiToken = s:config('api_token', s:required_config_value) + let apiUri = 'http://' . apiHost . ':' . apiPort . '/' . apiToken . '/api/find' + + let curlCommand = s:curl_path() . " -Gfs + \ --data-urlencode 'limit=" . resultLimit . "' + \ --data-urlencode 'query=" . a:base . "' " + \ . apiUri + + let jqFilter = ' + \ def prettyTermType: .termType|[(.[] | .segment)]|add; + \ def prettyTypeDef: if .tag == "BuiltinObject" then "builtin type " else "" end + (.contents|[(.[] | .segment)]|add); + \ def termToMatch: { + \ word: .bestFoundTermName, + \ info: (.namedTerm.termName + " : " + (.namedTerm|prettyTermType)), + \ menu: .namedTerm|prettyTermType + \ }; + \ def typeToMatch: { + \ word: .bestFoundTypeName, + \ info: (.namedType.typeName + " : " + (.typeDef|prettyTypeDef)), + \ menu: .typeDef|prettyTypeDef + \ }; + \ .[][1]|( + \ (select(.tag == "FoundTermResult")|.contents|termToMatch), + \ (select(.tag == "FoundTypeResult")|.contents|typeToMatch) + \ )' + + let command = curlCommand . " | " . s:jq_path() . " -c '" . jqFilter . "'" + let lines = system(command) + let resultObjects = split(lines, "\n") + call map(resultObjects, {_, val -> json_decode(val)}) + return resultObjects +endfunction + +" vim: set et sw=2 sts=2 ts=2: |