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/fsharp.vim | |
parent | 25db54573ad9d436ffff97124887c68a74b07e66 (diff) | |
download | vim-polyglot-63a175357a139ebbecf724b5d8229d383a08afef.tar.gz vim-polyglot-63a175357a139ebbecf724b5d8229d383a08afef.zip |
Remove some custom dirs config
Diffstat (limited to 'autoload/fsharp.vim')
-rw-r--r-- | autoload/fsharp.vim | 517 |
1 files changed, 517 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 |