From 95aea6b533e71e478d61d18fac71cca116c56a4d Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Sun, 22 May 2022 22:47:23 +0100 Subject: Add all the plugins I currently use --- start/Main/autoload/coreplug/fzf.vim | 19 + start/Main/plugin/init.vim | 3 + start/cmp/COMMIT | 1 + start/cmp/COMMIT-LSP | 1 + start/cmp/LICENSE | 21 + start/cmp/after/plugin/cmp_nvim_lsp.lua | 1 + start/cmp/autoload/cmp.vim | 64 + start/cmp/doc/cmp-nvim-lsp.txt | 29 + start/cmp/doc/cmp.txt | 806 +++ start/cmp/lua/cmp/config.lua | 229 + start/cmp/lua/cmp/config/compare.lua | 234 + start/cmp/lua/cmp/config/context.lua | 65 + start/cmp/lua/cmp/config/default.lua | 97 + start/cmp/lua/cmp/config/mapping.lua | 172 + start/cmp/lua/cmp/config/sources.lua | 10 + start/cmp/lua/cmp/config/window.lua | 12 + start/cmp/lua/cmp/context.lua | 105 + start/cmp/lua/cmp/context_spec.lua | 31 + start/cmp/lua/cmp/core.lua | 486 ++ start/cmp/lua/cmp/core_spec.lua | 158 + start/cmp/lua/cmp/entry.lua | 468 ++ start/cmp/lua/cmp/entry_spec.lua | 342 + start/cmp/lua/cmp/init.lua | 336 + start/cmp/lua/cmp/matcher.lua | 324 + start/cmp/lua/cmp/matcher_spec.lua | 64 + start/cmp/lua/cmp/source.lua | 365 ++ start/cmp/lua/cmp/source_spec.lua | 109 + start/cmp/lua/cmp/types/cmp.lua | 166 + start/cmp/lua/cmp/types/init.lua | 7 + start/cmp/lua/cmp/types/lsp.lua | 197 + start/cmp/lua/cmp/types/lsp_spec.lua | 47 + start/cmp/lua/cmp/types/vim.lua | 20 + start/cmp/lua/cmp/utils/api.lua | 69 + start/cmp/lua/cmp/utils/api_spec.lua | 46 + start/cmp/lua/cmp/utils/async.lua | 127 + start/cmp/lua/cmp/utils/async_spec.lua | 69 + start/cmp/lua/cmp/utils/autocmd.lua | 53 + start/cmp/lua/cmp/utils/binary.lua | 33 + start/cmp/lua/cmp/utils/binary_spec.lua | 28 + start/cmp/lua/cmp/utils/buffer.lua | 28 + start/cmp/lua/cmp/utils/cache.lua | 58 + start/cmp/lua/cmp/utils/char.lua | 117 + start/cmp/lua/cmp/utils/debug.lua | 20 + start/cmp/lua/cmp/utils/event.lua | 51 + start/cmp/lua/cmp/utils/feedkeys.lua | 53 + start/cmp/lua/cmp/utils/feedkeys_spec.lua | 56 + start/cmp/lua/cmp/utils/highlight.lua | 31 + start/cmp/lua/cmp/utils/keymap.lua | 251 + start/cmp/lua/cmp/utils/keymap_spec.lua | 187 + start/cmp/lua/cmp/utils/misc.lua | 253 + start/cmp/lua/cmp/utils/misc_spec.lua | 63 + start/cmp/lua/cmp/utils/pattern.lua | 28 + start/cmp/lua/cmp/utils/spec.lua | 92 + start/cmp/lua/cmp/utils/str.lua | 178 + start/cmp/lua/cmp/utils/str_spec.lua | 29 + start/cmp/lua/cmp/utils/window.lua | 313 + start/cmp/lua/cmp/view.lua | 243 + start/cmp/lua/cmp/view/custom_entries_view.lua | 409 ++ start/cmp/lua/cmp/view/docs_view.lua | 136 + start/cmp/lua/cmp/view/ghost_text_view.lua | 97 + start/cmp/lua/cmp/view/native_entries_view.lua | 181 + start/cmp/lua/cmp/view/wildmenu_entries_view.lua | 261 + start/cmp/lua/cmp/vim_source.lua | 53 + start/cmp/lua/cmp_nvim_lsp/init.lua | 84 + start/cmp/lua/cmp_nvim_lsp/source.lua | 117 + start/cmp/plugin/cmp.lua | 60 + start/fzf/README | 25 + start/fzf/autoload/fzf/vim.vim | 1324 ++++ start/fzf/autoload/fzf/vim/complete.vim | 163 + start/fzf/bin/preview.rb | 59 + start/fzf/bin/preview.sh | 54 + start/fzf/bin/tags.pl | 15 + start/fzf/plugin/fzf.vim | 994 +++ start/goyo/README.md | 130 + start/goyo/autoload/goyo.vim | 447 ++ start/goyo/doc/goyo.txt | 170 + start/goyo/plugin/goyo.vim | 24 + start/lightline/LICENSE | 21 + start/lightline/README.md | 389 ++ start/lightline/autoload/lightline.vim | 502 ++ start/lightline/autoload/lightline/colorscheme.vim | 257 + .../autoload/lightline/colorscheme/16color.vim | 49 + .../autoload/lightline/colorscheme/OldHope.vim | 44 + .../autoload/lightline/colorscheme/PaperColor.vim | 12 + .../lightline/colorscheme/PaperColor_dark.vim | 60 + .../lightline/colorscheme/PaperColor_light.vim | 55 + .../autoload/lightline/colorscheme/Tomorrow.vim | 41 + .../lightline/colorscheme/Tomorrow_Night.vim | 41 + .../lightline/colorscheme/Tomorrow_Night_Blue.vim | 43 + .../colorscheme/Tomorrow_Night_Bright.vim | 42 + .../colorscheme/Tomorrow_Night_Eighties.vim | 42 + .../autoload/lightline/colorscheme/darcula.vim | 37 + .../autoload/lightline/colorscheme/default.vim | 8 + .../autoload/lightline/colorscheme/deus.vim | 40 + .../autoload/lightline/colorscheme/jellybeans.vim | 40 + .../autoload/lightline/colorscheme/landscape.vim | 25 + .../autoload/lightline/colorscheme/materia.vim | 63 + .../autoload/lightline/colorscheme/material.vim | 63 + .../autoload/lightline/colorscheme/molokai.vim | 36 + .../autoload/lightline/colorscheme/nord.vim | 46 + .../autoload/lightline/colorscheme/one.vim | 64 + .../autoload/lightline/colorscheme/powerline.vim | 28 + .../autoload/lightline/colorscheme/seoul256.vim | 42 + .../autoload/lightline/colorscheme/solarized.vim | 80 + .../autoload/lightline/colorscheme/srcery_drk.vim | 44 + .../autoload/lightline/colorscheme/wombat.vim | 40 + start/lightline/autoload/lightline/colortable.vim | 42 + start/lightline/autoload/lightline/tab.vim | 33 + start/lightline/doc/lightline.txt | 1325 ++++ start/lightline/plugin/lightline.vim | 26 + start/lspconfig-0.1.3/LICENSE.md | 183 + start/lspconfig-0.1.3/doc/lspconfig.txt | 636 ++ start/lspconfig-0.1.3/doc/server_configurations.md | 6554 ++++++++++++++++++++ .../lspconfig-0.1.3/doc/server_configurations.txt | 6554 ++++++++++++++++++++ start/lspconfig-0.1.3/lua/lspconfig.lua | 92 + start/lspconfig-0.1.3/lua/lspconfig/configs.lua | 295 + .../lua/lspconfig/server_configurations/als.lua | 37 + .../lspconfig/server_configurations/angularls.lua | 75 + .../lspconfig/server_configurations/ansiblels.lua | 47 + .../arduino_language_server.lua | 50 + .../lspconfig/server_configurations/asm_lsp.lua | 19 + .../lua/lspconfig/server_configurations/awk_ls.lua | 22 + .../lua/lspconfig/server_configurations/bashls.lua | 39 + .../lspconfig/server_configurations/beancount.lua | 26 + .../lua/lspconfig/server_configurations/bicep.lua | 47 + .../lua/lspconfig/server_configurations/bsl_ls.lua | 19 + .../lua/lspconfig/server_configurations/ccls.lua | 43 + .../lua/lspconfig/server_configurations/clangd.lua | 87 + .../server_configurations/clarity_lsp.lua | 19 + .../server_configurations/clojure_lsp.lua | 19 + .../lua/lspconfig/server_configurations/cmake.lua | 26 + .../lspconfig/server_configurations/codeqlls.lua | 46 + .../server_configurations/crystalline.lua | 20 + .../lspconfig/server_configurations/csharp_ls.lua | 23 + .../lua/lspconfig/server_configurations/cssls.lua | 49 + .../server_configurations/cssmodules_ls.lua | 31 + .../cucumber_language_server.lua | 33 + .../lua/lspconfig/server_configurations/dartls.lua | 60 + .../lua/lspconfig/server_configurations/denols.lua | 114 + .../server_configurations/dhall_lsp_server.lua | 26 + .../server_configurations/diagnosticls.lua | 29 + .../lspconfig/server_configurations/dockerls.lua | 30 + .../lua/lspconfig/server_configurations/dotls.lua | 27 + .../lua/lspconfig/server_configurations/efm.lua | 43 + .../lspconfig/server_configurations/elixirls.lua | 39 + .../lua/lspconfig/server_configurations/elmls.lua | 44 + .../lua/lspconfig/server_configurations/ember.lua | 30 + .../lspconfig/server_configurations/emmet_ls.lua | 31 + .../lspconfig/server_configurations/erlangls.lua | 34 + .../lspconfig/server_configurations/esbonio.lua | 55 + .../lua/lspconfig/server_configurations/eslint.lua | 172 + .../lua/lspconfig/server_configurations/flow.lua | 27 + .../lspconfig/server_configurations/flux_lsp.lua | 22 + .../lspconfig/server_configurations/foam_ls.lua | 31 + .../lua/lspconfig/server_configurations/fortls.lua | 24 + .../server_configurations/fsautocomplete.lua | 32 + .../lua/lspconfig/server_configurations/fstar.lua | 19 + .../lspconfig/server_configurations/gdscript.lua | 19 + .../lua/lspconfig/server_configurations/ghcide.lua | 21 + .../server_configurations/golangci_lint_ls.lua | 34 + .../lua/lspconfig/server_configurations/gopls.lua | 22 + .../lspconfig/server_configurations/gradle_ls.lua | 37 + .../lspconfig/server_configurations/grammarly.lua | 38 + .../lspconfig/server_configurations/graphql.lua | 33 + .../lspconfig/server_configurations/groovyls.lua | 36 + .../server_configurations/haxe_language_server.lua | 47 + .../server_configurations/hdl_checker.lua | 20 + .../lua/lspconfig/server_configurations/hhvm.lua | 21 + .../lua/lspconfig/server_configurations/hie.lua | 34 + .../lua/lspconfig/server_configurations/hls.lua | 43 + .../lspconfig/server_configurations/hoon_ls.lua | 29 + .../lua/lspconfig/server_configurations/html.lua | 48 + .../lspconfig/server_configurations/idris2_lsp.lua | 41 + .../server_configurations/intelephense.lua | 50 + .../server_configurations/java_language_server.lua | 18 + .../lua/lspconfig/server_configurations/jdtls.lua | 193 + .../server_configurations/jedi_language_server.lua | 28 + .../lua/lspconfig/server_configurations/jsonls.lua | 48 + .../lspconfig/server_configurations/jsonnet_ls.lua | 40 + .../lspconfig/server_configurations/julials.lua | 75 + .../kotlin_language_server.lua | 71 + .../lspconfig/server_configurations/lean3ls.lua | 54 + .../lua/lspconfig/server_configurations/leanls.lua | 77 + .../lspconfig/server_configurations/lelwel_ls.lua | 21 + .../lspconfig/server_configurations/lemminx.lua | 23 + .../lua/lspconfig/server_configurations/ltex.lua | 47 + .../lua/lspconfig/server_configurations/metals.lua | 45 + .../lua/lspconfig/server_configurations/mint.lua | 20 + .../lua/lspconfig/server_configurations/mm0_ls.lua | 20 + .../lspconfig/server_configurations/nickel_ls.lua | 37 + .../lua/lspconfig/server_configurations/nimls.lua | 21 + .../lspconfig/server_configurations/ocamlls.lua | 28 + .../lspconfig/server_configurations/ocamllsp.lua | 38 + .../lua/lspconfig/server_configurations/ols.lua | 20 + .../lspconfig/server_configurations/omnisharp.lua | 52 + .../lspconfig/server_configurations/opencl_ls.lua | 21 + .../server_configurations/openscad_ls.lua | 32 + .../lua/lspconfig/server_configurations/pasls.lua | 28 + .../lua/lspconfig/server_configurations/perlls.lua | 39 + .../server_configurations/perlnavigator.lua | 39 + .../lspconfig/server_configurations/perlpls.lua | 29 + .../lspconfig/server_configurations/phpactor.lua | 26 + .../lua/lspconfig/server_configurations/please.lua | 19 + .../server_configurations/powershell_es.lua | 72 + .../lspconfig/server_configurations/prismals.lua | 34 + .../server_configurations/prosemd_lsp.lua | 22 + .../lua/lspconfig/server_configurations/psalm.lua | 29 + .../lua/lspconfig/server_configurations/puppet.lua | 38 + .../server_configurations/purescriptls.lua | 28 + .../lua/lspconfig/server_configurations/pylsp.lua | 31 + .../lua/lspconfig/server_configurations/pyre.lua | 22 + .../lspconfig/server_configurations/pyright.lua | 56 + .../server_configurations/quick_lint_js.lua | 19 + .../server_configurations/r_language_server.lua | 28 + .../server_configurations/racket_langserver.lua | 21 + .../lspconfig/server_configurations/reason_ls.lua | 23 + .../lspconfig/server_configurations/remark_ls.lua | 50 + .../lspconfig/server_configurations/rescriptls.lua | 42 + .../lua/lspconfig/server_configurations/rls.lua | 42 + .../lua/lspconfig/server_configurations/rnix.lua | 28 + .../server_configurations/robotframework_ls.lua | 21 + .../lua/lspconfig/server_configurations/rome.lua | 42 + .../server_configurations/rust_analyzer.lua | 79 + .../lspconfig/server_configurations/salt_ls.lua | 24 + .../lua/lspconfig/server_configurations/scry.lua | 22 + .../lspconfig/server_configurations/serve_d.lua | 20 + .../lspconfig/server_configurations/sixtyfps.lua | 28 + .../lspconfig/server_configurations/slint_lsp.lua | 26 + .../lua/lspconfig/server_configurations/solang.lua | 27 + .../lspconfig/server_configurations/solargraph.lua | 38 + .../lua/lspconfig/server_configurations/solc.lua | 19 + .../server_configurations/solidity_ls.lua | 24 + .../lua/lspconfig/server_configurations/sorbet.lua | 26 + .../lspconfig/server_configurations/sourcekit.lua | 19 + .../lspconfig/server_configurations/sourcery.lua | 55 + .../lspconfig/server_configurations/spectral.lua | 29 + .../lua/lspconfig/server_configurations/sqlls.lua | 18 + .../lua/lspconfig/server_configurations/sqls.lua | 25 + .../server_configurations/stylelint_lsp.lua | 54 + .../server_configurations/sumneko_lua.lua | 63 + .../lua/lspconfig/server_configurations/svelte.lua | 29 + .../lua/lspconfig/server_configurations/svls.lua | 24 + .../server_configurations/tailwindcss.lua | 126 + .../lua/lspconfig/server_configurations/taplo.lua | 27 + .../lspconfig/server_configurations/teal_ls.lua | 29 + .../server_configurations/terraform_lsp.lua | 43 + .../server_configurations/terraformls.lua | 42 + .../lua/lspconfig/server_configurations/texlab.lua | 126 + .../lua/lspconfig/server_configurations/tflint.lua | 20 + .../server_configurations/theme_check.lua | 31 + .../lspconfig/server_configurations/tsserver.lua | 60 + .../lspconfig/server_configurations/typeprof.lua | 19 + .../lspconfig/server_configurations/vala_ls.lua | 40 + .../lua/lspconfig/server_configurations/vdmj.lua | 128 + .../lspconfig/server_configurations/verible.lua | 21 + .../lua/lspconfig/server_configurations/vimls.lua | 41 + .../lua/lspconfig/server_configurations/vls.lua | 32 + .../lua/lspconfig/server_configurations/volar.lua | 138 + .../lua/lspconfig/server_configurations/vuels.lua | 68 + .../lua/lspconfig/server_configurations/yamlls.lua | 87 + .../lspconfig/server_configurations/zeta_note.lua | 28 + .../lua/lspconfig/server_configurations/zk.lua | 48 + .../lua/lspconfig/server_configurations/zls.lua | 20 + start/lspconfig-0.1.3/lua/lspconfig/ui/lspinfo.lua | 225 + start/lspconfig-0.1.3/lua/lspconfig/ui/windows.lua | 117 + start/lspconfig-0.1.3/lua/lspconfig/util.lua | 426 ++ start/lspconfig-0.1.3/plugin/lspconfig.vim | 16 + start/repeat/README.markdown | 47 + start/repeat/autoload/repeat.vim | 145 + start/signify/LICENSE | 20 + start/signify/README.md | 54 + start/signify/autoload/sy.vim | 199 + start/signify/autoload/sy/debug.vim | 48 + start/signify/autoload/sy/fold.vim | 125 + start/signify/autoload/sy/highlight.vim | 94 + start/signify/autoload/sy/jump.vim | 29 + start/signify/autoload/sy/repo.vim | 512 ++ start/signify/autoload/sy/sign.vim | 275 + start/signify/autoload/sy/util.vim | 109 + start/signify/doc/signify.txt | 689 ++ start/signify/plugin/signify.vim | 120 + 281 files changed, 39431 insertions(+) create mode 100644 start/Main/autoload/coreplug/fzf.vim create mode 100644 start/Main/plugin/init.vim create mode 100644 start/cmp/COMMIT create mode 100644 start/cmp/COMMIT-LSP create mode 100644 start/cmp/LICENSE create mode 100644 start/cmp/after/plugin/cmp_nvim_lsp.lua create mode 100644 start/cmp/autoload/cmp.vim create mode 100644 start/cmp/doc/cmp-nvim-lsp.txt create mode 100644 start/cmp/doc/cmp.txt create mode 100644 start/cmp/lua/cmp/config.lua create mode 100644 start/cmp/lua/cmp/config/compare.lua create mode 100644 start/cmp/lua/cmp/config/context.lua create mode 100644 start/cmp/lua/cmp/config/default.lua create mode 100644 start/cmp/lua/cmp/config/mapping.lua create mode 100644 start/cmp/lua/cmp/config/sources.lua create mode 100644 start/cmp/lua/cmp/config/window.lua create mode 100644 start/cmp/lua/cmp/context.lua create mode 100644 start/cmp/lua/cmp/context_spec.lua create mode 100644 start/cmp/lua/cmp/core.lua create mode 100644 start/cmp/lua/cmp/core_spec.lua create mode 100644 start/cmp/lua/cmp/entry.lua create mode 100644 start/cmp/lua/cmp/entry_spec.lua create mode 100644 start/cmp/lua/cmp/init.lua create mode 100644 start/cmp/lua/cmp/matcher.lua create mode 100644 start/cmp/lua/cmp/matcher_spec.lua create mode 100644 start/cmp/lua/cmp/source.lua create mode 100644 start/cmp/lua/cmp/source_spec.lua create mode 100644 start/cmp/lua/cmp/types/cmp.lua create mode 100644 start/cmp/lua/cmp/types/init.lua create mode 100644 start/cmp/lua/cmp/types/lsp.lua create mode 100644 start/cmp/lua/cmp/types/lsp_spec.lua create mode 100644 start/cmp/lua/cmp/types/vim.lua create mode 100644 start/cmp/lua/cmp/utils/api.lua create mode 100644 start/cmp/lua/cmp/utils/api_spec.lua create mode 100644 start/cmp/lua/cmp/utils/async.lua create mode 100644 start/cmp/lua/cmp/utils/async_spec.lua create mode 100644 start/cmp/lua/cmp/utils/autocmd.lua create mode 100644 start/cmp/lua/cmp/utils/binary.lua create mode 100644 start/cmp/lua/cmp/utils/binary_spec.lua create mode 100644 start/cmp/lua/cmp/utils/buffer.lua create mode 100644 start/cmp/lua/cmp/utils/cache.lua create mode 100644 start/cmp/lua/cmp/utils/char.lua create mode 100644 start/cmp/lua/cmp/utils/debug.lua create mode 100644 start/cmp/lua/cmp/utils/event.lua create mode 100644 start/cmp/lua/cmp/utils/feedkeys.lua create mode 100644 start/cmp/lua/cmp/utils/feedkeys_spec.lua create mode 100644 start/cmp/lua/cmp/utils/highlight.lua create mode 100644 start/cmp/lua/cmp/utils/keymap.lua create mode 100644 start/cmp/lua/cmp/utils/keymap_spec.lua create mode 100644 start/cmp/lua/cmp/utils/misc.lua create mode 100644 start/cmp/lua/cmp/utils/misc_spec.lua create mode 100644 start/cmp/lua/cmp/utils/pattern.lua create mode 100644 start/cmp/lua/cmp/utils/spec.lua create mode 100644 start/cmp/lua/cmp/utils/str.lua create mode 100644 start/cmp/lua/cmp/utils/str_spec.lua create mode 100644 start/cmp/lua/cmp/utils/window.lua create mode 100644 start/cmp/lua/cmp/view.lua create mode 100644 start/cmp/lua/cmp/view/custom_entries_view.lua create mode 100644 start/cmp/lua/cmp/view/docs_view.lua create mode 100644 start/cmp/lua/cmp/view/ghost_text_view.lua create mode 100644 start/cmp/lua/cmp/view/native_entries_view.lua create mode 100644 start/cmp/lua/cmp/view/wildmenu_entries_view.lua create mode 100644 start/cmp/lua/cmp/vim_source.lua create mode 100644 start/cmp/lua/cmp_nvim_lsp/init.lua create mode 100644 start/cmp/lua/cmp_nvim_lsp/source.lua create mode 100644 start/cmp/plugin/cmp.lua create mode 100644 start/fzf/README create mode 100644 start/fzf/autoload/fzf/vim.vim create mode 100644 start/fzf/autoload/fzf/vim/complete.vim create mode 100644 start/fzf/bin/preview.rb create mode 100644 start/fzf/bin/preview.sh create mode 100644 start/fzf/bin/tags.pl create mode 100644 start/fzf/plugin/fzf.vim create mode 100644 start/goyo/README.md create mode 100644 start/goyo/autoload/goyo.vim create mode 100644 start/goyo/doc/goyo.txt create mode 100644 start/goyo/plugin/goyo.vim create mode 100644 start/lightline/LICENSE create mode 100644 start/lightline/README.md create mode 100644 start/lightline/autoload/lightline.vim create mode 100644 start/lightline/autoload/lightline/colorscheme.vim create mode 100644 start/lightline/autoload/lightline/colorscheme/16color.vim create mode 100644 start/lightline/autoload/lightline/colorscheme/OldHope.vim create mode 100644 start/lightline/autoload/lightline/colorscheme/PaperColor.vim create mode 100644 start/lightline/autoload/lightline/colorscheme/PaperColor_dark.vim create mode 100644 start/lightline/autoload/lightline/colorscheme/PaperColor_light.vim create mode 100644 start/lightline/autoload/lightline/colorscheme/Tomorrow.vim create mode 100644 start/lightline/autoload/lightline/colorscheme/Tomorrow_Night.vim create mode 100644 start/lightline/autoload/lightline/colorscheme/Tomorrow_Night_Blue.vim create mode 100644 start/lightline/autoload/lightline/colorscheme/Tomorrow_Night_Bright.vim create mode 100644 start/lightline/autoload/lightline/colorscheme/Tomorrow_Night_Eighties.vim create mode 100644 start/lightline/autoload/lightline/colorscheme/darcula.vim create mode 100644 start/lightline/autoload/lightline/colorscheme/default.vim create mode 100644 start/lightline/autoload/lightline/colorscheme/deus.vim create mode 100644 start/lightline/autoload/lightline/colorscheme/jellybeans.vim create mode 100644 start/lightline/autoload/lightline/colorscheme/landscape.vim create mode 100644 start/lightline/autoload/lightline/colorscheme/materia.vim create mode 100644 start/lightline/autoload/lightline/colorscheme/material.vim create mode 100644 start/lightline/autoload/lightline/colorscheme/molokai.vim create mode 100644 start/lightline/autoload/lightline/colorscheme/nord.vim create mode 100644 start/lightline/autoload/lightline/colorscheme/one.vim create mode 100644 start/lightline/autoload/lightline/colorscheme/powerline.vim create mode 100644 start/lightline/autoload/lightline/colorscheme/seoul256.vim create mode 100644 start/lightline/autoload/lightline/colorscheme/solarized.vim create mode 100644 start/lightline/autoload/lightline/colorscheme/srcery_drk.vim create mode 100644 start/lightline/autoload/lightline/colorscheme/wombat.vim create mode 100644 start/lightline/autoload/lightline/colortable.vim create mode 100644 start/lightline/autoload/lightline/tab.vim create mode 100644 start/lightline/doc/lightline.txt create mode 100644 start/lightline/plugin/lightline.vim create mode 100644 start/lspconfig-0.1.3/LICENSE.md create mode 100644 start/lspconfig-0.1.3/doc/lspconfig.txt create mode 100644 start/lspconfig-0.1.3/doc/server_configurations.md create mode 100644 start/lspconfig-0.1.3/doc/server_configurations.txt create mode 100644 start/lspconfig-0.1.3/lua/lspconfig.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/configs.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/als.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/angularls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/ansiblels.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/arduino_language_server.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/asm_lsp.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/awk_ls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/bashls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/beancount.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/bicep.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/bsl_ls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/ccls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/clangd.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/clarity_lsp.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/clojure_lsp.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/cmake.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/codeqlls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/crystalline.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/csharp_ls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/cssls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/cssmodules_ls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/cucumber_language_server.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/dartls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/denols.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/dhall_lsp_server.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/diagnosticls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/dockerls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/dotls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/efm.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/elixirls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/elmls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/ember.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/emmet_ls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/erlangls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/esbonio.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/eslint.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/flow.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/flux_lsp.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/foam_ls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/fortls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/fsautocomplete.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/fstar.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/gdscript.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/ghcide.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/golangci_lint_ls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/gopls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/gradle_ls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/grammarly.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/graphql.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/groovyls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/haxe_language_server.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/hdl_checker.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/hhvm.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/hie.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/hls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/hoon_ls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/html.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/idris2_lsp.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/intelephense.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/java_language_server.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/jdtls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/jedi_language_server.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/jsonls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/jsonnet_ls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/julials.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/kotlin_language_server.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/lean3ls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/leanls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/lelwel_ls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/lemminx.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/ltex.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/metals.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/mint.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/mm0_ls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/nickel_ls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/nimls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/ocamlls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/ocamllsp.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/ols.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/omnisharp.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/opencl_ls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/openscad_ls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/pasls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/perlls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/perlnavigator.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/perlpls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/phpactor.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/please.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/powershell_es.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/prismals.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/prosemd_lsp.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/psalm.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/puppet.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/purescriptls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/pylsp.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/pyre.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/pyright.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/quick_lint_js.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/r_language_server.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/racket_langserver.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/reason_ls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/remark_ls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/rescriptls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/rls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/rnix.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/robotframework_ls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/rome.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/rust_analyzer.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/salt_ls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/scry.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/serve_d.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/sixtyfps.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/slint_lsp.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/solang.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/solargraph.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/solc.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/solidity_ls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/sorbet.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/sourcekit.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/sourcery.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/spectral.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/sqlls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/sqls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/stylelint_lsp.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/sumneko_lua.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/svelte.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/svls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/tailwindcss.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/taplo.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/teal_ls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/terraform_lsp.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/terraformls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/texlab.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/tflint.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/theme_check.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/tsserver.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/typeprof.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/vala_ls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/vdmj.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/verible.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/vimls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/vls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/volar.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/vuels.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/yamlls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/zeta_note.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/zk.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/server_configurations/zls.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/ui/lspinfo.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/ui/windows.lua create mode 100644 start/lspconfig-0.1.3/lua/lspconfig/util.lua create mode 100644 start/lspconfig-0.1.3/plugin/lspconfig.vim create mode 100644 start/repeat/README.markdown create mode 100644 start/repeat/autoload/repeat.vim create mode 100644 start/signify/LICENSE create mode 100644 start/signify/README.md create mode 100644 start/signify/autoload/sy.vim create mode 100644 start/signify/autoload/sy/debug.vim create mode 100644 start/signify/autoload/sy/fold.vim create mode 100644 start/signify/autoload/sy/highlight.vim create mode 100644 start/signify/autoload/sy/jump.vim create mode 100644 start/signify/autoload/sy/repo.vim create mode 100644 start/signify/autoload/sy/sign.vim create mode 100644 start/signify/autoload/sy/util.vim create mode 100644 start/signify/doc/signify.txt create mode 100644 start/signify/plugin/signify.vim (limited to 'start') diff --git a/start/Main/autoload/coreplug/fzf.vim b/start/Main/autoload/coreplug/fzf.vim new file mode 100644 index 0000000..0253dd3 --- /dev/null +++ b/start/Main/autoload/coreplug/fzf.vim @@ -0,0 +1,19 @@ +function! coreplug#fzf#create_window() + let buf = nvim_create_buf(v:false, v:true) + call setbufvar(buf, '&scl', 'no') + + let width = float2nr(&columns - (&columns * 2 / 5)) + let height = &lines < 18 ? &lines : 18 + let opts = { + \ 'relative': 'editor', + \ 'row': float2nr((&lines - height) / 2), + \ 'col': float2nr((&columns - width) / 2), + \ 'width': width, + \ 'height': height + \} + let win = nvim_open_win(buf, v:true, opts) + call setwinvar(win, '&nu', 0) + call setwinvar(win, '&rnu', 0) +endfunction + +" vi: sw=4 ts=4 noet tw=80 cc=80 diff --git a/start/Main/plugin/init.vim b/start/Main/plugin/init.vim new file mode 100644 index 0000000..e4639e7 --- /dev/null +++ b/start/Main/plugin/init.vim @@ -0,0 +1,3 @@ +let $FZF_DEFAULT_OPTS='--layout=reverse --margin=1' +let g:fzf_layout = {'window': 'call coreplug#fzf#create_window()'} +nn :call fzf#vim#files([], 0) diff --git a/start/cmp/COMMIT b/start/cmp/COMMIT new file mode 100644 index 0000000..c5798ea --- /dev/null +++ b/start/cmp/COMMIT @@ -0,0 +1 @@ +cd694b8944eb1ae98f1d0e01cf837e66b15c2857 \ No newline at end of file diff --git a/start/cmp/COMMIT-LSP b/start/cmp/COMMIT-LSP new file mode 100644 index 0000000..d5d6e67 --- /dev/null +++ b/start/cmp/COMMIT-LSP @@ -0,0 +1 @@ +affe808a5c56b71630f17aa7c38e15c59fd648a8 \ No newline at end of file diff --git a/start/cmp/LICENSE b/start/cmp/LICENSE new file mode 100644 index 0000000..ae725ef --- /dev/null +++ b/start/cmp/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 hrsh7th + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/start/cmp/after/plugin/cmp_nvim_lsp.lua b/start/cmp/after/plugin/cmp_nvim_lsp.lua new file mode 100644 index 0000000..6d566fa --- /dev/null +++ b/start/cmp/after/plugin/cmp_nvim_lsp.lua @@ -0,0 +1 @@ +require('cmp_nvim_lsp').setup() diff --git a/start/cmp/autoload/cmp.vim b/start/cmp/autoload/cmp.vim new file mode 100644 index 0000000..43b8cc2 --- /dev/null +++ b/start/cmp/autoload/cmp.vim @@ -0,0 +1,64 @@ +let s:bridge_id = 0 +let s:sources = {} + +" +" cmp#register_source +" +function! cmp#register_source(name, source) abort + let l:methods = [] + for l:method in ['is_available', 'get_debug_name', 'get_trigger_characters', 'get_keyword_pattern', 'complete', 'execute', 'resolve'] + if has_key(a:source, l:method) && type(a:source[l:method]) == v:t_func + call add(l:methods, l:method) + endif + endfor + + let s:bridge_id += 1 + let a:source.bridge_id = s:bridge_id + let a:source.id = luaeval('require("cmp").register_source(_A[1], require("cmp.vim_source").new(_A[2], _A[3]))', [a:name, s:bridge_id, l:methods]) + let s:sources[s:bridge_id] = a:source + return a:source.id +endfunction + +" +" cmp#unregister_source +" +function! cmp#unregister_source(id) abort + if has_key(s:sources, a:id) + unlet s:sources[a:id] + endif + call luaeval('require("cmp").unregister_source(_A)', a:id) +endfunction + +" +" cmp#_method +" +function! cmp#_method(bridge_id, method, args) abort + try + let l:source = s:sources[a:bridge_id] + if a:method ==# 'is_available' + return l:source[a:method]() + elseif a:method ==# 'get_debug_name' + return l:source[a:method]() + elseif a:method ==# 'get_keyword_pattern' + return l:source[a:method](a:args[0]) + elseif a:method ==# 'get_trigger_characters' + return l:source[a:method](a:args[0]) + elseif a:method ==# 'complete' + return l:source[a:method](a:args[0], s:callback(a:args[1])) + elseif a:method ==# 'resolve' + return l:source[a:method](a:args[0], s:callback(a:args[1])) + elseif a:method ==# 'execute' + return l:source[a:method](a:args[0], s:callback(a:args[1])) + endif + catch /.*/ + echomsg string({ 'exception': v:exception, 'throwpoint': v:throwpoint }) + endtry + return v:null +endfunction + +" +" s:callback +" +function! s:callback(id) abort + return { ... -> luaeval('require("cmp.vim_source").on_callback(_A[1], _A[2])', [a:id, a:000]) } +endfunction diff --git a/start/cmp/doc/cmp-nvim-lsp.txt b/start/cmp/doc/cmp-nvim-lsp.txt new file mode 100644 index 0000000..28e3700 --- /dev/null +++ b/start/cmp/doc/cmp-nvim-lsp.txt @@ -0,0 +1,29 @@ +*cmp-nvim-lsp* + +============================================================================== +CONTENTS *cmp-nvim-lsp-contents* + +FAQ |cmp-nvim-lsp-faq| + + + +============================================================================== +FAQ *cmp-nvim-lsp-faq* + +How to disable specific LSP server's cmpletion?~ + + You can disable specific LSP server's cmpletion by adding the following + +> + require('lspconfig')[%YOUR_LSP_SERVER%].setup { + on_attach = function(client) + client.server_capabilities.completionProvider = false + end + } +< + + + +============================================================================== + vim:tw=78:ts=2:et:ft=help:norl: + diff --git a/start/cmp/doc/cmp.txt b/start/cmp/doc/cmp.txt new file mode 100644 index 0000000..e54f66e --- /dev/null +++ b/start/cmp/doc/cmp.txt @@ -0,0 +1,806 @@ +*nvim-cmp* *cmp* + +A completion plugin for neovim coded in Lua. + +============================================================================== +CONTENTS *cmp-contents* + +Abstract |cmp-abstract| +Concept |cmp-concept| +Usage |cmp-usage| +Function |cmp-function| +Mapping |cmp-mapping| +Command |cmp-command| +Highlight |cmp-highlight| +Autocmd |cmp-autocmd| +Config |cmp-config| +Config Helper |cmp-config-helper| +Develop |cmp-develop| +FAQ |cmp-faq| +============================================================================== +Abstract *cmp-abstract* + +This is nvim-cmp's document. + +1. This help file uses the type definition notation like `{lsp,cmp,vim}.*` + - You can find it in `../lua/cmp/types/init.lua`. +2. Advanced configuration is described on the wiki. + - https://github.com/hrsh7th/nvim-cmp/wiki + +============================================================================== +Concept *cmp-concept* + +- Full support for LSP completion related capabilities +- Powerful customization abilities via Lua functions +- Smart handling of key mapping +- No flicker + +============================================================================== +Usage *cmp-usage* + +Recommended configuration is written below. + NOTE: + 1. You must provide `snippet.expand` function. + 2. `cmp.setup.cmdline` won't work if you use `native` completion menu. + 3. You can disable the `default` options via specifying `cmp.config.disable` value. +> + call plug#begin(s:plug_dir) + Plug 'neovim/nvim-lspconfig' + Plug 'hrsh7th/cmp-nvim-lsp' + Plug 'hrsh7th/cmp-buffer' + Plug 'hrsh7th/cmp-path' + Plug 'hrsh7th/cmp-cmdline' + Plug 'hrsh7th/nvim-cmp' + + " For vsnip users. + Plug 'hrsh7th/cmp-vsnip' + Plug 'hrsh7th/vim-vsnip' + + " For luasnip users. + " Plug 'L3MON4D3/LuaSnip' + " Plug 'saadparwaiz1/cmp_luasnip' + + " For snippy users. + " Plug 'dcampos/nvim-snippy' + " Plug 'dcampos/cmp-snippy' + + " For ultisnips users. + " Plug 'SirVer/ultisnips' + " Plug 'quangnguyen30192/cmp-nvim-ultisnips' + + call plug#end() + + set completeopt=menu,menuone,noselect + + lua <'] = cmp.mapping.scroll_docs(-4), + [''] = cmp.mapping.scroll_docs(4), + [''] = cmp.mapping.complete(), + [''] = cmp.mapping.confirm({ select = true }), + }), + sources = cmp.config.sources({ + { name = 'nvim_lsp' }, + { name = 'vsnip' }, -- For vsnip users. + -- { name = 'luasnip' }, -- For luasnip users. + -- { name = 'snippy' }, -- For snippy users. + -- { name = 'ultisnips' }, -- For ultisnips users. + }, { + { name = 'buffer' }, + }) + }) + + -- `/` cmdline setup. + cmp.setup.cmdline('/', { + mapping = cmp.mapping.preset.cmdline(), + sources = { + { name = 'buffer' } + } + }) + + -- `:` cmdline setup. + cmp.setup.cmdline(':', { + mapping = cmp.mapping.preset.cmdline(), + sources = cmp.config.sources({ + { name = 'path' } + }, { + { name = 'cmdline' } + }) + }) + + -- Setup lspconfig. + local capabilities = require('cmp_nvim_lsp').update_capabilities(vim.lsp.protocol.make_client_capabilities()) + require('lspconfig')[%YOUR_LSP_SERVER%].setup { + capabilities = capabilities + } + EOF +< +============================================================================== +Function *cmp-function* + +NOTE: `lua require('cmp').complete()` can be used to call these functions in mapping. + +*cmp.setup* (config: cmp.ConfigSchema) + Setup global configuration. See configuration options. + +*cmp.setup.filetype* (filetype: string, config: cmp.ConfigSchema) + Setup filetype-specific configuration. + +*cmp.setup.buffer* (config: cmp.ConfigSchema) + Setup configuration for the current buffer. + +*cmp.setup.cmdline* (cmdtype: string, config: cmp.ConfigSchema) + Setup cmdline configuration for the specific type of cmd. + See |getcmdtype()| + NOTE: nvim-cmp does not support the `=` cmd type. + +*cmp.visible* () + Return boolean showing whether the completion menu is visible or not. + +*cmp.get_entries* () + Return all current entries. + +*cmp.get_selected_entry* () + Return current selected entry (contains preselected). + +*cmp.get_active_entry* () + Return current selected entry (without preselected). + +*cmp.close* () + Close the completion menu. + +*cmp.abort* () + Closes the completion menu and restore the current line to the state when it was started current completion. + +*cmp.select_next_item* (option: { behavior = cmp.SelectBehavior }) + Select next item. + +*cmp.select_prev_item* (option: { behavior = cmp.SelectBehavior })* + Select previous item. + +*cmp.scroll_docs* (delta: number) + Scroll docs if visible. + +*cmp.complete* (option: { reason = cmp.ContextReason, config = cmp.ConfigSchema }) + Invoke completion. + + The following configurations defines the key mapping to show completion only for vsnip snippets. +> + cmp.setup { + mapping = { + [''] = cmp.mapping.complete({ + config = { + sources = { + { name = 'vsnip' } + } + } + }) + } + } +< > + inoremap lua require('cmp').complete({ config = { sources = { { name = 'vsnip' } } } }) +< + NOTE: `config` in that case means a temporary setting, but `config.mapping` remains permanent. + +*cmp.complete_common_string* () + Complete common string (reminds shell completion behavior). +> + cmp.setup { + mapping = { + [''] = cmp.mapping(function(fallback) + if cmp.visible() then + return cmp.complete_common_string() + end + fallback() + end, { 'i', 'c' }), + } + } +< +*cmp.confirm* (option: cmp.ConfirmOption, callback: function) + Accepts current selected completion item. + If you didn't select any item and `{ select = true }` is specified for + this, nvim-cmp would automatically select the first item. + +*cmp.event:on* ('%EVENT_NAME%, callback) + Subscribe to nvim-cmp's event. Events are listed below. + + - `complete_done`: emit after current completion is done. + - `confirm_done`: emit after confirmation is done. + +============================================================================== +Mapping *cmp-mapping* + +Nvim-cmp's mapping mechanism is complex but flexible and user-friendly. + +You can specify the mapping function that receives the `fallback` function as argument. +The `fallback` function can be used to call an existing mapping. + +For example, typical pair-wise plugin automatically defines the mappings for `` and `(`. +Nvim-cmp might overwrite it via specified mapping. +But you can use existing mapping via invoking the `fallback` function. +> + cmp.setup { + mapping = { + [''] = function(fallback) + if cmp.visible() then + cmp.confirm() + else + fallback() -- If you use vim-endwise, this fallback will behave as vim-endwise. + end + end + } + } +< > + cmp.setup { + mapping = { + [''] = function(fallback) + if cmp.visible() then + cmp.select_next_item() + else + fallback() + end + end + } + } +< + +And you can specify the mapping modes. +> + cmp.setup { + mapping = { + [''] = cmp.mapping(your_mapping_function, { 'i', 'c' }) + } + } +< +And you can specify different mappings for different modes using the same key. +> + cmp.setup { + mapping = { + [''] = cmp.mapping({ + i = your_mapping_function_a, + c = your_mapping_function_b, + }) + } + } +< +You can also use built-in mapping helpers. + + *cmp.mapping.close* () + Same as |cmp.close|. + + *cmp.mapping.abort* () + Same as |cmp.abort|. + + *cmp.mapping.select_next_item* (option: { behavior = cmp.SelectBehavior }) + Same as |cmp.select_next_item|. + + *cmp.mapping.select_prev_item* (option: { behavior = cmp.SelectBehavior }) + Same as |cmp.select_prev_item|. + + *cmp.mapping.scroll_docs* (delta: number) + Same as |cmp.scroll_docs|. + + *cmp.mapping.complete* (option: cmp.CompleteParams) + Same as |cmp.complete|. + + *cmp.mapping.complete_common_string* () + Same as |cmp.complete_common_string|. + + *cmp.mapping.confirm* (option: cmp.ConfirmOption) + Same as |cmp.confirm|. + +Built-in mapping helpers are only available as a configuration option. +If you want to call nvim-cmp features directly, please use |cmp-function| instead. + +============================================================================== +Command *cmp-command* + +*CmpStatus* + Describes statuses and states of sources. + Sometimes `unknown` source will be printed but it isn't problem. + For that reason `cmp-nvim-lsp` registered on the InsertEnter autocmd will + have `unknown` status. + +============================================================================== +Highlight *cmp-highlight* + +*CmpItemAbbr* + Highlights unmatched characters of each completion field. + +*CmpItemAbbrDeprecated* + Highlights unmatched characters of each deprecated completion field. + +*CmpItemAbbrMatch* + Highlights matched characters of each completion field. Matched characters + must form a substring of a field which share a starting position. + +*CmpItemAbbrMatchFuzzy* + Highlights fuzzy-matched characters of each completion field. + +*CmpItemKind* + Highlights kind of the field. + +NOTE: `kind` is a symbol after each completion option. + +*CmpItemKind%KIND_NAME%* + Highlights kind of the field for specific `lsp.CompletionItemKind`. + If you only want to overwrite the `method` kind's highlight group, you can do this: +> + highlight CmpItemKindMethod guibg=NONE guifg=Orange +< +*CmpItemMenu* + The menu field's highlight group. + +============================================================================== +Autocmd *cmp-autocmd* + +You can create custom autocommands for certain nvim-cmp events by defining +autocommands for the User event with the following patterns: + +*CmpReady* + Invoked when nvim-cmp gets sourced from `plugin/cmp.lua`. + +============================================================================== +Config *cmp-config* + +You can use the following options via `cmp.setup { ... }` . + + *cmp-config.enabled* +enabled~ + `boolean | fun(): boolean` + Toggles the plugin on and off. + + *cmp-config.preselect* +preselect~ + `cmp.PreselectMode` + + 1. `cmp.PreselectMode.Item` + nvim-cmp will pre-select the item that the source specified. + 2. `cmp.PreselectMode.None` + nvim-cmp wouldn't pre-select any items. + + *cmp-config.mapping* +mapping~ + `table + final_score = orig_score + ((#sources - (source_index - 1)) * sorting.priority_weight) +< + *cmp-config.sorting.comparators* +sorting.comparators~ + `(fun(entry1: cmp.Entry, entry2: cmp.Entry): boolean | nil)[]` + The function to customize the sorting behavior. + You can use built-in comparators via `cmp.config.compare.*`. + + *cmp-config.sources* +sources~ + `cmp.SourceConfig[]` + List of the sources and their configurations to use. + Order of the sources matters for sorting order. + + *cmp-config.sources[n].name* +sources[n].name~ + `string` + The source name. + + *cmp-config.sources[n].option* +sources[n].option~ + `table` + The specific options defined by the source itself. + + *cmp-config.sources[n].keyword_length* +sources[n].keyword_length~ + `number` + The source specific keyword length to trigger auto completion. + + *cmp-config.sources[n].keyword_pattern* +sources[n].keyword_pattern~ + `number` + The source specific keyword pattern. + + *cmp-config.sources[n].trigger_characters* +sources[n].trigger_characters~ + `string[]` + The source specific keyword pattern. + + *cmp-config.sources[n].priority* +sources[n].priority~ + `number` + The source specific priority value. + + *cmp-config.sources[n].max_item_count* +sources[n].max_item_count~ + `number` + The source specific item count. + + *cmp-config.sources[n].group_index* +sources[n].group_index~ + `number` + The source group index. + + For instance, you can specify the `buffer`'s source `group_index` to bigger number + if you don't want to see the buffer source items when nvim-lsp source is available. +> + cmp.setup { + sources = { + { name = 'nvim_lsp', group_index = 1 }, + { name = 'buffer', group_index = 2 }, + } + } +< + You can specify this via the built-in configuration helper like this. +> + cmp.setup { + sources = cmp.config.sources({ + { name = 'nvim_lsp' }, + }, { + { name = 'buffer' }, + }) + } +< + *cmp-config.view* +view~ + `{ entries: cmp.EntriesConfig|string }` + Specify the view class to customize appearance. + Currently available configuration options are: + + *cmp-config.window.{completion,documentation}.border* +window.{completion,documentation}.border~ + `string | string[] | nil` + Border characters used for the completion popup menu when |experimental.native_menu| is disabled. + See |nvim_open_win|. + + *cmp-config.window.{completion,documentation}.winhighlight* +window.{completion,documentation}.winhighlight~ + `string | cmp.WinhighlightConfig` + Specify the window's winhighlight option. + See |nvim_open_win|. + + *cmp-config.window.{completion,documentation}.zindex* +window.{completion,documentation}.zindex~ + `number` + The completion window's zindex. + See |nvim_open_win|. + + *cmp-config.window.documentation.max_width* +window.documentation.max_width~ + `number` + The documentation window's max width. + + *cmp-config.window.documentation.max_height* +window.documentation.max_height~ + `number` + The documentation window's max height. + + *cmp-config.experimental.ghost_text* +experimental.ghost_text~ + `boolean | { hl_group = string }` + Whether to enable the ghost_text feature. + +============================================================================== +Config Helper *cmp-config-helper* + +You can use the following configuration helpers: + +cmp.config.compare~ + + TBD + +cmp.config.context~ + + The `cmp.config.context` can be used for context-aware completion toggling. +> + cmp.setup { + enabled = function() + -- disable completion if the cursor is `Comment` syntax group. + return not cmp.config.context.in_syntax_group('Comment') + end + } +< + *cmp.config.context.in_syntax_group* (group) + You can specify the vim's built-in syntax group. + If you use tree-sitter, you should use `cmp.config.context.in_treesitter_capture` instead. + + *cmp.config.context.in_treesitter_capture* (capture) + You can specify the treesitter capture name. + If you don't use `nvim-treesitter`, this helper doesn't work correctly. + +cmp.config.mapping~ + + See |cmp-mapping| + +cmp.config.sources~ + + *cmp.config.sources* (...sources) + You can specify multiple source arrays. The sources are grouped in the + order you specify, and the groups are displayed as a fallback, like chain + completion. +> + cmp.setup { + sources = cmp.config.sources({ + { name = 'nvim_lsp' }, + }, { + { name = 'buffer' }, + }) + } +< +cmp.config.window~ + + *cmp.config.window.bordered* (option) + Make window `bordered`. + The option is described in `cmp.ConfigSchema`. +> + cmp.setup { + window = { + completion = cmp.config.window.bordered(), + documentation = cmp.config.window.bordered(), + } + } +< +============================================================================== +Develop *cmp-develop* + +Create custom source~ + +NOTE: + 1. The `complete` method is required. Others can be omitted. + 2. The `callback` argument must always be called. + 3. You can use only `require('cmp')` in custom source. + 4. If LSP spec was changed, nvim-cmp would follow it without any announcement. + 5. You should read ./lua/cmp/types and https://microsoft.github.io/language-server-protocol/specifications/specification-current. + 6. Please add `nvim-cmp` topic for github repo. + +You can create custom source like the following example. + +> + local source = {} + + ---Return this source is available in current context or not. (Optional) + ---@return boolean + function source:is_available() + return true + end + + ---Return the debug name of this source. (Optional) + ---@return string + function source:get_debug_name() + return 'debug name' + end + + ---Return keyword pattern for triggering completion. (Optional) + ---If this is ommited, nvim-cmp will use default keyword pattern. See |cmp-config.completion.keyword_pattern| + ---@return string + function source:get_keyword_pattern() + return [[\k\+]] + end + + ---Return trigger characters for triggering completion. (Optional) + function source:get_trigger_characters() + return { '.' } + end + + ---Invoke completion. (Required) + ---@param params cmp.SourceCompletionApiParams + ---@param callback fun(response: lsp.CompletionResponse|nil) + function source:complete(params, callback) + callback({ + { label = 'January' }, + { label = 'February' }, + { label = 'March' }, + { label = 'April' }, + { label = 'May' }, + { label = 'June' }, + { label = 'July' }, + { label = 'August' }, + { label = 'September' }, + { label = 'October' }, + { label = 'November' }, + { label = 'December' }, + }) + end + + ---Resolve completion item. (Optional) + ---@param completion_item lsp.CompletionItem + ---@param callback fun(completion_item: lsp.CompletionItem|nil) + function source:resolve(completion_item, callback) + callback(completion_item) + end + + ---Execute command after item was accepted. + ---@param completion_item lsp.CompletionItem + ---@param callback fun(completion_item: lsp.CompletionItem|nil) + function source:execute(completion_item, callback) + callback(completion_item) + end + + ---Register custom source to nvim-cmp. + require('cmp').register_source('month', source.new()) +< +============================================================================== +FAQ *cmp-faq* + +Why does cmp automatically select a particular item? ~ +How to disable the preselect feature? ~ + + Nvim-cmp respects LSP(Language Server Protocol) specification. + The LSP spec defines the `preselect` feature for completion. + + You can disable the `preselect` feature like the following. +> + cmp.setup { + preselect = cmp.PreselectMode.None + } +< + +Why nvim-cmp confirm item automatically?~ +How to disable commitCharacters?~ + + You can disable commitCharacters feature (that defined in LSP spec). +> + cmp.setup { + confirmation = { + get_commit_characters = function(commit_characters) + return {} + end + } + } +< + + +How to disable auto-completion?~ +How to use nvim-cmp as like omnifunc?~ + + You can disable auto-completion like this. +> + cmp.setup { + ... + completion = { + autocomplete = false + } + ... + } +< + And you can invoke completion manually. +> + inoremap lua require('cmp').complete() +< + +How to disable nvim-cmp on the specific buffer?~ +How to setup on the specific buffer?~ + + You can setup buffer specific configuration like this. +> + cmp.setup.filetype({ 'markdown', 'help' }, { + sources = { + { name = 'path' }, + { name = 'buffer' }, + } + }) +< + +How to disable documentation window?~ + + You can use the following config. +> + cmp.setup.filetype({ 'markdown', 'help' }, { + window = { + documentation = cmp.config.disable + } + }) +< + +How to integrate with copilot.vim?~ + + Copilot.vim and nvim-cmp both have a `key-mapping fallback` mechanism. + Therefore, you should manage those plugins by yourself. + + Fortunately, the copilot.vim has the feature that disables the fallback mechanism. +> + let g:copilot_no_tab_map = v:true + imap (vimrc:copilot-dummy-map) copilot#Accept("\") +< + You can manage copilot.vim's accept feature with nvim-cmp' key-mapping configuration. +> + cmp.setup { + mapping = { + [''] = cmp.mapping(function(fallback) + vim.api.nvim_feedkeys(vim.fn['copilot#Accept'](vim.api.nvim_replace_termcodes('', true, true, true)), 'n', true) + end) + }, + experimental = { + ghost_text = false -- this feature conflict with copilot.vim's preview. + } + } +< + + +How to customize menu appearance?~ + + You can see nvim-cmp wiki (https://github.com/hrsh7th/nvim-cmp/wiki). + +============================================================================== + vim:tw=78:ts=2:et:ft=help:norl: diff --git a/start/cmp/lua/cmp/config.lua b/start/cmp/lua/cmp/config.lua new file mode 100644 index 0000000..42e9a43 --- /dev/null +++ b/start/cmp/lua/cmp/config.lua @@ -0,0 +1,229 @@ +local mapping = require('cmp.config.mapping') +local cache = require('cmp.utils.cache') +local keymap = require('cmp.utils.keymap') +local misc = require('cmp.utils.misc') +local api = require('cmp.utils.api') + +---@class cmp.Config +---@field public g cmp.ConfigSchema +local config = {} + +---@type cmp.Cache +config.cache = cache.new() + +---@type cmp.ConfigSchema +config.global = require('cmp.config.default')() + +---@type table +config.buffers = {} + +---@type table +config.filetypes = {} + +---@type table +config.cmdline = {} + +---@type cmp.ConfigSchema +config.onetime = {} + +---Set configuration for global. +---@param c cmp.ConfigSchema +config.set_global = function(c) + config.global = config.normalize(misc.merge(c, config.global)) + config.global.revision = config.global.revision or 1 + config.global.revision = config.global.revision + 1 +end + +---Set configuration for buffer +---@param c cmp.ConfigSchema +---@param bufnr number|nil +config.set_buffer = function(c, bufnr) + local revision = (config.buffers[bufnr] or {}).revision or 1 + config.buffers[bufnr] = c or {} + config.buffers[bufnr].revision = revision + 1 +end + +---Set configuration for filetype +---@param c cmp.ConfigSchema +---@param filetypes string[]|string +config.set_filetype = function(c, filetypes) + for _, filetype in ipairs(type(filetypes) == 'table' and filetypes or { filetypes }) do + local revision = (config.filetypes[filetype] or {}).revision or 1 + config.filetypes[filetype] = c or {} + config.filetypes[filetype].revision = revision + 1 + end +end + +---Set configuration for cmdline +---@param c cmp.ConfigSchema +---@param cmdtype string +config.set_cmdline = function(c, cmdtype) + local revision = (config.cmdline[cmdtype] or {}).revision or 1 + config.cmdline[cmdtype] = c or {} + config.cmdline[cmdtype].revision = revision + 1 +end + +---Set configuration as oneshot completion. +---@param c cmp.ConfigSchema +config.set_onetime = function(c) + local revision = (config.onetime or {}).revision or 1 + config.onetime = c or {} + config.onetime.revision = revision + 1 +end + +---@return cmp.ConfigSchema +config.get = function() + local global_config = config.global + if config.onetime.sources then + local onetime_config = config.onetime + return config.cache:ensure({ + 'get', + 'onetime', + global_config.revision or 0, + onetime_config.revision or 0, + }, function() + local c = {} + c = misc.merge(c, config.normalize(onetime_config)) + c = misc.merge(c, config.normalize(global_config)) + return c + end) + elseif api.is_cmdline_mode() then + local cmdtype = vim.fn.getcmdtype() + local cmdline_config = config.cmdline[cmdtype] or { revision = 1, sources = {} } + return config.cache:ensure({ + 'get', + 'cmdline', + global_config.revision or 0, + cmdtype, + cmdline_config.revision or 0, + }, function() + local c = {} + c = misc.merge(c, config.normalize(cmdline_config)) + c = misc.merge(c, config.normalize(global_config)) + return c + end) + else + local bufnr = vim.api.nvim_get_current_buf() + local filetype = vim.api.nvim_buf_get_option(bufnr, 'filetype') + local buffer_config = config.buffers[bufnr] or { revision = 1 } + local filetype_config = config.filetypes[filetype] or { revision = 1 } + return config.cache:ensure({ + 'get', + 'default', + global_config.revision or 0, + filetype, + filetype_config.revision or 0, + bufnr, + buffer_config.revision or 0, + }, function() + local c = {} + c = misc.merge(config.normalize(c), config.normalize(buffer_config)) + c = misc.merge(config.normalize(c), config.normalize(filetype_config)) + c = misc.merge(config.normalize(c), config.normalize(global_config)) + return c + end) + end +end + +---Return cmp is enabled or not. +config.enabled = function() + local enabled = config.get().enabled + if type(enabled) == 'function' then + enabled = enabled() + end + return enabled and api.is_suitable_mode() +end + +---Return source config +---@param name string +---@return cmp.SourceConfig +config.get_source_config = function(name) + local c = config.get() + for _, s in ipairs(c.sources) do + if s.name == name then + return s + end + end + return nil +end + +---Return the current menu is native or not. +config.is_native_menu = function() + local c = config.get() + if c.experimental and c.experimental.native_menu then + return true + end + if c.view and c.view.entries then + return c.view.entries == 'native' or c.view.entries.name == 'native' + end + return false +end + +---Normalize mapping key +---@param c any +---@return cmp.ConfigSchema +config.normalize = function(c) + -- make sure c is not 'nil' + c = c == nil and {} or c + + -- Normalize mapping. + if c.mapping then + local normalized = {} + for k, v in pairs(c.mapping) do + normalized[keymap.normalize(k)] = mapping(v, { 'i' }) + end + c.mapping = normalized + end + + -- Notice experimental.native_menu. + if c.experimental and c.experimental.native_menu then + vim.api.nvim_echo({ + { '[nvim-cmp] ', 'Normal' }, + { 'experimental.native_menu', 'WarningMsg' }, + { ' is deprecated.\n', 'Normal' }, + { '[nvim-cmp] Please use ', 'Normal' }, + { 'view.entries = "native"', 'WarningMsg' }, + { ' instead.', 'Normal' }, + }, true, {}) + + c.view = c.view or {} + c.view.entries = c.view.entries or 'native' + end + + -- Notice documentation. + if c.documentation ~= nil then + vim.api.nvim_echo({ + { '[nvim-cmp] ', 'Normal' }, + { 'documentation', 'WarningMsg' }, + { ' is deprecated.\n', 'Normal' }, + { '[nvim-cmp] Please use ', 'Normal' }, + { 'window.documentation = cmp.config.window.bordered()', 'WarningMsg' }, + { ' instead.', 'Normal' }, + }, true, {}) + c.window = c.window or {} + c.window.documentation = c.documentation + end + + -- Notice sources.[n].opts + if c.sources then + for _, s in ipairs(c.sources) do + if s.opts and not s.option then + s.option = s.opts + s.opts = nil + vim.api.nvim_echo({ + { '[nvim-cmp] ', 'Normal' }, + { 'sources[number].opts', 'WarningMsg' }, + { ' is deprecated.\n', 'Normal' }, + { '[nvim-cmp] Please use ', 'Normal' }, + { 'sources[number].option', 'WarningMsg' }, + { ' instead.', 'Normal' }, + }, true, {}) + end + s.option = s.option or {} + end + end + + return c +end + +return config diff --git a/start/cmp/lua/cmp/config/compare.lua b/start/cmp/lua/cmp/config/compare.lua new file mode 100644 index 0000000..4b4fadc --- /dev/null +++ b/start/cmp/lua/cmp/config/compare.lua @@ -0,0 +1,234 @@ +local types = require('cmp.types') +local cache = require('cmp.utils.cache') +local misc = require('cmp.utils.misc') + +local compare = {} + +-- offset +compare.offset = function(entry1, entry2) + local diff = entry1:get_offset() - entry2:get_offset() + if diff < 0 then + return true + elseif diff > 0 then + return false + end +end + +-- exact +compare.exact = function(entry1, entry2) + if entry1.exact ~= entry2.exact then + return entry1.exact + end +end + +-- score +compare.score = function(entry1, entry2) + local diff = entry2.score - entry1.score + if diff < 0 then + return true + elseif diff > 0 then + return false + end +end + +-- recently_used +compare.recently_used = setmetatable({ + records = {}, + add_entry = function(self, e) + self.records[e.completion_item.label] = vim.loop.now() + end, +}, { + __call = function(self, entry1, entry2) + local t1 = self.records[entry1.completion_item.label] or -1 + local t2 = self.records[entry2.completion_item.label] or -1 + if t1 ~= t2 then + return t1 > t2 + end + end, +}) + +-- kind +compare.kind = function(entry1, entry2) + local kind1 = entry1:get_kind() + kind1 = kind1 == types.lsp.CompletionItemKind.Text and 100 or kind1 + local kind2 = entry2:get_kind() + kind2 = kind2 == types.lsp.CompletionItemKind.Text and 100 or kind2 + if kind1 ~= kind2 then + if kind1 == types.lsp.CompletionItemKind.Snippet then + return true + end + if kind2 == types.lsp.CompletionItemKind.Snippet then + return false + end + local diff = kind1 - kind2 + if diff < 0 then + return true + elseif diff > 0 then + return false + end + end +end + +-- sortText +compare.sort_text = function(entry1, entry2) + if misc.safe(entry1.completion_item.sortText) and misc.safe(entry2.completion_item.sortText) then + local diff = vim.stricmp(entry1.completion_item.sortText, entry2.completion_item.sortText) + if diff < 0 then + return true + elseif diff > 0 then + return false + end + end +end + +-- length +compare.length = function(entry1, entry2) + local diff = #entry1.completion_item.label - #entry2.completion_item.label + if diff < 0 then + return true + elseif diff > 0 then + return false + end +end + +-- order +compare.order = function(entry1, entry2) + local diff = entry1.id - entry2.id + if diff < 0 then + return true + elseif diff > 0 then + return false + end +end + +-- locality +compare.locality = setmetatable({ + lines_count = 10, + lines_cache = cache.new(), + locality_map = {}, + update = function(self) + local config = require('cmp').get_config() + if not vim.tbl_contains(config.sorting.comparators, compare.scopes) then + return + end + + local win, buf = vim.api.nvim_get_current_win(), vim.api.nvim_get_current_buf() + local cursor_row = vim.api.nvim_win_get_cursor(win)[1] - 1 + local max = vim.api.nvim_buf_line_count(buf) + + if self.lines_cache:get('buf') ~= buf then + self.lines_cache:clear() + self.lines_cache:set('buf', buf) + end + + self.locality_map = {} + for i = math.max(0, cursor_row - self.lines_count), math.min(max, cursor_row + self.lines_count) do + local is_above = i < cursor_row + local buffer = vim.api.nvim_buf_get_lines(buf, i, i + 1, false)[1] or '' + local locality_map = self.lines_cache:ensure({ 'line', buffer }, function() + local locality_map = {} + local regexp = vim.regex(config.completion.keyword_pattern) + while buffer ~= '' do + local s, e = regexp:match_str(buffer) + if s and e then + local w = string.sub(buffer, s + 1, e) + local d = math.abs(i - cursor_row) - (is_above and 0.1 or 0) + locality_map[w] = math.min(locality_map[w] or math.huge, d) + buffer = string.sub(buffer, e + 1) + else + break + end + end + return locality_map + end) + for w, d in pairs(locality_map) do + self.locality_map[w] = math.min(self.locality_map[w] or d, math.abs(i - cursor_row)) + end + end + end, +}, { + __call = function(self, entry1, entry2) + local local1 = self.locality_map[entry1:get_word()] + local local2 = self.locality_map[entry2:get_word()] + if local1 ~= local2 then + if local1 == nil then + return false + end + if local2 == nil then + return true + end + return local1 < local2 + end + end, +}) + +-- scopes +compare.scopes = setmetatable({ + scopes_map = {}, + update = function(self) + local config = require('cmp').get_config() + if not vim.tbl_contains(config.sorting.comparators, compare.scopes) then + return + end + + local ok, locals = pcall(require, 'nvim-treesitter.locals') + if ok then + local win, buf = vim.api.nvim_get_current_win(), vim.api.nvim_get_current_buf() + local cursor_row = vim.api.nvim_win_get_cursor(win)[1] - 1 + + -- Cursor scope. + local cursor_scope = nil + for _, scope in ipairs(locals.get_scopes(buf)) do + if scope:start() <= cursor_row and cursor_row <= scope:end_() then + if not cursor_scope then + cursor_scope = scope + else + if cursor_scope:start() <= scope:start() and scope:end_() <= cursor_scope:end_() then + cursor_scope = scope + end + end + elseif cursor_scope and cursor_scope:end_() <= scope:start() then + break + end + end + + -- Definitions. + local definitions = locals.get_definitions_lookup_table(buf) + + -- Narrow definitions. + local depth = 0 + for scope in locals.iter_scope_tree(cursor_scope, buf) do + local s, e = scope:start(), scope:end_() + + -- Check scope's direct child. + for _, definition in pairs(definitions) do + if s <= definition.node:start() and definition.node:end_() <= e then + if scope:id() == locals.containing_scope(definition.node, buf):id() then + local text = vim.treesitter.query.get_node_text(definition.node, buf) or '' + if not self.scopes_map[text] then + self.scopes_map[text] = depth + end + end + end + end + depth = depth + 1 + end + end + end, +}, { + __call = function(self, entry1, entry2) + local local1 = self.scopes_map[entry1:get_word()] + local local2 = self.scopes_map[entry2:get_word()] + if local1 ~= local2 then + if local1 == nil then + return false + end + if local2 == nil then + return true + end + return local1 < local2 + end + end, +}) + +return compare diff --git a/start/cmp/lua/cmp/config/context.lua b/start/cmp/lua/cmp/config/context.lua new file mode 100644 index 0000000..584f38a --- /dev/null +++ b/start/cmp/lua/cmp/config/context.lua @@ -0,0 +1,65 @@ +local context = {} + +---Check if cursor is in syntax group +---@param group string +---@return boolean +context.in_syntax_group = function(group) + local lnum, col = vim.fn.line('.'), math.min(vim.fn.col('.'), #vim.fn.getline('.')) + for _, syn_id in ipairs(vim.fn.synstack(lnum, col)) do + syn_id = vim.fn.synIDtrans(syn_id) -- Resolve :highlight links + if vim.fn.synIDattr(syn_id, 'name') == group then + return true + end + end + return false +end + +---Check if cursor is in treesitter capture +---@param capture string +---@return boolean +context.in_treesitter_capture = function(capture) + local highlighter = require('vim.treesitter.highlighter') + local ts_utils = require('nvim-treesitter.ts_utils') + local buf = vim.api.nvim_get_current_buf() + + local row, col = unpack(vim.api.nvim_win_get_cursor(0)) + row = row - 1 + if vim.api.nvim_get_mode().mode == 'i' then + col = col - 1 + end + + local self = highlighter.active[buf] + if not self then + return false + end + + local node_types = {} + + self.tree:for_each_tree(function(tstree, tree) + if not tstree then + return + end + + local root = tstree:root() + local root_start_row, _, root_end_row, _ = root:range() + if root_start_row > row or root_end_row < row then + return + end + + local query = self:get_query(tree:lang()) + if not query:query() then + return + end + + local iter = query:query():iter_captures(root, self.bufnr, row, row + 1) + for _, node, _ in iter do + if ts_utils.is_in_node_range(node, row, col) then + table.insert(node_types, node:type()) + end + end + end, true) + + return vim.tbl_contains(node_types, capture) +end + +return context diff --git a/start/cmp/lua/cmp/config/default.lua b/start/cmp/lua/cmp/config/default.lua new file mode 100644 index 0000000..dce5168 --- /dev/null +++ b/start/cmp/lua/cmp/config/default.lua @@ -0,0 +1,97 @@ +local compare = require('cmp.config.compare') +local types = require('cmp.types') + +local WIDE_HEIGHT = 40 + +---@return cmp.ConfigSchema +return function() + return { + enabled = function() + local disabled = false + disabled = disabled or (vim.api.nvim_buf_get_option(0, 'buftype') == 'prompt') + disabled = disabled or (vim.fn.reg_recording() ~= '') + disabled = disabled or (vim.fn.reg_executing() ~= '') + return not disabled + end, + + preselect = types.cmp.PreselectMode.Item, + + mapping = {}, + + snippet = { + expand = function() + error('snippet engine is not configured.') + end, + }, + + completion = { + autocomplete = { + types.cmp.TriggerEvent.TextChanged, + }, + completeopt = 'menu,menuone,noselect', + keyword_pattern = [[\%(-\?\d\+\%(\.\d\+\)\?\|\h\w*\%(-\w*\)*\)]], + keyword_length = 1, + }, + + formatting = { + fields = { 'abbr', 'kind', 'menu' }, + format = function(_, vim_item) + return vim_item + end, + }, + + matching = { + disallow_fuzzy_matching = false, + disallow_partial_matching = false, + disallow_prefix_unmatching = false, + }, + + sorting = { + priority_weight = 2, + comparators = { + compare.offset, + compare.exact, + -- compare.scopes, + compare.score, + compare.recently_used, + compare.locality, + compare.kind, + compare.sort_text, + compare.length, + compare.order, + }, + }, + + sources = {}, + + confirmation = { + default_behavior = types.cmp.ConfirmBehavior.Insert, + get_commit_characters = function(commit_characters) + return commit_characters + end, + }, + + event = {}, + + experimental = { + ghost_text = false, + }, + + view = { + entries = { name = 'custom', selection_order = 'top_down' }, + }, + + window = { + completion = { + border = { '', '', '', '', '', '', '', '' }, + winhighlight = 'Normal:Pmenu,FloatBorder:Pmenu,CursorLine:PmenuSel,Search:None', + }, + documentation = { + max_height = math.floor(WIDE_HEIGHT * (WIDE_HEIGHT / vim.o.lines)), + max_width = math.floor((WIDE_HEIGHT * 2) * (vim.o.columns / (WIDE_HEIGHT * 2 * 16 / 9))), + border = { '', '', '', ' ', '', '', '', ' ' }, + winhighlight = 'FloatBorder:NormalFloat', + }, + }, + } +end diff --git a/start/cmp/lua/cmp/config/mapping.lua b/start/cmp/lua/cmp/config/mapping.lua new file mode 100644 index 0000000..c2028c8 --- /dev/null +++ b/start/cmp/lua/cmp/config/mapping.lua @@ -0,0 +1,172 @@ +local types = require('cmp.types') +local misc = require('cmp.utils.misc') +local feedkeys = require('cmp.utils.feedkeys') +local keymap = require('cmp.utils.keymap') + +local mapping = setmetatable({}, { + __call = function(_, invoke, modes) + if type(invoke) == 'function' then + local map = {} + for _, mode in ipairs(modes or { 'i' }) do + map[mode] = invoke + end + return map + end + return invoke + end, +}) + +---Mapping preset configuration. +mapping.preset = {} + +---Mapping preset insert-mode configuration. +mapping.preset.insert = function(override) + return misc.merge(override or {}, { + [''] = { + i = mapping.select_next_item({ behavior = types.cmp.SelectBehavior.Select }), + }, + [''] = { + i = mapping.select_prev_item({ behavior = types.cmp.SelectBehavior.Select }), + }, + [''] = { + i = mapping.select_next_item({ behavior = types.cmp.SelectBehavior.Insert }), + }, + [''] = { + i = mapping.select_prev_item({ behavior = types.cmp.SelectBehavior.Insert }), + }, + [''] = { + i = mapping.confirm({ select = false }), + }, + [''] = { + i = mapping.abort(), + }, + }) +end + +---Mapping preset cmdline-mode configuration. +mapping.preset.cmdline = function(override) + return misc.merge(override or {}, { + [''] = { + c = function() + local cmp = require('cmp') + if cmp.visible() then + cmp.select_next_item() + else + feedkeys.call(keymap.t(''), 'n') + end + end, + }, + [''] = { + c = function() + local cmp = require('cmp') + if cmp.visible() then + cmp.select_prev_item() + else + feedkeys.call(keymap.t(''), 'n') + end + end, + }, + [''] = { + c = function(fallback) + local cmp = require('cmp') + if cmp.visible() then + cmp.select_next_item() + else + fallback() + end + end, + }, + [''] = { + c = function(fallback) + local cmp = require('cmp') + if cmp.visible() then + cmp.select_prev_item() + else + fallback() + end + end, + }, + [''] = { + c = mapping.close(), + }, + }) +end + +---Invoke completion +---@param option cmp.CompleteParams +mapping.complete = function(option) + return function(fallback) + if not require('cmp').complete(option) then + fallback() + end + end +end + +---Complete common string. +mapping.complete_common_string = function() + return function(fallback) + if not require('cmp').complete_common_string() then + fallback() + end + end +end + +---Close current completion menu if it displayed. +mapping.close = function() + return function(fallback) + if not require('cmp').close() then + fallback() + end + end +end + +---Abort current completion menu if it displayed. +mapping.abort = function() + return function(fallback) + if not require('cmp').abort() then + fallback() + end + end +end + +---Scroll documentation window. +mapping.scroll_docs = function(delta) + return function(fallback) + if not require('cmp').scroll_docs(delta) then + fallback() + end + end +end + +---Select next completion item. +mapping.select_next_item = function(option) + return function(fallback) + if not require('cmp').select_next_item(option) then + local release = require('cmp').core:suspend() + fallback() + vim.schedule(release) + end + end +end + +---Select prev completion item. +mapping.select_prev_item = function(option) + return function(fallback) + if not require('cmp').select_prev_item(option) then + local release = require('cmp').core:suspend() + fallback() + vim.schedule(release) + end + end +end + +---Confirm selection +mapping.confirm = function(option) + return function(fallback) + if not require('cmp').confirm(option) then + fallback() + end + end +end + +return mapping diff --git a/start/cmp/lua/cmp/config/sources.lua b/start/cmp/lua/cmp/config/sources.lua new file mode 100644 index 0000000..cfb09c0 --- /dev/null +++ b/start/cmp/lua/cmp/config/sources.lua @@ -0,0 +1,10 @@ +return function(...) + local sources = {} + for i, group in ipairs({ ... }) do + for _, source in ipairs(group) do + source.group_index = i + table.insert(sources, source) + end + end + return sources +end diff --git a/start/cmp/lua/cmp/config/window.lua b/start/cmp/lua/cmp/config/window.lua new file mode 100644 index 0000000..b6fec0f --- /dev/null +++ b/start/cmp/lua/cmp/config/window.lua @@ -0,0 +1,12 @@ +local window = {} + +window.bordered = function(opts) + opts = opts or {} + return { + border = opts.border or 'rounded', + winhighlight = opts.winhighlight or 'Normal:Normal,FloatBorder:Normal,CursorLine:Visual,Search:None', + zindex = opts.zindex or 1001, + } +end + +return window diff --git a/start/cmp/lua/cmp/context.lua b/start/cmp/lua/cmp/context.lua new file mode 100644 index 0000000..6188259 --- /dev/null +++ b/start/cmp/lua/cmp/context.lua @@ -0,0 +1,105 @@ +local misc = require('cmp.utils.misc') +local pattern = require('cmp.utils.pattern') +local types = require('cmp.types') +local cache = require('cmp.utils.cache') +local api = require('cmp.utils.api') + +---@class cmp.Context +---@field public id string +---@field public cache cmp.Cache +---@field public prev_context cmp.Context +---@field public option cmp.ContextOption +---@field public filetype string +---@field public time number +---@field public bufnr number +---@field public cursor vim.Position|lsp.Position +---@field public cursor_line string +---@field public cursor_after_line string +---@field public cursor_before_line string +local context = {} + +---Create new empty context +---@return cmp.Context +context.empty = function() + local ctx = context.new({}) -- dirty hack to prevent recursive call `context.empty`. + ctx.bufnr = -1 + ctx.input = '' + ctx.cursor = {} + ctx.cursor.row = -1 + ctx.cursor.col = -1 + return ctx +end + +---Create new context +---@param prev_context cmp.Context +---@param option cmp.ContextOption +---@return cmp.Context +context.new = function(prev_context, option) + option = option or {} + + local self = setmetatable({}, { __index = context }) + self.id = misc.id('cmp.context.new') + self.cache = cache.new() + self.prev_context = prev_context or context.empty() + self.option = option or { reason = types.cmp.ContextReason.None } + self.filetype = vim.api.nvim_buf_get_option(0, 'filetype') + self.time = vim.loop.now() + self.bufnr = vim.api.nvim_get_current_buf() + + local cursor = api.get_cursor() + self.cursor_line = api.get_current_line() + self.cursor = {} + self.cursor.row = cursor[1] + self.cursor.col = cursor[2] + 1 + self.cursor.line = self.cursor.row - 1 + self.cursor.character = misc.to_utfindex(self.cursor_line, self.cursor.col) + self.cursor_before_line = string.sub(self.cursor_line, 1, self.cursor.col - 1) + self.cursor_after_line = string.sub(self.cursor_line, self.cursor.col) + return self +end + +---Return context creation reason. +---@return cmp.ContextReason +context.get_reason = function(self) + return self.option.reason +end + +---Get keyword pattern offset +---@return number|nil +context.get_offset = function(self, keyword_pattern) + return self.cache:ensure({ 'get_offset', keyword_pattern, self.cursor_before_line }, function() + return pattern.offset(keyword_pattern .. '\\m$', self.cursor_before_line) or self.cursor.col + end) +end + +---Return if this context is changed from previous context or not. +---@return boolean +context.changed = function(self, ctx) + local curr = self + + if curr.bufnr ~= ctx.bufnr then + return true + end + if curr.cursor.row ~= ctx.cursor.row then + return true + end + if curr.cursor.col ~= ctx.cursor.col then + return true + end + if curr:get_reason() == types.cmp.ContextReason.Manual then + return true + end + + return false +end + +---Shallow clone +context.clone = function(self) + local cloned = {} + for k, v in pairs(self) do + cloned[k] = v + end + return cloned +end + +return context diff --git a/start/cmp/lua/cmp/context_spec.lua b/start/cmp/lua/cmp/context_spec.lua new file mode 100644 index 0000000..976e194 --- /dev/null +++ b/start/cmp/lua/cmp/context_spec.lua @@ -0,0 +1,31 @@ +local spec = require('cmp.utils.spec') + +local context = require('cmp.context') + +describe('context', function() + before_each(spec.before) + + describe('new', function() + it('middle of text', function() + vim.fn.setline('1', 'function! s:name() abort') + vim.bo.filetype = 'vim' + vim.fn.execute('normal! fm') + local ctx = context.new() + assert.are.equal(ctx.filetype, 'vim') + assert.are.equal(ctx.cursor.row, 1) + assert.are.equal(ctx.cursor.col, 15) + assert.are.equal(ctx.cursor_line, 'function! s:name() abort') + end) + + it('tab indent', function() + vim.fn.setline('1', '\t\tab') + vim.bo.filetype = 'vim' + vim.fn.execute('normal! fb') + local ctx = context.new() + assert.are.equal(ctx.filetype, 'vim') + assert.are.equal(ctx.cursor.row, 1) + assert.are.equal(ctx.cursor.col, 4) + assert.are.equal(ctx.cursor_line, '\t\tab') + end) + end) +end) diff --git a/start/cmp/lua/cmp/core.lua b/start/cmp/lua/cmp/core.lua new file mode 100644 index 0000000..08949a9 --- /dev/null +++ b/start/cmp/lua/cmp/core.lua @@ -0,0 +1,486 @@ +local debug = require('cmp.utils.debug') +local str = require('cmp.utils.str') +local char = require('cmp.utils.char') +local pattern = require('cmp.utils.pattern') +local feedkeys = require('cmp.utils.feedkeys') +local async = require('cmp.utils.async') +local keymap = require('cmp.utils.keymap') +local context = require('cmp.context') +local source = require('cmp.source') +local view = require('cmp.view') +local misc = require('cmp.utils.misc') +local config = require('cmp.config') +local types = require('cmp.types') +local api = require('cmp.utils.api') +local event = require('cmp.utils.event') + +local SOURCE_TIMEOUT = 500 +local DEBOUNCE_TIME = 80 +local THROTTLE_TIME = 40 + +---@class cmp.Core +---@field public suspending boolean +---@field public view cmp.View +---@field public sources cmp.Source[] +---@field public context cmp.Context +---@field public event cmp.Event +local core = {} + +core.new = function() + local self = setmetatable({}, { __index = core }) + self.suspending = false + self.sources = {} + self.context = context.new() + self.event = event.new() + self.view = view.new() + self.view.event:on('keymap', function(...) + self:on_keymap(...) + end) + self.view.event:on('complete_done', function(evt) + self.event:emit('complete_done', evt) + end) + return self +end + +---Register source +---@param s cmp.Source +core.register_source = function(self, s) + self.sources[s.id] = s +end + +---Unregister source +---@param source_id string +core.unregister_source = function(self, source_id) + self.sources[source_id] = nil +end + +---Get new context +---@param option cmp.ContextOption +---@return cmp.Context +core.get_context = function(self, option) + local prev = self.context:clone() + prev.prev_context = nil + local ctx = context.new(prev, option) + self:set_context(ctx) + return self.context +end + +---Set new context +---@param ctx cmp.Context +core.set_context = function(self, ctx) + self.context = ctx +end + +---Suspend completion +core.suspend = function(self) + self.suspending = true + -- It's needed to avoid conflicting with autocmd debouncing. + return vim.schedule_wrap(function() + self.suspending = false + end) +end + +---Get sources that sorted by priority +---@param filter cmp.SourceStatus[]|fun(s: cmp.Source): boolean +---@return cmp.Source[] +core.get_sources = function(self, filter) + local f = function(s) + if type(filter) == 'table' then + return vim.tbl_contains(filter, s.status) + elseif type(filter) == 'function' then + return filter(s) + end + return true + end + + local sources = {} + for _, c in pairs(config.get().sources) do + for _, s in pairs(self.sources) do + if c.name == s.name then + if s:is_available() and f(s) then + table.insert(sources, s) + end + end + end + end + return sources +end + +---Keypress handler +core.on_keymap = function(self, keys, fallback) + local mode = api.get_mode() + for key, mapping in pairs(config.get().mapping) do + if keymap.equals(key, keys) and mapping[mode] then + return mapping[mode](fallback) + end + end + + --Commit character. NOTE: This has a lot of cmp specific implementation to make more user-friendly. + local chars = keymap.t(keys) + local e = self.view:get_active_entry() + if e and vim.tbl_contains(config.get().confirmation.get_commit_characters(e:get_commit_characters()), chars) then + local is_printable = char.is_printable(string.byte(chars, 1)) + self:confirm(e, { + behavior = is_printable and 'insert' or 'replace', + commit_character = chars, + }, function() + local ctx = self:get_context() + local word = e:get_word() + if string.sub(ctx.cursor_before_line, -#word, ctx.cursor.col - 1) == word and is_printable then + fallback() + else + self:reset() + end + end) + return + end + + fallback() +end + +---Prepare completion +core.prepare = function(self) + for keys, mapping in pairs(config.get().mapping) do + for mode in pairs(mapping) do + keymap.listen(mode, keys, function(...) + self:on_keymap(...) + end) + end + end +end + +---Check auto-completion +core.on_change = function(self, trigger_event) + local ignore = false + ignore = ignore or self.suspending + ignore = ignore or (vim.fn.pumvisible() == 1 and (vim.v.completed_item).word) + ignore = ignore or not self.view:ready() + if ignore then + self:get_context({ reason = types.cmp.ContextReason.Auto }) + return + end + self:autoindent(trigger_event, function() + local ctx = self:get_context({ reason = types.cmp.ContextReason.Auto }) + debug.log(('ctx: `%s`'):format(ctx.cursor_before_line)) + if ctx:changed(ctx.prev_context) then + self.view:on_change() + debug.log('changed') + + if vim.tbl_contains(config.get().completion.autocomplete or {}, trigger_event) then + self:complete(ctx) + else + self.filter.timeout = self.view:visible() and THROTTLE_TIME or 0 + self:filter() + end + else + debug.log('unchanged') + end + end) +end + +---Cursor moved. +core.on_moved = function(self) + local ignore = false + ignore = ignore or self.suspending + ignore = ignore or (vim.fn.pumvisible() == 1 and (vim.v.completed_item).word) + ignore = ignore or not self.view:visible() + if ignore then + return + end + self:filter() +end + +---Check autoindent +---@param trigger_event cmp.TriggerEvent +---@param callback function +core.autoindent = function(self, trigger_event, callback) + if trigger_event ~= types.cmp.TriggerEvent.TextChanged then + return callback() + end + if not api.is_insert_mode() then + return callback() + end + + -- Check prefix + local cursor_before_line = api.get_cursor_before_line() + local prefix = pattern.matchstr('[^[:blank:]]\\+$', cursor_before_line) or '' + if #prefix == 0 then + return callback() + end + + -- Reset current completion if indentkeys matched. + for _, key in ipairs(vim.split(vim.bo.indentkeys, ',')) do + if vim.tbl_contains({ '=' .. prefix, '0=' .. prefix }, key) then + self:reset() + self:set_context(context.empty()) + break + end + end + + callback() +end + +---Complete common string for current completed entries. +core.complete_common_string = function(self) + if not self.view:visible() or self.view:get_active_entry() then + return false + end + + config.set_onetime({ + sources = config.get().sources, + matching = { + disallow_prefix_unmatching = true, + disallow_partial_matching = true, + disallow_fuzzy_matching = true, + }, + }) + + self:filter() + self.filter:sync(1000) + + config.set_onetime({}) + + local cursor = api.get_cursor() + local offset = self.view:get_offset() + local common_string + for _, e in ipairs(self.view:get_entries()) do + local vim_item = e:get_vim_item(offset) + if not common_string then + common_string = vim_item.word + else + common_string = str.get_common_string(common_string, vim_item.word) + end + end + if common_string and #common_string > (1 + cursor[2] - offset) then + feedkeys.call(keymap.backspace(string.sub(api.get_current_line(), offset, cursor[2])) .. common_string, 'n') + return true + end + return false +end + +---Invoke completion +---@param ctx cmp.Context +core.complete = function(self, ctx) + if not api.is_suitable_mode() then + return + end + + self:set_context(ctx) + + -- Invoke completion sources. + local sources = self:get_sources() + for _, s in ipairs(sources) do + local callback + callback = (function(s_) + return function() + local new = context.new(ctx) + if s_.incomplete and new:changed(s_.context) then + s_:complete(new, callback) + else + if not self.view:get_active_entry() then + self.filter.stop() + self.filter.timeout = DEBOUNCE_TIME + self:filter() + end + end + end + end)(s) + s:complete(ctx, callback) + end + + if not self.view:get_active_entry() then + self.filter.timeout = self.view:visible() and THROTTLE_TIME or 1 + self:filter() + end +end + +---Update completion menu +core.filter = async.throttle(function(self) + self.filter.timeout = THROTTLE_TIME + + -- Check invalid condition. + local ignore = false + ignore = ignore or not api.is_suitable_mode() + if ignore then + return + end + + -- Check fetching sources. + local sources = {} + for _, s in ipairs(self:get_sources({ source.SourceStatus.FETCHING, source.SourceStatus.COMPLETED })) do + -- Reserve filter call for timeout. + if not s.incomplete and SOURCE_TIMEOUT > s:get_fetching_time() then + self.filter.timeout = SOURCE_TIMEOUT - s:get_fetching_time() + self:filter() + if #sources == 0 then + return + end + end + table.insert(sources, s) + end + + local ctx = self:get_context() + + -- Display completion results. + self.view:open(ctx, sources) + + -- Check onetime config. + if #self:get_sources(function(s) + if s.status == source.SourceStatus.FETCHING then + return true + elseif #s:get_entries(ctx) > 0 then + return true + end + return false + end) == 0 then + config.set_onetime({}) + end +end, THROTTLE_TIME) + +---Confirm completion. +---@param e cmp.Entry +---@param option cmp.ConfirmOption +---@param callback function +core.confirm = function(self, e, option, callback) + if not (e and not e.confirmed) then + return callback() + end + e.confirmed = true + + debug.log('entry.confirm', e:get_completion_item()) + + local release = self:suspend() + + -- Close menus. + self.view:close() + + feedkeys.call(keymap.indentkeys(), 'n') + feedkeys.call('', 'n', function() + local ctx = context.new() + local keys = {} + table.insert(keys, keymap.backspace(ctx.cursor.character - misc.to_utfindex(ctx.cursor_line, e:get_offset()))) + table.insert(keys, e:get_word()) + table.insert(keys, keymap.undobreak()) + feedkeys.call(table.concat(keys, ''), 'in') + end) + feedkeys.call('', 'n', function() + local ctx = context.new() + if api.is_cmdline_mode() then + local keys = {} + table.insert(keys, keymap.backspace(ctx.cursor.character - misc.to_utfindex(ctx.cursor_line, e:get_offset()))) + table.insert(keys, string.sub(e.context.cursor_before_line, e:get_offset())) + feedkeys.call(table.concat(keys, ''), 'in') + else + vim.api.nvim_buf_set_text(0, ctx.cursor.row - 1, e:get_offset() - 1, ctx.cursor.row - 1, ctx.cursor.col - 1, { + string.sub(e.context.cursor_before_line, e:get_offset()), + }) + vim.api.nvim_win_set_cursor(0, { e.context.cursor.row, e.context.cursor.col - 1 }) + end + end) + feedkeys.call('', 'n', function() + local ctx = context.new() + if #(misc.safe(e:get_completion_item().additionalTextEdits) or {}) == 0 then + e:resolve(function() + local new = context.new() + local text_edits = misc.safe(e:get_completion_item().additionalTextEdits) or {} + if #text_edits == 0 then + return + end + + local has_cursor_line_text_edit = (function() + local minrow = math.min(ctx.cursor.row, new.cursor.row) + local maxrow = math.max(ctx.cursor.row, new.cursor.row) + for _, te in ipairs(text_edits) do + local srow = te.range.start.line + 1 + local erow = te.range['end'].line + 1 + if srow <= minrow and maxrow <= erow then + return true + end + end + return false + end)() + if has_cursor_line_text_edit then + return + end + vim.lsp.util.apply_text_edits(text_edits, ctx.bufnr, 'utf-16') + end) + else + vim.lsp.util.apply_text_edits(e:get_completion_item().additionalTextEdits, ctx.bufnr, 'utf-16') + end + end) + feedkeys.call('', 'n', function() + local ctx = context.new() + local completion_item = misc.copy(e:get_completion_item()) + if not misc.safe(completion_item.textEdit) then + completion_item.textEdit = {} + completion_item.textEdit.newText = misc.safe(completion_item.insertText) or completion_item.word or completion_item.label + end + local behavior = option.behavior or config.get().confirmation.default_behavior + if behavior == types.cmp.ConfirmBehavior.Replace then + completion_item.textEdit.range = e:get_replace_range() + else + completion_item.textEdit.range = e:get_insert_range() + end + + local diff_before = math.max(0, e.context.cursor.character - completion_item.textEdit.range.start.character) + local diff_after = math.max(0, completion_item.textEdit.range['end'].character - e.context.cursor.character) + local new_text = completion_item.textEdit.newText + + if api.is_insert_mode() then + local is_snippet = completion_item.insertTextFormat == types.lsp.InsertTextFormat.Snippet + completion_item.textEdit.range.start.line = ctx.cursor.line + completion_item.textEdit.range.start.character = ctx.cursor.character - diff_before + completion_item.textEdit.range['end'].line = ctx.cursor.line + completion_item.textEdit.range['end'].character = ctx.cursor.character + diff_after + if is_snippet then + completion_item.textEdit.newText = '' + end + vim.lsp.util.apply_text_edits({ completion_item.textEdit }, ctx.bufnr, 'utf-16') + local texts = vim.split(completion_item.textEdit.newText, '\n') + local position = completion_item.textEdit.range.start + position.line = position.line + (#texts - 1) + if #texts == 1 then + position.character = position.character + misc.to_utfindex(texts[1]) + else + position.character = misc.to_utfindex(texts[#texts]) + end + local pos = types.lsp.Position.to_vim(0, position) + vim.api.nvim_win_set_cursor(0, { pos.row, pos.col - 1 }) + if is_snippet then + config.get().snippet.expand({ + body = new_text, + insert_text_mode = completion_item.insertTextMode, + }) + end + else + local keys = {} + table.insert(keys, string.rep(keymap.t(''), diff_before)) + table.insert(keys, string.rep(keymap.t(''), diff_after)) + table.insert(keys, new_text) + feedkeys.call(table.concat(keys, ''), 'in') + end + end) + feedkeys.call(keymap.indentkeys(vim.bo.indentkeys), 'n') + feedkeys.call('', 'n', function() + e:execute(vim.schedule_wrap(function() + release() + self.event:emit('confirm_done', { + entry = e, + commit_character = option.commit_character, + }) + if callback then + callback() + end + end)) + end) +end + +---Reset current completion state +core.reset = function(self) + for _, s in pairs(self.sources) do + s:reset() + end + self.context = context.empty() +end + +return core diff --git a/start/cmp/lua/cmp/core_spec.lua b/start/cmp/lua/cmp/core_spec.lua new file mode 100644 index 0000000..c37090e --- /dev/null +++ b/start/cmp/lua/cmp/core_spec.lua @@ -0,0 +1,158 @@ +local spec = require('cmp.utils.spec') +local feedkeys = require('cmp.utils.feedkeys') +local types = require('cmp.types') +local core = require('cmp.core') +local source = require('cmp.source') +local keymap = require('cmp.utils.keymap') +local api = require('cmp.utils.api') + +describe('cmp.core', function() + describe('confirm', function() + local confirm = function(request, filter, completion_item) + local c = core.new() + local s = source.new('spec', { + complete = function(_, _, callback) + callback({ completion_item }) + end, + }) + c:register_source(s) + feedkeys.call(request, 'n', function() + c:complete(c:get_context({ reason = types.cmp.ContextReason.Manual })) + vim.wait(5000, function() + return #c.sources[s.id].entries > 0 + end) + end) + feedkeys.call(filter, 'n', function() + c:confirm(c.sources[s.id].entries[1], {}) + end) + local state = {} + feedkeys.call('', 'x', function() + feedkeys.call('', 'n', function() + if api.is_cmdline_mode() then + state.buffer = { api.get_current_line() } + else + state.buffer = vim.api.nvim_buf_get_lines(0, 0, -1, false) + end + state.cursor = api.get_cursor() + end) + end) + return state + end + + describe('insert-mode', function() + before_each(spec.before) + + it('label', function() + local state = confirm('iA', 'IU', { + label = 'AIUEO', + }) + assert.are.same(state.buffer, { 'AIUEO' }) + assert.are.same(state.cursor, { 1, 5 }) + end) + + it('insertText', function() + local state = confirm('iA', 'IU', { + label = 'AIUEO', + insertText = '_AIUEO_', + }) + assert.are.same(state.buffer, { '_AIUEO_' }) + assert.are.same(state.cursor, { 1, 7 }) + end) + + it('textEdit', function() + local state = confirm(keymap.t('i***AEO***'), 'IU', { + label = 'AIUEO', + textEdit = { + range = { + start = { + line = 0, + character = 3, + }, + ['end'] = { + line = 0, + character = 6, + }, + }, + newText = 'foo\nbar\nbaz', + }, + }) + assert.are.same(state.buffer, { '***foo', 'bar', 'baz***' }) + assert.are.same(state.cursor, { 3, 3 }) + end) + + it('insertText & snippet', function() + local state = confirm('iA', 'IU', { + label = 'AIUEO', + insertText = 'AIUEO($0)', + insertTextFormat = types.lsp.InsertTextFormat.Snippet, + }) + assert.are.same(state.buffer, { 'AIUEO()' }) + assert.are.same(state.cursor, { 1, 6 }) + end) + + it('textEdit & snippet', function() + local state = confirm(keymap.t('i***AEO***'), 'IU', { + label = 'AIUEO', + insertTextFormat = types.lsp.InsertTextFormat.Snippet, + textEdit = { + range = { + start = { + line = 0, + character = 3, + }, + ['end'] = { + line = 0, + character = 6, + }, + }, + newText = 'foo\nba$0r\nbaz', + }, + }) + assert.are.same(state.buffer, { '***foo', 'bar', 'baz***' }) + assert.are.same(state.cursor, { 2, 2 }) + end) + end) + + describe('cmdline-mode', function() + before_each(spec.before) + + it('label', function() + local state = confirm(':A', 'IU', { + label = 'AIUEO', + }) + assert.are.same(state.buffer, { 'AIUEO' }) + assert.are.same(state.cursor[2], 5) + end) + + it('insertText', function() + local state = confirm(':A', 'IU', { + label = 'AIUEO', + insertText = '_AIUEO_', + }) + assert.are.same(state.buffer, { '_AIUEO_' }) + assert.are.same(state.cursor[2], 7) + end) + + it('textEdit', function() + local state = confirm(keymap.t(':***AEO***'), 'IU', { + label = 'AIUEO', + textEdit = { + range = { + start = { + line = 0, + character = 3, + }, + ['end'] = { + line = 0, + character = 6, + }, + }, + newText = 'foobarbaz', + }, + }) + assert.are.same(state.buffer, { '***foobarbaz***' }) + assert.are.same(state.cursor[2], 12) + end) + end) + end) +end) diff --git a/start/cmp/lua/cmp/entry.lua b/start/cmp/lua/cmp/entry.lua new file mode 100644 index 0000000..83c53a2 --- /dev/null +++ b/start/cmp/lua/cmp/entry.lua @@ -0,0 +1,468 @@ +local cache = require('cmp.utils.cache') +local char = require('cmp.utils.char') +local misc = require('cmp.utils.misc') +local str = require('cmp.utils.str') +local config = require('cmp.config') +local types = require('cmp.types') +local matcher = require('cmp.matcher') + +---@class cmp.Entry +---@field public id number +---@field public cache cmp.Cache +---@field public match_cache cmp.Cache +---@field public score number +---@field public exact boolean +---@field public matches table +---@field public context cmp.Context +---@field public source cmp.Source +---@field public source_offset number +---@field public source_insert_range lsp.Range +---@field public source_replace_range lsp.Range +---@field public completion_item lsp.CompletionItem +---@field public resolved_completion_item lsp.CompletionItem|nil +---@field public resolved_callbacks fun()[] +---@field public resolving boolean +---@field public confirmed boolean +local entry = {} + +---Create new entry +---@param ctx cmp.Context +---@param source cmp.Source +---@param completion_item lsp.CompletionItem +---@return cmp.Entry +entry.new = function(ctx, source, completion_item) + local self = setmetatable({}, { __index = entry }) + self.id = misc.id('entry.new') + self.cache = cache.new() + self.match_cache = cache.new() + self.score = 0 + self.exact = false + self.matches = {} + self.context = ctx + self.source = source + self.source_offset = source.request_offset + self.source_insert_range = source:get_default_insert_range() + self.source_replace_range = source:get_default_replace_range() + self.completion_item = completion_item + self.resolved_completion_item = nil + self.resolved_callbacks = {} + self.resolving = false + self.confirmed = false + return self +end + +---Make offset value +---@return number +entry.get_offset = function(self) + return self.cache:ensure({ 'get_offset', self.resolved_completion_item and 1 or 0 }, function() + local offset = self.source_offset + if misc.safe(self:get_completion_item().textEdit) then + local range = misc.safe(self:get_completion_item().textEdit.insert) or misc.safe(self:get_completion_item().textEdit.range) + if range then + local c = misc.to_vimindex(self.context.cursor_line, range.start.character) + for idx = c, self.source_offset do + if not char.is_white(string.byte(self.context.cursor_line, idx)) then + offset = idx + break + end + end + end + else + -- NOTE + -- The VSCode does not implement this but it's useful if the server does not care about word patterns. + -- We should care about this performance. + local word = self:get_word() + for idx = self.source_offset - 1, self.source_offset - #word, -1 do + if char.is_semantic_index(self.context.cursor_line, idx) then + local c = string.byte(self.context.cursor_line, idx) + if char.is_white(c) then + break + end + local match = true + for i = 1, self.source_offset - idx do + local c1 = string.byte(word, i) + local c2 = string.byte(self.context.cursor_line, idx + i - 1) + if not c1 or not c2 or c1 ~= c2 then + match = false + break + end + end + if match then + offset = math.min(offset, idx) + end + end + end + end + return offset + end) +end + +---Create word for vim.CompletedItem +---NOTE: This method doesn't clear the cache after completionItem/resolve. +---@return string +entry.get_word = function(self) + return self.cache:ensure({ 'get_word' }, function() + --NOTE: This is nvim-cmp specific implementation. + if misc.safe(self:get_completion_item().word) then + return self:get_completion_item().word + end + + local word + if misc.safe(self:get_completion_item().textEdit) and not misc.empty(self:get_completion_item().textEdit.newText) then + word = str.trim(self:get_completion_item().textEdit.newText) + if self:get_completion_item().insertTextFormat == types.lsp.InsertTextFormat.Snippet then + word = vim.lsp.util.parse_snippet(word) + end + local overwrite = self:get_overwrite() + if 0 < overwrite[2] or self:get_completion_item().insertTextFormat == types.lsp.InsertTextFormat.Snippet then + word = str.get_word(word, string.byte(self.context.cursor_after_line, 1), overwrite[1] or 0) + end + elseif not misc.empty(self:get_completion_item().insertText) then + word = str.trim(self:get_completion_item().insertText) + if self:get_completion_item().insertTextFormat == types.lsp.InsertTextFormat.Snippet then + word = str.get_word(vim.lsp.util.parse_snippet(word)) + end + else + word = str.trim(self:get_completion_item().label) + end + return str.oneline(word) + end) +end + +---Get overwrite information +---@return number, number +entry.get_overwrite = function(self) + return self.cache:ensure({ 'get_overwrite', self.resolved_completion_item and 1 or 0 }, function() + if misc.safe(self:get_completion_item().textEdit) then + local r = misc.safe(self:get_completion_item().textEdit.insert) or misc.safe(self:get_completion_item().textEdit.range) + local s = misc.to_vimindex(self.context.cursor_line, r.start.character) + local e = misc.to_vimindex(self.context.cursor_line, r['end'].character) + local before = self.context.cursor.col - s + local after = e - self.context.cursor.col + return { before, after } + end + return { 0, 0 } + end) +end + +---Create filter text +---@return string +entry.get_filter_text = function(self) + return self.cache:ensure({ 'get_filter_text', self.resolved_completion_item and 1 or 0 }, function() + local word + if misc.safe(self:get_completion_item().filterText) then + word = self:get_completion_item().filterText + else + word = str.trim(self:get_completion_item().label) + end + return word + end) +end + +---Get LSP's insert text +---@return string +entry.get_insert_text = function(self) + return self.cache:ensure({ 'get_insert_text', self.resolved_completion_item and 1 or 0 }, function() + local word + if misc.safe(self:get_completion_item().textEdit) then + word = str.trim(self:get_completion_item().textEdit.newText) + if self:get_completion_item().insertTextFormat == types.lsp.InsertTextFormat.Snippet then + word = str.remove_suffix(str.remove_suffix(word, '$0'), '${0}') + end + elseif misc.safe(self:get_completion_item().insertText) then + word = str.trim(self:get_completion_item().insertText) + if self:get_completion_item().insertTextFormat == types.lsp.InsertTextFormat.Snippet then + word = str.remove_suffix(str.remove_suffix(word, '$0'), '${0}') + end + else + word = str.trim(self:get_completion_item().label) + end + return word + end) +end + +---Return the item is deprecated or not. +---@return boolean +entry.is_deprecated = function(self) + return self:get_completion_item().deprecated or vim.tbl_contains(self:get_completion_item().tags or {}, types.lsp.CompletionItemTag.Deprecated) +end + +---Return view information. +---@param suggest_offset number +---@param entries_buf number The buffer this entry will be rendered into. +---@return { abbr: { text: string, bytes: number, width: number, hl_group: string }, kind: { text: string, bytes: number, width: number, hl_group: string }, menu: { text: string, bytes: number, width: number, hl_group: string } } +entry.get_view = function(self, suggest_offset, entries_buf) + local item = self:get_vim_item(suggest_offset) + return self.cache:ensure({ 'get_view', self.resolved_completion_item and 1 or 0, entries_buf }, function() + local view = {} + -- The result of vim.fn.strdisplaywidth depends on which buffer it was + -- called in because it reads the values of the option 'tabstop' when + -- rendering characters. + vim.api.nvim_buf_call(entries_buf, function() + view.abbr = {} + view.abbr.text = item.abbr or '' + view.abbr.bytes = #view.abbr.text + view.abbr.width = vim.fn.strdisplaywidth(view.abbr.text) + view.abbr.hl_group = item.abbr_hl_group or (self:is_deprecated() and 'CmpItemAbbrDeprecated' or 'CmpItemAbbr') + view.kind = {} + view.kind.text = item.kind or '' + view.kind.bytes = #view.kind.text + view.kind.width = vim.fn.strdisplaywidth(view.kind.text) + view.kind.hl_group = item.kind_hl_group or ('CmpItemKind' .. (types.lsp.CompletionItemKind[self:get_kind()] or '')) + view.menu = {} + view.menu.text = item.menu or '' + view.menu.bytes = #view.menu.text + view.menu.width = vim.fn.strdisplaywidth(view.menu.text) + view.menu.hl_group = item.menu_hl_group or 'CmpItemMenu' + view.dup = item.dup + end) + return view + end) +end + +---Make vim.CompletedItem +---@param suggest_offset number +---@return vim.CompletedItem +entry.get_vim_item = function(self, suggest_offset) + return self.cache:ensure({ 'get_vim_item', suggest_offset, self.resolved_completion_item and 1 or 0 }, function() + local completion_item = self:get_completion_item() + local word = self:get_word() + local abbr = str.oneline(completion_item.label) + + -- ~ indicator + local is_snippet = false + if #(misc.safe(completion_item.additionalTextEdits) or {}) > 0 then + is_snippet = true + elseif completion_item.insertTextFormat == types.lsp.InsertTextFormat.Snippet then + is_snippet = self:get_insert_text() ~= word + elseif completion_item.kind == types.lsp.CompletionItemKind.Snippet then + is_snippet = true + end + if is_snippet then + abbr = abbr .. '~' + end + + -- append delta text + if suggest_offset < self:get_offset() then + word = string.sub(self.context.cursor_before_line, suggest_offset, self:get_offset() - 1) .. word + end + + -- labelDetails. + local menu = nil + if misc.safe(completion_item.labelDetails) then + menu = '' + if misc.safe(completion_item.labelDetails.detail) then + menu = menu .. completion_item.labelDetails.detail + end + if misc.safe(completion_item.labelDetails.description) then + menu = menu .. completion_item.labelDetails.description + end + end + + -- remove duplicated string. + if self:get_offset() ~= self.context.cursor.col then + for i = 1, #word - 1 do + if str.has_prefix(self.context.cursor_after_line, string.sub(word, i, #word)) then + word = string.sub(word, 1, i - 1) + break + end + end + end + + local vim_item = { + word = word, + abbr = abbr, + kind = types.lsp.CompletionItemKind[self:get_kind()] or types.lsp.CompletionItemKind[1], + menu = menu, + dup = self:get_completion_item().dup or 1, + } + if config.get().formatting.format then + vim_item = config.get().formatting.format(self, vim_item) + end + vim_item.word = str.oneline(vim_item.word or '') + vim_item.abbr = str.oneline(vim_item.abbr or '') + vim_item.kind = str.oneline(vim_item.kind or '') + vim_item.menu = str.oneline(vim_item.menu or '') + vim_item.equal = 1 + vim_item.empty = 1 + + return vim_item + end) +end + +---Get commit characters +---@return string[] +entry.get_commit_characters = function(self) + return misc.safe(self:get_completion_item().commitCharacters) or {} +end + +---Return insert range +---@return lsp.Range|nil +entry.get_insert_range = function(self) + local insert_range + if misc.safe(self:get_completion_item().textEdit) then + if misc.safe(self:get_completion_item().textEdit.insert) then + insert_range = self:get_completion_item().textEdit.insert + else + insert_range = self:get_completion_item().textEdit.range + end + else + insert_range = { + start = { + line = self.context.cursor.row - 1, + character = math.min(misc.to_utfindex(self.context.cursor_line, self:get_offset()), self.source_insert_range.start.character), + }, + ['end'] = self.source_insert_range['end'], + } + end + return insert_range +end + +---Return replace range +---@return lsp.Range|nil +entry.get_replace_range = function(self) + return self.cache:ensure({ 'get_replace_range', self.resolved_completion_item and 1 or 0 }, function() + local replace_range + if misc.safe(self:get_completion_item().textEdit) and misc.safe(self:get_completion_item().textEdit.replace) then + replace_range = self:get_completion_item().textEdit.replace + else + replace_range = { + start = { + line = self.source_replace_range.start.line, + character = math.min(misc.to_utfindex(self.context.cursor_line, self:get_offset()), self.source_replace_range.start.character), + }, + ['end'] = self.source_replace_range['end'], + } + end + return replace_range + end) +end + +---Match line. +---@param input string +---@param matching_config cmp.MatchingConfig +---@return { score: number, matches: table[] } +entry.match = function(self, input, matching_config) + return self.match_cache:ensure({ + input, + self.resolved_completion_item and 1 or 0, + matching_config.disallow_fuzzy_matching and 1 or 0, + matching_config.disallow_partial_matching and 1 or 0, + matching_config.disallow_prefix_unmatching and 1 or 0, + }, function() + local option = { + disallow_fuzzy_matching = matching_config.disallow_fuzzy_matching, + disallow_partial_matching = matching_config.disallow_partial_matching, + disallow_prefix_unmatching = matching_config.disallow_prefix_unmatching, + synonyms = { + self:get_word(), + self:get_completion_item().label, + }, + } + + local score, matches, _ + score, matches = matcher.match(input, self:get_filter_text(), option) + + -- Support the language server that doesn't respect VSCode's behaviors. + if score == 0 then + if misc.safe(self:get_completion_item().textEdit) and not misc.empty(self:get_completion_item().textEdit.newText) then + local diff = self.source_offset - self:get_offset() + if diff > 0 then + local prefix = string.sub(self.context.cursor_line, self:get_offset(), self:get_offset() + diff) + local accept = false + accept = accept or string.match(prefix, '^[^%a]+$') + accept = accept or string.find(self:get_completion_item().textEdit.newText, prefix, 1, true) + if accept then + score, matches = matcher.match(input, prefix .. self:get_filter_text(), option) + end + end + end + end + + if self:get_filter_text() ~= self:get_completion_item().label then + _, matches = matcher.match(input, self:get_completion_item().label, { self:get_word() }) + end + + return { score = score, matches = matches } + end) +end + +---Get resolved completion item if possible. +---@return lsp.CompletionItem +entry.get_completion_item = function(self) + return self.cache:ensure({ 'get_completion_item', self.resolved_completion_item and 1 or 0 }, function() + if self.resolved_completion_item then + local completion_item = misc.copy(self.completion_item) + for k, v in pairs(self.resolved_completion_item) do + completion_item[k] = v or completion_item[k] + end + return completion_item + end + return self.completion_item + end) +end + +---Create documentation +---@return string +entry.get_documentation = function(self) + local item = self:get_completion_item() + + local documents = {} + + -- detail + if misc.safe(item.detail) and item.detail ~= '' then + local ft = self.context.filetype + local dot_index = string.find(ft, '%.') + if dot_index ~= nil then + ft = string.sub(ft, 0, dot_index - 1) + end + table.insert(documents, { + kind = types.lsp.MarkupKind.Markdown, + value = ('```%s\n%s\n```'):format(ft, str.trim(item.detail)), + }) + end + + if type(item.documentation) == 'string' and item.documentation ~= '' then + table.insert(documents, { + kind = types.lsp.MarkupKind.PlainText, + value = str.trim(item.documentation), + }) + elseif type(item.documentation) == 'table' and item.documentation.value ~= '' then + table.insert(documents, item.documentation) + end + + return vim.lsp.util.convert_input_to_markdown_lines(documents) +end + +---Get completion item kind +---@return lsp.CompletionItemKind +entry.get_kind = function(self) + return misc.safe(self:get_completion_item().kind) or types.lsp.CompletionItemKind.Text +end + +---Execute completion item's command. +---@param callback fun() +entry.execute = function(self, callback) + self.source:execute(self:get_completion_item(), callback) +end + +---Resolve completion item. +---@param callback fun() +entry.resolve = function(self, callback) + if self.resolved_completion_item then + return callback() + end + table.insert(self.resolved_callbacks, callback) + + if not self.resolving then + self.resolving = true + self.source:resolve(self.completion_item, function(completion_item) + self.resolved_completion_item = misc.safe(completion_item) or self.completion_item + for _, c in ipairs(self.resolved_callbacks) do + c() + end + end) + end +end + +return entry diff --git a/start/cmp/lua/cmp/entry_spec.lua b/start/cmp/lua/cmp/entry_spec.lua new file mode 100644 index 0000000..d01125c --- /dev/null +++ b/start/cmp/lua/cmp/entry_spec.lua @@ -0,0 +1,342 @@ +local spec = require('cmp.utils.spec') +local source = require('cmp.source') +local async = require('cmp.utils.async') + +local entry = require('cmp.entry') + +describe('entry', function() + before_each(spec.before) + + it('one char', function() + local state = spec.state('@.', 1, 3) + state.input('@') + local e = entry.new(state.manual(), state.source(), { + label = '@', + }) + assert.are.equal(e:get_offset(), 3) + assert.are.equal(e:get_vim_item(e:get_offset()).word, '@') + end) + + it('word length (no fix)', function() + local state = spec.state('a.b', 1, 4) + state.input('.') + local e = entry.new(state.manual(), state.source(), { + label = 'b', + }) + assert.are.equal(e:get_offset(), 5) + assert.are.equal(e:get_vim_item(e:get_offset()).word, 'b') + end) + + it('word length (fix)', function() + local state = spec.state('a.b', 1, 4) + state.input('.') + local e = entry.new(state.manual(), state.source(), { + label = 'b.', + }) + assert.are.equal(e:get_offset(), 3) + assert.are.equal(e:get_vim_item(e:get_offset()).word, 'b.') + end) + + it('semantic index (no fix)', function() + local state = spec.state('a.bc', 1, 5) + state.input('.') + local e = entry.new(state.manual(), state.source(), { + label = 'c.', + }) + assert.are.equal(e:get_offset(), 6) + assert.are.equal(e:get_vim_item(e:get_offset()).word, 'c.') + end) + + it('semantic index (fix)', function() + local state = spec.state('a.bc', 1, 5) + state.input('.') + local e = entry.new(state.manual(), state.source(), { + label = 'bc.', + }) + assert.are.equal(e:get_offset(), 3) + assert.are.equal(e:get_vim_item(e:get_offset()).word, 'bc.') + end) + + it('[vscode-html-language-server] 1', function() + local state = spec.state(' ', 1, 7) + state.input('.') + local e = entry.new(state.manual(), state.source(), { + label = '/div', + textEdit = { + range = { + start = { + line = 0, + character = 0, + }, + ['end'] = { + line = 0, + character = 6, + }, + }, + newText = ' foo') + assert.are.equal(e:get_filter_text(), 'foo') + end) + + it('[typescript-language-server] 1', function() + local state = spec.state('Promise.resolve()', 1, 18) + state.input('.') + local e = entry.new(state.manual(), state.source(), { + label = 'catch', + }) + -- The offset will be 18 in this situation because the server returns `[Symbol]` as candidate. + assert.are.equal(e:get_vim_item(18).word, '.catch') + assert.are.equal(e:get_filter_text(), 'catch') + end) + + it('[typescript-language-server] 2', function() + local state = spec.state('Promise.resolve()', 1, 18) + state.input('.') + local e = entry.new(state.manual(), state.source(), { + filterText = '.Symbol', + label = 'Symbol', + textEdit = { + newText = '[Symbol]', + range = { + ['end'] = { + character = 18, + line = 0, + }, + start = { + character = 17, + line = 0, + }, + }, + }, + }) + assert.are.equal(e:get_vim_item(18).word, '[Symbol]') + assert.are.equal(e:get_filter_text(), '.Symbol') + end) + + it('[lua-language-server] 1', function() + local state = spec.state("local m = require'cmp.confi", 1, 28) + local e + + -- press g + state.input('g') + e = entry.new(state.manual(), state.source(), { + insertTextFormat = 2, + label = 'cmp.config', + textEdit = { + newText = 'cmp.config', + range = { + ['end'] = { + character = 27, + line = 1, + }, + start = { + character = 18, + line = 1, + }, + }, + }, + }) + assert.are.equal(e:get_vim_item(19).word, 'cmp.config') + assert.are.equal(e:get_filter_text(), 'cmp.config') + + -- press ' + state.input("'") + e = entry.new(state.manual(), state.source(), { + insertTextFormat = 2, + label = 'cmp.config', + textEdit = { + newText = 'cmp.config', + range = { + ['end'] = { + character = 27, + line = 1, + }, + start = { + character = 18, + line = 1, + }, + }, + }, + }) + assert.are.equal(e:get_vim_item(19).word, 'cmp.config') + assert.are.equal(e:get_filter_text(), 'cmp.config') + end) + + it('[lua-language-server] 2', function() + local state = spec.state("local m = require'cmp.confi", 1, 28) + local e + + -- press g + state.input('g') + e = entry.new(state.manual(), state.source(), { + insertTextFormat = 2, + label = 'lua.cmp.config', + textEdit = { + newText = 'lua.cmp.config', + range = { + ['end'] = { + character = 27, + line = 1, + }, + start = { + character = 18, + line = 1, + }, + }, + }, + }) + assert.are.equal(e:get_vim_item(19).word, 'lua.cmp.config') + assert.are.equal(e:get_filter_text(), 'lua.cmp.config') + + -- press ' + state.input("'") + e = entry.new(state.manual(), state.source(), { + insertTextFormat = 2, + label = 'lua.cmp.config', + textEdit = { + newText = 'lua.cmp.config', + range = { + ['end'] = { + character = 27, + line = 1, + }, + start = { + character = 18, + line = 1, + }, + }, + }, + }) + assert.are.equal(e:get_vim_item(19).word, 'lua.cmp.config') + assert.are.equal(e:get_filter_text(), 'lua.cmp.config') + end) + + it('[intelephense] 1', function() + local state = spec.state('\t\t', 1, 4) + + -- press g + state.input('$') + local e = entry.new(state.manual(), state.source(), { + kind = 6, + label = '$this', + sortText = '$this', + textEdit = { + newText = '$this', + range = { + ['end'] = { + character = 3, + line = 1, + }, + start = { + character = 2, + line = 1, + }, + }, + }, + }) + assert.are.equal(e:get_vim_item(e:get_offset()).word, '$this') + assert.are.equal(e:get_filter_text(), '$this') + end) + + it('[odin-language-server] 1', function() + local state = spec.state('\t\t', 1, 4) + + -- press g + state.input('s') + local e = entry.new(state.manual(), state.source(), { + additionalTextEdits = {}, + command = { + arguments = {}, + command = '', + title = '', + }, + deprecated = false, + detail = 'string', + documentation = '', + insertText = '', + insertTextFormat = 1, + kind = 14, + label = 'string', + tags = {}, + }) + assert.are.equal(e:get_vim_item(e:get_offset()).word, 'string') + end) + + it('[ansiblels] 1', function() + local item = { + detail = 'ansible.builtin', + filterText = 'blockinfile ansible.builtin.blockinfile', + kind = 7, + label = 'blockinfile', + sortText = '2_blockinfile', + textEdit = { + newText = '', + range = { + ['end'] = { + character = 7, + line = 15, + }, + start = { + character = 6, + line = 15, + }, + }, + }, + } + local s = source.new('dummy', { + resolve = function(_, _, callback) + item.textEdit.newText = 'modified' + callback(item) + end, + }) + local e = entry.new(spec.state('', 1, 1).manual(), s, item) + assert.are.equal(e:get_vim_item(e:get_offset()).word, 'blockinfile') + async.sync(function(done) + e:resolve(done) + end, 100) + assert.are.equal(e:get_vim_item(e:get_offset()).word, 'blockinfile') + end) + + it('[#47] word should not contain \\n character', function() + local state = spec.state('', 1, 1) + + -- press g + state.input('_') + local e = entry.new(state.manual(), state.source(), { + kind = 6, + label = '__init__', + insertTextFormat = 1, + insertText = '__init__(self) -> None:\n pass', + }) + assert.are.equal(e:get_vim_item(e:get_offset()).word, '__init__(self) -> None:') + assert.are.equal(e:get_filter_text(), '__init__') + end) +end) diff --git a/start/cmp/lua/cmp/init.lua b/start/cmp/lua/cmp/init.lua new file mode 100644 index 0000000..06f5f41 --- /dev/null +++ b/start/cmp/lua/cmp/init.lua @@ -0,0 +1,336 @@ +local core = require('cmp.core') +local source = require('cmp.source') +local config = require('cmp.config') +local feedkeys = require('cmp.utils.feedkeys') +local autocmd = require('cmp.utils.autocmd') +local keymap = require('cmp.utils.keymap') +local misc = require('cmp.utils.misc') +local async = require('cmp.utils.async') + +local cmp = {} + +cmp.core = core.new() + +---Expose types +for k, v in pairs(require('cmp.types.cmp')) do + cmp[k] = v +end +cmp.lsp = require('cmp.types.lsp') +cmp.vim = require('cmp.types.vim') + +---Expose event +cmp.event = cmp.core.event + +---Export mapping for special case +cmp.mapping = require('cmp.config.mapping') + +---Export default config presets +cmp.config = {} +cmp.config.disable = misc.none +cmp.config.compare = require('cmp.config.compare') +cmp.config.sources = require('cmp.config.sources') +cmp.config.mapping = require('cmp.config.mapping') +cmp.config.window = require('cmp.config.window') + +---Sync asynchronous process. +cmp.sync = function(callback) + return function(...) + cmp.core.filter:sync(1000) + if callback then + return callback(...) + end + end +end + +---Suspend completion. +cmp.suspend = function() + return cmp.core:suspend() +end + +---Register completion sources +---@param name string +---@param s cmp.Source +---@return number +cmp.register_source = function(name, s) + local src = source.new(name, s) + cmp.core:register_source(src) + return src.id +end + +---Unregister completion source +---@param id number +cmp.unregister_source = function(id) + cmp.core:unregister_source(id) +end + +---Get current configuration. +---@return cmp.ConfigSchema +cmp.get_config = function() + return require('cmp.config').get() +end + +---Invoke completion manually +---@param option cmp.CompleteParams +cmp.complete = cmp.sync(function(option) + option = option or {} + config.set_onetime(option.config) + cmp.core:complete(cmp.core:get_context({ reason = option.reason or cmp.ContextReason.Manual })) + return true +end) + +---Complete common string in current entries. +cmp.complete_common_string = cmp.sync(function() + return cmp.core:complete_common_string() +end) + +---Return view is visible or not. +cmp.visible = cmp.sync(function() + return cmp.core.view:visible() or vim.fn.pumvisible() == 1 +end) + +---Get current selected entry or nil +cmp.get_selected_entry = cmp.sync(function() + return cmp.core.view:get_selected_entry() +end) + +---Get current active entry or nil +cmp.get_active_entry = cmp.sync(function() + return cmp.core.view:get_active_entry() +end) + +---Get current all entries +cmp.get_entries = cmp.sync(function() + return cmp.core.view:get_entries() +end) + +---Close current completion +cmp.close = cmp.sync(function() + if cmp.core.view:visible() then + local release = cmp.core:suspend() + cmp.core.view:close() + cmp.core:reset() + vim.schedule(release) + return true + else + return false + end +end) + +---Abort current completion +cmp.abort = cmp.sync(function() + if cmp.core.view:visible() then + local release = cmp.core:suspend() + cmp.core.view:abort() + vim.schedule(release) + return true + else + return false + end +end) + +---Select next item if possible +cmp.select_next_item = cmp.sync(function(option) + option = option or {} + + if cmp.core.view:visible() then + local release = cmp.core:suspend() + cmp.core.view:select_next_item(option) + vim.schedule(release) + return true + elseif vim.fn.pumvisible() == 1 then + -- Special handling for native pum. Required to facilitate key mapping processing. + if (option.behavior or cmp.SelectBehavior.Insert) == cmp.SelectBehavior.Insert then + feedkeys.call(keymap.t(''), 'in') + else + feedkeys.call(keymap.t(''), 'in') + end + return true + end + return false +end) + +---Select prev item if possible +cmp.select_prev_item = cmp.sync(function(option) + option = option or {} + + if cmp.core.view:visible() then + local release = cmp.core:suspend() + cmp.core.view:select_prev_item(option) + vim.schedule(release) + return true + elseif vim.fn.pumvisible() == 1 then + -- Special handling for native pum. Required to facilitate key mapping processing. + if (option.behavior or cmp.SelectBehavior.Insert) == cmp.SelectBehavior.Insert then + feedkeys.call(keymap.t(''), 'in') + else + feedkeys.call(keymap.t(''), 'in') + end + return true + end + return false +end) + +---Scrolling documentation window if possible +cmp.scroll_docs = cmp.sync(function(delta) + if cmp.core.view:visible() then + cmp.core.view:scroll_docs(delta) + return true + else + return false + end +end) + +---Confirm completion +cmp.confirm = cmp.sync(function(option, callback) + option = option or {} + callback = callback or function() end + + local e = cmp.core.view:get_selected_entry() or (option.select and cmp.core.view:get_first_entry() or nil) + if e then + cmp.core:confirm(e, { + behavior = option.behavior, + }, function() + callback() + cmp.core:complete(cmp.core:get_context({ reason = cmp.ContextReason.TriggerOnly })) + end) + return true + else + -- Special handling for native puma. Required to facilitate key mapping processing. + if vim.fn.complete_info({ 'selected' }).selected ~= -1 then + feedkeys.call(keymap.t(''), 'in') + return true + end + return false + end +end) + +---Show status +cmp.status = function() + local kinds = {} + kinds.available = {} + kinds.unavailable = {} + kinds.installed = {} + kinds.invalid = {} + local names = {} + for _, s in pairs(cmp.core.sources) do + names[s.name] = true + + if config.get_source_config(s.name) then + if s:is_available() then + table.insert(kinds.available, s:get_debug_name()) + else + table.insert(kinds.unavailable, s:get_debug_name()) + end + else + table.insert(kinds.installed, s:get_debug_name()) + end + end + for _, s in ipairs(config.get().sources) do + if not names[s.name] then + table.insert(kinds.invalid, s.name) + end + end + + if #kinds.available > 0 then + vim.api.nvim_echo({ { '\n', 'Normal' } }, false, {}) + vim.api.nvim_echo({ { '# ready source names\n', 'Special' } }, false, {}) + for _, name in ipairs(kinds.available) do + vim.api.nvim_echo({ { ('- %s\n'):format(name), 'Normal' } }, false, {}) + end + end + + if #kinds.unavailable > 0 then + vim.api.nvim_echo({ { '\n', 'Normal' } }, false, {}) + vim.api.nvim_echo({ { '# unavailable source names\n', 'Comment' } }, false, {}) + for _, name in ipairs(kinds.unavailable) do + vim.api.nvim_echo({ { ('- %s\n'):format(name), 'Normal' } }, false, {}) + end + end + + if #kinds.installed > 0 then + vim.api.nvim_echo({ { '\n', 'Normal' } }, false, {}) + vim.api.nvim_echo({ { '# unused source names\n', 'WarningMsg' } }, false, {}) + for _, name in ipairs(kinds.installed) do + vim.api.nvim_echo({ { ('- %s\n'):format(name), 'Normal' } }, false, {}) + end + end + + if #kinds.invalid > 0 then + vim.api.nvim_echo({ { '\n', 'Normal' } }, false, {}) + vim.api.nvim_echo({ { '# unknown source names\n', 'ErrorMsg' } }, false, {}) + for _, name in ipairs(kinds.invalid) do + vim.api.nvim_echo({ { ('- %s\n'):format(name), 'Normal' } }, false, {}) + end + end +end + +---@type cmp.Setup +cmp.setup = setmetatable({ + global = function(c) + config.set_global(c) + end, + filetype = function(filetype, c) + config.set_filetype(c, filetype) + end, + buffer = function(c) + config.set_buffer(c, vim.api.nvim_get_current_buf()) + end, + cmdline = function(type, c) + config.set_cmdline(c, type) + end, +}, { + __call = function(self, c) + self.global(c) + end, +}) + +-- In InsertEnter autocmd, vim will detects mode=normal unexpectedly. +local on_insert_enter = function() + if config.enabled() then + cmp.config.compare.scopes:update() + cmp.config.compare.locality:update() + cmp.core:prepare() + cmp.core:on_change('InsertEnter') + end +end +autocmd.subscribe({ 'InsertEnter', 'CmdlineEnter' }, async.debounce_next_tick(on_insert_enter)) + +-- async.throttle is needed for performance. The mapping `:...` will fire `CmdlineChanged` for each character. +local on_text_changed = function() + if config.enabled() then + cmp.core:on_change('TextChanged') + end +end +autocmd.subscribe({ 'TextChangedI', 'TextChangedP' }, on_text_changed) +autocmd.subscribe('CmdlineChanged', async.debounce_next_tick(on_text_changed)) + +autocmd.subscribe('CursorMovedI', function() + if config.enabled() then + cmp.core:on_moved() + else + cmp.core:reset() + cmp.core.view:close() + end +end) + +-- If make this asynchronous, the completion menu will not close when the command output is displayed. +autocmd.subscribe({ 'InsertLeave', 'CmdlineLeave' }, function() + cmp.core:reset() + cmp.core.view:close() +end) + +cmp.event:on('complete_done', function(evt) + if evt.entry then + cmp.config.compare.recently_used:add_entry(evt.entry) + end + cmp.config.compare.scopes:update() + cmp.config.compare.locality:update() +end) + +cmp.event:on('confirm_done', function(evt) + if evt.entry then + cmp.config.compare.recently_used:add_entry(evt.entry) + end +end) + +return cmp diff --git a/start/cmp/lua/cmp/matcher.lua b/start/cmp/lua/cmp/matcher.lua new file mode 100644 index 0000000..7a22d9e --- /dev/null +++ b/start/cmp/lua/cmp/matcher.lua @@ -0,0 +1,324 @@ +local char = require('cmp.utils.char') + +local matcher = {} + +matcher.WORD_BOUNDALY_ORDER_FACTOR = 10 + +matcher.PREFIX_FACTOR = 8 +matcher.NOT_FUZZY_FACTOR = 6 + +---@type function +matcher.debug = function(...) + return ... +end + +--- score +-- +-- ### The score +-- +-- The `score` is `matched char count` generally. +-- +-- But cmp will fix the score with some of the below points so the actual score is not `matched char count`. +-- +-- 1. Word boundary order +-- +-- cmp prefers the match that near by word-beggining. +-- +-- 2. Strict case +-- +-- cmp prefers strict match than ignorecase match. +-- +-- +-- ### Matching specs. +-- +-- 1. Prefix matching per word boundary +-- +-- `bora` -> `border-radius` # imaginary score: 4 +-- ^^~~ ^^ ~~ +-- +-- 2. Try sequential match first +-- +-- `woroff` -> `word_offset` # imaginary score: 6 +-- ^^^~~~ ^^^ ~~~ +-- +-- * The `woroff`'s second `o` should not match `word_offset`'s first `o` +-- +-- 3. Prefer early word boundary +-- +-- `call` -> `call` # imaginary score: 4.1 +-- ^^^^ ^^^^ +-- `call` -> `condition_all` # imaginary score: 4 +-- ^~~~ ^ ~~~ +-- +-- 4. Prefer strict match +-- +-- `Buffer` -> `Buffer` # imaginary score: 6.1 +-- ^^^^^^ ^^^^^^ +-- `buffer` -> `Buffer` # imaginary score: 6 +-- ^^^^^^ ^^^^^^ +-- +-- 5. Use remaining characters for substring match +-- +-- `fmodify` -> `fnamemodify` # imaginary score: 1 +-- ^~~~~~~ ^ ~~~~~~ +-- +-- 6. Avoid unexpected match detection +-- +-- `candlesingle` -> candle#accept#single +-- ^^^^^^~~~~~~ ^^^^^^ ~~~~~~ +-- * The `accept`'s `a` should not match to `candle`'s `a` +-- +-- 7. Avoid false positive matching +-- +-- `,` -> print, +-- ~ +-- * Typically, the middle match with symbol characters only is false positive. should be ignored. +-- +-- +---Match entry +---@param input string +---@param word string +---@param option { synonyms: string[], disallow_fuzzy_matching: boolean, disallow_partial_matching: boolean, disallow_prefix_unmatching: boolean } +---@return number +matcher.match = function(input, word, option) + option = option or {} + + -- Empty input + if #input == 0 then + return matcher.PREFIX_FACTOR + matcher.NOT_FUZZY_FACTOR, {} + end + + -- Ignore if input is long than word + if #input > #word then + return 0, {} + end + + -- Check prefix matching. + if option.disallow_prefix_unmatching then + if not char.match(string.byte(input, 1), string.byte(word, 1)) then + return 0, {} + end + end + + -- Gather matched regions + local matches = {} + local input_start_index = 1 + local input_end_index = 1 + local word_index = 1 + local word_bound_index = 1 + local no_symbol_match = false + while input_end_index <= #input and word_index <= #word do + local m = matcher.find_match_region(input, input_start_index, input_end_index, word, word_index) + if m and input_end_index <= m.input_match_end then + m.index = word_bound_index + input_start_index = m.input_match_start + 1 + input_end_index = m.input_match_end + 1 + no_symbol_match = no_symbol_match or m.no_symbol_match + word_index = char.get_next_semantic_index(word, m.word_match_end) + table.insert(matches, m) + else + word_index = char.get_next_semantic_index(word, word_index) + end + word_bound_index = word_bound_index + 1 + end + + -- Check partial matching. + if option.disallow_partial_matching and #matches > 1 then + return 0, {} + end + + if #matches == 0 then + return 0, {} + end + + matcher.debug(word, matches) + + -- Add prefix bonus + local prefix = false + if matches[1].input_match_start == 1 and matches[1].word_match_start == 1 then + prefix = true + else + for _, synonym in ipairs(option.synonyms or {}) do + prefix = true + local o = 1 + for i = matches[1].input_match_start, matches[1].input_match_end do + if not char.match(string.byte(synonym, o), string.byte(input, i)) then + prefix = false + break + end + o = o + 1 + end + if prefix then + break + end + end + end + + if no_symbol_match and not prefix then + return 0, {} + end + + -- Compute prefix match score + local score = prefix and matcher.PREFIX_FACTOR or 0 + local offset = prefix and matches[1].index - 1 or 0 + local idx = 1 + for _, m in ipairs(matches) do + local s = 0 + for i = math.max(idx, m.input_match_start), m.input_match_end do + s = s + 1 + idx = i + end + idx = idx + 1 + if s > 0 then + s = s * (1 + m.strict_ratio) + s = s * (1 + math.max(0, matcher.WORD_BOUNDALY_ORDER_FACTOR - (m.index - offset)) / matcher.WORD_BOUNDALY_ORDER_FACTOR) + score = score + s + end + end + + -- Check remaining input as fuzzy + if matches[#matches].input_match_end < #input then + if not option.disallow_fuzzy_matching then + if prefix and matcher.fuzzy(input, word, matches) then + return score, matches + end + end + return 0, {} + end + + return score + matcher.NOT_FUZZY_FACTOR, matches +end + +--- fuzzy +matcher.fuzzy = function(input, word, matches) + local last_match = matches[#matches] + + -- Lately specified middle of text. + local input_index = last_match.input_match_end + 1 + for i = 1, #matches - 1 do + local curr_match = matches[i] + local next_match = matches[i + 1] + local word_offset = 0 + local word_index = char.get_next_semantic_index(word, curr_match.word_match_end) + while word_offset + word_index < next_match.word_match_start and input_index <= #input do + if char.match(string.byte(word, word_index + word_offset), string.byte(input, input_index)) then + input_index = input_index + 1 + word_offset = word_offset + 1 + else + word_index = char.get_next_semantic_index(word, word_index + word_offset) + word_offset = 0 + end + end + end + + -- Remaining text fuzzy match. + local last_input_index = input_index + local matched = false + local word_offset = 0 + local word_index = last_match.word_match_end + 1 + local input_match_start = -1 + local input_match_end = -1 + local word_match_start = -1 + local strict_count = 0 + local match_count = 0 + while word_offset + word_index <= #word and input_index <= #input do + local c1, c2 = string.byte(word, word_index + word_offset), string.byte(input, input_index) + if char.match(c1, c2) then + if not matched then + input_match_start = input_index + word_match_start = word_index + word_offset + end + matched = true + input_index = input_index + 1 + strict_count = strict_count + (c1 == c2 and 1 or 0) + match_count = match_count + 1 + elseif matched then + input_index = last_input_index + input_match_end = input_index - 1 + end + word_offset = word_offset + 1 + end + if input_index > #input then + table.insert(matches, { + input_match_start = input_match_start, + input_match_end = input_match_end, + word_match_start = word_match_start, + word_match_end = word_index + word_offset - 1, + strict_ratio = strict_count / match_count, + fuzzy = true, + }) + return true + end + return false +end + +--- find_match_region +matcher.find_match_region = function(input, input_start_index, input_end_index, word, word_index) + -- determine input position ( woroff -> word_offset ) + while input_start_index < input_end_index do + if char.match(string.byte(input, input_end_index), string.byte(word, word_index)) then + break + end + input_end_index = input_end_index - 1 + end + + -- Can't determine input position + if input_end_index < input_start_index then + return nil + end + + local input_match_start = -1 + local input_index = input_end_index + local word_offset = 0 + local strict_count = 0 + local match_count = 0 + local no_symbol_match = false + while input_index <= #input and word_index + word_offset <= #word do + local c1 = string.byte(input, input_index) + local c2 = string.byte(word, word_index + word_offset) + if char.match(c1, c2) then + -- Match start. + if input_match_start == -1 then + input_match_start = input_index + end + + strict_count = strict_count + (c1 == c2 and 1 or 0) + match_count = match_count + 1 + word_offset = word_offset + 1 + no_symbol_match = no_symbol_match or char.is_symbol(c1) + else + -- Match end (partial region) + if input_match_start ~= -1 then + return { + input_match_start = input_match_start, + input_match_end = input_index - 1, + word_match_start = word_index, + word_match_end = word_index + word_offset - 1, + strict_ratio = strict_count / match_count, + no_symbol_match = no_symbol_match, + fuzzy = false, + } + else + return nil + end + end + input_index = input_index + 1 + end + + -- Match end (whole region) + if input_match_start ~= -1 then + return { + input_match_start = input_match_start, + input_match_end = input_index - 1, + word_match_start = word_index, + word_match_end = word_index + word_offset - 1, + strict_ratio = strict_count / match_count, + no_symbol_match = no_symbol_match, + fuzzy = false, + } + end + + return nil +end + +return matcher diff --git a/start/cmp/lua/cmp/matcher_spec.lua b/start/cmp/lua/cmp/matcher_spec.lua new file mode 100644 index 0000000..c95dfc3 --- /dev/null +++ b/start/cmp/lua/cmp/matcher_spec.lua @@ -0,0 +1,64 @@ +local spec = require('cmp.utils.spec') + +local matcher = require('cmp.matcher') + +describe('matcher', function() + before_each(spec.before) + + it('match', function() + assert.is.truthy(matcher.match('', 'a') >= 1) + assert.is.truthy(matcher.match('a', 'a') >= 1) + assert.is.truthy(matcher.match('ab', 'a') == 0) + assert.is.truthy(matcher.match('ab', 'ab') > matcher.match('ab', 'a_b')) + assert.is.truthy(matcher.match('ab', 'a_b_c') > matcher.match('ac', 'a_b_c')) + + assert.is.truthy(matcher.match('bora', 'border-radius') >= 1) + assert.is.truthy(matcher.match('woroff', 'word_offset') >= 1) + assert.is.truthy(matcher.match('call', 'call') > matcher.match('call', 'condition_all')) + assert.is.truthy(matcher.match('Buffer', 'Buffer') > matcher.match('Buffer', 'buffer')) + assert.is.truthy(matcher.match('luacon', 'lua_context') > matcher.match('luacon', 'LuaContext')) + assert.is.truthy(matcher.match('fmodify', 'fnamemodify') >= 1) + assert.is.truthy(matcher.match('candlesingle', 'candle#accept#single') >= 1) + + assert.is.truthy(matcher.match('vi', 'void#') >= 1) + assert.is.truthy(matcher.match('vo', 'void#') >= 1) + assert.is.truthy(matcher.match('var_', 'var_dump') >= 1) + assert.is.truthy(matcher.match('conso', 'console') > matcher.match('conso', 'ConstantSourceNode')) + assert.is.truthy(matcher.match('usela', 'useLayoutEffect') > matcher.match('usela', 'useDataLayer')) + assert.is.truthy(matcher.match('my_', 'my_awesome_variable') > matcher.match('my_', 'completion_matching_strategy_list')) + assert.is.truthy(matcher.match('2', '[[2021') >= 1) + + assert.is.truthy(matcher.match(',', 'pri,') == 0) + assert.is.truthy(matcher.match('/', '/**') >= 1) + + assert.is.truthy(matcher.match('true', 'v:true', { synonyms = { 'true' } }) == matcher.match('true', 'true')) + assert.is.truthy(matcher.match('g', 'get', { synonyms = { 'get' } }) > matcher.match('g', 'dein#get', { 'dein#get' })) + end) + + it('disallow_fuzzy_matching', function() + assert.is.truthy(matcher.match('fmodify', 'fnamemodify', { disallow_fuzzy_matching = true }) == 0) + assert.is.truthy(matcher.match('fmodify', 'fnamemodify', { disallow_fuzzy_matching = false }) >= 1) + end) + + it('disallow_partial_matching', function() + assert.is.truthy(matcher.match('fb', 'foo_bar', { disallow_partial_matching = true }) == 0) + assert.is.truthy(matcher.match('fb', 'foo_bar', { disallow_partial_matching = false }) >= 1) + assert.is.truthy(matcher.match('fb', 'fboo_bar', { disallow_partial_matching = true }) >= 1) + assert.is.truthy(matcher.match('fb', 'fboo_bar', { disallow_partial_matching = false }) >= 1) + end) + + it('disallow_prefix_unmatching', function() + assert.is.truthy(matcher.match('bar', 'foo_bar', { disallow_prefix_unmatching = true }) == 0) + assert.is.truthy(matcher.match('bar', 'foo_bar', { disallow_prefix_unmatching = false }) >= 1) + end) + + it('debug', function() + matcher.debug = function(...) + print(vim.inspect({ ... })) + end + -- print(vim.inspect({ + -- a = matcher.match('true', 'v:true', { 'true' }), + -- b = matcher.match('true', 'true'), + -- })) + end) +end) diff --git a/start/cmp/lua/cmp/source.lua b/start/cmp/lua/cmp/source.lua new file mode 100644 index 0000000..bee0634 --- /dev/null +++ b/start/cmp/lua/cmp/source.lua @@ -0,0 +1,365 @@ +local context = require('cmp.context') +local config = require('cmp.config') +local entry = require('cmp.entry') +local debug = require('cmp.utils.debug') +local misc = require('cmp.utils.misc') +local cache = require('cmp.utils.cache') +local types = require('cmp.types') +local async = require('cmp.utils.async') +local pattern = require('cmp.utils.pattern') +local char = require('cmp.utils.char') + +---@class cmp.Source +---@field public id number +---@field public name string +---@field public source any +---@field public cache cmp.Cache +---@field public revision number +---@field public incomplete boolean +---@field public is_triggered_by_symbol boolean +---@field public entries cmp.Entry[] +---@field public offset number +---@field public request_offset number +---@field public context cmp.Context +---@field public completion_context lsp.CompletionContext|nil +---@field public status cmp.SourceStatus +---@field public complete_dedup function +local source = {} + +---@alias cmp.SourceStatus 1 | 2 | 3 +source.SourceStatus = {} +source.SourceStatus.WAITING = 1 +source.SourceStatus.FETCHING = 2 +source.SourceStatus.COMPLETED = 3 + +---@return cmp.Source +source.new = function(name, s) + local self = setmetatable({}, { __index = source }) + self.id = misc.id('cmp.source.new') + self.name = name + self.source = s + self.cache = cache.new() + self.complete_dedup = async.dedup() + self.revision = 0 + self:reset() + return self +end + +---Reset current completion state +---@return boolean +source.reset = function(self) + self.cache:clear() + self.revision = self.revision + 1 + self.context = context.empty() + self.is_triggered_by_symbol = false + self.incomplete = false + self.entries = {} + self.offset = -1 + self.request_offset = -1 + self.completion_context = nil + self.status = source.SourceStatus.WAITING + self.complete_dedup(function() end) +end + +---Return source config +---@return cmp.SourceConfig +source.get_source_config = function(self) + return config.get_source_config(self.name) or {} +end + +---Return matching config +---@return cmp.MatchingConfig +source.get_matching_config = function() + return config.get().matching +end + +---Get fetching time +source.get_fetching_time = function(self) + if self.status == source.SourceStatus.FETCHING then + return vim.loop.now() - self.context.time + end + return 100 * 1000 -- return pseudo time if source isn't fetching. +end + +---Return filtered entries +---@param ctx cmp.Context +---@return cmp.Entry[] +source.get_entries = function(self, ctx) + if self.offset == -1 then + return {} + end + + local target_entries = (function() + local key = { 'get_entries', self.revision } + for i = ctx.cursor.col, self.offset, -1 do + key[3] = string.sub(ctx.cursor_before_line, 1, i) + local prev_entries = self.cache:get(key) + if prev_entries then + return prev_entries + end + end + return self.entries + end)() + + local inputs = {} + local entries = {} + for _, e in ipairs(target_entries) do + local o = e:get_offset() + if not inputs[o] then + inputs[o] = string.sub(ctx.cursor_before_line, o) + end + + local match = e:match(inputs[o], self:get_matching_config()) + e.score = match.score + e.exact = false + if e.score >= 1 then + e.matches = match.matches + e.exact = e:get_filter_text() == inputs[o] or e:get_word() == inputs[o] + table.insert(entries, e) + end + end + self.cache:set({ 'get_entries', self.revision, ctx.cursor_before_line }, entries) + + local max_item_count = self:get_source_config().max_item_count or 200 + local limited_entries = {} + for _, e in ipairs(entries) do + table.insert(limited_entries, e) + if max_item_count and #limited_entries >= max_item_count then + break + end + end + return limited_entries +end + +---Get default insert range +---@return lsp.Range|nil +source.get_default_insert_range = function(self) + if not self.context then + return nil + end + + return self.cache:ensure({ 'get_default_insert_range', self.revision }, function() + return { + start = { + line = self.context.cursor.row - 1, + character = misc.to_utfindex(self.context.cursor_line, self.offset), + }, + ['end'] = { + line = self.context.cursor.row - 1, + character = misc.to_utfindex(self.context.cursor_line, self.context.cursor.col), + }, + } + end) +end + +---Get default replace range +---@return lsp.Range|nil +source.get_default_replace_range = function(self) + if not self.context then + return nil + end + + return self.cache:ensure({ 'get_default_replace_range', self.revision }, function() + local _, e = pattern.offset('^' .. '\\%(' .. self:get_keyword_pattern() .. '\\)', string.sub(self.context.cursor_line, self.offset)) + return { + start = { + line = self.context.cursor.row - 1, + character = misc.to_utfindex(self.context.cursor_line, self.offset), + }, + ['end'] = { + line = self.context.cursor.row - 1, + character = misc.to_utfindex(self.context.cursor_line, e and self.offset + e - 1 or self.context.cursor.col), + }, + } + end) +end + +---Return source name. +source.get_debug_name = function(self) + local name = self.name + if self.source.get_debug_name then + name = self.source:get_debug_name() + end + return name +end + +---Return the source is available or not. +source.is_available = function(self) + if self.source.is_available then + return self.source:is_available() + end + return true +end + +---Get trigger_characters +---@return string[] +source.get_trigger_characters = function(self) + local c = self:get_source_config() + if c.trigger_characters then + return c.trigger_characters + end + + local trigger_characters = {} + if self.source.get_trigger_characters then + trigger_characters = self.source:get_trigger_characters(misc.copy(c)) or {} + end + if config.get().completion.get_trigger_characters then + return config.get().completion.get_trigger_characters(trigger_characters) + end + return trigger_characters +end + +---Get keyword_pattern +---@return string +source.get_keyword_pattern = function(self) + local c = self:get_source_config() + if c.keyword_pattern then + return c.keyword_pattern + end + if self.source.get_keyword_pattern then + return self.source:get_keyword_pattern(misc.copy(c)) + end + return config.get().completion.keyword_pattern +end + +---Get keyword_length +---@return number +source.get_keyword_length = function(self) + local c = self:get_source_config() + if c.keyword_length then + return c.keyword_length + end + return config.get().completion.keyword_length or 1 +end + +---Invoke completion +---@param ctx cmp.Context +---@param callback function +---@return boolean Return true if not trigger completion. +source.complete = function(self, ctx, callback) + local offset = ctx:get_offset(self:get_keyword_pattern()) + + -- NOTE: This implementation is nvim-cmp specific. + -- We trigger new completion after core.confirm but we check only the symbol trigger_character in this case. + local before_char = string.sub(ctx.cursor_before_line, -1) + if ctx:get_reason() == types.cmp.ContextReason.TriggerOnly then + before_char = string.match(ctx.cursor_before_line, '(.)%s*$') + if not before_char or not char.is_symbol(string.byte(before_char)) then + before_char = '' + end + end + + local completion_context + if ctx:get_reason() == types.cmp.ContextReason.Manual then + completion_context = { + triggerKind = types.lsp.CompletionTriggerKind.Invoked, + } + elseif vim.tbl_contains(self:get_trigger_characters(), before_char) then + completion_context = { + triggerKind = types.lsp.CompletionTriggerKind.TriggerCharacter, + triggerCharacter = before_char, + } + elseif ctx:get_reason() ~= types.cmp.ContextReason.TriggerOnly then + if self:get_keyword_length() <= (ctx.cursor.col - offset) then + if self.incomplete and self.context.cursor.col ~= ctx.cursor.col and self.status ~= source.SourceStatus.FETCHING then + completion_context = { + triggerKind = types.lsp.CompletionTriggerKind.TriggerForIncompleteCompletions, + } + elseif not vim.tbl_contains({ self.request_offset, self.offset }, offset) then + completion_context = { + triggerKind = types.lsp.CompletionTriggerKind.Invoked, + } + end + else + self:reset() -- Should clear current completion if the TriggerKind isn't TriggerCharacter or Manual and keyword length does not enough. + end + else + self:reset() -- Should clear current completion if ContextReason is TriggerOnly and the triggerCharacter isn't matched + end + + -- Does not perform completions. + if not completion_context then + return + end + + if completion_context.triggerKind == types.lsp.CompletionTriggerKind.TriggerCharacter then + self.is_triggered_by_symbol = char.is_symbol(string.byte(completion_context.triggerCharacter)) + end + + debug.log(self:get_debug_name(), 'request', offset, vim.inspect(completion_context)) + local prev_status = self.status + self.status = source.SourceStatus.FETCHING + self.offset = offset + self.request_offset = offset + self.context = ctx + self.completion_context = completion_context + self.source:complete( + vim.tbl_extend('keep', misc.copy(self:get_source_config()), { + offset = self.offset, + context = ctx, + completion_context = completion_context, + }), + self.complete_dedup(vim.schedule_wrap(function(response) + response = response or {} + + self.incomplete = response.isIncomplete or false + + if #(response.items or response) > 0 then + debug.log(self:get_debug_name(), 'retrieve', #(response.items or response)) + local old_offset = self.offset + local old_entries = self.entries + + self.status = source.SourceStatus.COMPLETED + self.entries = {} + for i, item in ipairs(response.items or response) do + if (misc.safe(item) or {}).label then + local e = entry.new(ctx, self, item) + self.entries[i] = e + self.offset = math.min(self.offset, e:get_offset()) + end + end + self.revision = self.revision + 1 + if #self:get_entries(ctx) == 0 then + self.offset = old_offset + self.entries = old_entries + self.revision = self.revision + 1 + end + else + -- The completion will be invoked when pressing if the trigger characters contain the . + -- If the server returns an empty response in such a case, should invoke the keyword completion on the next keypress. + if offset == ctx.cursor.col then + self:reset() + end + self.status = prev_status + end + callback() + end)) + ) + return true +end + +---Resolve CompletionItem +---@param item lsp.CompletionItem +---@param callback fun(item: lsp.CompletionItem) +source.resolve = function(self, item, callback) + if not self.source.resolve then + return callback(item) + end + self.source:resolve(item, function(resolved_item) + callback(resolved_item or item) + end) +end + +---Execute command +---@param item lsp.CompletionItem +---@param callback fun() +source.execute = function(self, item, callback) + if not self.source.execute then + return callback() + end + self.source:execute(item, function() + callback() + end) +end + +return source diff --git a/start/cmp/lua/cmp/source_spec.lua b/start/cmp/lua/cmp/source_spec.lua new file mode 100644 index 0000000..339149f --- /dev/null +++ b/start/cmp/lua/cmp/source_spec.lua @@ -0,0 +1,109 @@ +local config = require('cmp.config') +local spec = require('cmp.utils.spec') + +local source = require('cmp.source') + +describe('source', function() + before_each(spec.before) + + describe('keyword length', function() + it('not enough', function() + config.set_buffer({ + completion = { + keyword_length = 3, + }, + }, vim.api.nvim_get_current_buf()) + + local state = spec.state('', 1, 1) + local s = source.new('spec', { + complete = function(_, _, callback) + callback({ { label = 'spec' } }) + end, + }) + assert.is.truthy(not s:complete(state.input('a'), function() end)) + end) + + it('enough', function() + config.set_buffer({ + completion = { + keyword_length = 3, + }, + }, vim.api.nvim_get_current_buf()) + + local state = spec.state('', 1, 1) + local s = source.new('spec', { + complete = function(_, _, callback) + callback({ { label = 'spec' } }) + end, + }) + assert.is.truthy(s:complete(state.input('aiu'), function() end)) + end) + + it('enough -> not enough', function() + config.set_buffer({ + completion = { + keyword_length = 3, + }, + }, vim.api.nvim_get_current_buf()) + + local state = spec.state('', 1, 1) + local s = source.new('spec', { + complete = function(_, _, callback) + callback({ { label = 'spec' } }) + end, + }) + assert.is.truthy(s:complete(state.input('aiu'), function() end)) + assert.is.truthy(not s:complete(state.backspace(), function() end)) + end) + + it('continue', function() + config.set_buffer({ + completion = { + keyword_length = 3, + }, + }, vim.api.nvim_get_current_buf()) + + local state = spec.state('', 1, 1) + local s = source.new('spec', { + complete = function(_, _, callback) + callback({ { label = 'spec' } }) + end, + }) + assert.is.truthy(s:complete(state.input('aiu'), function() end)) + assert.is.truthy(not s:complete(state.input('eo'), function() end)) + end) + end) + + describe('isIncomplete', function() + it('isIncomplete=true', function() + local state = spec.state('', 1, 1) + local s = source.new('spec', { + complete = function(_, _, callback) + callback({ + items = { { label = 'spec' } }, + isIncomplete = true, + }) + end, + }) + vim.wait(100, function() + return s.status == source.SourceStatus.COMPLETED + end, 100, false) + assert.is.truthy(s:complete(state.input('s'), function() end)) + vim.wait(100, function() + return s.status == source.SourceStatus.COMPLETED + end, 100, false) + assert.is.truthy(s:complete(state.input('p'), function() end)) + vim.wait(100, function() + return s.status == source.SourceStatus.COMPLETED + end, 100, false) + assert.is.truthy(s:complete(state.input('e'), function() end)) + vim.wait(100, function() + return s.status == source.SourceStatus.COMPLETED + end, 100, false) + assert.is.truthy(s:complete(state.input('c'), function() end)) + vim.wait(100, function() + return s.status == source.SourceStatus.COMPLETED + end, 100, false) + end) + end) +end) diff --git a/start/cmp/lua/cmp/types/cmp.lua b/start/cmp/lua/cmp/types/cmp.lua new file mode 100644 index 0000000..8759aca --- /dev/null +++ b/start/cmp/lua/cmp/types/cmp.lua @@ -0,0 +1,166 @@ +local cmp = {} + +---@alias cmp.ConfirmBehavior 'insert' | 'replace' +cmp.ConfirmBehavior = { + Insert = 'insert', + Replace = 'replace', +} + +---@alias cmp.SelectBehavior 'insert' | 'select' +cmp.SelectBehavior = { + Insert = 'insert', + Select = 'select', +} + +---@alias cmp.ContextReason 'auto' | 'manual' 'triggerOnly' | 'none' +cmp.ContextReason = { + Auto = 'auto', + Manual = 'manual', + TriggerOnly = 'triggerOnly', + None = 'none', +} + +---@alias cmp.TriggerEvent 'InsertEnter' | 'TextChanged' +cmp.TriggerEvent = { + InsertEnter = 'InsertEnter', + TextChanged = 'TextChanged', +} + +---@alias cmp.PreselectMode 'item' | 'None' +cmp.PreselectMode = { + Item = 'item', + None = 'none', +} + +---@alias cmp.ItemField 'abbr' | 'kind' | 'menu' +cmp.ItemField = { + Abbr = 'abbr', + Kind = 'kind', + Menu = 'menu', +} + +---@class cmp.ContextOption +---@field public reason cmp.ContextReason|nil + +---@class cmp.ConfirmOption +---@field public behavior cmp.ConfirmBehavior +---@field public commit_character? string + +---@class cmp.SelectOption +---@field public behavior cmp.SelectBehavior + +---@class cmp.SnippetExpansionParams +---@field public body string +---@field public insert_text_mode number + +---@class cmp.CompleteParams +---@field public reason? cmp.ContextReason +---@field public config? cmp.ConfigSchema + +---@class cmp.Setup +---@field public __call fun(c: cmp.ConfigSchema) +---@field public buffer fun(c: cmp.ConfigSchema) +---@field public global fun(c: cmp.ConfigSchema) +---@field public cmdline fun(type: string, c: cmp.ConfigSchema) +---@field public filetype fun(type: string|string[], c: cmp.ConfigSchema) + +---@class cmp.SourceApiParams: cmp.SourceConfig + +---@class cmp.SourceCompletionApiParams : cmp.SourceConfig +---@field public offset number +---@field public context cmp.Context +---@field public completion_context lsp.CompletionContext + +---@class cmp.Mapping +---@field public i nil|function(fallback: function): void +---@field public c nil|function(fallback: function): void +---@field public x nil|function(fallback: function): void +---@field public s nil|function(fallback: function): void + +---@class cmp.ConfigSchema +---@field private revision number +---@field public enabled fun():boolean|boolean +---@field public preselect cmp.PreselectMode +---@field public completion cmp.CompletionConfig +---@field public window cmp.WindowConfig|nil +---@field public confirmation cmp.ConfirmationConfig +---@field public matching cmp.MatchingConfig +---@field public sorting cmp.SortingConfig +---@field public formatting cmp.FormattingConfig +---@field public snippet cmp.SnippetConfig +---@field public mapping table +---@field public sources cmp.SourceConfig[] +---@field public view cmp.ViewConfig +---@field public experimental cmp.ExperimentalConfig + +---@class cmp.WindowConfig +---@field completion cmp.WindowConfig +---@field documentation cmp.WindowConfig|nil + +---@class cmp.CompletionConfig +---@field public autocomplete cmp.TriggerEvent[] +---@field public completeopt string +---@field public get_trigger_characters fun(trigger_characters: string[]): string[] +---@field public keyword_length number +---@field public keyword_pattern string + +---@class cmp.WindowConfig +---@field public border string|string[] +---@field public winhighlight string +---@field public zindex number|nil +---@field public max_width number|nil +---@field public max_height number|nil + +---@class cmp.ConfirmationConfig +---@field public default_behavior cmp.ConfirmBehavior +---@field public get_commit_characters fun(commit_characters: string[]): string[] + +---@class cmp.MatchingConfig +---@field public disallow_fuzzy_matching boolean +---@field public disallow_partial_matching boolean +---@field public disallow_prefix_unmatching boolean + +---@class cmp.SortingConfig +---@field public priority_weight number +---@field public comparators function[] + +---@class cmp.FormattingConfig +---@field public fields cmp.ItemField[] +---@field public format fun(entry: cmp.Entry, vim_item: vim.CompletedItem): vim.CompletedItem + +---@class cmp.SnippetConfig +---@field public expand fun(args: cmp.SnippetExpansionParams) + +---@class cmp.ExperimentalConfig +---@field public ghost_text cmp.GhostTextConfig|false + +---@class cmp.GhostTextConfig +---@field hl_group string + +---@class cmp.SourceConfig +---@field public name string +---@field public option table|nil +---@field public priority number|nil +---@field public trigger_characters string[]|nil +---@field public keyword_pattern string|nil +---@field public keyword_length number|nil +---@field public max_item_count number|nil +---@field public group_index number|nil + +---@class cmp.ViewConfig +---@field public entries cmp.EntriesConfig + +---@alias cmp.EntriesConfig cmp.CustomEntriesConfig|cmp.NativeEntriesConfig|cmp.WildmenuEntriesConfig|string + +---@class cmp.CustomEntriesConfig +---@field name 'custom' +---@field selection_order 'top_down'|'near_cursor' + +---@class cmp.NativeEntriesConfig +---@field name 'native' + +---@class cmp.WildmenuEntriesConfig +---@field name 'wildmenu' +---@field separator string|nil + +return cmp diff --git a/start/cmp/lua/cmp/types/init.lua b/start/cmp/lua/cmp/types/init.lua new file mode 100644 index 0000000..c4f601e --- /dev/null +++ b/start/cmp/lua/cmp/types/init.lua @@ -0,0 +1,7 @@ +local types = {} + +types.cmp = require('cmp.types.cmp') +types.lsp = require('cmp.types.lsp') +types.vim = require('cmp.types.vim') + +return types diff --git a/start/cmp/lua/cmp/types/lsp.lua b/start/cmp/lua/cmp/types/lsp.lua new file mode 100644 index 0000000..4af54a9 --- /dev/null +++ b/start/cmp/lua/cmp/types/lsp.lua @@ -0,0 +1,197 @@ +local misc = require('cmp.utils.misc') + +---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/ +---@class lsp +local lsp = {} + +lsp.Position = { + ---Convert lsp.Position to vim.Position + ---@param buf number|string + ---@param position lsp.Position + ---@return vim.Position + to_vim = function(buf, position) + if not vim.api.nvim_buf_is_loaded(buf) then + vim.fn.bufload(buf) + end + local lines = vim.api.nvim_buf_get_lines(buf, position.line, position.line + 1, false) + if #lines > 0 then + return { + row = position.line + 1, + col = misc.to_vimindex(lines[1], position.character), + } + end + return { + row = position.line + 1, + col = position.character + 1, + } + end, + ---Convert vim.Position to lsp.Position + ---@param buf number|string + ---@param position vim.Position + ---@return lsp.Position + to_lsp = function(buf, position) + if not vim.api.nvim_buf_is_loaded(buf) then + vim.fn.bufload(buf) + end + local lines = vim.api.nvim_buf_get_lines(buf, position.row - 1, position.row, false) + if #lines > 0 then + return { + line = position.row - 1, + character = misc.to_utfindex(lines[1], position.col), + } + end + return { + line = position.row - 1, + character = position.col - 1, + } + end, +} + +lsp.Range = { + ---Convert lsp.Range to vim.Range + ---@param buf number|string + ---@param range lsp.Range + ---@return vim.Range + to_vim = function(buf, range) + return { + start = lsp.Position.to_vim(buf, range.start), + ['end'] = lsp.Position.to_vim(buf, range['end']), + } + end, + + ---Convert vim.Range to lsp.Range + ---@param buf number|string + ---@param range vim.Range + ---@return lsp.Range + to_lsp = function(buf, range) + return { + start = lsp.Position.to_lsp(buf, range.start), + ['end'] = lsp.Position.to_lsp(buf, range['end']), + } + end, +} + +---@alias lsp.CompletionTriggerKind 1 | 2 | 3 +lsp.CompletionTriggerKind = { + Invoked = 1, + TriggerCharacter = 2, + TriggerForIncompleteCompletions = 3, +} + +---@alias lsp.InsertTextFormat 1 | 2 +lsp.InsertTextFormat = {} +lsp.InsertTextFormat.PlainText = 1 +lsp.InsertTextFormat.Snippet = 2 + +---@alias lsp.InsertTextMode 1 | 2 +lsp.InsertTextMode = { + AsIs = 1, + AdjustIndentation = 2, +} + +---@alias lsp.MarkupKind 'plaintext' | 'markdown' +lsp.MarkupKind = { + PlainText = 'plaintext', + Markdown = 'markdown', +} + +---@alias lsp.CompletionItemTag 1 +lsp.CompletionItemTag = { + Deprecated = 1, +} + +---@alias lsp.CompletionItemKind 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 +lsp.CompletionItemKind = { + Text = 1, + Method = 2, + Function = 3, + Constructor = 4, + Field = 5, + Variable = 6, + Class = 7, + Interface = 8, + Module = 9, + Property = 10, + Unit = 11, + Value = 12, + Enum = 13, + Keyword = 14, + Snippet = 15, + Color = 16, + File = 17, + Reference = 18, + Folder = 19, + EnumMember = 20, + Constant = 21, + Struct = 22, + Event = 23, + Operator = 24, + TypeParameter = 25, +} +lsp.CompletionItemKind = vim.tbl_add_reverse_lookup(lsp.CompletionItemKind) + +---@class lsp.CompletionContext +---@field public triggerKind lsp.CompletionTriggerKind +---@field public triggerCharacter string|nil + +---@class lsp.CompletionList +---@field public isIncomplete boolean +---@field public items lsp.CompletionItem[] + +---@alias lsp.CompletionResponse lsp.CompletionList|lsp.CompletionItem[]|nil + +---@class lsp.MarkupContent +---@field public kind lsp.MarkupKind +---@field public value string + +---@class lsp.Position +---@field public line number +---@field public character number + +---@class lsp.Range +---@field public start lsp.Position +---@field public end lsp.Position + +---@class lsp.Command +---@field public title string +---@field public command string +---@field public arguments any[]|nil + +---@class lsp.TextEdit +---@field public range lsp.Range|nil +---@field public newText string + +---@class lsp.InsertReplaceTextEdit +---@field public insert lsp.Range|nil +---@field public replace lsp.Range|nil +---@field public newText string + +---@class lsp.CompletionItemLabelDetails +---@field public detail string|nil +---@field public description string|nil + +---@class lsp.CompletionItem +---@field public label string +---@field public labelDetails lsp.CompletionItemLabelDetails|nil +---@field public kind lsp.CompletionItemKind|nil +---@field public tags lsp.CompletionItemTag[]|nil +---@field public detail string|nil +---@field public documentation lsp.MarkupContent|string|nil +---@field public deprecated boolean|nil +---@field public preselect boolean|nil +---@field public sortText string|nil +---@field public filterText string|nil +---@field public insertText string|nil +---@field public insertTextFormat lsp.InsertTextFormat +---@field public insertTextMode lsp.InsertTextMode +---@field public textEdit lsp.TextEdit|lsp.InsertReplaceTextEdit|nil +---@field public additionalTextEdits lsp.TextEdit[] +---@field public commitCharacters string[]|nil +---@field public command lsp.Command|nil +---@field public data any|nil +--- +---TODO: Should send the issue for upstream? +---@field public word string|nil +---@field public dup boolean|nil + +return lsp diff --git a/start/cmp/lua/cmp/types/lsp_spec.lua b/start/cmp/lua/cmp/types/lsp_spec.lua new file mode 100644 index 0000000..fc2b857 --- /dev/null +++ b/start/cmp/lua/cmp/types/lsp_spec.lua @@ -0,0 +1,47 @@ +local spec = require('cmp.utils.spec') +local lsp = require('cmp.types.lsp') + +describe('types.lsp', function() + before_each(spec.before) + describe('Position', function() + vim.fn.setline('1', { + 'あいうえお', + 'かきくけこ', + 'さしすせそ', + }) + local vim_position, lsp_position + + local bufnr = vim.api.nvim_get_current_buf() + vim_position = lsp.Position.to_vim(bufnr, { line = 1, character = 3 }) + assert.are.equal(vim_position.row, 2) + assert.are.equal(vim_position.col, 10) + lsp_position = lsp.Position.to_lsp(bufnr, vim_position) + assert.are.equal(lsp_position.line, 1) + assert.are.equal(lsp_position.character, 3) + + vim_position = lsp.Position.to_vim(bufnr, { line = 1, character = 0 }) + assert.are.equal(vim_position.row, 2) + assert.are.equal(vim_position.col, 1) + lsp_position = lsp.Position.to_lsp(bufnr, vim_position) + assert.are.equal(lsp_position.line, 1) + assert.are.equal(lsp_position.character, 0) + + vim_position = lsp.Position.to_vim(bufnr, { line = 1, character = 5 }) + assert.are.equal(vim_position.row, 2) + assert.are.equal(vim_position.col, 16) + lsp_position = lsp.Position.to_lsp(bufnr, vim_position) + assert.are.equal(lsp_position.line, 1) + assert.are.equal(lsp_position.character, 5) + + -- overflow (lsp -> vim) + vim_position = lsp.Position.to_vim(bufnr, { line = 1, character = 6 }) + assert.are.equal(vim_position.row, 2) + assert.are.equal(vim_position.col, 16) + + -- overflow(vim -> lsp) + vim_position.col = vim_position.col + 1 + lsp_position = lsp.Position.to_lsp(bufnr, vim_position) + assert.are.equal(lsp_position.line, 1) + assert.are.equal(lsp_position.character, 5) + end) +end) diff --git a/start/cmp/lua/cmp/types/vim.lua b/start/cmp/lua/cmp/types/vim.lua new file mode 100644 index 0000000..95e757d --- /dev/null +++ b/start/cmp/lua/cmp/types/vim.lua @@ -0,0 +1,20 @@ +---@class vim.CompletedItem +---@field public word string +---@field public abbr string|nil +---@field public kind string|nil +---@field public menu string|nil +---@field public equal 1|nil +---@field public empty 1|nil +---@field public dup 1|nil +---@field public id any +---@field public abbr_hl_group string|nil +---@field public kind_hl_group string|nil +---@field public menu_hl_group string|nil + +---@class vim.Position +---@field public row number +---@field public col number + +---@class vim.Range +---@field public start vim.Position +---@field public end vim.Position diff --git a/start/cmp/lua/cmp/utils/api.lua b/start/cmp/lua/cmp/utils/api.lua new file mode 100644 index 0000000..d053409 --- /dev/null +++ b/start/cmp/lua/cmp/utils/api.lua @@ -0,0 +1,69 @@ +local api = {} + +local CTRL_V = vim.api.nvim_replace_termcodes('', true, true, true) +local CTRL_S = vim.api.nvim_replace_termcodes('', true, true, true) + +api.get_mode = function() + local mode = vim.api.nvim_get_mode().mode:sub(1, 1) + if mode == 'i' then + return 'i' -- insert + elseif mode == 'v' or mode == 'V' or mode == CTRL_V then + return 'x' -- visual + elseif mode == 's' or mode == 'S' or mode == CTRL_S then + return 's' -- select + elseif mode == 'c' and vim.fn.getcmdtype() ~= '=' then + return 'c' -- cmdline + end +end + +api.is_insert_mode = function() + return api.get_mode() == 'i' +end + +api.is_cmdline_mode = function() + return api.get_mode() == 'c' +end + +api.is_select_mode = function() + return api.get_mode() == 's' +end + +api.is_visual_mode = function() + return api.get_mode() == 'x' +end + +api.is_suitable_mode = function() + local mode = api.get_mode() + return mode == 'i' or mode == 'c' +end + +api.get_current_line = function() + if api.is_cmdline_mode() then + return vim.fn.getcmdline() + end + return vim.api.nvim_get_current_line() +end + +api.get_cursor = function() + if api.is_cmdline_mode() then + return { vim.o.lines - (vim.api.nvim_get_option('cmdheight') or 1) + 1, vim.fn.getcmdpos() - 1 } + end + return vim.api.nvim_win_get_cursor(0) +end + +api.get_screen_cursor = function() + if api.is_cmdline_mode() then + local cursor = api.get_cursor() + return { cursor[1], cursor[2] + 1 } + end + local cursor = api.get_cursor() + local pos = vim.fn.screenpos(0, cursor[1], cursor[2] + 1) + return { pos.row, pos.col - 1 } +end + +api.get_cursor_before_line = function() + local cursor = api.get_cursor() + return string.sub(api.get_current_line(), 1, cursor[2]) +end + +return api diff --git a/start/cmp/lua/cmp/utils/api_spec.lua b/start/cmp/lua/cmp/utils/api_spec.lua new file mode 100644 index 0000000..5363b48 --- /dev/null +++ b/start/cmp/lua/cmp/utils/api_spec.lua @@ -0,0 +1,46 @@ +local spec = require('cmp.utils.spec') +local keymap = require('cmp.utils.keymap') +local feedkeys = require('cmp.utils.feedkeys') +local api = require('cmp.utils.api') + +describe('api', function() + describe('get_cursor', function() + before_each(spec.before) + it('insert-mode', function() + local cursor + feedkeys.call(keymap.t('i\t1234567890'), 'nx', function() + cursor = api.get_cursor() + end) + assert.are.equal(cursor[2], 11) + end) + it('cmdline-mode', function() + local cursor + keymap.set_map(0, 'c', '(cmp-spec-spy)', function() + cursor = api.get_cursor() + end, { expr = true, noremap = true }) + feedkeys.call(keymap.t(':\t1234567890'), 'n') + feedkeys.call(keymap.t('(cmp-spec-spy)'), 'x') + assert.are.equal(cursor[2], 11) + end) + end) + + describe('get_cursor_before_line', function() + before_each(spec.before) + it('insert-mode', function() + local cursor_before_line + feedkeys.call(keymap.t('i\t1234567890'), 'nx', function() + cursor_before_line = api.get_cursor_before_line() + end) + assert.are.same(cursor_before_line, '\t12345678') + end) + it('cmdline-mode', function() + local cursor_before_line + keymap.set_map(0, 'c', '(cmp-spec-spy)', function() + cursor_before_line = api.get_cursor_before_line() + end, { expr = true, noremap = true }) + feedkeys.call(keymap.t(':\t1234567890'), 'n') + feedkeys.call(keymap.t('(cmp-spec-spy)'), 'x') + assert.are.same(cursor_before_line, '\t12345678') + end) + end) +end) diff --git a/start/cmp/lua/cmp/utils/async.lua b/start/cmp/lua/cmp/utils/async.lua new file mode 100644 index 0000000..13f126b --- /dev/null +++ b/start/cmp/lua/cmp/utils/async.lua @@ -0,0 +1,127 @@ +local async = {} + +---@class cmp.AsyncThrottle +---@field public running boolean +---@field public timeout number +---@field public sync function(self: cmp.AsyncThrottle, timeout: number|nil) +---@field public stop function +---@field public __call function + +---@param fn function +---@param timeout number +---@return cmp.AsyncThrottle +async.throttle = function(fn, timeout) + local time = nil + local timer = vim.loop.new_timer() + return setmetatable({ + running = false, + timeout = timeout, + sync = function(self, timeout_) + vim.wait(timeout_ or 1000, function() + return not self.running + end) + end, + stop = function() + time = nil + timer:stop() + end, + }, { + __call = function(self, ...) + local args = { ... } + + if time == nil then + time = vim.loop.now() + end + + self.running = true + timer:stop() + timer:start(math.max(1, self.timeout - (vim.loop.now() - time)), 0, function() + vim.schedule(function() + time = nil + fn(unpack(args)) + self.running = false + end) + end) + end, + }) +end + +---Control async tasks. +async.step = function(...) + local tasks = { ... } + local next + next = function(...) + if #tasks > 0 then + table.remove(tasks, 1)(next, ...) + end + end + table.remove(tasks, 1)(next) +end + +---Timeout callback function +---@param fn function +---@param timeout number +---@return function +async.timeout = function(fn, timeout) + local timer + local done = false + local callback = function(...) + if not done then + done = true + timer:stop() + timer:close() + fn(...) + end + end + timer = vim.loop.new_timer() + timer:start(timeout, 0, function() + callback() + end) + return callback +end + +---@alias cmp.AsyncDedup fun(callback: function): function + +---Create deduplicated callback +---@return function +async.dedup = function() + local id = 0 + return function(callback) + id = id + 1 + + local current = id + return function(...) + if current == id then + callback(...) + end + end + end +end + +---Convert async process as sync +async.sync = function(runner, timeout) + local done = false + runner(function() + done = true + end) + vim.wait(timeout, function() + return done + end, 10, false) +end + +---Wait and callback for next safe state. +async.debounce_next_tick = function(callback) + local running = false + return function() + if running then + return + end + running = true + vim.schedule(function() + running = false + callback() + end) + end +end + +return async diff --git a/start/cmp/lua/cmp/utils/async_spec.lua b/start/cmp/lua/cmp/utils/async_spec.lua new file mode 100644 index 0000000..62f5379 --- /dev/null +++ b/start/cmp/lua/cmp/utils/async_spec.lua @@ -0,0 +1,69 @@ +local async = require('cmp.utils.async') + +describe('utils.async', function() + it('throttle', function() + local count = 0 + local now + local f = async.throttle(function() + count = count + 1 + end, 100) + + -- 1. delay for 100ms + now = vim.loop.now() + f.timeout = 100 + f() + vim.wait(1000, function() + return count == 1 + end) + assert.is.truthy(math.abs(f.timeout - (vim.loop.now() - now)) < 10) + + -- 2. delay for 500ms + now = vim.loop.now() + f.timeout = 500 + f() + vim.wait(1000, function() + return count == 2 + end) + assert.is.truthy(math.abs(f.timeout - (vim.loop.now() - now)) < 10) + + -- 4. delay for 500ms and wait 100ms (remain 400ms) + f.timeout = 500 + f() + vim.wait(100) -- remain 400ms + + -- 5. call immediately (100ms already elapsed from No.4) + now = vim.loop.now() + f.timeout = 100 + f() + vim.wait(1000, function() + return count == 3 + end) + assert.is.truthy(math.abs(vim.loop.now() - now) < 10) + end) + it('step', function() + local done = false + local step = {} + async.step(function(next) + vim.defer_fn(function() + table.insert(step, 1) + next() + end, 10) + end, function(next) + vim.defer_fn(function() + table.insert(step, 2) + next() + end, 10) + end, function(next) + vim.defer_fn(function() + table.insert(step, 3) + next() + end, 10) + end, function() + done = true + end) + vim.wait(1000, function() + return done + end) + assert.are.same(step, { 1, 2, 3 }) + end) +end) diff --git a/start/cmp/lua/cmp/utils/autocmd.lua b/start/cmp/lua/cmp/utils/autocmd.lua new file mode 100644 index 0000000..438e231 --- /dev/null +++ b/start/cmp/lua/cmp/utils/autocmd.lua @@ -0,0 +1,53 @@ +local debug = require('cmp.utils.debug') + +local autocmd = {} + +autocmd.group = vim.api.nvim_create_augroup('___cmp___', { clear = true }) + +autocmd.events = {} + +---Subscribe autocmd +---@param events string|string[] +---@param callback function +---@return function +autocmd.subscribe = function(events, callback) + events = type(events) == 'string' and { events } or events + + for _, event in ipairs(events) do + if not autocmd.events[event] then + autocmd.events[event] = {} + vim.api.nvim_create_autocmd(event, { + desc = ('nvim-cmp: autocmd: %s'):format(event), + group = autocmd.group, + callback = function() + autocmd.emit(event) + end, + }) + end + table.insert(autocmd.events[event], callback) + end + + return function() + for _, event in ipairs(events) do + for i, callback_ in ipairs(autocmd.events[event]) do + if callback_ == callback then + table.remove(autocmd.events[event], i) + break + end + end + end + end +end + +---Emit autocmd +---@param event string +autocmd.emit = function(event) + debug.log(' ') + debug.log(string.format('>>> %s', event)) + autocmd.events[event] = autocmd.events[event] or {} + for _, callback in ipairs(autocmd.events[event]) do + callback() + end +end + +return autocmd diff --git a/start/cmp/lua/cmp/utils/binary.lua b/start/cmp/lua/cmp/utils/binary.lua new file mode 100644 index 0000000..c6a7088 --- /dev/null +++ b/start/cmp/lua/cmp/utils/binary.lua @@ -0,0 +1,33 @@ +local binary = {} + +---Insert item to list to ordered index +---@param list any[] +---@param item any +---@param func fun(a: any, b: any): 1|-1|0 +binary.insort = function(list, item, func) + table.insert(list, binary.search(list, item, func), item) +end + +---Search suitable index from list +---@param list any[] +---@param item any +---@param func fun(a: any, b: any): 1|-1|0 +---@return number +binary.search = function(list, item, func) + local s = 1 + local e = #list + while s <= e do + local idx = math.floor((e + s) / 2) + local diff = func(item, list[idx]) + if diff > 0 then + s = idx + 1 + elseif diff < 0 then + e = idx - 1 + else + return idx + 1 + end + end + return s +end + +return binary diff --git a/start/cmp/lua/cmp/utils/binary_spec.lua b/start/cmp/lua/cmp/utils/binary_spec.lua new file mode 100644 index 0000000..92fe129 --- /dev/null +++ b/start/cmp/lua/cmp/utils/binary_spec.lua @@ -0,0 +1,28 @@ +local binary = require('cmp.utils.binary') + +describe('utils.binary', function() + it('insort', function() + local func = function(a, b) + return a.score - b.score + end + local list = {} + binary.insort(list, { id = 'a', score = 1 }, func) + binary.insort(list, { id = 'b', score = 5 }, func) + binary.insort(list, { id = 'c', score = 2.5 }, func) + binary.insort(list, { id = 'd', score = 2 }, func) + binary.insort(list, { id = 'e', score = 8 }, func) + binary.insort(list, { id = 'g', score = 8 }, func) + binary.insort(list, { id = 'h', score = 7 }, func) + binary.insort(list, { id = 'i', score = 6 }, func) + binary.insort(list, { id = 'j', score = 4 }, func) + assert.are.equal(list[1].id, 'a') + assert.are.equal(list[2].id, 'd') + assert.are.equal(list[3].id, 'c') + assert.are.equal(list[4].id, 'j') + assert.are.equal(list[5].id, 'b') + assert.are.equal(list[6].id, 'i') + assert.are.equal(list[7].id, 'h') + assert.are.equal(list[8].id, 'e') + assert.are.equal(list[9].id, 'g') + end) +end) diff --git a/start/cmp/lua/cmp/utils/buffer.lua b/start/cmp/lua/cmp/utils/buffer.lua new file mode 100644 index 0000000..63171c9 --- /dev/null +++ b/start/cmp/lua/cmp/utils/buffer.lua @@ -0,0 +1,28 @@ +local buffer = {} + +buffer.cache = {} + +---@return number buf +buffer.get = function(name) + local buf = buffer.cache[name] + if buf and vim.api.nvim_buf_is_valid(buf) then + return buf + else + return nil + end +end + +---@return number buf +---@return boolean created_new +buffer.ensure = function(name) + local created_new = false + local buf = buffer.get(name) + if not buf then + created_new = true + buf = vim.api.nvim_create_buf(false, true) + buffer.cache[name] = buf + end + return buf, created_new +end + +return buffer diff --git a/start/cmp/lua/cmp/utils/cache.lua b/start/cmp/lua/cmp/utils/cache.lua new file mode 100644 index 0000000..8607b2a --- /dev/null +++ b/start/cmp/lua/cmp/utils/cache.lua @@ -0,0 +1,58 @@ +---@class cmp.Cache +---@field public entries any +local cache = {} + +cache.new = function() + local self = setmetatable({}, { __index = cache }) + self.entries = {} + return self +end + +---Get cache value +---@param key string +---@return any|nil +cache.get = function(self, key) + key = self:key(key) + if self.entries[key] ~= nil then + return self.entries[key] + end + return nil +end + +---Set cache value explicitly +---@param key string +---@vararg any +cache.set = function(self, key, value) + key = self:key(key) + self.entries[key] = value +end + +---Ensure value by callback +---@param key string +---@param callback fun(): any +cache.ensure = function(self, key, callback) + local value = self:get(key) + if value == nil then + local v = callback() + self:set(key, v) + return v + end + return value +end + +---Clear all cache entries +cache.clear = function(self) + self.entries = {} +end + +---Create key +---@param key string|table +---@return string +cache.key = function(_, key) + if type(key) == 'table' then + return table.concat(key, ':') + end + return key +end + +return cache diff --git a/start/cmp/lua/cmp/utils/char.lua b/start/cmp/lua/cmp/utils/char.lua new file mode 100644 index 0000000..6e18994 --- /dev/null +++ b/start/cmp/lua/cmp/utils/char.lua @@ -0,0 +1,117 @@ +local _ + +local alpha = {} +_ = string.gsub('abcdefghijklmnopqrstuvwxyz', '.', function(char) + alpha[string.byte(char)] = true +end) + +local ALPHA = {} +_ = string.gsub('ABCDEFGHIJKLMNOPQRSTUVWXYZ', '.', function(char) + ALPHA[string.byte(char)] = true +end) + +local digit = {} +_ = string.gsub('1234567890', '.', function(char) + digit[string.byte(char)] = true +end) + +local white = {} +_ = string.gsub(' \t\n', '.', function(char) + white[string.byte(char)] = true +end) + +local char = {} + +---@param byte number +---@return boolean +char.is_upper = function(byte) + return ALPHA[byte] +end + +---@param byte number +---@return boolean +char.is_alpha = function(byte) + return alpha[byte] or ALPHA[byte] +end + +---@param byte number +---@return boolean +char.is_digit = function(byte) + return digit[byte] +end + +---@param byte number +---@return boolean +char.is_white = function(byte) + return white[byte] +end + +---@param byte number +---@return boolean +char.is_symbol = function(byte) + return not (char.is_alnum(byte) or char.is_white(byte)) +end + +---@param byte number +---@return boolean +char.is_printable = function(byte) + return string.match(string.char(byte), '^%c$') == nil +end + +---@param byte number +---@return boolean +char.is_alnum = function(byte) + return char.is_alpha(byte) or char.is_digit(byte) +end + +---@param text string +---@param index number +---@return boolean +char.is_semantic_index = function(text, index) + if index <= 1 then + return true + end + + local prev = string.byte(text, index - 1) + local curr = string.byte(text, index) + + if not char.is_upper(prev) and char.is_upper(curr) then + return true + end + if char.is_symbol(curr) or char.is_white(curr) then + return true + end + if not char.is_alpha(prev) and char.is_alpha(curr) then + return true + end + if not char.is_digit(prev) and char.is_digit(curr) then + return true + end + return false +end + +---@param text string +---@param current_index number +---@return boolean +char.get_next_semantic_index = function(text, current_index) + for i = current_index + 1, #text do + if char.is_semantic_index(text, i) then + return i + end + end + return #text + 1 +end + +---Ignore case match +---@param byte1 number +---@param byte2 number +---@return boolean +char.match = function(byte1, byte2) + if not char.is_alpha(byte1) or not char.is_alpha(byte2) then + return byte1 == byte2 + end + local diff = byte1 - byte2 + return diff == 0 or diff == 32 or diff == -32 +end + +return char diff --git a/start/cmp/lua/cmp/utils/debug.lua b/start/cmp/lua/cmp/utils/debug.lua new file mode 100644 index 0000000..c8b0dba --- /dev/null +++ b/start/cmp/lua/cmp/utils/debug.lua @@ -0,0 +1,20 @@ +local debug = {} + +debug.flag = false + +---Print log +---@vararg any +debug.log = function(...) + if debug.flag then + local data = {} + for _, v in ipairs({ ... }) do + if not vim.tbl_contains({ 'string', 'number', 'boolean' }, type(v)) then + v = vim.inspect(v) + end + table.insert(data, v) + end + print(table.concat(data, '\t')) + end +end + +return debug diff --git a/start/cmp/lua/cmp/utils/event.lua b/start/cmp/lua/cmp/utils/event.lua new file mode 100644 index 0000000..662d573 --- /dev/null +++ b/start/cmp/lua/cmp/utils/event.lua @@ -0,0 +1,51 @@ +---@class cmp.Event +---@field private events table +local event = {} + +---Create vents +event.new = function() + local self = setmetatable({}, { __index = event }) + self.events = {} + return self +end + +---Add event listener +---@param name string +---@param callback function +---@return function +event.on = function(self, name, callback) + if not self.events[name] then + self.events[name] = {} + end + table.insert(self.events[name], callback) + return function() + self:off(name, callback) + end +end + +---Remove event listener +---@param name string +---@param callback function +event.off = function(self, name, callback) + for i, callback_ in ipairs(self.events[name] or {}) do + if callback_ == callback then + table.remove(self.events[name], i) + break + end + end +end + +---Remove all events +event.clear = function(self) + self.events = {} +end + +---Emit event +---@param name string +event.emit = function(self, name, ...) + for _, callback in ipairs(self.events[name] or {}) do + callback(...) + end +end + +return event diff --git a/start/cmp/lua/cmp/utils/feedkeys.lua b/start/cmp/lua/cmp/utils/feedkeys.lua new file mode 100644 index 0000000..cd20f60 --- /dev/null +++ b/start/cmp/lua/cmp/utils/feedkeys.lua @@ -0,0 +1,53 @@ +local keymap = require('cmp.utils.keymap') +local misc = require('cmp.utils.misc') + +local feedkeys = {} + +feedkeys.call = setmetatable({ + callbacks = {}, +}, { + __call = function(self, keys, mode, callback) + local is_insert = string.match(mode, 'i') ~= nil + local is_immediate = string.match(mode, 'x') ~= nil + + local queue = {} + if #keys > 0 then + table.insert(queue, { keymap.t('setlocal lazyredraw'), 'n' }) + table.insert(queue, { keymap.t('setlocal textwidth=0'), 'n' }) + table.insert(queue, { keymap.t('setlocal backspace=2'), 'n' }) + table.insert(queue, { keys, string.gsub(mode, '[itx]', ''), true }) + table.insert(queue, { keymap.t('setlocal %slazyredraw'):format(vim.o.lazyredraw and '' or 'no'), 'n' }) + table.insert(queue, { keymap.t('setlocal textwidth=%s'):format(vim.bo.textwidth or 0), 'n' }) + table.insert(queue, { keymap.t('setlocal backspace=%s'):format(vim.go.backspace or 2), 'n' }) + end + + if callback then + local id = misc.id('cmp.utils.feedkeys.call') + self.callbacks[id] = callback + table.insert(queue, { keymap.t('call v:lua.cmp.utils.feedkeys.call.run(%s)'):format(id), 'n', true }) + end + + if is_insert then + for i = #queue, 1, -1 do + vim.api.nvim_feedkeys(queue[i][1], queue[i][2] .. 'i', queue[i][3]) + end + else + for i = 1, #queue do + vim.api.nvim_feedkeys(queue[i][1], queue[i][2], queue[i][3]) + end + end + + if is_immediate then + vim.api.nvim_feedkeys('', 'x', true) + end + end, +}) +misc.set(_G, { 'cmp', 'utils', 'feedkeys', 'call', 'run' }, function(id) + if feedkeys.call.callbacks[id] then + feedkeys.call.callbacks[id]() + feedkeys.call.callbacks[id] = nil + end + return '' +end) + +return feedkeys diff --git a/start/cmp/lua/cmp/utils/feedkeys_spec.lua b/start/cmp/lua/cmp/utils/feedkeys_spec.lua new file mode 100644 index 0000000..24fba71 --- /dev/null +++ b/start/cmp/lua/cmp/utils/feedkeys_spec.lua @@ -0,0 +1,56 @@ +local spec = require('cmp.utils.spec') +local keymap = require('cmp.utils.keymap') + +local feedkeys = require('cmp.utils.feedkeys') + +describe('feedkeys', function() + before_each(spec.before) + + it('dot-repeat', function() + local reg + feedkeys.call(keymap.t('iaiueo'), 'nx', function() + reg = vim.fn.getreg('.') + end) + assert.are.equal(reg, keymap.t('aiueo')) + end) + + it('textwidth', function() + vim.cmd([[setlocal textwidth=6]]) + feedkeys.call(keymap.t('iaiueo '), 'nx') + feedkeys.call(keymap.t('aaiueoaiueo'), 'nx') + assert.are.same(vim.api.nvim_buf_get_lines(0, 0, -1, false), { + 'aiueo aiueoaiueo', + }) + end) + + it('bacckspace', function() + vim.cmd([[setlocal backspace=0]]) + feedkeys.call(keymap.t('iaiueo'), 'nx') + feedkeys.call(keymap.t('a'), 'nx') + assert.are.same(vim.api.nvim_buf_get_lines(0, 0, -1, false), { + 'aiu', + }) + end) + + it('testability', function() + feedkeys.call('i', 'n', function() + feedkeys.call('', 'n', function() + feedkeys.call('aiueo', 'in') + end) + feedkeys.call('', 'n', function() + feedkeys.call(keymap.t(''), 'in') + end) + feedkeys.call('', 'n', function() + feedkeys.call(keymap.t('abcde'), 'in') + end) + feedkeys.call('', 'n', function() + feedkeys.call(keymap.t(''), 'in') + end) + feedkeys.call('', 'n', function() + feedkeys.call(keymap.t('12345'), 'in') + end) + end) + feedkeys.call('', 'x') + assert.are.same(vim.api.nvim_buf_get_lines(0, 0, -1, false), { '12345' }) + end) +end) diff --git a/start/cmp/lua/cmp/utils/highlight.lua b/start/cmp/lua/cmp/utils/highlight.lua new file mode 100644 index 0000000..867632a --- /dev/null +++ b/start/cmp/lua/cmp/utils/highlight.lua @@ -0,0 +1,31 @@ +local highlight = {} + +highlight.keys = { + 'fg', + 'bg', + 'bold', + 'italic', + 'reverse', + 'standout', + 'underline', + 'undercurl', + 'strikethrough', +} + +highlight.inherit = function(name, source, settings) + for _, key in ipairs(highlight.keys) do + if not settings[key] then + local v = vim.fn.synIDattr(vim.fn.hlID(source), key) + if key == 'fg' or key == 'bg' then + local n = tonumber(v, 10) + v = type(n) == 'number' and n or v + else + v = v == 1 + end + settings[key] = v == '' and 'NONE' or v + end + end + vim.api.nvim_set_hl(0, name, settings) +end + +return highlight diff --git a/start/cmp/lua/cmp/utils/keymap.lua b/start/cmp/lua/cmp/utils/keymap.lua new file mode 100644 index 0000000..aea5c1d --- /dev/null +++ b/start/cmp/lua/cmp/utils/keymap.lua @@ -0,0 +1,251 @@ +local misc = require('cmp.utils.misc') +local buffer = require('cmp.utils.buffer') +local api = require('cmp.utils.api') + +local keymap = {} + +---Shortcut for nvim_replace_termcodes +---@param keys string +---@return string +keymap.t = function(keys) + return (string.gsub(keys, '(<[A-Za-z0-9\\%-%[%]%^@]->)', function(match) + return vim.api.nvim_eval(string.format([["\%s"]], match)) + end)) +end + +---Normalize key sequence. +---@param keys string +---@return string +keymap.normalize = function(keys) + local normalize_buf = buffer.ensure('cmp.util.keymap.normalize') + vim.api.nvim_buf_set_keymap(normalize_buf, 't', keys, '(cmp.utils.keymap.normalize)', {}) + for _, map in ipairs(vim.api.nvim_buf_get_keymap(normalize_buf, 't')) do + if keymap.equals(map.rhs, '(cmp.utils.keymap.normalize)') then + vim.api.nvim_buf_del_keymap(normalize_buf, 't', keys) + return map.lhs + end + end + vim.api.nvim_buf_del_keymap(normalize_buf, 't', keys) + return keys +end + +---Return vim notation keymapping (simple conversion). +---@param s string +---@return string +keymap.to_keymap = setmetatable({ + [''] = { '\n', '\r', '\r\n' }, + [''] = { '\t' }, + [''] = { '\\' }, + [''] = { '|' }, + [''] = { ' ' }, +}, { + __call = function(self, s) + return string.gsub(s, '.', function(c) + for key, chars in pairs(self) do + if vim.tbl_contains(chars, c) then + return key + end + end + return c + end) + end, +}) + +---Mode safe break undo +keymap.undobreak = function() + if not api.is_insert_mode() then + return '' + end + return keymap.t('u') +end + +---Mode safe join undo +keymap.undojoin = function() + if not api.is_insert_mode() then + return '' + end + return keymap.t('U') +end + +---Create backspace keys. +---@param count number +---@return string +keymap.backspace = function(count) + if type(count) == 'string' then + count = vim.fn.strchars(count, true) + end + if count <= 0 then + return '' + end + local keys = {} + table.insert(keys, keymap.t(string.rep('', count))) + return table.concat(keys, '') +end + +---Update indentkeys. +---@param expr string +---@return string +keymap.indentkeys = function(expr) + return string.format(keymap.t('set indentkeys=%s'), expr and vim.fn.escape(expr, '| \t\\') or '') +end + +---Return two key sequence are equal or not. +---@param a string +---@param b string +---@return boolean +keymap.equals = function(a, b) + return keymap.t(a) == keymap.t(b) +end + +---Register keypress handler. +keymap.listen = function(mode, lhs, callback) + lhs = keymap.normalize(keymap.to_keymap(lhs)) + + local existing = keymap.get_map(mode, lhs) + local id = string.match(existing.rhs, 'v:lua%.cmp%.utils%.keymap%.set_map%((%d+)%)') + if id and keymap.set_map.callbacks[tonumber(id, 10)] then + return + end + + local bufnr = existing.buffer and vim.api.nvim_get_current_buf() or -1 + local fallback = keymap.fallback(bufnr, mode, existing) + keymap.set_map(bufnr, mode, lhs, function() + local ignore = false + ignore = ignore or (mode == 'c' and vim.fn.getcmdtype() == '=') + if ignore then + fallback() + else + callback(lhs, misc.once(fallback)) + end + end, { + expr = false, + noremap = true, + silent = true, + }) +end + +---Fallback +keymap.fallback = function(bufnr, mode, map) + return function() + if map.expr then + local fallback_expr = string.format('(cmp.u.k.fallback_expr:%s)', map.lhs) + keymap.set_map(bufnr, mode, fallback_expr, function() + return keymap.solve(bufnr, mode, map).keys + end, { + expr = true, + noremap = map.noremap, + script = map.script, + nowait = map.nowait, + silent = map.silent and mode ~= 'c', + }) + vim.api.nvim_feedkeys(keymap.t(fallback_expr), 'im', true) + elseif not map.callback then + local solved = keymap.solve(bufnr, mode, map) + vim.api.nvim_feedkeys(solved.keys, solved.mode, true) + else + map.callback() + end + end +end + +---Solve +keymap.solve = function(bufnr, mode, map) + local lhs = keymap.t(map.lhs) + local rhs = map.expr and (map.callback and map.callback() or vim.api.nvim_eval(keymap.t(map.rhs))) or keymap.t(map.rhs) + + if map.noremap then + return { keys = rhs, mode = 'in' } + end + + if string.find(rhs, lhs, 1, true) == 1 then + local recursive = string.format('0_(cmp.u.k.recursive:%s)', lhs) + keymap.set_map(bufnr, mode, recursive, lhs, { + noremap = true, + script = map.script, + nowait = map.nowait, + silent = map.silent and mode ~= 'c', + }) + return { keys = keymap.t(recursive) .. string.gsub(rhs, '^' .. vim.pesc(lhs), ''), mode = 'im' } + end + return { keys = rhs, mode = 'im' } +end + +---Get map +---@param mode string +---@param lhs string +---@return table +keymap.get_map = function(mode, lhs) + lhs = keymap.normalize(lhs) + + for _, map in ipairs(vim.api.nvim_buf_get_keymap(0, mode)) do + if keymap.equals(map.lhs, lhs) then + return { + lhs = map.lhs, + rhs = map.rhs or '', + expr = map.expr == 1, + callback = map.callback, + noremap = map.noremap == 1, + script = map.script == 1, + silent = map.silent == 1, + nowait = map.nowait == 1, + buffer = true, + } + end + end + + for _, map in ipairs(vim.api.nvim_get_keymap(mode)) do + if keymap.equals(map.lhs, lhs) then + return { + lhs = map.lhs, + rhs = map.rhs or '', + expr = map.expr == 1, + callback = map.callback, + noremap = map.noremap == 1, + script = map.script == 1, + silent = map.silent == 1, + nowait = map.nowait == 1, + buffer = false, + } + end + end + + return { + lhs = lhs, + rhs = lhs, + expr = false, + callback = nil, + noremap = true, + script = false, + silent = true, + nowait = false, + buffer = false, + } +end + +---Set keymapping +keymap.set_map = setmetatable({ + callbacks = {}, +}, { + __call = function(self, bufnr, mode, lhs, rhs, opts) + if type(rhs) == 'function' then + local id = misc.id('cmp.utils.keymap.set_map') + self.callbacks[id] = rhs + if opts.expr then + rhs = ('v:lua.cmp.utils.keymap.set_map(%s)'):format(id) + else + rhs = ('call v:lua.cmp.utils.keymap.set_map(%s)'):format(id) + end + end + + if bufnr == -1 then + vim.api.nvim_set_keymap(mode, lhs, rhs, opts) + else + vim.api.nvim_buf_set_keymap(bufnr, mode, lhs, rhs, opts) + end + end, +}) +misc.set(_G, { 'cmp', 'utils', 'keymap', 'set_map' }, function(id) + return keymap.set_map.callbacks[id]() or '' +end) + +return keymap diff --git a/start/cmp/lua/cmp/utils/keymap_spec.lua b/start/cmp/lua/cmp/utils/keymap_spec.lua new file mode 100644 index 0000000..959783f --- /dev/null +++ b/start/cmp/lua/cmp/utils/keymap_spec.lua @@ -0,0 +1,187 @@ +local spec = require('cmp.utils.spec') +local api = require('cmp.utils.api') +local feedkeys = require('cmp.utils.feedkeys') + +local keymap = require('cmp.utils.keymap') + +describe('keymap', function() + before_each(spec.before) + + it('t', function() + for _, key in ipairs({ + '', + '', + '', + '', + '', + '', + '', + '', + '', + '(example)', + '="abc"', + 'normal! ==', + }) do + assert.are.equal(keymap.t(key), vim.api.nvim_replace_termcodes(key, true, true, true)) + assert.are.equal(keymap.t(key .. key), vim.api.nvim_replace_termcodes(key .. key, true, true, true)) + assert.are.equal(keymap.t(key .. key .. key), vim.api.nvim_replace_termcodes(key .. key .. key, true, true, true)) + end + end) + + it('to_keymap', function() + assert.are.equal(keymap.to_keymap('\n'), '') + assert.are.equal(keymap.to_keymap(''), '') + assert.are.equal(keymap.to_keymap('|'), '') + end) + + describe('fallback', function() + before_each(spec.before) + + local run_fallback = function(keys, fallback) + local state = {} + feedkeys.call(keys, '', function() + fallback() + end) + feedkeys.call('', '', function() + if api.is_cmdline_mode() then + state.buffer = { api.get_current_line() } + else + state.buffer = vim.api.nvim_buf_get_lines(0, 0, -1, false) + end + state.cursor = api.get_cursor() + end) + feedkeys.call('', 'x') + return state + end + + describe('basic', function() + it('', function() + vim.api.nvim_buf_set_keymap(0, 'i', '(pairs)', '()', { noremap = true }) + vim.api.nvim_buf_set_keymap(0, 'i', '(', '(pairs)', { noremap = false }) + local fallback = keymap.fallback(0, 'i', keymap.get_map('i', '(')) + local state = run_fallback('i', fallback) + assert.are.same({ '()' }, state.buffer) + assert.are.same({ 1, 1 }, state.cursor) + end) + + it('=', function() + vim.api.nvim_buf_set_keymap(0, 'i', '(', '="()"', {}) + local fallback = keymap.fallback(0, 'i', keymap.get_map('i', '(')) + local state = run_fallback('i', fallback) + assert.are.same({ '()' }, state.buffer) + assert.are.same({ 1, 1 }, state.cursor) + end) + + it('callback', function() + vim.api.nvim_buf_set_keymap(0, 'i', '(', '', { + callback = function() + vim.api.nvim_feedkeys('()' .. keymap.t(''), 'int', true) + end, + }) + local fallback = keymap.fallback(0, 'i', keymap.get_map('i', '(')) + local state = run_fallback('i', fallback) + assert.are.same({ '()' }, state.buffer) + assert.are.same({ 1, 1 }, state.cursor) + end) + + it('expr-callback', function() + vim.api.nvim_buf_set_keymap(0, 'i', '(', '', { + expr = true, + noremap = false, + silent = true, + callback = function() + return '()' .. keymap.t('') + end, + }) + local fallback = keymap.fallback(0, 'i', keymap.get_map('i', '(')) + local state = run_fallback('i', fallback) + assert.are.same({ '()' }, state.buffer) + assert.are.same({ 1, 1 }, state.cursor) + end) + + -- it('cmdline default ', function() + -- local fallback = keymap.fallback(0, 'c', keymap.get_map('c', '')) + -- local state = run_fallback(':', fallback) + -- assert.are.same({ '' }, state.buffer) + -- assert.are.same({ 1, 0 }, state.cursor) + -- end) + end) + + describe('recursive', function() + it('non-expr', function() + vim.api.nvim_buf_set_keymap(0, 'i', '(', '()', { + expr = false, + noremap = false, + silent = true, + }) + local fallback = keymap.fallback(0, 'i', keymap.get_map('i', '(')) + local state = run_fallback('i', fallback) + assert.are.same({ '()' }, state.buffer) + assert.are.same({ 1, 1 }, state.cursor) + end) + + it('expr', function() + vim.api.nvim_buf_set_keymap(0, 'i', '(', '"()"', { + expr = true, + noremap = false, + silent = true, + }) + local fallback = keymap.fallback(0, 'i', keymap.get_map('i', '(')) + local state = run_fallback('i', fallback) + assert.are.same({ '()' }, state.buffer) + assert.are.same({ 1, 1 }, state.cursor) + end) + + it('expr-callback', function() + pcall(function() + vim.api.nvim_buf_set_keymap(0, 'i', '(', '', { + expr = true, + noremap = false, + silent = true, + callback = function() + return keymap.t('()') + end, + }) + local fallback = keymap.fallback(0, 'i', keymap.get_map('i', '(')) + local state = run_fallback('i', fallback) + assert.are.same({ '()' }, state.buffer) + assert.are.same({ 1, 1 }, state.cursor) + end) + end) + end) + end) + + describe('realworld', function() + before_each(spec.before) + + it('#226', function() + keymap.listen('i', '', function(_, fallback) + fallback() + end) + vim.api.nvim_feedkeys(keymap.t('iaiueoa'), 'tx', true) + assert.are.same({ 'aiueo', 'aiueo' }, vim.api.nvim_buf_get_lines(0, 0, -1, true)) + end) + + it('#414', function() + keymap.listen('i', '', function() + vim.api.nvim_feedkeys(keymap.t(''), 'int', true) + end) + vim.api.nvim_feedkeys(keymap.t('iaiueoa'), 'tx', true) + assert.are.same({ 'aiueo', 'aiueo' }, vim.api.nvim_buf_get_lines(0, 0, -1, true)) + end) + + it('#744', function() + vim.api.nvim_buf_set_keymap(0, 'i', '', 'recursive', { + noremap = true, + }) + vim.api.nvim_buf_set_keymap(0, 'i', '', 'recursive', { + noremap = false, + }) + keymap.listen('i', '', function(_, fallback) + fallback() + end) + feedkeys.call(keymap.t('i'), 'tx') + assert.are.same({ '', 'recursive' }, vim.api.nvim_buf_get_lines(0, 0, -1, true)) + end) + end) +end) diff --git a/start/cmp/lua/cmp/utils/misc.lua b/start/cmp/lua/cmp/utils/misc.lua new file mode 100644 index 0000000..7c6d0e7 --- /dev/null +++ b/start/cmp/lua/cmp/utils/misc.lua @@ -0,0 +1,253 @@ +local misc = {} + +---Create once callback +---@param callback function +---@return function +misc.once = function(callback) + local done = false + return function(...) + if done then + return + end + done = true + callback(...) + end +end + +---Return concatenated list +---@param list1 any[] +---@param list2 any[] +---@return any[] +misc.concat = function(list1, list2) + local new_list = {} + for _, v in ipairs(list1) do + table.insert(new_list, v) + end + for _, v in ipairs(list2) do + table.insert(new_list, v) + end + return new_list +end + +---Repeat values +---@generic T +---@param str_or_tbl T +---@param count number +---@return T +misc.rep = function(str_or_tbl, count) + if type(str_or_tbl) == 'string' then + return string.rep(str_or_tbl, count) + end + local rep = {} + for _ = 1, count do + for _, v in ipairs(str_or_tbl) do + table.insert(rep, v) + end + end + return rep +end + +---Return the valu is empty or not. +---@param v any +---@return boolean +misc.empty = function(v) + if not v then + return true + end + if v == vim.NIL then + return true + end + if type(v) == 'string' and v == '' then + return true + end + if type(v) == 'table' and vim.tbl_isempty(v) then + return true + end + if type(v) == 'number' and v == 0 then + return true + end + return false +end + +---The symbol to remove key in misc.merge. +misc.none = vim.NIL + +---Merge two tables recursively +---@generic T +---@param v1 T +---@param v2 T +---@return T +misc.merge = function(v1, v2) + local merge1 = type(v1) == 'table' and (not vim.tbl_islist(v1) or vim.tbl_isempty(v1)) + local merge2 = type(v2) == 'table' and (not vim.tbl_islist(v2) or vim.tbl_isempty(v2)) + if merge1 and merge2 then + local new_tbl = {} + for k, v in pairs(v2) do + new_tbl[k] = misc.merge(v1[k], v) + end + for k, v in pairs(v1) do + if v2[k] == nil and v ~= misc.none then + new_tbl[k] = v + end + end + return new_tbl + end + if v1 == misc.none then + return nil + end + if v1 == nil then + if v2 == misc.none then + return nil + else + return v2 + end + end + if v1 == true then + if merge2 then + return v2 + end + return {} + end + + return v1 +end + +---Generate id for group name +misc.id = setmetatable({ + group = {}, +}, { + __call = function(_, group) + misc.id.group[group] = misc.id.group[group] or 0 + misc.id.group[group] = misc.id.group[group] + 1 + return misc.id.group[group] + end, +}) + +---Check the value is nil or not. +---@param v boolean +---@return boolean +misc.safe = function(v) + if v == nil or v == vim.NIL then + return nil + end + return v +end + +---Treat 1/0 as bool value +---@param v boolean|1|0 +---@param def boolean +---@return boolean +misc.bool = function(v, def) + if misc.safe(v) == nil then + return def + end + return v == true or v == 1 +end + +---Set value to deep object +---@param t table +---@param keys string[] +---@param v any +misc.set = function(t, keys, v) + local c = t + for i = 1, #keys - 1 do + local key = keys[i] + c[key] = misc.safe(c[key]) or {} + c = c[key] + end + c[keys[#keys]] = v +end + +---Copy table +---@generic T +---@param tbl T +---@return T +misc.copy = function(tbl) + if type(tbl) ~= 'table' then + return tbl + end + + if vim.tbl_islist(tbl) then + local copy = {} + for i, value in ipairs(tbl) do + copy[i] = misc.copy(value) + end + return copy + end + + local copy = {} + for key, value in pairs(tbl) do + copy[key] = misc.copy(value) + end + return copy +end + +---Safe version of vim.str_utfindex +---@param text string +---@param vimindex number|nil +---@return number +misc.to_utfindex = function(text, vimindex) + vimindex = vimindex or #text + 1 + return vim.str_utfindex(text, math.max(0, math.min(vimindex - 1, #text))) +end + +---Safe version of vim.str_byteindex +---@param text string +---@param utfindex number +---@return number +misc.to_vimindex = function(text, utfindex) + utfindex = utfindex or #text + for i = utfindex, 1, -1 do + local s, v = pcall(function() + return vim.str_byteindex(text, i) + 1 + end) + if s then + return v + end + end + return utfindex + 1 +end + +---Mark the function as deprecated +misc.deprecated = function(fn, msg) + local printed = false + return function(...) + if not printed then + print(msg) + printed = true + end + return fn(...) + end +end + +--Redraw +misc.redraw = setmetatable({ + doing = false, + force = false, + termcode = vim.api.nvim_replace_termcodes('', true, true, true), +}, { + __call = function(self, force) + if vim.tbl_contains({ '/', '?' }, vim.fn.getcmdtype()) then + if vim.o.incsearch then + return vim.api.nvim_feedkeys(self.termcode, 'in', true) + end + end + + if self.doing then + return + end + self.doing = true + self.force = not not force + vim.schedule(function() + if self.force then + vim.cmd([[redraw!]]) + else + vim.cmd([[redraw]]) + end + self.doing = false + self.force = false + end) + end, +}) + +return misc diff --git a/start/cmp/lua/cmp/utils/misc_spec.lua b/start/cmp/lua/cmp/utils/misc_spec.lua new file mode 100644 index 0000000..f687155 --- /dev/null +++ b/start/cmp/lua/cmp/utils/misc_spec.lua @@ -0,0 +1,63 @@ +local spec = require('cmp.utils.spec') + +local misc = require('cmp.utils.misc') + +describe('misc', function() + before_each(spec.before) + + it('merge', function() + local merged + merged = misc.merge({ + a = {}, + }, { + a = { + b = 1, + }, + }) + assert.are.equal(merged.a.b, 1) + + merged = misc.merge({ + a = { + i = 1, + }, + }, { + a = { + c = 2, + }, + }) + assert.are.equal(merged.a.i, 1) + assert.are.equal(merged.a.c, 2) + + merged = misc.merge({ + a = false, + }, { + a = { + b = 1, + }, + }) + assert.are.equal(merged.a, false) + + merged = misc.merge({ + a = misc.none, + }, { + a = { + b = 1, + }, + }) + assert.are.equal(merged.a, nil) + + merged = misc.merge({ + a = misc.none, + }, { + a = nil, + }) + assert.are.equal(merged.a, nil) + + merged = misc.merge({ + a = nil, + }, { + a = misc.none, + }) + assert.are.equal(merged.a, nil) + end) +end) diff --git a/start/cmp/lua/cmp/utils/pattern.lua b/start/cmp/lua/cmp/utils/pattern.lua new file mode 100644 index 0000000..1481e84 --- /dev/null +++ b/start/cmp/lua/cmp/utils/pattern.lua @@ -0,0 +1,28 @@ +local pattern = {} + +pattern._regexes = {} + +pattern.regex = function(p) + if not pattern._regexes[p] then + pattern._regexes[p] = vim.regex(p) + end + return pattern._regexes[p] +end + +pattern.offset = function(p, text) + local s, e = pattern.regex(p):match_str(text) + if s then + return s + 1, e + 1 + end + return nil, nil +end + +pattern.matchstr = function(p, text) + local s, e = pattern.offset(p, text) + if s then + return string.sub(text, s, e) + end + return nil +end + +return pattern diff --git a/start/cmp/lua/cmp/utils/spec.lua b/start/cmp/lua/cmp/utils/spec.lua new file mode 100644 index 0000000..a4b2c83 --- /dev/null +++ b/start/cmp/lua/cmp/utils/spec.lua @@ -0,0 +1,92 @@ +local context = require('cmp.context') +local source = require('cmp.source') +local types = require('cmp.types') +local config = require('cmp.config') + +local spec = {} + +spec.before = function() + vim.cmd([[ + bdelete! + enew! + imapclear + imapclear + cmapclear + cmapclear + smapclear + smapclear + xmapclear + xmapclear + tmapclear + tmapclear + setlocal noswapfile + setlocal virtualedit=all + setlocal completeopt=menu,menuone,noselect + ]]) + config.set_global({ + sources = { + { name = 'spec' }, + }, + snippet = { + expand = function(args) + local ctx = context.new() + vim.api.nvim_buf_set_text(ctx.bufnr, ctx.cursor.row - 1, ctx.cursor.col - 1, ctx.cursor.row - 1, ctx.cursor.col - 1, vim.split(string.gsub(args.body, '%$0', ''), '\n')) + for i, t in ipairs(vim.split(args.body, '\n')) do + local s = string.find(t, '$0', 1, true) + if s then + if i == 1 then + vim.api.nvim_win_set_cursor(0, { ctx.cursor.row, ctx.cursor.col + s - 2 }) + else + vim.api.nvim_win_set_cursor(0, { ctx.cursor.row + i - 1, s - 1 }) + end + break + end + end + end, + }, + }) + config.set_cmdline({ + sources = { + { name = 'spec' }, + }, + }, ':') +end + +spec.state = function(text, row, col) + vim.fn.setline(1, text) + vim.fn.cursor(row, col) + local ctx = context.empty() + local s = source.new('spec', { + complete = function() end, + }) + return { + context = function() + return ctx + end, + source = function() + return s + end, + backspace = function() + vim.fn.feedkeys('x', 'nx') + vim.fn.feedkeys('h', 'nx') + ctx = context.new(ctx, { reason = types.cmp.ContextReason.Auto }) + s:complete(ctx, function() end) + return ctx + end, + input = function(char) + vim.fn.feedkeys(('i%s'):format(char), 'nx') + vim.fn.feedkeys(string.rep('l', #char), 'nx') + ctx.prev_context = nil + ctx = context.new(ctx, { reason = types.cmp.ContextReason.Auto }) + s:complete(ctx, function() end) + return ctx + end, + manual = function() + ctx = context.new(ctx, { reason = types.cmp.ContextReason.Manual }) + s:complete(ctx, function() end) + return ctx + end, + } +end + +return spec diff --git a/start/cmp/lua/cmp/utils/str.lua b/start/cmp/lua/cmp/utils/str.lua new file mode 100644 index 0000000..bca210c --- /dev/null +++ b/start/cmp/lua/cmp/utils/str.lua @@ -0,0 +1,178 @@ +local char = require('cmp.utils.char') + +local str = {} + +local INVALIDS = {} +INVALIDS[string.byte("'")] = true +INVALIDS[string.byte('"')] = true +INVALIDS[string.byte('=')] = true +INVALIDS[string.byte('$')] = true +INVALIDS[string.byte('(')] = true +INVALIDS[string.byte('[')] = true +INVALIDS[string.byte('<')] = true +INVALIDS[string.byte('{')] = true +INVALIDS[string.byte(' ')] = true +INVALIDS[string.byte('\t')] = true +INVALIDS[string.byte('\n')] = true +INVALIDS[string.byte('\r')] = true + +local NR_BYTE = string.byte('\n') + +local PAIRS = {} +PAIRS[string.byte('<')] = string.byte('>') +PAIRS[string.byte('[')] = string.byte(']') +PAIRS[string.byte('(')] = string.byte(')') +PAIRS[string.byte('{')] = string.byte('}') +PAIRS[string.byte('"')] = string.byte('"') +PAIRS[string.byte("'")] = string.byte("'") + +---Return if specified text has prefix or not +---@param text string +---@param prefix string +---@return boolean +str.has_prefix = function(text, prefix) + if #text < #prefix then + return false + end + for i = 1, #prefix do + if not char.match(string.byte(text, i), string.byte(prefix, i)) then + return false + end + end + return true +end + +---get_common_string +str.get_common_string = function(text1, text2) + local min = math.min(#text1, #text2) + for i = 1, min do + if not char.match(string.byte(text1, i), string.byte(text2, i)) then + return string.sub(text1, 1, i - 1) + end + end + return string.sub(text1, 1, min) +end + +---Remove suffix +---@param text string +---@param suffix string +---@return string +str.remove_suffix = function(text, suffix) + if #text < #suffix then + return text + end + + local i = 0 + while i < #suffix do + if string.byte(text, #text - i) ~= string.byte(suffix, #suffix - i) then + return text + end + i = i + 1 + end + return string.sub(text, 1, -#suffix - 1) +end + +---trim +---@param text string +---@return string +str.trim = function(text) + local s = 1 + for i = 1, #text do + if not char.is_white(string.byte(text, i)) then + s = i + break + end + end + + local e = #text + for i = #text, 1, -1 do + if not char.is_white(string.byte(text, i)) then + e = i + break + end + end + if s == 1 and e == #text then + return text + end + return string.sub(text, s, e) +end + +---get_word +---@param text string +---@param stop_char number +---@param min_length number +---@return string +str.get_word = function(text, stop_char, min_length) + min_length = min_length or 0 + + local has_alnum = false + local stack = {} + local word = {} + local add = function(c) + table.insert(word, string.char(c)) + if stack[#stack] == c then + table.remove(stack, #stack) + else + if PAIRS[c] then + table.insert(stack, c) + end + end + end + for i = 1, #text do + local c = string.byte(text, i, i) + if #word < min_length then + table.insert(word, string.char(c)) + elseif not INVALIDS[c] then + add(c) + has_alnum = has_alnum or char.is_alnum(c) + elseif not has_alnum then + add(c) + elseif #stack ~= 0 then + add(c) + if has_alnum and #stack == 0 then + break + end + else + break + end + end + if stop_char and word[#word] == string.char(stop_char) then + table.remove(word, #word) + end + return table.concat(word, '') +end + +---Oneline +---@param text string +---@return string +str.oneline = function(text) + for i = 1, #text do + if string.byte(text, i) == NR_BYTE then + return string.sub(text, 1, i - 1) + end + end + return text +end + +---Escape special chars +---@param text string +---@param chars string[] +---@return string +str.escape = function(text, chars) + table.insert(chars, '\\') + local escaped = {} + local i = 1 + while i <= #text do + local c = string.sub(text, i, i) + if vim.tbl_contains(chars, c) then + table.insert(escaped, '\\') + table.insert(escaped, c) + else + table.insert(escaped, c) + end + i = i + 1 + end + return table.concat(escaped, '') +end + +return str diff --git a/start/cmp/lua/cmp/utils/str_spec.lua b/start/cmp/lua/cmp/utils/str_spec.lua new file mode 100644 index 0000000..1a21855 --- /dev/null +++ b/start/cmp/lua/cmp/utils/str_spec.lua @@ -0,0 +1,29 @@ +local str = require('cmp.utils.str') + +describe('utils.str', function() + it('get_word', function() + assert.are.equal(str.get_word('print'), 'print') + assert.are.equal(str.get_word('$variable'), '$variable') + assert.are.equal(str.get_word('print()'), 'print') + assert.are.equal(str.get_word('["cmp#confirm"]'), '["cmp#confirm"]') + assert.are.equal(str.get_word('"devDependencies":', string.byte('"')), '"devDependencies') + assert.are.equal(str.get_word('"devDependencies": ${1},', string.byte('"')), '"devDependencies') + assert.are.equal(str.get_word('#[cfg(test)]'), '#[cfg(test)]') + assert.are.equal(str.get_word('import { GetStaticProps$1 } from "next";', nil, 9), 'import { GetStaticProps') + end) + + it('remove_suffix', function() + assert.are.equal(str.remove_suffix('log()', '$0'), 'log()') + assert.are.equal(str.remove_suffix('log()$0', '$0'), 'log()') + assert.are.equal(str.remove_suffix('log()${0}', '${0}'), 'log()') + assert.are.equal(str.remove_suffix('log()${0:placeholder}', '${0}'), 'log()${0:placeholder}') + end) + + it('escape', function() + assert.are.equal(str.escape('plain', {}), 'plain') + assert.are.equal(str.escape('plain\\', {}), 'plain\\\\') + assert.are.equal(str.escape('plain\\"', {}), 'plain\\\\"') + assert.are.equal(str.escape('pla"in', { '"' }), 'pla\\"in') + assert.are.equal(str.escape('call("")', { '"' }), 'call(\\"\\")') + end) +end) diff --git a/start/cmp/lua/cmp/utils/window.lua b/start/cmp/lua/cmp/utils/window.lua new file mode 100644 index 0000000..a8a271e --- /dev/null +++ b/start/cmp/lua/cmp/utils/window.lua @@ -0,0 +1,313 @@ +local cache = require('cmp.utils.cache') +local misc = require('cmp.utils.misc') +local buffer = require('cmp.utils.buffer') +local api = require('cmp.utils.api') + +---@class cmp.WindowStyle +---@field public relative string +---@field public row number +---@field public col number +---@field public width number +---@field public height number +---@field public border string|string[]|nil +---@field public zindex number|nil + +---@class cmp.Window +---@field public name string +---@field public win number|nil +---@field public thumb_win number|nil +---@field public sbar_win number|nil +---@field public style cmp.WindowStyle +---@field public opt table +---@field public buffer_opt table +---@field public cache cmp.Cache +local window = {} + +---new +---@return cmp.Window +window.new = function() + local self = setmetatable({}, { __index = window }) + self.name = misc.id('cmp.utils.window.new') + self.win = nil + self.sbar_win = nil + self.thumb_win = nil + self.style = {} + self.cache = cache.new() + self.opt = {} + self.buffer_opt = {} + return self +end + +---Set window option. +---NOTE: If the window already visible, immediately applied to it. +---@param key string +---@param value any +window.option = function(self, key, value) + if vim.fn.exists('+' .. key) == 0 then + return + end + + if value == nil then + return self.opt[key] + end + + self.opt[key] = value + if self:visible() then + vim.api.nvim_win_set_option(self.win, key, value) + end +end + +---Set buffer option. +---NOTE: If the buffer already visible, immediately applied to it. +---@param key string +---@param value any +window.buffer_option = function(self, key, value) + if vim.fn.exists('+' .. key) == 0 then + return + end + + if value == nil then + return self.buffer_opt[key] + end + + self.buffer_opt[key] = value + local existing_buf = buffer.get(self.name) + if existing_buf then + vim.api.nvim_buf_set_option(existing_buf, key, value) + end +end + +---Set style. +---@param style cmp.WindowStyle +window.set_style = function(self, style) + self.style = style + local info = self:info() + + if vim.o.lines and vim.o.lines <= info.row + info.height + 1 then + self.style.height = vim.o.lines - info.row - info.border_info.vert - 1 + end + + self.style.zindex = self.style.zindex or 1 +end + +---Return buffer id. +---@return number +window.get_buffer = function(self) + local buf, created_new = buffer.ensure(self.name) + if created_new then + for k, v in pairs(self.buffer_opt) do + vim.api.nvim_buf_set_option(buf, k, v) + end + end + return buf +end + +---Open window +---@param style cmp.WindowStyle +window.open = function(self, style) + if style then + self:set_style(style) + end + + if self.style.width < 1 or self.style.height < 1 then + return + end + + if self.win and vim.api.nvim_win_is_valid(self.win) then + vim.api.nvim_win_set_config(self.win, self.style) + else + local s = misc.copy(self.style) + s.noautocmd = true + self.win = vim.api.nvim_open_win(self:get_buffer(), false, s) + for k, v in pairs(self.opt) do + vim.api.nvim_win_set_option(self.win, k, v) + end + end + self:update() +end + +---Update +window.update = function(self) + local info = self:info() + if info.scrollable then + -- Draw the background of the scrollbar + + if not info.border_info.visible then + local style = { + relative = 'editor', + style = 'minimal', + width = 1, + height = self.style.height, + row = info.row, + col = info.col + info.width - info.scrollbar_offset, -- info.col was already contained the scrollbar offset. + zindex = (self.style.zindex and (self.style.zindex + 1) or 1), + } + if self.sbar_win and vim.api.nvim_win_is_valid(self.sbar_win) then + vim.api.nvim_win_set_config(self.sbar_win, style) + else + style.noautocmd = true + self.sbar_win = vim.api.nvim_open_win(buffer.ensure(self.name .. 'sbar_buf'), false, style) + vim.api.nvim_win_set_option(self.sbar_win, 'winhighlight', 'EndOfBuffer:PmenuSbar,NormalFloat:PmenuSbar') + end + end + + -- Draw the scrollbar thumb + local thumb_height = math.floor(info.inner_height * (info.inner_height / self:get_content_height()) + 0.5) + local thumb_offset = math.floor(info.inner_height * (vim.fn.getwininfo(self.win)[1].topline / self:get_content_height())) + + local style = { + relative = 'editor', + style = 'minimal', + width = 1, + height = math.max(1, thumb_height), + row = info.row + thumb_offset + (info.border_info.visible and info.border_info.top or 0), + col = info.col + info.width - 1, -- info.col was already added scrollbar offset. + zindex = (self.style.zindex and (self.style.zindex + 2) or 2), + } + if self.thumb_win and vim.api.nvim_win_is_valid(self.thumb_win) then + vim.api.nvim_win_set_config(self.thumb_win, style) + else + style.noautocmd = true + self.thumb_win = vim.api.nvim_open_win(buffer.ensure(self.name .. 'thumb_buf'), false, style) + vim.api.nvim_win_set_option(self.thumb_win, 'winhighlight', 'EndOfBuffer:PmenuThumb,NormalFloat:PmenuThumb') + end + else + if self.sbar_win and vim.api.nvim_win_is_valid(self.sbar_win) then + vim.api.nvim_win_hide(self.sbar_win) + self.sbar_win = nil + end + if self.thumb_win and vim.api.nvim_win_is_valid(self.thumb_win) then + vim.api.nvim_win_hide(self.thumb_win) + self.thumb_win = nil + end + end + + -- In cmdline, vim does not redraw automatically. + if api.is_cmdline_mode() then + vim.api.nvim_win_call(self.win, function() + misc.redraw() + end) + end +end + +---Close window +window.close = function(self) + if self.win and vim.api.nvim_win_is_valid(self.win) then + if self.win and vim.api.nvim_win_is_valid(self.win) then + vim.api.nvim_win_hide(self.win) + self.win = nil + end + if self.sbar_win and vim.api.nvim_win_is_valid(self.sbar_win) then + vim.api.nvim_win_hide(self.sbar_win) + self.sbar_win = nil + end + if self.thumb_win and vim.api.nvim_win_is_valid(self.thumb_win) then + vim.api.nvim_win_hide(self.thumb_win) + self.thumb_win = nil + end + end +end + +---Return the window is visible or not. +window.visible = function(self) + return self.win and vim.api.nvim_win_is_valid(self.win) +end + +---Return win info. +window.info = function(self) + local border_info = self:get_border_info() + local info = { + row = self.style.row, + col = self.style.col, + width = self.style.width + border_info.left + border_info.right, + height = self.style.height + border_info.top + border_info.bottom, + inner_width = self.style.width, + inner_height = self.style.height, + border_info = border_info, + scrollable = false, + scrollbar_offset = 0, + } + + if self:get_content_height() > info.inner_height then + info.scrollable = true + if not border_info.visible then + info.scrollbar_offset = 1 + info.width = info.width + 1 + end + end + + return info +end + +---Return border information. +---@return { top: number, left: number, right: number, bottom: number, vert: number, horiz: number, visible: boolean } +window.get_border_info = function(self) + local border = self.style.border + if not border or border == 'none' then + return { + top = 0, + left = 0, + right = 0, + bottom = 0, + vert = 0, + horiz = 0, + visible = false, + } + end + if type(border) == 'string' then + if border == 'shadow' then + return { + top = 0, + left = 0, + right = 1, + bottom = 1, + vert = 1, + horiz = 1, + visible = false, + } + end + return { + top = 1, + left = 1, + right = 1, + bottom = 1, + vert = 2, + horiz = 2, + visible = true, + } + end + + local new_border = {} + while #new_border <= 8 do + for _, b in ipairs(border) do + table.insert(new_border, type(b) == 'string' and b or b[1]) + end + end + local info = {} + info.top = new_border[2] == '' and 0 or 1 + info.right = new_border[4] == '' and 0 or 1 + info.bottom = new_border[6] == '' and 0 or 1 + info.left = new_border[8] == '' and 0 or 1 + info.vert = info.top + info.bottom + info.horiz = info.left + info.right + info.visible = not (vim.tbl_contains({ '', ' ' }, new_border[2]) and vim.tbl_contains({ '', ' ' }, new_border[4]) and vim.tbl_contains({ '', ' ' }, new_border[6]) and vim.tbl_contains({ '', ' ' }, new_border[8])) + return info +end + +---Get scroll height. +---NOTE: The result of vim.fn.strdisplaywidth depends on the buffer it was called in (see comment in cmp.Entry.get_view). +---@return number +window.get_content_height = function(self) + if not self:option('wrap') then + return vim.api.nvim_buf_line_count(self:get_buffer()) + end + local height = 0 + vim.api.nvim_buf_call(self:get_buffer(), function() + for _, text in ipairs(vim.api.nvim_buf_get_lines(self:get_buffer(), 0, -1, false)) do + height = height + math.max(1, math.ceil(vim.fn.strdisplaywidth(text) / self.style.width)) + end + end) + return height +end + +return window diff --git a/start/cmp/lua/cmp/view.lua b/start/cmp/lua/cmp/view.lua new file mode 100644 index 0000000..981378b --- /dev/null +++ b/start/cmp/lua/cmp/view.lua @@ -0,0 +1,243 @@ +local config = require('cmp.config') +local async = require('cmp.utils.async') +local event = require('cmp.utils.event') +local keymap = require('cmp.utils.keymap') +local docs_view = require('cmp.view.docs_view') +local custom_entries_view = require('cmp.view.custom_entries_view') +local wildmenu_entries_view = require('cmp.view.wildmenu_entries_view') +local native_entries_view = require('cmp.view.native_entries_view') +local ghost_text_view = require('cmp.view.ghost_text_view') + +---@class cmp.View +---@field public event cmp.Event +---@field private resolve_dedup cmp.AsyncDedup +---@field private native_entries_view cmp.NativeEntriesView +---@field private custom_entries_view cmp.CustomEntriesView +---@field private wildmenu_entries_view cmp.CustomEntriesView +---@field private change_dedup cmp.AsyncDedup +---@field private docs_view cmp.DocsView +---@field private ghost_text_view cmp.GhostTextView +local view = {} + +---Create menu +view.new = function() + local self = setmetatable({}, { __index = view }) + self.resolve_dedup = async.dedup() + self.custom_entries_view = custom_entries_view.new() + self.native_entries_view = native_entries_view.new() + self.wildmenu_entries_view = wildmenu_entries_view.new() + self.docs_view = docs_view.new() + self.ghost_text_view = ghost_text_view.new() + self.event = event.new() + + return self +end + +---Return the view components are available or not. +---@return boolean +view.ready = function(self) + return self:_get_entries_view():ready() +end + +---OnChange handler. +view.on_change = function(self) + self:_get_entries_view():on_change() +end + +---Open menu +---@param ctx cmp.Context +---@param sources cmp.Source[] +view.open = function(self, ctx, sources) + local source_group_map = {} + for _, s in ipairs(sources) do + local group_index = s:get_source_config().group_index or 0 + if not source_group_map[group_index] then + source_group_map[group_index] = {} + end + table.insert(source_group_map[group_index], s) + end + + local group_indexes = vim.tbl_keys(source_group_map) + table.sort(group_indexes, function(a, b) + return a ~= b and (a < b) or nil + end) + + local entries = {} + for _, group_index in ipairs(group_indexes) do + local source_group = source_group_map[group_index] or {} + + -- check the source triggered by character + local has_triggered_by_symbol_source = false + for _, s in ipairs(source_group) do + if #s:get_entries(ctx) > 0 then + if s.is_triggered_by_symbol then + has_triggered_by_symbol_source = true + break + end + end + end + + -- create filtered entries. + local offset = ctx.cursor.col + for i, s in ipairs(source_group) do + if s.offset <= ctx.cursor.col then + if not has_triggered_by_symbol_source or s.is_triggered_by_symbol then + -- source order priority bonus. + local priority = s:get_source_config().priority or ((#source_group - (i - 1)) * config.get().sorting.priority_weight) + + for _, e in ipairs(s:get_entries(ctx)) do + e.score = e.score + priority + table.insert(entries, e) + offset = math.min(offset, e:get_offset()) + end + end + end + end + + -- sort. + local comparetors = config.get().sorting.comparators + table.sort(entries, function(e1, e2) + for _, fn in ipairs(comparetors) do + local diff = fn(e1, e2) + if diff ~= nil then + return diff + end + end + end) + + -- open + if #entries > 0 then + self:_get_entries_view():open(offset, entries) + break + end + end + + -- complete_done. + if #entries == 0 then + self:close() + end +end + +---Close menu +view.close = function(self) + if self:visible() then + self.event:emit('complete_done', { + entry = self:_get_entries_view():get_selected_entry(), + }) + end + self:_get_entries_view():close() + self.docs_view:close() + self.ghost_text_view:hide() +end + +---Abort menu +view.abort = function(self) + self:_get_entries_view():abort() + self.docs_view:close() + self.ghost_text_view:hide() +end + +---Return the view is visible or not. +---@return boolean +view.visible = function(self) + return self:_get_entries_view():visible() +end + +---Scroll documentation window if possible. +---@param delta number +view.scroll_docs = function(self, delta) + self.docs_view:scroll(delta) +end + +---Select prev menu item. +---@param option cmp.SelectOption +view.select_next_item = function(self, option) + self:_get_entries_view():select_next_item(option) +end + +---Select prev menu item. +---@param option cmp.SelectOption +view.select_prev_item = function(self, option) + self:_get_entries_view():select_prev_item(option) +end + +---Get offset. +view.get_offset = function(self) + return self:_get_entries_view():get_offset() +end + +---Get entries. +---@return cmp.Entry[] +view.get_entries = function(self) + return self:_get_entries_view():get_entries() +end + +---Get first entry +---@param self cmp.Entry|nil +view.get_first_entry = function(self) + return self:_get_entries_view():get_first_entry() +end + +---Get current selected entry +---@return cmp.Entry|nil +view.get_selected_entry = function(self) + return self:_get_entries_view():get_selected_entry() +end + +---Get current active entry +---@return cmp.Entry|nil +view.get_active_entry = function(self) + return self:_get_entries_view():get_active_entry() +end + +---Return current configured entries_view +---@return cmp.CustomEntriesView|cmp.NativeEntriesView +view._get_entries_view = function(self) + self.native_entries_view.event:clear() + self.custom_entries_view.event:clear() + self.wildmenu_entries_view.event:clear() + + local c = config.get() + local v = self.custom_entries_view + if (c.view and c.view.entries and (c.view.entries.name or c.view.entries)) == 'wildmenu' then + v = self.wildmenu_entries_view + elseif (c.view and c.view.entries and (c.view.entries.name or c.view.entries)) == 'native' then + v = self.native_entries_view + end + v.event:on('change', function() + self:on_entry_change() + end) + return v +end + +---On entry change +view.on_entry_change = async.throttle(function(self) + if not self:visible() then + return + end + local e = self:get_selected_entry() + if e then + for _, c in ipairs(config.get().confirmation.get_commit_characters(e:get_commit_characters())) do + keymap.listen('i', c, function(...) + self.event:emit('keymap', ...) + end) + end + e:resolve(vim.schedule_wrap(self.resolve_dedup(function() + if not self:visible() then + return + end + self.docs_view:open(e, self:_get_entries_view():info()) + end))) + else + self.docs_view:close() + end + + e = e or self:get_first_entry() + if e then + self.ghost_text_view:show(e) + else + self.ghost_text_view:hide() + end +end, 20) + +return view diff --git a/start/cmp/lua/cmp/view/custom_entries_view.lua b/start/cmp/lua/cmp/view/custom_entries_view.lua new file mode 100644 index 0000000..8020a9b --- /dev/null +++ b/start/cmp/lua/cmp/view/custom_entries_view.lua @@ -0,0 +1,409 @@ +local event = require('cmp.utils.event') +local autocmd = require('cmp.utils.autocmd') +local feedkeys = require('cmp.utils.feedkeys') +local window = require('cmp.utils.window') +local config = require('cmp.config') +local types = require('cmp.types') +local keymap = require('cmp.utils.keymap') +local misc = require('cmp.utils.misc') +local api = require('cmp.utils.api') + +local SIDE_PADDING = 1 + +local DEFAULT_HEIGHT = 10 -- @see https://github.com/vim/vim/blob/master/src/popupmenu.c#L45 + +---@class cmp.CustomEntriesView +---@field private entries_win cmp.Window +---@field private offset number +---@field private active boolean +---@field private entries cmp.Entry[] +---@field private column_width any +---@field public event cmp.Event +local custom_entries_view = {} + +custom_entries_view.ns = vim.api.nvim_create_namespace('cmp.view.custom_entries_view') + +custom_entries_view.new = function() + local self = setmetatable({}, { __index = custom_entries_view }) + + self.entries_win = window.new() + self.entries_win:option('conceallevel', 2) + self.entries_win:option('concealcursor', 'n') + self.entries_win:option('cursorlineopt', 'line') + self.entries_win:option('foldenable', false) + self.entries_win:option('wrap', false) + self.entries_win:option('scrolloff', 0) + -- This is done so that strdisplaywidth calculations for lines in the + -- custom_entries_view window exactly match with what is really displayed, + -- see comment in cmp.Entry.get_view. Setting tabstop to 1 makes all tabs be + -- always rendered one column wide, which removes the unpredictability coming + -- from variable width of the tab character. + self.entries_win:buffer_option('tabstop', 1) + self.event = event.new() + self.offset = -1 + self.active = false + self.entries = {} + self.bottom_up = false + + autocmd.subscribe( + 'CompleteChanged', + vim.schedule_wrap(function() + if self:visible() and vim.fn.pumvisible() == 1 then + self:close() + end + end) + ) + + vim.api.nvim_set_decoration_provider(custom_entries_view.ns, { + on_win = function(_, win, buf, top, bot) + if win ~= self.entries_win.win or buf ~= self.entries_win:get_buffer() then + return + end + + local fields = config.get().formatting.fields + for i = top, bot do + local e = self.entries[i + 1] + if e then + local v = e:get_view(self.offset, buf) + local o = SIDE_PADDING + local a = 0 + for _, field in ipairs(fields) do + if field == types.cmp.ItemField.Abbr then + a = o + end + vim.api.nvim_buf_set_extmark(buf, custom_entries_view.ns, i, o, { + end_line = i, + end_col = o + v[field].bytes, + hl_group = v[field].hl_group, + hl_mode = 'combine', + ephemeral = true, + }) + o = o + v[field].bytes + (self.column_width[field] - v[field].width) + 1 + end + + for _, m in ipairs(e.matches or {}) do + vim.api.nvim_buf_set_extmark(buf, custom_entries_view.ns, i, a + m.word_match_start - 1, { + end_line = i, + end_col = a + m.word_match_end, + hl_group = m.fuzzy and 'CmpItemAbbrMatchFuzzy' or 'CmpItemAbbrMatch', + hl_mode = 'combine', + ephemeral = true, + }) + end + end + end + end, + }) + + return self +end + +custom_entries_view.ready = function() + return vim.fn.pumvisible() == 0 +end + +custom_entries_view.on_change = function(self) + self.active = false +end + +custom_entries_view.is_direction_top_down = function(self) + local c = config.get() + if (c.view and c.view.entries and c.view.entries.selection_order) == 'top_down' then + return true + elseif c.view.entries == nil or c.view.entries.selection_order == nil then + return true + else + return not self.bottom_up + end +end + +custom_entries_view.open = function(self, offset, entries) + local completion = config.get().window.completion + self.offset = offset + self.entries = {} + self.column_width = { abbr = 0, kind = 0, menu = 0 } + + local entries_buf = self.entries_win:get_buffer() + local lines = {} + local dedup = {} + local preselect = 0 + for _, e in ipairs(entries) do + local view = e:get_view(offset, entries_buf) + if view.dup == 1 or not dedup[e.completion_item.label] then + dedup[e.completion_item.label] = true + self.column_width.abbr = math.max(self.column_width.abbr, view.abbr.width) + self.column_width.kind = math.max(self.column_width.kind, view.kind.width) + self.column_width.menu = math.max(self.column_width.menu, view.menu.width) + table.insert(self.entries, e) + table.insert(lines, ' ') + if preselect == 0 and e.completion_item.preselect then + preselect = #self.entries + end + end + end + vim.api.nvim_buf_set_lines(entries_buf, 0, -1, false, lines) + vim.api.nvim_buf_set_option(entries_buf, 'modified', false) + + local width = 0 + width = width + 1 + width = width + self.column_width.abbr + (self.column_width.kind > 0 and 1 or 0) + width = width + self.column_width.kind + (self.column_width.menu > 0 and 1 or 0) + width = width + self.column_width.menu + 1 + + local height = vim.api.nvim_get_option('pumheight') + height = height ~= 0 and height or #self.entries + height = math.min(height, #self.entries) + + local pos = api.get_screen_cursor() + local cursor = api.get_cursor() + local delta = cursor[2] + 1 - self.offset + local row, col = pos[1], pos[2] - delta - 1 + + local border_info = window.get_border_info({ style = completion }) + local border_offset_row = border_info.top + border_info.bottom + local border_offset_col = border_info.left + border_info.right + if math.floor(vim.o.lines * 0.5) <= row + border_offset_row and vim.o.lines - row - border_offset_row <= math.min(DEFAULT_HEIGHT, height) then + height = math.min(height, row - 1) + row = row - height - border_offset_row - 1 + if row < 0 then + height = height + row + end + end + if math.floor(vim.o.columns * 0.5) <= col + border_offset_col and vim.o.columns - col - border_offset_col <= width then + width = math.min(width, vim.o.columns - 1) + col = vim.o.columns - width - border_offset_col - 1 + if col < 0 then + width = width + col + end + end + + if pos[1] > row then + self.bottom_up = true + else + self.bottom_up = false + end + + if not self:is_direction_top_down() then + local n = #self.entries + for i = 1, math.floor(n / 2) do + self.entries[i], self.entries[n - i + 1] = self.entries[n - i + 1], self.entries[i] + end + if preselect ~= 0 then + preselect = #self.entries - preselect + 1 + end + end + + -- Apply window options (that might be changed) on the custom completion menu. + self.entries_win:option('winblend', vim.o.pumblend) + self.entries_win:option('winhighlight', completion.winhighlight) + self.entries_win:open({ + relative = 'editor', + style = 'minimal', + row = math.max(0, row), + col = math.max(0, col), + width = width, + height = height, + border = completion.border, + zindex = completion.zindex or 1001, + }) + -- always set cursor when starting. It will be adjusted on the call to _select + vim.api.nvim_win_set_cursor(self.entries_win.win, { 1, 0 }) + if preselect > 0 and config.get().preselect == types.cmp.PreselectMode.Item then + self:_select(preselect, { behavior = types.cmp.SelectBehavior.Select }) + elseif not string.match(config.get().completion.completeopt, 'noselect') then + if self:is_direction_top_down() then + self:_select(1, { behavior = types.cmp.SelectBehavior.Select }) + else + self:_select(#self.entries - 1, { behavior = types.cmp.SelectBehavior.Select }) + end + else + if self:is_direction_top_down() then + self:_select(0, { behavior = types.cmp.SelectBehavior.Select }) + else + self:_select(#self.entries + 1, { behavior = types.cmp.SelectBehavior.Select }) + end + end +end + +custom_entries_view.close = function(self) + self.prefix = nil + self.offset = -1 + self.active = false + self.entries = {} + self.entries_win:close() + self.bottom_up = false +end + +custom_entries_view.abort = function(self) + if self.prefix then + self:_insert(self.prefix) + end + feedkeys.call('', 'n', function() + self:close() + end) +end + +custom_entries_view.draw = function(self) + local info = vim.fn.getwininfo(self.entries_win.win)[1] + local topline = info.topline - 1 + local botline = info.topline + info.height - 1 + local texts = {} + local fields = config.get().formatting.fields + local entries_buf = self.entries_win:get_buffer() + for i = topline, botline - 1 do + local e = self.entries[i + 1] + if e then + local view = e:get_view(self.offset, entries_buf) + local text = {} + table.insert(text, string.rep(' ', SIDE_PADDING)) + for _, field in ipairs(fields) do + table.insert(text, view[field].text) + table.insert(text, string.rep(' ', 1 + self.column_width[field] - view[field].width)) + end + table.insert(text, string.rep(' ', SIDE_PADDING)) + table.insert(texts, table.concat(text, '')) + end + end + vim.api.nvim_buf_set_lines(entries_buf, topline, botline, false, texts) + vim.api.nvim_buf_set_option(entries_buf, 'modified', false) + + if api.is_cmdline_mode() then + vim.api.nvim_win_call(self.entries_win.win, function() + misc.redraw() + end) + end +end + +custom_entries_view.visible = function(self) + return self.entries_win:visible() +end + +custom_entries_view.info = function(self) + return self.entries_win:info() +end + +custom_entries_view.select_next_item = function(self, option) + if self:visible() then + local cursor = vim.api.nvim_win_get_cursor(self.entries_win.win)[1] + if self:is_direction_top_down() then + cursor = cursor + 1 + else + cursor = cursor - 1 + end + if not self.entries_win:option('cursorline') then + cursor = (self:is_direction_top_down() and 1) or #self.entries + elseif #self.entries < cursor then + cursor = (not self:is_direction_top_down() and #self.entries + 1) or 0 + end + self:_select(cursor, option) + end +end + +custom_entries_view.select_prev_item = function(self, option) + if self:visible() then + local cursor = vim.api.nvim_win_get_cursor(self.entries_win.win)[1] + if self:is_direction_top_down() then + cursor = cursor - 1 + else + cursor = cursor + 1 + end + if not self.entries_win:option('cursorline') then + cursor = (self:is_direction_top_down() and #self.entries) or 1 + elseif #self.entries < cursor then + cursor = (not self:is_direction_top_down() and 0) or #self.entries + 1 + end + self:_select(cursor, option) + end +end + +custom_entries_view.get_offset = function(self) + if self:visible() then + return self.offset + end + return nil +end + +custom_entries_view.get_entries = function(self) + if self:visible() then + return self.entries + end + return {} +end + +custom_entries_view.get_first_entry = function(self) + if self:visible() then + return (self:is_direction_top_down() and self.entries[1]) or self.entries[#self.entries] + end +end + +custom_entries_view.get_selected_entry = function(self) + if self:visible() and self.entries_win:option('cursorline') then + return self.entries[vim.api.nvim_win_get_cursor(self.entries_win.win)[1]] + end +end + +custom_entries_view.get_active_entry = function(self) + if self:visible() and self.active then + return self:get_selected_entry() + end +end + +custom_entries_view._select = function(self, cursor, option) + local is_insert = (option.behavior or types.cmp.SelectBehavior.Insert) == types.cmp.SelectBehavior.Insert + if is_insert and not self.active then + self.prefix = string.sub(api.get_current_line(), self.offset, api.get_cursor()[2]) or '' + end + + self.active = cursor > 0 and cursor <= #self.entries and is_insert + self.entries_win:option('cursorline', cursor > 0 and cursor <= #self.entries) + + vim.api.nvim_win_set_cursor(self.entries_win.win, { + math.max(math.min(cursor, #self.entries), 1), + 0, + }) + + if is_insert then + self:_insert(self.entries[cursor] and self.entries[cursor]:get_vim_item(self.offset).word or self.prefix) + end + + self.entries_win:update() + self:draw() + self.event:emit('change') +end + +custom_entries_view._insert = setmetatable({ + pending = false, +}, { + __call = function(this, self, word) + word = word or '' + if api.is_cmdline_mode() then + local cursor = api.get_cursor() + vim.api.nvim_feedkeys(keymap.backspace(string.sub(api.get_current_line(), self.offset, cursor[2])) .. word, 'int', true) + else + if this.pending then + return + end + this.pending = true + + local release = require('cmp').suspend() + feedkeys.call('', '', function() + local cursor = api.get_cursor() + local keys = {} + table.insert(keys, keymap.indentkeys()) + table.insert(keys, keymap.backspace(string.sub(api.get_current_line(), self.offset, cursor[2]))) + table.insert(keys, word) + table.insert(keys, keymap.indentkeys(vim.bo.indentkeys)) + feedkeys.call( + table.concat(keys, ''), + 'int', + vim.schedule_wrap(function() + this.pending = false + release() + end) + ) + end) + end + end, +}) + +return custom_entries_view diff --git a/start/cmp/lua/cmp/view/docs_view.lua b/start/cmp/lua/cmp/view/docs_view.lua new file mode 100644 index 0000000..9d2cd3f --- /dev/null +++ b/start/cmp/lua/cmp/view/docs_view.lua @@ -0,0 +1,136 @@ +local window = require('cmp.utils.window') +local config = require('cmp.config') + +---@class cmp.DocsView +---@field public window cmp.Window +local docs_view = {} + +---Create new floating window module +docs_view.new = function() + local self = setmetatable({}, { __index = docs_view }) + self.entry = nil + self.window = window.new() + self.window:option('conceallevel', 2) + self.window:option('concealcursor', 'n') + self.window:option('foldenable', false) + self.window:option('linebreak', true) + self.window:option('scrolloff', 0) + self.window:option('wrap', true) + return self +end + +---Open documentation window +---@param e cmp.Entry +---@param view cmp.WindowStyle +docs_view.open = function(self, e, view) + local documentation = config.get().window.documentation + if not documentation then + return + end + + if not e or not view then + return self:close() + end + + local border_info = window.get_border_info({ style = documentation }) + local right_space = vim.o.columns - (view.col + view.width) - 1 + local left_space = view.col - 1 + local max_width = math.min(documentation.max_width, math.max(left_space, right_space)) + + -- Update buffer content if needed. + if not self.entry or e.id ~= self.entry.id then + local documents = e:get_documentation() + if #documents == 0 then + return self:close() + end + + self.entry = e + vim.api.nvim_buf_call(self.window:get_buffer(), function() + vim.cmd([[syntax clear]]) + vim.api.nvim_buf_set_lines(self.window:get_buffer(), 0, -1, false, {}) + end) + vim.lsp.util.stylize_markdown(self.window:get_buffer(), documents, { + max_width = max_width, + max_height = documentation.max_height, + }) + end + + -- Calculate window size. + local width, height = vim.lsp.util._make_floating_popup_size(vim.api.nvim_buf_get_lines(self.window:get_buffer(), 0, -1, false), { + max_width = max_width - border_info.horiz, + max_height = documentation.max_height - border_info.vert, + }) + if width <= 0 or height <= 0 then + return self:close() + end + + -- Calculate window position. + local right_col = view.col + view.width + local left_col = view.col - width - border_info.horiz + local col, left + if right_space >= width and left_space >= width then + if right_space < left_space then + col = left_col + left = true + else + col = right_col + end + elseif right_space >= width then + col = right_col + elseif left_space >= width then + col = left_col + left = true + else + return self:close() + end + + -- Render window. + self.window:option('winblend', vim.o.pumblend) + self.window:option('winhighlight', documentation.winhighlight) + local style = { + relative = 'editor', + style = 'minimal', + width = width, + height = height, + row = view.row, + col = col, + border = documentation.border, + zindex = documentation.zindex or 50, + } + self.window:open(style) + + -- Correct left-col for scrollbar existence. + if left then + style.col = style.col - self.window:info().scrollbar_offset + self.window:open(style) + end +end + +---Close floating window +docs_view.close = function(self) + self.window:close() + self.entry = nil +end + +docs_view.scroll = function(self, delta) + if self:visible() then + local info = vim.fn.getwininfo(self.window.win)[1] or {} + local top = info.topline or 1 + top = top + delta + top = math.max(top, 1) + top = math.min(top, self.window:get_content_height() - info.height + 1) + + vim.defer_fn(function() + vim.api.nvim_buf_call(self.window:get_buffer(), function() + vim.api.nvim_command('normal! ' .. top .. 'zt') + self.window:update() + end) + end, 0) + end +end + +docs_view.visible = function(self) + return self.window:visible() +end + +return docs_view diff --git a/start/cmp/lua/cmp/view/ghost_text_view.lua b/start/cmp/lua/cmp/view/ghost_text_view.lua new file mode 100644 index 0000000..b798ebb --- /dev/null +++ b/start/cmp/lua/cmp/view/ghost_text_view.lua @@ -0,0 +1,97 @@ +local config = require('cmp.config') +local misc = require('cmp.utils.misc') +local str = require('cmp.utils.str') +local types = require('cmp.types') +local api = require('cmp.utils.api') + +---@class cmp.GhostTextView +local ghost_text_view = {} + +ghost_text_view.ns = vim.api.nvim_create_namespace('cmp:GHOST_TEXT') + +ghost_text_view.new = function() + local self = setmetatable({}, { __index = ghost_text_view }) + self.win = nil + self.entry = nil + vim.api.nvim_set_decoration_provider(ghost_text_view.ns, { + on_win = function(_, win) + return win == self.win + end, + on_line = function(_) + local c = config.get().experimental.ghost_text + if not c then + return + end + + if not self.entry then + return + end + + local row, col = unpack(vim.api.nvim_win_get_cursor(0)) + local line = vim.api.nvim_get_current_line() + if string.sub(line, col + 1) ~= '' then + return + end + + local text = self.text_gen(self, line, col) + if #text > 0 then + vim.api.nvim_buf_set_extmark(0, ghost_text_view.ns, row - 1, col, { + right_gravity = false, + virt_text = { { text, c.hl_group or 'Comment' } }, + virt_text_pos = 'overlay', + hl_mode = 'combine', + ephemeral = true, + }) + end + end, + }) + return self +end + +---Generate the ghost text +--- This function calculates the bytes of the entry to display calculating the number +--- of character differences instead of just byte difference. +ghost_text_view.text_gen = function(self, line, cursor_col) + local word = self.entry:get_insert_text() + if self.entry.completion_item.insertTextFormat == types.lsp.InsertTextFormat.Snippet then + word = vim.lsp.util.parse_snippet(word) + end + word = str.oneline(word) + local word_clen = vim.str_utfindex(word) + local cword = string.sub(line, self.entry:get_offset(), cursor_col) + local cword_clen = vim.str_utfindex(cword) + -- Number of characters from entry text (word) to be displayed as ghost thext + local nchars = word_clen - cword_clen + -- Missing characters to complete the entry text + local text + if nchars > 0 then + text = string.sub(word, vim.str_byteindex(word, word_clen - nchars) + 1) + else + text = '' + end + return text +end + +---Show ghost text +---@param e cmp.Entry +ghost_text_view.show = function(self, e) + if not api.is_insert_mode() then + return + end + local changed = e ~= self.entry + self.win = vim.api.nvim_get_current_win() + self.entry = e + if changed then + misc.redraw(true) -- force invoke decoration provider. + end +end + +ghost_text_view.hide = function(self) + if self.win and self.entry then + self.win = nil + self.entry = nil + misc.redraw(true) -- force invoke decoration provider. + end +end + +return ghost_text_view diff --git a/start/cmp/lua/cmp/view/native_entries_view.lua b/start/cmp/lua/cmp/view/native_entries_view.lua new file mode 100644 index 0000000..d8b0b1b --- /dev/null +++ b/start/cmp/lua/cmp/view/native_entries_view.lua @@ -0,0 +1,181 @@ +local event = require('cmp.utils.event') +local autocmd = require('cmp.utils.autocmd') +local keymap = require('cmp.utils.keymap') +local feedkeys = require('cmp.utils.feedkeys') +local types = require('cmp.types') +local config = require('cmp.config') +local api = require('cmp.utils.api') + +---@class cmp.NativeEntriesView +---@field private offset number +---@field private items vim.CompletedItem +---@field private entries cmp.Entry[] +---@field private preselect_index number +---@field public event cmp.Event +local native_entries_view = {} + +native_entries_view.new = function() + local self = setmetatable({}, { __index = native_entries_view }) + self.event = event.new() + self.offset = -1 + self.items = {} + self.entries = {} + self.preselect_index = 0 + autocmd.subscribe('CompleteChanged', function() + self.event:emit('change') + end) + return self +end + +native_entries_view.ready = function(_) + if vim.fn.pumvisible() == 0 then + return true + end + return vim.fn.complete_info({ 'mode' }).mode == 'eval' +end + +native_entries_view.on_change = function(self) + if #self.entries > 0 and self.offset <= vim.api.nvim_win_get_cursor(0)[2] + 1 then + local preselect_enabled = config.get().preselect == types.cmp.PreselectMode.Item + + local completeopt = vim.o.completeopt + if self.preselect_index == 1 and preselect_enabled then + vim.o.completeopt = 'menu,menuone,noinsert' + else + vim.o.completeopt = config.get().completion.completeopt + end + vim.fn.complete(self.offset, self.items) + vim.o.completeopt = completeopt + + if self.preselect_index > 1 and preselect_enabled then + self:preselect(self.preselect_index) + end + end +end + +native_entries_view.open = function(self, offset, entries) + local dedup = {} + local items = {} + local dedup_entries = {} + local preselect_index = 0 + for _, e in ipairs(entries) do + local item = e:get_vim_item(offset) + if item.dup == 1 or not dedup[item.abbr] then + dedup[item.abbr] = true + table.insert(items, item) + table.insert(dedup_entries, e) + if preselect_index == 0 and e.completion_item.preselect then + preselect_index = #dedup_entries + end + end + end + self.offset = offset + self.items = items + self.entries = dedup_entries + self.preselect_index = preselect_index + self:on_change() +end + +native_entries_view.close = function(self) + if api.is_suitable_mode() and self:visible() then + vim.fn.complete(1, {}) + vim.api.nvim_select_popupmenu_item(-1, false, true, {}) + end + self.offset = -1 + self.entries = {} + self.items = {} + self.preselect_index = 0 +end + +native_entries_view.abort = function(_) + if api.is_suitable_mode() then + vim.api.nvim_select_popupmenu_item(-1, true, true, {}) + end +end + +native_entries_view.visible = function(_) + return vim.fn.pumvisible() == 1 +end + +native_entries_view.info = function(self) + if self:visible() then + local info = vim.fn.pum_getpos() + return { + width = info.width + (info.scrollable and 1 or 0), + height = info.height, + row = info.row, + col = info.col, + } + end +end + +native_entries_view.preselect = function(self, index) + if self:visible() then + if index <= #self.entries then + vim.api.nvim_select_popupmenu_item(index - 1, false, false, {}) + end + end +end + +native_entries_view.select_next_item = function(self, option) + local callback = function() + self.event:emit('change') + end + if self:visible() then + if (option.behavior or types.cmp.SelectBehavior.Insert) == types.cmp.SelectBehavior.Insert then + feedkeys.call(keymap.t(''), 'n', callback) + else + feedkeys.call(keymap.t(''), 'n', callback) + end + end +end + +native_entries_view.select_prev_item = function(self, option) + local callback = function() + self.event:emit('change') + end + if self:visible() then + if (option.behavior or types.cmp.SelectBehavior.Insert) == types.cmp.SelectBehavior.Insert then + feedkeys.call(keymap.t(''), 'n', callback) + else + feedkeys.call(keymap.t(''), 'n', callback) + end + end +end + +native_entries_view.get_offset = function(self) + if self:visible() then + return self.offset + end + return nil +end + +native_entries_view.get_entries = function(self) + if self:visible() then + return self.entries + end + return {} +end + +native_entries_view.get_first_entry = function(self) + if self:visible() then + return self.entries[1] + end +end + +native_entries_view.get_selected_entry = function(self) + if self:visible() then + local idx = vim.fn.complete_info({ 'selected' }).selected + if idx > -1 then + return self.entries[math.max(0, idx) + 1] + end + end +end + +native_entries_view.get_active_entry = function(self) + if self:visible() and (vim.v.completed_item or {}).word then + return self:get_selected_entry() + end +end + +return native_entries_view diff --git a/start/cmp/lua/cmp/view/wildmenu_entries_view.lua b/start/cmp/lua/cmp/view/wildmenu_entries_view.lua new file mode 100644 index 0000000..3419164 --- /dev/null +++ b/start/cmp/lua/cmp/view/wildmenu_entries_view.lua @@ -0,0 +1,261 @@ +local event = require('cmp.utils.event') +local autocmd = require('cmp.utils.autocmd') +local feedkeys = require('cmp.utils.feedkeys') +local config = require('cmp.config') +local window = require('cmp.utils.window') +local types = require('cmp.types') +local keymap = require('cmp.utils.keymap') +local misc = require('cmp.utils.misc') +local api = require('cmp.utils.api') + +---@class cmp.CustomEntriesView +---@field private offset number +---@field private entries_win cmp.Window +---@field private active boolean +---@field private entries cmp.Entry[] +---@field public event cmp.Event +local wildmenu_entries_view = {} + +wildmenu_entries_view.ns = vim.api.nvim_create_namespace('cmp.view.statusline_entries_view') + +wildmenu_entries_view.new = function() + local self = setmetatable({}, { __index = wildmenu_entries_view }) + self.event = event.new() + self.offset = -1 + self.active = false + self.entries = {} + self.offsets = {} + self.selected_index = 0 + self.entries_win = window.new() + + self.entries_win:option('conceallevel', 2) + self.entries_win:option('concealcursor', 'n') + self.entries_win:option('cursorlineopt', 'line') + self.entries_win:option('foldenable', false) + self.entries_win:option('wrap', false) + self.entries_win:option('scrolloff', 0) + self.entries_win:option('sidescrolloff', 0) + self.entries_win:option('winhighlight', 'Normal:Pmenu,FloatBorder:Pmenu,CursorLine:PmenuSel,Search:None') + self.entries_win:buffer_option('tabstop', 1) + + autocmd.subscribe( + 'CompleteChanged', + vim.schedule_wrap(function() + if self:visible() and vim.fn.pumvisible() == 1 then + self:close() + end + end) + ) + + vim.api.nvim_set_decoration_provider(wildmenu_entries_view.ns, { + on_win = function(_, win, buf, _, _) + if win ~= self.entries_win.win or buf ~= self.entries_win:get_buffer() then + return + end + + for i, e in ipairs(self.entries) do + if e then + local view = e:get_view(self.offset, buf) + vim.api.nvim_buf_set_extmark(buf, wildmenu_entries_view.ns, 0, self.offsets[i], { + end_line = 0, + end_col = self.offsets[i] + view.abbr.bytes, + hl_group = view.abbr.hl_group, + hl_mode = 'combine', + ephemeral = true, + }) + + if i == self.selected_index then + vim.api.nvim_buf_set_extmark(buf, wildmenu_entries_view.ns, 0, self.offsets[i], { + end_line = 0, + end_col = self.offsets[i] + view.abbr.bytes, + hl_group = 'PmenuSel', + hl_mode = 'combine', + ephemeral = true, + }) + end + + for _, m in ipairs(e.matches or {}) do + vim.api.nvim_buf_set_extmark(buf, wildmenu_entries_view.ns, 0, self.offsets[i] + m.word_match_start - 1, { + end_line = 0, + end_col = self.offsets[i] + m.word_match_end, + hl_group = m.fuzzy and 'CmpItemAbbrMatchFuzzy' or 'CmpItemAbbrMatch', + hl_mode = 'combine', + ephemeral = true, + }) + end + end + end + end, + }) + return self +end + +wildmenu_entries_view.close = function(self) + self.entries_win:close() +end + +wildmenu_entries_view.ready = function() + return vim.fn.pumvisible() == 0 +end + +wildmenu_entries_view.on_change = function(self) + self.active = false +end + +wildmenu_entries_view.open = function(self, offset, entries) + self.offset = offset + self.entries = {} + + -- Apply window options (that might be changed) on the custom completion menu. + self.entries_win:option('winblend', vim.o.pumblend) + + local dedup = {} + local preselect = 0 + local i = 1 + for _, e in ipairs(entries) do + local view = e:get_view(offset, 0) + if view.dup == 1 or not dedup[e.completion_item.label] then + dedup[e.completion_item.label] = true + table.insert(self.entries, e) + if preselect == 0 and e.completion_item.preselect then + preselect = i + end + i = i + 1 + end + end + + self.entries_win:open({ + relative = 'editor', + style = 'minimal', + row = vim.o.lines - 2, + col = 0, + width = vim.o.columns, + height = 1, + zindex = 1001, + }) + self:draw() + + if preselect > 0 and config.get().preselect == types.cmp.PreselectMode.Item then + self:_select(preselect, { behavior = types.cmp.SelectBehavior.Select }) + elseif not string.match(config.get().completion.completeopt, 'noselect') then + self:_select(1, { behavior = types.cmp.SelectBehavior.Select }) + else + self:_select(0, { behavior = types.cmp.SelectBehavior.Select }) + end +end + +wildmenu_entries_view.abort = function(self) + feedkeys.call('', 'n', function() + self:close() + end) +end + +wildmenu_entries_view.draw = function(self) + self.offsets = {} + + local entries_buf = self.entries_win:get_buffer() + local texts = {} + local offset = 0 + for _, e in ipairs(self.entries) do + local view = e:get_view(self.offset, entries_buf) + table.insert(self.offsets, offset) + table.insert(texts, view.abbr.text) + offset = offset + view.abbr.bytes + #self:_get_separator() + end + + vim.api.nvim_buf_set_lines(entries_buf, 0, 1, false, { table.concat(texts, self:_get_separator()) }) + vim.api.nvim_buf_set_option(entries_buf, 'modified', false) + + vim.api.nvim_win_call(0, function() + misc.redraw() + end) +end + +wildmenu_entries_view.visible = function(self) + return self.entries_win:visible() +end + +wildmenu_entries_view.info = function(self) + return self.entries_win:info() +end + +wildmenu_entries_view.select_next_item = function(self, option) + if self:visible() then + if self.selected_index == 0 or self.selected_index == #self.entries then + self:_select(1, option) + else + self:_select(self.selected_index + 1, option) + end + end +end + +wildmenu_entries_view.select_prev_item = function(self, option) + if self:visible() then + if self.selected_index == 0 or self.selected_index <= 1 then + self:_select(#self.entries, option) + else + self:_select(self.selected_index - 1, option) + end + end +end + +wildmenu_entries_view.get_offset = function(self) + if self:visible() then + return self.offset + end + return nil +end + +wildmenu_entries_view.get_entries = function(self) + if self:visible() then + return self.entries + end + return {} +end + +wildmenu_entries_view.get_first_entry = function(self) + if self:visible() then + return self.entries[1] + end +end + +wildmenu_entries_view.get_selected_entry = function(self) + if self:visible() and self.active then + return self.entries[self.selected_index] + end +end + +wildmenu_entries_view.get_active_entry = function(self) + if self:visible() and self.active then + return self:get_selected_entry() + end +end + +wildmenu_entries_view._select = function(self, selected_index, option) + local is_next = self.selected_index < selected_index + self.selected_index = selected_index + self.active = (selected_index ~= 0) + + if self.active then + local e = self:get_active_entry() + if option.behavior == types.cmp.SelectBehavior.Insert then + local cursor = api.get_cursor() + local word = e:get_vim_item(self.offset).word + vim.api.nvim_feedkeys(keymap.backspace(string.sub(api.get_current_line(), self.offset, cursor[2])) .. word, 'int', true) + end + vim.api.nvim_win_call(self.entries_win.win, function() + local view = e:get_view(self.offset, self.entries_win:get_buffer()) + vim.api.nvim_win_set_cursor(0, { 1, self.offsets[selected_index] + (is_next and view.abbr.bytes or 0) }) + vim.cmd([[redraw!]]) -- Force refresh for vim.api.nvim_set_decoration_provider + end) + end + + self.event:emit('change') +end + +wildmenu_entries_view._get_separator = function() + local c = config.get() + return (c and c.view and c.view.entries and c.view.entries.separator) or ' ' +end + +return wildmenu_entries_view diff --git a/start/cmp/lua/cmp/vim_source.lua b/start/cmp/lua/cmp/vim_source.lua new file mode 100644 index 0000000..2ee8fbf --- /dev/null +++ b/start/cmp/lua/cmp/vim_source.lua @@ -0,0 +1,53 @@ +local misc = require('cmp.utils.misc') + +local vim_source = {} + +---@param id number +---@param args any[] +vim_source.on_callback = function(id, args) + if vim_source.to_callback.callbacks[id] then + vim_source.to_callback.callbacks[id](unpack(args)) + end +end + +---@param callback function +---@return number +vim_source.to_callback = setmetatable({ + callbacks = {}, +}, { + __call = function(self, callback) + local id = misc.id('cmp.vim_source.to_callback') + self.callbacks[id] = function(...) + callback(...) + self.callbacks[id] = nil + end + return id + end, +}) + +---Convert to serializable args. +---@param args any[] +vim_source.to_args = function(args) + for i, arg in ipairs(args) do + if type(arg) == 'function' then + args[i] = vim_source.to_callback(arg) + end + end + return args +end + +---@param bridge_id number +---@param methods string[] +vim_source.new = function(bridge_id, methods) + local self = {} + for _, method in ipairs(methods) do + self[method] = (function(m) + return function(_, ...) + return vim.fn['cmp#_method'](bridge_id, m, vim_source.to_args({ ... })) + end + end)(method) + end + return self +end + +return vim_source diff --git a/start/cmp/lua/cmp_nvim_lsp/init.lua b/start/cmp/lua/cmp_nvim_lsp/init.lua new file mode 100644 index 0000000..9feb93a --- /dev/null +++ b/start/cmp/lua/cmp_nvim_lsp/init.lua @@ -0,0 +1,84 @@ +local source = require('cmp_nvim_lsp.source') + +local M = {} + +---Registered client and source mapping. +M.client_source_map = {} + +---Setup cmp-nvim-lsp source. +M.setup = function() + vim.cmd([[ + augroup cmp_nvim_lsp + autocmd! + autocmd InsertEnter * lua require'cmp_nvim_lsp'._on_insert_enter() + augroup END + ]]) +end + +local if_nil = function(val, default) + if val == nil then return default end + return val +end + +M.update_capabilities = function(capabilities, override) + override = override or {} + + local completionItem = capabilities.textDocument.completion.completionItem + + completionItem.snippetSupport = if_nil(override.snippetSupport, true) + completionItem.preselectSupport = if_nil(override.preselectSupport, true) + completionItem.insertReplaceSupport = if_nil(override.insertReplaceSupport, true) + completionItem.labelDetailsSupport = if_nil(override.labelDetailsSupport, true) + completionItem.deprecatedSupport = if_nil(override.deprecatedSupport, true) + completionItem.commitCharactersSupport = if_nil(override.commitCharactersSupport, true) + completionItem.tagSupport = if_nil(override.tagSupport, { valueSet = { 1 } }) + completionItem.resolveSupport = if_nil(override.resolveSupport, { + properties = { + 'documentation', + 'detail', + 'additionalTextEdits', + } + }) + + return capabilities +end + +---Refresh sources on InsertEnter. +M._on_insert_enter = function() + local cmp = require('cmp') + + local allowed_clients = {} + + -- register all active clients. + for _, client in ipairs(vim.lsp.get_active_clients()) do + allowed_clients[client.id] = client + if not M.client_source_map[client.id] then + local s = source.new(client) + if s:is_available() then + M.client_source_map[client.id] = cmp.register_source('nvim_lsp', s) + end + end + end + + -- register all buffer clients (early register before activation) + for _, client in ipairs(vim.lsp.buf_get_clients(0)) do + allowed_clients[client.id] = client + if not M.client_source_map[client.id] then + local s = source.new(client) + if s:is_available() then + M.client_source_map[client.id] = cmp.register_source('nvim_lsp', s) + end + end + end + + -- unregister stopped/detached clients. + for client_id, source_id in pairs(M.client_source_map) do + if not allowed_clients[client_id] or allowed_clients[client_id]:is_stopped() then + cmp.unregister_source(source_id) + M.client_source_map[client_id] = nil + end + end +end + +return M + diff --git a/start/cmp/lua/cmp_nvim_lsp/source.lua b/start/cmp/lua/cmp_nvim_lsp/source.lua new file mode 100644 index 0000000..d4dd587 --- /dev/null +++ b/start/cmp/lua/cmp_nvim_lsp/source.lua @@ -0,0 +1,117 @@ +local source = {} + +source.new = function(client) + local self = setmetatable({}, { __index = source }) + self.client = client + self.request_ids = {} + return self +end + +source.get_debug_name = function(self) + return table.concat({ 'nvim_lsp', self.client.name }, ':') +end + +source.is_available = function(self) + -- client is stopped. + if self.client.is_stopped() then + return false + end + + -- client is not attached to current buffer. + if not vim.lsp.buf_get_clients(vim.api.nvim_get_current_buf())[self.client.id] then + return false + end + + -- client has no completion capability. + if not self:_get(self.client.server_capabilities, { 'completionProvider' }) then + return false + end + return true; +end + +source.get_trigger_characters = function(self) + return self:_get(self.client.server_capabilities, { 'completionProvider', 'triggerCharacters' }) or {} +end + +source.complete = function(self, request, callback) + local params = vim.lsp.util.make_position_params(0, self.client.offset_encoding) + params.context = {} + params.context.triggerKind = request.completion_context.triggerKind + params.context.triggerCharacter = request.completion_context.triggerCharacter + + self:_request('textDocument/completion', params, function(_, response) + callback(response) + end) +end + +source.resolve = function(self, completion_item, callback) + -- client is stopped. + if self.client.is_stopped() then + return callback() + end + + -- client has no completion capability. + if not self:_get(self.client.server_capabilities, { 'completionProvider', 'resolveProvider' }) then + return callback() + end + + self:_request('completionItem/resolve', completion_item, function(_, response) + callback(response or completion_item) + end) +end + +source.execute = function(self, completion_item, callback) + -- client is stopped. + if self.client.is_stopped() then + return callback() + end + + -- completion_item has no command. + if not completion_item.command then + return callback() + end + + self:_request('workspace/executeCommand', completion_item.command, function(_, _) + callback() + end) +end + +source._get = function(_, root, paths) + local c = root + for _, path in ipairs(paths) do + c = c[path] + if not c then + return nil + end + end + return c +end + +source._request = function(self, method, params, callback) + if self.request_ids[method] ~= nil then + self.client.cancel_request(self.request_ids[method]) + self.request_ids[method] = nil + end + local _, request_id + _, request_id = self.client.request(method, params, function(arg1, arg2, arg3) + if self.request_ids[method] ~= request_id then + return + end + self.request_ids[method] = nil + + -- Text changed, retry + if arg1 and arg1.code == -32801 then + self:_request(method, params, callback) + return + end + + if method == arg2 then + callback(arg1, arg3) -- old signature + else + callback(arg1, arg2) -- new signature + end + end) + self.request_ids[method] = request_id +end + +return source diff --git a/start/cmp/plugin/cmp.lua b/start/cmp/plugin/cmp.lua new file mode 100644 index 0000000..caf8c27 --- /dev/null +++ b/start/cmp/plugin/cmp.lua @@ -0,0 +1,60 @@ +if vim.g.loaded_cmp then + return +end +vim.g.loaded_cmp = true + +if not vim.api.nvim_create_autocmd then + return print('[nvim-cmp] Your nvim does not has `nvim_create_autocmd` function. Please update to latest nvim.') +end + +local api = require('cmp.utils.api') +local types = require('cmp.types') +local highlight = require('cmp.utils.highlight') +local autocmd = require('cmp.utils.autocmd') + +vim.api.nvim_set_hl(0, 'CmpItemAbbr', { link = 'CmpItemAbbrDefault', default = true }) +vim.api.nvim_set_hl(0, 'CmpItemAbbrDeprecated', { link = 'CmpItemAbbrDeprecatedDefault', default = true }) +vim.api.nvim_set_hl(0, 'CmpItemAbbrMatch', { link = 'CmpItemAbbrMatchDefault', default = true }) +vim.api.nvim_set_hl(0, 'CmpItemAbbrMatchFuzzy', { link = 'CmpItemAbbrMatchFuzzyDefault', default = true }) +vim.api.nvim_set_hl(0, 'CmpItemKind', { link = 'CmpItemKindDefault', default = true }) +vim.api.nvim_set_hl(0, 'CmpItemMenu', { link = 'CmpItemMenuDefault', default = true }) +for kind in pairs(types.lsp.CompletionItemKind) do + if type(kind) == 'string' then + local name = ('CmpItemKind%s'):format(kind) + vim.api.nvim_set_hl(0, name, { link = ('%sDefault'):format(name), default = true }) + end +end + +autocmd.subscribe('ColorScheme', function() + highlight.inherit('CmpItemAbbrDefault', 'Pmenu', { bg = 'NONE', default = true }) + highlight.inherit('CmpItemAbbrDeprecatedDefault', 'Comment', { bg = 'NONE', default = true }) + highlight.inherit('CmpItemAbbrMatchDefault', 'Pmenu', { bg = 'NONE', default = true }) + highlight.inherit('CmpItemAbbrMatchFuzzyDefault', 'Pmenu', { bg = 'NONE', default = true }) + highlight.inherit('CmpItemKindDefault', 'Special', { bg = 'NONE', default = true }) + highlight.inherit('CmpItemMenuDefault', 'Pmenu', { bg = 'NONE', default = true }) + for name in pairs(types.lsp.CompletionItemKind) do + if type(name) == 'string' then + vim.api.nvim_set_hl(0, ('CmpItemKind%sDefault'):format(name), { link = 'CmpItemKind', default = true }) + end + end +end) +autocmd.emit('ColorScheme') + +if vim.on_key then + vim.on_key(function(keys) + if keys == vim.api.nvim_replace_termcodes('', true, true, true) then + vim.schedule(function() + if not api.is_suitable_mode() then + autocmd.emit('InsertLeave') + end + end) + end + end, vim.api.nvim_create_namespace('cmp.plugin')) +end + +vim.api.nvim_create_user_command('CmpStatus', function() + require('cmp').status() +end, { desc = 'Check status of cmp sources' }) + +vim.cmd([[doautocmd User CmpReady]]) + diff --git a/start/fzf/README b/start/fzf/README new file mode 100644 index 0000000..13007c7 --- /dev/null +++ b/start/fzf/README @@ -0,0 +1,25 @@ +This is a stripped down subset of some random old version of fzf.vim. + +Its only real purpose is to provide the normal mode C-p binding for file search. + +License +------- + +MIT LICENSE + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/start/fzf/autoload/fzf/vim.vim b/start/fzf/autoload/fzf/vim.vim new file mode 100644 index 0000000..82b0e00 --- /dev/null +++ b/start/fzf/autoload/fzf/vim.vim @@ -0,0 +1,1324 @@ +" Copyright (c) 2017 Junegunn Choi +" +" MIT License +" +" Permission is hereby granted, free of charge, to any person obtaining +" a copy of this software and associated documentation files (the +" "Software"), to deal in the Software without restriction, including +" without limitation the rights to use, copy, modify, merge, publish, +" distribute, sublicense, and/or sell copies of the Software, and to +" permit persons to whom the Software is furnished to do so, subject to +" the following conditions: +" +" The above copyright notice and this permission notice shall be +" included in all copies or substantial portions of the Software. +" +" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +" EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +" NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +" LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +" OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +" WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +let s:cpo_save = &cpo +set cpo&vim + +" ------------------------------------------------------------------ +" Common +" ------------------------------------------------------------------ + +let s:is_win = has('win32') || has('win64') +let s:layout_keys = ['window', 'up', 'down', 'left', 'right'] +let s:bin_dir = expand(':h:h:h').'/bin/' +let s:bin = { +\ 'preview': s:bin_dir.'preview.sh', +\ 'tags': s:bin_dir.'tags.pl' } +let s:TYPE = {'dict': type({}), 'funcref': type(function('call')), 'string': type(''), 'list': type([])} +if s:is_win + if has('nvim') + let s:bin.preview = split(system('for %A in ("'.s:bin.preview.'") do @echo %~sA'), "\n")[0] + else + let s:bin.preview = fnamemodify(s:bin.preview, ':8') + endif + let s:bin.preview = 'bash '.escape(s:bin.preview, '\') +endif + +let s:wide = 120 + +function! s:extend_opts(dict, eopts, prepend) + if empty(a:eopts) + return + endif + if has_key(a:dict, 'options') + if type(a:dict.options) == s:TYPE.list && type(a:eopts) == s:TYPE.list + if a:prepend + let a:dict.options = extend(copy(a:eopts), a:dict.options) + else + call extend(a:dict.options, a:eopts) + endif + else + let all_opts = a:prepend ? [a:eopts, a:dict.options] : [a:dict.options, a:eopts] + let a:dict.options = join(map(all_opts, 'type(v:val) == s:TYPE.list ? join(map(copy(v:val), "fzf#shellescape(v:val)")) : v:val')) + endif + else + let a:dict.options = a:eopts + endif +endfunction + +function! s:merge_opts(dict, eopts) + return s:extend_opts(a:dict, a:eopts, 0) +endfunction + +function! s:prepend_opts(dict, eopts) + return s:extend_opts(a:dict, a:eopts, 1) +endfunction + +" [[options to wrap], [preview window expression], [toggle-preview keys...]] +function! fzf#vim#with_preview(...) + " Default options + let options = {} + let window = 'right' + + let args = copy(a:000) + + " Options to wrap + if len(args) && type(args[0]) == s:TYPE.dict + let options = copy(args[0]) + call remove(args, 0) + endif + + " Preview window + if len(args) && type(args[0]) == s:TYPE.string + if args[0] !~# '^\(up\|down\|left\|right\)' + throw 'invalid preview window: '.args[0] + endif + let window = args[0] + call remove(args, 0) + endif + + let preview = ['--preview-window', window, '--preview', (s:is_win ? s:bin.preview : fzf#shellescape(s:bin.preview)).' {}'] + + if len(args) + call extend(preview, ['--bind', join(map(args, 'v:val.":toggle-preview"'), ',')]) + endif + call s:merge_opts(options, preview) + return options +endfunction + +function! s:remove_layout(opts) + for key in s:layout_keys + if has_key(a:opts, key) + call remove(a:opts, key) + endif + endfor + return a:opts +endfunction + +function! s:wrap(name, opts, bang) + " fzf#wrap does not append --expect if sink or sink* is found + let opts = copy(a:opts) + let options = '' + if has_key(opts, 'options') + let options = type(opts.options) == s:TYPE.list ? join(opts.options) : opts.options + endif + if options !~ '--expect' && has_key(opts, 'sink*') + let Sink = remove(opts, 'sink*') + let wrapped = fzf#wrap(a:name, opts, a:bang) + let wrapped['sink*'] = Sink + else + let wrapped = fzf#wrap(a:name, opts, a:bang) + endif + return wrapped +endfunction + +function! s:strip(str) + return substitute(a:str, '^\s*\|\s*$', '', 'g') +endfunction + +function! s:chomp(str) + return substitute(a:str, '\n*$', '', 'g') +endfunction + +function! s:escape(path) + let path = fnameescape(a:path) + return s:is_win ? escape(path, '$') : path +endfunction + +if v:version >= 704 + function! s:function(name) + return function(a:name) + endfunction +else + function! s:function(name) + " By Ingo Karkat + return function(substitute(a:name, '^s:', matchstr(expand(''), '\d\+_\zefunction$'), '')) + endfunction +endif + +function! s:get_color(attr, ...) + let gui = has('termguicolors') && &termguicolors + let fam = gui ? 'gui' : 'cterm' + let pat = gui ? '^#[a-f0-9]\+' : '^[0-9]\+$' + for group in a:000 + let code = synIDattr(synIDtrans(hlID(group)), a:attr, fam) + if code =~? pat + return code + endif + endfor + return '' +endfunction + +let s:ansi = {'black': 30, 'red': 31, 'green': 32, 'yellow': 33, 'blue': 34, 'magenta': 35, 'cyan': 36} + +function! s:csi(color, fg) + let prefix = a:fg ? '38;' : '48;' + if a:color[0] == '#' + return prefix.'2;'.join(map([a:color[1:2], a:color[3:4], a:color[5:6]], 'str2nr(v:val, 16)'), ';') + endif + return prefix.'5;'.a:color +endfunction + +function! s:ansi(str, group, default, ...) + let fg = s:get_color('fg', a:group) + let bg = s:get_color('bg', a:group) + let color = (empty(fg) ? s:ansi[a:default] : s:csi(fg, 1)) . + \ (empty(bg) ? '' : ';'.s:csi(bg, 0)) + return printf("\x1b[%s%sm%s\x1b[m", color, a:0 ? ';1' : '', a:str) +endfunction + +for s:color_name in keys(s:ansi) + execute "function! s:".s:color_name."(str, ...)\n" + \ " return s:ansi(a:str, get(a:, 1, ''), '".s:color_name."')\n" + \ "endfunction" +endfor + +function! s:buflisted() + return filter(range(1, bufnr('$')), 'buflisted(v:val) && getbufvar(v:val, "&filetype") != "qf"') +endfunction + +function! s:fzf(name, opts, extra) + let [extra, bang] = [{}, 0] + if len(a:extra) <= 1 + let first = get(a:extra, 0, 0) + if type(first) == s:TYPE.dict + let extra = first + else + let bang = first + endif + elseif len(a:extra) == 2 + let [extra, bang] = a:extra + else + throw 'invalid number of arguments' + endif + + let eopts = has_key(extra, 'options') ? remove(extra, 'options') : '' + let merged = extend(copy(a:opts), extra) + call s:merge_opts(merged, eopts) + return fzf#run(s:wrap(a:name, merged, bang)) +endfunction + +let s:default_action = { + \ 'ctrl-t': 'tab split', + \ 'ctrl-x': 'split', + \ 'ctrl-v': 'vsplit' } + +function! s:action_for(key, ...) + let default = a:0 ? a:1 : '' + let Cmd = get(get(g:, 'fzf_action', s:default_action), a:key, default) + return type(Cmd) == s:TYPE.string ? Cmd : default +endfunction + +function! s:open(cmd, target) + if stridx('edit', a:cmd) == 0 && fnamemodify(a:target, ':p') ==# expand('%:p') + return + endif + execute a:cmd s:escape(a:target) +endfunction + +function! s:align_lists(lists) + let maxes = {} + for list in a:lists + let i = 0 + while i < len(list) + let maxes[i] = max([get(maxes, i, 0), len(list[i])]) + let i += 1 + endwhile + endfor + for list in a:lists + call map(list, "printf('%-'.maxes[v:key].'s', v:val)") + endfor + return a:lists +endfunction + +function! s:warn(message) + echohl WarningMsg + echom a:message + echohl None + return 0 +endfunction + +function! s:fill_quickfix(list, ...) + if len(a:list) > 1 + call setqflist(a:list) + copen + wincmd p + if a:0 + execute a:1 + endif + endif +endfunction + +function! fzf#vim#_uniq(list) + let visited = {} + let ret = [] + for l in a:list + if !empty(l) && !has_key(visited, l) + call add(ret, l) + let visited[l] = 1 + endif + endfor + return ret +endfunction + +" ------------------------------------------------------------------ +" Files +" ------------------------------------------------------------------ +function! s:shortpath() + let short = fnamemodify(getcwd(), ':~:.') + if !has('win32unix') + let short = pathshorten(short) + endif + let slash = (s:is_win && !&shellslash) ? '\' : '/' + return empty(short) ? '~'.slash : short . (short =~ escape(slash, '\').'$' ? '' : slash) +endfunction + +function! fzf#vim#files(dir, ...) + let args = {} + if !empty(a:dir) + if !isdirectory(expand(a:dir)) + return s:warn('Invalid directory') + endif + let slash = (s:is_win && !&shellslash) ? '\\' : '/' + let dir = substitute(a:dir, '[/\\]*$', slash, '') + let args.dir = dir + else + let dir = s:shortpath() + endif + + let args.options = ['-m', '--prompt', strwidth(dir) < &columns / 2 - 20 ? dir : '> '] + call s:merge_opts(args, get(g:, 'fzf_files_options', [])) + return s:fzf('files', args, a:000) +endfunction + +" ------------------------------------------------------------------ +" Lines +" ------------------------------------------------------------------ +function! s:line_handler(lines) + if len(a:lines) < 2 + return + endif + normal! m' + let cmd = s:action_for(a:lines[0]) + if !empty(cmd) && stridx('edit', cmd) < 0 + execute 'silent' cmd + endif + + let keys = split(a:lines[1], '\t') + execute 'buffer' keys[0] + execute keys[2] + normal! ^zvzz +endfunction + +function! fzf#vim#_lines(all) + let cur = [] + let rest = [] + let buf = bufnr('') + let longest_name = 0 + let display_bufnames = &columns > s:wide + if display_bufnames + let bufnames = {} + for b in s:buflisted() + let bufnames[b] = pathshorten(fnamemodify(bufname(b), ":~:.")) + let longest_name = max([longest_name, len(bufnames[b])]) + endfor + endif + let len_bufnames = min([15, longest_name]) + for b in s:buflisted() + let lines = getbufline(b, 1, "$") + if empty(lines) + let path = fnamemodify(bufname(b), ':p') + let lines = filereadable(path) ? readfile(path) : [] + endif + if display_bufnames + let bufname = bufnames[b] + if len(bufname) > len_bufnames + 1 + let bufname = '…' . bufname[-len_bufnames+1:] + endif + let bufname = printf(s:green("%".len_bufnames."s", "Directory"), bufname) + else + let bufname = '' + endif + let linefmt = s:blue("%2d\t", "TabLine")."%s".s:yellow("\t%4d ", "LineNr")."\t%s" + call extend(b == buf ? cur : rest, + \ filter( + \ map(lines, + \ '(!a:all && empty(v:val)) ? "" : printf(linefmt, b, bufname, v:key + 1, v:val)'), + \ 'a:all || !empty(v:val)')) + endfor + return [display_bufnames, extend(cur, rest)] +endfunction + +function! fzf#vim#lines(...) + let [display_bufnames, lines] = fzf#vim#_lines(1) + let nth = display_bufnames ? 3 : 2 + let [query, args] = (a:0 && type(a:1) == type('')) ? + \ [a:1, a:000[1:]] : ['', a:000] + return s:fzf('lines', { + \ 'source': lines, + \ 'sink*': s:function('s:line_handler'), + \ 'options': ['+m', '--tiebreak=index', '--prompt', 'Lines> ', '--ansi', '--extended', '--nth='.nth.'..', '--layout=reverse-list', '--tabstop=1', '--query', query] + \}, args) +endfunction + +" ------------------------------------------------------------------ +" BLines +" ------------------------------------------------------------------ +function! s:buffer_line_handler(lines) + if len(a:lines) < 2 + return + endif + let qfl = [] + for line in a:lines[1:] + let chunks = split(line, "\t", 1) + let ln = chunks[0] + let ltxt = join(chunks[1:], "\t") + call add(qfl, {'filename': expand('%'), 'lnum': str2nr(ln), 'text': ltxt}) + endfor + call s:fill_quickfix(qfl, 'cfirst') + normal! m' + let cmd = s:action_for(a:lines[0]) + if !empty(cmd) + execute 'silent' cmd + endif + + execute split(a:lines[1], '\t')[0] + normal! ^zvzz +endfunction + +function! s:buffer_lines(query) + let linefmt = s:yellow(" %4d ", "LineNr")."\t%s" + let fmtexpr = 'printf(linefmt, v:key + 1, v:val)' + let lines = getline(1, '$') + if empty(a:query) + return map(lines, fmtexpr) + end + return filter(map(lines, 'v:val =~ a:query ? '.fmtexpr.' : ""'), 'len(v:val)') +endfunction + +function! fzf#vim#buffer_lines(...) + let [query, args] = (a:0 && type(a:1) == type('')) ? + \ [a:1, a:000[1:]] : ['', a:000] + return s:fzf('blines', { + \ 'source': s:buffer_lines(query), + \ 'sink*': s:function('s:buffer_line_handler'), + \ 'options': ['+m', '--tiebreak=index', '--multi', '--prompt', 'BLines> ', '--ansi', '--extended', '--nth=2..', '--layout=reverse-list', '--tabstop=1'] + \}, args) +endfunction + +" ------------------------------------------------------------------ +" Colors +" ------------------------------------------------------------------ +function! fzf#vim#colors(...) + let colors = split(globpath(&rtp, "colors/*.vim"), "\n") + if has('packages') + let colors += split(globpath(&packpath, "pack/*/opt/*/colors/*.vim"), "\n") + endif + return s:fzf('colors', { + \ 'source': fzf#vim#_uniq(map(colors, "substitute(fnamemodify(v:val, ':t'), '\\..\\{-}$', '', '')")), + \ 'sink': 'colo', + \ 'options': '+m --prompt="Colors> "' + \}, a:000) +endfunction + +" ------------------------------------------------------------------ +" Locate +" ------------------------------------------------------------------ +function! fzf#vim#locate(query, ...) + return s:fzf('locate', { + \ 'source': 'locate '.a:query, + \ 'options': '-m --prompt "Locate> "' + \}, a:000) +endfunction + +" ------------------------------------------------------------------ +" History[:/] +" ------------------------------------------------------------------ +function! s:all_files() + return fzf#vim#_uniq(map( + \ filter([expand('%')], 'len(v:val)') + \ + filter(map(s:buflisted_sorted(), 'bufname(v:val)'), 'len(v:val)') + \ + filter(copy(v:oldfiles), "filereadable(fnamemodify(v:val, ':p'))"), + \ 'fnamemodify(v:val, ":~:.")')) +endfunction + +function! s:history_source(type) + let max = histnr(a:type) + let fmt = ' %'.len(string(max)).'d ' + let list = filter(map(range(1, max), 'histget(a:type, - v:val)'), '!empty(v:val)') + return extend([' :: Press '.s:magenta('CTRL-E', 'Special').' to edit'], + \ map(list, 's:yellow(printf(fmt, len(list) - v:key), "Number")." ".v:val')) +endfunction + +nnoremap (-fzf-vim-do) :execute g:__fzf_command +nnoremap (-fzf-/) / +nnoremap (-fzf-:) : + +function! s:history_sink(type, lines) + if len(a:lines) < 2 + return + endif + + let prefix = "\(-fzf-".a:type.')' + let key = a:lines[0] + let item = matchstr(a:lines[1], ' *[0-9]\+ *\zs.*') + if key == 'ctrl-e' + call histadd(a:type, item) + redraw + call feedkeys(a:type."\") + else + if a:type == ':' + call histadd(a:type, item) + endif + let g:__fzf_command = "normal ".prefix.item."\" + call feedkeys("\(-fzf-vim-do)") + endif +endfunction + +function! s:cmd_history_sink(lines) + call s:history_sink(':', a:lines) +endfunction + +function! fzf#vim#command_history(...) + return s:fzf('history-command', { + \ 'source': s:history_source(':'), + \ 'sink*': s:function('s:cmd_history_sink'), + \ 'options': '+m --ansi --prompt="Hist:> " --header-lines=1 --expect=ctrl-e --tiebreak=index'}, a:000) +endfunction + +function! s:search_history_sink(lines) + call s:history_sink('/', a:lines) +endfunction + +function! fzf#vim#search_history(...) + return s:fzf('history-search', { + \ 'source': s:history_source('/'), + \ 'sink*': s:function('s:search_history_sink'), + \ 'options': '+m --ansi --prompt="Hist/> " --header-lines=1 --expect=ctrl-e --tiebreak=index'}, a:000) +endfunction + +function! fzf#vim#history(...) + return s:fzf('history-files', { + \ 'source': s:all_files(), + \ 'options': ['-m', '--header-lines', !empty(expand('%')), '--prompt', 'Hist> '] + \}, a:000) +endfunction + +" ------------------------------------------------------------------ +" GFiles[?] +" ------------------------------------------------------------------ + +function! s:get_git_root() + let root = split(system('git rev-parse --show-toplevel'), '\n')[0] + return v:shell_error ? '' : root +endfunction + +function! fzf#vim#gitfiles(args, ...) + let root = s:get_git_root() + if empty(root) + return s:warn('Not in git repo') + endif + if a:args != '?' + return s:fzf('gfiles', { + \ 'source': 'git ls-files '.a:args.(s:is_win ? '' : ' | uniq'), + \ 'dir': root, + \ 'options': '-m --prompt "GitFiles> "' + \}, a:000) + endif + + " Here be dragons! + " We're trying to access the common sink function that fzf#wrap injects to + " the options dictionary. + let wrapped = fzf#wrap({ + \ 'source': 'git -c color.status=always status --short --untracked-files=all', + \ 'dir': root, + \ 'options': ['--ansi', '--multi', '--nth', '2..,..', '--tiebreak=index', '--prompt', 'GitFiles?> ', '--preview', 'sh -c "(git diff --color=always -- {-1} | sed 1,4d; cat {-1}) | head -500"'] + \}) + call s:remove_layout(wrapped) + let wrapped.common_sink = remove(wrapped, 'sink*') + function! wrapped.newsink(lines) + let lines = extend(a:lines[0:0], map(a:lines[1:], 'substitute(v:val[3:], ".* -> ", "", "")')) + return self.common_sink(lines) + endfunction + let wrapped['sink*'] = remove(wrapped, 'newsink') + return s:fzf('gfiles-diff', wrapped, a:000) +endfunction + +" ------------------------------------------------------------------ +" Buffers +" ------------------------------------------------------------------ +function! s:find_open_window(b) + let [tcur, tcnt] = [tabpagenr() - 1, tabpagenr('$')] + for toff in range(0, tabpagenr('$') - 1) + let t = (tcur + toff) % tcnt + 1 + let buffers = tabpagebuflist(t) + for w in range(1, len(buffers)) + let b = buffers[w - 1] + if b == a:b + return [t, w] + endif + endfor + endfor + return [0, 0] +endfunction + +function! s:jump(t, w) + execute a:t.'tabnext' + execute a:w.'wincmd w' +endfunction + +function! s:bufopen(lines) + if len(a:lines) < 2 + return + endif + let b = matchstr(a:lines[1], '\[\zs[0-9]*\ze\]') + if empty(a:lines[0]) && get(g:, 'fzf_buffers_jump') + let [t, w] = s:find_open_window(b) + if t + call s:jump(t, w) + return + endif + endif + let cmd = s:action_for(a:lines[0]) + if !empty(cmd) + execute 'silent' cmd + endif + execute 'buffer' b +endfunction + +function! s:format_buffer(b) + let name = bufname(a:b) + let name = empty(name) ? '[No Name]' : fnamemodify(name, ":p:~:.") + let flag = a:b == bufnr('') ? s:blue('%', 'Conditional') : + \ (a:b == bufnr('#') ? s:magenta('#', 'Special') : ' ') + let modified = getbufvar(a:b, '&modified') ? s:red(' [+]', 'Exception') : '' + let readonly = getbufvar(a:b, '&modifiable') ? '' : s:green(' [RO]', 'Constant') + let extra = join(filter([modified, readonly], '!empty(v:val)'), '') + return s:strip(printf("[%s] %s\t%s\t%s", s:yellow(a:b, 'Number'), flag, name, extra)) +endfunction + +function! s:sort_buffers(...) + let [b1, b2] = map(copy(a:000), 'get(g:fzf#vim#buffers, v:val, v:val)') + " Using minus between a float and a number in a sort function causes an error + return b1 < b2 ? 1 : -1 +endfunction + +function! s:buflisted_sorted() + return sort(s:buflisted(), 's:sort_buffers') +endfunction + +function! fzf#vim#buffers(...) + let [query, args] = (a:0 && type(a:1) == type('')) ? + \ [a:1, a:000[1:]] : ['', a:000] + return s:fzf('buffers', { + \ 'source': map(s:buflisted_sorted(), 's:format_buffer(v:val)'), + \ 'sink*': s:function('s:bufopen'), + \ 'options': ['+m', '-x', '--tiebreak=index', '--header-lines=1', '--ansi', '-d', '\t', '-n', '2,1..2', '--prompt', 'Buf> ', '--query', query] + \}, args) +endfunction + +" ------------------------------------------------------------------ +" Ag / Rg +" ------------------------------------------------------------------ +function! s:ag_to_qf(line, with_column) + let parts = split(a:line, ':') + let text = join(parts[(a:with_column ? 3 : 2):], ':') + let dict = {'filename': &acd ? fnamemodify(parts[0], ':p') : parts[0], 'lnum': parts[1], 'text': text} + if a:with_column + let dict.col = parts[2] + endif + return dict +endfunction + +function! s:ag_handler(lines, with_column) + if len(a:lines) < 2 + return + endif + + let cmd = s:action_for(a:lines[0], 'e') + let list = map(filter(a:lines[1:], 'len(v:val)'), 's:ag_to_qf(v:val, a:with_column)') + if empty(list) + return + endif + + let first = list[0] + try + call s:open(cmd, first.filename) + execute first.lnum + if a:with_column + execute 'normal!' first.col.'|' + endif + normal! zz + catch + endtry + + call s:fill_quickfix(list) +endfunction + +" query, [[ag options], options] +function! fzf#vim#ag(query, ...) + if type(a:query) != s:TYPE.string + return s:warn('Invalid query argument') + endif + let query = empty(a:query) ? '^(?=.)' : a:query + let args = copy(a:000) + let ag_opts = len(args) > 1 && type(args[0]) == s:TYPE.string ? remove(args, 0) : '' + let command = ag_opts . ' ' . fzf#shellescape(query) + return call('fzf#vim#ag_raw', insert(args, command, 0)) +endfunction + +" ag command suffix, [options] +function! fzf#vim#ag_raw(command_suffix, ...) + if !executable('ag') + return s:warn('ag is not found') + endif + return call('fzf#vim#grep', extend(['ag --nogroup --column --color '.a:command_suffix, 1], a:000)) +endfunction + +" command, with_column, [options] +function! fzf#vim#grep(grep_command, with_column, ...) + let words = [] + for word in split(a:grep_command) + if word !~# '^[a-z]' + break + endif + call add(words, word) + endfor + let words = empty(words) ? ['grep'] : words + let name = join(words, '-') + let capname = join(map(words, 'toupper(v:val[0]).v:val[1:]'), '') + let opts = { + \ 'source': a:grep_command, + \ 'column': a:with_column, + \ 'options': ['--ansi', '--prompt', capname.'> ', + \ '--multi', '--bind', 'alt-a:select-all,alt-d:deselect-all', + \ '--color', 'hl:4,hl+:12'] + \} + function! opts.sink(lines) + return s:ag_handler(a:lines, self.column) + endfunction + let opts['sink*'] = remove(opts, 'sink') + return s:fzf(name, opts, a:000) +endfunction + +" ------------------------------------------------------------------ +" BTags +" ------------------------------------------------------------------ +function! s:btags_source(tag_cmds) + if !filereadable(expand('%')) + throw 'Save the file first' + endif + + for cmd in a:tag_cmds + let lines = split(system(cmd), "\n") + if !v:shell_error && len(lines) + break + endif + endfor + if v:shell_error + throw get(lines, 0, 'Failed to extract tags') + elseif empty(lines) + throw 'No tags found' + endif + return map(s:align_lists(map(lines, 'split(v:val, "\t")')), 'join(v:val, "\t")') +endfunction + +function! s:btags_sink(lines) + if len(a:lines) < 2 + return + endif + normal! m' + let cmd = s:action_for(a:lines[0]) + if !empty(cmd) + execute 'silent' cmd '%' + endif + let qfl = [] + for line in a:lines[1:] + execute split(line, "\t")[2] + call add(qfl, {'filename': expand('%'), 'lnum': line('.'), 'text': getline('.')}) + endfor + call s:fill_quickfix(qfl, 'cfirst') + normal! zz +endfunction + +" query, [[tag commands], options] +function! fzf#vim#buffer_tags(query, ...) + let args = copy(a:000) + let escaped = fzf#shellescape(expand('%')) + let null = s:is_win ? 'nul' : '/dev/null' + let sort = has('unix') && !has('win32unix') && executable('sort') ? '| sort -s -k 5' : '' + let tag_cmds = (len(args) > 1 && type(args[0]) != type({})) ? remove(args, 0) : [ + \ printf('ctags -f - --sort=yes --excmd=number --language-force=%s %s 2> %s %s', &filetype, escaped, null, sort), + \ printf('ctags -f - --sort=yes --excmd=number %s 2> %s %s', escaped, null, sort)] + if type(tag_cmds) != type([]) + let tag_cmds = [tag_cmds] + endif + try + return s:fzf('btags', { + \ 'source': s:btags_source(tag_cmds), + \ 'sink*': s:function('s:btags_sink'), + \ 'options': ['--layout=reverse-list', '-m', '-d', '\t', '--with-nth', '1,4..', '-n', '1', '--prompt', 'BTags> ', '--query', a:query]}, args) + catch + return s:warn(v:exception) + endtry +endfunction + +" ------------------------------------------------------------------ +" Tags +" ------------------------------------------------------------------ +function! s:tags_sink(lines) + if len(a:lines) < 2 + return + endif + normal! m' + let qfl = [] + let cmd = s:action_for(a:lines[0], 'e') + try + let [magic, &magic, wrapscan, &wrapscan, acd, &acd] = [&magic, 0, &wrapscan, 1, &acd, 0] + for line in a:lines[1:] + try + let parts = split(line, '\t\zs') + let excmd = matchstr(join(parts[2:-2], '')[:-2], '^.\{-}\ze;\?"\t') + let base = fnamemodify(parts[-1], ':h') + let relpath = parts[1][:-2] + let abspath = relpath =~ (s:is_win ? '^[A-Z]:\' : '^/') ? relpath : join([base, relpath], '/') + call s:open(cmd, expand(abspath, 1)) + execute excmd + call add(qfl, {'filename': expand('%'), 'lnum': line('.'), 'text': getline('.')}) + catch /^Vim:Interrupt$/ + break + catch + call s:warn(v:exception) + endtry + endfor + finally + let [&magic, &wrapscan, &acd] = [magic, wrapscan, acd] + endtry + call s:fill_quickfix(qfl, 'clast') + normal! zz +endfunction + +function! fzf#vim#tags(query, ...) + if !executable('perl') + return s:warn('Tags command requires perl') + endif + if empty(tagfiles()) + call inputsave() + echohl WarningMsg + let gen = input('tags not found. Generate? (y/N) ') + echohl None + call inputrestore() + redraw + if gen =~? '^y' + call s:warn('Preparing tags') + call system(get(g:, 'fzf_tags_command', 'ctags -R'.(s:is_win ? ' --output-format=e-ctags' : ''))) + if empty(tagfiles()) + return s:warn('Failed to create tags') + endif + else + return s:warn('No tags found') + endif + endif + + let tagfiles = tagfiles() + let v2_limit = 1024 * 1024 * 200 + for tagfile in tagfiles + let v2_limit -= getfsize(tagfile) + if v2_limit < 0 + break + endif + endfor + let opts = v2_limit < 0 ? ['--algo=v1'] : [] + + return s:fzf('tags', { + \ 'source': 'perl '.fzf#shellescape(s:bin.tags).' '.join(map(tagfiles, 'fzf#shellescape(fnamemodify(v:val, ":p"))')), + \ 'sink*': s:function('s:tags_sink'), + \ 'options': extend(opts, ['--nth', '1..2', '-m', '--tiebreak=begin', '--prompt', 'Tags> ', '--query', a:query])}, a:000) +endfunction + +" ------------------------------------------------------------------ +" Snippets (UltiSnips) +" ------------------------------------------------------------------ +function! s:inject_snippet(line) + let snip = split(a:line, "\t")[0] + execute 'normal! a'.s:strip(snip)."\=UltiSnips#ExpandSnippet()\" +endfunction + +function! fzf#vim#snippets(...) + if !exists(':UltiSnipsEdit') + return s:warn('UltiSnips not found') + endif + let list = UltiSnips#SnippetsInCurrentScope() + if empty(list) + return s:warn('No snippets available here') + endif + let aligned = sort(s:align_lists(items(list))) + let colored = map(aligned, 's:yellow(v:val[0])."\t".v:val[1]') + return s:fzf('snippets', { + \ 'source': colored, + \ 'options': '--ansi --tiebreak=index +m -n 1 -d "\t"', + \ 'sink': s:function('s:inject_snippet')}, a:000) +endfunction + +" ------------------------------------------------------------------ +" Commands +" ------------------------------------------------------------------ +let s:nbs = nr2char(0x2007) + +function! s:format_cmd(line) + return substitute(a:line, '\C \([A-Z]\S*\) ', + \ '\=s:nbs.s:yellow(submatch(1), "Function").s:nbs', '') +endfunction + +function! s:command_sink(lines) + if len(a:lines) < 2 + return + endif + let cmd = matchstr(a:lines[1], s:nbs.'\zs\S*\ze'.s:nbs) + if empty(a:lines[0]) + call feedkeys(':'.cmd.(a:lines[1][0] == '!' ? '' : ' '), 'n') + else + execute cmd + endif +endfunction + +let s:fmt_excmd = ' '.s:blue('%-38s', 'Statement').'%s' + +function! s:format_excmd(ex) + let match = matchlist(a:ex, '^|:\(\S\+\)|\s*\S*\(.*\)') + return printf(s:fmt_excmd, s:nbs.match[1].s:nbs, s:strip(match[2])) +endfunction + +function! s:excmds() + let help = globpath($VIMRUNTIME, 'doc/index.txt') + if empty(help) + return [] + endif + + let commands = [] + let command = '' + for line in readfile(help) + if line =~ '^|:[^|]' + if !empty(command) + call add(commands, s:format_excmd(command)) + endif + let command = line + elseif line =~ '^\s\+\S' && !empty(command) + let command .= substitute(line, '^\s*', ' ', '') + elseif !empty(commands) && line =~ '^\s*$' + break + endif + endfor + if !empty(command) + call add(commands, s:format_excmd(command)) + endif + return commands +endfunction + +function! fzf#vim#commands(...) + redir => cout + silent command + redir END + let list = split(cout, "\n") + return s:fzf('commands', { + \ 'source': extend(extend(list[0:0], map(list[1:], 's:format_cmd(v:val)')), s:excmds()), + \ 'sink*': s:function('s:command_sink'), + \ 'options': '--ansi --expect '.get(g:, 'fzf_commands_expect', 'ctrl-x'). + \ ' --tiebreak=index --header-lines 1 -x --prompt "Commands> " -n2,3,2..3 -d'.s:nbs}, a:000) +endfunction + +" ------------------------------------------------------------------ +" Marks +" ------------------------------------------------------------------ +function! s:format_mark(line) + return substitute(a:line, '\S', '\=s:yellow(submatch(0), "Number")', '') +endfunction + +function! s:mark_sink(lines) + if len(a:lines) < 2 + return + endif + let cmd = s:action_for(a:lines[0]) + if !empty(cmd) + execute 'silent' cmd + endif + execute 'normal! `'.matchstr(a:lines[1], '\S').'zz' +endfunction + +function! fzf#vim#marks(...) + redir => cout + silent marks + redir END + let list = split(cout, "\n") + return s:fzf('marks', { + \ 'source': extend(list[0:0], map(list[1:], 's:format_mark(v:val)')), + \ 'sink*': s:function('s:mark_sink'), + \ 'options': '+m -x --ansi --tiebreak=index --header-lines 1 --tiebreak=begin --prompt "Marks> "'}, a:000) +endfunction + +" ------------------------------------------------------------------ +" Help tags +" ------------------------------------------------------------------ +function! s:helptag_sink(line) + let [tag, file, path] = split(a:line, "\t")[0:2] + let rtp = fnamemodify(path, ':p:h:h') + if stridx(&rtp, rtp) < 0 + execute 'set rtp+='.s:escape(rtp) + endif + execute 'help' tag +endfunction + +function! fzf#vim#helptags(...) + if !executable('grep') || !executable('perl') + return s:warn('Helptags command requires grep and perl') + endif + let sorted = sort(split(globpath(&runtimepath, 'doc/tags', 1), '\n')) + let tags = exists('*uniq') ? uniq(sorted) : fzf#vim#_uniq(sorted) + + if exists('s:helptags_script') + silent! call delete(s:helptags_script) + endif + let s:helptags_script = tempname() + call writefile(['/('.(s:is_win ? '^[A-Z]:\/.*?[^:]' : '.*?').'):(.*?)\t(.*?)\t/; printf(qq('.s:green('%-40s', 'Label').'\t%s\t%s\n), $2, $3, $1)'], s:helptags_script) + return s:fzf('helptags', { + \ 'source': 'grep -H ".*" '.join(map(tags, 'fzf#shellescape(v:val)')). + \ ' | perl -n '.fzf#shellescape(s:helptags_script).' | sort', + \ 'sink': s:function('s:helptag_sink'), + \ 'options': ['--ansi', '+m', '--tiebreak=begin', '--with-nth', '..-2']}, a:000) +endfunction + +" ------------------------------------------------------------------ +" File types +" ------------------------------------------------------------------ +function! fzf#vim#filetypes(...) + return s:fzf('filetypes', { + \ 'source': fzf#vim#_uniq(sort(map(split(globpath(&rtp, 'syntax/*.vim'), '\n'), + \ 'fnamemodify(v:val, ":t:r")'))), + \ 'sink': 'setf', + \ 'options': '+m --prompt="File types> "' + \}, a:000) +endfunction + +" ------------------------------------------------------------------ +" Windows +" ------------------------------------------------------------------ +function! s:format_win(tab, win, buf) + let modified = getbufvar(a:buf, '&modified') + let name = bufname(a:buf) + let name = empty(name) ? '[No Name]' : name + let active = tabpagewinnr(a:tab) == a:win + return (active? s:blue('> ', 'Operator') : ' ') . name . (modified? s:red(' [+]', 'Exception') : '') +endfunction + +function! s:windows_sink(line) + let list = matchlist(a:line, '^ *\([0-9]\+\) *\([0-9]\+\)') + call s:jump(list[1], list[2]) +endfunction + +function! fzf#vim#windows(...) + let lines = [] + for t in range(1, tabpagenr('$')) + let buffers = tabpagebuflist(t) + for w in range(1, len(buffers)) + call add(lines, + \ printf('%s %s %s', + \ s:yellow(printf('%3d', t), 'Number'), + \ s:cyan(printf('%3d', w), 'String'), + \ s:format_win(t, w, buffers[w-1]))) + endfor + endfor + return s:fzf('windows', { + \ 'source': extend(['Tab Win Name'], lines), + \ 'sink': s:function('s:windows_sink'), + \ 'options': '+m --ansi --tiebreak=begin --header-lines=1'}, a:000) +endfunction + +" ------------------------------------------------------------------ +" Commits / BCommits +" ------------------------------------------------------------------ +function! s:yank_to_register(data) + let @" = a:data + silent! let @* = a:data + silent! let @+ = a:data +endfunction + +function! s:commits_sink(lines) + if len(a:lines) < 2 + return + endif + + let pat = '[0-9a-f]\{7,9}' + + if a:lines[0] == 'ctrl-y' + let hashes = join(filter(map(a:lines[1:], 'matchstr(v:val, pat)'), 'len(v:val)')) + return s:yank_to_register(hashes) + end + + let diff = a:lines[0] == 'ctrl-d' + let cmd = s:action_for(a:lines[0], 'e') + let buf = bufnr('') + for idx in range(1, len(a:lines) - 1) + let sha = matchstr(a:lines[idx], pat) + if !empty(sha) + if diff + if idx > 1 + execute 'tab sb' buf + endif + execute 'Gdiff' sha + else + " Since fugitive buffers are unlisted, we can't keep using 'e' + let c = (cmd == 'e' && idx > 1) ? 'tab split' : cmd + execute c FugitiveFind(sha) + endif + endif + endfor +endfunction + +function! s:commits(buffer_local, args) + let s:git_root = s:get_git_root() + if empty(s:git_root) + return s:warn('Not in git repository') + endif + + let source = 'git log '.get(g:, 'fzf_commits_log_options', '--color=always '.fzf#shellescape('--format=%C(auto)%h%d %s %C(green)%cr')) + let current = expand('%') + let managed = 0 + if !empty(current) + call system('git show '.fzf#shellescape(current).' 2> '.(s:is_win ? 'nul' : '/dev/null')) + let managed = !v:shell_error + endif + + if a:buffer_local + if !managed + return s:warn('The current buffer is not in the working tree') + endif + let source .= ' --follow '.fzf#shellescape(current) + else + let source .= ' --graph' + endif + + let command = a:buffer_local ? 'BCommits' : 'Commits' + let expect_keys = join(keys(get(g:, 'fzf_action', s:default_action)), ',') + let options = { + \ 'source': source, + \ 'sink*': s:function('s:commits_sink'), + \ 'options': ['--ansi', '--multi', '--tiebreak=index', '--layout=reverse-list', + \ '--inline-info', '--prompt', command.'> ', '--bind=ctrl-s:toggle-sort', + \ '--header', ':: Press '.s:magenta('CTRL-S', 'Special').' to toggle sort, '.s:magenta('CTRL-Y', 'Special').' to yank commit hashes', + \ '--expect=ctrl-y,'.expect_keys] + \ } + + if a:buffer_local + let options.options[-2] .= ', '.s:magenta('CTRL-D', 'Special').' to diff' + let options.options[-1] .= ',ctrl-d' + endif + + if !s:is_win && &columns > s:wide + call extend(options.options, + \ ['--preview', 'echo {} | grep -o "[a-f0-9]\{7,\}" | head -1 | xargs git show --format=format: --color=always | head -200']) + endif + + return s:fzf(a:buffer_local ? 'bcommits' : 'commits', options, a:args) +endfunction + +function! fzf#vim#commits(...) + return s:commits(0, a:000) +endfunction + +function! fzf#vim#buffer_commits(...) + return s:commits(1, a:000) +endfunction + +" ------------------------------------------------------------------ +" fzf#vim#maps(mode, opts[with count and op]) +" ------------------------------------------------------------------ +function! s:align_pairs(list) + let maxlen = 0 + let pairs = [] + for elem in a:list + let match = matchlist(elem, '^\(\S*\)\s*\(.*\)$') + let [_, k, v] = match[0:2] + let maxlen = max([maxlen, len(k)]) + call add(pairs, [k, substitute(v, '^\*\?[@ ]\?', '', '')]) + endfor + let maxlen = min([maxlen, 35]) + return map(pairs, "printf('%-'.maxlen.'s', v:val[0]).' '.v:val[1]") +endfunction + +function! s:highlight_keys(str) + return substitute( + \ substitute(a:str, '<[^ >]\+>', s:yellow('\0', 'Special'), 'g'), + \ '', s:blue('', 'SpecialKey'), 'g') +endfunction + +function! s:key_sink(line) + let key = matchstr(a:line, '^\S*') + redraw + call feedkeys(s:map_gv.s:map_cnt.s:map_reg, 'n') + call feedkeys(s:map_op. + \ substitute(key, '<[^ >]\+>', '\=eval("\"\\".submatch(0)."\"")', 'g')) +endfunction + +function! fzf#vim#maps(mode, ...) + let s:map_gv = a:mode == 'x' ? 'gv' : '' + let s:map_cnt = v:count == 0 ? '' : v:count + let s:map_reg = empty(v:register) ? '' : ('"'.v:register) + let s:map_op = a:mode == 'o' ? v:operator : '' + + redir => cout + silent execute 'verbose' a:mode.'map' + redir END + let list = [] + let curr = '' + for line in split(cout, "\n") + if line =~ "^\t" + let src = ' '.join(reverse(reverse(split(split(line)[-1], '/'))[0:2]), '/') + call add(list, printf('%s %s', curr, s:green(src, 'Comment'))) + let curr = '' + else + let curr = line[3:] + endif + endfor + if !empty(curr) + call add(list, curr) + endif + let aligned = s:align_pairs(list) + let sorted = sort(aligned) + let colored = map(sorted, 's:highlight_keys(v:val)') + let pcolor = a:mode == 'x' ? 9 : a:mode == 'o' ? 10 : 12 + return s:fzf('maps', { + \ 'source': colored, + \ 'sink': s:function('s:key_sink'), + \ 'options': '--prompt "Maps ('.a:mode.')> " --ansi --no-hscroll --nth 1,.. --color prompt:'.pcolor}, a:000) +endfunction + +" ---------------------------------------------------------------------------- +" fzf#vim#complete - completion helper +" ---------------------------------------------------------------------------- +inoremap (-fzf-complete-trigger) :call complete_trigger() + +function! s:pluck(dict, key, default) + return has_key(a:dict, a:key) ? remove(a:dict, a:key) : a:default +endfunction + +function! s:complete_trigger() + let opts = copy(s:opts) + call s:prepend_opts(opts, ['+m', '-q', s:query]) + let opts['sink*'] = s:function('s:complete_insert') + let s:reducer = s:pluck(opts, 'reducer', s:function('s:first_line')) + call fzf#run(opts) +endfunction + +" The default reducer +function! s:first_line(lines) + return a:lines[0] +endfunction + +function! s:complete_insert(lines) + if empty(a:lines) + return + endif + + let chars = strchars(s:query) + if chars == 0 | let del = '' + elseif chars == 1 | let del = '"_x' + else | let del = (chars - 1).'"_dvh' + endif + + let data = call(s:reducer, [a:lines]) + let ve = &ve + set ve= + execute 'normal!' ((s:eol || empty(chars)) ? '' : 'h').del.(s:eol ? 'a': 'i').data + let &ve = ve + if mode() =~ 't' + call feedkeys('a', 'n') + else + execute "normal! \la" + endif +endfunction + +function! s:eval(dict, key, arg) + if has_key(a:dict, a:key) && type(a:dict[a:key]) == s:TYPE.funcref + let ret = copy(a:dict) + let ret[a:key] = call(a:dict[a:key], [a:arg]) + return ret + endif + return a:dict +endfunction + +function! fzf#vim#complete(...) + if a:0 == 0 + let s:opts = fzf#wrap() + elseif type(a:1) == s:TYPE.dict + let s:opts = copy(a:1) + elseif type(a:1) == s:TYPE.string + let s:opts = extend({'source': a:1}, get(a:000, 1, fzf#wrap())) + else + echoerr 'Invalid argument: '.string(a:000) + return '' + endif + for s in ['sink', 'sink*'] + if has_key(s:opts, s) + call remove(s:opts, s) + endif + endfor + + let eol = col('$') + let ve = &ve + set ve=all + let s:eol = col('.') == eol + let &ve = ve + + let Prefix = s:pluck(s:opts, 'prefix', '\k*$') + if col('.') == 1 + let s:query = '' + else + let full_prefix = getline('.')[0 : col('.')-2] + if type(Prefix) == s:TYPE.funcref + let s:query = call(Prefix, [full_prefix]) + else + let s:query = matchstr(full_prefix, Prefix) + endif + endif + let s:opts = s:eval(s:opts, 'source', s:query) + let s:opts = s:eval(s:opts, 'options', s:query) + let s:opts = s:eval(s:opts, 'extra_options', s:query) + if has_key(s:opts, 'extra_options') + call s:merge_opts(s:opts, remove(s:opts, 'extra_options')) + endif + if has_key(s:opts, 'options') + if type(s:opts.options) == s:TYPE.list + call add(s:opts.options, '--no-expect') + else + let s:opts.options .= ' --no-expect' + endif + endif + + call feedkeys("\(-fzf-complete-trigger)") + return '' +endfunction + +" ------------------------------------------------------------------ +let &cpo = s:cpo_save +unlet s:cpo_save + diff --git a/start/fzf/autoload/fzf/vim/complete.vim b/start/fzf/autoload/fzf/vim/complete.vim new file mode 100644 index 0000000..03c9b3b --- /dev/null +++ b/start/fzf/autoload/fzf/vim/complete.vim @@ -0,0 +1,163 @@ +" Copyright (c) 2015 Junegunn Choi +" +" MIT License +" +" Permission is hereby granted, free of charge, to any person obtaining +" a copy of this software and associated documentation files (the +" "Software"), to deal in the Software without restriction, including +" without limitation the rights to use, copy, modify, merge, publish, +" distribute, sublicense, and/or sell copies of the Software, and to +" permit persons to whom the Software is furnished to do so, subject to +" the following conditions: +" +" The above copyright notice and this permission notice shall be +" included in all copies or substantial portions of the Software. +" +" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +" EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +" NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +" LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +" OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +" WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +let s:cpo_save = &cpo +set cpo&vim +let s:is_win = has('win32') || has('win64') + +function! s:extend(base, extra) + let base = copy(a:base) + if has_key(a:extra, 'options') + let extra = copy(a:extra) + let extra.extra_options = remove(extra, 'options') + return extend(base, extra) + endif + return extend(base, a:extra) +endfunction + +if v:version >= 704 + function! s:function(name) + return function(a:name) + endfunction +else + function! s:function(name) + " By Ingo Karkat + return function(substitute(a:name, '^s:', matchstr(expand(''), '\d\+_\zefunction$'), '')) + endfunction +endif + +function! fzf#vim#complete#word(...) + return fzf#vim#complete(s:extend({ + \ 'source': 'cat /usr/share/dict/words'}, + \ get(a:000, 0, fzf#wrap()))) +endfunction + +" ---------------------------------------------------------------------------- +" (fzf-complete-path) +" (fzf-complete-file) +" (fzf-complete-file-ag) +" ---------------------------------------------------------------------------- +function! s:file_split_prefix(prefix) + let expanded = expand(a:prefix) + let slash = (s:is_win && !&shellslash) ? '\\' : '/' + return isdirectory(expanded) ? + \ [expanded, + \ substitute(a:prefix, '[/\\]*$', slash, ''), + \ ''] : + \ [fnamemodify(expanded, ':h'), + \ substitute(fnamemodify(a:prefix, ':h'), '[/\\]*$', slash, ''), + \ fnamemodify(expanded, ':t')] +endfunction + +function! s:file_source(prefix) + let [dir, head, tail] = s:file_split_prefix(a:prefix) + return printf( + \ "cd %s && ".s:file_cmd." | sed %s", + \ fzf#shellescape(dir), fzf#shellescape('s:^:'.(empty(a:prefix) || a:prefix == tail ? '' : head).':')) +endfunction + +function! s:file_options(prefix) + let [_, head, tail] = s:file_split_prefix(a:prefix) + return ['--prompt', head, '--query', tail] +endfunction + +function! s:fname_prefix(str) + let isf = &isfname + let white = [] + let black = [] + if isf =~ ',,,' + call add(white, ',') + let isf = substitute(isf, ',,,', ',', 'g') + endif + if isf =~ ',^,,' + call add(black, ',') + let isf = substitute(isf, ',^,,', ',', 'g') + endif + + for token in split(isf, ',') + let target = white + if token[0] == '^' + let target = black + let token = token[1:] + endif + + let ends = matchlist(token, '\(.\+\)-\(.\+\)') + if empty(ends) + call add(target, token) + else + let ends = map(ends[1:2], "len(v:val) == 1 ? char2nr(v:val) : str2nr(v:val)") + for i in range(ends[0], ends[1]) + call add(target, nr2char(i)) + endfor + endif + endfor + + let prefix = a:str + for offset in range(1, len(a:str)) + let char = a:str[len(a:str) - offset] + if (char =~ '\w' || index(white, char) >= 0) && index(black, char) < 0 + continue + endif + let prefix = strpart(a:str, len(a:str) - offset + 1) + break + endfor + + return prefix +endfunction + +function! fzf#vim#complete#path(command, ...) + let s:file_cmd = a:command + return fzf#vim#complete(s:extend({ + \ 'prefix': s:function('s:fname_prefix'), + \ 'source': s:function('s:file_source'), + \ 'options': s:function('s:file_options')}, get(a:000, 0, fzf#wrap()))) +endfunction + +" ---------------------------------------------------------------------------- +" (fzf-complete-line) +" (fzf-complete-buffer-line) +" ---------------------------------------------------------------------------- +function! s:reduce_line(lines) + return join(split(a:lines[0], '\t\zs')[3:], '') +endfunction + + +function! fzf#vim#complete#line(...) + let [display_bufnames, lines] = fzf#vim#_lines(0) + let nth = display_bufnames ? 4 : 3 + return fzf#vim#complete(s:extend({ + \ 'prefix': '^.*$', + \ 'source': lines, + \ 'options': '--tiebreak=index --ansi --nth '.nth.'.. --tabstop=1', + \ 'reducer': s:function('s:reduce_line')}, get(a:000, 0, fzf#wrap()))) +endfunction + +function! fzf#vim#complete#buffer_line(...) + return fzf#vim#complete(s:extend({ + \ 'prefix': '^.*$', + \ 'source': fzf#vim#_uniq(getline(1, '$'))}, get(a:000, 0, fzf#wrap()))) +endfunction + +let &cpo = s:cpo_save +unlet s:cpo_save + diff --git a/start/fzf/bin/preview.rb b/start/fzf/bin/preview.rb new file mode 100644 index 0000000..cc8260b --- /dev/null +++ b/start/fzf/bin/preview.rb @@ -0,0 +1,59 @@ +#!/usr/bin/env ruby +# +# usage: ./preview.rb FILENAME[:LINE][:IGNORED] + +require 'open3' +require 'shellwords' + +COMMAND = ENV.fetch( + 'FZF_PREVIEW_COMMAND', + %[bat --style=numbers --color=always {} || highlight -O ansi -l {} || coderay {} || rougify {} || cat {}] +) +ANSI = /\x1b\[[0-9;]*m/ +REVERSE = "\x1b[7m" +RESET = "\x1b[m" + +def usage + puts "usage: #$0 FILENAME[:LINENO][:IGNORED]" + exit 1 +end + +usage if ARGV.empty? + +file, center, extra = ARGV.first.split(':') +if ARGV.first =~ /^[A-Z]:\\/ + file << ':' + center + center = extra +end +usage unless file + +path = File.expand_path(file) +unless File.readable? path + puts "File not found: #{file}" + exit 1 +end + +if `file --dereference --mime "#{file}"` =~ /binary/ + puts "#{file} is a binary file" + exit 0 +end + +center = (center || 0).to_i +height = + if ENV['LINES'] + ENV['LINES'].to_i + else + File.readable?('/dev/tty') ? `stty size < /dev/tty`.split.first.to_i : 40 + end +offset = [1, center - height / 3].max + +Open3.popen3(COMMAND.gsub('{}', Shellwords.shellescape(path))) do |_in, out, _err| + out.each_line.drop(offset - 1).take(height).each_with_index do |line, lno| + if lno + offset == center + puts REVERSE + line.chomp.gsub(ANSI) { |m| m + REVERSE } + RESET + else + puts line + end + end +end +print RESET diff --git a/start/fzf/bin/preview.sh b/start/fzf/bin/preview.sh new file mode 100644 index 0000000..41ebfb9 --- /dev/null +++ b/start/fzf/bin/preview.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash + +REVERSE="\x1b[7m" +RESET="\x1b[m" + +if [ -z "$1" ]; then + echo "usage: $0 FILENAME[:LINENO][:IGNORED]" + exit 1 +fi + +IFS=':' read -r -a INPUT <<< "$1" +FILE=${INPUT[0]} +CENTER=${INPUT[1]} + +if [[ $1 =~ ^[A-Z]:\\ ]]; then + FILE=$FILE:${INPUT[1]} + CENTER=${INPUT[2]} +fi + +if [ ! -r "$FILE" ]; then + echo "File not found ${FILE}" + exit 1 +fi + +if [[ "$(file --dereference --mime "$FILE")" =~ binary ]]; then + echo "$1 is a binary file" + exit 0 +fi + +if [ -z "$CENTER" ]; then + CENTER=0 +fi + +if [ -z "$LINES" ]; then + if [ -r /dev/tty ]; then + LINES=$(stty size < /dev/tty | awk '{print $1}') + else + LINES=40 + fi +fi + +FIRST=$(($CENTER-$LINES/3)) +FIRST=$(($FIRST < 1 ? 1 : $FIRST)) +LAST=$((${FIRST}+${LINES}-1)) + +DEFAULT_COMMAND="bat --style=numbers --color=always {} || highlight -O ansi -l {} || coderay {} || rougify {} || cat {}" +CMD=${FZF_PREVIEW_COMMAND:-$DEFAULT_COMMAND} +CMD=${CMD//{\}/$(printf %q "$FILE")} + +eval "$CMD" 2> /dev/null | awk "NR >= $FIRST && NR <= $LAST { \ + if (NR == $CENTER) \ + { gsub(/\x1b[[0-9;]*m/, \"&$REVERSE\"); printf(\"$REVERSE%s\n$RESET\", \$0); } \ + else printf(\"$RESET%s\n\", \$0); \ + }" diff --git a/start/fzf/bin/tags.pl b/start/fzf/bin/tags.pl new file mode 100644 index 0000000..4208c16 --- /dev/null +++ b/start/fzf/bin/tags.pl @@ -0,0 +1,15 @@ +#!/usr/bin/env perl + +use strict; + +foreach my $file (@ARGV) { + open my $lines, $file; + while (<$lines>) { + unless (/^\!/) { + s/^[^\t]*/sprintf("%-24s", $&)/e; + s/$/\t$file/; + print; + } + } + close $lines; +} diff --git a/start/fzf/plugin/fzf.vim b/start/fzf/plugin/fzf.vim new file mode 100644 index 0000000..26c35b8 --- /dev/null +++ b/start/fzf/plugin/fzf.vim @@ -0,0 +1,994 @@ +" Copyright (c) 2017 Junegunn Choi +" +" MIT License +" +" Permission is hereby granted, free of charge, to any person obtaining +" a copy of this software and associated documentation files (the +" "Software"), to deal in the Software without restriction, including +" without limitation the rights to use, copy, modify, merge, publish, +" distribute, sublicense, and/or sell copies of the Software, and to +" permit persons to whom the Software is furnished to do so, subject to +" the following conditions: +" +" The above copyright notice and this permission notice shall be +" included in all copies or substantial portions of the Software. +" +" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +" EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +" NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +" LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +" OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +" WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +if exists('g:loaded_fzf') + finish +endif +let g:loaded_fzf = 1 + +let s:is_win = has('win32') || has('win64') +if s:is_win && &shellslash + set noshellslash + let s:base_dir = expand(':h:h') + set shellslash +else + let s:base_dir = expand(':h:h') +endif +if s:is_win + let s:term_marker = '&::FZF' + + function! s:fzf_call(fn, ...) + let shellslash = &shellslash + try + set noshellslash + return call(a:fn, a:000) + finally + let &shellslash = shellslash + endtry + endfunction + + " Use utf-8 for fzf.vim commands + " Return array of shell commands for cmd.exe + function! s:enc_to_cp(str) + if !has('iconv') + return a:str + endif + if !exists('s:codepage') + let s:codepage = libcallnr('kernel32.dll', 'GetACP', 0) + endif + return iconv(a:str, &encoding, 'cp'.s:codepage) + endfunction + function! s:wrap_cmds(cmds) + return map([ + \ '@echo off', + \ 'setlocal enabledelayedexpansion'] + \ + (has('gui_running') ? ['set TERM= > nul'] : []) + \ + (type(a:cmds) == type([]) ? a:cmds : [a:cmds]) + \ + ['endlocal'], + \ 'enc_to_cp(v:val."\r")') + endfunction +else + let s:term_marker = ";#FZF" + + function! s:fzf_call(fn, ...) + return call(a:fn, a:000) + endfunction + + function! s:wrap_cmds(cmds) + return a:cmds + endfunction + + function! s:enc_to_cp(str) + return a:str + endfunction +endif + +function! s:shellesc_cmd(arg) + let escaped = substitute(a:arg, '[&|<>()@^]', '^&', 'g') + let escaped = substitute(escaped, '%', '%%', 'g') + let escaped = substitute(escaped, '"', '\\^&', 'g') + let escaped = substitute(escaped, '\(\\\+\)\(\\^\)', '\1\1\2', 'g') + return '^"'.substitute(escaped, '\(\\\+\)$', '\1\1', '').'^"' +endfunction + +function! fzf#shellescape(arg, ...) + let shell = get(a:000, 0, s:is_win ? 'cmd.exe' : 'sh') + if shell =~# 'cmd.exe$' + return s:shellesc_cmd(a:arg) + endif + return s:fzf_call('shellescape', a:arg) +endfunction + +function! s:fzf_getcwd() + return s:fzf_call('getcwd') +endfunction + +function! s:fzf_fnamemodify(fname, mods) + return s:fzf_call('fnamemodify', a:fname, a:mods) +endfunction + +function! s:fzf_expand(fmt) + return s:fzf_call('expand', a:fmt, 1) +endfunction + +function! s:fzf_tempname() + return s:fzf_call('tempname') +endfunction + +let s:layout_keys = ['window', 'tmux', 'up', 'down', 'left', 'right'] +let s:fzf_go = s:base_dir.'/bin/fzf' +let s:fzf_tmux = s:base_dir.'/bin/fzf-tmux' + +let s:cpo_save = &cpo +set cpo&vim + +function! s:popup_support() + return has('nvim') ? has('nvim-0.4') : has('popupwin') && has('patch-8.2.191') +endfunction + +function! s:default_layout() + return s:popup_support() + \ ? { 'window' : { 'width': 0.9, 'height': 0.6 } } + \ : { 'down': '~40%' } +endfunction + +function! fzf#install() + if s:is_win && !has('win32unix') + let script = s:base_dir.'/install.ps1' + if !filereadable(script) + throw script.' not found' + endif + let script = 'powershell -ExecutionPolicy Bypass -file ' . script + else + let script = s:base_dir.'/install' + if !executable(script) + throw script.' not found' + endif + let script .= ' --bin' + endif + + call s:warn('Running fzf installer ...') + call system(script) + if v:shell_error + throw 'Failed to download fzf: '.script + endif +endfunction + +function! s:version_requirement(val, min) + let val = split(a:val, '\.') + let min = split(a:min, '\.') + for idx in range(0, len(min) - 1) + let v = get(val, idx, 0) + if v < min[idx] | return 0 + elseif v > min[idx] | return 1 + endif + endfor + return 1 +endfunction + +let s:checked = {} +function! fzf#exec(...) + if !exists('s:exec') + if executable(s:fzf_go) + let s:exec = s:fzf_go + elseif executable('fzf') + let s:exec = 'fzf' + elseif input('fzf executable not found. Download binary? (y/n) ') =~? '^y' + redraw + call fzf#install() + return fzf#exec() + else + redraw + throw 'fzf executable not found' + endif + endif + + if a:0 && !has_key(s:checked, a:1) + let command = s:exec . ' --version' + let output = systemlist(command) + if v:shell_error || empty(output) + throw printf('Failed to run "%s": %s', command, output) + endif + let fzf_version = matchstr(output[-1], '[0-9.]\+') + if s:version_requirement(fzf_version, a:1) + let s:checked[a:1] = 1 + return s:exec + elseif a:0 < 2 && input(printf('You need fzf %s or above. Found: %s. Download binary? (y/n) ', a:1, fzf_version)) =~? '^y' + redraw + call fzf#install() + return fzf#exec(a:1, 1) + else + throw printf('You need to upgrade fzf (required: %s or above)', a:1) + endif + endif + + return s:exec +endfunction + +function! s:tmux_enabled() + if has('gui_running') || !exists('$TMUX') + return 0 + endif + + if exists('s:tmux') + return s:tmux + endif + + let s:tmux = 0 + if !executable(s:fzf_tmux) + if executable('fzf-tmux') + let s:fzf_tmux = 'fzf-tmux' + else + return 0 + endif + endif + + let output = system('tmux -V') + let s:tmux = !v:shell_error && output >= 'tmux 1.7' + return s:tmux +endfunction + +function! s:escape(path) + let path = fnameescape(a:path) + return s:is_win ? escape(path, '$') : path +endfunction + +function! s:error(msg) + echohl ErrorMsg + echom a:msg + echohl None +endfunction + +function! s:warn(msg) + echohl WarningMsg + echom a:msg + echohl None +endfunction + +function! s:has_any(dict, keys) + for key in a:keys + if has_key(a:dict, key) + return 1 + endif + endfor + return 0 +endfunction + +function! s:open(cmd, target) + if stridx('edit', a:cmd) == 0 && s:fzf_fnamemodify(a:target, ':p') ==# s:fzf_expand('%:p') + return + endif + execute a:cmd s:escape(a:target) +endfunction + +function! s:common_sink(action, lines) abort + if len(a:lines) < 2 + return + endif + let key = remove(a:lines, 0) + let Cmd = get(a:action, key, 'e') + if type(Cmd) == type(function('call')) + return Cmd(a:lines) + endif + if len(a:lines) > 1 + augroup fzf_swap + autocmd SwapExists * let v:swapchoice='o' + \| call s:warn('fzf: E325: swap file exists: '.s:fzf_expand('')) + augroup END + endif + try + let empty = empty(s:fzf_expand('%')) && line('$') == 1 && empty(getline(1)) && !&modified + " Preserve the current working directory in case it's changed during + " the execution (e.g. `set autochdir` or `autocmd BufEnter * lcd ...`) + let cwd = exists('w:fzf_pushd') ? w:fzf_pushd.dir : expand('%:p:h') + for item in a:lines + if item[0] != '~' && item !~ (s:is_win ? '^[A-Z]:\' : '^/') + let sep = s:is_win ? '\' : '/' + let item = join([cwd, item], cwd[len(cwd)-1] == sep ? '' : sep) + endif + if empty + execute 'e' s:escape(item) + let empty = 0 + else + call s:open(Cmd, item) + endif + if !has('patch-8.0.0177') && !has('nvim-0.2') && exists('#BufEnter') + \ && isdirectory(item) + doautocmd BufEnter + endif + endfor + catch /^Vim:Interrupt$/ + finally + silent! autocmd! fzf_swap + endtry +endfunction + +function! s:get_color(attr, ...) + let gui = !s:is_win && !has('win32unix') && has('termguicolors') && &termguicolors + let fam = gui ? 'gui' : 'cterm' + let pat = gui ? '^#[a-f0-9]\+' : '^[0-9]\+$' + for group in a:000 + let code = synIDattr(synIDtrans(hlID(group)), a:attr, fam) + if code =~? pat + return code + endif + endfor + return '' +endfunction + +function! s:defaults() + let rules = copy(get(g:, 'fzf_colors', {})) + let colors = join(map(items(filter(map(rules, 'call("s:get_color", v:val)'), '!empty(v:val)')), 'join(v:val, ":")'), ',') + return empty(colors) ? '' : fzf#shellescape('--color='.colors) +endfunction + +function! s:validate_layout(layout) + for key in keys(a:layout) + if index(s:layout_keys, key) < 0 + throw printf('Invalid entry in g:fzf_layout: %s (allowed: %s)%s', + \ key, join(s:layout_keys, ', '), key == 'options' ? '. Use $FZF_DEFAULT_OPTS.' : '') + endif + endfor + return a:layout +endfunction + +function! s:evaluate_opts(options) + return type(a:options) == type([]) ? + \ join(map(copy(a:options), 'fzf#shellescape(v:val)')) : a:options +endfunction + +" [name string,] [opts dict,] [fullscreen boolean] +function! fzf#wrap(...) + let args = ['', {}, 0] + let expects = map(copy(args), 'type(v:val)') + let tidx = 0 + for arg in copy(a:000) + let tidx = index(expects, type(arg) == 6 ? type(0) : type(arg), tidx) + if tidx < 0 + throw 'Invalid arguments (expected: [name string] [opts dict] [fullscreen boolean])' + endif + let args[tidx] = arg + let tidx += 1 + unlet arg + endfor + let [name, opts, bang] = args + + if len(name) + let opts.name = name + end + + " Layout: g:fzf_layout (and deprecated g:fzf_height) + if bang + for key in s:layout_keys + if has_key(opts, key) + call remove(opts, key) + endif + endfor + elseif !s:has_any(opts, s:layout_keys) + if !exists('g:fzf_layout') && exists('g:fzf_height') + let opts.down = g:fzf_height + else + let opts = extend(opts, s:validate_layout(get(g:, 'fzf_layout', s:default_layout()))) + endif + endif + + " Colors: g:fzf_colors + let opts.options = s:defaults() .' '. s:evaluate_opts(get(opts, 'options', '')) + + " History: g:fzf_history_dir + if len(name) && len(get(g:, 'fzf_history_dir', '')) + let dir = s:fzf_expand(g:fzf_history_dir) + if !isdirectory(dir) + call mkdir(dir, 'p') + endif + let history = fzf#shellescape(dir.'/'.name) + let opts.options = join(['--history', history, opts.options]) + endif + + " Action: g:fzf_action + if !s:has_any(opts, ['sink', 'sink*']) + let opts._action = get(g:, 'fzf_action', s:default_action) + let opts.options .= ' --expect='.join(keys(opts._action), ',') + function! opts.sink(lines) abort + return s:common_sink(self._action, a:lines) + endfunction + let opts['sink*'] = remove(opts, 'sink') + endif + + return opts +endfunction + +function! s:use_sh() + let [shell, shellslash, shellcmdflag, shellxquote] = [&shell, &shellslash, &shellcmdflag, &shellxquote] + if s:is_win + set shell=cmd.exe + set noshellslash + let &shellcmdflag = has('nvim') ? '/s /c' : '/c' + let &shellxquote = has('nvim') ? '"' : '(' + else + set shell=sh + endif + return [shell, shellslash, shellcmdflag, shellxquote] +endfunction + +function! fzf#run(...) abort +try + let [shell, shellslash, shellcmdflag, shellxquote] = s:use_sh() + + let dict = exists('a:1') ? copy(a:1) : {} + let temps = { 'result': s:fzf_tempname() } + let optstr = s:evaluate_opts(get(dict, 'options', '')) + try + let fzf_exec = fzf#shellescape(fzf#exec()) + catch + throw v:exception + endtry + + if !s:present(dict, 'dir') + let dict.dir = s:fzf_getcwd() + endif + if has('win32unix') && s:present(dict, 'dir') + let dict.dir = fnamemodify(dict.dir, ':p') + endif + + if has_key(dict, 'source') + let source = dict.source + let type = type(source) + if type == 1 + let prefix = '( '.source.' )|' + elseif type == 3 + let temps.input = s:fzf_tempname() + call writefile(source, temps.input) + let prefix = (s:is_win ? 'type ' : 'cat ').fzf#shellescape(temps.input).'|' + else + throw 'Invalid source type' + endif + else + let prefix = '' + endif + + let prefer_tmux = get(g:, 'fzf_prefer_tmux', 0) || has_key(dict, 'tmux') + let use_height = has_key(dict, 'down') && !has('gui_running') && + \ !(has('nvim') || s:is_win || has('win32unix') || s:present(dict, 'up', 'left', 'right', 'window')) && + \ executable('tput') && filereadable('/dev/tty') + let has_vim8_term = has('terminal') && has('patch-8.0.995') + let has_nvim_term = has('nvim-0.2.1') || has('nvim') && !s:is_win + let use_term = has_nvim_term || + \ has_vim8_term && !has('win32unix') && (has('gui_running') || s:is_win || !use_height && s:present(dict, 'down', 'up', 'left', 'right', 'window')) + let use_tmux = (has_key(dict, 'tmux') || (!use_height && !use_term || prefer_tmux) && !has('win32unix') && s:splittable(dict)) && s:tmux_enabled() + if prefer_tmux && use_tmux + let use_height = 0 + let use_term = 0 + endif + if use_height + let height = s:calc_size(&lines, dict.down, dict) + let optstr .= ' --height='.height + elseif use_term + let optstr .= ' --no-height' + endif + let optstr .= s:border_opt(get(dict, 'window', 0)) + let command = prefix.(use_tmux ? s:fzf_tmux(dict) : fzf_exec).' '.optstr.' > '.temps.result + + if use_term + return s:execute_term(dict, command, temps) + endif + + let lines = use_tmux ? s:execute_tmux(dict, command, temps) + \ : s:execute(dict, command, use_height, temps) + call s:callback(dict, lines) + return lines +finally + let [&shell, &shellslash, &shellcmdflag, &shellxquote] = [shell, shellslash, shellcmdflag, shellxquote] +endtry +endfunction + +function! s:present(dict, ...) + for key in a:000 + if !empty(get(a:dict, key, '')) + return 1 + endif + endfor + return 0 +endfunction + +function! s:fzf_tmux(dict) + let size = get(a:dict, 'tmux', '') + if empty(size) + for o in ['up', 'down', 'left', 'right'] + if s:present(a:dict, o) + let spec = a:dict[o] + if (o == 'up' || o == 'down') && spec[0] == '~' + let size = '-'.o[0].s:calc_size(&lines, spec, a:dict) + else + " Legacy boolean option + let size = '-'.o[0].(spec == 1 ? '' : substitute(spec, '^\~', '', '')) + endif + break + endif + endfor + endif + return printf('LINES=%d COLUMNS=%d %s %s %s --', + \ &lines, &columns, fzf#shellescape(s:fzf_tmux), size, (has_key(a:dict, 'source') ? '' : '-')) +endfunction + +function! s:splittable(dict) + return s:present(a:dict, 'up', 'down') && &lines > 15 || + \ s:present(a:dict, 'left', 'right') && &columns > 40 +endfunction + +function! s:pushd(dict) + if s:present(a:dict, 'dir') + let cwd = s:fzf_getcwd() + let w:fzf_pushd = { + \ 'command': haslocaldir() ? 'lcd' : (exists(':tcd') && haslocaldir(-1) ? 'tcd' : 'cd'), + \ 'origin': cwd, + \ 'bufname': bufname('') + \ } + execute 'lcd' s:escape(a:dict.dir) + let cwd = s:fzf_getcwd() + let w:fzf_pushd.dir = cwd + let a:dict.pushd = w:fzf_pushd + return cwd + endif + return '' +endfunction + +augroup fzf_popd + autocmd! + autocmd WinEnter * call s:dopopd() +augroup END + +function! s:dopopd() + if !exists('w:fzf_pushd') + return + endif + + " FIXME: We temporarily change the working directory to 'dir' entry + " of options dictionary (set to the current working directory if not given) + " before running fzf. + " + " e.g. call fzf#run({'dir': '/tmp', 'source': 'ls', 'sink': 'e'}) + " + " After processing the sink function, we have to restore the current working + " directory. But doing so may not be desirable if the function changed the + " working directory on purpose. + " + " So how can we tell if we should do it or not? A simple heuristic we use + " here is that we change directory only if the current working directory + " matches 'dir' entry. However, it is possible that the sink function did + " change the directory to 'dir'. In that case, the user will have an + " unexpected result. + if s:fzf_getcwd() ==# w:fzf_pushd.dir && (!&autochdir || w:fzf_pushd.bufname ==# bufname('')) + execute w:fzf_pushd.command s:escape(w:fzf_pushd.origin) + endif + unlet! w:fzf_pushd +endfunction + +function! s:xterm_launcher() + let fmt = 'xterm -T "[fzf]" -bg "%s" -fg "%s" -geometry %dx%d+%d+%d -e bash -ic %%s' + if has('gui_macvim') + let fmt .= '&& osascript -e "tell application \"MacVim\" to activate"' + endif + return printf(fmt, + \ escape(synIDattr(hlID("Normal"), "bg"), '#'), escape(synIDattr(hlID("Normal"), "fg"), '#'), + \ &columns, &lines/2, getwinposx(), getwinposy()) +endfunction +unlet! s:launcher +if s:is_win || has('win32unix') + let s:launcher = '%s' +else + let s:launcher = function('s:xterm_launcher') +endif + +function! s:exit_handler(code, command, ...) + if a:code == 130 + return 0 + elseif has('nvim') && a:code == 129 + " When deleting the terminal buffer while fzf is still running, + " Nvim sends SIGHUP. + return 0 + elseif a:code > 1 + call s:error('Error running ' . a:command) + if !empty(a:000) + sleep + endif + return 0 + endif + return 1 +endfunction + +function! s:execute(dict, command, use_height, temps) abort + call s:pushd(a:dict) + if has('unix') && !a:use_height + silent! !clear 2> /dev/null + endif + let escaped = (a:use_height || s:is_win) ? a:command : escape(substitute(a:command, '\n', '\\n', 'g'), '%#!') + if has('gui_running') + let Launcher = get(a:dict, 'launcher', get(g:, 'Fzf_launcher', get(g:, 'fzf_launcher', s:launcher))) + let fmt = type(Launcher) == 2 ? call(Launcher, []) : Launcher + if has('unix') + let escaped = "'".substitute(escaped, "'", "'\"'\"'", 'g')."'" + endif + let command = printf(fmt, escaped) + else + let command = escaped + endif + if s:is_win + let batchfile = s:fzf_tempname().'.bat' + call writefile(s:wrap_cmds(command), batchfile) + let command = batchfile + let a:temps.batchfile = batchfile + if has('nvim') + let fzf = {} + let fzf.dict = a:dict + let fzf.temps = a:temps + function! fzf.on_exit(job_id, exit_status, event) dict + call s:pushd(self.dict) + let lines = s:collect(self.temps) + call s:callback(self.dict, lines) + endfunction + let cmd = 'start /wait cmd /c '.command + call jobstart(cmd, fzf) + return [] + endif + elseif has('win32unix') && $TERM !=# 'cygwin' + let shellscript = s:fzf_tempname() + call writefile([command], shellscript) + let command = 'cmd.exe /C '.fzf#shellescape('set "TERM=" & start /WAIT sh -c '.shellscript) + let a:temps.shellscript = shellscript + endif + if a:use_height + let stdin = has_key(a:dict, 'source') ? '' : '< /dev/tty' + call system(printf('tput cup %d > /dev/tty; tput cnorm > /dev/tty; %s %s 2> /dev/tty', &lines, command, stdin)) + else + execute 'silent !'.command + endif + let exit_status = v:shell_error + redraw! + let lines = s:collect(a:temps) + return s:exit_handler(exit_status, command) ? lines : [] +endfunction + +function! s:execute_tmux(dict, command, temps) abort + let command = a:command + let cwd = s:pushd(a:dict) + if len(cwd) + " -c '#{pane_current_path}' is only available on tmux 1.9 or above + let command = join(['cd', fzf#shellescape(cwd), '&&', command]) + endif + + call system(command) + let exit_status = v:shell_error + redraw! + let lines = s:collect(a:temps) + return s:exit_handler(exit_status, command) ? lines : [] +endfunction + +function! s:calc_size(max, val, dict) + let val = substitute(a:val, '^\~', '', '') + if val =~ '%$' + let size = a:max * str2nr(val[:-2]) / 100 + else + let size = min([a:max, str2nr(val)]) + endif + + let srcsz = -1 + if type(get(a:dict, 'source', 0)) == type([]) + let srcsz = len(a:dict.source) + endif + + let opts = $FZF_DEFAULT_OPTS.' '.s:evaluate_opts(get(a:dict, 'options', '')) + if opts =~ 'preview' + return size + endif + let margin = match(opts, '--inline-info\|--info[^-]\{-}inline') > match(opts, '--no-inline-info\|--info[^-]\{-}\(default\|hidden\)') ? 1 : 2 + let margin += stridx(opts, '--border') > stridx(opts, '--no-border') ? 2 : 0 + if stridx(opts, '--header') > stridx(opts, '--no-header') + let margin += len(split(opts, "\n")) + endif + return srcsz >= 0 ? min([srcsz + margin, size]) : size +endfunction + +function! s:getpos() + return {'tab': tabpagenr(), 'win': winnr(), 'winid': win_getid(), 'cnt': winnr('$'), 'tcnt': tabpagenr('$')} +endfunction + +function! s:border_opt(window) + if type(a:window) != type({}) + return '' + endif + + " Border style + let style = tolower(get(a:window, 'border', 'rounded')) + if !has_key(a:window, 'border') && !get(a:window, 'rounded', 1) + let style = 'sharp' + endif + if style == 'none' || style == 'no' + return '' + endif + + " For --border styles, we need fzf 0.24.0 or above + call fzf#exec('0.24.0') + let opt = ' --border=' . style + if has_key(a:window, 'highlight') + let color = s:get_color('fg', a:window.highlight) + if len(color) + let opt .= ' --color=border:' . color + endif + endif + return opt +endfunction + +function! s:split(dict) + let directions = { + \ 'up': ['topleft', 'resize', &lines], + \ 'down': ['botright', 'resize', &lines], + \ 'left': ['vertical topleft', 'vertical resize', &columns], + \ 'right': ['vertical botright', 'vertical resize', &columns] } + let ppos = s:getpos() + let is_popup = 0 + try + if s:present(a:dict, 'window') + if type(a:dict.window) == type({}) + if !s:popup_support() + throw 'Nvim 0.4+ or Vim 8.2.191+ with popupwin feature is required for pop-up window' + end + call s:popup(a:dict.window) + let is_popup = 1 + else + execute 'keepalt' a:dict.window + endif + elseif !s:splittable(a:dict) + execute (tabpagenr()-1).'tabnew' + else + for [dir, triple] in items(directions) + let val = get(a:dict, dir, '') + if !empty(val) + let [cmd, resz, max] = triple + if (dir == 'up' || dir == 'down') && val[0] == '~' + let sz = s:calc_size(max, val, a:dict) + else + let sz = s:calc_size(max, val, {}) + endif + execute cmd sz.'new' + execute resz sz + return [ppos, {}, is_popup] + endif + endfor + endif + return [ppos, is_popup ? {} : { '&l:wfw': &l:wfw, '&l:wfh': &l:wfh }, is_popup] + finally + if !is_popup + setlocal winfixwidth winfixheight + endif + endtry +endfunction + +nnoremap (fzf-insert) i +nnoremap (fzf-normal) +if exists(':tnoremap') + tnoremap (fzf-insert) i + tnoremap (fzf-normal) +endif + +function! s:execute_term(dict, command, temps) abort + let winrest = winrestcmd() + let pbuf = bufnr('') + let [ppos, winopts, is_popup] = s:split(a:dict) + call s:use_sh() + let b:fzf = a:dict + let fzf = { 'buf': bufnr(''), 'pbuf': pbuf, 'ppos': ppos, 'dict': a:dict, 'temps': a:temps, + \ 'winopts': winopts, 'winrest': winrest, 'lines': &lines, + \ 'columns': &columns, 'command': a:command } + function! fzf.switch_back(inplace) + if a:inplace && bufnr('') == self.buf + if bufexists(self.pbuf) + execute 'keepalt keepjumps b' self.pbuf + endif + " No other listed buffer + if bufnr('') == self.buf + enew + endif + endif + endfunction + function! fzf.on_exit(id, code, ...) + if s:getpos() == self.ppos " {'window': 'enew'} + for [opt, val] in items(self.winopts) + execute 'let' opt '=' val + endfor + call self.switch_back(1) + else + if bufnr('') == self.buf + " We use close instead of bd! since Vim does not close the split when + " there's no other listed buffer (nvim +'set nobuflisted') + close + endif + silent! execute 'tabnext' self.ppos.tab + silent! execute self.ppos.win.'wincmd w' + endif + + if bufexists(self.buf) + execute 'bd!' self.buf + endif + + if &lines == self.lines && &columns == self.columns && s:getpos() == self.ppos + execute self.winrest + endif + + let lines = s:collect(self.temps) + if !s:exit_handler(a:code, self.command, 1) + return + endif + + call s:pushd(self.dict) + call s:callback(self.dict, lines) + call self.switch_back(s:getpos() == self.ppos) + + if &buftype == 'terminal' + call feedkeys(&filetype == 'fzf' ? "\(fzf-insert)" : "\(fzf-normal)") + endif + endfunction + + try + call s:pushd(a:dict) + if s:is_win + let fzf.temps.batchfile = s:fzf_tempname().'.bat' + call writefile(s:wrap_cmds(a:command), fzf.temps.batchfile) + let command = fzf.temps.batchfile + else + let command = a:command + endif + let command .= s:term_marker + if has('nvim') + call termopen(command, fzf) + else + let term_opts = {'exit_cb': function(fzf.on_exit)} + if v:version >= 802 + let term_opts.term_kill = 'term' + endif + if is_popup + let term_opts.hidden = 1 + else + let term_opts.curwin = 1 + endif + let fzf.buf = term_start([&shell, &shellcmdflag, command], term_opts) + if exists('&termwinkey') + call setbufvar(fzf.buf, '&termwinkey', '') + endif + if is_popup && exists('#TerminalWinOpen') + doautocmd TerminalWinOpen + endif + if !has('patch-8.0.1261') && !s:is_win + call term_wait(fzf.buf, 20) + endif + endif + tnoremap + finally + call s:dopopd() + endtry + setlocal nospell bufhidden=wipe nobuflisted nonumber + setf fzf + startinsert + return [] +endfunction + +function! s:collect(temps) abort + try + return filereadable(a:temps.result) ? readfile(a:temps.result) : [] + finally + for tf in values(a:temps) + silent! call delete(tf) + endfor + endtry +endfunction + +function! s:callback(dict, lines) abort + let popd = has_key(a:dict, 'pushd') + if popd + let w:fzf_pushd = a:dict.pushd + endif + + try + if has_key(a:dict, 'sink') + for line in a:lines + if type(a:dict.sink) == 2 + call a:dict.sink(line) + else + execute a:dict.sink s:escape(line) + endif + endfor + endif + if has_key(a:dict, 'sink*') + call a:dict['sink*'](a:lines) + endif + catch + if stridx(v:exception, ':E325:') < 0 + echoerr v:exception + endif + endtry + + " We may have opened a new window or tab + if popd + let w:fzf_pushd = a:dict.pushd + call s:dopopd() + endif +endfunction + +if has('nvim') + function s:create_popup(hl, opts) abort + let buf = nvim_create_buf(v:false, v:true) + let opts = extend({'relative': 'editor', 'style': 'minimal'}, a:opts) + let win = nvim_open_win(buf, v:true, opts) + call setwinvar(win, '&winhighlight', 'NormalFloat:'..a:hl) + call setwinvar(win, '&colorcolumn', '') + return buf + endfunction +else + function! s:create_popup(hl, opts) abort + let s:popup_create = {buf -> popup_create(buf, #{ + \ line: a:opts.row, + \ col: a:opts.col, + \ minwidth: a:opts.width, + \ maxwidth: a:opts.width, + \ minheight: a:opts.height, + \ maxheight: a:opts.height, + \ zindex: 1000, + \ })} + autocmd TerminalOpen * ++once call s:popup_create(str2nr(expand(''))) + endfunction +endif + +function! s:popup(opts) abort + " Size and position + let width = min([max([8, a:opts.width > 1 ? a:opts.width : float2nr(&columns * a:opts.width)]), &columns]) + let height = min([max([4, a:opts.height > 1 ? a:opts.height : float2nr(&lines * a:opts.height)]), &lines - has('nvim')]) + let row = float2nr(get(a:opts, 'yoffset', 0.5) * (&lines - height)) + let col = float2nr(get(a:opts, 'xoffset', 0.5) * (&columns - width)) + + " Managing the differences + let row = min([max([0, row]), &lines - has('nvim') - height]) + let col = min([max([0, col]), &columns - width]) + let row += !has('nvim') + let col += !has('nvim') + + call s:create_popup('Normal', { + \ 'row': row, 'col': col, 'width': width, 'height': height + \ }) +endfunction + +let s:default_action = { + \ 'ctrl-t': 'tab split', + \ 'ctrl-x': 'split', + \ 'ctrl-v': 'vsplit' } + +function! s:shortpath() + let short = fnamemodify(getcwd(), ':~:.') + if !has('win32unix') + let short = pathshorten(short) + endif + let slash = (s:is_win && !&shellslash) ? '\' : '/' + return empty(short) ? '~'.slash : short . (short =~ escape(slash, '\').'$' ? '' : slash) +endfunction + +function! s:cmd(bang, ...) abort + let args = copy(a:000) + let opts = { 'options': ['--multi'] } + if len(args) && isdirectory(expand(args[-1])) + let opts.dir = substitute(substitute(remove(args, -1), '\\\(["'']\)', '\1', 'g'), '[/\\]*$', '/', '') + if s:is_win && !&shellslash + let opts.dir = substitute(opts.dir, '/', '\\', 'g') + endif + let prompt = opts.dir + else + let prompt = s:shortpath() + endif + let prompt = strwidth(prompt) < &columns - 20 ? prompt : '> ' + call extend(opts.options, ['--prompt', prompt]) + call extend(opts.options, args) + call fzf#run(fzf#wrap('FZF', opts, a:bang)) +endfunction + +command! -nargs=* -complete=dir -bang FZF call s:cmd(0, ) + +let &cpo = s:cpo_save +unlet s:cpo_save diff --git a/start/goyo/README.md b/start/goyo/README.md new file mode 100644 index 0000000..e37e15c --- /dev/null +++ b/start/goyo/README.md @@ -0,0 +1,130 @@ +goyo.vim ([고요](http://en.wiktionary.org/wiki/고요하다)) +========================================================= + +Distraction-free writing in Vim. + +![](https://raw.github.com/junegunn/i/master/goyo.png) + +(Color scheme: [seoul256](https://github.com/junegunn/seoul256.vim)) + +Best served with [limelight.vim](https://github.com/junegunn/limelight.vim). + +Installation +------------ + +Use your favorite plugin manager. + +- [vim-plug](https://github.com/junegunn/vim-plug) + 1. Add `Plug 'junegunn/goyo.vim'` to .vimrc + 2. Run `:PlugInstall` + +Usage +----- + +- `:Goyo` + - Toggle Goyo +- `:Goyo [dimension]` + - Turn on or resize Goyo +- `:Goyo!` + - Turn Goyo off + +The window can be resized with the usual `[count]` + `>`, `<`, `+`, +`-` keys, and `` + `=` will resize it back to the initial size. + +### Dimension expression + +The expected format of a dimension expression is +`[WIDTH][XOFFSET][x[HEIGHT][YOFFSET]]`. `XOFFSET` and `YOFFSET` should be +prefixed by `+` or `-`. Each component can be given in percentage. + +```vim +" Width +Goyo 120 + +" Height +Goyo x30 + +" Both +Goyo 120x30 + +" In percentage +Goyo 120x50% + +" With offsets +Goyo 50%+25%x50%-25% +``` + +Configuration +------------- + +- `g:goyo_width` (default: 80) +- `g:goyo_height` (default: 85%) +- `g:goyo_linenr` (default: 0) + +### Callbacks + +By default, [vim-airline](https://github.com/bling/vim-airline), +[vim-powerline](https://github.com/Lokaltog/vim-powerline), +[powerline](https://github.com/Lokaltog/powerline), +[lightline.vim](https://github.com/itchyny/lightline.vim), +[vim-signify](https://github.com/mhinz/vim-signify), +and [vim-gitgutter](https://github.com/airblade/vim-gitgutter) are temporarily +disabled while in Goyo mode. + +If you have other plugins that you want to disable/enable, or if you want to +change the default settings of Goyo window, you can set up custom routines +to be triggered on `GoyoEnter` and `GoyoLeave` events. + +```vim +function! s:goyo_enter() + silent !tmux set status off + silent !tmux list-panes -F '\#F' | grep -q Z || tmux resize-pane -Z + set noshowmode + set noshowcmd + set scrolloff=999 + Limelight + " ... +endfunction + +function! s:goyo_leave() + silent !tmux set status on + silent !tmux list-panes -F '\#F' | grep -q Z && tmux resize-pane -Z + set showmode + set showcmd + set scrolloff=5 + Limelight! + " ... +endfunction + +autocmd! User GoyoEnter nested call goyo_enter() +autocmd! User GoyoLeave nested call goyo_leave() +``` + +More examples can be found here: +[Customization](https://github.com/junegunn/goyo.vim/wiki/Customization) + +Inspiration +----------- + +- [LiteDFM](https://github.com/bilalq/lite-dfm) +- [VimRoom](http://projects.mikewest.org/vimroom/) + +Pros. +----- + +1. Works well with splits. Doesn't mess up with the current window arrangement +1. Works well with popular statusline plugins +1. Prevents accessing the empty windows around the central buffer +1. Can be closed with any of `:q[uit]`, `:clo[se]`, `:tabc[lose]`, or `:Goyo` +1. Can dynamically change the width of the window +1. Adjusts its colors when color scheme is changed +1. Realigns the window when the terminal (or window) is resized or when the size + of the font is changed +1. Correctly hides colorcolumns and Emojis in statusline +1. Highly customizable with callbacks + +License +------- + +MIT + diff --git a/start/goyo/autoload/goyo.vim b/start/goyo/autoload/goyo.vim new file mode 100644 index 0000000..94216d1 --- /dev/null +++ b/start/goyo/autoload/goyo.vim @@ -0,0 +1,447 @@ +" Copyright (c) 2015 Junegunn Choi +" +" MIT License +" +" Permission is hereby granted, free of charge, to any person obtaining +" a copy of this software and associated documentation files (the +" "Software"), to deal in the Software without restriction, including +" without limitation the rights to use, copy, modify, merge, publish, +" distribute, sublicense, and/or sell copies of the Software, and to +" permit persons to whom the Software is furnished to do so, subject to +" the following conditions: +" +" The above copyright notice and this permission notice shall be +" included in all copies or substantial portions of the Software. +" +" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +" EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +" NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +" LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +" OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +" WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +let s:cpo_save = &cpo +set cpo&vim + +function! s:const(val, min, max) + return min([max([a:val, a:min]), a:max]) +endfunction + +function! s:get_color(group, attr) + return synIDattr(synIDtrans(hlID(a:group)), a:attr) +endfunction + +function! s:set_color(group, attr, color) + let gui = has('gui_running') || has('termguicolors') && &termguicolors + execute printf('hi %s %s%s=%s', a:group, gui ? 'gui' : 'cterm', a:attr, a:color) +endfunction + +function! s:blank(repel) + if bufwinnr(t:goyo_pads.r) <= bufwinnr(t:goyo_pads.l) + 1 + \ || bufwinnr(t:goyo_pads.b) <= bufwinnr(t:goyo_pads.t) + 3 + call s:goyo_off() + endif + execute 'wincmd' a:repel +endfunction + +function! s:init_pad(command) + execute a:command + + setlocal buftype=nofile bufhidden=wipe nomodifiable nobuflisted noswapfile + \ nonu nocursorline nocursorcolumn winfixwidth winfixheight statusline=\ + if exists('&rnu') + setlocal nornu + endif + if exists('&colorcolumn') + setlocal colorcolumn= + endif + let bufnr = winbufnr(0) + + execute winnr('#') . 'wincmd w' + return bufnr +endfunction + +function! s:setup_pad(bufnr, vert, size, repel) + let win = bufwinnr(a:bufnr) + execute win . 'wincmd w' + execute (a:vert ? 'vertical ' : '') . 'resize ' . max([0, a:size]) + augroup goyop + execute 'autocmd WinEnter,CursorMoved nested call s:blank("'.a:repel.'")' + autocmd WinLeave call s:hide_statusline() + augroup END + + " To hide scrollbars of pad windows in GVim + let diff = winheight(0) - line('$') - (has('gui_running') ? 2 : 0) + if diff > 0 + setlocal modifiable + call append(0, map(range(1, diff), '""')) + normal! gg + setlocal nomodifiable + endif + execute winnr('#') . 'wincmd w' +endfunction + +function! s:resize_pads() + augroup goyop + autocmd! + augroup END + + let t:goyo_dim.width = s:const(t:goyo_dim.width, 2, &columns) + let t:goyo_dim.height = s:const(t:goyo_dim.height, 2, &lines) + + let vmargin = max([0, (&lines - t:goyo_dim.height) / 2 - 1]) + let yoff = s:const(t:goyo_dim.yoff, - vmargin, vmargin) + let top = vmargin + yoff + let bot = vmargin - yoff - 1 + call s:setup_pad(t:goyo_pads.t, 0, top, 'j') + call s:setup_pad(t:goyo_pads.b, 0, bot, 'k') + + let nwidth = max([len(string(line('$'))) + 1, &numberwidth]) + let width = t:goyo_dim.width + (&number ? nwidth : 0) + let hmargin = max([0, (&columns - width) / 2 - 1]) + let xoff = s:const(t:goyo_dim.xoff, - hmargin, hmargin) + call s:setup_pad(t:goyo_pads.l, 1, hmargin + xoff, 'l') + call s:setup_pad(t:goyo_pads.r, 1, hmargin - xoff, 'h') +endfunction + +function! s:tranquilize() + let bg = s:get_color('Normal', 'bg#') + for grp in ['NonText', 'FoldColumn', 'ColorColumn', 'VertSplit', + \ 'StatusLine', 'StatusLineNC', 'SignColumn'] + " -1 on Vim / '' on GVim + if bg == -1 || empty(bg) + call s:set_color(grp, 'fg', get(g:, 'goyo_bg', 'black')) + call s:set_color(grp, 'bg', 'NONE') + else + call s:set_color(grp, 'fg', bg) + call s:set_color(grp, 'bg', bg) + endif + call s:set_color(grp, '', 'NONE') + endfor +endfunction + +function! s:hide_statusline() + setlocal statusline=\ +endfunction + +function! s:hide_linenr() + if !get(g:, 'goyo_linenr', 0) + setlocal nonu + if exists('&rnu') + setlocal nornu + endif + endif + if exists('&colorcolumn') + setlocal colorcolumn= + endif +endfunction + +function! s:maps_nop() + let mapped = filter(['R', 'H', 'J', 'K', 'L', '|', '_'], + \ "empty(maparg(\"\\".v:val, 'n'))") + for c in mapped + execute 'nnoremap '.escape(c, '|').' ' + endfor + return mapped +endfunction + +function! s:maps_resize() + let commands = { + \ '=': ':let t:goyo_dim = parse_arg(t:goyo_dim_expr) call resize_pads()', + \ '>': ':let t:goyo_dim.width = winwidth(0) + 2 * v:count1 call resize_pads()', + \ '<': ':let t:goyo_dim.width = winwidth(0) - 2 * v:count1 call resize_pads()', + \ '+': ':let t:goyo_dim.height += 2 * v:count1 call resize_pads()', + \ '-': ':let t:goyo_dim.height -= 2 * v:count1 call resize_pads()' + \ } + let mapped = filter(keys(commands), "empty(maparg(\"\\".v:val, 'n'))") + for c in mapped + execute 'nnoremap '.c.' '.commands[c] + endfor + return mapped +endfunction + +nnoremap (goyo-resize) :call resize_pads() + +function! s:goyo_on(dim) + let dim = s:parse_arg(a:dim) + if empty(dim) + return + endif + + let s:orig_tab = tabpagenr() + let settings = + \ { 'laststatus': &laststatus, + \ 'showtabline': &showtabline, + \ 'fillchars': &fillchars, + \ 'winminwidth': &winminwidth, + \ 'winwidth': &winwidth, + \ 'winminheight': &winminheight, + \ 'winheight': &winheight, + \ 'ruler': &ruler, + \ 'sidescroll': &sidescroll, + \ 'sidescrolloff': &sidescrolloff + \ } + + " New tab + tab split + + let t:goyo_master = winbufnr(0) + let t:goyo_dim = dim + let t:goyo_dim_expr = a:dim + let t:goyo_pads = {} + let t:goyo_revert = settings + let t:goyo_maps = extend(s:maps_nop(), s:maps_resize()) + if has('gui_running') + let t:goyo_revert.guioptions = &guioptions + endif + + " vim-gitgutter + let t:goyo_disabled_gitgutter = get(g:, 'gitgutter_enabled', 0) + if t:goyo_disabled_gitgutter + silent! GitGutterDisable + endif + + " vim-signify + let t:goyo_disabled_signify = exists('b:sy') && b:sy.active + if t:goyo_disabled_signify + SignifyToggle + endif + + " vim-airline + let t:goyo_disabled_airline = exists('#airline') + if t:goyo_disabled_airline + AirlineToggle + endif + + " vim-powerline + let t:goyo_disabled_powerline = exists('#PowerlineMain') + if t:goyo_disabled_powerline + augroup PowerlineMain + autocmd! + augroup END + augroup! PowerlineMain + endif + + " lightline.vim + let t:goyo_disabled_lightline = exists('#lightline') + if t:goyo_disabled_lightline + silent! call lightline#disable() + endif + + call s:hide_linenr() + " Global options + let &winheight = max([&winminheight, 1]) + set winminheight=1 + set winheight=1 + set winminwidth=1 winwidth=1 + set laststatus=0 + set showtabline=0 + set noruler + set fillchars+=vert:\ + set fillchars+=stl:\ + set fillchars+=stlnc:\ + set sidescroll=1 + set sidescrolloff=0 + + " Hide left-hand scrollbars + if has('gui_running') + set guioptions-=l + set guioptions-=L + endif + + let t:goyo_pads.l = s:init_pad('vertical topleft new') + let t:goyo_pads.r = s:init_pad('vertical botright new') + let t:goyo_pads.t = s:init_pad('topleft new') + let t:goyo_pads.b = s:init_pad('botright new') + + call s:resize_pads() + call s:tranquilize() + + augroup goyo + autocmd! + autocmd TabLeave * call s:goyo_off() + autocmd VimResized * call s:resize_pads() + autocmd ColorScheme * call s:tranquilize() + autocmd BufWinEnter * call s:hide_linenr() | call s:hide_statusline() + autocmd WinEnter,WinLeave * call s:hide_statusline() + if has('nvim') + autocmd TermClose * call feedkeys("\(goyo-resize)") + endif + augroup END + + call s:hide_statusline() + if exists('g:goyo_callbacks[0]') + call g:goyo_callbacks[0]() + endif + if exists('#User#GoyoEnter') + doautocmd User GoyoEnter + endif +endfunction + +function! s:goyo_off() + if !exists('#goyo') + return + endif + + " Oops, not this tab + if !exists('t:goyo_revert') + return + endif + + " Clear auto commands + augroup goyo + autocmd! + augroup END + augroup! goyo + augroup goyop + autocmd! + augroup END + augroup! goyop + + for c in t:goyo_maps + execute 'nunmap '.escape(c, '|') + endfor + + let goyo_revert = t:goyo_revert + let goyo_disabled_gitgutter = t:goyo_disabled_gitgutter + let goyo_disabled_signify = t:goyo_disabled_signify + let goyo_disabled_airline = t:goyo_disabled_airline + let goyo_disabled_powerline = t:goyo_disabled_powerline + let goyo_disabled_lightline = t:goyo_disabled_lightline + let goyo_orig_buffer = t:goyo_master + let [line, col] = [line('.'), col('.')] + + if tabpagenr() == 1 + tabnew + normal! gt + bd + endif + tabclose + execute 'normal! '.s:orig_tab.'gt' + if winbufnr(0) == goyo_orig_buffer + " Doesn't work if window closed with `q` + execute printf('normal! %dG%d|', line, col) + endif + + let wmw = remove(goyo_revert, 'winminwidth') + let ww = remove(goyo_revert, 'winwidth') + let &winwidth = ww + let &winminwidth = wmw + let wmh = remove(goyo_revert, 'winminheight') + let wh = remove(goyo_revert, 'winheight') + let &winheight = max([wmh, 1]) + let &winminheight = wmh + let &winheight = wh + + for [k, v] in items(goyo_revert) + execute printf('let &%s = %s', k, string(v)) + endfor + execute 'colo '. get(g:, 'colors_name', 'default') + + if goyo_disabled_gitgutter + silent! GitGutterEnable + endif + + if goyo_disabled_signify + silent! if !b:sy.active + SignifyToggle + endif + endif + + if goyo_disabled_airline && !exists('#airline') + AirlineToggle + " For some reason, Airline requires two refreshes to avoid display + " artifacts + silent! AirlineRefresh + silent! AirlineRefresh + endif + + if goyo_disabled_powerline && !exists('#PowerlineMain') + doautocmd PowerlineStartup VimEnter + silent! PowerlineReloadColorscheme + endif + + if goyo_disabled_lightline + silent! call lightline#enable() + endif + + if exists('#Powerline') + doautocmd Powerline ColorScheme + endif + + if exists('g:goyo_callbacks[1]') + call g:goyo_callbacks[1]() + endif + if exists('#User#GoyoLeave') + doautocmd User GoyoLeave + endif +endfunction + +function! s:relsz(expr, limit) + if a:expr !~ '%$' + return str2nr(a:expr) + endif + return a:limit * str2nr(a:expr[:-2]) / 100 +endfunction + +function! s:parse_arg(arg) + if exists('g:goyo_height') || !exists('g:goyo_margin_top') && !exists('g:goyo_margin_bottom') + let height = s:relsz(get(g:, 'goyo_height', '85%'), &lines) + let yoff = 0 + else + let top = max([0, s:relsz(get(g:, 'goyo_margin_top', 4), &lines)]) + let bot = max([0, s:relsz(get(g:, 'goyo_margin_bottom', 4), &lines)]) + let height = &lines - top - bot + let yoff = top - bot + endif + + let dim = { 'width': s:relsz(get(g:, 'goyo_width', 80), &columns), + \ 'height': height, + \ 'xoff': 0, + \ 'yoff': yoff } + if empty(a:arg) + return dim + endif + let parts = matchlist(a:arg, '^\s*\([0-9]\+%\?\)\?\([+-][0-9]\+%\?\)\?\%(x\([0-9]\+%\?\)\?\([+-][0-9]\+%\?\)\?\)\?\s*$') + if empty(parts) + echohl WarningMsg + echo 'Invalid dimension expression: '.a:arg + echohl None + return {} + endif + if !empty(parts[1]) | let dim.width = s:relsz(parts[1], &columns) | endif + if !empty(parts[2]) | let dim.xoff = s:relsz(parts[2], &columns) | endif + if !empty(parts[3]) | let dim.height = s:relsz(parts[3], &lines) | endif + if !empty(parts[4]) | let dim.yoff = s:relsz(parts[4], &lines) | endif + return dim +endfunction + +function! goyo#execute(bang, dim) + if a:bang + if exists('#goyo') + call s:goyo_off() + endif + else + if exists('#goyo') == 0 + call s:goyo_on(a:dim) + elseif !empty(a:dim) + if winnr('$') < 5 + call s:goyo_off() + return goyo#execute(a:bang, a:dim) + endif + let dim = s:parse_arg(a:dim) + if !empty(dim) + let t:goyo_dim = dim + let t:goyo_dim_expr = a:dim + call s:resize_pads() + endif + else + call s:goyo_off() + end + end +endfunction + +let &cpo = s:cpo_save +unlet s:cpo_save + diff --git a/start/goyo/doc/goyo.txt b/start/goyo/doc/goyo.txt new file mode 100644 index 0000000..c703146 --- /dev/null +++ b/start/goyo/doc/goyo.txt @@ -0,0 +1,170 @@ +goyo.txt goyo Last change: April 2 2017 +GOYO - TABLE OF CONTENTS *goyo* *goyo-toc* +============================================================================== + + goyo.vim (고요) + Installation + Usage + Dimension expression + Configuration + Callbacks + Inspiration + Pros. + License + +GOYO.VIM (고요) *goyo-vim* +============================================================================== + +Distraction-free writing in Vim. + +https://raw.github.com/junegunn/i/master/goyo.png + +(Color scheme: {seoul256}{1}) + +Best served with {limelight.vim}{2}. + + {1} https://github.com/junegunn/seoul256.vim + {2} https://github.com/junegunn/limelight.vim + + +INSTALLATION *goyo-installation* +============================================================================== + +Use your favorite plugin manager. + + *:PlugInstall* + + - {vim-plug}{3} + 1. Add `Plug 'junegunn/goyo.vim'` to .vimrc + 2. Run `:PlugInstall` + + {3} https://github.com/junegunn/vim-plug + + +USAGE *goyo-usage* +============================================================================== + + *:Goyo* + + - `:Goyo` + - Toggle Goyo + - `:Goyo [dimension]` + - Turn on or resize Goyo + - `:Goyo!` + - Turn Goyo off + +The window can be resized with the usual [count]`CTRL-W` + `>`, `<`, `+`, `-` keys, +and `CTRL-W` + `=` will resize it back to the initial size. + + +< Dimension expression >______________________________________________________~ + *goyo-dimension-expression* + +The expected format of a dimension expression is +`[WIDTH][XOFFSET][x[HEIGHT][YOFFSET]]`. `XOFFSET` and `YOFFSET` should be +prefixed by `+` or `-`. Each component can be given in percentage. +> + " Width + Goyo 120 + + " Height + Goyo x30 + + " Both + Goyo 120x30 + + " In percentage + Goyo 120x50% + + " With offsets + Goyo 50%+25%x50%-25% +< + +CONFIGURATION *goyo-configuration* +============================================================================== + + *g:goyo_width* *g:goyo_height* *g:goyo_linenr* + + - `g:goyo_width` (default: 80) + - `g:goyo_height` (default: 85%) + - `g:goyo_linenr` (default: 0) + + +< Callbacks >_________________________________________________________________~ + *goyo-callbacks* + +By default, {vim-airline}{4}, {vim-powerline}{5}, {powerline}{6}, +{lightline.vim}{7}, {vim-signify}{8}, and {vim-gitgutter}{9} are temporarily +disabled while in Goyo mode. + +If you have other plugins that you want to disable/enable, or if you want to +change the default settings of Goyo window, you can set up custom routines to +be triggered on `GoyoEnter` and `GoyoLeave` events. +> + function! s:goyo_enter() + silent !tmux set status off + silent !tmux list-panes -F '\#F' | grep -q Z || tmux resize-pane -Z + set noshowmode + set noshowcmd + set scrolloff=999 + Limelight + " ... + endfunction + + function! s:goyo_leave() + silent !tmux set status on + silent !tmux list-panes -F '\#F' | grep -q Z && tmux resize-pane -Z + set showmode + set showcmd + set scrolloff=5 + Limelight! + " ... + endfunction + + autocmd! User GoyoEnter nested call goyo_enter() + autocmd! User GoyoLeave nested call goyo_leave() +< +More examples can be found here: {Customization}{10} + + {4} https://github.com/bling/vim-airline + {5} https://github.com/Lokaltog/vim-powerline + {6} https://github.com/Lokaltog/powerline + {7} https://github.com/itchyny/lightline.vim + {8} https://github.com/mhinz/vim-signify + {9} https://github.com/airblade/vim-gitgutter + {10} https://github.com/junegunn/goyo.vim/wiki/Customization + + +INSPIRATION *goyo-inspiration* +============================================================================== + + - {LiteDFM}{11} + - {VimRoom}{12} + + {11} https://github.com/bilalq/lite-dfm + {12} http://projects.mikewest.org/vimroom/ + + +PROS. *goyo-pros* +============================================================================== + + 1. Works well with splits. Doesn't mess up with the current window arrangement + 2. Works well with popular statusline plugins + 3. Prevents accessing the empty windows around the central buffer + 4. Can be closed with any of `:q[uit]`, `:clo[se]`, `:tabc[lose]`, or `:Goyo` + 5. Can dynamically change the width of the window + 6. Adjusts its colors when color scheme is changed + 7. Realigns the window when the terminal (or window) is resized or when the size + of the font is changed + 8. Correctly hides colorcolumns and Emojis in statusline + 9. Highly customizable with callbacks + + +LICENSE *goyo-license* +============================================================================== + +MIT + + +============================================================================== +vim:tw=78:sw=2:ts=2:ft=help:norl:nowrap: diff --git a/start/goyo/plugin/goyo.vim b/start/goyo/plugin/goyo.vim new file mode 100644 index 0000000..af4793a --- /dev/null +++ b/start/goyo/plugin/goyo.vim @@ -0,0 +1,24 @@ +" Copyright (c) 2015 Junegunn Choi +" +" MIT License +" +" Permission is hereby granted, free of charge, to any person obtaining +" a copy of this software and associated documentation files (the +" "Software"), to deal in the Software without restriction, including +" without limitation the rights to use, copy, modify, merge, publish, +" distribute, sublicense, and/or sell copies of the Software, and to +" permit persons to whom the Software is furnished to do so, subject to +" the following conditions: +" +" The above copyright notice and this permission notice shall be +" included in all copies or substantial portions of the Software. +" +" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +" EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +" NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +" LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +" OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +" WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +command! -nargs=? -bar -bang Goyo call goyo#execute(0, ) diff --git a/start/lightline/LICENSE b/start/lightline/LICENSE new file mode 100644 index 0000000..56144fc --- /dev/null +++ b/start/lightline/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2013-2019 itchyny + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/start/lightline/README.md b/start/lightline/README.md new file mode 100644 index 0000000..1e6eb81 --- /dev/null +++ b/start/lightline/README.md @@ -0,0 +1,389 @@ +# lightline.vim +A light and configurable statusline/tabline plugin for Vim + +https://github.com/itchyny/lightline.vim + +### powerline (default) + +![lightline.vim - powerline](https://raw.githubusercontent.com/wiki/itchyny/lightline.vim/image/powerline.png) + +### wombat + +![lightline.vim - wombat](https://raw.githubusercontent.com/wiki/itchyny/lightline.vim/image/wombat.png) + +### jellybeans + +![lightline.vim - jellybeans](https://raw.githubusercontent.com/wiki/itchyny/lightline.vim/image/jellybeans.png) + +### solarized dark + +![lightline.vim - solarized_dark](https://raw.githubusercontent.com/wiki/itchyny/lightline.vim/image/solarized_dark.png) + +### solarized light + +![lightline.vim - solarized_light](https://raw.githubusercontent.com/wiki/itchyny/lightline.vim/image/solarized_light.png) + +### PaperColor light + +![lightline.vim - PaperColor](https://raw.githubusercontent.com/wiki/itchyny/lightline.vim/image/PaperColor.png) + +### seoul256 + +![lightline.vim - seoul256](https://raw.githubusercontent.com/wiki/itchyny/lightline.vim/image/seoul256.png) + +### one + +![lightline.vim - one](https://raw.githubusercontent.com/wiki/itchyny/lightline.vim/image/one.png) + +### landscape + +![lightline.vim - landscape](https://raw.githubusercontent.com/wiki/itchyny/lightline.vim/image/landscape.png) + +landscape is my colorscheme, which is a high-contrast cterm-supported colorscheme, available at https://github.com/itchyny/landscape.vim + +## Why yet another clone of powerline? ++ [vim-powerline](https://github.com/Lokaltog/vim-powerline) is a nice plugin, but deprecated. ++ [powerline](https://github.com/powerline/powerline) is a nice plugin, but difficult to configure. ++ [vim-airline](https://github.com/vim-airline/vim-airline) is a nice plugin, but it uses too much functions of other plugins, which should be done by users in `.vimrc`. + +## Spirit of this plugin ++ Minimalism. The core script is very small to achieve enough functions as a statusline plugin. ++ Configurability. You can create your own component and easily add to the statusline and the tabline. ++ Orthogonality. The plugin does not rely on the implementation of other plugins. Such plugin crossing settings should be configured by users. + +## Installation +### [Pathogen](https://github.com/tpope/vim-pathogen) +1. Install with the following command. + + git clone https://github.com/itchyny/lightline.vim ~/.vim/bundle/lightline.vim + +### [Vundle](https://github.com/VundleVim/Vundle.vim) +1. Add the following configuration to your `.vimrc`. + + Plugin 'itchyny/lightline.vim' + +2. Install with `:PluginInstall`. + +### [NeoBundle](https://github.com/Shougo/neobundle.vim) +1. Add the following configuration to your `.vimrc`. + + NeoBundle 'itchyny/lightline.vim' + +2. Install with `:NeoBundleInstall`. + +### [vim-plug](https://github.com/junegunn/vim-plug) +1. Add the following configuration to your `.vimrc`. + + Plug 'itchyny/lightline.vim' + +2. Install with `:PlugInstall`. + +## Introduction +After installing this plugin, you restart the editor and will get a cool statusline. +![lightline.vim - tutorial](https://raw.githubusercontent.com/wiki/itchyny/lightline.vim/image/tutorial/1.png) + +The color of the statusline changes due to the mode of Vim. Try typing something, selecting in visual mode and replacing some texts. + +If the statusline looks like +![lightline.vim - tutorial](https://raw.githubusercontent.com/wiki/itchyny/lightline.vim/image/tutorial/21.png) + +add the following configuration to your `.vimrc`. +```vim +set laststatus=2 +``` + +If the statusline is not coloured like +![lightline.vim - tutorial](https://raw.githubusercontent.com/wiki/itchyny/lightline.vim/image/tutorial/20.png) + +then modify `TERM` in your shell configuration (`.zshrc` for example) +```sh +export TERM=xterm-256color +``` +and then add the following configure to your `.vimrc`. +```vim +if !has('gui_running') + set t_Co=256 +endif +``` + +Your statusline appears to work correctly? If yes, great, thanks for choosing lightline.vim! If no, please file an issue report to the [issue tracker](https://github.com/itchyny/lightline.vim/issues). + +By the way, `-- INSERT --` is unnecessary anymore because the mode information is displayed in the statusline. +![lightline.vim - tutorial](https://raw.githubusercontent.com/wiki/itchyny/lightline.vim/image/tutorial/13.png) +If you want to get rid of it, configure as follows. +```vim +set noshowmode +``` + +## Colorscheme configuration +The lightline.vim plugin provides multiple colorschemes to meet your editor colorscheme. +Do not be confused, editor colorscheme rules how codes look like in buffers and lightline.vim has independent colorscheme feature, which rules how the statusline looks like. + +If you are using wombat colorscheme, add the following setting to your `.vimrc`, +```vim +let g:lightline = { + \ 'colorscheme': 'wombat', + \ } +``` +restart Vim and the statusline looks like: + +![lightline.vim - tutorial](https://raw.githubusercontent.com/wiki/itchyny/lightline.vim/image/tutorial/2.png) + +If the colors of the statusline do not change, move the settings of `g:lightline` before setting the editor colorscheme. + +There are many lightline colorschemes available as screenshots shown above. See `:h g:lightline.colorscheme` for the complete list. + +## Advanced configuration +The default appearance of lightline.vim is carefully designed that the tutorial is enough here for most people. +So please read this section if you really want to configure and enjoy the configurability of lightline.vim. + +Sometimes people want to display information of other plugins. +For example git branch information, syntax check errors and some statuses of plugins. + +The lightline.vim plugin does not provide any plugin integration by default. +This plugin considers orthogonality to be one of the important ideas, which means that the plugin does not rely on implementation of other plugins. +Once a plugin starts to integrate with some famous plugins, it should be kept updated to follow the changes of the plugins, and should accept integration requests with new plugins and it will suffer from performance regression due to plugin availability checks. + +Instead, lightline.vim provides a simple API that user can easily integrate with other plugins. +Once you understand how to configure and how it will be displayed in the statusline, you can also tell how to integrate with your favorite plugins. + +Let's start to configure the appearance. +The statusline is composed by multiple components. +It shows the current mode, filename, modified status on the left, and file format, encoding, filetype and cursor positions on the right. +So in order to add something in the statusline, you firstly create a new component and specify the place. + +This is the hello world of lightline.vim component. +```vim +let g:lightline = { + \ 'colorscheme': 'wombat', + \ 'active': { + \ 'left': [ [ 'mode', 'paste' ], + \ [ 'readonly', 'filename', 'modified', 'helloworld' ] ] + \ }, + \ 'component': { + \ 'helloworld': 'Hello, world!' + \ }, + \ } +``` +The statusline will look like: +![lightline.vim - tutorial](https://raw.githubusercontent.com/wiki/itchyny/lightline.vim/image/tutorial/3.png) + +You have succeeded in displaying `Hello, world!` in the statusline. +The `helloworld` component is added to `g:lightline.active.left` and its content is configured in `g:lightline.component`. +The component contents are simply added to `&statusline`. +Try `:echo &statusline`, it might be a little bit complicated, but you will find `Hello, world!` somewhere. + +You can use `'statusline'` syntax for lightline.vim components. +Consult `:h 'statusline'` to see what's available here. +For example, if you want to print the value of character under the cursor in hexadecimal, configure as +```vim +let g:lightline = { + \ 'colorscheme': 'wombat', + \ 'active': { + \ 'left': [ [ 'mode', 'paste' ], + \ [ 'readonly', 'filename', 'modified', 'charvaluehex' ] ] + \ }, + \ 'component': { + \ 'charvaluehex': '0x%B' + \ }, + \ } +``` +![lightline.vim - tutorial](https://raw.githubusercontent.com/wiki/itchyny/lightline.vim/image/tutorial/4.png) + +You want the character value information on the right hand side? OK, configure as +```vim +let g:lightline = { + \ 'colorscheme': 'wombat', + \ 'active': { + \ 'right': [ [ 'lineinfo' ], + \ [ 'percent' ], + \ [ 'fileformat', 'fileencoding', 'filetype', 'charvaluehex' ] ] + \ }, + \ 'component': { + \ 'charvaluehex': '0x%B' + \ }, + \ } +``` +![lightline.vim - tutorial](https://raw.githubusercontent.com/wiki/itchyny/lightline.vim/image/tutorial/5.png) + +We have learned how to add a simple component. + +- See `:h 'statusline'` to check the statusline flags. +- Add a new component to `g:lightline.component`. +- Add the component name to `g:lightline.active.left` or `g:lightline.active.right`. + +You can also configure the statusline of inactive buffers by adding the component to `g:lightline.inactive.left` or `g:lightline.inactive.right`. + + +Now let's add some integrations with other plugin. +The name of the git branch is important these days. +But lightline.vim does not provide this information by default because it is also one of plugin crossing configurations, and not all people want the integration. + +In order to show the branch name in the statusline, install some plugins which provides the branch information. +The [vim-fugitive](https://github.com/tpope/vim-fugitive) plugin is a famous plugin so let's integrate lightline.vim with it. +If you don't like to install full git integration but just want to display the branch name in the statusline, you can use the [vim-gitbranch](https://github.com/itchyny/vim-gitbranch) plugin which provides `gitbranch#name` function. +```vim +let g:lightline = { + \ 'colorscheme': 'wombat', + \ 'active': { + \ 'left': [ [ 'mode', 'paste' ], + \ [ 'gitbranch', 'readonly', 'filename', 'modified' ] ] + \ }, + \ 'component_function': { + \ 'gitbranch': 'fugitive#head' + \ }, + \ } +``` +![lightline.vim - tutorial](https://raw.githubusercontent.com/wiki/itchyny/lightline.vim/image/tutorial/6.png) + +Okay, now the statusline shows that we are coding at the master branch. +What do we learn from this example? + +- Find out the function which is suitable to use in the statusline. +- Create a function component. The previous `charvaluehex` component has `'statusline'` item configuration and registered in `g:lightline.component`. In the current example, we register the name of the function in `g:lightline.component_function`. It should return the string to be displayed in the statusline. +- Add the component name `gitbranch` to `g:lightline.active.left` or `g:lightline.active.right`. + + +Here we have leaned two kinds of components. + +- component: it has a `%`-prefixed item which you can find the meaning at `:h 'statusline'`. All the default components of lightline.vim are components in this style. See the default components at `:h g:lightline.component`. +- function component: the name of functions are registered. The function is called again and again so be careful not to register a heavy function. See the help with `:h g:lightline.component_function`. + + +The function component is an important design for the configurability of lightline.vim. +By providing the configuration interface via functions, you can adjust the statusline information as you wish. +For the proof, let's look into some configuration examples in Q&A style. + +### Can I hide the readonly component in the help buffer? +Yes, create a function component for `readonly`. +The configuration of function component has priority over the default component. +```vim +let g:lightline = { + \ 'component_function': { + \ 'readonly': 'LightlineReadonly', + \ }, + \ } + +function! LightlineReadonly() + return &readonly && &filetype !=# 'help' ? 'RO' : '' +endfunction +``` +![lightline.vim - tutorial](https://raw.githubusercontent.com/wiki/itchyny/lightline.vim/image/tutorial/7.png) + +### Can I hide the readonly component in other plugins buffer? +Yes, modify the `LightlineReadonly` function as you wish. +```vim +function! LightlineReadonly() + return &readonly && &filetype !~# '\v(help|vimfiler|unite)' ? 'RO' : '' +endfunction + +let g:unite_force_overwrite_statusline = 0 +let g:vimfiler_force_overwrite_statusline = 0 +``` +![lightline.vim - tutorial](https://raw.githubusercontent.com/wiki/itchyny/lightline.vim/image/tutorial/8.png) + +### Can I display the plugin information at the filename component? +Yes, overwrite the filename component. +```vim +let g:lightline = { + \ 'component_function': { + \ 'filename': 'LightlineFilename', + \ }, + \ } + +function! LightlineFilename() + return &filetype ==# 'vimfiler' ? vimfiler#get_status_string() : + \ &filetype ==# 'unite' ? unite#get_status_string() : + \ &filetype ==# 'vimshell' ? vimshell#get_status_string() : + \ expand('%:t') !=# '' ? expand('%:t') : '[No Name]' +endfunction + +let g:unite_force_overwrite_statusline = 0 +let g:vimfiler_force_overwrite_statusline = 0 +let g:vimshell_force_overwrite_statusline = 0 +``` +![lightline.vim - tutorial](https://raw.githubusercontent.com/wiki/itchyny/lightline.vim/image/tutorial/9.png) + +### Can I display the plugin name at the mode component? +Yes, overwrite the mode component. +```vim +let g:lightline = { + \ 'component_function': { + \ 'mode': 'LightlineMode', + \ }, + \ } + +function! LightlineMode() + return expand('%:t') ==# '__Tagbar__' ? 'Tagbar': + \ expand('%:t') ==# 'ControlP' ? 'CtrlP' : + \ &filetype ==# 'unite' ? 'Unite' : + \ &filetype ==# 'vimfiler' ? 'VimFiler' : + \ &filetype ==# 'vimshell' ? 'VimShell' : + \ lightline#mode() +endfunction +``` +![lightline.vim - tutorial](https://raw.githubusercontent.com/wiki/itchyny/lightline.vim/image/tutorial/10.png) + +### Can I trim the file format and encoding information on narrow windows? +Yes, check `winwidth(0)` and return empty string with some threshold. +```vim +let g:lightline = { + \ 'component_function': { + \ 'fileformat': 'LightlineFileformat', + \ 'filetype': 'LightlineFiletype', + \ }, + \ } + +function! LightlineFileformat() + return winwidth(0) > 70 ? &fileformat : '' +endfunction + +function! LightlineFiletype() + return winwidth(0) > 70 ? (&filetype !=# '' ? &filetype : 'no ft') : '' +endfunction +``` +![lightline.vim - tutorial](https://raw.githubusercontent.com/wiki/itchyny/lightline.vim/image/tutorial/11.png) + +### Can I trim the bar between the filename and modified sign? +Yes, by joining the two components. +```vim +let g:lightline = { + \ 'active': { + \ 'left': [ [ 'mode', 'paste' ], + \ [ 'readonly', 'filename' ] ], + \ }, + \ 'component_function': { + \ 'filename': 'LightlineFilename', + \ }, + \ } + +function! LightlineFilename() + let filename = expand('%:t') !=# '' ? expand('%:t') : '[No Name]' + let modified = &modified ? ' +' : '' + return filename . modified +endfunction +``` +![lightline.vim - tutorial](https://raw.githubusercontent.com/wiki/itchyny/lightline.vim/image/tutorial/12.png) + +You can control the visibility and contents by writing simple functions. +Now you notice how much function component is important for the configurability of lightline.vim. + +## Note for developers of other plugins +Appearance consistency matters. + +The statusline is an important space for Vim users. +Overwriting the statusline forcibly in your plugin is not a good idea. +It is not hospitality, but just an annoying feature. +If your plugin has such a feature, add an option to be modest. + +A good design is as follows. +Firstly, give the users a clue to judge which buffer is the one your plugin creates. +The filename is a manner and the filetype is another. +Then, export a function which is useful to be shown in the statusline. +Lastly, for advanced users, set important information in buffer variables so that the users can obtain the condition of the plugin easily. + +## Author +itchyny (https://github.com/itchyny) + +## License +This software is released under the MIT License, see LICENSE. diff --git a/start/lightline/autoload/lightline.vim b/start/lightline/autoload/lightline.vim new file mode 100644 index 0000000..2076a11 --- /dev/null +++ b/start/lightline/autoload/lightline.vim @@ -0,0 +1,502 @@ +" ============================================================================= +" Filename: autoload/lightline.vim +" Author: itchyny +" License: MIT License +" Last Change: 2018/11/24 12:00:00. +" ============================================================================= + +let s:save_cpo = &cpo +set cpo&vim + +let s:_ = 1 " 1: uninitialized, 2: disabled + +function! lightline#update() abort + if s:_ + if s:_ == 2 | return | endif + call lightline#init() + call lightline#colorscheme() + endif + if !s:lightline.enable.statusline + return + endif + let w = winnr() + let s = winnr('$') == 1 ? [lightline#statusline(0)] : [lightline#statusline(0), lightline#statusline(1)] + for n in range(1, winnr('$')) + call setwinvar(n, '&statusline', s[n!=w]) + call setwinvar(n, 'lightline', n!=w) + endfor +endfunction + +function! lightline#update_once() abort + if !exists('w:lightline') || w:lightline + call lightline#update() + endif +endfunction + +function! lightline#update_disable() abort + if !s:lightline.enable.statusline + return + endif + call setwinvar(0, '&statusline', '') +endfunction + +function! lightline#enable() abort + let s:_ = 1 + call lightline#update() + augroup lightline + autocmd! + autocmd WinEnter,BufWinEnter,FileType,SessionLoadPost * call lightline#update() + autocmd SessionLoadPost * call lightline#highlight() + autocmd ColorScheme * if !has('vim_starting') || expand('') !=# 'macvim' + \ | call lightline#update() | call lightline#highlight() | endif + autocmd CursorMoved,BufUnload * call lightline#update_once() + augroup END + augroup lightline-disable + autocmd! + augroup END + augroup! lightline-disable +endfunction + +function! lightline#disable() abort + let [&statusline, &tabline] = [get(s:, '_statusline', ''), get(s:, '_tabline', '')] + for t in range(1, tabpagenr('$')) + for n in range(1, tabpagewinnr(t, '$')) + call settabwinvar(t, n, '&statusline', '') + endfor + endfor + augroup lightline + autocmd! + augroup END + augroup! lightline + augroup lightline-disable + autocmd! + autocmd WinEnter * call lightline#update_disable() + augroup END + let s:_ = 2 +endfunction + +function! lightline#toggle() abort + if exists('#lightline') + call lightline#disable() + else + call lightline#enable() + endif +endfunction + +let s:_lightline = { + \ 'active': { + \ 'left': [['mode', 'paste'], ['readonly', 'filename', 'modified']], + \ 'right': [['lineinfo'], ['percent'], ['fileformat', 'fileencoding', 'filetype']] + \ }, + \ 'inactive': { + \ 'left': [['filename']], + \ 'right': [['lineinfo'], ['percent']] + \ }, + \ 'tabline': { + \ 'left': [['tabs']], + \ 'right': [['close']] + \ }, + \ 'tab': { + \ 'active': ['tabnum', 'filename', 'modified'], + \ 'inactive': ['tabnum', 'filename', 'modified'] + \ }, + \ 'component': { + \ 'mode': '%{lightline#mode()}', + \ 'absolutepath': '%F', 'relativepath': '%f', 'filename': '%t', 'modified': '%M', 'bufnum': '%n', + \ 'paste': '%{&paste?"PASTE":""}', 'readonly': '%R', 'charvalue': '%b', 'charvaluehex': '%B', + \ 'spell': '%{&spell?&spelllang:""}', 'fileencoding': '%{&fenc!=#""?&fenc:&enc}', 'fileformat': '%{&ff}', + \ 'filetype': '%{&ft!=#""?&ft:"no ft"}', 'percent': '%3p%%', 'percentwin': '%P', + \ 'lineinfo': '%3l:%-2v', 'line': '%l', 'column': '%c', 'close': '%999X X ', 'winnr': '%{winnr()}' + \ }, + \ 'component_visible_condition': { + \ 'modified': '&modified||!&modifiable', 'readonly': '&readonly', 'paste': '&paste', 'spell': '&spell' + \ }, + \ 'component_function': {}, + \ 'component_function_visible_condition': {}, + \ 'component_expand': { + \ 'tabs': 'lightline#tabs' + \ }, + \ 'component_type': { + \ 'tabs': 'tabsel', 'close': 'raw' + \ }, + \ 'component_raw': {}, + \ 'tab_component': {}, + \ 'tab_component_function': { + \ 'filename': 'lightline#tab#filename', 'modified': 'lightline#tab#modified', + \ 'readonly': 'lightline#tab#readonly', 'tabnum': 'lightline#tab#tabnum' + \ }, + \ 'colorscheme': 'default', + \ 'mode_map': { + \ 'n': 'NORMAL', 'i': 'INSERT', 'R': 'REPLACE', 'v': 'VISUAL', 'V': 'V-LINE', "\": 'V-BLOCK', + \ 'c': 'COMMAND', 's': 'SELECT', 'S': 'S-LINE', "\": 'S-BLOCK', 't': 'TERMINAL' + \ }, + \ 'separator': { 'left': '', 'right': '' }, + \ 'subseparator': { 'left': '|', 'right': '|' }, + \ 'tabline_separator': {}, + \ 'tabline_subseparator': {}, + \ 'enable': { 'statusline': 1, 'tabline': 1 }, + \ '_mode_': { + \ 'n': 'normal', 'i': 'insert', 'R': 'replace', 'v': 'visual', 'V': 'visual', "\": 'visual', + \ 'c': 'command', 's': 'select', 'S': 'select', "\": 'select', 't': 'terminal' + \ }, + \ 'mode_fallback': { 'replace': 'insert', 'terminal': 'insert', 'select': 'visual' }, + \ 'palette': {}, + \ 'winwidth': winwidth(0), + \ } +function! lightline#init() abort + let s:lightline = deepcopy(get(g:, 'lightline', {})) + for [key, value] in items(s:_lightline) + if type(value) == 4 + if !has_key(s:lightline, key) + let s:lightline[key] = {} + endif + call extend(s:lightline[key], value, 'keep') + elseif !has_key(s:lightline, key) + let s:lightline[key] = value + endif + unlet value + endfor + call extend(s:lightline.tabline_separator, s:lightline.separator, 'keep') + call extend(s:lightline.tabline_subseparator, s:lightline.subseparator, 'keep') + let s:lightline.tabline_configured = has_key(get(get(g:, 'lightline', {}), 'component_expand', {}), 'tabs') + for components in deepcopy(s:lightline.tabline.left + s:lightline.tabline.right) + if len(filter(components, 'v:val !=# "tabs" && v:val !=# "close"')) > 0 + let s:lightline.tabline_configured = 1 + break + endif + endfor + if !exists('s:_statusline') + let s:_statusline = &statusline + endif + if !exists('s:_tabline') + let s:_tabline = &tabline + endif + if s:lightline.enable.tabline + set tabline=%!lightline#tabline() + else + let &tabline = get(s:, '_tabline', '') + endif + for f in values(s:lightline.component_function) + silent! call call(f, []) + endfor + for f in values(s:lightline.tab_component_function) + silent! call call(f, [1]) + endfor + let s:mode = '' +endfunction + +function! lightline#colorscheme() abort + try + let s:lightline.palette = g:lightline#colorscheme#{s:lightline.colorscheme}#palette + catch + call lightline#error('Could not load colorscheme ' . s:lightline.colorscheme . '.') + let s:lightline.colorscheme = 'default' + let s:lightline.palette = g:lightline#colorscheme#{s:lightline.colorscheme}#palette + finally + if has('win32') && !has('gui_running') && &t_Co < 256 + for u in values(s:lightline.palette) + for v in values(u) + for _ in v + let [_[2], _[3]] = [lightline#colortable#gui2cui(_[0], _[2]), lightline#colortable#gui2cui(_[1], _[3])] + endfor + endfor + endfor + endif + let s:highlight = {} + call lightline#highlight('normal') + call lightline#link() + let s:_ = 0 + endtry +endfunction + +function! lightline#palette() abort + return s:lightline.palette +endfunction + +function! lightline#mode() abort + return get(s:lightline.mode_map, mode(), '') +endfunction + +let s:mode = '' +function! lightline#link(...) abort + let mode = get(s:lightline._mode_, a:0 ? a:1 : mode(), 'normal') + if s:mode == mode + return '' + endif + let s:mode = mode + if !has_key(s:highlight, mode) + call lightline#highlight(mode) + endif + let types = map(s:uniq(sort(filter(values(s:lightline.component_type), 'v:val !=# "raw"'))), '[v:val, 1]') + for [p, l] in [['Left', len(s:lightline.active.left)], ['Right', len(s:lightline.active.right)]] + for [i, t] in map(range(0, l), '[v:val, 0]') + types + if i != l + exec printf('hi link Lightline%s_active_%s Lightline%s_%s_%s', p, i, p, mode, i) + endif + for [j, s] in map(range(0, l), '[v:val, 0]') + types + if i + 1 == j || t || s && i != l + exec printf('hi link Lightline%s_active_%s_%s Lightline%s_%s_%s_%s', p, i, j, p, mode, i, j) + endif + endfor + endfor + endfor + exec printf('hi link LightlineMiddle_active LightlineMiddle_%s', mode) + return '' +endfunction + +function! s:term(p) abort + return get(a:p, 4) !=# '' ? 'term='.a:p[4].' cterm='.a:p[4].' gui='.a:p[4] : '' +endfunction + +if exists('*uniq') + let s:uniq = function('uniq') +else + function! s:uniq(xs) abort + let i = len(a:xs) - 1 + while i > 0 + if a:xs[i] ==# a:xs[i - 1] + call remove(a:xs, i) + endif + let i -= 1 + endwhile + return a:xs + endfunction +endif + +function! lightline#highlight(...) abort + let [c, f] = [s:lightline.palette, s:lightline.mode_fallback] + let [s:lightline.llen, s:lightline.rlen] = [len(c.normal.left), len(c.normal.right)] + let [s:lightline.tab_llen, s:lightline.tab_rlen] = [len(has_key(get(c, 'tabline', {}), 'left') ? c.tabline.left : c.normal.left), len(has_key(get(c, 'tabline', {}), 'right') ? c.tabline.right : c.normal.right)] + let types = map(s:uniq(sort(filter(values(s:lightline.component_type), 'v:val !=# "raw"'))), '[v:val, 1]') + let modes = a:0 ? [a:1] : extend(['normal', 'insert', 'replace', 'visual', 'inactive', 'command', 'select', 'tabline'], exists(':terminal') == 2 ? ['terminal'] : []) + for mode in modes + let s:highlight[mode] = 1 + let d = has_key(c, mode) ? mode : has_key(f, mode) && has_key(c, f[mode]) ? f[mode] : 'normal' + let left = d ==# 'tabline' ? s:lightline.tabline.left : d ==# 'inactive' ? s:lightline.inactive.left : s:lightline.active.left + let right = d ==# 'tabline' ? s:lightline.tabline.right : d ==# 'inactive' ? s:lightline.inactive.right : s:lightline.active.right + let ls = has_key(get(c, d, {}), 'left') ? c[d].left : has_key(f, d) && has_key(get(c, f[d], {}), 'left') ? c[f[d]].left : c.normal.left + let ms = has_key(get(c, d, {}), 'middle') ? c[d].middle[0] : has_key(f, d) && has_key(get(c, f[d], {}), 'middle') ? c[f[d]].middle[0] : c.normal.middle[0] + let rs = has_key(get(c, d, {}), 'right') ? c[d].right : has_key(f, d) && has_key(get(c, f[d], {}), 'right') ? c[f[d]].right : c.normal.right + for [p, l, zs] in [['Left', len(left), ls], ['Right', len(right), rs]] + for [i, t] in map(range(0, l), '[v:val, 0]') + types + if i < l || i < 1 + let r = t ? (has_key(get(c, d, []), i) ? c[d][i][0] : has_key(get(c, 'tabline', {}), i) ? c.tabline[i][0] : get(c.normal, i, zs)[0]) : get(zs, i, ms) + exec printf('hi Lightline%s_%s_%s guifg=%s guibg=%s ctermfg=%s ctermbg=%s %s', p, mode, i, r[0], r[1], r[2], r[3], s:term(r)) + endif + for [j, s] in map(range(0, l), '[v:val, 0]') + types + if i + 1 == j || t || s && i != l + let q = s ? (has_key(get(c, d, []), j) ? c[d][j][0] : has_key(get(c, 'tabline', {}), j) ? c.tabline[j][0] : get(c.normal, j, zs)[0]) : (j != l ? get(zs, j, ms) :ms) + exec printf('hi Lightline%s_%s_%s_%s guifg=%s guibg=%s ctermfg=%s ctermbg=%s', p, mode, i, j, r[1], q[1], r[3], q[3]) + endif + endfor + endfor + endfor + exec printf('hi LightlineMiddle_%s guifg=%s guibg=%s ctermfg=%s ctermbg=%s %s', mode, ms[0], ms[1], ms[2], ms[3], s:term(ms)) + endfor +endfunction + +function! s:subseparator(components, subseparator, expanded) abort + let [a, c, f, v, u] = [a:components, s:lightline.component, s:lightline.component_function, s:lightline.component_visible_condition, s:lightline.component_function_visible_condition] + let xs = map(range(len(a:components)), 'a:expanded[v:val] ? "1" : + \ has_key(f, a[v:val]) ? (has_key(u, a[v:val]) ? "(".u[a[v:val]].")" : (exists("*".f[a[v:val]]) ? "" : "exists(\"*".f[a[v:val]]."\")&&").f[a[v:val]]."()!=#\"\"") : + \ has_key(v, a[v:val]) ? "(".v[a[v:val]].")" : has_key(c, a[v:val]) ? "1" : "0"') + return '%{' . (xs[0] ==# '1' || xs[0] ==# '(1)' ? '' : xs[0] . '&&(') . join(xs[1:], '||') . (xs[0] ==# '1' || xs[0] ==# '(1)' ? '' : ')') . '?"' . a:subseparator . '":""}' +endfunction + +function! lightline#concatenate(xs, right) abort + let separator = a:right ? s:lightline.subseparator.right : s:lightline.subseparator.left + return join(filter(copy(a:xs), 'v:val !=# ""'), ' ' . separator . ' ') +endfunction + +function! lightline#statusline(inactive) abort + if a:inactive && !has_key(s:highlight, 'inactive') + call lightline#highlight('inactive') + endif + return s:line(0, a:inactive) +endfunction + +function! s:normalize(result) abort + if type(a:result) == 3 + return map(a:result, 'type(v:val) == 1 ? v:val : string(v:val)') + elseif type(a:result) == 1 + return [a:result] + else + return [string(a:result)] + endif +endfunction + +function! s:evaluate_expand(component) abort + try + let result = eval(a:component . '()') + if type(result) == 1 && result ==# '' + return [] + endif + catch + return [] + endtry + return map(type(result) == 3 ? (result + [[], [], []])[:2] : [[], [result], []], 'filter(s:normalize(v:val), "v:val !=# ''''")') +endfunction + +function! s:convert(name, index) abort + if has_key(s:lightline.component_expand, a:name) + let type = get(s:lightline.component_type, a:name, a:index) + let is_raw = get(s:lightline.component_raw, a:name) || type ==# 'raw' + return filter(s:map(s:evaluate_expand(s:lightline.component_expand[a:name]), + \ '[v:val, 1 + ' . is_raw . ', v:key == 1 && ' . (type !=# 'raw') . ' ? "' . type . '" : "' . a:index . '", "' . a:index . '"]'), 'v:val[0] != []') + else + return [[[a:name], 0, a:index, a:index]] + endif +endfunction + +function! s:flatten_twice(xss) abort + let ys = [] + for xs in a:xss + for x in xs + let ys += x + endfor + endfor + return ys +endfunction + +if v:version > 702 || v:version == 702 && has('patch295') + let s:map = function('map') +else + function! s:map(xs, f) abort + let ys = [] + for i in range(len(a:xs)) + call extend(ys, map(a:xs[(i):(i)], substitute(a:f, 'v:key', i, 'g'))) + endfor + return ys + endfunction +endif + +function! s:expand(components) abort + let components = [] + let expanded = [] + let indices = [] + let prevtype = '' + let previndex = -1 + let xs = s:flatten_twice(s:map(deepcopy(a:components), 'map(v:val, "s:convert(v:val, ''" . v:key . "'')")')) + for [component, expand, type, index] in xs + if prevtype !=# type + for i in range(previndex + 1, max([previndex, index - 1])) + call add(indices, string(i)) + call add(components, []) + call add(expanded, []) + endfor + call add(indices, type) + call add(components, []) + call add(expanded, []) + endif + call extend(components[-1], component) + call extend(expanded[-1], repeat([expand], len(component))) + let prevtype = type + let previndex = index + endfor + for i in range(previndex + 1, max([previndex, len(a:components) - 1])) + call add(indices, string(i)) + call add(components, []) + call add(expanded, []) + endfor + call add(indices, string(len(a:components))) + return [components, expanded, indices] +endfunction + +function! s:line(tabline, inactive) abort + let _ = a:tabline ? '' : '%{lightline#link()}' + if s:lightline.palette == {} + call lightline#colorscheme() + endif + let [l, r] = a:tabline ? [s:lightline.tab_llen, s:lightline.tab_rlen] : [s:lightline.llen, s:lightline.rlen] + let [p, s] = a:tabline ? [s:lightline.tabline_separator, s:lightline.tabline_subseparator] : [s:lightline.separator, s:lightline.subseparator] + let [c, f, t, w] = [s:lightline.component, s:lightline.component_function, s:lightline.component_type, s:lightline.component_raw] + let mode = a:tabline ? 'tabline' : a:inactive ? 'inactive' : 'active' + let l_ = has_key(s:lightline, mode) ? s:lightline[mode].left : s:lightline.active.left + let [lt, lc, ll] = s:expand(copy(l_)) + let r_ = has_key(s:lightline, mode) ? s:lightline[mode].right : s:lightline.active.right + let [rt, rc, rl] = s:expand(copy(r_)) + for i in range(len(lt)) + let _ .= '%#LightlineLeft_' . mode . '_' . ll[i] . '#' + for j in range(len(lt[i])) + let x = lc[i][j] ? lt[i][j] : has_key(f, lt[i][j]) ? (exists('*' . f[lt[i][j]]) ? '%{' . f[lt[i][j]] . '()}' : '%{exists("*' . f[lt[i][j]] . '")?' . f[lt[i][j]] . '():""}') : get(c, lt[i][j], '') + let _ .= has_key(t, lt[i][j]) && t[lt[i][j]] ==# 'raw' || get(w, lt[i][j]) || lc[i][j] ==# 2 || x ==# '' ? x : '%( ' . x . ' %)' + if j < len(lt[i]) - 1 && s.left !=# '' + let _ .= s:subseparator(lt[i][(j):], s.left, lc[i][(j):]) + endif + endfor + let _ .= '%#LightlineLeft_' . mode . '_' . ll[i] . '_' . ll[i + 1] . '#' + let _ .= i < l + len(lt) - len(l_) && ll[i] < l || ll[i] != ll[i + 1] ? p.left : len(lt[i]) ? s.left : '' + endfor + let _ .= '%#LightlineMiddle_' . mode . '#%=' + for i in reverse(range(len(rt))) + let _ .= '%#LightlineRight_' . mode . '_' . rl[i] . '_' . rl[i + 1] . '#' + let _ .= i < r + len(rt) - len(r_) && rl[i] < r || rl[i] != rl[i + 1] ? p.right : len(rt[i]) ? s.right : '' + let _ .= '%#LightlineRight_' . mode . '_' . rl[i] . '#' + for j in range(len(rt[i])) + let x = rc[i][j] ? rt[i][j] : has_key(f, rt[i][j]) ? (exists('*' . f[rt[i][j]]) ? '%{' . f[rt[i][j]] . '()}' : '%{exists("*' . f[rt[i][j]] . '")?' . f[rt[i][j]] . '():""}') : get(c, rt[i][j], '') + let _ .= has_key(t, rt[i][j]) && t[rt[i][j]] ==# 'raw' || get(w, rt[i][j]) || rc[i][j] ==# 2 || x ==# '' ? x : '%( ' . x . ' %)' + if j < len(rt[i]) - 1 && s.right !=# '' + let _ .= s:subseparator(rt[i][(j):], s.right, rc[i][(j):]) + endif + endfor + endfor + return _ +endfunction + +let s:tabnr = -1 +let s:tabcnt = -1 +let s:tabline = '' +function! lightline#tabline() abort + if !has_key(s:highlight, 'tabline') + call lightline#highlight('tabline') + endif + if s:lightline.tabline_configured || s:tabnr != tabpagenr() || s:tabcnt != tabpagenr('$') + let s:tabnr = tabpagenr() + let s:tabcnt = tabpagenr('$') + let s:tabline = s:line(1, 0) + endif + return s:tabline +endfunction + +function! lightline#tabs() abort + let [x, y, z] = [[], [], []] + let nr = tabpagenr() + let cnt = tabpagenr('$') + for i in range(1, cnt) + call add(i < nr ? x : i == nr ? y : z, (i > nr + 3 ? '%<' : '') . '%'. i . 'T%{lightline#onetab(' . i . ',' . (i == nr) . ')}' . (i == cnt ? '%T' : '')) + endfor + let abbr = '...' + let n = min([max([s:lightline.winwidth / 40, 2]), 8]) + if len(x) > n && len(z) > n + let x = extend(add(x[:n/2-1], abbr), x[-(n+1)/2:]) + let z = extend(add(z[:(n+1)/2-1], abbr), z[-n/2:]) + elseif len(x) + len(z) > 2 * n + if len(x) > n + let x = extend(add(x[:(2*n-len(z))/2-1], abbr), x[-(2*n-len(z)+1)/2:]) + elseif len(z) > n + let z = extend(add(z[:(2*n-len(x)+1)/2-1], abbr), z[-(2*n-len(x))/2:]) + endif + endif + return [x, y, z] +endfunction + +function! lightline#onetab(n, active) abort + let _ = [] + for name in a:active ? s:lightline.tab.active : s:lightline.tab.inactive + if has_key(s:lightline.tab_component_function, name) + call add(_, call(s:lightline.tab_component_function[name], [a:n])) + else + call add(_, get(s:lightline.tab_component, name, '')) + endif + endfor + return join(filter(_, 'v:val !=# ""'), ' ') +endfunction + +function! lightline#error(msg) abort + echohl ErrorMsg + echomsg 'lightline.vim: '.a:msg + echohl None +endfunction + +let &cpo = s:save_cpo +unlet s:save_cpo diff --git a/start/lightline/autoload/lightline/colorscheme.vim b/start/lightline/autoload/lightline/colorscheme.vim new file mode 100644 index 0000000..79013ff --- /dev/null +++ b/start/lightline/autoload/lightline/colorscheme.vim @@ -0,0 +1,257 @@ +" ============================================================================= +" Filename: autoload/lightline/colorscheme.vim +" Author: itchyny +" License: MIT License +" Last Change: 2018/09/01 22:48:24. +" ============================================================================= + +let s:save_cpo = &cpo +set cpo&vim + +let s:cuicolor = { + \ 'black' : 16, + \ 'white' : 231, + \ + \ 'darkestgreen' : 22, + \ 'darkgreen' : 28, + \ 'mediumgreen' : 70, + \ 'brightgreen' : 148, + \ + \ 'darkestcyan' : 23, + \ 'mediumcyan' : 117, + \ + \ 'darkestblue' : 24, + \ 'darkblue' : 31, + \ + \ 'darkestred' : 52, + \ 'darkred' : 88, + \ 'mediumred' : 124, + \ 'brightred' : 160, + \ 'brightestred' : 196, + \ + \ 'darkestpurple' : 55, + \ 'mediumpurple' : 98, + \ 'brightpurple' : 189, + \ + \ 'brightorange' : 208, + \ 'brightestorange': 214, + \ + \ 'gray0' : 233, + \ 'gray1' : 235, + \ 'gray2' : 236, + \ 'gray3' : 239, + \ 'gray4' : 240, + \ 'gray5' : 241, + \ 'gray6' : 244, + \ 'gray7' : 245, + \ 'gray8' : 247, + \ 'gray9' : 250, + \ 'gray10' : 252, + \ + \ 'yellow' : 136, + \ 'orange' : 166, + \ 'red' : 160, + \ 'magenta' : 125, + \ 'violet' : 61, + \ 'blue' : 33, + \ 'cyan' : 37, + \ 'green' : 64, + \ } + +let s:guicolor = { + \ 'black' : '#000000', + \ 'white' : '#ffffff', + \ + \ 'darkestgreen' : '#005f00', + \ 'darkgreen' : '#008700', + \ 'mediumgreen' : '#5faf00', + \ 'brightgreen' : '#afdf00', + \ + \ 'darkestcyan' : '#005f5f', + \ 'mediumcyan' : '#87dfff', + \ + \ 'darkestblue' : '#005f87', + \ 'darkblue' : '#0087af', + \ + \ 'darkestred' : '#5f0000', + \ 'darkred' : '#870000', + \ 'mediumred' : '#af0000', + \ 'brightred' : '#df0000', + \ 'brightestred' : '#ff0000', + \ + \ 'darkestpurple' : '#5f00af', + \ 'mediumpurple' : '#875fdf', + \ 'brightpurple' : '#dfdfff', + \ + \ 'brightorange' : '#ff8700', + \ 'brightestorange': '#ffaf00', + \ + \ 'gray0' : '#121212', + \ 'gray1' : '#262626', + \ 'gray2' : '#303030', + \ 'gray3' : '#4e4e4e', + \ 'gray4' : '#585858', + \ 'gray5' : '#606060', + \ 'gray6' : '#808080', + \ 'gray7' : '#8a8a8a', + \ 'gray8' : '#9e9e9e', + \ 'gray9' : '#bcbcbc', + \ 'gray10' : '#d0d0d0', + \ + \ 'yellow' : '#b58900', + \ 'orange' : '#cb4b16', + \ 'red' : '#dc322f', + \ 'magenta' : '#d33682', + \ 'violet' : '#6c71c4', + \ 'blue' : '#268bd2', + \ 'cyan' : '#2aa198', + \ 'green' : '#859900', + \ } + +function! s:convert(rgb) abort + let rgb = map(matchlist(a:rgb, '#\(..\)\(..\)\(..\)')[1:3], '0 + ("0x".v:val)') + if len(rgb) == 0 + return 0 + endif + if rgb[0] == 0xc0 && rgb[1] == 0xc0 && rgb[2] == 0xc0 + return 7 + elseif rgb[0] == 0x80 && rgb[1] == 0x80 && rgb[2] == 0x80 + return 8 + elseif (rgb[0] == 0x80 || rgb[0] == 0x00) && (rgb[1] == 0x80 || rgb[1] == 0x00) && (rgb[2] == 0x80 || rgb[2] == 0x00) + return (rgb[0] / 0x80) + (rgb[1] / 0x80) * 2 + (rgb[1] / 0x80) * 4 + elseif abs(rgb[0]-rgb[1]) < 3 && abs(rgb[1]-rgb[2]) < 3 && abs(rgb[2]-rgb[0]) < 3 + return s:black((rgb[0] + rgb[1] + rgb[2]) / 3) + else + return 16 + ((s:nr(rgb[0]) * 6) + s:nr(rgb[1])) * 6 + s:nr(rgb[2]) + endif +endfunction + +function! s:black(x) abort + if a:x < 0x04 + return 16 + elseif a:x > 0xf4 + return 231 + elseif index([0x00, 0x5f, 0x87, 0xaf, 0xdf, 0xff], a:x) >= 0 + let l = a:x / 0x30 + return ((l * 6) + l) * 6 + l + 16 + else + return 232 + (a:x < 8 ? 0 : a:x < 0x60 ? (a:x-8)/10 : a:x < 0x76 ? (a:x-0x60)/6+9 : (a:x-8)/10) + endif +endfunction + +function! s:nr(x) abort + return a:x < 0x2f ? 0 : a:x < 0x73 ? 1 : a:x < 0x9b ? 2 : a:x < 0xc7 ? 3 : a:x < 0xef ? 4 : 5 +endfunction + +function! s:rgb(r, g, b) abort + return printf('#%02x%02x%02x', a:r, a:g, a:b) +endfunction + +function! s:upconvert(nr) abort + let x = a:nr * 1 + if x < 7 + let [b, rg] = [x / 4, x % 4] + let [g, r] = [rg / 2, rg % 2] + return s:rgb(r * 0x80, g * 0x80, b * 0x80) + elseif x == 7 + return s:rgb(0xc0, 0xc0, 0xc0) + elseif x == 8 + return s:rgb(0x80, 0x80, 0x80) + elseif x < 16 + let y = x - 8 + let [b, rg] = [y / 4, y % 4] + let [g, r] = [rg / 2, rg % 2] + return s:rgb(r * 0xff, g * 0xff, b * 0xff) + elseif x < 232 + let y = x - 16 + let [rg, b] = [y / 6, y % 6] + let [r, g] = [rg / 6, rg % 6] + let l = [0x00, 0x5f, 0x87, 0xaf, 0xdf, 0xff] + return s:rgb(l[r], l[g], l[b]) + elseif x < 241 + let k = (x - 232) * 10 + 8 + return s:rgb(k, k, k) + elseif x < 243 + let k = (x - 241) * 6 + 0x60 + return s:rgb(k, k, k) + else + let k = (x - 232) * 10 + 8 + return s:rgb(k, k, k) + endif +endfunction + +function! lightline#colorscheme#fill(p) abort + for k in values(a:p) + for l in values(k) + for m in l + if len(m) < 4 + if type(m[0]) == 1 && type(m[1]) == 1 + if m[0] =~# '^\d\+$' && m[1] =~# '^\d\+$' + call insert(m, s:upconvert(m[1]), 0) + call insert(m, s:upconvert(m[1]), 0) + else + call insert(m, get(s:cuicolor, m[0], s:convert(m[0])), 2) + call insert(m, get(s:cuicolor, m[1], s:convert(m[1])), 3) + let m[0] = get(s:guicolor, m[0], m[0]) + let m[1] = get(s:guicolor, m[1], m[1]) + endif + elseif type(m[0]) == 0 && type(m[1]) == 0 + call insert(m, s:upconvert(m[1]), 0) + call insert(m, s:upconvert(m[1]), 0) + endif + endif + endfor + endfor + endfor + return a:p +endfunction + +function! lightline#colorscheme#flatten(p) abort + for k in values(a:p) + for l in values(k) + for m in range(len(l)) + let attr = '' + if len(l[m]) == 3 && type(l[m][2]) == 1 + let attr = l[m][2] + endif + let l[m] = [l[m][0][0], l[m][1][0], l[m][0][1], l[m][1][1]] + if !empty(attr) + call add(l[m], attr) + endif + endfor + endfor + endfor + return a:p +endfunction + +if has('gui_running') || (has('termguicolors') && &termguicolors) + function! lightline#colorscheme#background() abort + return &background + endfunction +else + " &background is set inappropriately when the colorscheme sets ctermbg of the Normal group + function! lightline#colorscheme#background() abort + let bg_color = synIDattr(synIDtrans(hlID('Normal')), 'bg', 'cterm') + if bg_color !=# '' + if bg_color < 16 + return &background + elseif 232 <= bg_color && bg_color < 244 + return 'dark' + elseif 244 <= bg_color + return 'light' + endif + endif + let fg_color = synIDattr(synIDtrans(hlID('Normal')), 'fg', 'cterm') + if fg_color !=# '' + if fg_color < 8 || 232 <= fg_color && fg_color < 244 + return 'light' + elseif 8 <= fg_color && fg_color < 16 || 244 <= fg_color + return 'dark' + endif + endif + return &background + endfunction +endif + +let &cpo = s:save_cpo +unlet s:save_cpo diff --git a/start/lightline/autoload/lightline/colorscheme/16color.vim b/start/lightline/autoload/lightline/colorscheme/16color.vim new file mode 100644 index 0000000..41e6497 --- /dev/null +++ b/start/lightline/autoload/lightline/colorscheme/16color.vim @@ -0,0 +1,49 @@ +" ============================================================================= +" Filename: autoload/lightline/colorscheme/16color.vim +" Author: itchyny +" License: MIT License +" Last Change: 2017/11/25 11:14:04. +" ============================================================================= + +let s:base03 = [ '#808080', 8 ] +let s:base02 = [ '#000000', 0 ] +let s:base01 = [ '#00ff00', 10 ] +let s:base00 = [ '#ffff00', 11 ] +let s:base0 = [ '#0000ff', 12 ] +let s:base1 = [ '#00ffff', 14 ] +let s:base2 = [ '#c0c0c0', 7 ] +let s:base3 = [ '#ffffff', 15 ] +let s:yellow = [ '#808000', 3 ] +let s:orange = [ '#ff0000', 9 ] +let s:red = [ '#800000', 1 ] +let s:magenta = [ '#800080', 5 ] +let s:violet = [ '#ff00ff', 13 ] +let s:blue = [ '#000080', 4 ] +let s:cyan = [ '#008080', 6 ] +let s:green = [ '#008000', 2 ] + +if lightline#colorscheme#background() ==# 'light' + let [s:base03, s:base3] = [s:base3, s:base03] + let [s:base02, s:base2] = [s:base2, s:base02] + let [s:base01, s:base1] = [s:base1, s:base01] + let [s:base00, s:base0] = [s:base0, s:base00] +endif + +let s:p = {'normal': {}, 'inactive': {}, 'insert': {}, 'replace': {}, 'visual': {}, 'tabline': {}} +let s:p.normal.left = [ [ s:base3, s:blue ], [ s:base3, s:base01 ] ] +let s:p.normal.right = [ [ s:base02, s:base0 ], [ s:base1, s:base01 ] ] +let s:p.inactive.right = [ [ s:base02, s:base01 ], [ s:base00, s:base02 ] ] +let s:p.inactive.left = [ [ s:base0, s:base02 ], [ s:base00, s:base02 ] ] +let s:p.insert.left = [ [ s:base3, s:green ], [ s:base3, s:base01 ] ] +let s:p.replace.left = [ [ s:base3, s:red ], [ s:base3, s:base01 ] ] +let s:p.visual.left = [ [ s:base3, s:magenta ], [ s:base3, s:base01 ] ] +let s:p.normal.middle = [ [ s:base1, s:base02 ] ] +let s:p.inactive.middle = [ [ s:base0, s:base02 ] ] +let s:p.tabline.left = [ [ s:base2, s:base01 ] ] +let s:p.tabline.tabsel = [ [ s:base2, s:base02 ] ] +let s:p.tabline.middle = [ [ s:base01, s:base2 ] ] +let s:p.tabline.right = copy(s:p.normal.right) +let s:p.normal.error = [ [ s:base2, s:red ] ] +let s:p.normal.warning = [ [ s:base02, s:yellow ] ] + +let g:lightline#colorscheme#16color#palette = lightline#colorscheme#flatten(s:p) diff --git a/start/lightline/autoload/lightline/colorscheme/OldHope.vim b/start/lightline/autoload/lightline/colorscheme/OldHope.vim new file mode 100644 index 0000000..ff78290 --- /dev/null +++ b/start/lightline/autoload/lightline/colorscheme/OldHope.vim @@ -0,0 +1,44 @@ +" ============================================================================= +" Filename: autoload/lightline/colorscheme/OldHope.vim +" Author: tomb0y +" License: MIT License +" Last Change: 2017/10/15 06:20:54. +" ============================================================================= + +let s:yellow = [ '#e5cd52' , 221 ] +let s:blue = [ '#4fb4d8' , 39 ] +let s:red = [ '#f92672' , 161 ] +let s:green = [ '#78bd65' , 41 ] +let s:orange = [ '#ef7c2a' , 202 ] +let s:white = [ '#ffffff' , 15 ] +let s:lightGray = [ '#848794' , 245 ] +let s:gray = [ '#686b78' , 242 ] +let s:darkGray = [ '#45474f' , 238 ] +let s:veryDarkGray = [ '#1c1d21' , 234 ] + +let s:p = {'normal': {}, 'inactive': {}, 'insert': {}, 'replace': {}, 'visual': {}, 'tabline': {}} + +let s:p.normal.left = [ [ s:white, s:blue ], [ s:white, s:gray ] ] +let s:p.insert.left = [ [ s:white, s:green ], [ s:white, s:gray ] ] +let s:p.visual.left = [ [ s:white, s:orange ], [ s:white, s:gray ] ] +let s:p.replace.left = [ [ s:white, s:red ], [ s:white, s:gray ] ] + +let s:p.inactive.right = [ [ s:darkGray, s:gray ], [ s:darkGray, s:gray ] ] +let s:p.inactive.left = [ [ s:lightGray, s:darkGray ], [ s:white, s:darkGray ] ] +let s:p.inactive.middle = [ [ s:white, s:darkGray ] ] + +let s:p.normal.middle = [ [ s:white, s:darkGray ] ] +let s:p.normal.error = [ [ s:red, s:darkGray ] ] +let s:p.normal.warning = [ [ s:orange, s:darkGray ] ] + +let s:p.tabline.left = [ [ s:lightGray, s:darkGray ] ] +let s:p.tabline.tabsel = [ [ s:darkGray, s:yellow ] ] +let s:p.tabline.middle = [ [ s:yellow, s:veryDarkGray ] ] + +let s:p.normal.right = copy(s:p.normal.left) +let s:p.insert.right = copy(s:p.insert.left) +let s:p.visual.right = copy(s:p.visual.left) +let s:p.replace.right = copy(s:p.replace.left) +let s:p.tabline.right = copy(s:p.tabline.left) + +let g:lightline#colorscheme#OldHope#palette = lightline#colorscheme#flatten(s:p) diff --git a/start/lightline/autoload/lightline/colorscheme/PaperColor.vim b/start/lightline/autoload/lightline/colorscheme/PaperColor.vim new file mode 100644 index 0000000..90aa426 --- /dev/null +++ b/start/lightline/autoload/lightline/colorscheme/PaperColor.vim @@ -0,0 +1,12 @@ +" ============================================================================= +" Filename: autoload/lightline/colorscheme/PaperColor.vim +" Author: TKNGUE +" License: MIT License +" Last Change: 2017/11/25 11:13:35. +" ============================================================================= + +if lightline#colorscheme#background() ==# 'light' + let g:lightline#colorscheme#PaperColor#palette = g:lightline#colorscheme#PaperColor_light#palette +else + let g:lightline#colorscheme#PaperColor#palette = g:lightline#colorscheme#PaperColor_dark#palette +endif diff --git a/start/lightline/autoload/lightline/colorscheme/PaperColor_dark.vim b/start/lightline/autoload/lightline/colorscheme/PaperColor_dark.vim new file mode 100644 index 0000000..0a70b34 --- /dev/null +++ b/start/lightline/autoload/lightline/colorscheme/PaperColor_dark.vim @@ -0,0 +1,60 @@ +" ============================================================================= +" Filename: autoload/lightline/colorscheme/PaperColor_dark.vim +" Author: TKNGUE +" License: MIT License +" Last Change: 2015-07-27 06:01 +" ============================================================================= + +let s:red = '#df0000' +let s:green = '#008700' +let s:blue = '#00afaf' + +let s:pink = '#afdf00' +let s:olive = '#dfaf5f' +let s:navy = '#df875f' + +let s:orange = '#d75f00' +let s:purple = '#8959a8' +let s:aqua = '#3e999f' + +" Basics: +let s:foreground = '#d0d0d0' +let s:background = '#444444' +let s:window = '#efefef' +let s:status = '#c6c6c6' +let s:error = '#5f0000' + +" Tabline: +let s:tabline_bg = '#3a3a3a' +let s:tabline_active_fg = '#1c1c1c' +let s:tabline_active_bg = '#00afaf' +let s:tabline_inactive_fg = '#c6c6c6' +let s:tabline_inactive_bg = '#585858' + +" Statusline: +let s:statusline_active_fg = '#1c1c1c' +let s:statusline_active_bg = '#5f8787' +let s:statusline_inactive_fg = '#c6c6c6' +let s:statusline_inactive_bg = '#444444' + +" Visual: +let s:visual_fg = '#000000' +let s:visual_bg = '#8787af' + +let s:p = {'normal': {}, 'inactive': {}, 'insert': {}, 'replace': {}, 'visual': {}, 'tabline': {}} +let s:p.normal.left = [ [ s:foreground, s:background ], [ s:statusline_active_fg, s:status ], [ s:statusline_active_fg, s:statusline_active_bg ] ] +let s:p.normal.right = [ [ s:foreground, s:background ], [ s:statusline_active_fg, s:status ], [ s:statusline_active_fg, s:statusline_active_bg ] ] +let s:p.normal.middle = [ [ s:statusline_active_fg, s:statusline_active_bg ]] +let s:p.inactive.right = [ [ s:foreground, s:background ], [ s:foreground, s:background ] ] +let s:p.inactive.left = [ [ s:foreground, s:background ], [ s:foreground, s:background ] ] +let s:p.inactive.middle = [ [ s:foreground, s:background ], ] +let s:p.insert.left = [ [ s:background, s:blue], [ s:statusline_active_fg, s:status ], [ s:statusline_active_fg, s:statusline_active_bg ] ] +let s:p.replace.left = [ [ s:background, s:pink ], [s:statusline_active_fg, s:status ], [ s:statusline_active_fg, s:statusline_active_bg ] ] +let s:p.visual.left = [ [ s:visual_fg, s:visual_bg ], [s:statusline_active_fg, s:status ], [ s:statusline_active_fg, s:statusline_active_bg ] ] +let s:p.tabline.left = [ [s:tabline_inactive_fg, s:tabline_inactive_bg ]] +let s:p.tabline.tabsel = [ [s:tabline_active_fg, s:tabline_active_bg ] ] +let s:p.tabline.middle = [ [s:tabline_bg, s:tabline_bg]] +let s:p.tabline.right = copy(s:p.normal.right) +let s:p.normal.error = [ [ s:background, s:error ] ] + +let g:lightline#colorscheme#PaperColor_dark#palette = lightline#colorscheme#fill(s:p) diff --git a/start/lightline/autoload/lightline/colorscheme/PaperColor_light.vim b/start/lightline/autoload/lightline/colorscheme/PaperColor_light.vim new file mode 100644 index 0000000..aef0b86 --- /dev/null +++ b/start/lightline/autoload/lightline/colorscheme/PaperColor_light.vim @@ -0,0 +1,55 @@ +" ============================================================================= +" Filename: autoload/lightline/colorscheme/PaperColor_light.vim +" Author: TKNGUE +" License: MIT License +" Last Change: 2015/07/28 07:46:40. +" ============================================================================= + +let s:red = '#df0000' +let s:green = '#008700' +let s:blue = '#4271ae' +let s:pink = '#d7005f' +let s:olive = '#718c00' +let s:navy = '#005f87' +let s:orange = '#d75f00' +let s:purple = '#8959a8' +let s:aqua = '#3e999f' + +" Basics: +let s:foreground = '#4d4d4c' +let s:background = '#F5F5F5' +let s:window = '#efefef' +let s:status = s:aqua +let s:error = '#ffafdf' + +" Tabline: +let s:tabline_bg = s:navy +let s:tabline_active_fg = s:foreground +let s:tabline_active_bg = s:window +let s:tabline_inactive_fg = s:background +let s:tabline_inactive_bg = s:aqua + +" Statusline: +let s:statusline_active_fg = s:window +let s:statusline_active_bg = s:navy +let s:statusline_inactive_fg = s:foreground +let s:statusline_inactive_bg = '#dadada' + +let s:p = {'normal': {}, 'inactive': {}, 'insert': {}, 'replace': {}, 'visual': {}, 'tabline': {}} +let s:p.normal.left = [ [ s:foreground, s:background ], [ s:statusline_active_fg, s:status ], [ s:statusline_active_fg, s:statusline_active_bg ] ] +let s:p.normal.right = [ [ s:foreground, s:background ], [ s:statusline_active_fg, s:status ], [ s:statusline_active_fg, s:statusline_active_bg ] ] +let s:p.normal.middle = [ [ s:statusline_active_fg, s:statusline_active_bg ]] +let s:p.inactive.right = [ [ s:foreground, s:background ], [ s:foreground, s:background ] ] +let s:p.inactive.left = [ [ s:foreground, s:background ], [ s:foreground, s:background ] ] +let s:p.inactive.middle = [ [ s:foreground, s:background ], ] +let s:p.insert.left = [ [ s:blue, s:background ], [ s:statusline_active_fg, s:status ], [ s:statusline_active_fg, s:statusline_active_bg ] ] +let s:p.replace.left = [ [ s:background, s:pink ], [s:statusline_active_fg, s:status ], [ s:statusline_active_fg, s:statusline_active_bg ] ] +let s:p.visual.left = [ [ s:background, s:orange ], [s:statusline_active_fg, s:status ], [ s:statusline_active_fg, s:statusline_active_bg ] ] +let s:p.tabline.left = [ [s:tabline_inactive_fg, s:tabline_inactive_bg ]] +let s:p.tabline.tabsel = [ [s:tabline_active_fg, s:tabline_active_bg ] ] +let s:p.tabline.middle = [ [s:tabline_bg, s:tabline_bg]] +let s:p.tabline.right = copy(s:p.normal.right) +let s:p.normal.error = [ [ s:background, s:error ] ] +let s:p.normal.warning = [ [ s:background, s:olive ] ] + +let g:lightline#colorscheme#PaperColor_light#palette = lightline#colorscheme#fill(s:p) diff --git a/start/lightline/autoload/lightline/colorscheme/Tomorrow.vim b/start/lightline/autoload/lightline/colorscheme/Tomorrow.vim new file mode 100644 index 0000000..8255966 --- /dev/null +++ b/start/lightline/autoload/lightline/colorscheme/Tomorrow.vim @@ -0,0 +1,41 @@ +" ============================================================================= +" Filename: autoload/lightline/colorscheme/Tomorrow.vim +" Author: itchyny +" License: MIT License +" Last Change: 2013/09/07 12:22:37. +" ============================================================================= +let s:base03 = '#fafafa' +let s:base023 = '#dfdfdf' +let s:base02 = '#c8c8c8' +let s:base01 = '#b4b4b4' +let s:base00 = '#808080' +let s:base0 = '#666666' +let s:base1 = '#555555' +let s:base2 = '#4f4f4f' +let s:base3 = '#4d4d4c' +let s:red = '#c82829' +let s:orange = '#f5871f' +let s:yellow = '#eab700' +let s:green = '#718c00' +let s:cyan = '#3e999f' +let s:blue = '#4271ae' +let s:magenta = '#8959a8' + +let s:p = {'normal': {}, 'inactive': {}, 'insert': {}, 'replace': {}, 'visual': {}, 'tabline': {}} +let s:p.normal.left = [ [ s:base02, s:blue ], [ s:base3, s:base01 ] ] +let s:p.normal.right = [ [ s:base02, s:base0 ], [ s:base1, s:base01 ] ] +let s:p.inactive.right = [ [ s:base02, s:base00 ], [ s:base00, s:base02 ] ] +let s:p.inactive.left = [ [ s:base0, s:base02 ], [ s:base00, s:base03 ] ] +let s:p.insert.left = [ [ s:base02, s:green ], [ s:base3, s:base01 ] ] +let s:p.replace.left = [ [ s:base02, s:orange ], [ s:base3, s:base01 ] ] +let s:p.visual.left = [ [ s:base02, s:magenta ], [ s:base3, s:base01 ] ] +let s:p.normal.middle = [ [ s:base1, s:base02 ] ] +let s:p.inactive.middle = [ [ s:base0, s:base02 ] ] +let s:p.tabline.left = [ [ s:base2, s:base01 ] ] +let s:p.tabline.tabsel = [ [ s:base2, s:base023 ] ] +let s:p.tabline.middle = [ [ s:base01, s:base00 ] ] +let s:p.tabline.right = copy(s:p.normal.right) +let s:p.normal.error = [ [ s:red, s:base01 ] ] +let s:p.normal.warning = [ [ s:yellow, s:base0 ] ] + +let g:lightline#colorscheme#Tomorrow#palette = lightline#colorscheme#fill(s:p) diff --git a/start/lightline/autoload/lightline/colorscheme/Tomorrow_Night.vim b/start/lightline/autoload/lightline/colorscheme/Tomorrow_Night.vim new file mode 100644 index 0000000..8903180 --- /dev/null +++ b/start/lightline/autoload/lightline/colorscheme/Tomorrow_Night.vim @@ -0,0 +1,41 @@ +" ============================================================================= +" Filename: autoload/lightline/colorscheme/Tomorrow_Night.vim +" Author: itchyny +" License: MIT License +" Last Change: 2013/09/07 12:23:38. +" ============================================================================= +let s:base3 = '#c5c8c6' +let s:base2 = '#bababa' +let s:base1 = '#a0a0a0' +let s:base0 = '#909090' +let s:base00 = '#666666' +let s:base01 = '#555555' +let s:base02 = '#434343' +let s:base023 = '#303030' +let s:base03 = '#1d1f21' +let s:red = '#cc6666' +let s:orange = '#de935f' +let s:yellow = '#f0c674' +let s:green = '#b5bd68' +let s:cyan = '#8abeb7' +let s:blue = '#81a2be' +let s:magenta = '#b294bb' + +let s:p = {'normal': {}, 'inactive': {}, 'insert': {}, 'replace': {}, 'visual': {}, 'tabline': {}} +let s:p.normal.left = [ [ s:base02, s:blue ], [ s:base3, s:base01 ] ] +let s:p.normal.right = [ [ s:base02, s:base0 ], [ s:base1, s:base01 ] ] +let s:p.inactive.right = [ [ s:base02, s:base00 ], [ s:base00, s:base02 ] ] +let s:p.inactive.left = [ [ s:base0, s:base02 ], [ s:base00, s:base03 ] ] +let s:p.insert.left = [ [ s:base02, s:green ], [ s:base3, s:base01 ] ] +let s:p.replace.left = [ [ s:base02, s:orange ], [ s:base3, s:base01 ] ] +let s:p.visual.left = [ [ s:base02, s:magenta ], [ s:base3, s:base01 ] ] +let s:p.normal.middle = [ [ s:base1, s:base02 ] ] +let s:p.inactive.middle = [ [ s:base0, s:base02 ] ] +let s:p.tabline.left = [ [ s:base2, s:base01 ] ] +let s:p.tabline.tabsel = [ [ s:base2, s:base023 ] ] +let s:p.tabline.middle = [ [ s:base01, s:base0 ] ] +let s:p.tabline.right = copy(s:p.normal.right) +let s:p.normal.error = [ [ s:red, s:base023 ] ] +let s:p.normal.warning = [ [ s:yellow, s:base02 ] ] + +let g:lightline#colorscheme#Tomorrow_Night#palette = lightline#colorscheme#fill(s:p) diff --git a/start/lightline/autoload/lightline/colorscheme/Tomorrow_Night_Blue.vim b/start/lightline/autoload/lightline/colorscheme/Tomorrow_Night_Blue.vim new file mode 100644 index 0000000..31c27f3 --- /dev/null +++ b/start/lightline/autoload/lightline/colorscheme/Tomorrow_Night_Blue.vim @@ -0,0 +1,43 @@ +" ============================================================================= +" Filename: autoload/lightline/colorscheme/Tomorrow_Night_Blue.vim +" Author: itchyny +" License: MIT License +" Last Change: 2013/09/07 14:13:21. +" ============================================================================= +let s:base3 = '#ffffff' +let s:base23 = '#ffffff' +let s:base2 = '#ffffff' +let s:base1 = '#ffffff' +let s:base0 = '#ffffff' +let s:base00 = '#6060df' +let s:base01 = '#6060af' +let s:base02 = '#606087' +let s:base023 = '#202087' +let s:base03 = '#002451' +let s:red = '#ff9da4' +let s:orange = '#ffc58f' +let s:yellow = '#ffeead' +let s:green = '#d1f1a9' +let s:cyan = '#99ffff' +let s:blue = '#bbdaff' +let s:magenta = '#ebbbff' + + +let s:p = {'normal': {}, 'inactive': {}, 'insert': {}, 'replace': {}, 'visual': {}, 'tabline': {}} +let s:p.normal.left = [ [ s:base023, s:blue ], [ s:base3, s:base01 ] ] +let s:p.normal.right = [ [ s:base02, s:base1 ], [ s:base2, s:base01 ] ] +let s:p.inactive.right = [ [ s:base02, s:base0 ], [ s:base1, s:base01 ] ] +let s:p.inactive.left = [ [ s:base02, s:base0 ], [ s:base00, s:base03 ] ] +let s:p.insert.left = [ [ s:base023, s:green ], [ s:base3, s:base01 ] ] +let s:p.replace.left = [ [ s:base023, s:orange ], [ s:base3, s:base01 ] ] +let s:p.visual.left = [ [ s:base023, s:magenta ], [ s:base3, s:base01 ] ] +let s:p.normal.middle = [ [ s:base1, s:base02 ] ] +let s:p.inactive.middle = [ [ s:base0, s:base02 ] ] +let s:p.tabline.left = [ [ s:base2, s:base01 ] ] +let s:p.tabline.tabsel = [ [ s:base2, s:base03 ] ] +let s:p.tabline.middle = [ [ s:base01, s:base1 ] ] +let s:p.tabline.right = copy(s:p.normal.right) +let s:p.normal.error = [ [ s:base023, s:red ] ] +let s:p.normal.warning = [ [ s:base023, s:yellow ] ] + +let g:lightline#colorscheme#Tomorrow_Night_Blue#palette = lightline#colorscheme#fill(s:p) diff --git a/start/lightline/autoload/lightline/colorscheme/Tomorrow_Night_Bright.vim b/start/lightline/autoload/lightline/colorscheme/Tomorrow_Night_Bright.vim new file mode 100644 index 0000000..5b81a31 --- /dev/null +++ b/start/lightline/autoload/lightline/colorscheme/Tomorrow_Night_Bright.vim @@ -0,0 +1,42 @@ +" ============================================================================= +" Filename: autoload/lightline/colorscheme/Tomorrow_Night_Bright.vim +" Author: itchyny +" License: MIT License +" Last Change: 2013/09/07 14:13:26. +" ============================================================================= +let s:base3 = '#eaeaea' +let s:base23 = '#d0d0d0' +let s:base2 = '#c6c6c6' +let s:base1 = '#b2b2b2' +let s:base0 = '#949494' +let s:base00 = '#767676' +let s:base01 = '#606060' +let s:base02 = '#4e4e4e' +let s:base023 = '#262626' +let s:base03 = '#12124c' +let s:red = '#d54e53' +let s:orange = '#e78c45' +let s:yellow = '#e7c547' +let s:green = '#b9ca4a' +let s:cyan = '#70c0b1' +let s:blue = '#7aa6da' +let s:magenta = '#c397d8' + +let s:p = {'normal': {}, 'inactive': {}, 'insert': {}, 'replace': {}, 'visual': {}, 'tabline': {}} +let s:p.normal.left = [ [ s:base023, s:blue ], [ s:base3, s:base01 ] ] +let s:p.normal.right = [ [ s:base02, s:base1 ], [ s:base2, s:base01 ] ] +let s:p.inactive.right = [ [ s:base02, s:base0 ], [ s:base1, s:base01 ] ] +let s:p.inactive.left = [ [ s:base02, s:base0 ], [ s:base00, s:base03 ] ] +let s:p.insert.left = [ [ s:base023, s:green ], [ s:base3, s:base01 ] ] +let s:p.replace.left = [ [ s:base023, s:orange ], [ s:base3, s:base01 ] ] +let s:p.visual.left = [ [ s:base023, s:magenta ], [ s:base3, s:base01 ] ] +let s:p.normal.middle = [ [ s:base1, s:base02 ] ] +let s:p.inactive.middle = [ [ s:base0, s:base02 ] ] +let s:p.tabline.left = [ [ s:base2, s:base01 ] ] +let s:p.tabline.tabsel = [ [ s:base2, s:base023 ] ] +let s:p.tabline.middle = [ [ s:base01, s:base1 ] ] +let s:p.tabline.right = copy(s:p.normal.right) +let s:p.normal.error = [ [ s:red, s:base023 ] ] +let s:p.normal.warning = [ [ s:yellow, s:base02 ] ] + +let g:lightline#colorscheme#Tomorrow_Night_Bright#palette = lightline#colorscheme#fill(s:p) diff --git a/start/lightline/autoload/lightline/colorscheme/Tomorrow_Night_Eighties.vim b/start/lightline/autoload/lightline/colorscheme/Tomorrow_Night_Eighties.vim new file mode 100644 index 0000000..5124ecc --- /dev/null +++ b/start/lightline/autoload/lightline/colorscheme/Tomorrow_Night_Eighties.vim @@ -0,0 +1,42 @@ +" ============================================================================= +" Filename: autoload/lightline/colorscheme/Tomorrow_Night_Eighties.vim +" Author: itchyny +" License: MIT License +" Last Change: 2013/09/07 14:14:14. +" ============================================================================= +let s:base3 = '#cccccc' +let s:base23 = '#bbbbbb' +let s:base2 = '#aaaaaa' +let s:base1 = '#999999' +let s:base0 = '#777777' +let s:base00 = '#666666' +let s:base01 = '#555555' +let s:base02 = '#444444' +let s:base023 = '#333333' +let s:base03 = '#2d2d2d' +let s:red = '#f2777a' +let s:orange = '#f99157' +let s:yellow = '#ffcc66' +let s:green = '#99cc99' +let s:cyan = '#009999' +let s:blue = '#99cccc' +let s:magenta = '#cc99cc' + +let s:p = {'normal': {}, 'inactive': {}, 'insert': {}, 'replace': {}, 'visual': {}, 'tabline': {}} +let s:p.normal.left = [ [ s:base023, s:blue ], [ s:base3, s:base01 ] ] +let s:p.normal.right = [ [ s:base02, s:base1 ], [ s:base2, s:base01 ] ] +let s:p.inactive.right = [ [ s:base02, s:base0 ], [ s:base1, s:base01 ] ] +let s:p.inactive.left = [ [ s:base02, s:base0 ], [ s:base00, s:base03 ] ] +let s:p.insert.left = [ [ s:base023, s:green ], [ s:base3, s:base01 ] ] +let s:p.replace.left = [ [ s:base023, s:orange ], [ s:base3, s:base01 ] ] +let s:p.visual.left = [ [ s:base023, s:magenta ], [ s:base3, s:base01 ] ] +let s:p.normal.middle = [ [ s:base1, s:base02 ] ] +let s:p.inactive.middle = [ [ s:base0, s:base02 ] ] +let s:p.tabline.left = [ [ s:base2, s:base01 ] ] +let s:p.tabline.tabsel = [ [ s:base2, s:base03 ] ] +let s:p.tabline.middle = [ [ s:base01, s:base1 ] ] +let s:p.tabline.right = copy(s:p.normal.right) +let s:p.normal.error = [ [ s:base023, s:red ] ] +let s:p.normal.warning = [ [ s:base023, s:yellow ] ] + +let g:lightline#colorscheme#Tomorrow_Night_Eighties#palette = lightline#colorscheme#fill(s:p) diff --git a/start/lightline/autoload/lightline/colorscheme/darcula.vim b/start/lightline/autoload/lightline/colorscheme/darcula.vim new file mode 100644 index 0000000..928e8b7 --- /dev/null +++ b/start/lightline/autoload/lightline/colorscheme/darcula.vim @@ -0,0 +1,37 @@ +" ============================================================================= +" Filename: autoload/lightline/colorscheme/darcula.vim +" Author: kkopec +" License: MIT License +" Last Change: 2017/02/11 21:18:54. +" ============================================================================= + +let s:black = [ '#2b2b2b', 235 ] +let s:gray = [ '#323232', 236 ] +let s:white = [ '#a9b7c6', 250 ] +let s:blue = [ '#6897bb' , 67 ] +let s:green = [ '#629755', 71 ] +let s:purple = [ '#9876aa', 104 ] +let s:red = [ '#ff6b68', 204 ] +let s:yellow = [ '#ffc66d', 222 ] + +let s:p = {'normal': {}, 'inactive': {}, 'insert': {}, 'replace': {}, 'visual': {}, 'tabline': {}} +let s:p.normal.left = [ [ s:black, s:purple ], [ s:purple, s:gray ] ] +let s:p.normal.right = [ [ s:black, s:purple ], [ s:purple, s:gray ] ] +let s:p.inactive.left = [ [ s:black, s:blue ], [ s:blue, s:gray ] ] +let s:p.inactive.right = [ [ s:black, s:blue ], [ s:blue, s:gray ] ] +let s:p.insert.left = [ [ s:black, s:green ], [ s:green, s:gray ] ] +let s:p.insert.right = [ [ s:black, s:green ], [ s:green, s:gray ] ] +let s:p.replace.left = [ [ s:black, s:red ], [ s:red, s:gray ] ] +let s:p.replace.right = [ [ s:black, s:red ], [ s:red, s:gray ] ] +let s:p.visual.left = [ [ s:black, s:yellow ], [ s:yellow, s:gray ] ] +let s:p.visual.right = [ [ s:black, s:yellow ], [ s:yellow, s:gray ] ] +let s:p.normal.middle = [ [ s:white, s:gray ] ] +let s:p.inactive.middle = [ [ s:white, s:gray ] ] +let s:p.tabline.left = [ [ s:blue, s:gray ] ] +let s:p.tabline.tabsel = [ [ s:black, s:blue ] ] +let s:p.tabline.middle = [ [ s:blue, s:gray ] ] +let s:p.tabline.right = [ [ s:black, s:blue ] ] +let s:p.normal.error = [ [ s:red, s:black ] ] +let s:p.normal.warning = [ [ s:yellow, s:black ] ] + +let g:lightline#colorscheme#darcula#palette = lightline#colorscheme#flatten(s:p) diff --git a/start/lightline/autoload/lightline/colorscheme/default.vim b/start/lightline/autoload/lightline/colorscheme/default.vim new file mode 100644 index 0000000..ee9835c --- /dev/null +++ b/start/lightline/autoload/lightline/colorscheme/default.vim @@ -0,0 +1,8 @@ +" ============================================================================= +" Filename: autoload/lightline/colorscheme/default.vim +" Author: itchyny +" License: MIT License +" Last Change: 2013/08/22 06:05:52. +" ============================================================================= + +let g:lightline#colorscheme#default#palette = g:lightline#colorscheme#powerline#palette diff --git a/start/lightline/autoload/lightline/colorscheme/deus.vim b/start/lightline/autoload/lightline/colorscheme/deus.vim new file mode 100644 index 0000000..0a7da60 --- /dev/null +++ b/start/lightline/autoload/lightline/colorscheme/deus.vim @@ -0,0 +1,40 @@ +" ============================================================================= +" Filename: autoload/lightline/colorscheme/deus.vim +" Author: nikersify +" License: MIT License +" Last Change: 2018/01/24 13:26:00 +" ============================================================================= + +let s:term_red = 204 +let s:term_green = 114 +let s:term_yellow = 180 +let s:term_blue = 39 +let s:term_purple = 170 +let s:term_white = 145 +let s:term_black = 235 +let s:term_grey = 236 + +let s:p = {'normal': {}, 'inactive': {}, 'insert': {}, 'replace': {}, 'visual': {}, 'tabline': {}} + +let s:p.normal.left = [ [ '#292c33', '#98c379', s:term_black, s:term_green, 'bold' ], [ '#98c379', '#292c33', s:term_green, s:term_black ] ] +let s:p.normal.right = [ [ '#292c33', '#98c379', s:term_black, s:term_green ], [ '#abb2bf', '#3e4452', s:term_white, s:term_grey ], [ '#98c379', '#292c33', s:term_green, s:term_black ] ] +let s:p.inactive.right = [ [ '#292c33', '#61afef', s:term_black, s:term_blue], [ '#abb2bf', '#3e4452', s:term_white, s:term_grey ] ] +let s:p.inactive.left = s:p.inactive.right[1:] +" her +let s:p.insert.left = [ [ '#292c33', '#61afef', s:term_black, s:term_blue, 'bold' ], [ '#61afef', '#292c33', s:term_blue, s:term_black ] ] +let s:p.insert.right = [ [ '#292c33', '#61afef', s:term_black, s:term_blue ], [ '#ABB2BF', '#3E4452', s:term_white, s:term_grey ], [ '#61afef', '#292c33', s:term_blue, s:term_black ] ] +let s:p.replace.left = [ [ '#292c33', '#e06c75', s:term_black, s:term_red, 'bold' ], [ '#e06c75', '#292c33', s:term_red, s:term_black ] ] +let s:p.replace.right = [ [ '#292c33', '#e06c75', s:term_black, s:term_red, 'bold' ], s:p.normal.right[1], [ '#e06c75', '#292c33', s:term_red, s:term_black ] ] +let s:p.visual.left = [ [ '#292c33', '#c678dd', s:term_black, s:term_purple, 'bold' ], [ '#c678dd', '#292c33', s:term_purple, s:term_black ] ] +let s:p.visual.right = [ [ '#292c33', '#c678dd', s:term_black, s:term_purple, 'bold' ], s:p.normal.right[1], [ '#c678dd', '#292c33', s:term_purple, s:term_black ] ] +let s:p.normal.middle = [ [ '#abb2bf', '#292c33', s:term_white, s:term_black ] ] +let s:p.insert.middle = s:p.normal.middle +let s:p.replace.middle = s:p.normal.middle +let s:p.tabline.left = [ s:p.normal.left[1] ] +let s:p.tabline.tabsel = [ s:p.normal.left[0] ] +let s:p.tabline.middle = s:p.normal.middle +let s:p.tabline.right = [ s:p.normal.left[1] ] +let s:p.normal.error = [ [ '#292c33', '#e06c75', s:term_black, s:term_red ] ] +let s:p.normal.warning = [ [ '#292c33', '#e5c07b', s:term_black, s:term_yellow ] ] + +let g:lightline#colorscheme#deus#palette = lightline#colorscheme#fill(s:p) diff --git a/start/lightline/autoload/lightline/colorscheme/jellybeans.vim b/start/lightline/autoload/lightline/colorscheme/jellybeans.vim new file mode 100644 index 0000000..15b2b35 --- /dev/null +++ b/start/lightline/autoload/lightline/colorscheme/jellybeans.vim @@ -0,0 +1,40 @@ +" ============================================================================= +" Filename: autoload/lightline/colorscheme/jellybeans.vim +" Author: itchyny +" License: MIT License +" Last Change: 2013/09/07 12:21:04. +" ============================================================================= +let s:base03 = [ '#151513', 233 ] +let s:base02 = [ '#30302c ', 236 ] +let s:base01 = [ '#4e4e43', 239 ] +let s:base00 = [ '#666656', 242 ] +let s:base0 = [ '#808070', 244 ] +let s:base1 = [ '#949484', 246 ] +let s:base2 = [ '#a8a897', 248 ] +let s:base3 = [ '#e8e8d3', 253 ] +let s:yellow = [ '#ffb964', 215 ] +let s:orange = [ '#fad07a', 222 ] +let s:red = [ '#cf6a4c', 167 ] +let s:magenta = [ '#f0a0c0', 217 ] +let s:blue = [ '#8197bf', 103 ] +let s:cyan = [ '#8fbfdc', 110 ] +let s:green = [ '#99ad6a', 107 ] + +let s:p = {'normal': {}, 'inactive': {}, 'insert': {}, 'replace': {}, 'visual': {}, 'tabline': {}} +let s:p.normal.left = [ [ s:base02, s:blue ], [ s:base3, s:base01 ] ] +let s:p.normal.right = [ [ s:base02, s:base1 ], [ s:base2, s:base01 ] ] +let s:p.inactive.right = [ [ s:base02, s:base00 ], [ s:base0, s:base02 ] ] +let s:p.inactive.left = [ [ s:base0, s:base02 ], [ s:base00, s:base02 ] ] +let s:p.insert.left = [ [ s:base02, s:green ], [ s:base3, s:base01 ] ] +let s:p.replace.left = [ [ s:base02, s:red ], [ s:base3, s:base01 ] ] +let s:p.visual.left = [ [ s:base02, s:magenta ], [ s:base3, s:base01 ] ] +let s:p.normal.middle = [ [ s:base0, s:base02 ] ] +let s:p.inactive.middle = [ [ s:base00, s:base02 ] ] +let s:p.tabline.left = [ [ s:base3, s:base00 ] ] +let s:p.tabline.tabsel = [ [ s:base3, s:base02 ] ] +let s:p.tabline.middle = [ [ s:base01, s:base1 ] ] +let s:p.tabline.right = copy(s:p.normal.right) +let s:p.normal.error = [ [ s:red, s:base02 ] ] +let s:p.normal.warning = [ [ s:yellow, s:base01 ] ] + +let g:lightline#colorscheme#jellybeans#palette = lightline#colorscheme#flatten(s:p) diff --git a/start/lightline/autoload/lightline/colorscheme/landscape.vim b/start/lightline/autoload/lightline/colorscheme/landscape.vim new file mode 100644 index 0000000..68d0920 --- /dev/null +++ b/start/lightline/autoload/lightline/colorscheme/landscape.vim @@ -0,0 +1,25 @@ +" ============================================================================= +" Filename: autoload/lightline/colorscheme/landscape.vim +" Author: itchyny +" License: MIT License +" Last Change: 2015/11/26 21:49:44. +" ============================================================================= + +let s:p = {'normal': {}, 'inactive': {}, 'insert': {}, 'replace': {}, 'visual': {}, 'tabline': {}} +let s:p.normal.left = [ ['#0000ff', '#ffffff', 21, 231, 'bold' ], [ '#ffffff', '#0000ff', 231, 21 ] ] +let s:p.normal.right = [ [ '#303030', '#d0d0d0', 236, 252 ], [ '#303030', '#8a8a8a', 236, 245 ], [ '#bcbcbc', '#585858', 250, 240 ] ] +let s:p.inactive.right = [ [ '#121212', '#606060', 233, 241 ], [ '#121212', '#3a3a3a', 233, 237 ], [ '#121212', '#262626', 233, 235 ] ] +let s:p.inactive.left = s:p.inactive.right[1:] +let s:p.insert.left = [ ['#005f00', '#ffffff', 22, 231, 'bold' ], [ '#ffffff', '#005f00', 231, 22 ] ] +let s:p.replace.left = [ [ '#af0000', '#ffffff', 124, 231, 'bold' ], [ '#ffffff', '#af0000', 231, 124 ] ] +let s:p.visual.left = [ [ '#5f00ff', '#ffffff', 57, 231, 'bold' ], [ '#ffffff', '#5f00ff', 231, 57 ] ] +let s:p.normal.middle = [ [ '#8a8a8a', '#303030', 245, 236 ] ] +let s:p.inactive.middle = [ [ '#303030', '#121212', 236, 233 ] ] +let s:p.tabline.left = [ [ '#d0d0d0', '#666666', 252, 242 ] ] +let s:p.tabline.tabsel = [ [ '#dadada', '#121212', 253, 233 ] ] +let s:p.tabline.middle = [ [ '#8a8a8a', '#3a3a3a', 245, 237 ] ] +let s:p.tabline.right = [ [ '#d0d0d0', '#666666', 252, 242 ] ] +let s:p.normal.error = [ [ '#d0d0d0', '#ff0000', 252, 196 ] ] +let s:p.normal.warning = [ [ '#262626', '#ffff00', 235, 226 ] ] + +let g:lightline#colorscheme#landscape#palette = s:p diff --git a/start/lightline/autoload/lightline/colorscheme/materia.vim b/start/lightline/autoload/lightline/colorscheme/materia.vim new file mode 100644 index 0000000..fdab2cb --- /dev/null +++ b/start/lightline/autoload/lightline/colorscheme/materia.vim @@ -0,0 +1,63 @@ +" ============================================================================= +" Filename: autoload/lightline/colorscheme/materia.vim +" Author: Lokesh Krishna +" License: MIT License +" Last Change: 2017/11/25 11:13:40. +" ============================================================================= + +" Common colors +let s:fg = '#d5dbe5' +let s:blue = '#89ddff' +let s:green = '#8bd649' +let s:purple = '#82aaff' +let s:red1 = '#ec5f67' +let s:red2 = '#ec5f67' +let s:yellow = '#ffcc00' + +let s:p = {'normal': {}, 'inactive': {}, 'insert': {}, 'replace': {}, 'visual': {}, 'tabline': {}} + +if lightline#colorscheme#background() ==# 'light' + " Light variant + let s:bg = '#ffffff' + let s:gray1 = '#2c393f' + let s:gray2 = '#d5dbe5' + let s:gray3 = '#707880' + + let s:p.normal.left = [ [ s:bg, s:green, 'bold' ], [ s:gray1, s:gray3 ] ] + let s:p.normal.middle = [ [ s:gray1, s:gray2 ] ] + let s:p.inactive.left = [ [ s:bg, s:gray3 ], [ s:bg, s:gray3 ] ] + let s:p.inactive.middle = [ [ s:gray3, s:gray2 ] ] + let s:p.inactive.right = [ [ s:bg, s:gray3 ], [ s:bg, s:gray3 ] ] + let s:p.insert.left = [ [ s:bg, s:blue, 'bold' ], [ s:gray1, s:gray3 ] ] + let s:p.replace.left = [ [ s:bg, s:red1, 'bold' ], [ s:gray1, s:gray3 ] ] + let s:p.visual.left = [ [ s:bg, s:purple, 'bold' ], [ s:gray1, s:gray3 ] ] +else + " Dark variant + let s:bg = '#263238' + let s:gray1 = '#37474f' + let s:gray2 = '#2c393f' + let s:gray3 = '#37474f' + + let s:p.normal.left = [ [ s:bg, s:green, 'bold' ], [ s:fg, s:gray3 ] ] + let s:p.normal.middle = [ [ s:fg, s:gray2 ] ] + let s:p.inactive.left = [ [ s:gray1, s:bg ], [ s:gray1, s:bg ] ] + let s:p.inactive.middle = [ [ s:gray1, s:gray2 ] ] + let s:p.inactive.right = [ [ s:gray1, s:bg ], [ s:gray1, s:bg ] ] + let s:p.insert.left = [ [ s:bg, s:blue, 'bold' ], [ s:fg, s:gray3 ] ] + let s:p.replace.left = [ [ s:bg, s:red1, 'bold' ], [ s:fg, s:gray3 ] ] + let s:p.visual.left = [ [ s:bg, s:purple, 'bold' ], [ s:fg, s:gray3 ] ] +endif + +" Common +let s:p.normal.right = [ [ s:bg, s:green, 'bold' ], [ s:bg, s:green, 'bold' ] ] +let s:p.normal.error = [ [ s:red2, s:bg ] ] +let s:p.normal.warning = [ [ s:yellow, s:bg ] ] +let s:p.insert.right = [ [ s:bg, s:blue, 'bold' ], [ s:bg, s:blue, 'bold' ] ] +let s:p.replace.right = [ [ s:bg, s:red1, 'bold' ], [ s:bg, s:red1, 'bold' ] ] +let s:p.visual.right = [ [ s:bg, s:purple, 'bold' ], [ s:bg, s:purple, 'bold' ] ] +let s:p.tabline.left = [ [ s:bg, s:gray3 ] ] +let s:p.tabline.tabsel = [ [ s:bg, s:purple, 'bold' ] ] +let s:p.tabline.middle = [ [ s:gray3, s:gray2 ] ] +let s:p.tabline.right = copy(s:p.normal.right) + +let g:lightline#colorscheme#materia#palette = lightline#colorscheme#fill(s:p) diff --git a/start/lightline/autoload/lightline/colorscheme/material.vim b/start/lightline/autoload/lightline/colorscheme/material.vim new file mode 100644 index 0000000..0d704b7 --- /dev/null +++ b/start/lightline/autoload/lightline/colorscheme/material.vim @@ -0,0 +1,63 @@ +" ============================================================================= +" Filename: autoload/lightline/colorscheme/material.vim +" Author: Lokesh Krishna +" License: MIT License +" Last Change: 2017/11/25 11:13:42. +" ============================================================================= + +" Common colors +let s:fg = '#eeffff' +let s:blue = '#82aaff' +let s:green = '#c3e88d' +let s:purple = '#c792ea' +let s:red1 = '#f07178' +let s:red2 = '#ff5370' +let s:yellow = '#ffcb6b' + +let s:p = {'normal': {}, 'inactive': {}, 'insert': {}, 'replace': {}, 'visual': {}, 'tabline': {}} + +if lightline#colorscheme#background() ==# 'light' + " Light variant + let s:bg = '#ffffff' + let s:gray1 = '#2e3c43' + let s:gray2 = '#eeffff' + let s:gray3 = '#546e7a' + + let s:p.normal.left = [ [ s:bg, s:blue, 'bold' ], [ s:gray1, s:gray3 ] ] + let s:p.normal.middle = [ [ s:gray1, s:gray2 ] ] + let s:p.inactive.left = [ [ s:bg, s:gray3 ], [ s:bg, s:gray3 ] ] + let s:p.inactive.middle = [ [ s:gray3, s:gray2 ] ] + let s:p.inactive.right = [ [ s:bg, s:gray3 ], [ s:bg, s:gray3 ] ] + let s:p.insert.left = [ [ s:bg, s:green, 'bold' ], [ s:gray1, s:gray3 ] ] + let s:p.replace.left = [ [ s:bg, s:red1, 'bold' ], [ s:gray1, s:gray3 ] ] + let s:p.visual.left = [ [ s:bg, s:purple, 'bold' ], [ s:gray1, s:gray3 ] ] +else + " Dark variant + let s:bg = '#263238' + let s:gray1 = '#314549' + let s:gray2 = '#2E3C43' + let s:gray3 = '#314549' + + let s:p.normal.left = [ [ s:bg, s:blue, 'bold' ], [ s:fg, s:gray3 ] ] + let s:p.normal.middle = [ [ s:fg, s:gray2 ] ] + let s:p.inactive.left = [ [ s:gray1, s:bg ], [ s:gray1, s:bg ] ] + let s:p.inactive.middle = [ [ s:gray1, s:gray2 ] ] + let s:p.inactive.right = [ [ s:gray1, s:bg ], [ s:gray1, s:bg ] ] + let s:p.insert.left = [ [ s:bg, s:green, 'bold' ], [ s:fg, s:gray3 ] ] + let s:p.replace.left = [ [ s:bg, s:red1, 'bold' ], [ s:fg, s:gray3 ] ] + let s:p.visual.left = [ [ s:bg, s:purple, 'bold' ], [ s:fg, s:gray3 ] ] +endif + +" Common +let s:p.normal.right = [ [ s:bg, s:blue, 'bold' ], [ s:bg, s:blue, 'bold' ] ] +let s:p.normal.error = [ [ s:red2, s:bg ] ] +let s:p.normal.warning = [ [ s:yellow, s:bg ] ] +let s:p.insert.right = [ [ s:bg, s:green, 'bold' ], [ s:bg, s:green, 'bold' ] ] +let s:p.replace.right = [ [ s:bg, s:red1, 'bold' ], [ s:bg, s:red1, 'bold' ] ] +let s:p.visual.right = [ [ s:bg, s:purple, 'bold' ], [ s:bg, s:purple, 'bold' ] ] +let s:p.tabline.left = [ [ s:fg, s:gray3 ] ] +let s:p.tabline.tabsel = [ [ s:bg, s:purple, 'bold' ] ] +let s:p.tabline.middle = [ [ s:gray3, s:gray2 ] ] +let s:p.tabline.right = [ [ s:bg, s:red1, 'bold' ] ] + +let g:lightline#colorscheme#material#palette = lightline#colorscheme#fill(s:p) diff --git a/start/lightline/autoload/lightline/colorscheme/molokai.vim b/start/lightline/autoload/lightline/colorscheme/molokai.vim new file mode 100644 index 0000000..9d066a1 --- /dev/null +++ b/start/lightline/autoload/lightline/colorscheme/molokai.vim @@ -0,0 +1,36 @@ +" ============================================================================= +" Filename: autoload/lightline/colorscheme/molokai.vim +" Author: challsted +" License: MIT License +" Last Change: 2016/11/17 00:27:58. +" ============================================================================= +" +let s:black = [ '#232526', 233 ] +let s:gray = [ '#808080', 244 ] +let s:white = [ '#f8f8f2', 234 ] +let s:cyan = [ '#66d9ef', 81 ] +let s:green = [ '#a6e22e', 118 ] +let s:orange = [ '#ef5939', 166 ] +let s:pink = [ '#f92672', 161 ] +let s:red = [ '#ff0000', 160 ] +let s:yellow = [ '#e6db74', 229 ] + +let s:p = {'normal': {}, 'inactive': {}, 'insert': {}, 'replace': {}, 'visual': {}, 'tabline': {}} + +let s:p.normal.left = [ [ s:black, s:cyan ], [ s:orange, s:black ] ] +let s:p.normal.middle = [ [ s:orange, s:black ] ] +let s:p.normal.right = [ [ s:pink, s:black ], [ s:black, s:pink ] ] +let s:p.normal.error = [ [ s:pink, s:black ] ] +let s:p.normal.warning = [ [ s:yellow, s:black ] ] +let s:p.insert.left = [ [ s:black, s:green ], [ s:green, s:black ] ] +let s:p.visual.left = [ [ s:black, s:yellow ], [ s:yellow, s:black ] ] +let s:p.replace.left = [ [ s:black, s:red ], [ s:red, s:black ] ] +let s:p.inactive.left = [ [ s:pink, s:black ], [ s:white, s:black ] ] +let s:p.inactive.middle = [ [ s:gray, s:black ] ] +let s:p.inactive.right = [ [ s:white, s:pink ], [ s:pink, s:black ] ] +let s:p.tabline.left = [ [ s:pink, s:black ] ] +let s:p.tabline.middle = [ [ s:pink, s:black] ] +let s:p.tabline.right = copy(s:p.normal.right) +let s:p.tabline.tabsel = [ [ s:black, s:pink ] ] + +let g:lightline#colorscheme#molokai#palette = lightline#colorscheme#flatten(s:p) diff --git a/start/lightline/autoload/lightline/colorscheme/nord.vim b/start/lightline/autoload/lightline/colorscheme/nord.vim new file mode 100644 index 0000000..96d24ae --- /dev/null +++ b/start/lightline/autoload/lightline/colorscheme/nord.vim @@ -0,0 +1,46 @@ +" ============================================================================= +" Filename: autoload/lightline/colorscheme/nord.vim +" Author: arcticicestudio +" License: MIT +" Last Change: 2017/11/12 20:27:51 +" ============================================================================= + +let s:p = {'normal': {}, 'inactive': {}, 'insert': {}, 'replace': {}, 'visual': {}, 'tabline': {}} + +let s:nord0 = ["#2E3440", "NONE"] +let s:nord1 = ["#3B4252", 0] +let s:nord2 = ["#434C5E", "NONE"] +let s:nord3 = ["#4C566A", 8] +let s:nord4 = ["#D8DEE9", "NONE"] +let s:nord5 = ["#E5E9F0", 7] +let s:nord6 = ["#ECEFF4", 15] +let s:nord7 = ["#8FBCBB", 14] +let s:nord8 = ["#88C0D0", 6] +let s:nord9 = ["#81A1C1", 4] +let s:nord10 = ["#5E81AC", 12] +let s:nord11 = ["#BF616A", 1] +let s:nord12 = ["#D08770", 11] +let s:nord13 = ["#EBCB8B", 3] +let s:nord14 = ["#A3BE8C", 2] +let s:nord15 = ["#B48EAD", 5] + +let s:p.normal.left = [ [ s:nord1, s:nord8 ], [ s:nord5, s:nord1 ] ] +let s:p.normal.middle = [ [ s:nord5, s:nord3 ] ] +let s:p.normal.right = [ [ s:nord5, s:nord1 ], [ s:nord5, s:nord1 ] ] +let s:p.normal.warning = [ [ s:nord1, s:nord13 ] ] +let s:p.normal.error = [ [ s:nord1, s:nord11 ] ] + +let s:p.inactive.left = [ [ s:nord1, s:nord8 ], [ s:nord5, s:nord1 ] ] +let s:p.inactive.middle = [ [ s:nord5, s:nord1 ] ] +let s:p.inactive.right = [ [ s:nord5, s:nord1 ], [ s:nord5, s:nord1 ] ] + +let s:p.insert.left = [ [ s:nord1, s:nord6 ], [ s:nord5, s:nord1 ] ] +let s:p.replace.left = [ [ s:nord1, s:nord13 ], [ s:nord5, s:nord1 ] ] +let s:p.visual.left = [ [ s:nord1, s:nord7 ], [ s:nord5, s:nord1 ] ] + +let s:p.tabline.left = [ [ s:nord5, s:nord3 ] ] +let s:p.tabline.middle = [ [ s:nord5, s:nord3 ] ] +let s:p.tabline.right = [ [ s:nord5, s:nord3 ] ] +let s:p.tabline.tabsel = [ [ s:nord1, s:nord8 ] ] + +let g:lightline#colorscheme#nord#palette = lightline#colorscheme#flatten(s:p) diff --git a/start/lightline/autoload/lightline/colorscheme/one.vim b/start/lightline/autoload/lightline/colorscheme/one.vim new file mode 100644 index 0000000..a28fb8d --- /dev/null +++ b/start/lightline/autoload/lightline/colorscheme/one.vim @@ -0,0 +1,64 @@ +" ============================================================================= +" Filename: autoload/lightline/colorscheme/one.vim +" Author: Zoltan Dalmadi +" License: MIT License +" Last Change: 2017/11/28 21:53:01. +" ============================================================================= + +" Common colors +let s:fg = [ '#abb2bf', 145 ] +let s:blue = [ '#61afef', 75 ] +let s:green = [ '#98c379', 76 ] +let s:purple = [ '#c678dd', 176 ] +let s:red1 = [ '#e06c75', 168 ] +let s:red2 = [ '#be5046', 168 ] +let s:yellow = [ '#e5c07b', 180 ] + +let s:p = {'normal': {}, 'inactive': {}, 'insert': {}, 'replace': {}, 'visual': {}, 'tabline': {}} + +if lightline#colorscheme#background() ==# 'light' + " Light variant + let s:bg = [ '#fafafa', 255 ] + let s:gray1 = [ '#494b53', 238 ] + let s:gray2 = [ '#f0f0f0', 255 ] + let s:gray3 = [ '#d0d0d0', 250 ] + let s:green = [ '#98c379', 35 ] + + let s:p.normal.left = [ [ s:bg, s:green, 'bold' ], [ s:gray1, s:gray3 ] ] + let s:p.normal.middle = [ [ s:gray1, s:gray2 ] ] + let s:p.inactive.left = [ [ s:bg, s:gray3 ], [ s:bg, s:gray3 ] ] + let s:p.inactive.middle = [ [ s:gray3, s:gray2 ] ] + let s:p.inactive.right = [ [ s:bg, s:gray3 ], [ s:bg, s:gray3 ] ] + let s:p.insert.left = [ [ s:bg, s:blue, 'bold' ], [ s:gray1, s:gray3 ] ] + let s:p.replace.left = [ [ s:bg, s:red1, 'bold' ], [ s:gray1, s:gray3 ] ] + let s:p.visual.left = [ [ s:bg, s:purple, 'bold' ], [ s:gray1, s:gray3 ] ] +else + " Dark variant + let s:bg = [ '#282c34', 235 ] + let s:gray1 = [ '#5c6370', 241 ] + let s:gray2 = [ '#2c323d', 235 ] + let s:gray3 = [ '#3e4452', 240 ] + + let s:p.normal.left = [ [ s:bg, s:green, 'bold' ], [ s:fg, s:gray3 ] ] + let s:p.normal.middle = [ [ s:fg, s:gray2 ] ] + let s:p.inactive.left = [ [ s:gray1, s:bg ], [ s:gray1, s:bg ] ] + let s:p.inactive.middle = [ [ s:gray1, s:gray2 ] ] + let s:p.inactive.right = [ [ s:gray1, s:bg ], [ s:gray1, s:bg ] ] + let s:p.insert.left = [ [ s:bg, s:blue, 'bold' ], [ s:fg, s:gray3 ] ] + let s:p.replace.left = [ [ s:bg, s:red1, 'bold' ], [ s:fg, s:gray3 ] ] + let s:p.visual.left = [ [ s:bg, s:purple, 'bold' ], [ s:fg, s:gray3 ] ] +endif + +" Common +let s:p.normal.right = [ [ s:bg, s:green, 'bold' ], [ s:bg, s:green, 'bold' ] ] +let s:p.normal.error = [ [ s:red2, s:bg ] ] +let s:p.normal.warning = [ [ s:yellow, s:bg ] ] +let s:p.insert.right = [ [ s:bg, s:blue, 'bold' ], [ s:bg, s:blue, 'bold' ] ] +let s:p.replace.right = [ [ s:bg, s:red1, 'bold' ], [ s:bg, s:red1, 'bold' ] ] +let s:p.visual.right = [ [ s:bg, s:purple, 'bold' ], [ s:bg, s:purple, 'bold' ] ] +let s:p.tabline.left = [ [ s:bg, s:gray3 ] ] +let s:p.tabline.tabsel = [ [ s:bg, s:purple, 'bold' ] ] +let s:p.tabline.middle = [ [ s:gray3, s:gray2 ] ] +let s:p.tabline.right = copy(s:p.normal.right) + +let g:lightline#colorscheme#one#palette = lightline#colorscheme#flatten(s:p) diff --git a/start/lightline/autoload/lightline/colorscheme/powerline.vim b/start/lightline/autoload/lightline/colorscheme/powerline.vim new file mode 100644 index 0000000..40e48d4 --- /dev/null +++ b/start/lightline/autoload/lightline/colorscheme/powerline.vim @@ -0,0 +1,28 @@ +" ============================================================================= +" Filename: autoload/lightline/colorscheme/powerline.vim +" Author: itchyny +" License: MIT License +" Last Change: 2013/09/07 15:54:41. +" ============================================================================= + +let s:p = {'normal': {}, 'inactive': {}, 'insert': {}, 'replace': {}, 'visual': {}, 'tabline': {}} +let s:p.normal.left = [ ['darkestgreen', 'brightgreen', 'bold'], ['white', 'gray4'] ] +let s:p.normal.right = [ ['gray5', 'gray10'], ['gray9', 'gray4'], ['gray8', 'gray2'] ] +let s:p.inactive.right = [ ['gray1', 'gray5'], ['gray4', 'gray1'], ['gray4', 'gray0'] ] +let s:p.inactive.left = s:p.inactive.right[1:] +let s:p.insert.left = [ ['darkestcyan', 'white', 'bold'], ['white', 'darkblue'] ] +let s:p.insert.right = [ [ 'darkestcyan', 'mediumcyan' ], [ 'mediumcyan', 'darkblue' ], [ 'mediumcyan', 'darkestblue' ] ] +let s:p.replace.left = [ ['white', 'brightred', 'bold'], ['white', 'gray4'] ] +let s:p.visual.left = [ ['darkred', 'brightorange', 'bold'], ['white', 'gray4'] ] +let s:p.normal.middle = [ [ 'gray7', 'gray2' ] ] +let s:p.insert.middle = [ [ 'mediumcyan', 'darkestblue' ] ] +let s:p.replace.middle = s:p.normal.middle +let s:p.replace.right = s:p.normal.right +let s:p.tabline.left = [ [ 'gray9', 'gray4' ] ] +let s:p.tabline.tabsel = [ [ 'gray9', 'gray1' ] ] +let s:p.tabline.middle = [ [ 'gray2', 'gray8' ] ] +let s:p.tabline.right = [ [ 'gray9', 'gray3' ] ] +let s:p.normal.error = [ [ 'gray9', 'brightestred' ] ] +let s:p.normal.warning = [ [ 'gray1', 'yellow' ] ] + +let g:lightline#colorscheme#powerline#palette = lightline#colorscheme#fill(s:p) diff --git a/start/lightline/autoload/lightline/colorscheme/seoul256.vim b/start/lightline/autoload/lightline/colorscheme/seoul256.vim new file mode 100644 index 0000000..ca2d5a0 --- /dev/null +++ b/start/lightline/autoload/lightline/colorscheme/seoul256.vim @@ -0,0 +1,42 @@ +" ============================================================================= +" Filename: autoload/lightline/colorscheme/seoul256.vim +" Author: atweiden +" License: MIT License +" Last Change: 2015/11/02 08:23:27. +" ============================================================================= +let s:base03 = [ '#151513', 233 ] +let s:base02 = [ '#30302c ', 236 ] +let s:base01 = [ '#4e4e43', 239 ] +let s:base00 = [ '#666656', 242 ] +let s:base0 = [ '#808070', 244 ] +let s:base1 = [ '#949484', 246 ] +let s:base2 = [ '#a8a897', 248 ] +let s:base3 = [ '#e8e8d3', 253 ] +let s:yellow = [ '#d8af5f', 3 ] +let s:orange = [ '#d7875f', 216 ] +let s:red = [ '#d68787', 131 ] +let s:magenta = [ '#df5f87', 168 ] +let s:peach = [ '#d7afaf', 181 ] +let s:blue = [ '#87afaf', 109 ] +let s:cyan = [ '#87d7d7', 23 ] +let s:green = [ '#87af87', 108 ] +let s:white = [ '#d0d0d0', 252 ] + +let s:p = {'normal': {}, 'inactive': {}, 'insert': {}, 'replace': {}, 'visual': {}, 'tabline': {}} +let s:p.normal.left = [ [ s:base02, s:blue ], [ s:base3, s:base01 ] ] +let s:p.normal.right = [ [ s:base02, s:base1 ], [ s:base2, s:base01 ] ] +let s:p.inactive.right = [ [ s:base02, s:base00 ], [ s:base0, s:base02 ] ] +let s:p.inactive.left = [ [ s:base0, s:base02 ], [ s:base00, s:base02 ] ] +let s:p.insert.left = [ [ s:base02, s:green ], [ s:base3, s:base01 ] ] +let s:p.replace.left = [ [ s:base02, s:magenta ], [ s:base3, s:base01 ] ] +let s:p.visual.left = [ [ s:base02, s:peach ], [ s:base3, s:base01 ] ] +let s:p.normal.middle = [ [ s:base0, s:base02 ] ] +let s:p.inactive.middle = [ [ s:base00, s:base02 ] ] +let s:p.tabline.left = [ [ s:base3, s:base00 ] ] +let s:p.tabline.tabsel = [ [ s:base3, s:base02 ] ] +let s:p.tabline.middle = [ [ s:base01, s:base1 ] ] +let s:p.tabline.right = copy(s:p.normal.right) +let s:p.normal.error = [ [ s:red, s:base02 ] ] +let s:p.normal.warning = [ [ s:yellow, s:base01 ] ] + +let g:lightline#colorscheme#seoul256#palette = lightline#colorscheme#flatten(s:p) diff --git a/start/lightline/autoload/lightline/colorscheme/solarized.vim b/start/lightline/autoload/lightline/colorscheme/solarized.vim new file mode 100644 index 0000000..d6ee9c6 --- /dev/null +++ b/start/lightline/autoload/lightline/colorscheme/solarized.vim @@ -0,0 +1,80 @@ +" ============================================================================= +" Filename: autoload/lightline/colorscheme/solarized.vim +" Author: itchyny +" License: MIT License +" Last Change: 2017/11/25 11:13:46. +" ============================================================================= + +let s:cuicolors = { + \ 'base03': [ '8', '234', 'DarkGray' ], + \ 'base02': [ '0', '235', 'Black' ], + \ 'base01': [ '10', '239', 'LightGreen' ], + \ 'base00': [ '11', '240', 'LightYellow' ], + \ 'base0': [ '12', '244', 'LightBlue' ], + \ 'base1': [ '14', '245', 'LightCyan' ], + \ 'base2': [ '7', '187', 'LightGray' ], + \ 'base3': [ '15', '230', 'White' ], + \ 'yellow': [ '3', '136', 'DarkYellow' ], + \ 'orange': [ '9', '166', 'LightRed' ], + \ 'red': [ '1', '124', 'DarkRed' ], + \ 'magenta': [ '5', '125', 'DarkMagenta' ], + \ 'violet': [ '13', '61', 'LightMagenta' ], + \ 'blue': [ '4', '33', 'DarkBlue' ], + \ 'cyan': [ '6', '37', 'DarkCyan' ], + \ 'green': [ '2', '64', 'DarkGreen' ], + \ } + +" The following condition only applies for the console and is the same +" condition vim-colors-solarized uses to determine which set of colors +" to use. +let s:solarized_termcolors = get(g:, 'solarized_termcolors', 256) +if s:solarized_termcolors != 256 && &t_Co >= 16 + let s:cuiindex = 0 +elseif s:solarized_termcolors == 256 + let s:cuiindex = 1 +else + let s:cuiindex = 2 +endif + +let s:base03 = [ '#002b36', s:cuicolors.base03[s:cuiindex] ] +let s:base02 = [ '#073642', s:cuicolors.base02[s:cuiindex] ] +let s:base01 = [ '#586e75', s:cuicolors.base01[s:cuiindex] ] +let s:base00 = [ '#657b83', s:cuicolors.base00[s:cuiindex] ] +let s:base0 = [ '#839496', s:cuicolors.base0[s:cuiindex] ] +let s:base1 = [ '#93a1a1', s:cuicolors.base1[s:cuiindex] ] +let s:base2 = [ '#eee8d5', s:cuicolors.base2[s:cuiindex] ] +let s:base3 = [ '#fdf6e3', s:cuicolors.base3[s:cuiindex] ] +let s:yellow = [ '#b58900', s:cuicolors.yellow[s:cuiindex] ] +let s:orange = [ '#cb4b16', s:cuicolors.orange[s:cuiindex] ] +let s:red = [ '#dc322f', s:cuicolors.red[s:cuiindex] ] +let s:magenta = [ '#d33682', s:cuicolors.magenta[s:cuiindex] ] +let s:violet = [ '#6c71c4', s:cuicolors.violet[s:cuiindex] ] +let s:blue = [ '#268bd2', s:cuicolors.blue[s:cuiindex] ] +let s:cyan = [ '#2aa198', s:cuicolors.cyan[s:cuiindex] ] +let s:green = [ '#859900', s:cuicolors.green[s:cuiindex] ] + +if lightline#colorscheme#background() ==# 'light' + let [ s:base03, s:base3 ] = [ s:base3, s:base03 ] + let [ s:base02, s:base2 ] = [ s:base2, s:base02 ] + let [ s:base01, s:base1 ] = [ s:base1, s:base01 ] + let [ s:base00, s:base0 ] = [ s:base0, s:base00 ] +endif + +let s:p = {'normal': {}, 'inactive': {}, 'insert': {}, 'replace': {}, 'visual': {}, 'tabline': {}} +let s:p.normal.left = [ [ s:base03, s:blue ], [ s:base03, s:base00 ] ] +let s:p.normal.right = [ [ s:base03, s:base1 ], [ s:base03, s:base00 ] ] +let s:p.inactive.right = [ [ s:base03, s:base00 ], [ s:base0, s:base02 ] ] +let s:p.inactive.left = [ [ s:base0, s:base02 ], [ s:base0, s:base02 ] ] +let s:p.insert.left = [ [ s:base03, s:green ], [ s:base03, s:base00 ] ] +let s:p.replace.left = [ [ s:base03, s:red ], [ s:base03, s:base00 ] ] +let s:p.visual.left = [ [ s:base03, s:magenta ], [ s:base03, s:base00 ] ] +let s:p.normal.middle = [ [ s:base1, s:base02 ] ] +let s:p.inactive.middle = [ [ s:base01, s:base02 ] ] +let s:p.tabline.left = [ [ s:base03, s:base00 ] ] +let s:p.tabline.tabsel = [ [ s:base03, s:base1 ] ] +let s:p.tabline.middle = [ [ s:base0, s:base02 ] ] +let s:p.tabline.right = copy(s:p.normal.right) +let s:p.normal.error = [ [ s:base03, s:red ] ] +let s:p.normal.warning = [ [ s:base03, s:yellow ] ] + +let g:lightline#colorscheme#solarized#palette = lightline#colorscheme#flatten(s:p) diff --git a/start/lightline/autoload/lightline/colorscheme/srcery_drk.vim b/start/lightline/autoload/lightline/colorscheme/srcery_drk.vim new file mode 100644 index 0000000..f1c7e1d --- /dev/null +++ b/start/lightline/autoload/lightline/colorscheme/srcery_drk.vim @@ -0,0 +1,44 @@ +" ============================================================================= +" Filename: autoload/lightline/colorscheme/srcery_drk.vim +" Author: Christopher Vittal +" License: MIT License +" Last Change: 2018/05/19 +" ============================================================================= +let s:base03 = [ '#151513', 233 ] +let s:base02 = [ '#30302c ', 236 ] +let s:base01 = [ '#4e4e43', 239 ] +let s:base00 = [ '#666656', 242 ] +let s:base0 = [ '#808070', 244 ] +let s:base1 = [ '#949484', 246 ] +let s:base2 = [ '#a8a897', 248 ] +let s:base3 = [ '#e8e8d3', 253 ] +let s:yellow = [ '#fbb829', 3 ] +let s:orange = [ '#d75f00', 166 ] +let s:red = [ '#ff3128', 1 ] +let s:magenta = [ '#e02c6d', 5 ] +let s:bright_magenta = [ '#e35682', 13 ] +let s:blue = [ '#5573a3', 4 ] +let s:bright_blue = [ '#8eb2f7', 12 ] +let s:cyan = [ '#0aaeb3', 6 ] +let s:green = [ '#519f50', 2 ] +let s:bright_green = [ '#98bc37', 10 ] +let s:white = [ '#fce8c3', 15 ] + +let s:p = {'normal': {}, 'inactive': {}, 'insert': {}, 'replace': {}, 'visual': {}, 'tabline': {}} +let s:p.normal.left = [ [ s:base02, s:bright_blue, 'bold' ], [ s:base3, s:base01 ] ] +let s:p.normal.right = [ [ s:base02, s:base1 ], [ s:base2, s:base01 ] ] +let s:p.inactive.right = [ [ s:base02, s:base00 ], [ s:base0, s:base02 ] ] +let s:p.inactive.left = [ [ s:base0, s:base02 ], [ s:base00, s:base02 ] ] +let s:p.insert.left = [ [ s:base02, s:bright_green, 'bold' ], [ s:base3, s:base01 ] ] +let s:p.replace.left = [ [ s:base3, s:red, 'bold' ], [ s:base3, s:base01 ] ] +let s:p.visual.left = [ [ s:base3, s:bright_magenta, 'bold' ], [ s:base3, s:base01 ] ] +let s:p.normal.middle = [ [ s:base0, s:base02 ] ] +let s:p.inactive.middle = [ [ s:base00, s:base02 ] ] +let s:p.tabline.left = [ [ s:base3, s:base00, 'bold'] ] +let s:p.tabline.tabsel = [ [ s:base3, s:base02 ] ] +let s:p.tabline.middle = [ [ s:base01, s:base1 ] ] +let s:p.tabline.right = copy(s:p.normal.right) +let s:p.normal.error = [ [ s:red, s:base02 ] ] +let s:p.normal.warning = [ [ s:yellow, s:base01 ] ] + +let g:lightline#colorscheme#srcery_drk#palette = lightline#colorscheme#flatten(s:p) diff --git a/start/lightline/autoload/lightline/colorscheme/wombat.vim b/start/lightline/autoload/lightline/colorscheme/wombat.vim new file mode 100644 index 0000000..9619247 --- /dev/null +++ b/start/lightline/autoload/lightline/colorscheme/wombat.vim @@ -0,0 +1,40 @@ +" ============================================================================= +" Filename: autoload/lightline/colorscheme/wombat.vim +" Author: itchyny +" License: MIT License +" Last Change: 2015/11/30 08:37:43. +" ============================================================================= +let s:base03 = [ '#242424', 235 ] +let s:base023 = [ '#353535 ', 236 ] +let s:base02 = [ '#444444 ', 238 ] +let s:base01 = [ '#585858', 240 ] +let s:base00 = [ '#666666', 242 ] +let s:base0 = [ '#808080', 244 ] +let s:base1 = [ '#969696', 247 ] +let s:base2 = [ '#a8a8a8', 248 ] +let s:base3 = [ '#d0d0d0', 252 ] +let s:yellow = [ '#cae682', 180 ] +let s:orange = [ '#e5786d', 173 ] +let s:red = [ '#e5786d', 203 ] +let s:magenta = [ '#f2c68a', 216 ] +let s:blue = [ '#8ac6f2', 117 ] +let s:cyan = s:blue +let s:green = [ '#95e454', 119 ] +let s:p = {'normal': {}, 'inactive': {}, 'insert': {}, 'replace': {}, 'visual': {}, 'tabline': {}} +let s:p.normal.left = [ [ s:base02, s:blue ], [ s:base3, s:base01 ] ] +let s:p.normal.right = [ [ s:base02, s:base0 ], [ s:base1, s:base01 ] ] +let s:p.inactive.right = [ [ s:base023, s:base01 ], [ s:base00, s:base02 ] ] +let s:p.inactive.left = [ [ s:base1, s:base02 ], [ s:base00, s:base023 ] ] +let s:p.insert.left = [ [ s:base02, s:green ], [ s:base3, s:base01 ] ] +let s:p.replace.left = [ [ s:base023, s:red ], [ s:base3, s:base01 ] ] +let s:p.visual.left = [ [ s:base02, s:magenta ], [ s:base3, s:base01 ] ] +let s:p.normal.middle = [ [ s:base2, s:base02 ] ] +let s:p.inactive.middle = [ [ s:base1, s:base023 ] ] +let s:p.tabline.left = [ [ s:base3, s:base00 ] ] +let s:p.tabline.tabsel = [ [ s:base3, s:base03 ] ] +let s:p.tabline.middle = [ [ s:base2, s:base02 ] ] +let s:p.tabline.right = [ [ s:base2, s:base00 ] ] +let s:p.normal.error = [ [ s:base03, s:red ] ] +let s:p.normal.warning = [ [ s:base023, s:yellow ] ] + +let g:lightline#colorscheme#wombat#palette = lightline#colorscheme#flatten(s:p) diff --git a/start/lightline/autoload/lightline/colortable.vim b/start/lightline/autoload/lightline/colortable.vim new file mode 100644 index 0000000..82617b2 --- /dev/null +++ b/start/lightline/autoload/lightline/colortable.vim @@ -0,0 +1,42 @@ +" ============================================================================= +" Filename: autoload/lightline/colortable.vim +" Author: itchyny +" License: MIT License +" Last Change: 2015/03/29 06:21:39. +" ============================================================================= + +let s:save_cpo = &cpo +set cpo&vim + +function! s:load() abort + let rgbfile = $VIMRUNTIME . '/rgb.txt' + let table = {} + if filereadable(rgbfile) + for _ in map(filter(readfile(rgbfile), 'v:val !~# "^!"'), 'matchlist(v:val, "^\\s*\\(\\d\\+\\)\\s\\+\\(\\d\\+\\)\\s\\+\\(\\d\\+\\)\\s\\+\\(.*\\)")[1:4]') + let table[tolower(_[3])] = _[0:2] + endfor + endif + return table +endfunction + +let s:table = s:load() + +function! lightline#colortable#name_to_rgb(name) abort + let name = tolower(a:name) + return has_key(s:table, name) ? s:table[name] : [] +endfunction + +function! lightline#colortable#gui2cui(rgb, fallback) abort + let rgb = map(matchlist(a:rgb, '#\(..\)\(..\)\(..\)')[1:3], '0 + ("0x".v:val)') + if len(rgb) == 0 + let rgb = lightline#colortable#name_to_rgb(a:rgb) + if len(rgb) == 0 + return a:fallback % 128 + endif + endif + let rgb = [rgb[0] > 127 ? 4 : 0, rgb[1] > 127 ? 2 : 0, rgb[2] > 127 ? 1 : 0] + return rgb[0] + rgb[1] + rgb[2] +endfunction + +let &cpo = s:save_cpo +unlet s:save_cpo diff --git a/start/lightline/autoload/lightline/tab.vim b/start/lightline/autoload/lightline/tab.vim new file mode 100644 index 0000000..f2accc1 --- /dev/null +++ b/start/lightline/autoload/lightline/tab.vim @@ -0,0 +1,33 @@ +" ============================================================================= +" Filename: autoload/lightline/tab.vim +" Author: itchyny +" License: MIT License +" Last Change: 2016/05/07 22:31:02. +" ============================================================================= + +let s:save_cpo = &cpo +set cpo&vim + +function! lightline#tab#filename(n) abort + let buflist = tabpagebuflist(a:n) + let winnr = tabpagewinnr(a:n) + let _ = expand('#'.buflist[winnr - 1].':t') + return _ !=# '' ? _ : '[No Name]' +endfunction + +function! lightline#tab#modified(n) abort + let winnr = tabpagewinnr(a:n) + return gettabwinvar(a:n, winnr, '&modified') ? '+' : gettabwinvar(a:n, winnr, '&modifiable') ? '' : '-' +endfunction + +function! lightline#tab#readonly(n) abort + let winnr = tabpagewinnr(a:n) + return gettabwinvar(a:n, winnr, '&readonly') ? 'RO' : '' +endfunction + +function! lightline#tab#tabnum(n) abort + return a:n +endfunction + +let &cpo = s:save_cpo +unlet s:save_cpo diff --git a/start/lightline/doc/lightline.txt b/start/lightline/doc/lightline.txt new file mode 100644 index 0000000..7c2a886 --- /dev/null +++ b/start/lightline/doc/lightline.txt @@ -0,0 +1,1325 @@ +*lightline.txt* A light and configurable statusline/tabline for Vim + +Version: 0.1 +Author: itchyny (https://github.com/itchyny) +License: MIT License +Repository: https://github.com/itchyny/lightline.vim +Last Change: 2018/04/28 00:08:18. + +CONTENTS *lightline-contents* + +Introduction |lightline-introduction| +Spirit |lightline-spirit| +Option |lightline-option| +Font |lightline-font| +Function |lightline-function| +Component Expansion |lightline-component-expansion| +Colorscheme |lightline-colorscheme| +Examples |lightline-examples| +Nice Examples |lightline-nice-examples| +Powerful Example |lightline-powerful-example| +Troubleshooting |lightline-troubleshooting| + +============================================================================== +INTRODUCTION *lightline-introduction* + +The *lightline* plugin is a light and configurable statusline/tabline for Vim. + +------------------------------------------------------------------------------ +SPIRIT *lightline-spirit* + + Minimalism + The core script is very small to achieve enough functions as a + statusline plugin. + + Configurability + You can create your own component and easily add to the statusline + and the tabline. + + Orthogonality + The plugin does not rely on the implementation of other plugins. + Such plugin crossing settings should be configured by users. + + You find this plugin does not integrate with other plugins by default. + This plugin does not provide branch information, which is a basic + component in existing statusline plugins. It is a design of + lightline.vim that such plugin crossing configuration should be + written by users. Once a plugin starts to integrate with some famous + plugins, it should be kept updated to follow the changes of the + plugins and should accept integration requests with new plugins. + Instead, lightline.vim is designed very carefully so that users can + easily integrate with other plugins. Good APIs keep a plugin clean. + +------------------------------------------------------------------------------ +OPTIONS *lightline-option* + + g:lightline *g:lightline* + All the configurations are stored in this global variable. + + g:lightline.active *g:lightline.active* + g:lightline.inactive *g:lightline.inactive* + g:lightline.tabline *g:lightline.tabline* + Dictionaries to store the statusline/tabline components. + Note that right groups of components are stored from right to + left. + The default values are: +> + let g:lightline.active = { + \ 'left': [ [ 'mode', 'paste' ], + \ [ 'readonly', 'filename', 'modified' ] ], + \ 'right': [ [ 'lineinfo' ], + \ [ 'percent' ], + \ [ 'fileformat', 'fileencoding', 'filetype' ] ] } + let g:lightline.inactive = { + \ 'left': [ [ 'filename' ] ], + \ 'right': [ [ 'lineinfo' ], + \ [ 'percent' ] ] } + let g:lightline.tabline = { + \ 'left': [ [ 'tabs' ] ], + \ 'right': [ [ 'close' ] ] } +< + g:lightline.tab *g:lightline.tab* + A dictionary to store the tab components in each tabs. + The default values are: +> + let g:lightline.tab = { + \ 'active': [ 'tabnum', 'filename', 'modified' ], + \ 'inactive': [ 'tabnum', 'filename', 'modified' ] } +< + g:lightline.component *g:lightline.component* + A dictionary for statusline/tabline components. + The default value is: +> + let g:lightline.component = { + \ 'mode': '%{lightline#mode()}', + \ 'absolutepath': '%F', + \ 'relativepath': '%f', + \ 'filename': '%t', + \ 'modified': '%M', + \ 'bufnum': '%n', + \ 'paste': '%{&paste?"PASTE":""}', + \ 'readonly': '%R', + \ 'charvalue': '%b', + \ 'charvaluehex': '%B', + \ 'fileencoding': '%{&fenc!=#""?&fenc:&enc}', + \ 'fileformat': '%{&ff}', + \ 'filetype': '%{&ft!=#""?&ft:"no ft"}', + \ 'percent': '%3p%%', + \ 'percentwin': '%P', + \ 'spell': '%{&spell?&spelllang:""}', + \ 'lineinfo': '%3l:%-2v', + \ 'line': '%l', + \ 'column': '%c', + \ 'close': '%999X X ', + \ 'winnr': '%{winnr()}' } +< + g:lightline.component_visible_condition + *g:lightline.component_visible_condition* + A dictionary to store the visible condition of the components. + Note that this configuration is used to control the visibility + of the subseparators, not to control the visibility of the + components themselves. Each expression should correspond to + the condition on which each component is not empty. + The default value is: +> + let g:lightline.component_visible_condition = { + \ 'modified': '&modified||!&modifiable', + \ 'readonly': '&readonly', + \ 'paste': '&paste', + \ 'spell': '&spell' } +< + g:lightline.component_function *g:lightline.component_function* + A dictionary to store the function components. + This is useful to write a complex component configuration and + to integrate with other plugins. If a component set in both + component and component_function, the configuration of + component_function has priority. + + The default value is: +> + let g:lightline.component_function = {} +< + For example, if you want to display the name of the git branch, + install |vim-fugitive| plugin and then configure as: +> + let g:lightline = { + \ 'active': { + \ 'left': [ [ 'mode', 'paste' ], + \ [ 'gitbranch', 'readonly', 'filename', 'modified' ] ] + \ }, + \ 'component_function': { + \ 'gitbranch': 'fugitive#head' + \ }, + \ } +< + g:lightline.component_function_visible_condition + *g:lightline.component_function_visible_condition* + A dictionary to store the visible conditions of the function + components. Each expression should correspond to the condition + each component is not empty. This configuration is used to + control the visibility of the sub-separators. You can use this + configuration to reduce the number of function calls for + performance improvement by setting the value 1 (to tell lightline + that the component is always visible). + The default value is: +> + let g:lightline.component_function_visible_condition = {} +< + g:lightline.component_expand *g:lightline.component_expand* + A dictionary to store expanding components. You can create + warning and critical components. The values should be the name + of functions should return either one of: + + a string + + an array of three elements: + [[ left ], [ middle ], [ right ]] + The component in this dictionary has priority over + |g:lightline.component| and |g:lightline.component_function|. + Note that the return string is appended to the statusline + string without any conversion. So you should replace all the + % signs with %%. Otherwise, lightline will be disabled in case + the text has a % sign. + (example: return substitute(text, '%', '%%', 'g')). + See |lightline-component-expansion| for more detail. +> + let g:lightline.component_expand = { + \ 'tabs': 'lightline#tabs' } +< + g:lightline.component_type *g:lightline.component_type* + A dictionary to specify the types for components in + |g:lightline.component_expand|. The types are used to specify + the color. Specifically, the type raw is used to specify a + component which should not be wrapped by item group: %(...%). + If you want to specify the type of a raw component, please use + |g:lightline.component_raw|. + The default value is: > + + let g:lightline.component_type = { + \ 'tabs': 'tabsel', + \ 'close': 'raw' } +< + g:lightline.component_raw *g:lightline.component_raw* + A dictionary to specify the raw type components. When you + register a component to this dictionary (like > + let g:lightline.component_raw = { 'example': 1 } +< ), the example component is not wrapped by item group: %(...%). + The default value is: > + + let g:lightline.component_raw = {} +< + g:lightline.tab_component *g:lightline.tab_component* + A dictionary for components in one tab. + The default value is: > + + let g:lightline.tab_component = {} +< + g:lightline.tab_component_function *g:lightline.tab_component_function* + Another dictionary for components in one tab. + A function specified as a tab component takes one argument: + the tab [count]. + The default value is: +> + let g:lightline.tab_component_function = { + \ 'filename': 'lightline#tab#filename', + \ 'modified': 'lightline#tab#modified', + \ 'readonly': 'lightline#tab#readonly', + \ 'tabnum': 'lightline#tab#tabnum' } +< + g:lightline.colorscheme *g:lightline.colorscheme* + The colorscheme for lightline.vim. + Currently, wombat, solarized, powerline, jellybeans, Tomorrow, + Tomorrow_Night, Tomorrow_Night_Blue, Tomorrow_Night_Eighties, + PaperColor, seoul256, landscape, one, darcula, molokai, materia, + material, OldHope, nord, 16color and deus are available. + The default value is: +> + let g:lightline.colorscheme = 'default' +< + Note that the default colorscheme is exactly the same as the + powerline theme. + + g:lightline.mode_map *g:lightline.mode_map* + A dictionary of names for the modes. The keys are the return + values of |mode()|. + The default value is: +> + let g:lightline.mode_map = { + \ 'n' : 'NORMAL', + \ 'i' : 'INSERT', + \ 'R' : 'REPLACE', + \ 'v' : 'VISUAL', + \ 'V' : 'V-LINE', + \ "\": 'V-BLOCK', + \ 'c' : 'COMMAND', + \ 's' : 'SELECT', + \ 'S' : 'S-LINE', + \ "\": 'S-BLOCK', + \ 't': 'TERMINAL', + \ } +< + When you search a word, you get into the command mode. But if + you want to keep the mode indicator as 'NORMAL', add > + let g:lightline = { 'mode_map': { 'c': 'NORMAL' } } +< to your .vimrc. + + g:lightline.separator *g:lightline.separator* + g:lightline.subseparator *g:lightline.subseparator* + Dictionaries to store separators. + The default value is +> + let g:lightline.separator = { 'left': '', 'right': '' } + let g:lightline.subseparator = { 'left': '|', 'right': '|' } +< + g:lightline.tabline_separator *g:lightline.tabline_separator* + g:lightline.tabline_subseparator *g:lightline.tabline_subseparator* + Dictionaries to store separators for the tabline. + The default value is +> + let g:lightline.tabline_separator = g:lightline.separator + let g:lightline.tabline_subseparator = g:lightline.subseparator +< + g:lightline.enable *g:lightline.enable* + A dictionary to specify which feature is turned on. + The default value is +> + let g:lightline.enable = { + \ 'statusline': 1, + \ 'tabline': 1 + \ } +< +============================================================================== +FONT *lightline-font* +You can use the patched font you used for |vim-powerline| and |powerline|. + +The patched fonts for |powerline| are available at +https://github.com/Lokaltog/powerline-fonts + +A tutorial to create a patched font for |vim-powerline| is available at +https://github.com/Lokaltog/vim-powerline/tree/develop/fontpatcher + +If you have installed the patched font for |powerline|, following settings look +nice. +> + let g:lightline = { + \ 'component': { + \ 'lineinfo': ' %3l:%-2v', + \ }, + \ 'component_function': { + \ 'readonly': 'LightlineReadonly', + \ 'fugitive': 'LightlineFugitive' + \ }, + \ 'separator': { 'left': '', 'right': '' }, + \ 'subseparator': { 'left': '', 'right': '' } + \ } + function! LightlineReadonly() + return &readonly ? '' : '' + endfunction + function! LightlineFugitive() + if exists('*fugitive#head') + let branch = fugitive#head() + return branch !=# '' ? ''.branch : '' + endif + return '' + endfunction +< +If you have installed the patched font for |vim-powerline|, following settings +look nice. +> + let g:lightline = { + \ 'component': { + \ 'lineinfo': '⭡ %3l:%-2v', + \ }, + \ 'component_function': { + \ 'readonly': 'LightlineReadonly', + \ 'fugitive': 'LightlineFugitive' + \ }, + \ 'separator': { 'left': '⮀', 'right': '⮂' }, + \ 'subseparator': { 'left': '⮁', 'right': '⮃' } + \ } + function! LightlineReadonly() + return &readonly ? '⭤' : '' + endfunction + function! LightlineFugitive() + if exists('*fugitive#head') + let branch = fugitive#head() + return branch !=# '' ? '⭠ '.branch : '' + endif + return '' + endfunction +< +If the statusline does not correctly show the special characters, use the +unicode numbers. For |powerline| font users: +> + \ 'separator': { 'left': "\ue0b0", 'right': "\ue0b2" }, + \ 'subseparator': { 'left': "\ue0b1", 'right': "\ue0b3" } +< +For |vim-powerline| font users: +> + \ 'separator': { 'left': "\u2b80", 'right': "\u2b82" }, + \ 'subseparator': { 'left': "\u2b81", 'right': "\u2b83" } +< +See |lightline-problem-9| for more detail. +============================================================================== +FUNCTION *lightline-function* +Exposed functions for lightline.vim. + + lightline#mode() *lightline#mode()* + Returns the mode of the Vim using |g:lightline.mode_map|. + + lightline#init() *lightline#init()* + Initializes the internal state from |g:lightline|. + + lightline#colorscheme() *lightline#colorscheme()* + Initializes the colorscheme and the highlight groups. + + lightline#update() *lightline#update()* + Updates all the statuslines of existing windows. + + lightline#update_once() *lightline#update_once()* + Updates the statuslines only once. + + lightline#enable() *lightline#enable()* + Enables |lightline|. + + lightline#disable() *lightline#disable()* + Disables |lightline|. + + lightline#toggle() *lightline#toggle()* + Toggles |lightline|. + + lightline#link([mode]) *lightline#link()* + Creates links of the highlight groups for the active window. + This function accepts an optional argument. It should be one + of the return value of |mode()|. + + lightline#highlight() *lightline#highlight()* + Set the highlight groups. + + lightline#statusline({inactive}) *lightline#statusline()* + Returns |statusline| strings. If the argument is 0, it returns + the statusline for active window, and the statusline for + inactive window otherwise. + + lightline#tabline() *lightline#tabline()* + Returns the tabline string. + + lightline#concatenate({list}, {num}) *lightline#concatenate()* + A string concatenation function. Concatenating all the strings + in {list} using the sub-separator of lightline. If {num} is 0, + then the left sub-separator is used. Otherwise, the right + sub-separator is used. + + lightline#palette() *lightline#palette()* + Returns the palette data. + +============================================================================== +COMPONENT EXPANSION *lightline-component-expansion* +You can create components, which have specific colors. This section gives an +example using |syntastic|. + +If you want to add the |syntastic| flag to the statusline, an easy example is: +> + " Example A + let g:lightline = { + \ 'active': { + \ 'right': [ [ 'lineinfo', 'syntastic' ], + \ [ 'percent' ], + \ [ 'fileformat', 'fileencoding', 'filetype' ] ] + \ }, + \ 'component_function': { + \ 'syntastic': 'SyntasticStatuslineFlag', + \ } + \ } + let g:syntastic_mode_map = { 'mode': 'passive', + \ 'active_filetypes': ['c', 'cpp'] } +< +However, the color of the syntastic component is the same as the lineinfo +component. + +In order to change the syntastic component more outstanding, you have to use +|g:lightline.component_expand|. See the following example: +> + " Example B + let g:lightline = { + \ 'active': { + \ 'right': [ [ 'syntastic', 'lineinfo' ], + \ [ 'percent' ], + \ [ 'fileformat', 'fileencoding', 'filetype' ] ] + \ }, + \ 'component_expand': { + \ 'syntastic': 'SyntasticStatuslineFlag', + \ }, + \ 'component_type': { + \ 'syntastic': 'error', + \ } + \ } + " Syntastic can call a post-check hook, let's update lightline there + " For more information: :help syntastic-loclist-callback + function! SyntasticCheckHook(errors) + call lightline#update() + endfunction +< +In order to understand the above codes, you firstly should know how the +colorschemes work in lightline.vim. Open the following file. + autoload/lightline/colorscheme/powerline.vim +The colorscheme is created by one dictionary: s:p (abbreviation for palette). +See the value of s:p.normal.right. +> + let s:p.normal.right = [ ['gray5', 'gray10'], + \ ['gray9', 'gray4'], + \ ['gray8', 'gray2'] ] +< +This array corresponds to the structure of g:lightline.active.right. Recall +the example A. +> + " Example A + let g:lightline.active.right = [ [ 'lineinfo', 'syntastic' ], + \ [ 'percent' ], + \ [ 'fileformat', 'fileencoding', 'filetype' ] ] +< +The colors are ([fgcolor, bgcolor): +> + (0) [ 'lineinfo', 'syntastic' ] --- s:p.normal.right[0] = ['gray5', 'gray10'] + (1) [ 'percent' ] --- s:p.normal.right[1] = ['gray9', 'gray4'] + (2) [ 'fileformat', 'fileencoding', 'filetype' ] --- s:p.normal.right[2] = ['gray8', 'gray2'] +< +Recall the example B. +> + " Example B + let g:lightline.active.right = [ [ 'syntastic', 'lineinfo' ], + \ [ 'percent' ], + \ [ 'fileformat', 'fileencoding', 'filetype' ] ] +< +If a component is specified in |g:lightline.component_expand|, lightline.vim +expands the components before setting to statusline/tabline. In this example, +the syntastic component is expanded using the |SyntasticStatuslineFlag| function. +This function returns a {string}. Let us call it `syntastic_flag`. +> + let syntastic_flag = SyntasticStatuslineFlag() +< +The syntastic component is now expanded, so it go up to one component group. +The type of the syntastic component is error, and the palette has error +colors, the result is: +> + " Expanded result of Example B + (error) [ syntastic_flag ] --- s:p.normal.error[0] = ['gray9', 'brightestred'] + (0) [ 'lineinfo' ] --- s:p.normal.right[0] = ['gray5', 'gray10'] + (1) [ 'percent' ] --- s:p.normal.right[1] = ['gray9', 'gray4'] + (2) [ 'fileformat', 'fileencoding', 'filetype' ] --- s:p.normal.right[2] = ['gray8', 'gray2'] +< +Thus the syntastic component has the red color. + + +Another example for |g:lightline.component_expand| is the tabs component. +Actually, the expand feature is created for the tabs component. +> + let g:lightline.tabline.left = [ [ 'tabs' ] ] + let g:lightline.component_expand = { + \ 'tabs': 'lightline#tabs' } +< +Create three tabs and select the middle tab. Then execute +> + echo lightline#tabs() + " [['%1T%{lightline#onetab(1,0)}'], + " ['%2T%{lightline#onetab(2,1)}'], + " ['%3T%{lightline#onetab(3,0)}%T']] +< +It returns an array of three elements. The expanded result is: +> + " Expanded result of tabline + (0) ['%1T%{lightline#onetab(1,0)}'] --- s:p.tabline.left[0] = ['gray9', 'gray4'] + (tabsel) ['%2T%{lightline#onetab(2,1)}'] --- s:p.tabline.tabsel[0] = ['gray9', 'gray1'] + (0) ['%3T%{lightline#onetab(3,0)}%T'] --- s:p.tabline.left[0] = ['gray9', 'gray4'] +< +If the tabline components are +> + let g:lightline.tabline.left = [ [ 'A', 'B', 'tabs', 'C', 'D' ] ] +< +then the expanded result is: +> + (0) ['A', 'B', '%1T%{lightline#onetab(1,0)}'] --- s:p.tabline.left[0] + (tabsel) ['%2T%{lightline#onetab(2,1)}'] --- s:p.tabline.tabsel[0] + (0) ['%3T%{lightline#onetab(3,0)}%T', 'C', 'D'] --- s:p.tabline.left[0] +< +In summary, when a function in |g:lightline.component_expand| returns an +array of three elements, the first element and the last element remains as a +part of existing component group. And the middle element goes up to new +component group. +------------------------------------------------------------------------------ +COLORSCHEME *lightline-colorscheme* +You can configure the colorscheme of lightline. For example, +> + let g:lightline = { + \ 'colorscheme': 'wombat', + \ } +< +The colorscheme files are found in the directory + + lightline.vim/autoload/lightline/colorscheme/ + +In each file, one global variable is defined. For example, in the landscape.vim +file, you see +> + let g:lightline#colorscheme#landscape#palette = s:p +< +In the file, the colors for the landscape colorscheme are defined. For example, +> + let s:p.normal.left = [ ['#0000ff', '#ffffff', 21, 231, 'bold' ], [ '#ffffff', '#0000ff', 231, 21 ] ] +< +defines the colors for the components on the left hand side, in normal mode. +> + let s:p.tabline.tabsel = [ [ '#dadada', '#121212', 253, 233 ] ] +< +defines the colors for the selected tab in tabline. In general, each palette +follows the following style: +> + let s:p.{mode}.{where} = [ [ {guifg}, {guibg}, {ctermfg}, {ctermbg} ], ... ] +< + + +Now, you can create your own colorscheme for lightline. Create a +yourcolorscheme.vim at + + {one of the paths in &rtp}/autoload/lightline/colorscheme/yourcolorscheme.vim + +The following code gives the minimal palette definition for lightline. +> + let s:p = {'normal': {}} + let s:p.normal.left = [ [ ... ] ] + let s:p.normal.right = [ [ ... ] ] + let s:p.normal.middle = [ [ ... ] ] + let g:lightline#colorscheme#yourcolorscheme#palette = s:p +< +And if you add the colorscheme configuration to your .vimrc(_vimrc), +> + let g:lightline = { + \ 'colorscheme': 'yourcolorscheme', + \ } +< +you find it possible to change the lightline colors as you wish. + +Moreover, if you want to change the colors based on the mode of vim, write +something like this: +> + let s:p.insert.left = [ [ ... ] ] + let s:p.insert.right = [ [ ... ] ] + let s:p.replace.left = [ [ ... ] ] + let s:p.replace.right = [ [ ... ] ] + ... + ... +< +For expanded components, you are recommended to define the following two +colors. +> + let s:p.normal.error = [ [ ... ] ] + let s:p.normal.warning = [ [ ... ] ] +< +For the complete list of components the color of which you should define in +your colorscheme, see the colorscheme files in lightline. + +It is sometimes painful to write all the colors for both gui and cterm. +Actually, lightline has some useful functions for writing colorschemes. For +example, see + lightline.vim/autoload/lightline/colorscheme/Tomorrow_Night.vim +this colorscheme is defined using only gui color numbers. And convert to the +normal colorscheme form using: +> + let g:lightline#colorscheme#Tomorrow_Night#palette = lightline#colorscheme#fill(s:p) +< +This function fills the cterm colors for a palette which has only gui colors, or +vice versa. However, note that using the convenient function sources an +additional Vim script file (autoload/lightline/colorscheme.vim), which causes +a little slow down. If you want to avoid this situation, write all the colors +as done in autoload/lightline/colorscheme/landscape.vim; firstly create the +colorscheme using the fill function, and see the result, in a sense, the +compiled version of your colorscheme. +> + echo g:lightline#colorscheme#yourcolorscheme#palette +< +Then copy and paste the result to the colorscheme file. + +If you want to contribute a new colorscheme that is not currently available +please follow the following rules: + *) All hex codes should be lowercase only + *) Use 2 space soft tabs + *) If your colorscheme has both light and dark variants, use a single file + *) Normal Mode should default to Cyan + *) Insert Mode should default to Green + *) Visual Mode should default to Yellow + *) Replace Mode should default to Red + +============================================================================== +EXAMPLES *lightline-examples* +You can configure the appearance of statusline. +Write the following examples in you .vimrc(_vimrc). + +In order to change the colorscheme: +> + let g:lightline = { + \ 'colorscheme': 'wombat', + \ } +< + +In order to define your own component: +> + let g:lightline = { + \ 'active': { + \ 'left': [ [ 'mode', 'paste' ], [ 'myfilename' ] ] + \ }, + \ 'component_function': { + \ 'myfilename': 'LightlineFilename', + \ 'myreadonly': 'LightlineReadonly', + \ 'mymodified': 'LightlineModified', + \ } + \ } + function! LightlineFilename() + return ('' != LightlineReadonly() ? LightlineReadonly() . ' ' : '') . + \ (&ft == 'vimfiler' ? vimfiler#get_status_string() : + \ &ft == 'unite' ? unite#get_status_string() : + \ '' != expand('%:t') ? expand('%:t') : '[No Name]') . + \ ('' != LightlineModified() ? ' ' . LightlineModified() : '') + endfunction + function! LightlineReadonly() + return &ft !~? 'help' && &readonly ? 'RO' : '' + endfunction + function! LightlineModified() + return &modifiable && &modified ? '+' : '' + endfunction +< + +Separators settings: +> + let g:lightline = { + \ 'separator': { 'left': '', 'right': '' }, + \ 'subseparator': { 'left': '|', 'right': '|' } + \ } +< + +For |powerline| font users: +> + let g:lightline = { + \ 'separator': { 'left': '', 'right': '' }, + \ 'subseparator': { 'left': '', 'right': '' } + \ } +< + +For |vim-powerline| font users: +> + let g:lightline = { + \ 'separator': { 'left': '⮀', 'right': '⮂' }, + \ 'subseparator': { 'left': '⮁', 'right': '⮃' } + \ } +< + +------------------------------------------------------------------------------ +NICE EXAMPLES *lightline-nice-examples* + +A nice example for non-patched font users. +> + let g:lightline = { + \ 'colorscheme': 'wombat', + \ 'active': { + \ 'left': [ [ 'mode', 'paste' ], [ 'fugitive', 'filename' ] ] + \ }, + \ 'component_function': { + \ 'fugitive': 'LightlineFugitive', + \ 'filename': 'LightlineFilename' + \ } + \ } + function! LightlineModified() + return &ft =~ 'help\|vimfiler' ? '' : &modified ? '+' : &modifiable ? '' : '-' + endfunction + function! LightlineReadonly() + return &ft !~? 'help\|vimfiler' && &readonly ? 'RO' : '' + endfunction + function! LightlineFilename() + return ('' != LightlineReadonly() ? LightlineReadonly() . ' ' : '') . + \ (&ft == 'vimfiler' ? vimfiler#get_status_string() : + \ &ft == 'unite' ? unite#get_status_string() : + \ &ft == 'vimshell' ? vimshell#get_status_string() : + \ '' != expand('%:t') ? expand('%:t') : '[No Name]') . + \ ('' != LightlineModified() ? ' ' . LightlineModified() : '') + endfunction + function! LightlineFugitive() + if &ft !~? 'vimfiler' && exists('*fugitive#head') + return fugitive#head() + endif + return '' + endfunction +< +A nice example for |vim-powerline| font users: +> + let g:lightline = { + \ 'colorscheme': 'wombat', + \ 'active': { + \ 'left': [ [ 'mode', 'paste' ], [ 'fugitive', 'filename' ] ] + \ }, + \ 'component_function': { + \ 'fugitive': 'LightlineFugitive', + \ 'filename': 'LightlineFilename' + \ }, + \ 'separator': { 'left': '⮀', 'right': '⮂' }, + \ 'subseparator': { 'left': '⮁', 'right': '⮃' } + \ } + function! LightlineModified() + return &ft =~ 'help\|vimfiler' ? '' : &modified ? '+' : &modifiable ? '' : '-' + endfunction + function! LightlineReadonly() + return &ft !~? 'help\|vimfiler' && &readonly ? '⭤' : '' + endfunction + function! LightlineFilename() + return ('' != LightlineReadonly() ? LightlineReadonly() . ' ' : '') . + \ (&ft == 'vimfiler' ? vimfiler#get_status_string() : + \ &ft == 'unite' ? unite#get_status_string() : + \ &ft == 'vimshell' ? vimshell#get_status_string() : + \ '' != expand('%:t') ? expand('%:t') : '[No Name]') . + \ ('' != LightlineModified() ? ' ' . LightlineModified() : '') + endfunction + function! LightlineFugitive() + if &ft !~? 'vimfiler' && exists('*fugitive#head') + let branch = fugitive#head() + return branch !=# '' ? '⭠ '.branch : '' + endif + return '' + endfunction +< + +------------------------------------------------------------------------------ +POWERFUL EXAMPLE *lightline-powerful-example* + +For users who uses lots of plugins: +> + let g:lightline = { + \ 'colorscheme': 'wombat', + \ 'active': { + \ 'left': [ [ 'mode', 'paste' ], [ 'fugitive', 'filename' ], ['ctrlpmark'] ], + \ 'right': [ [ 'syntastic', 'lineinfo' ], ['percent'], [ 'fileformat', 'fileencoding', 'filetype' ] ] + \ }, + \ 'component_function': { + \ 'fugitive': 'LightlineFugitive', + \ 'filename': 'LightlineFilename', + \ 'fileformat': 'LightlineFileformat', + \ 'filetype': 'LightlineFiletype', + \ 'fileencoding': 'LightlineFileencoding', + \ 'mode': 'LightlineMode', + \ 'ctrlpmark': 'CtrlPMark', + \ }, + \ 'component_expand': { + \ 'syntastic': 'SyntasticStatuslineFlag', + \ }, + \ 'component_type': { + \ 'syntastic': 'error', + \ }, + \ 'subseparator': { 'left': '|', 'right': '|' } + \ } + + function! LightlineModified() + return &ft =~ 'help' ? '' : &modified ? '+' : &modifiable ? '' : '-' + endfunction + + function! LightlineReadonly() + return &ft !~? 'help' && &readonly ? 'RO' : '' + endfunction + + function! LightlineFilename() + let fname = expand('%:t') + return fname == 'ControlP' && has_key(g:lightline, 'ctrlp_item') ? g:lightline.ctrlp_item : + \ fname == '__Tagbar__' ? g:lightline.fname : + \ fname =~ '__Gundo\|NERD_tree' ? '' : + \ &ft == 'vimfiler' ? vimfiler#get_status_string() : + \ &ft == 'unite' ? unite#get_status_string() : + \ &ft == 'vimshell' ? vimshell#get_status_string() : + \ ('' != LightlineReadonly() ? LightlineReadonly() . ' ' : '') . + \ ('' != fname ? fname : '[No Name]') . + \ ('' != LightlineModified() ? ' ' . LightlineModified() : '') + endfunction + + function! LightlineFugitive() + try + if expand('%:t') !~? 'Tagbar\|Gundo\|NERD' && &ft !~? 'vimfiler' && exists('*fugitive#head') + let mark = '' " edit here for cool mark + let branch = fugitive#head() + return branch !=# '' ? mark.branch : '' + endif + catch + endtry + return '' + endfunction + + function! LightlineFileformat() + return winwidth(0) > 70 ? &fileformat : '' + endfunction + + function! LightlineFiletype() + return winwidth(0) > 70 ? (&filetype !=# '' ? &filetype : 'no ft') : '' + endfunction + + function! LightlineFileencoding() + return winwidth(0) > 70 ? (&fenc !=# '' ? &fenc : &enc) : '' + endfunction + + function! LightlineMode() + let fname = expand('%:t') + return fname == '__Tagbar__' ? 'Tagbar' : + \ fname == 'ControlP' ? 'CtrlP' : + \ fname == '__Gundo__' ? 'Gundo' : + \ fname == '__Gundo_Preview__' ? 'Gundo Preview' : + \ fname =~ 'NERD_tree' ? 'NERDTree' : + \ &ft == 'unite' ? 'Unite' : + \ &ft == 'vimfiler' ? 'VimFiler' : + \ &ft == 'vimshell' ? 'VimShell' : + \ winwidth(0) > 60 ? lightline#mode() : '' + endfunction + + function! CtrlPMark() + if expand('%:t') =~ 'ControlP' && has_key(g:lightline, 'ctrlp_item') + call lightline#link('iR'[g:lightline.ctrlp_regex]) + return lightline#concatenate([g:lightline.ctrlp_prev, g:lightline.ctrlp_item + \ , g:lightline.ctrlp_next], 0) + else + return '' + endif + endfunction + + let g:ctrlp_status_func = { + \ 'main': 'CtrlPStatusFunc_1', + \ 'prog': 'CtrlPStatusFunc_2', + \ } + + function! CtrlPStatusFunc_1(focus, byfname, regex, prev, item, next, marked) + let g:lightline.ctrlp_regex = a:regex + let g:lightline.ctrlp_prev = a:prev + let g:lightline.ctrlp_item = a:item + let g:lightline.ctrlp_next = a:next + return lightline#statusline(0) + endfunction + + function! CtrlPStatusFunc_2(str) + return lightline#statusline(0) + endfunction + + let g:tagbar_status_func = 'TagbarStatusFunc' + + function! TagbarStatusFunc(current, sort, fname, ...) abort + let g:lightline.fname = a:fname + return lightline#statusline(0) + endfunction + + " Syntastic can call a post-check hook, let's update lightline there + " For more information: :help syntastic-loclist-callback + function! SyntasticCheckHook(errors) + call lightline#update() + endfunction + + let g:unite_force_overwrite_statusline = 0 + let g:vimfiler_force_overwrite_statusline = 0 + let g:vimshell_force_overwrite_statusline = 0 +< +------------------------------------------------------------------------------ +TROUBLESHOOTING *lightline-troubleshooting* + +Problem 1: |lightline-problem-1| + How to install this plugin. + +Problem 2: |lightline-problem-2| + How to update this plugin. + +Problem 3: |lightline-problem-3| + How to uninstall this plugin. + +Problem 4: |lightline-problem-4| + Cool statuslines appear only on |:vsp|. + +Problem 5: |lightline-problem-5| + The statusline does not seem to be correctly colored. + +Problem 6: |lightline-problem-6| + How to install a patched font. + +Problem 7: |lightline-problem-7| + Right triangles do not stick to the right components with the + patched font. + +Problem 8: |lightline-problem-8| + Triangles do not appear. Triangles look weird. + +Problem 9: |lightline-problem-9| + Where can I find the list of all the cool characters for patched fonts? + +Problem 10: |lightline-problem-10| + Cool statusline disappears in |unite|, |vimfiler| and |vimshell| + buffers. + +Problem 11: |lightline-problem-11| + Cool statusline disappears in |CtrlP|, |Tagbar| buffers. + +Problem 12: |lightline-problem-12| + How to make the plus sign red like |powerline|? + +Problem 13: |lightline-problem-13| + How to change the lightline colorscheme on the fly. + +Problem 14: |lightline-problem-14| + The 'E541' warning appears on the right hand side. + Many components disable the statusline of lightline. + +Problem 15: |lightline-problem-15| + Do not deal with the tabline. + Do not use the fancy separators in the tabline. + +Problem 16: |lightline-problem-16| + When changed the component to a function component to an expanding + component, the statusline of lightline is sometimes disabled. + +Problem 17: |lightline-problem-17| + Found a bug of this plugin. + Got many errors while using this plugin. + Vim hangs while using this plugin. + Want this plugin to be more configurable. + This troubleshooting is not helpful. + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +Problem 1: *lightline-problem-1* + How to install this plugin. + + If you are to install this plugin manually: + + 1. Put all the files under $VIM. + + If you are using |vim-pathogen|, install this plugin with the + following command. +> + git clone https://github.com/itchyny/lightline.vim \ + ~/.vim/bundle/lightline.vim +< + If you are to install this plugin using |Vundle|: + + 1. Add the following configuration to your + .vimrc(_vimrc). +> + Plugin 'itchyny/lightline.vim' +< + 2. Install with |:PluginInstall|. + + If you are to install this plugin using |NeoBundle|: + + 1. Add the following configuration to your + .vimrc(_vimrc). +> + NeoBundle 'itchyny/lightline.vim' +< + 2. Install with |:NeoBundleInstall|. + + If you are to install this plugin using |vim-plug|: + + 1. Add the following configuration to your + .vimrc(_vimrc). +> + Plug 'itchyny/lightline.vim' +< + 2. Install with |:PlugInstall|. + +Problem 2: *lightline-problem-2* + How to update this plugin. + + If you have installed this plugin manually: + + 1. Access https://github.com/itchyny/lightline.vim . + 2. Download the latest scripts. + 3. Place the scripts as written in Problem 1. + + If you have installed this plugin using Vundle: + + 1. Execute |:PluginUpdate|. + + If you have installed this plugin using NeoBundle: + + 1. Execute |:NeoBundleUpdate|. + + If you have installed this plugin using vim-plug: + + 1. Execute |:PlugUpdate|. + +Problem 3: *lightline-problem-3* + How to uninstall this plugin. + + If you have installed this plugin manually: + + 1. Remove all the lightline.*s under $VIM. + + If you have installed this plugin using Vundle: + + 1. Remove the :Plugin 'itchyny/lightline.vim' + configuration from your .vimrc(_vimrc). + 2. Update with |:PluginClean|. + + If you have installed this plugin using NeoBundle: + + 1. Remove the :NeoBundle 'itchyny/lightline.vim' + configuration from your .vimrc(_vimrc). + 2. Update with |:NeoBundleClean|. + + If you have installed this plugin using vim-plug: + + 1. Remove the :Plug 'itchyny/lightline.vim' + configuration from your .vimrc(_vimrc). + 2. Update with |:PlugClean|. + +Problem 4: *lightline-problem-4* + Cool statuslines appear only on |:vsp|. + + Add the following setting to your .vimrc(_vimrc). +> + set laststatus=2 +< +Problem 5: *lightline-problem-5* + The statusline does not seem to be correctly colored. + + Add +> + export TERM=xterm-256color +< + to your .*shrc and add +> + if !has('gui_running') + set t_Co=256 + endif +< + to your .vimrc(_vimrc). + +Problem 6: *lightline-problem-6* + How to install a patched font. + + There are two kinds of patched fonts: + + + The patched fonts for |vim-powerline| + (https://github.com/Lokaltog/vim-powerline): + follow the guide https://github.com/Lokaltog/vim-powerline/tree/develop/fontpatcher + + The patched fonts for |powerline| + (https://github.com/Lokaltog/powerline): + download from https://github.com/Lokaltog/powerline-fonts + +Problem 7: *lightline-problem-7* + Right triangles do not stick to the right components with patched + font. + + Remove the following setting from your .vimrc(_vimrc). +> + set ambiwidth=double +< + If you want to keep this setting, try the patched font for + |vim-powerline|. + +Problem 8: *lightline-problem-8* + Triangles do not appear. Triangles look weird. + + If the triangles do not appear (but you get some spaces or + weird characters like or ¿), firstly try adding +> + scriptencoding utf-8 + set encoding=utf-8 +< + to the head of your .vimrc(_vimrc). Still you have weird + characters, use the unicode numbers. For |powerline| font + users: +> + \ 'separator': { 'left': "\ue0b0", 'right': "\ue0b2" }, + \ 'subseparator': { 'left': "\ue0b1", 'right': "\ue0b3" } +< + For |vim-powerline| font users: +> + \ 'separator': { 'left': "\u2b80", 'right': "\u2b82" }, + \ 'subseparator': { 'left': "\u2b81", 'right': "\u2b83" } +< + The full list of unicode numbers for fancy characters is shown + in |lightline-problem-9|. + + If the triangles are shown in appropriate characters but the + colors do not look correctly, see the following. + If you are using iTerm2, change the following settings. + + + set Profiles>Colors>Minimum contrast to the Lowest. + + set Profiles>Window>Transparency to the Opaquest. + + For other terminals, this weird-triangle problem will be + resolved by disabling transparency or contrast adjustment. + +Problem 9: *lightline-problem-9* + Where can I find the list of all the cool characters for patched fonts? + + Default powerline vim-powerline + separator.left '' '' (\ue0b0) '⮀' (\u2b80) + separator.right '' '' (\ue0b2) '⮂' (\u2b82) + subseparator.left '|' '' (\ue0b1) '⮁' (\u2b81) + subseparator.right '|' '' (\ue0b3) '⮃' (\u2b83) + branch symbol -- '' (\ue0a0) '⭠' (\u2b60) + readonly symbol -- '' (\ue0a2) '⭤' (\u2b64) + linecolumn symbol -- '' (\ue0a1) '⭡' (\u2b61) + +Problem 10: *lightline-problem-10* + Cool statusline disappears on |unite|, |vimfiler| and |vimshell| + buffers. + + Add the following settings to your .vimrc(_vimrc). +> + let g:unite_force_overwrite_statusline = 0 + let g:vimfiler_force_overwrite_statusline = 0 + let g:vimshell_force_overwrite_statusline = 0 +< +Problem 11: *lightline-problem-11* + Cool statusline disappears in |CtrlP|, |Tagbar| buffers. + + Add the following settings to your .vimrc(_vimrc). +> + let g:ctrlp_status_func = { + \ 'main': 'CtrlPStatusFunc_1', + \ 'prog': 'CtrlPStatusFunc_2', + \ } + function! CtrlPStatusFunc_1(focus, byfname, regex, prev, item, next, marked) + return lightline#statusline(0) + endfunction + function! CtrlPStatusFunc_2(str) + return lightline#statusline(0) + endfunction + + let g:tagbar_status_func = 'TagbarStatusFunc' + function! TagbarStatusFunc(current, sort, fname, ...) abort + return lightline#statusline(0) + endfunction +< + See |lightline-powerful-example| for more cool settings for + these plugins. + +Problem 12: *lightline-problem-12* + How to make the plus sign red like |powerline|? + + Use the following settings. +> + let g:lightline = { + \ 'component': { + \ 'modified': '%#ModifiedColor#%{LightlineModified()}', + \ } + \ } + function! LightlineModified() + let map = { 'V': 'n', "\": 'n', 's': 'n', 'v': 'n', "\": 'n', 'c': 'n', 'R': 'n'} + let mode = get(map, mode()[0], mode()[0]) + let bgcolor = {'n': [240, '#585858'], 'i': [31, '#0087af']} + let color = get(bgcolor, mode, bgcolor.n) + exe printf('hi ModifiedColor ctermfg=196 ctermbg=%d guifg=#ff0000 guibg=%s term=bold cterm=bold', + \ color[0], color[1]) + return &modified ? '+' : &modifiable ? '' : '-' + endfunction +< + It's surely complicated. There's no easy API to do a thing + like this. But it means that your request does not match + the spirit of lightline. + +Problem 13: *lightline-problem-13* + How to change the lightline colorscheme on the fly. + + To update your lightline colorscheme in sync with your vim + colorscheme (only for select colorschemes which exist for + both), add the following settings to your .vimrc(_vimrc). +> + augroup LightlineColorscheme + autocmd! + autocmd ColorScheme * call s:lightline_update() + augroup END + function! s:lightline_update() + if !exists('g:loaded_lightline') + return + endif + try + if g:colors_name =~# 'wombat\|solarized\|landscape\|jellybeans\|seoul256\|Tomorrow' + let g:lightline.colorscheme = + \ substitute(substitute(g:colors_name, '-', '_', 'g'), '256.*', '', '') + call lightline#init() + call lightline#colorscheme() + call lightline#update() + endif + catch + endtry + endfunction +< + If you have not settled on a single lightline colorscheme, you + can easily switch between lightline colorschemes by adding the + following LightlineColorscheme command to your .vimrc(_vimrc). +> + function! s:set_lightline_colorscheme(name) abort + let g:lightline.colorscheme = a:name + call lightline#init() + call lightline#colorscheme() + call lightline#update() + endfunction + + function! s:lightline_colorschemes(...) abort + return join(map( + \ globpath(&rtp,"autoload/lightline/colorscheme/*.vim",1,1), + \ "fnamemodify(v:val,':t:r')"), + \ "\n") + endfunction + + command! -nargs=1 -complete=custom,s:lightline_colorschemes LightlineColorscheme + \ call s:set_lightline_colorscheme() +< +Problem 14: *lightline-problem-14* + The 'E541' warning appears on the right hand side. + Many components disable the statusline of lightline. + + The number of items in statusline/tabline is limited to 80 + (see |E541|). You cannot register too much components. + +Problem 15: *lightline-problem-15* + Do not deal with the tabline. + Do not use the fancy separators in the tabline. + + You can disable the tabline feature of lightline.vim using: +> + let g:lightline = { + \ 'enable': { 'tabline': 0 }, + \ } +< + If you don't like the separators in the tabline, use: +> + let g:lightline = { + \ 'tabline_separator': { 'left': "", 'right': "" }, + \ 'tabline_subseparator': { 'left': "", 'right': "" }, + \ } +< +Problem 16: *lightline-problem-16* + When changed the component to a function component to an expanding + component, the statusline of lightline is sometimes disabled. + + When you changed from +> + \ 'component_function': { + \ 'my': 'My', + \ } +< + to +> + \ 'component_expand': { + \ 'my': 'My', + \ } +< + the statusline of lightline is disabled unexpectedly. + In such a case, the text returned by 'My' function may include + the '%' character. Replace all the '%' signs with '%%'. +> + function My() + ... + return substitute(text, '%', '%%', 'g') + endfunction +< +Problem 17: *lightline-problem-17* + Found a bug of this plugin. + Got many errors while using this plugin. + Vim hangs while using this plugin. + Want this plugin to be more configurable. + This troubleshooting is not helpful. + + Report/Request the issue/feature at + https://github.com/itchyny/lightline.vim/issues. + +============================================================================== +vim:tw=78:sw=4:ts=8:ft=help:norl:noet: diff --git a/start/lightline/plugin/lightline.vim b/start/lightline/plugin/lightline.vim new file mode 100644 index 0000000..fc8f598 --- /dev/null +++ b/start/lightline/plugin/lightline.vim @@ -0,0 +1,26 @@ +" ============================================================================= +" Filename: plugin/lightline.vim +" Author: itchyny +" License: MIT License +" Last Change: 2018/06/22 08:49:00. +" ============================================================================= + +if exists('g:loaded_lightline') || v:version < 700 + finish +endif +let g:loaded_lightline = 1 + +let s:save_cpo = &cpo +set cpo&vim + +augroup lightline + autocmd! + autocmd WinEnter,BufWinEnter,FileType,SessionLoadPost * call lightline#update() + autocmd SessionLoadPost * call lightline#highlight() + autocmd ColorScheme * if !has('vim_starting') || expand('') !=# 'macvim' + \ | call lightline#update() | call lightline#highlight() | endif + autocmd CursorMoved,BufUnload * call lightline#update_once() +augroup END + +let &cpo = s:save_cpo +unlet s:save_cpo diff --git a/start/lspconfig-0.1.3/LICENSE.md b/start/lspconfig-0.1.3/LICENSE.md new file mode 100644 index 0000000..be03814 --- /dev/null +++ b/start/lspconfig-0.1.3/LICENSE.md @@ -0,0 +1,183 @@ +Copyright Neovim contributors. All rights reserved. + +nvim-lsp is licensed under the terms of the Apache 2.0 license. + +nvim-lsp's license follows: + +==== + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS diff --git a/start/lspconfig-0.1.3/doc/lspconfig.txt b/start/lspconfig-0.1.3/doc/lspconfig.txt new file mode 100644 index 0000000..d1d9103 --- /dev/null +++ b/start/lspconfig-0.1.3/doc/lspconfig.txt @@ -0,0 +1,636 @@ +*lspconfig.txt* For Nvim version 0.6.1+ Last change: 2021 Nov 7 +============================================================================== +TABLE OF CONTENTS *lspconfig-toc* + +1. Introduction (|lspconfig|) +2. LSP overview (|lspconfig-lsp|) +3. Quickstart (|lspconfig-quickstart|) +4. Setup {} (|lspconfig-setup|) +5. Global defaults (|lspconfig-global-defaults|) +6. Server configurations (|lspconfig-configurations|) + 6a. Adding servers (|lspconfig-adding-servers|) +7. Root directories (|lspconfig-root-detection|) + 7a. Advanced detection (|lspconfig-root-advanced|) + 7b. Single file support (|lspconfig-single-file-support|) +8. Commands (|lspconfig-commands|) +9. Keybindings (|lspconfig-keybindings|) +10. Completion (|lspconfig-completion|) +11. Debugging (|lspconfig-debugging|) +12. Logging (|lspconfig-logging|) +13. Scope (|lspconfig-scope|) + +============================================================================== +INTRODUCTION *lspconfig* + +`lspconfig` is a collection of community contributed configurations for the +built-in language server client in Neovim core. This plugin provides four +primary functionalities: + + - default launch commands, initialization options, and settings for each + server + - a root directory resolver which attempts to detect the root of your project + - an autocommand mapping that either launches a new language server or + attempts to attach a language server to each opened buffer if it falls + under a tracked project + - utility commands such as LspInfo, LspStart, LspStop, and LspRestart for + managing language server instances + +`lspconfig` is not required to use the built-in client, it is only one front-end +interface for when a language server specific plugin is not available. + +See |lspconfig-server-configurations| by typing `K` over it for the complete +list of language servers configurations. + +============================================================================== +LSP OVERVIEW *lspconfig-lsp* + +Nvim supports the Language Server Protocol (LSP) via the built-in language +server client. LSP facilitates many features, some of which include: + +- go-to-definition +- find-references +- hover +- completion +- rename +- format +- refactor + +These features are implemented in Neovim core, not `lspconfig`. See `:help lsp` +for more details. + +NOTE: Feature availability depends on the implementation details of the +server. A server may implement only a subset of these features. Always +consult the server documentation before filing a bug report on a missing +feature. + +============================================================================== +QUICKSTART *lspconfig-quickstart* + +- ensure the server is installed and executable from the command line + +- enable the server in your Neovim configuration (Lua example): +> + require'lspconfig'.clangd.setup{} +< +- create a new project, ensure that it contains a root marker which matches the + server requirements specified in |lspconfig-server-configurations|. + +- open a file within that project, such as `main.c`. + +- If you need more information about a server configuration, read the corresponding + entry in |lspconfig-server-configurations|. + +============================================================================== +THE SETUP METAMETHOD *lspconfig-setup* + +`lspconfig` consists of a collection of language server configurations. Each +configuration exposes a `setup {}` metamethod which makes it easy to directly +use the default configuration or selectively override the defaults. +`setup {}` is the primary interface by which users interact with `lspconfig`. + +Using the default configuration for a server is simple: +> + require'lspconfig'.clangd.setup{} +< +The available server names are listed in |lspconfig-server-configurations| and +match the server name in `config.SERVER_NAME` defined in each configuration's +source file. + +The purpose of `setup{}` is to wrap the call to Nvim's built-in +`vim.lsp.start_client()` with an autocommand that automatically launch a +language server. + +This autocommand calls `start_client()` or `vim.lsp.buf_attach_client()` +depending on whether the current file belongs to a project with a currently +running client. See |lspconfig-root-detection| for more details. + +The `setup{}` function takes a table which contains a superset of the keys +listed in `:help vim.lsp.start_client()` with the following unique entries: + +- {root_dir} + + `function(filename, bufnr)` + + Returns either a filepath (string) or nil. The language server will only + start if the function returns a filepath. + + If a root directory (string) is returned which is unique from any + previously returned root_dir, a new server will be spawned with that + root directory. See |lspconfig-root-detection| for more details + +- {name} + + `string` + + Defaults to the server's name (`clangd`, `pyright`, etc.). + +- {filetypes} + + `list[string] | nil` + + Set of filetypes for which to attempt to resolve {root_dir}. + + May be empty, or server may specify a default value. + +- {autostart} + + `bool` (default: true) + + Controls if the `FileType` autocommand that launches a language server is + created. If `false`, allows for deferring language servers until manually + launched with `:LspStart` (|lspconfig-commands|). + +- {single_file_support} + + `bool` (default: nil) + + Determines if a server is started without a matching root directory. + See |lspconfig-single-file-support|. + +- {on_new_config} + + `function(new_config, new_root_dir)` + + Function executed after a root directory is detected. This is used to + modify the server configuration (including `cmd` itself). Most commonly, + this is used to inject additional arguments into `cmd`. + + If overriding `on_new_config`, ensure that you read the + `on_new_config` defined in the source file of the default configuration + in `lspconfig`. The original `on_new_config` snippet for a given server + should likely be included in your new override. Some configurations + use `on_new_config` to dynamically set or modify `cmd`. + +Note: all entries passed to `setup {}` override the entry in the default +configuration. There is no composition. + +All `config` elements described in `:help vim.lsp.start_client()` can +additionally be overridden via the `setup {}` call. The most commonly +passed overrides to `setup {}` are: + +- {capabilities} `table ` + + a table which represents the neovim client capabilities. Useful for + broadcasting to the server additional functionality (snippets, off-protocol + features) provided by plugins. + +- {cmd} `list[string]` + + a list where each entry corresponds to the blankspace delimited part of + the command that launches the server. The first entry is the binary used + to run the language server. Additional entries are passed as arguments. + + The equivalent `cmd` for: +> + foo --bar baz +< + is: +> + {'foo', '--bar', 'baz} +< +- {handlers} `list[functions]` + + a list of handlers which override the function used to process a response + from a given language server. Applied only to the server referenced by + setup. See |lsp-handler|. + +- {init_options} `table ` + + a table passed during the initialization notification after launching + a language server. Equivalent to the `initializationOptions` field found + in `InitializeParams` in the LSP specification. + + See upstream server documentation for available initialization + options. + +- {on_attach} `function(client, bufnr)` + + Callback invoked by Nvim's built-in client when attaching a buffer to a + language server. Often used to set Nvim (buffer or global) options or to + override the Nvim client properties (`resolved_capabilities`) after a + language server attaches. Most commonly used for settings buffer + local keybindings. See |lspconfig-keybindings| for a usage example. + +- {settings} `table ` + + The `settings` table is sent in `on_init` via a + `workspace/didChangeConfiguration` notification from the Nvim client to + the language server. These settings allow a user to change optional runtime + settings of the language server. + + As an example, to set the following settings found in the pyright + documentation: + + `pyright.disableLanguageServices`: `boolean` + `pyright.disableOrganizeImports`: `boolean` + + Nested keys need to be translated into a nested table and passed to + the settings field in `setup {}` as follows: +> + require('lspconfig').pyright.setup{ + settings = { + pyright = { + disableLanguageServices = true, + disableOrganizeImports = true, + } + } + } +< +============================================================================== +OVERRIDING GLOBAL DEFAULTS *lspconfig-global-defaults* + +The global defaults for all servers can be overridden by extending the +`default_config` table. + +> + local lspconfig = require'lspconfig' + lspconfig.util.default_config = vim.tbl_extend( + "force", + lspconfig.util.default_config, + { + autostart = false, + handlers = { + ["window/logMessage"] = function(err, method, params, client_id) + if params and params.type <= vim.lsp.protocol.MessageType.Log then + vim.lsp.handlers["window/logMessage"](err, method, params, client_id) + end + end; + ["window/showMessage"] = function(err, method, params, client_id) + if params and params.type <= vim.lsp.protocol.MessageType.Warning.Error then + vim.lsp.handlers["window/showMessage"](err, method, params, client_id) + end + end; + } + } + ) +< +`setup {}` can additionally override these defaults in subsequent calls. + +============================================================================== +SERVER CONFIGURATIONS *lspconfig-configurations* + +See |lspconfig-server-configurations| by typing `K` over it for the complete +list of language servers configurations. + +While the `setup {}` function is the primary interface to `lspconfig`, for +servers for which there is not a configuration, it is necessary to define a +configuration directly. This can be useful if there is an outstanding PR that +is in review, or when developing a language server that is unavailable +publicly. This can be done through the `configs` module. + +The `configs` module is a singleton where configs are defined. The schema for +validating using `vim.validate` is: +> + configs.SERVER_NAME = { + default_config = {'t'}; + on_new_config = {'f', true}; + on_attach = {'f', true}; + commands = {'t', true}; + docs = {'t', true}; + } +< +where the structure of the docs table is as follows: +> + docs = { + description = {'s', true}; + default_config = {'t', true}; + } +< +`commands` is a map of `name:definition` key:value pairs, where `definition` +is a list whose first value is a function implementing the command, and the +rest are either array values which will be formed into flags for the command, +or special keys like `description`. Example: +> + commands = { + TexlabBuild = { + function() + buf_build(0) + end; + "-range"; + description = "Build the current buffer"; + }; + }; +< +The `configs.__newindex` metamethod consumes the config definition and returns +an object with a `setup()` method, to be invoked by users: +> + require'lspconfig'.SERVER_NAME.setup{} + +After you set `configs.SERVER_NAME` you can add arbitrary language-specific +functions to it if necessary. + +Example: + +> + configs.texlab.buf_build = buf_build +< +============================================================================== +ADDING NEW SERVERS *lspconfig-adding-servers* + +The three steps for adding and enabling a new server configuration are: + +- load the `lspconfig` module (note that this is a stylistic choice) +> + local lspconfig = require 'lspconfig' +< +- define the configuration + +> + local configs = require 'lspconfig.configs' + + -- Check if the config is already defined (useful when reloading this file) + if not configs.foo_lsp then + configs.foo_lsp = { + default_config = { + cmd = {'/home/neovim/lua-language-server/run.sh'}; + filetypes = {'lua'}; + root_dir = function(fname) + return lspconfig.util.find_git_ancestor(fname) + end; + settings = {}; + }; + } + end + +- call `setup()` to enable the FileType autocmd +> + lspconfig.foo_lsp.setup{} +< +============================================================================== +ROOT DETECTION *lspconfig-root-detection* + *lspconfig-root-dir* + +A project's `root_dir` is used by `lspconfig` to determine whether `lspconfig` +should start a new server, or attach a previous one, to the current file. + +`lspconfig` automatically launches language servers by defining a filetype +autocommand based on the `filetypes` specified in the default configuration of +each server, optionally overridable by the `filetypes` table passed to +`setup`. + +This autocommand triggers a search from the current file position in the +filesystem hierarchy up to the top level directory of your filesystem. The +`root_dir` entry of each configuration is a function that returns true if the +current directory in this traversal matches a given root pattern. + +The following utility functions are provided by `lspconfig`. Each function call +below returns a function that takes as its argument the current buffer path. + +- `util.root_pattern`: function which takes multiple arguments, each + corresponding to a different root pattern against which the contents of the + current directory are matched using |vim.fin.glob()| while traversing up the + filesystem. +> + root_dir = util.root_pattern('pyproject.toml', 'requirements.txt') +< +- `util.find_git_ancestor`: a function that locates the first parent directory + containing a `.git` directory. +> + root_dir = util.find_git_ancestor + +- `util.find_node_modules_ancestor`: a function that locates the first parent + directory containing a `node_modules` directory. +> + root_dir = util.find_node_modules_ancestor +< + +- `util.find_package_json_ancestor`: a function that locates the first parent + directory containing a `package.json`. +> + root_dir = util.find_json_ancestor +< +Note: On Windows, `lspconfig` always assumes forward slash normalized paths with +capitalized drive letters. + +============================================================================== +ADVANCED ROOT DIRECTORY DETECTION *lspconfig-root-advanced* + *lspconfig-root-composition* + +The `root_dir` key in `config` and `setup` can hold any function of the form +> + function custom_root_dir(filename, bufnr) + returns nil | string +> +This allows for rich composition of root directory patterns which is necessary +for some project structures. Example (for Kotlin): +> + local root_files = { + 'settings.gradle', -- Gradle (multi-project) + 'settings.gradle.kts', -- Gradle (multi-project) + 'build.xml', -- Ant + 'pom.xml', -- Maven + } + + local fallback_root_files = { + 'build.gradle', -- Gradle + 'build.gradle.kts', -- Gradle + } + root_dir = function(fname) + local primary = util.root_pattern(unpack(root_files))(fname) + local fallback = util.root_pattern(unpack(fallback_root_files))(fname) + return primary or fallback + end +< +Browsing the source of the default configurations is recommended. + +============================================================================== +SINGLE FILE SUPPORT *lspconfig-single-file-support* + +Language servers require each project to have a `root` in order to provide +features that require cross-file indexing. + +Some servers support not passing a root directory as a proxy for single file +mode under which cross-file features may be degraded. + +`lspconfig` offers limited support for an implicit single-file mode by: + +- first trying to resolve the root directory pattern +- then, if `single_file_support` is enabled for a given language server + configuration, starting the server without sending `rootDirectory` or + `workspaceFolders` during initialization. +- attaching subsequent files in the parent directory to the same server + instance, depending on filetype. + +Cross-file features (navigation, hover) may or may not work depending on the +language server. For a full feature-set, consider moving your files to a +directory with a project structure `lspconfig` can infer. + +Note that in the event that the LSP specification is extended to support a +standard for single-file mode, lspconfig will adopt that standard. + +============================================================================== +COMMANDS *lspconfig-commands* + +- `:LspInfo` shows the status of active and configured language servers. Note + that client id refers to the Nvim RPC instance connected to a given + language server. + +The following commands support tab-completion for all arguments. All commands +that require a client id can either leverage tab-completion or the info +contained in `:LspInfo`: + +- `:LspStart ` launches the requested (configured) client, but only + if it successfully resolves a root directory. Note: Defaults to all + configured servers matching the current buffer filetype. +- `:LspStop ` stops the server with the given client id. Defaults to + stopping all servers active on the current buffer. +- `:LspRestart ` restarts the client with the given client id, and + will attempt to reattach to all previously attached buffers. + +============================================================================== +EXAMPLE KEYBINDINGS *lspconfig-keybindings* + +`lspconfig`, and the core client, do not map any keybindings by default. The +following is an example Lua block which demonstrates how to leverage +`on-attach` to selectively apply keybindings after a language servers has +attached to a given buffer. +> +> + -- Mappings. + -- See `:help vim.diagnostic.*` for documentation on any of the below functions + local opts = { noremap=true, silent=true } + vim.api.nvim_set_keymap('n', 'e', 'lua vim.diagnostic.open_float()', opts) + vim.api.nvim_set_keymap('n', '[d', 'lua vim.diagnostic.goto_prev()', opts) + vim.api.nvim_set_keymap('n', ']d', 'lua vim.diagnostic.goto_next()', opts) + vim.api.nvim_set_keymap('n', 'q', 'lua vim.diagnostic.setloclist()', opts) + + -- Use an on_attach function to only map the following keys + -- after the language server attaches to the current buffer + local on_attach = function(client, bufnr) + -- Enable completion triggered by + vim.api.nvim_buf_set_option(bufnr, 'omnifunc', 'v:lua.vim.lsp.omnifunc') + + -- Mappings. + -- See `:help vim.lsp.*` for documentation on any of the below functions + vim.api.nvim_buf_set_keymap(bufnr, 'n', 'gD', 'lua vim.lsp.buf.declaration()', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', 'gd', 'lua vim.lsp.buf.definition()', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', 'K', 'lua vim.lsp.buf.hover()', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', 'gi', 'lua vim.lsp.buf.implementation()', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', '', 'lua vim.lsp.buf.signature_help()', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', 'wa', 'lua vim.lsp.buf.add_workspace_folder()', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', 'wr', 'lua vim.lsp.buf.remove_workspace_folder()', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', 'wl', 'lua print(vim.inspect(vim.lsp.buf.list_workspace_folders()))', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', 'D', 'lua vim.lsp.buf.type_definition()', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', 'rn', 'lua vim.lsp.buf.rename()', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', 'ca', 'lua vim.lsp.buf.code_action()', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', 'gr', 'lua vim.lsp.buf.references()', opts) + vim.api.nvim_buf_set_keymap(bufnr, 'n', 'f', 'lua vim.lsp.buf.formatting()', opts) + end + + -- Use a loop to conveniently call 'setup' on multiple servers and + -- map buffer local keybindings when the language server attaches + local servers = { 'pyright', 'rust_analyzer', 'tsserver' } + for _, lsp in pairs(servers) do + require('lspconfig')[lsp].setup { + on_attach = on_attach, + flags = { + -- This will be the default in neovim 0.7+ + debounce_text_changes = 150, + } + } + end +< +Note: these keymappings are meant for illustration and override some +infrequently used default mappings. + +============================================================================== +COMPLETION SUPPORT *lspconfig-completion* + +Manually triggered completion can be provided by Nvim's built-in omnifunc. +See `:help omnifunc` for more details. + +For autocompletion, Nvim does not offer built-in functionality at this time. +Consult the `lspconfig` wiki, which provides configuration examples for using a +completion plugin with the built-in client + +============================================================================== +DEBUGGING *lspconfig-debugging* + +While using language servers should be easy, debugging issues can be +challenging. First, it is important to identify the source of the issue, which +is typically (in rough order): + +- the language server itself +- a plugin +- overrides in a user configuration +- the built-in client in Nvim core +- `lspconfig` + +The first step in debugging is to test with a minimal configuration (such as +`../test/minimal_init.lua`). Historically, many users problems are due to +plugins or misconfiguration. + +Should that fail, identifying which component is the culprit is challenging. +The following are the only categories of bugs that pertain to `lspconfig`. + +- The root directory inferred for your project is wrong, or it should be + detected but is not due to a bug in the `lspconfig` path utilities. +- The server is launching, but you believe that the default settings, + initialization options, or command arguments are suboptimal and should be + replaced based on your understanding of the server documentation. + +All bugs Nvim's built-in client should be reported to the Nvim core issue +tracker. All bugs pertaining to plugins should be reported to the respective +plugin. All missing features in a language server should be reported to the +upstream language server issue tracker. + +For debugging `lspconfig` issues, the most common hurdles users face are: + + - The language server is not installed or is otherwise not executable. + `lspconfig` does not install language servers for you. Ensure the `cmd` + defined in `server_configurations.md` is executable from the command + line. If the absolute path to the binary is not supplied in `cmd`, ensure + it is on your PATH. + - No root detected. `lspconfig` is built around the concept of projects. See + |lspconfig-root-detection| for more details. Most of the time, + initializing a git repo will suffice. + - Misconfiguration. Often users will override `cmd`, `on_init`, or + `handlers`. Ensure that you debug by using a stock configuration to ensure + your customizations are not introducing issues. + +|LspInfo| provides an overview of your active and configured language servers +which can be useful for debugging. + +Note that it will not report any configuration changes applied in +`on_new_config`. + +============================================================================== +LOGGING *lspconfig-logging* + +When debugging language servers, it is helpful to enable additional logging in +the built-in client, specifically considering the RPC logs. Example: +> + vim.lsp.set_log_level 'trace' + if vim.fn.has 'nvim-0.5.1' == 1 then + require('vim.lsp.log').set_format_func(vim.inspect) + end +< +Attempt to run the language server, and open the log with: + +> + :lua vim.cmd('e'..vim.lsp.get_log_path()) +< +Note that `ERROR` messages containing `stderr` only indicate that the log was +sent to `stderr`. Many servers counter-intuitively send harmless messages +via stderr. + +============================================================================== +SCOPE *lspconfig-scope* + +`lspconfig` is a community effort to create default configurations that fit +within the scope of an official plugin for Nvim. All features that are not +strictly providing default configurations for language servers will be removed +from `lspconfig` in time. The power of the Neovim LSP ecosystem is in the +composability and flexibility of integrating multiple plugins which maximizes +user choice and freedom. + +`lspconfig` also opts to adhere strictly to the LSP specification, with some +small allowances when small modifications to a server configuration are +necessary to enable features critical to its usability. For more featureful +options, the `lspconfig` wiki lists community created plugins that build upon +the built-in client to provide functionality tailored to specific language +servers. + +============================================================================== + +vim:tw=78:ts=8:ft=help:norl: diff --git a/start/lspconfig-0.1.3/doc/server_configurations.md b/start/lspconfig-0.1.3/doc/server_configurations.md new file mode 100644 index 0000000..426c422 --- /dev/null +++ b/start/lspconfig-0.1.3/doc/server_configurations.md @@ -0,0 +1,6554 @@ +# Configurations + + +The following LSP configs are included. This documentation is autogenerated from the lua files. Follow a link to find documentation for +that config. This file is accessible in neovim via `:help lspconfig-server-configurations` + +- [als](#als) +- [angularls](#angularls) +- [ansiblels](#ansiblels) +- [arduino_language_server](#arduino_language_server) +- [asm_lsp](#asm_lsp) +- [awk_ls](#awk_ls) +- [bashls](#bashls) +- [beancount](#beancount) +- [bicep](#bicep) +- [bsl_ls](#bsl_ls) +- [ccls](#ccls) +- [clangd](#clangd) +- [clarity_lsp](#clarity_lsp) +- [clojure_lsp](#clojure_lsp) +- [cmake](#cmake) +- [codeqlls](#codeqlls) +- [crystalline](#crystalline) +- [csharp_ls](#csharp_ls) +- [cssls](#cssls) +- [cssmodules_ls](#cssmodules_ls) +- [cucumber_language_server](#cucumber_language_server) +- [dartls](#dartls) +- [denols](#denols) +- [dhall_lsp_server](#dhall_lsp_server) +- [diagnosticls](#diagnosticls) +- [dockerls](#dockerls) +- [dotls](#dotls) +- [efm](#efm) +- [elixirls](#elixirls) +- [elmls](#elmls) +- [ember](#ember) +- [emmet_ls](#emmet_ls) +- [erlangls](#erlangls) +- [esbonio](#esbonio) +- [eslint](#eslint) +- [flow](#flow) +- [flux_lsp](#flux_lsp) +- [foam_ls](#foam_ls) +- [fortls](#fortls) +- [fsautocomplete](#fsautocomplete) +- [fstar](#fstar) +- [gdscript](#gdscript) +- [ghcide](#ghcide) +- [golangci_lint_ls](#golangci_lint_ls) +- [gopls](#gopls) +- [gradle_ls](#gradle_ls) +- [grammarly](#grammarly) +- [graphql](#graphql) +- [groovyls](#groovyls) +- [haxe_language_server](#haxe_language_server) +- [hdl_checker](#hdl_checker) +- [hhvm](#hhvm) +- [hie](#hie) +- [hls](#hls) +- [hoon_ls](#hoon_ls) +- [html](#html) +- [idris2_lsp](#idris2_lsp) +- [intelephense](#intelephense) +- [java_language_server](#java_language_server) +- [jdtls](#jdtls) +- [jedi_language_server](#jedi_language_server) +- [jsonls](#jsonls) +- [jsonnet_ls](#jsonnet_ls) +- [julials](#julials) +- [kotlin_language_server](#kotlin_language_server) +- [lean3ls](#lean3ls) +- [leanls](#leanls) +- [lelwel_ls](#lelwel_ls) +- [lemminx](#lemminx) +- [ltex](#ltex) +- [metals](#metals) +- [mint](#mint) +- [mm0_ls](#mm0_ls) +- [nickel_ls](#nickel_ls) +- [nimls](#nimls) +- [ocamlls](#ocamlls) +- [ocamllsp](#ocamllsp) +- [ols](#ols) +- [omnisharp](#omnisharp) +- [opencl_ls](#opencl_ls) +- [openscad_ls](#openscad_ls) +- [pasls](#pasls) +- [perlls](#perlls) +- [perlnavigator](#perlnavigator) +- [perlpls](#perlpls) +- [phpactor](#phpactor) +- [please](#please) +- [powershell_es](#powershell_es) +- [prismals](#prismals) +- [prosemd_lsp](#prosemd_lsp) +- [psalm](#psalm) +- [puppet](#puppet) +- [purescriptls](#purescriptls) +- [pylsp](#pylsp) +- [pyre](#pyre) +- [pyright](#pyright) +- [quick_lint_js](#quick_lint_js) +- [r_language_server](#r_language_server) +- [racket_langserver](#racket_langserver) +- [reason_ls](#reason_ls) +- [remark_ls](#remark_ls) +- [rescriptls](#rescriptls) +- [rls](#rls) +- [rnix](#rnix) +- [robotframework_ls](#robotframework_ls) +- [rome](#rome) +- [rust_analyzer](#rust_analyzer) +- [salt_ls](#salt_ls) +- [scry](#scry) +- [serve_d](#serve_d) +- [sixtyfps](#sixtyfps) +- [slint_lsp](#slint_lsp) +- [solang](#solang) +- [solargraph](#solargraph) +- [solc](#solc) +- [solidity_ls](#solidity_ls) +- [sorbet](#sorbet) +- [sourcekit](#sourcekit) +- [sourcery](#sourcery) +- [spectral](#spectral) +- [sqlls](#sqlls) +- [sqls](#sqls) +- [stylelint_lsp](#stylelint_lsp) +- [sumneko_lua](#sumneko_lua) +- [svelte](#svelte) +- [svls](#svls) +- [tailwindcss](#tailwindcss) +- [taplo](#taplo) +- [teal_ls](#teal_ls) +- [terraform_lsp](#terraform_lsp) +- [terraformls](#terraformls) +- [texlab](#texlab) +- [tflint](#tflint) +- [theme_check](#theme_check) +- [tsserver](#tsserver) +- [typeprof](#typeprof) +- [vala_ls](#vala_ls) +- [vdmj](#vdmj) +- [verible](#verible) +- [vimls](#vimls) +- [vls](#vls) +- [volar](#volar) +- [vuels](#vuels) +- [yamlls](#yamlls) +- [zeta_note](#zeta_note) +- [zk](#zk) +- [zls](#zls) + +## als + +https://github.com/AdaCore/ada_language_server + +Installation instructions can be found [here](https://github.com/AdaCore/ada_language_server#Install). + +Can be configured by passing a "settings" object to `als.setup{}`: + +```lua +require('lspconfig').als.setup{ + settings = { + ada = { + projectFile = "project.gpr"; + scenarioVariables = { ... }; + } + } +} +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.als.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "ada_language_server" } + ``` + - `filetypes` : + ```lua + { "ada" } + ``` + - `root_dir` : + ```lua + util.root_pattern("Makefile", ".git", "*.gpr", "*.adc") + ``` + + +## angularls + +https://github.com/angular/vscode-ng-language-service + +`angular-language-server` can be installed via npm `npm install -g @angular/language-server`. + +Note, that if you override the default `cmd`, you must also update `on_new_config` to set `new_config.cmd` during startup. + +```lua +local project_library_path = "/path/to/project/lib" +local cmd = {"ngserver", "--stdio", "--tsProbeLocations", project_library_path , "--ngProbeLocations", project_library_path} + +require'lspconfig'.angularls.setup{ + cmd = cmd, + on_new_config = function(new_config,new_root_dir) + new_config.cmd = cmd + end, +} +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.angularls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "ngserver", "--stdio", "--tsProbeLocations", "", "--ngProbeLocations", "" } + ``` + - `filetypes` : + ```lua + { "typescript", "html", "typescriptreact", "typescript.tsx" } + ``` + - `root_dir` : + ```lua + root_pattern("angular.json", ".git") + ``` + + +## ansiblels + +https://github.com/ansible/ansible-language-server + +Language server for the ansible configuration management tool. + +`ansible-language-server` can be installed via `npm`: + +```sh +npm install -g @ansible/ansible-language-server +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.ansiblels.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "ansible-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "yaml.ansible" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `settings` : + ```lua + { + ansible = { + ansible = { + path = "ansible" + }, + ansibleLint = { + enabled = true, + path = "ansible-lint" + }, + executionEnvironment = { + enabled = false + }, + python = { + interpreterPath = "python" + } + } + } + ``` + - `single_file_support` : + ```lua + true + ``` + + +## arduino_language_server + +https://github.com/arduino/arduino-language-server + +Language server for Arduino + +The `arduino-language-server` can be installed by running: + go get -u github.com/arduino/arduino-language-server + +The `arduino-cli` tools must also be installed. Follow these instructions for your distro: + https://arduino.github.io/arduino-cli/latest/installation/ + +After installing the `arduino-cli` tools, follow these instructions for generating +a configuration file: + https://arduino.github.io/arduino-cli/latest/getting-started/#create-a-configuration-file +and make sure you install any relevant platforms libraries: + https://arduino.github.io/arduino-cli/latest/getting-started/#install-the-core-for-your-board + +The language server also requires `clangd` be installed. It will look for `clangd` by default but +the binary path can be overridden if need be. + +After all dependencies are installed you'll need to override the lspconfig command for the +language server in your setup function with the necessary configurations: + +```lua +lspconfig.arduino_language_server.setup({ + cmd = { + -- Required + "arduino-language-server", + "-cli-config", "/path/to/arduino-cli.yaml", + -- Optional + "-cli", "/path/to/arduino-cli", + "-clangd", "/path/to/clangd" + } +}) +``` + +For further instruction about configuration options, run `arduino-language-server --help`. + + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.arduino_language_server.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "arduino-language-server" } + ``` + - `filetypes` : + ```lua + { "arduino" } + ``` + - `root_dir` : + ```lua + see source file + ``` + + +## asm_lsp + +https://github.com/bergercookie/asm-lsp + +Language Server for GAS/GO Assembly + +`asm-lsp` can be installed via cargo: +cargo install asm-lsp + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.asm_lsp.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "asm-lsp" } + ``` + - `filetypes` : + ```lua + { "asm", "vmasm" } + ``` + - `root_dir` : + ```lua + see source file + ``` + + +## awk_ls + +https://github.com/Beaglefoot/awk-language-server/ + +`awk-language-server` can be installed via `npm`: +```sh +npm install -g awk-language-server +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.awk_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "awk-language-server" } + ``` + - `filetypes` : + ```lua + { "awk" } + ``` + - `single_file_support` : + ```lua + true + ``` + + +## bashls + +https://github.com/mads-hartmann/bash-language-server + +`bash-language-server` can be installed via `npm`: +```sh +npm i -g bash-language-server +``` + +Language server for bash, written using tree sitter in typescript. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.bashls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "bash-language-server", "start" } + ``` + - `cmd_env` : + ```lua + { + GLOB_PATTERN = "*@(.sh|.inc|.bash|.command)" + } + ``` + - `filetypes` : + ```lua + { "sh" } + ``` + - `root_dir` : + ```lua + util.find_git_ancestor + ``` + - `single_file_support` : + ```lua + true + ``` + + +## beancount + +https://github.com/polarmutex/beancount-language-server#installation + +See https://github.com/polarmutex/beancount-language-server#configuration for configuration options + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.beancount.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "beancount-langserver", "--stdio" } + ``` + - `filetypes` : + ```lua + { "beancount" } + ``` + - `init_options` : + ```lua + { + journalFile = "", + pythonPath = "python3" + } + ``` + - `root_dir` : + ```lua + root_pattern("elm.json") + ``` + - `single_file_support` : + ```lua + true + ``` + + +## bicep + +https://github.com/azure/bicep +Bicep language server + +Bicep language server can be installed by downloading and extracting a release of bicep-langserver.zip from [Bicep GitHub releases](https://github.com/Azure/bicep/releases). + +Bicep language server requires the [dotnet-sdk](https://dotnet.microsoft.com/download) to be installed. + +Neovim does not have built-in support for the bicep filetype which is required for lspconfig to automatically launch the language server. + +Filetype detection can be added via an autocmd: +```lua +vim.cmd [[ autocmd BufNewFile,BufRead *.bicep set filetype=bicep ]] +``` + +**By default, bicep language server does not have a `cmd` set.** This is because nvim-lspconfig does not make assumptions about your path. You must add the following to your init.vim or init.lua to set `cmd` to the absolute path ($HOME and ~ are not expanded) of the unzipped run script or binary. + +```lua +local bicep_lsp_bin = "/path/to/bicep-langserver/Bicep.LangServer.dll" +require'lspconfig'.bicep.setup{ + cmd = { "dotnet", bicep_lsp_bin }; + ... +} +``` + +To download the latest release and place in /usr/local/bin/bicep-langserver: +```bash +(cd $(mktemp -d) \ + && curl -fLO https://github.com/Azure/bicep/releases/latest/download/bicep-langserver.zip \ + && rm -rf /usr/local/bin/bicep-langserver \ + && unzip -d /usr/local/bin/bicep-langserver bicep-langserver.zip) +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.bicep.setup{} +``` + + +**Default values:** + - `filetypes` : + ```lua + { "bicep" } + ``` + - `init_options` : + ```lua + {} + ``` + - `root_dir` : + ```lua + util.find_git_ancestor + ``` + + +## bsl_ls + + https://github.com/1c-syntax/bsl-language-server + + Language Server Protocol implementation for 1C (BSL) - 1C:Enterprise 8 and OneScript languages. + + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.bsl_ls.setup{} +``` + + +**Default values:** + - `filetypes` : + ```lua + { "bsl", "os" } + ``` + - `root_dir` : + ```lua + root_pattern(".git") + ``` + + +## ccls + +https://github.com/MaskRay/ccls/wiki + +ccls relies on a [JSON compilation database](https://clang.llvm.org/docs/JSONCompilationDatabase.html) specified +as compile_commands.json or, for simpler projects, a .ccls. +For details on how to automatically generate one using CMake look [here](https://cmake.org/cmake/help/latest/variable/CMAKE_EXPORT_COMPILE_COMMANDS.html). Alternatively, you can use [Bear](https://github.com/rizsotto/Bear). + +Customization options are passed to ccls at initialization time via init_options, a list of available options can be found [here](https://github.com/MaskRay/ccls/wiki/Customization#initialization-options). For example: + +```lua +local lspconfig = require'lspconfig' +lspconfig.ccls.setup { + init_options = { + compilationDatabaseDirectory = "build"; + index = { + threads = 0; + }; + clang = { + excludeArgs = { "-frounding-math"} ; + }; + } +} + +``` + + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.ccls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "ccls" } + ``` + - `filetypes` : + ```lua + { "c", "cpp", "objc", "objcpp" } + ``` + - `offset_encoding` : + ```lua + "utf-32" + ``` + - `root_dir` : + ```lua + root_pattern("compile_commands.json", ".ccls", ".git") + ``` + - `single_file_support` : + ```lua + false + ``` + + +## clangd + +https://clangd.llvm.org/installation.html + +**NOTE:** Clang >= 11 is recommended! See [this issue for more](https://github.com/neovim/nvim-lsp/issues/23). + +clangd relies on a [JSON compilation database](https://clang.llvm.org/docs/JSONCompilationDatabase.html) specified as compile_commands.json, see https://clangd.llvm.org/installation#compile_commandsjson + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.clangd.setup{} +``` +**Commands:** +- ClangdSwitchSourceHeader: Switch between source/header + +**Default values:** + - `capabilities` : + ```lua + default capabilities, with offsetEncoding utf-8 + ``` + - `cmd` : + ```lua + { "clangd" } + ``` + - `filetypes` : + ```lua + { "c", "cpp", "objc", "objcpp" } + ``` + - `root_dir` : + ```lua + root_pattern( + '.clangd', + '.clang-tidy', + '.clang-format', + 'compile_commands.json', + 'compile_flags.txt', + 'configure.ac', + '.git' + ) + + ``` + - `single_file_support` : + ```lua + true + ``` + + +## clarity_lsp + +`clarity-lsp` is a language server for the Clarity language. Clarity is a decidable smart contract language that optimizes for predictability and security. Smart contracts allow developers to encode essential business logic on a blockchain. + +To learn how to configure the clarity language server, see the [clarity-lsp documentation](https://github.com/hirosystems/clarity-lsp). + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.clarity_lsp.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "clarity-lsp" } + ``` + - `filetypes` : + ```lua + { "clar", "clarity" } + ``` + - `root_dir` : + ```lua + root_pattern(".git") + ``` + + +## clojure_lsp + +https://github.com/snoe/clojure-lsp + +Clojure Language Server + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.clojure_lsp.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "clojure-lsp" } + ``` + - `filetypes` : + ```lua + { "clojure", "edn" } + ``` + - `root_dir` : + ```lua + root_pattern("project.clj", "deps.edn", "build.boot", "shadow-cljs.edn", ".git") + ``` + + +## cmake + +https://github.com/regen100/cmake-language-server + +CMake LSP Implementation + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.cmake.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "cmake-language-server" } + ``` + - `filetypes` : + ```lua + { "cmake" } + ``` + - `init_options` : + ```lua + { + buildDirectory = "build" + } + ``` + - `root_dir` : + ```lua + root_pattern(".git", "compile_commands.json", "build") + ``` + - `single_file_support` : + ```lua + true + ``` + + +## codeqlls + +Reference: +https://help.semmle.com/codeql/codeql-cli.html + +Binaries: +https://github.com/github/codeql-cli-binaries + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.codeqlls.setup{} +``` + + +**Default values:** + - `before_init` : + ```lua + see source file + ``` + - `cmd` : + ```lua + { "codeql", "execute", "language-server", "--check-errors", "ON_CHANGE", "-q" } + ``` + - `filetypes` : + ```lua + { "ql" } + ``` + - `log_level` : + ```lua + 2 + ``` + - `root_dir` : + ```lua + see source file + ``` + - `settings` : + ```lua + { + search_path = "list containing all search paths, eg: '~/codeql-home/codeql-repo'" + } + ``` + + +## crystalline + +https://github.com/elbywan/crystalline + +Crystal language server. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.crystalline.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "crystalline" } + ``` + - `filetypes` : + ```lua + { "crystal" } + ``` + - `root_dir` : + ```lua + root_pattern('shard.yml', '.git') + ``` + - `single_file_support` : + ```lua + true + ``` + + +## csharp_ls + +https://github.com/razzmatazz/csharp-language-server + +Language Server for C#. + +csharp-ls requires the [dotnet-sdk](https://dotnet.microsoft.com/download) to be installed. + +The preferred way to install csharp-ls is with `dotnet tool install --global csharp-ls`. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.csharp_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "csharp-ls" } + ``` + - `filetypes` : + ```lua + { "cs" } + ``` + - `init_options` : + ```lua + { + AutomaticWorkspaceInit = true + } + ``` + - `root_dir` : + ```lua + see source file + ``` + + +## cssls + + +https://github.com/hrsh7th/vscode-langservers-extracted + +`css-languageserver` can be installed via `npm`: + +```sh +npm i -g vscode-langservers-extracted +``` + +Neovim does not currently include built-in snippets. `vscode-css-language-server` only provides completions when snippet support is enabled. To enable completion, install a snippet plugin and add the following override to your language client capabilities during setup. + +```lua +--Enable (broadcasting) snippet capability for completion +local capabilities = vim.lsp.protocol.make_client_capabilities() +capabilities.textDocument.completion.completionItem.snippetSupport = true + +require'lspconfig'.cssls.setup { + capabilities = capabilities, +} +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.cssls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "vscode-css-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "css", "scss", "less" } + ``` + - `root_dir` : + ```lua + root_pattern("package.json", ".git") or bufdir + ``` + - `settings` : + ```lua + { + css = { + validate = true + }, + less = { + validate = true + }, + scss = { + validate = true + } + } + ``` + - `single_file_support` : + ```lua + true + ``` + + +## cssmodules_ls + +https://github.com/antonk52/cssmodules-language-server + +Language server for autocompletion and go-to-definition functionality for CSS modules. + +You can install cssmodules-language-server via npm: +```sh +npm install -g cssmodules-language-server +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.cssmodules_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "cssmodules-language-server" } + ``` + - `filetypes` : + ```lua + { "javascript", "javascriptreact", "typescript", "typescriptreact" } + ``` + - `root_dir` : + ```lua + root_pattern("package.json") + ``` + + +## cucumber_language_server + +https://cucumber.io +https://github.com/cucumber/common +https://www.npmjs.com/package/@cucumber/language-server + +Language server for Cucumber. + +`cucumber-language-server` can be installed via `npm`: +```sh +npm install -g @cucumber/language-server +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.cucumber_language_server.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "cucumber-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "cucumber" } + ``` + - `root_dir` : + ```lua + util.find_git_ancestor + ``` + + +## dartls + +https://github.com/dart-lang/sdk/tree/master/pkg/analysis_server/tool/lsp_spec + +Language server for dart. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.dartls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "dart", "./snapshots/analysis_server.dart.snapshot", "--lsp" } + ``` + - `filetypes` : + ```lua + { "dart" } + ``` + - `init_options` : + ```lua + { + closingLabels = true, + flutterOutline = true, + onlyAnalyzeProjectsWithOpenFiles = true, + outline = true, + suggestFromUnimportedLibraries = true + } + ``` + - `root_dir` : + ```lua + root_pattern("pubspec.yaml") + ``` + - `settings` : + ```lua + { + dart = { + completeFunctionCalls = true, + showTodos = true + } + } + ``` + + +## denols + +https://github.com/denoland/deno + +Deno's built-in language server + +To approrpiately highlight codefences returned from denols, you will need to augment vim.g.markdown_fenced languages + in your init.lua. Example: + +```lua +vim.g.markdown_fenced_languages = { + "ts=typescript" +} +``` + + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.denols.setup{} +``` +**Commands:** +- DenolsCache: Cache a module and all of its dependencies. + +**Default values:** + - `cmd` : + ```lua + { "deno", "lsp" } + ``` + - `filetypes` : + ```lua + { "javascript", "javascriptreact", "javascript.jsx", "typescript", "typescriptreact", "typescript.tsx" } + ``` + - `handlers` : + ```lua + { + ["textDocument/definition"] = , + ["textDocument/references"] = + } + ``` + - `init_options` : + ```lua + { + enable = true, + lint = false, + unstable = false + } + ``` + - `root_dir` : + ```lua + root_pattern("deno.json", "deno.jsonc", "tsconfig.json", ".git") + ``` + + +## dhall_lsp_server + +https://github.com/dhall-lang/dhall-haskell/tree/master/dhall-lsp-server + +language server for dhall + +`dhall-lsp-server` can be installed via cabal: +```sh +cabal install dhall-lsp-server +``` +prebuilt binaries can be found [here](https://github.com/dhall-lang/dhall-haskell/releases). + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.dhall_lsp_server.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "dhall-lsp-server" } + ``` + - `filetypes` : + ```lua + { "dhall" } + ``` + - `root_dir` : + ```lua + root_pattern(".git") + ``` + - `single_file_support` : + ```lua + true + ``` + + +## diagnosticls + +https://github.com/iamcco/diagnostic-languageserver + +Diagnostic language server integrate with linters. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.diagnosticls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "diagnostic-languageserver", "--stdio" } + ``` + - `filetypes` : + ```lua + Empty by default, override to add filetypes + ``` + - `root_dir` : + ```lua + Vim's starting directory + ``` + - `single_file_support` : + ```lua + true + ``` + + +## dockerls + +https://github.com/rcjsuen/dockerfile-language-server-nodejs + +`docker-langserver` can be installed via `npm`: +```sh +npm install -g dockerfile-language-server-nodejs +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.dockerls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "docker-langserver", "--stdio" } + ``` + - `filetypes` : + ```lua + { "dockerfile" } + ``` + - `root_dir` : + ```lua + root_pattern("Dockerfile") + ``` + - `single_file_support` : + ```lua + true + ``` + + +## dotls + +https://github.com/nikeee/dot-language-server + +`dot-language-server` can be installed via `npm`: +```sh +npm install -g dot-language-server +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.dotls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "dot-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "dot" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `single_file_support` : + ```lua + true + ``` + + +## efm + +https://github.com/mattn/efm-langserver + +General purpose Language Server that can use specified error message format generated from specified command. + +Requires at minimum EFM version [v0.0.38](https://github.com/mattn/efm-langserver/releases/tag/v0.0.38) to support +launching the language server on single files. If on an older version of EFM, disable single file support: + +```lua +require('lspconfig')['efm'].setup{ + settings = ..., -- You must populate this according to the EFM readme + filetypes = ..., -- Populate this according to the note below + single_file_support = false, -- This is the important line for supporting older version of EFM +} +``` + +Note: In order for neovim's built-in language server client to send the appropriate `languageId` to EFM, **you must +specify `filetypes` in your call to `setup{}`**. Otherwise `lspconfig` will launch EFM on the `BufEnter` instead +of the `FileType` autocommand, and the `filetype` variable used to populate the `languageId` will not yet be set. + +```lua +require('lspconfig')['efm'].setup{ + settings = ..., -- You must populate this according to the EFM readme + filetypes = { 'python','cpp','lua' } +} +``` + + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.efm.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "efm-langserver" } + ``` + - `root_dir` : + ```lua + util.root_pattern(".git") + ``` + - `single_file_support` : + ```lua + true + ``` + + +## elixirls + +https://github.com/elixir-lsp/elixir-ls + +`elixir-ls` can be installed by following the instructions [here](https://github.com/elixir-lsp/elixir-ls#building-and-running). + +```bash +curl -fLO https://github.com/elixir-lsp/elixir-ls/releases/latest/download/elixir-ls.zip +unzip elixir-ls.zip -d /path/to/elixir-ls +# Unix +chmod +x /path/to/elixir-ls/language_server.sh +``` + +**By default, elixir-ls doesn't have a `cmd` set.** This is because nvim-lspconfig does not make assumptions about your path. You must add the following to your init.vim or init.lua to set `cmd` to the absolute path ($HOME and ~ are not expanded) of your unzipped elixir-ls. + +```lua +require'lspconfig'.elixirls.setup{ + -- Unix + cmd = { "/path/to/elixir-ls/language_server.sh" }; + -- Windows + cmd = { "/path/to/elixir-ls/language_server.bat" }; + ... +} +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.elixirls.setup{} +``` + + +**Default values:** + - `filetypes` : + ```lua + { "elixir", "eelixir" } + ``` + - `root_dir` : + ```lua + root_pattern("mix.exs", ".git") or vim.loop.os_homedir() + ``` + + +## elmls + +https://github.com/elm-tooling/elm-language-server#installation + +If you don't want to use Nvim to install it, then you can use: +```sh +npm install -g elm elm-test elm-format @elm-tooling/elm-language-server +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.elmls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "elm-language-server" } + ``` + - `filetypes` : + ```lua + { "elm" } + ``` + - `init_options` : + ```lua + { + elmAnalyseTrigger = "change" + } + ``` + - `root_dir` : + ```lua + root_pattern("elm.json") + ``` + + +## ember + +https://github.com/lifeart/ember-language-server + +`ember-language-server` can be installed via `npm`: + +```sh +npm install -g @lifeart/ember-language-server +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.ember.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "ember-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "handlebars", "typescript", "javascript" } + ``` + - `root_dir` : + ```lua + root_pattern("ember-cli-build.js", ".git") + ``` + + +## emmet_ls + +https://github.com/aca/emmet-ls + +Package can be installed via `npm`: +```sh +npm install -g emmet-ls +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.emmet_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "emmet-ls", "--stdio" } + ``` + - `filetypes` : + ```lua + { "html", "css" } + ``` + - `root_dir` : + ```lua + git root + ``` + - `single_file_support` : + ```lua + true + ``` + + +## erlangls + +https://erlang-ls.github.io + +Language Server for Erlang. + +Clone [erlang_ls](https://github.com/erlang-ls/erlang_ls) +Compile the project with `make` and copy resulting binaries somewhere in your $PATH eg. `cp _build/*/bin/* ~/local/bin` + +Installation instruction can be found [here](https://github.com/erlang-ls/erlang_ls). + +Installation requirements: + - [Erlang OTP 21+](https://github.com/erlang/otp) + - [rebar3 3.9.1+](https://github.com/erlang/rebar3) + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.erlangls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "erlang_ls" } + ``` + - `filetypes` : + ```lua + { "erlang" } + ``` + - `root_dir` : + ```lua + root_pattern('rebar.config', 'erlang.mk', '.git') + ``` + - `single_file_support` : + ```lua + true + ``` + + +## esbonio + +https://github.com/swyddfa/esbonio + +Esbonio is a language server for [Sphinx](https://www.sphinx-doc.org/en/master/) documentation projects. +The language server can be installed via pip + +``` +pip install esbonio +``` + +Since Sphinx is highly extensible you will get best results if you install the language server in the same +Python environment as the one used to build your documentation. To ensure that the correct Python environment +is picked up, you can either launch `nvim` with the correct environment activated. + +``` +source env/bin/activate +nvim +``` + +Or you can modify the default `cmd` to include the full path to the Python interpreter. + +```lua +require'lspconfig'.esbonio.setup { + cmd = { '/path/to/virtualenv/bin/python', '-m', 'esbonio' } +} +``` + +Esbonio supports a number of config values passed as `init_options` on startup, for example. + +```lua +require'lspconfig'.esbonio.setup { + init_options = { + server = { + logLevel = "debug" + }, + sphinx = { + confDir = "/path/to/docs", + srcDir = "${confDir}/../docs-src" + } +} +``` + +A full list and explanation of the available options can be found [here](https://swyddfa.github.io/esbonio/docs/lsp/editors/index.html) + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.esbonio.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "python3", "-m", "esbonio" } + ``` + - `filetypes` : + ```lua + { "rst" } + ``` + - `root_dir` : + ```lua + see source file + ``` + + +## eslint + +https://github.com/hrsh7th/vscode-langservers-extracted + +vscode-eslint-language-server: A linting engine for JavaScript / Typescript + +`vscode-eslint-language-server` can be installed via `npm`: +```sh +npm i -g vscode-langservers-extracted +``` + +vscode-eslint-language-server provides an EslintFixAll command that can be used to format document on save +```vim +autocmd BufWritePre *.tsx,*.ts,*.jsx,*.js EslintFixAll +``` + +See [vscode-eslint](https://github.com/microsoft/vscode-eslint/blob/55871979d7af184bf09af491b6ea35ebd56822cf/server/src/eslintServer.ts#L216-L229) for configuration options. + +Additional messages you can handle: eslint/noConfig +Messages already handled in lspconfig: eslint/openDoc, eslint/confirmESLintExecution, eslint/probeFailed, eslint/noLibrary + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.eslint.setup{} +``` +**Commands:** +- EslintFixAll: Fix all eslint problems for this buffer + +**Default values:** + - `cmd` : + ```lua + { "vscode-eslint-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "javascript", "javascriptreact", "javascript.jsx", "typescript", "typescriptreact", "typescript.tsx", "vue" } + ``` + - `handlers` : + ```lua + { + ["eslint/confirmESLintExecution"] = , + ["eslint/noLibrary"] = , + ["eslint/openDoc"] = , + ["eslint/probeFailed"] = + } + ``` + - `on_new_config` : + ```lua + see source file + ``` + - `root_dir` : + ```lua + see source file + ``` + - `settings` : + ```lua + { + codeAction = { + disableRuleComment = { + enable = true, + location = "separateLine" + }, + showDocumentation = { + enable = true + } + }, + codeActionOnSave = { + enable = false, + mode = "all" + }, + format = true, + nodePath = "", + onIgnoredFiles = "off", + packageManager = "npm", + quiet = false, + rulesCustomizations = {}, + run = "onType", + useESLintClass = false, + validate = "on", + workingDirectory = { + mode = "location" + } + } + ``` + + +## flow + +https://flow.org/ +https://github.com/facebook/flow + +See below for how to setup Flow itself. +https://flow.org/en/docs/install/ + +See below for lsp command options. + +```sh +npx flow lsp --help +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.flow.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "npx", "--no-install", "flow", "lsp" } + ``` + - `filetypes` : + ```lua + { "javascript", "javascriptreact", "javascript.jsx" } + ``` + - `root_dir` : + ```lua + root_pattern(".flowconfig") + ``` + + +## flux_lsp + +https://github.com/influxdata/flux-lsp +`flux-lsp` can be installed via `cargo`: +```sh +cargo install --git https://github.com/influxdata/flux-lsp +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.flux_lsp.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "flux-lsp" } + ``` + - `filetypes` : + ```lua + { "flux" } + ``` + - `root_dir` : + ```lua + util.find_git_ancestor + ``` + - `single_file_support` : + ```lua + true + ``` + + +## foam_ls + +https://github.com/FoamScience/foam-language-server + +`foam-language-server` can be installed via `npm` +```sh +npm install -g foam-language-server +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.foam_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "foam-ls", "--stdio" } + ``` + - `filetypes` : + ```lua + { "foam", "OpenFOAM" } + ``` + - `root_dir` : + ```lua + see source file + ``` + + +## fortls + +https://github.com/hansec/fortran-language-server + +Fortran Language Server for the Language Server Protocol + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.fortls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "fortls" } + ``` + - `filetypes` : + ```lua + { "fortran" } + ``` + - `root_dir` : + ```lua + root_pattern(".fortls") + ``` + - `settings` : + ```lua + { + nthreads = 1 + } + ``` + + +## fsautocomplete + +https://github.com/fsharp/FsAutoComplete + +Language Server for F# provided by FsAutoComplete (FSAC). + +FsAutoComplete requires the [dotnet-sdk](https://dotnet.microsoft.com/download) to be installed. + +The preferred way to install FsAutoComplete is with `dotnet tool install --global fsautocomplete`. + +Instructions to compile from source are found on the main [repository](https://github.com/fsharp/FsAutoComplete). + +You may also need to configure the filetype as Vim defaults to Forth for `*.fs` files: + +`autocmd BufNewFile,BufRead *.fs,*.fsx,*.fsi set filetype=fsharp` + +This is automatically done by plugins such as [PhilT/vim-fsharp](https://github.com/PhilT/vim-fsharp), [fsharp/vim-fsharp](https://github.com/fsharp/vim-fsharp), and [adelarsq/neofsharp.vim](https://github.com/adelarsq/neofsharp.vim). + + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.fsautocomplete.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "fsautocomplete", "--background-service-enabled" } + ``` + - `filetypes` : + ```lua + { "fsharp" } + ``` + - `init_options` : + ```lua + { + AutomaticWorkspaceInit = true + } + ``` + - `root_dir` : + ```lua + see source file + ``` + + +## fstar + +https://github.com/FStarLang/FStar + +LSP support is included in FStar. Make sure `fstar.exe` is in your PATH. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.fstar.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "fstar.exe", "--lsp" } + ``` + - `filetypes` : + ```lua + { "fstar" } + ``` + - `root_dir` : + ```lua + util.find_git_ancestor + ``` + + +## gdscript + +https://github.com/godotengine/godot + +Language server for GDScript, used by Godot Engine. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.gdscript.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "nc", "localhost", "6008" } + ``` + - `filetypes` : + ```lua + { "gd", "gdscript", "gdscript3" } + ``` + - `root_dir` : + ```lua + util.root_pattern("project.godot", ".git") + ``` + + +## ghcide + +https://github.com/digital-asset/ghcide + +A library for building Haskell IDE tooling. +"ghcide" isn't for end users now. Use "haskell-language-server" instead of "ghcide". + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.ghcide.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "ghcide", "--lsp" } + ``` + - `filetypes` : + ```lua + { "haskell", "lhaskell" } + ``` + - `root_dir` : + ```lua + root_pattern("stack.yaml", "hie-bios", "BUILD.bazel", "cabal.config", "package.yaml") + ``` + + +## golangci_lint_ls + +Combination of both lint server and client + +https://github.com/nametake/golangci-lint-langserver +https://github.com/golangci/golangci-lint + + +Installation of binaries needed is done via + +``` +go install github.com/nametake/golangci-lint-langserver@latest +go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.42.1 +``` + + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.golangci_lint_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "golangci-lint-langserver" } + ``` + - `filetypes` : + ```lua + { "go", "gomod" } + ``` + - `init_options` : + ```lua + { + command = { "golangci-lint", "run", "--out-format", "json" } + } + ``` + - `root_dir` : + ```lua + root_pattern('go.work') or root_pattern('go.mod', '.golangci.yaml', '.git') + ``` + + +## gopls + +https://github.com/golang/tools/tree/master/gopls + +Google's lsp server for golang. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.gopls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "gopls" } + ``` + - `filetypes` : + ```lua + { "go", "gomod", "gotmpl" } + ``` + - `root_dir` : + ```lua + root_pattern("go.mod", ".git") + ``` + - `single_file_support` : + ```lua + true + ``` + + +## gradle_ls + +https://github.com/microsoft/vscode-gradle + +Microsoft's lsp server for gradle files + +If you're setting this up manually, build vscode-gradle using `./gradlew installDist` and point `cmd` to the `gradle-language-server` generated in the build directory + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.gradle_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "gradle-language-server" } + ``` + - `filetypes` : + ```lua + { "groovy" } + ``` + - `root_dir` : + ```lua + root_pattern("settings.gradle") + ``` + + +## grammarly + +https://github.com/emacs-grammarly/unofficial-grammarly-language-server + +`unofficial-grammarly-language-server` can be installed via `npm`: + +```sh +npm i -g @emacs-grammarly/unofficial-grammarly-language-server +``` + +WARNING: Since this language server uses Grammarly's API, any document you open with it running is shared with them. Please evaluate their [privacy policy](https://www.grammarly.com/privacy-policy) before using this. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.grammarly.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "unofficial-grammarly-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "markdown" } + ``` + - `handlers` : + ```lua + { + ["$/updateDocumentState"] = + } + ``` + - `root_dir` : + ```lua + util.find_git_ancestor + ``` + - `single_file_support` : + ```lua + true + ``` + + +## graphql + +https://github.com/graphql/graphiql/tree/main/packages/graphql-language-service-cli + +`graphql-lsp` can be installed via `npm`: + +```sh +npm install -g graphql-language-service-cli +``` + +Note that you must also have [the graphql package](https://github.com/graphql/graphql-js) installed and create a [GraphQL config file](https://www.graphql-config.com/docs/user/user-introduction). + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.graphql.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "graphql-lsp", "server", "-m", "stream" } + ``` + - `filetypes` : + ```lua + { "graphql", "typescriptreact", "javascriptreact" } + ``` + - `root_dir` : + ```lua + root_pattern('.git', '.graphqlrc*', '.graphql.config.*') + ``` + + +## groovyls + +https://github.com/prominic/groovy-language-server.git + +Requirements: + - Linux/macOS (for now) + - Java 11+ + +`groovyls` can be installed by following the instructions [here](https://github.com/prominic/groovy-language-server.git#build). + +If you have installed groovy language server, you can set the `cmd` custom path as follow: + +```lua +require'lspconfig'.groovyls.setup{ + -- Unix + cmd = { "java", "-jar", "path/to/groovyls/groovy-language-server-all.jar" }, + ... +} +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.groovyls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "java", "-jar", "groovy-language-server-all.jar" } + ``` + - `filetypes` : + ```lua + { "groovy" } + ``` + - `root_dir` : + ```lua + see source file + ``` + + +## haxe_language_server + +https://github.com/vshaxe/haxe-language-server + +The Haxe language server can be built by running the following commands from +the project's root directory: + + npm install + npx lix run vshaxe-build -t language-server + +This will create `bin/server.js`. Note that the server requires Haxe 3.4.0 or +higher. + +After building the language server, set the `cmd` setting in your setup +function: + +```lua +lspconfig.haxe_language_server.setup({ + cmd = {"node", "path/to/bin/server.js"}, +}) +``` + +By default, an HXML compiler arguments file named `build.hxml` is expected in +your project's root directory. If your file is named something different, +specify it using the `init_options.displayArguments` setting. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.haxe_language_server.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "haxe-language-server" } + ``` + - `filetypes` : + ```lua + { "haxe" } + ``` + - `init_options` : + ```lua + { + displayArguments = { "build.hxml" } + } + ``` + - `root_dir` : + ```lua + root_pattern("*.hxml") + ``` + - `settings` : + ```lua + { + haxe = { + executable = "haxe" + } + } + ``` + + +## hdl_checker + +https://github.com/suoto/hdl_checker +Language server for hdl-checker. +Install using: `pip install hdl-checker --upgrade` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.hdl_checker.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "hdl_checker", "--lsp" } + ``` + - `filetypes` : + ```lua + { "vhdl", "verilog", "systemverilog" } + ``` + - `root_dir` : + ```lua + util.find_git_ancestor + ``` + - `single_file_support` : + ```lua + true + ``` + + +## hhvm + +Language server for programs written in Hack +https://hhvm.com/ +https://github.com/facebook/hhvm +See below for how to setup HHVM & typechecker: +https://docs.hhvm.com/hhvm/getting-started/getting-started + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.hhvm.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "hh_client", "lsp" } + ``` + - `filetypes` : + ```lua + { "php", "hack" } + ``` + - `root_dir` : + ```lua + root_pattern(".hhconfig") + ``` + + +## hie + +https://github.com/haskell/haskell-ide-engine + +the following init_options are supported (see https://github.com/haskell/haskell-ide-engine#configuration): +```lua +init_options = { + languageServerHaskell = { + hlintOn = bool; + maxNumberOfProblems = number; + diagnosticsDebounceDuration = number; + liquidOn = bool (default false); + completionSnippetsOn = bool (default true); + formatOnImportOn = bool (default true); + formattingProvider = string (default "brittany", alternate "floskell"); + } +} +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.hie.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "hie-wrapper", "--lsp" } + ``` + - `filetypes` : + ```lua + { "haskell" } + ``` + - `root_dir` : + ```lua + root_pattern("stack.yaml", "package.yaml", ".git") + ``` + + +## hls + +https://github.com/haskell/haskell-language-server + +Haskell Language Server + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.hls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "haskell-language-server-wrapper", "--lsp" } + ``` + - `filetypes` : + ```lua + { "haskell", "lhaskell" } + ``` + - `lspinfo` : + ```lua + see source file + ``` + - `root_dir` : + ```lua + root_pattern("*.cabal", "stack.yaml", "cabal.project", "package.yaml", "hie.yaml") + ``` + - `settings` : + ```lua + { + haskell = { + formattingProvider = "ormolu" + } + } + ``` + - `single_file_support` : + ```lua + true + ``` + + +## hoon_ls + +https://github.com/urbit/hoon-language-server + +A language server for Hoon. + +The language server can be installed via `npm install -g @hoon-language-server` + +Start a fake ~zod with `urbit -F zod`. +Start the language server at the Urbit Dojo prompt with: `|start %language-server` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.hoon_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "hoon-language-server" } + ``` + - `filetypes` : + ```lua + { "hoon" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `single_file_support` : + ```lua + true + ``` + + +## html + +https://github.com/hrsh7th/vscode-langservers-extracted + +`vscode-html-language-server` can be installed via `npm`: +```sh +npm i -g vscode-langservers-extracted +``` + +Neovim does not currently include built-in snippets. `vscode-html-language-server` only provides completions when snippet support is enabled. +To enable completion, install a snippet plugin and add the following override to your language client capabilities during setup. + +The code-formatting feature of the lsp can be controlled with the `provideFormatter` option. + +```lua +--Enable (broadcasting) snippet capability for completion +local capabilities = vim.lsp.protocol.make_client_capabilities() +capabilities.textDocument.completion.completionItem.snippetSupport = true + +require'lspconfig'.html.setup { + capabilities = capabilities, +} +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.html.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "vscode-html-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "html" } + ``` + - `init_options` : + ```lua + { + configurationSection = { "html", "css", "javascript" }, + embeddedLanguages = { + css = true, + javascript = true + }, + provideFormatter = true + } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `settings` : + ```lua + {} + ``` + - `single_file_support` : + ```lua + true + ``` + + +## idris2_lsp + +https://github.com/idris-community/idris2-lsp + +The Idris 2 language server. + +Plugins for the Idris 2 filetype include +[Idris2-Vim](https://github.com/edwinb/idris2-vim) (fewer features, stable) and +[Nvim-Idris2](https://github.com/ShinKage/nvim-idris2) (cutting-edge, +experimental). + +Idris2-Lsp requires a build of Idris 2 that includes the "Idris 2 API" package. +Package managers with known support for this build include the +[AUR](https://aur.archlinux.org/packages/idris2-api-git/) and +[Homebrew](https://formulae.brew.sh/formula/idris2#default). + +If your package manager does not support the Idris 2 API, you will need to build +Idris 2 from source. Refer to the +[the Idris 2 installation instructions](https://github.com/idris-lang/Idris2/blob/main/INSTALL.md) +for details. Steps 5 and 8 are listed as "optional" in that guide, but they are +necessary in order to make the Idris 2 API available. + +You need to install a version of Idris2-Lsp that is compatible with your +version of Idris 2. There should be a branch corresponding to every released +Idris 2 version after v0.4.0. Use the latest commit on that branch. For example, +if you have Idris v0.5.1, you should use the v0.5.1 branch of Idris2-Lsp. + +If your Idris 2 version is newer than the newest Idris2-Lsp branch, use the +latest commit on the `master` branch, and set a reminder to check the Idris2-Lsp +repo for the release of a compatible versioned branch. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.idris2_lsp.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "idris2-lsp" } + ``` + - `filetypes` : + ```lua + { "idris2" } + ``` + - `root_dir` : + ```lua + see source file + ``` + + +## intelephense + +https://intelephense.com/ + +`intelephense` can be installed via `npm`: +```sh +npm install -g intelephense +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.intelephense.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "intelephense", "--stdio" } + ``` + - `filetypes` : + ```lua + { "php" } + ``` + - `root_dir` : + ```lua + root_pattern("composer.json", ".git") + ``` + + +## java_language_server + +https://github.com/georgewfraser/java-language-server + +Java language server + +Point `cmd` to `lang_server_linux.sh` or the equivalent script for macOS/Windows provided by java-language-server + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.java_language_server.setup{} +``` + + +**Default values:** + - `filetypes` : + ```lua + { "java" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `settings` : + ```lua + {} + ``` + + +## jdtls + +https://projects.eclipse.org/projects/eclipse.jdt.ls + +Language server for Java. + +IMPORTANT: If you want all the features jdtls has to offer, [nvim-jdtls](https://github.com/mfussenegger/nvim-jdtls) +is highly recommended. If all you need is diagnostics, completion, imports, gotos and formatting and some code actions +you can keep reading here. + +For manual installation you can download precompiled binaries from the +[official downloads site](http://download.eclipse.org/jdtls/snapshots/?d) + +Due to the nature of java, settings cannot be inferred. Please set the following +environmental variables to match your installation. If you need per-project configuration +[direnv](https://github.com/direnv/direnv) is highly recommended. + +```bash +# Mandatory: +# .bashrc +export JDTLS_HOME=/path/to/jdtls_root # Directory with the plugin and configs directories + +# Optional: +export JAVA_HOME=/path/to/java_home # In case you don't have java in path or want to use a version in particular +export WORKSPACE=/path/to/workspace # Defaults to $HOME/workspace +``` +```lua + -- init.lua + require'lspconfig'.jdtls.setup{} +``` + +For automatic installation you can use the following unofficial installers/launchers under your own risk: + - [jdtls-launcher](https://github.com/eruizc-dev/jdtls-launcher) (Includes lombok support by default) + ```lua + -- init.lua + require'lspconfig'.jdtls.setup{ cmd = { 'jdtls' } } + ``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.jdtls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "/usr/lib/jvm/temurin-11-jdk-amd64/bin/java", "-Declipse.application=org.eclipse.jdt.ls.core.id1", "-Dosgi.bundles.defaultStartLevel=4", "-Declipse.product=org.eclipse.jdt.ls.core.product", "-Dlog.protocol=true", "-Dlog.level=ALL", "-Xms1g", "-Xmx2G", "--add-modules=ALL-SYSTEM", "--add-opens", "java.base/java.util=ALL-UNNAMED", "--add-opens", "java.base/java.lang=ALL-UNNAMED", "-jar", "/plugins/org.eclipse.equinox.launcher_*.jar", "-configuration", "config_linux", "-data", "/home/runner/workspace" } + ``` + - `filetypes` : + ```lua + { "java" } + ``` + - `handlers` : + ```lua + { + ["language/status"] = , + ["textDocument/codeAction"] = , + ["textDocument/rename"] = , + ["workspace/applyEdit"] = + } + ``` + - `init_options` : + ```lua + { + jvm_args = {}, + workspace = "/home/runner/workspace" + } + ``` + - `root_dir` : + ```lua + { + -- Single-module projects + { + 'build.xml', -- Ant + 'pom.xml', -- Maven + 'settings.gradle', -- Gradle + 'settings.gradle.kts', -- Gradle + }, + -- Multi-module projects + { 'build.gradle', 'build.gradle.kts' }, + } or vim.fn.getcwd() + ``` + - `single_file_support` : + ```lua + true + ``` + + +## jedi_language_server + +https://github.com/pappasam/jedi-language-server + +`jedi-language-server`, a language server for Python, built on top of jedi + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.jedi_language_server.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "jedi-language-server" } + ``` + - `filetypes` : + ```lua + { "python" } + ``` + - `root_dir` : + ```lua + vim's starting directory + ``` + - `single_file_support` : + ```lua + true + ``` + + +## jsonls + +https://github.com/hrsh7th/vscode-langservers-extracted + +vscode-json-language-server, a language server for JSON and JSON schema + +`vscode-json-language-server` can be installed via `npm`: +```sh +npm i -g vscode-langservers-extracted +``` + +Neovim does not currently include built-in snippets. `vscode-json-language-server` only provides completions when snippet support is enabled. To enable completion, install a snippet plugin and add the following override to your language client capabilities during setup. + +```lua +--Enable (broadcasting) snippet capability for completion +local capabilities = vim.lsp.protocol.make_client_capabilities() +capabilities.textDocument.completion.completionItem.snippetSupport = true + +require'lspconfig'.jsonls.setup { + capabilities = capabilities, +} +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.jsonls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "vscode-json-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "json", "jsonc" } + ``` + - `init_options` : + ```lua + { + provideFormatter = true + } + ``` + - `root_dir` : + ```lua + util.find_git_ancestor + ``` + - `single_file_support` : + ```lua + true + ``` + + +## jsonnet_ls + +https://github.com/grafana/jsonnet-language-server + +A Language Server Protocol (LSP) server for Jsonnet. + +The language server can be installed with `go`: +```sh +go install github.com/grafana/jsonnet-language-server@latest +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.jsonnet_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "jsonnet-language-server" } + ``` + - `filetypes` : + ```lua + { "jsonnet", "libsonnet" } + ``` + - `on_new_config` : + ```lua + see source file + ``` + - `root_dir` : + ```lua + root_pattern("jsonnetfile.json") + ``` + + +## julials + +https://github.com/julia-vscode/julia-vscode + +LanguageServer.jl can be installed with `julia` and `Pkg`: +```sh +julia --project=~/.julia/environments/nvim-lspconfig -e 'using Pkg; Pkg.add("LanguageServer")' +``` +where `~/.julia/environments/nvim-lspconfig` is the location where +the default configuration expects LanguageServer.jl to be installed. + +To update an existing install, use the following command: +```sh +julia --project=~/.julia/environments/nvim-lspconfig -e 'using Pkg; Pkg.update()' +``` + +Note: In order to have LanguageServer.jl pick up installed packages or dependencies in a +Julia project, you must make sure that the project is instantiated: +```sh +julia --project=/path/to/my/project -e 'using Pkg; Pkg.instantiate()' +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.julials.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "julia", "--startup-file=no", "--history-file=no", "-e", ' # Load LanguageServer.jl: attempt to load from ~/.julia/environments/nvim-lspconfig\n # with the regular load path as a fallback\n ls_install_path = joinpath(\n get(DEPOT_PATH, 1, joinpath(homedir(), ".julia")),\n "environments", "nvim-lspconfig"\n )\n pushfirst!(LOAD_PATH, ls_install_path)\n using LanguageServer\n popfirst!(LOAD_PATH)\n depot_path = get(ENV, "JULIA_DEPOT_PATH", "")\n project_path = let\n dirname(something(\n ## 1. Finds an explicitly set project (JULIA_PROJECT)\n Base.load_path_expand((\n p = get(ENV, "JULIA_PROJECT", nothing);\n p === nothing ? nothing : isempty(p) ? nothing : p\n )),\n ## 2. Look for a Project.toml file in the current working directory,\n ## or parent directories, with $HOME as an upper boundary\n Base.current_project(),\n ## 3. First entry in the load path\n get(Base.load_path(), 1, nothing),\n ## 4. Fallback to default global environment,\n ## this is more or less unreachable\n Base.load_path_expand("@v#.#"),\n ))\n end\n @info "Running language server" VERSION pwd() project_path depot_path\n server = LanguageServer.LanguageServerInstance(stdin, stdout, project_path, depot_path)\n server.runlinter = true\n run(server)\n ' } + ``` + - `filetypes` : + ```lua + { "julia" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `single_file_support` : + ```lua + true + ``` + + +## kotlin_language_server + + A kotlin language server which was developed for internal usage and + released afterwards. Maintaining is not done by the original author, + but by fwcd. + + It is built via gradle and developed on github. + Source and additional description: + https://github.com/fwcd/kotlin-language-server + + This server requires vim to be aware of the kotlin-filetype. + You could refer for this capability to: + https://github.com/udalov/kotlin-vim (recommended) + Note that there is no LICENSE specified yet. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.kotlin_language_server.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "kotlin-language-server" } + ``` + - `filetypes` : + ```lua + { "kotlin" } + ``` + - `root_dir` : + ```lua + root_pattern("settings.gradle") + ``` + + +## lean3ls + +https://github.com/leanprover/lean-client-js/tree/master/lean-language-server + +Lean installation instructions can be found +[here](https://leanprover-community.github.io/get_started.html#regular-install). + +Once Lean is installed, you can install the Lean 3 language server by running +```sh +npm install -g lean-language-server +``` + +Note: that if you're using [lean.nvim](https://github.com/Julian/lean.nvim), +that plugin fully handles the setup of the Lean language server, +and you shouldn't set up `lean3ls` both with it and `lspconfig`. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.lean3ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "lean-language-server", "--stdio", "--", "-M", "4096", "-T", "100000" } + ``` + - `filetypes` : + ```lua + { "lean3" } + ``` + - `offset_encoding` : + ```lua + "utf-32" + ``` + - `root_dir` : + ```lua + root_pattern("leanpkg.toml") or root_pattern(".git") + ``` + - `single_file_support` : + ```lua + true + ``` + + +## leanls + +https://github.com/leanprover/lean4 + +Lean installation instructions can be found +[here](https://leanprover-community.github.io/get_started.html#regular-install). + +The Lean 4 language server is built-in with a Lean 4 install +(and can be manually run with, e.g., `lean --server`). + +Note: that if you're using [lean.nvim](https://github.com/Julian/lean.nvim), +that plugin fully handles the setup of the Lean language server, +and you shouldn't set up `leanls` both with it and `lspconfig`. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.leanls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "lake", "serve", "--" } + ``` + - `filetypes` : + ```lua + { "lean" } + ``` + - `on_new_config` : + ```lua + see source file + ``` + - `options` : + ```lua + { + no_lake_lsp_cmd = { "lean", "--server" } + } + ``` + - `root_dir` : + ```lua + root_pattern("lakefile.lean", "lean-toolchain", "leanpkg.toml", ".git") + ``` + - `single_file_support` : + ```lua + true + ``` + + +## lelwel_ls + +https://github.com/0x2a-42/lelwel + +Language server for lelwel grammars. + +You can install `lelwel-ls` via cargo: +```sh +cargo install --features="lsp" lelwel +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.lelwel_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "lelwel-ls" } + ``` + - `filetypes` : + ```lua + { "llw" } + ``` + - `root_dir` : + ```lua + see source file + ``` + + +## lemminx + +https://github.com/eclipse/lemminx + +The easiest way to install the server is to get a binary at https://download.jboss.org/jbosstools/vscode/stable/lemminx-binary/ and place it in your PATH. + +NOTE to macOS users: Binaries from unidentified developers are blocked by default. If you trust the downloaded binary from jboss.org, run it once, cancel the prompt, then remove the binary from Gatekeeper quarantine with `xattr -d com.apple.quarantine lemminx`. It should now run without being blocked. + + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.lemminx.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "lemminx" } + ``` + - `filetypes` : + ```lua + { "xml", "xsd", "xsl", "xslt", "svg" } + ``` + - `root_dir` : + ```lua + util.find_git_ancestor + ``` + - `single_file_support` : + ```lua + true + ``` + + +## ltex + +https://github.com/valentjn/ltex-ls + +LTeX Language Server: LSP language server for LanguageTool 🔍✔️ with support for LaTeX 🎓, Markdown 📝, and others + +To install, download the latest [release](https://github.com/valentjn/ltex-ls/releases) and ensure `ltex-ls` is on your path. + +To support org files or R sweave, users can define a custom filetype autocommand (or use a plugin which defines these filetypes): + +```lua +vim.cmd [[ autocmd BufRead,BufNewFile *.org set filetype=org ]] +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.ltex.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "ltex-ls" } + ``` + - `filetypes` : + ```lua + { "bib", "gitcommit", "markdown", "org", "plaintex", "rst", "rnoweb", "tex" } + ``` + - `get_language_id` : + ```lua + see source file + ``` + - `root_dir` : + ```lua + see source file + ``` + - `single_file_support` : + ```lua + true + ``` + + +## metals + +https://scalameta.org/metals/ + +Scala language server with rich IDE features. + +See full instructions in the Metals documentation: + +https://scalameta.org/metals/docs/editors/vim.html#using-an-alternative-lsp-client + +Note: that if you're using [nvim-metals](https://github.com/scalameta/nvim-metals), that plugin fully handles the setup and installation of Metals, and you shouldn't set up Metals both with it and `lspconfig`. + +To install Metals, make sure to have [coursier](https://get-coursier.io/docs/cli-installation) installed, and once you do you can install the latest Metals with `cs install metals`. You can also manually bootstrap Metals with the following command. + +```bash +cs bootstrap \ + --java-opt -Xss4m \ + --java-opt -Xms100m \ + org.scalameta:metals_2.12: \ + -r bintray:scalacenter/releases \ + -r sonatype:snapshots \ + -o /usr/local/bin/metals -f +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.metals.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "metals" } + ``` + - `filetypes` : + ```lua + { "scala" } + ``` + - `init_options` : + ```lua + { + compilerOptions = { + snippetAutoIndent = false + }, + isHttpEnabled = true, + statusBarProvider = "show-message" + } + ``` + - `message_level` : + ```lua + 4 + ``` + - `root_dir` : + ```lua + util.root_pattern("build.sbt", "build.sc", "build.gradle", "pom.xml") + ``` + + +## mint + +https://www.mint-lang.com + +Install Mint using the [instructions](https://www.mint-lang.com/install). +The language server is included since version 0.12.0. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.mint.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "mint", "ls" } + ``` + - `filetypes` : + ```lua + { "mint" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `single_file_support` : + ```lua + true + ``` + + +## mm0_ls + +https://github.com/digama0/mm0 + +Language Server for the metamath-zero theorem prover. + +Requires [mm0-rs](https://github.com/digama0/mm0/tree/master/mm0-rs) to be installed +and available on the `PATH`. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.mm0_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "mm0-rs", "server" } + ``` + - `filetypes` : + ```lua + { "metamath-zero" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `single_file_support` : + ```lua + true + ``` + + +## nickel_ls + +Nickel Language Server + +https://github.com/tweag/nickel + +`nls` can be installed with nix, or cargo, from the Nickel repository. +```sh +git clone https://github.com/tweag/nickel.git +``` + +Nix: +```sh +cd nickel +nix-env -f . -i +``` + +cargo: +```sh +cd nickel/lsp/nls +cargo install --path . +``` + +In order to have lspconfig detect Nickel filetypes (a prequisite for autostarting a server), +install the [Nickel vim plugin](https://github.com/nickel-lang/vim-nickel). + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.nickel_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "nls" } + ``` + - `filetypes` : + ```lua + { "ncl", "nickel" } + ``` + - `root_dir` : + ```lua + see source file + ``` + + +## nimls + +https://github.com/PMunch/nimlsp +`nimlsp` can be installed via the `nimble` package manager: +```sh +nimble install nimlsp +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.nimls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "nimlsp" } + ``` + - `filetypes` : + ```lua + { "nim" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `single_file_support` : + ```lua + true + ``` + + +## ocamlls + +https://github.com/ocaml-lsp/ocaml-language-server + +`ocaml-language-server` can be installed via `npm` +```sh +npm install -g ocaml-language-server +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.ocamlls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "ocaml-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "ocaml", "reason" } + ``` + - `root_dir` : + ```lua + root_pattern("*.opam", "esy.json", "package.json") + ``` + + +## ocamllsp + +https://github.com/ocaml/ocaml-lsp + +`ocaml-lsp` can be installed as described in [installation guide](https://github.com/ocaml/ocaml-lsp#installation). + +To install the lsp server in a particular opam switch: +```sh +opam pin add ocaml-lsp-server https://github.com/ocaml/ocaml-lsp.git +opam install ocaml-lsp-server +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.ocamllsp.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "ocamllsp" } + ``` + - `filetypes` : + ```lua + { "ocaml", "ocaml.menhir", "ocaml.interface", "ocaml.ocamllex", "reason" } + ``` + - `get_language_id` : + ```lua + see source file + ``` + - `root_dir` : + ```lua + root_pattern("*.opam", "esy.json", "package.json", ".git") + ``` + + +## ols + + https://github.com/DanielGavin/ols + + `Odin Language Server`. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.ols.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "ols" } + ``` + - `filetypes` : + ```lua + { "odin" } + ``` + - `root_dir` : + ```lua + util.root_pattern("ols.json", ".git") + ``` + - `single_file_support` : + ```lua + true + ``` + + +## omnisharp + +https://github.com/omnisharp/omnisharp-roslyn +OmniSharp server based on Roslyn workspaces + +`omnisharp-roslyn` can be installed by downloading and extracting a release from [here](https://github.com/OmniSharp/omnisharp-roslyn/releases). +Omnisharp can also be built from source by following the instructions [here](https://github.com/omnisharp/omnisharp-roslyn#downloading-omnisharp). + +Omnisharp requires the [dotnet-sdk](https://dotnet.microsoft.com/download) to be installed. + +**By default, omnisharp-roslyn doesn't have a `cmd` set.** This is because nvim-lspconfig does not make assumptions about your path. You must add the following to your init.vim or init.lua to set `cmd` to the absolute path ($HOME and ~ are not expanded) of the unzipped run script or binary. + +```lua +local pid = vim.fn.getpid() +-- On linux/darwin if using a release build, otherwise under scripts/OmniSharp(.Core)(.cmd) +local omnisharp_bin = "/path/to/omnisharp-repo/run" +-- on Windows +-- local omnisharp_bin = "/path/to/omnisharp/OmniSharp.exe" +require'lspconfig'.omnisharp.setup{ + cmd = { omnisharp_bin, "--languageserver" , "--hostPID", tostring(pid) }; + ... +} +``` + +Note, if you download the executable for darwin you will need to strip the quarantine label to run: +```bash +find /path/to/omnisharp-osx | xargs xattr -r -d com.apple.quarantine +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.omnisharp.setup{} +``` + + +**Default values:** + - `filetypes` : + ```lua + { "cs", "vb" } + ``` + - `init_options` : + ```lua + {} + ``` + - `on_new_config` : + ```lua + see source file + ``` + - `root_dir` : + ```lua + root_pattern(".sln") or root_pattern(".csproj") + ``` + + +## opencl_ls + +https://github.com/Galarius/opencl-language-server + +Build instructions can be found [here](https://github.com/Galarius/opencl-language-server/blob/main/_dev/build.md). + +Prebuilt binaries are available for Linux, macOS and Windows [here](https://github.com/Galarius/opencl-language-server/releases). + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.opencl_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "opencl-language-server" } + ``` + - `filetypes` : + ```lua + { "opencl" } + ``` + - `root_dir` : + ```lua + util.root_pattern(".git") + ``` + + +## openscad_ls + +https://github.com/dzhu/openscad-language-server + +A Language Server Protocol server for OpenSCAD + +You can build and install `openscad-language-server` binary with `cargo`: +```sh +cargo install openscad-language-server +``` + +Vim does not have built-in syntax for the `openscad` filetype currently. + +This can be added via an autocmd: + +```lua +vim.cmd [[ autocmd BufRead,BufNewFile *.scad set filetype=openscad ]] +``` + +or by installing a filetype plugin such as https://github.com/sirtaj/vim-openscad + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.openscad_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "openscad-language-server" } + ``` + - `filetypes` : + ```lua + { "openscad" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `single_file_support` : + ```lua + true + ``` + + +## pasls + +https://github.com/genericptr/pascal-language-server + +An LSP server implementation for Pascal variants that are supported by Free Pascal, including Object Pascal. It uses CodeTools from Lazarus as backend. + +First set `cmd` to the Pascal lsp binary. + +Customization options are passed to pasls as environment variables for example in your `.bashrc`: +```bash +export FPCDIR='/usr/lib/fpc/src' # FPC source directory (This is the only required option for the server to work). +export PP='/usr/lib/fpc/3.2.2/ppcx64' # Path to the Free Pascal compiler executable. +export LAZARUSDIR='/usr/lib/lazarus' # Path to the Lazarus sources. +export FPCTARGET='' # Target operating system for cross compiling. +export FPCTARGETCPU='x86_64' # Target CPU for cross compiling. +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.pasls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "pasls" } + ``` + - `filetypes` : + ```lua + { "pascal" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `single_file_support` : + ```lua + true + ``` + + +## perlls + +https://github.com/richterger/Perl-LanguageServer/tree/master/clients/vscode/perl + +`Perl-LanguageServer`, a language server for Perl. + +To use the language server, ensure that you have Perl::LanguageServer installed and perl command is on your path. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.perlls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "perl", "-MPerl::LanguageServer", "-e", "Perl::LanguageServer::run", "--", "--port 13603", "--nostdio 0", "--version 2.1.0" } + ``` + - `filetypes` : + ```lua + { "perl" } + ``` + - `root_dir` : + ```lua + vim's starting directory + ``` + - `settings` : + ```lua + { + perl = { + fileFilter = { ".pm", ".pl" }, + ignoreDirs = ".git", + perlCmd = "perl", + perlInc = " " + } + } + ``` + - `single_file_support` : + ```lua + true + ``` + + +## perlnavigator + +https://github.com/bscan/PerlNavigator + +A Perl language server + +**By default, perlnavigator doesn't have a `cmd` set.** This is because nvim-lspconfig does not make assumptions about your path. +You have to install the language server manually. + +Clone the PerlNavigator repo, install based on the [instructions](https://github.com/bscan/PerlNavigator#installation-for-other-editors), +and point `cmd` to `server.js` inside the `server/out` directory: + +```lua +cmd = {'node', '/server/out/server.js', '--stdio'} +``` + +At minimum, you will need `perl` in your path. If you want to use a non-standard `perl` you will need to set your configuration like so: +```lua +settings = { + perlnavigator = { + perlPath = '/some/odd/location/my-perl' + } +} +``` + +The `contributes.configuration.properties` section of `perlnavigator`'s `package.json` has all available configuration settings. All +settings have a reasonable default, but, at minimum, you may want to point `perlnavigator` at your `perltidy` and `perlcritic` configurations. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.perlnavigator.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + {} + ``` + - `filetypes` : + ```lua + { "perl" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `single_file_support` : + ```lua + true + ``` + + +## perlpls + +https://github.com/FractalBoy/perl-language-server +https://metacpan.org/pod/PLS + +`PLS`, another language server for Perl. + +To use the language server, ensure that you have PLS installed and that it is in your path + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.perlpls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "pls" } + ``` + - `filetypes` : + ```lua + { "perl" } + ``` + - `root_dir` : + ```lua + util.find_git_ancestor + ``` + - `settings` : + ```lua + { + perl = { + perlcritic = { + enabled = false + }, + syntax = { + enabled = true + } + } + } + ``` + - `single_file_support` : + ```lua + true + ``` + + +## phpactor + +https://github.com/phpactor/phpactor + +Installation: https://phpactor.readthedocs.io/en/master/usage/standalone.html#global-installation + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.phpactor.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "phpactor", "language-server" } + ``` + - `filetypes` : + ```lua + { "php" } + ``` + - `root_dir` : + ```lua + root_pattern("composer.json", ".git") + ``` + + +## please + +https://github.com/thought-machine/please + +High-performance extensible build system for reproducible multi-language builds. + +The `plz` binary will automatically install the LSP for you on first run + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.please.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "plz", "tool", "lps" } + ``` + - `filetypes` : + ```lua + { "bzl" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `single_file_support` : + ```lua + true + ``` + + +## powershell_es + +https://github.com/PowerShell/PowerShellEditorServices + +Language server for PowerShell. + +To install, download and extract PowerShellEditorServices.zip +from the [releases](https://github.com/PowerShell/PowerShellEditorServices/releases). +To configure the language server, set the property `bundle_path` to the root +of the extracted PowerShellEditorServices.zip. + +The default configuration doesn't set `cmd` unless `bundle_path` is specified. + +```lua +require'lspconfig'.powershell_es.setup{ + bundle_path = 'c:/w/PowerShellEditorServices', +} +``` + +By default the languageserver is started in `pwsh` (PowerShell Core). This can be changed by specifying `shell`. + +```lua +require'lspconfig'.powershell_es.setup{ + bundle_path = 'c:/w/PowerShellEditorServices', + shell = 'powershell.exe', +} +``` + +Note that the execution policy needs to be set to `Unrestricted` for the languageserver run under PowerShell + +If necessary, specific `cmd` can be defined instead of `bundle_path`. +See [PowerShellEditorServices](https://github.com/PowerShell/PowerShellEditorServices#stdio) +to learn more. + +```lua +require'lspconfig'.powershell_es.setup{ + cmd = {'pwsh', '-NoLogo', '-NoProfile', '-Command', "c:/PSES/Start-EditorServices.ps1 ..."} +} +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.powershell_es.setup{} +``` + + +**Default values:** + - `filetypes` : + ```lua + { "ps1" } + ``` + - `on_new_config` : + ```lua + see source file + ``` + - `root_dir` : + ```lua + git root or current directory + ``` + - `shell` : + ```lua + "pwsh" + ``` + - `single_file_support` : + ```lua + true + ``` + + +## prismals + +Language Server for the Prisma JavaScript and TypeScript ORM + +`@prisma/language-server` can be installed via npm +```sh +npm install -g @prisma/language-server +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.prismals.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "prisma-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "prisma" } + ``` + - `root_dir` : + ```lua + root_pattern(".git", "package.json") + ``` + - `settings` : + ```lua + { + prisma = { + prismaFmtBinPath = "" + } + } + ``` + + +## prosemd_lsp + +https://github.com/kitten/prosemd-lsp + +An experimental LSP for Markdown. + +Please see the manual installation instructions: https://github.com/kitten/prosemd-lsp#manual-installation + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.prosemd_lsp.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "prosemd-lsp", "--stdio" } + ``` + - `filetypes` : + ```lua + { "markdown" } + ``` + - `root_dir` : + ```lua + + ``` + - `single_file_support` : + ```lua + true + ``` + + +## psalm + +https://github.com/vimeo/psalm + +Can be installed with composer. +```sh +composer global require vimeo/psalm +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.psalm.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "psalm-language-server" } + ``` + - `filetypes` : + ```lua + { "php" } + ``` + - `root_dir` : + ```lua + root_pattern("psalm.xml", "psalm.xml.dist") + ``` + + +## puppet + +LSP server for Puppet. + +Installation: + +- Clone the editor-services repository: + https://github.com/puppetlabs/puppet-editor-services + +- Navigate into that directory and run: `bundle install` + +- Install the 'puppet-lint' gem: `gem install puppet-lint` + +- Add that repository to $PATH. + +- Ensure you can run `puppet-languageserver` from outside the editor-services directory. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.puppet.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "puppet-languageserver", "--stdio" } + ``` + - `filetypes` : + ```lua + { "puppet" } + ``` + - `root_dir` : + ```lua + root_pattern("manifests", ".puppet-lint.rc", "hiera.yaml", ".git") + ``` + - `single_file_support` : + ```lua + true + ``` + + +## purescriptls + +https://github.com/nwolverson/purescript-language-server +`purescript-language-server` can be installed via `npm` +```sh +npm install -g purescript-language-server +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.purescriptls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "purescript-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "purescript" } + ``` + - `root_dir` : + ```lua + root_pattern("spago.dhall, 'psc-package.json', bower.json") + ``` + + +## pylsp + +https://github.com/python-lsp/python-lsp-server + +A Python 3.6+ implementation of the Language Server Protocol. + +The language server can be installed via `pipx install 'python-lsp-server[all]'`. +Further instructions can be found in the [project's README](https://github.com/python-lsp/python-lsp-server). + +Note: This is a community fork of `pyls`. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.pylsp.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "pylsp" } + ``` + - `filetypes` : + ```lua + { "python" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `single_file_support` : + ```lua + true + ``` + + +## pyre + +https://pyre-check.org/ + +`pyre` a static type checker for Python 3. + +`pyre` offers an extremely limited featureset. It currently only supports diagnostics, +which are triggered on save. + +Do not report issues for missing features in `pyre` to `lspconfig`. + + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.pyre.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "pyre", "persistent" } + ``` + - `filetypes` : + ```lua + { "python" } + ``` + - `root_dir` : + ```lua + see source file + ``` + + +## pyright + +https://github.com/microsoft/pyright + +`pyright`, a static type checker and language server for python + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.pyright.setup{} +``` +**Commands:** +- PyrightOrganizeImports: Organize Imports + +**Default values:** + - `cmd` : + ```lua + { "pyright-langserver", "--stdio" } + ``` + - `filetypes` : + ```lua + { "python" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `settings` : + ```lua + { + python = { + analysis = { + autoSearchPaths = true, + diagnosticMode = "workspace", + useLibraryCodeForTypes = true + } + } + } + ``` + - `single_file_support` : + ```lua + true + ``` + + +## quick_lint_js + +https://quick-lint-js.com/ + +quick-lint-js finds bugs in JavaScript programs. + +See installation [instructions](https://quick-lint-js.com/install/) + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.quick_lint_js.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "quick-lint-js", "--lsp-server" } + ``` + - `filetypes` : + ```lua + { "javascript" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `single_file_support` : + ```lua + true + ``` + + +## r_language_server + +[languageserver](https://github.com/REditorSupport/languageserver) is an +implementation of the Microsoft's Language Server Protocol for the R +language. + +It is released on CRAN and can be easily installed by + +```R +install.packages("languageserver") +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.r_language_server.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "R", "--slave", "-e", "languageserver::run()" } + ``` + - `filetypes` : + ```lua + { "r", "rmd" } + ``` + - `log_level` : + ```lua + 2 + ``` + - `root_dir` : + ```lua + root_pattern(".git") or os_homedir + ``` + + +## racket_langserver + +[https://github.com/jeapostrophe/racket-langserver](https://github.com/jeapostrophe/racket-langserver) + +The Racket language server. This project seeks to use +[DrRacket](https://github.com/racket/drracket)'s public API to provide +functionality that mimics DrRacket's code tools as closely as possible. + +Install via `raco`: `raco pkg install racket-langserver` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.racket_langserver.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "racket", "--lib", "racket-langserver" } + ``` + - `filetypes` : + ```lua + { "racket", "scheme" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `single_file_support` : + ```lua + true + ``` + + +## reason_ls + +Reason language server + +**By default, reason_ls doesn't have a `cmd` set.** This is because nvim-lspconfig does not make assumptions about your path. +You have to install the language server manually. + +You can install reason language server from [reason-language-server](https://github.com/jaredly/reason-language-server) repository. + +```lua +cmd = {''} +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.reason_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "reason-language-server" } + ``` + - `filetypes` : + ```lua + { "reason" } + ``` + - `root_dir` : + ```lua + see source file + ``` + + +## remark_ls + +https://github.com/remarkjs/remark-language-server + +`remark-language-server` can be installed via `npm`: +```sh +npm install -g remark-language-server +``` + +`remark-language-server` uses the same +[configuration files](https://github.com/remarkjs/remark/tree/main/packages/remark-cli#example-config-files-json-yaml-js) +as `remark-cli`. + +This uses a plugin based system. Each plugin needs to be installed locally using `npm` or `yarn`. + +For example, given the following `.remarkrc.json`: + +```json +{ + "presets": [ + "remark-preset-lint-recommended" + ] +} +``` + +`remark-preset-lint-recommended` needs to be installed in the local project: + +```sh +npm install remark-preset-lint-recommended +``` + + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.remark_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "remark-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "markdown" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `single_file_support` : + ```lua + true + ``` + + +## rescriptls + +https://github.com/rescript-lang/rescript-vscode + +ReScript language server + +**By default, rescriptls doesn't have a `cmd` set.** This is because nvim-lspconfig does not make assumptions about your path. +You have to install the language server manually. + +You can use the bundled language server inside the [vim-rescript](https://github.com/rescript-lang/vim-rescript) repo. + +Clone the vim-rescript repo and point `cmd` to `server.js` inside `server/out` directory: + +```lua +cmd = {'node', '/server/out/server.js', '--stdio'} + +``` + +If you have vim-rescript installed you can also use that installation. for example if you're using packer.nvim you can set cmd to something like this: + +```lua +cmd = { + 'node', + '/home/username/.local/share/nvim/site/pack/packer/start/vim-rescript/server/out/server.js', + '--stdio' +} +``` + +Another option is to use vscode extension [release](https://github.com/rescript-lang/rescript-vscode/releases). +Take a look at [here](https://github.com/rescript-lang/rescript-vscode#use-with-other-editors) for instructions. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.rescriptls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + {} + ``` + - `filetypes` : + ```lua + { "rescript" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `settings` : + ```lua + {} + ``` + + +## rls + +https://github.com/rust-lang/rls + +rls, a language server for Rust + +See https://github.com/rust-lang/rls#setup to setup rls itself. +See https://github.com/rust-lang/rls#configuration for rls-specific settings. +All settings listed on the rls configuration section of the readme +must be set under settings.rust as follows: + +```lua +nvim_lsp.rls.setup { + settings = { + rust = { + unstable_features = true, + build_on_save = false, + all_features = true, + }, + }, +} +``` + +If you want to use rls for a particular build, eg nightly, set cmd as follows: + +```lua +cmd = {"rustup", "run", "nightly", "rls"} +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.rls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "rls" } + ``` + - `filetypes` : + ```lua + { "rust" } + ``` + - `root_dir` : + ```lua + root_pattern("Cargo.toml") + ``` + + +## rnix + +https://github.com/nix-community/rnix-lsp + +A language server for Nix providing basic completion and formatting via nixpkgs-fmt. + +To install manually, run `cargo install rnix-lsp`. If you are using nix, rnix-lsp is in nixpkgs. + +This server accepts configuration via the `settings` key. + + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.rnix.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "rnix-lsp" } + ``` + - `filetypes` : + ```lua + { "nix" } + ``` + - `init_options` : + ```lua + {} + ``` + - `root_dir` : + ```lua + vim's starting directory + ``` + - `settings` : + ```lua + {} + ``` + + +## robotframework_ls + +https://github.com/robocorp/robotframework-lsp + +Language Server Protocol implementation for Robot Framework. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.robotframework_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "robotframework_ls" } + ``` + - `filetypes` : + ```lua + { "robot" } + ``` + - `root_dir` : + ```lua + util.root_pattern('robotidy.toml', 'pyproject.toml')(fname) or util.find_git_ancestor(fname) + ``` + + +## rome + +https://rome.tools + +Language server for the Rome Frontend Toolchain. + +```sh +npm install [-g] rome +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.rome.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "rome", "lsp" } + ``` + - `filetypes` : + ```lua + { "javascript", "javascriptreact", "json", "typescript", "typescript.tsx", "typescriptreact" } + ``` + - `root_dir` : + ```lua + root_pattern('package.json', 'node_modules', '.git') + ``` + - `single_file_support` : + ```lua + true + ``` + + +## rust_analyzer + +https://github.com/rust-analyzer/rust-analyzer + +rust-analyzer (aka rls 2.0), a language server for Rust + +See [docs](https://github.com/rust-analyzer/rust-analyzer/tree/master/docs/user#settings) for extra settings. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.rust_analyzer.setup{} +``` +**Commands:** +- CargoReload: Reload current cargo workspace + +**Default values:** + - `cmd` : + ```lua + { "rust-analyzer" } + ``` + - `filetypes` : + ```lua + { "rust" } + ``` + - `root_dir` : + ```lua + root_pattern("Cargo.toml", "rust-project.json") + ``` + - `settings` : + ```lua + { + ["rust-analyzer"] = {} + } + ``` + + +## salt_ls + +Language server for Salt configuration files. +https://github.com/dcermak/salt-lsp + +The language server can be installed with `pip`: +```sh +pip install salt-lsp +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.salt_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "salt_lsp_server" } + ``` + - `filetypes` : + ```lua + { "sls" } + ``` + - `root_dir` : + ```lua + root_pattern('.git') + ``` + - `single_file_support` : + ```lua + true + ``` + + +## scry + +https://github.com/crystal-lang-tools/scry + +Crystal language server. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.scry.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "scry" } + ``` + - `filetypes` : + ```lua + { "crystal" } + ``` + - `root_dir` : + ```lua + root_pattern('shard.yml', '.git') + ``` + - `single_file_support` : + ```lua + true + ``` + + +## serve_d + + https://github.com/Pure-D/serve-d + + `Microsoft language server protocol implementation for D using workspace-d.` + Download a binary from https://github.com/Pure-D/serve-d/releases and put it in your $PATH. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.serve_d.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "serve-d" } + ``` + - `filetypes` : + ```lua + { "d" } + ``` + - `root_dir` : + ```lua + util.root_pattern("dub.json", "dub.sdl", ".git") + ``` + + +## sixtyfps + +https://github.com/sixtyfpsui/sixtyfps +`SixtyFPS`'s language server + +You can build and install `sixtyfps-lsp` binary with `cargo`: +```sh +cargo install sixtyfps-lsp +``` + +Vim does not have built-in syntax for the `sixtyfps` filetype currently. + +This can be added via an autocmd: + +```lua +vim.cmd [[ autocmd BufRead,BufNewFile *.60 set filetype=sixtyfps ]] +``` + +or by installing a filetype plugin such as https://github.com/RustemB/sixtyfps-vim + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.sixtyfps.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "sixtyfps-lsp" } + ``` + - `filetypes` : + ```lua + { "sixtyfps" } + ``` + - `single_file_support` : + ```lua + true + ``` + + +## slint_lsp + +https://github.com/slint-ui/slint +`Slint`'s language server + +You can build and install `slint-lsp` binary with `cargo`: +```sh +cargo install slint-lsp +``` + +Vim does not have built-in syntax for the `slint` filetype at this time. + +This can be added via an autocmd: + +```lua +vim.cmd [[ autocmd BufRead,BufNewFile *.slint set filetype=slint ]] +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.slint_lsp.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "slint-lsp" } + ``` + - `filetypes` : + ```lua + { "slint" } + ``` + - `single_file_support` : + ```lua + true + ``` + + +## solang + +A language server for Solidity + +See the [documentation](https://solang.readthedocs.io/en/latest/installing.html) for installation instructions. + +The language server only provides the following capabilities: +* Syntax highlighting +* Diagnostics +* Hover + +There is currently no support for completion, goto definition, references, or other functionality. + + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.solang.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "solang", "--language-server", "--target", "ewasm" } + ``` + - `filetypes` : + ```lua + { "solidity" } + ``` + - `root_dir` : + ```lua + util.find_git_ancestor + ``` + + +## solargraph + +https://solargraph.org/ + +solargraph, a language server for Ruby + +You can install solargraph via gem install. + +```sh +gem install --user-install solargraph +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.solargraph.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "solargraph", "stdio" } + ``` + - `filetypes` : + ```lua + { "ruby" } + ``` + - `init_options` : + ```lua + { + formatting = true + } + ``` + - `root_dir` : + ```lua + root_pattern("Gemfile", ".git") + ``` + - `settings` : + ```lua + { + solargraph = { + diagnostics = true + } + } + ``` + + +## solc + +https://docs.soliditylang.org/en/latest/installing-solidity.html + +solc is the native language server for the Solidity language. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.solc.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "solc", "--lsp" } + ``` + - `filetypes` : + ```lua + { "solidity" } + ``` + - `root_dir` : + ```lua + root_pattern(".git") + ``` + + +## solidity_ls + +npm install -g solidity-language-server + +solidity-language-server is a language server for the solidity language ported from the vscode solidity extension + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.solidity_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "solidity-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "solidity" } + ``` + - `root_dir` : + ```lua + root_pattern(".git", "package.json") + ``` + + +## sorbet + +https://sorbet.org + +Sorbet is a fast, powerful type checker designed for Ruby. + +You can install Sorbet via gem install. You might also be interested in how to set +Sorbet up for new projects: https://sorbet.org/docs/adopting. + +```sh +gem install sorbet +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.sorbet.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "srb", "tc", "--lsp" } + ``` + - `filetypes` : + ```lua + { "ruby" } + ``` + - `root_dir` : + ```lua + root_pattern("Gemfile", ".git") + ``` + + +## sourcekit + +https://github.com/apple/sourcekit-lsp + +Language server for Swift and C/C++/Objective-C. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.sourcekit.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "sourcekit-lsp" } + ``` + - `filetypes` : + ```lua + { "swift", "c", "cpp", "objective-c", "objective-cpp" } + ``` + - `root_dir` : + ```lua + root_pattern("Package.swift", ".git") + ``` + + +## sourcery + +https://github.com/sourcery-ai/sourcery + +Refactor Python instantly using the power of AI. + +It requires the initializationOptions param to be populated as shown below and will respond with the list of ServerCapabilities that it supports. + +init_options = { + --- The Sourcery token for authenticating the user. + --- This is retrieved from the Sourcery website and must be + --- provided by each user. The extension must provide a + --- configuration option for the user to provide this value. + token = + + --- The extension's name and version as defined by the extension. + extension_version = 'vim.lsp' + + --- The editor's name and version as defined by the editor. + editor_version = 'vim' +} + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.sourcery.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "sourcery", "lsp" } + ``` + - `filetypes` : + ```lua + { "python" } + ``` + - `init_options` : + ```lua + { + editor_version = "vim", + extension_version = "vim.lsp" + } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `single_file_support` : + ```lua + true + ``` + + +## spectral + +https://github.com/luizcorreia/spectral-language-server + `A flexible JSON/YAML linter for creating automated style guides, with baked in support for OpenAPI v2 & v3.` + +`spectral-language-server` can be installed via `npm`: +```sh +npm i -g spectral-language-server +``` +See [vscode-spectral](https://github.com/stoplightio/vscode-spectral#extension-settings) for configuration options. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.spectral.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "spectral-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "yaml", "json", "yml" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `settings` : + ```lua + { + enable = true, + run = "onType", + validateLanguages = { "yaml", "json", "yml" } + } + ``` + - `single_file_support` : + ```lua + true + ``` + + +## sqlls + +https://github.com/joe-re/sql-language-server + +This LSP can be installed via `npm`. Find further instructions on manual installation of the sql-language-server at [joe-re/sql-language-server](https://github.com/joe-re/sql-language-server). +
+ + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.sqlls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "sql-language-server", "up", "--method", "stdio" } + ``` + - `filetypes` : + ```lua + { "sql", "mysql" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `settings` : + ```lua + {} + ``` + + +## sqls + +https://github.com/lighttiger2505/sqls + +```lua +require'lspconfig'.sqls.setup{ + cmd = {"path/to/command", "-config", "path/to/config.yml"}; + ... +} +``` +Sqls can be installed via `go get github.com/lighttiger2505/sqls`. Instructions for compiling Sqls from the source can be found at [lighttiger2505/sqls](https://github.com/lighttiger2505/sqls). + + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.sqls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "sqls" } + ``` + - `filetypes` : + ```lua + { "sql", "mysql" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `settings` : + ```lua + {} + ``` + - `single_file_support` : + ```lua + true + ``` + + +## stylelint_lsp + +https://github.com/bmatcuk/stylelint-lsp + +`stylelint-lsp` can be installed via `npm`: + +```sh +npm i -g stylelint-lsp +``` + +Can be configured by passing a `settings.stylelintplus` object to `stylelint_lsp.setup`: + +```lua +require'lspconfig'.stylelint_lsp.setup{ + settings = { + stylelintplus = { + -- see available options in stylelint-lsp documentation + } + } +} +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.stylelint_lsp.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "stylelint-lsp", "--stdio" } + ``` + - `filetypes` : + ```lua + { "css", "less", "scss", "sugarss", "vue", "wxss", "javascript", "javascriptreact", "typescript", "typescriptreact" } + ``` + - `root_dir` : + ```lua + root_pattern('.stylelintrc', 'package.json') + ``` + - `settings` : + ```lua + {} + ``` + + +## sumneko_lua + +https://github.com/sumneko/lua-language-server + +Lua language server. + +`lua-language-server` can be installed by following the instructions [here](https://github.com/sumneko/lua-language-server/wiki/Build-and-Run). The default `cmd` assumes that the `lua-language-server` binary can be found in `$PATH`. + +```lua +local runtime_path = vim.split(package.path, ';') +table.insert(runtime_path, "lua/?.lua") +table.insert(runtime_path, "lua/?/init.lua") + +require'lspconfig'.sumneko_lua.setup { + settings = { + Lua = { + runtime = { + -- Tell the language server which version of Lua you're using (most likely LuaJIT in the case of Neovim) + version = 'LuaJIT', + -- Setup your lua path + path = runtime_path, + }, + diagnostics = { + -- Get the language server to recognize the `vim` global + globals = {'vim'}, + }, + workspace = { + -- Make the server aware of Neovim runtime files + library = vim.api.nvim_get_runtime_file("", true), + }, + -- Do not send telemetry data containing a randomized but unique identifier + telemetry = { + enable = false, + }, + }, + }, +} +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.sumneko_lua.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "lua-language-server" } + ``` + - `filetypes` : + ```lua + { "lua" } + ``` + - `log_level` : + ```lua + 2 + ``` + - `root_dir` : + ```lua + root_pattern(".luarc.json", ".luacheckrc", ".stylua.toml", "selene.toml", ".git") + ``` + - `settings` : + ```lua + { + Lua = { + telemetry = { + enable = false + } + } + } + ``` + - `single_file_support` : + ```lua + true + ``` + + +## svelte + +https://github.com/sveltejs/language-tools/tree/master/packages/language-server + +`svelte-language-server` can be installed via `npm`: +```sh +npm install -g svelte-language-server +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.svelte.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "svelteserver", "--stdio" } + ``` + - `filetypes` : + ```lua + { "svelte" } + ``` + - `root_dir` : + ```lua + root_pattern("package.json", ".git") + ``` + + +## svls + +https://github.com/dalance/svls + +Language server for verilog and SystemVerilog + +`svls` can be installed via `cargo`: + ```sh + cargo install svls + ``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.svls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "svls" } + ``` + - `filetypes` : + ```lua + { "verilog", "systemverilog" } + ``` + - `root_dir` : + ```lua + util.find_git_ancestor + ``` + + +## tailwindcss + +https://github.com/tailwindlabs/tailwindcss-intellisense + +Tailwind CSS Language Server can be installed via npm: +```sh +npm install -g @tailwindcss/language-server +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.tailwindcss.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "tailwindcss-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "aspnetcorerazor", "astro", "astro-markdown", "blade", "django-html", "htmldjango", "edge", "eelixir", "ejs", "erb", "eruby", "gohtml", "haml", "handlebars", "hbs", "html", "html-eex", "heex", "jade", "leaf", "liquid", "markdown", "mdx", "mustache", "njk", "nunjucks", "php", "razor", "slim", "twig", "css", "less", "postcss", "sass", "scss", "stylus", "sugarss", "javascript", "javascriptreact", "reason", "rescript", "typescript", "typescriptreact", "vue", "svelte" } + ``` + - `init_options` : + ```lua + { + userLanguages = { + eelixir = "html-eex", + eruby = "erb" + } + } + ``` + - `on_new_config` : + ```lua + see source file + ``` + - `root_dir` : + ```lua + root_pattern('tailwind.config.js', 'tailwind.config.ts', 'postcss.config.js', 'postcss.config.ts', 'package.json', 'node_modules', '.git') + ``` + - `settings` : + ```lua + { + tailwindCSS = { + classAttributes = { "class", "className", "classList", "ngClass" }, + lint = { + cssConflict = "warning", + invalidApply = "error", + invalidConfigPath = "error", + invalidScreen = "error", + invalidTailwindDirective = "error", + invalidVariant = "error", + recommendedVariantOrder = "warning" + }, + validate = true + } + } + ``` + + +## taplo + +https://taplo.tamasfe.dev/lsp/ + +Language server for Taplo, a TOML toolkit. + +`taplo-cli` can be installed via `cargo`: +```sh +cargo install --locked taplo-cli +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.taplo.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "taplo", "lsp", "stdio" } + ``` + - `filetypes` : + ```lua + { "toml" } + ``` + - `root_dir` : + ```lua + root_pattern("*.toml", ".git") + ``` + - `single_file_support` : + ```lua + true + ``` + + +## teal_ls + +https://github.com/teal-language/teal-language-server + +Install with: +``` +luarocks install --dev teal-language-server +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.teal_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "teal-language-server" } + ``` + - `filetypes` : + ```lua + { "teal" } + ``` + - `root_dir` : + ```lua + root_pattern("tlconfig.lua", ".git") + ``` + + +## terraform_lsp + +https://github.com/juliosueiras/terraform-lsp + +Terraform language server +Download a released binary from +https://github.com/juliosueiras/terraform-lsp/releases. + +From https://github.com/hashicorp/terraform-ls#terraform-ls-vs-terraform-lsp: + +Both HashiCorp and the maintainer of terraform-lsp expressed interest in +collaborating on a language server and are working towards a _long-term_ +goal of a single stable and feature-complete implementation. + +For the time being both projects continue to exist, giving users the +choice: + +- `terraform-ls` providing + - overall stability (by relying only on public APIs) + - compatibility with any provider and any Terraform >=0.12.0 currently + less features + - due to project being younger and relying on public APIs which may + not offer the same functionality yet + +- `terraform-lsp` providing + - currently more features + - compatibility with a single particular Terraform (0.12.20 at time of writing) + - configs designed for other 0.12 versions may work, but interpretation may be inaccurate + - less stability (due to reliance on Terraform's own internal packages) + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.terraform_lsp.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "terraform-lsp" } + ``` + - `filetypes` : + ```lua + { "terraform", "hcl" } + ``` + - `root_dir` : + ```lua + root_pattern(".terraform", ".git") + ``` + + +## terraformls + +https://github.com/hashicorp/terraform-ls + +Terraform language server +Download a released binary from https://github.com/hashicorp/terraform-ls/releases. + +From https://github.com/hashicorp/terraform-ls#terraform-ls-vs-terraform-lsp: + +Both HashiCorp and the maintainer of terraform-lsp expressed interest in +collaborating on a language server and are working towards a _long-term_ +goal of a single stable and feature-complete implementation. + +For the time being both projects continue to exist, giving users the +choice: + +- `terraform-ls` providing + - overall stability (by relying only on public APIs) + - compatibility with any provider and any Terraform >=0.12.0 currently + less features + - due to project being younger and relying on public APIs which may + not offer the same functionality yet + +- `terraform-lsp` providing + - currently more features + - compatibility with a single particular Terraform (0.12.20 at time of writing) + - configs designed for other 0.12 versions may work, but interpretation may be inaccurate + - less stability (due to reliance on Terraform's own internal packages) + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.terraformls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "terraform-ls", "serve" } + ``` + - `filetypes` : + ```lua + { "terraform" } + ``` + - `root_dir` : + ```lua + root_pattern(".terraform", ".git") + ``` + + +## texlab + +https://github.com/latex-lsp/texlab + +A completion engine built from scratch for (La)TeX. + +See https://github.com/latex-lsp/texlab/blob/master/docs/options.md for configuration options. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.texlab.setup{} +``` +**Commands:** +- TexlabBuild: Build the current buffer +- TexlabForward: Forward search from current position + +**Default values:** + - `cmd` : + ```lua + { "texlab" } + ``` + - `filetypes` : + ```lua + { "tex", "bib" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `settings` : + ```lua + { + texlab = { + auxDirectory = ".", + bibtexFormatter = "texlab", + build = { + args = { "-pdf", "-interaction=nonstopmode", "-synctex=1", "%f" }, + executable = "latexmk", + forwardSearchAfter = false, + onSave = false + }, + chktex = { + onEdit = false, + onOpenAndSave = false + }, + diagnosticsDelay = 300, + formatterLineLength = 80, + forwardSearch = { + args = {} + }, + latexFormatter = "latexindent", + latexindent = { + modifyLineBreaks = false + } + } + } + ``` + - `single_file_support` : + ```lua + true + ``` + + +## tflint + +https://github.com/terraform-linters/tflint + +A pluggable Terraform linter that can act as lsp server. +Installation instructions can be found in https://github.com/terraform-linters/tflint#installation. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.tflint.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "tflint", "--langserver" } + ``` + - `filetypes` : + ```lua + { "terraform" } + ``` + - `root_dir` : + ```lua + root_pattern(".terraform", ".git", ".tflint.hcl") + ``` + + +## theme_check + +https://github.com/Shopify/shopify-cli + +`theme-check-language-server` is bundled with `shopify-cli` or it can also be installed via + +https://github.com/Shopify/theme-check#installation + +**NOTE:** +If installed via Homebrew, `cmd` must be set to 'theme-check-liquid-server' + +```lua +require lspconfig.theme_check.setup { + cmd = { 'theme-check-liquid-server' } +} +``` + + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.theme_check.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "theme-check-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "liquid" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `settings` : + ```lua + {} + ``` + + +## tsserver + +https://github.com/theia-ide/typescript-language-server + +`typescript-language-server` depends on `typescript`. Both packages can be installed via `npm`: +```sh +npm install -g typescript typescript-language-server +``` + +To configure type language server, add a +[`tsconfig.json`](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html) or +[`jsconfig.json`](https://code.visualstudio.com/docs/languages/jsconfig) to the root of your +project. + +Here's an example that disables type checking in JavaScript files. + +```json +{ + "compilerOptions": { + "module": "commonjs", + "target": "es6", + "checkJs": false + }, + "exclude": [ + "node_modules" + ] +} +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.tsserver.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "typescript-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "javascript", "javascriptreact", "javascript.jsx", "typescript", "typescriptreact", "typescript.tsx" } + ``` + - `init_options` : + ```lua + { + hostInfo = "neovim" + } + ``` + - `root_dir` : + ```lua + root_pattern("package.json", "tsconfig.json", "jsconfig.json", ".git") + ``` + + +## typeprof + +https://github.com/ruby/typeprof + +`typeprof` is the built-in analysis and LSP tool for Ruby 3.1+. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.typeprof.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "typeprof", "--lsp", "--stdio" } + ``` + - `filetypes` : + ```lua + { "ruby", "eruby" } + ``` + - `root_dir` : + ```lua + root_pattern("Gemfile", ".git") + ``` + + +## vala_ls + +https://github.com/Prince781/vala-language-server + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.vala_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "vala-language-server" } + ``` + - `filetypes` : + ```lua + { "vala", "genie" } + ``` + - `root_dir` : + ```lua + root_pattern("meson.build", ".git") + ``` + - `single_file_support` : + ```lua + true + ``` + + +## vdmj + +https://github.com/nickbattle/vdmj + +The VDMJ language server can be installed by cloning the VDMJ repository and +running `mvn clean install`. + +Various options are provided to configure the language server (see below). In +particular: +- `annotation_paths` is a list of folders and/or jar file paths for annotations +that should be used with the language server; +- any value of `debugger_port` less than zero will disable the debugger; note +that if a non-zero value is used, only one instance of the server can be active +at a time. + +More settings for VDMJ can be changed in a file called `vdmj.properties` under +`root_dir/.vscode`. For a description of the available settings, see +[Section 7 of the VDMJ User Guide](https://raw.githubusercontent.com/nickbattle/vdmj/master/vdmj/documentation/UserGuide.pdf). + +Note: proof obligations and combinatorial testing are not currently supported +by neovim. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.vdmj.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + Generated from the options given + ``` + - `filetypes` : + ```lua + { "vdmsl", "vdmpp", "vdmrt" } + ``` + - `options` : + ```lua + { + annotation_paths = {}, + debugger_port = -1, + high_precision = false, + java = "$JAVA_HOME/bin/java", + java_opts = { "-Xmx3000m", "-Xss1m" }, + logfile = "path.join(vim.fn.stdpath 'cache', 'vdm-lsp.log')", + mavenrepo = "$HOME/.m2/repository/com/fujitsu", + version = "The latest version installed in `mavenrepo`" + } + ``` + - `root_dir` : + ```lua + util.find_git_ancestor(fname) or find_vscode_ancestor(fname) + ``` + + +## verible + +https://github.com/chipsalliance/verible + +A linter and formatter for verilog and SystemVerilog files. + +Release binaries can be downloaded from [here](https://github.com/chipsalliance/verible/releases) +and placed in a directory on PATH. + +See https://github.com/chipsalliance/verible/tree/master/verilog/tools/ls/README.md for options. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.verible.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "verible-verilog-ls" } + ``` + - `filetypes` : + ```lua + { "systemverilog", "verilog" } + ``` + - `root_dir` : + ```lua + see source file + ``` + + +## vimls + +https://github.com/iamcco/vim-language-server + +You can install vim-language-server via npm: +```sh +npm install -g vim-language-server +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.vimls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "vim-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "vim" } + ``` + - `init_options` : + ```lua + { + diagnostic = { + enable = true + }, + indexes = { + count = 3, + gap = 100, + projectRootPatterns = { "runtime", "nvim", ".git", "autoload", "plugin" }, + runtimepath = true + }, + iskeyword = "@,48-57,_,192-255,-#", + runtimepath = "", + suggest = { + fromRuntimepath = true, + fromVimruntime = true + }, + vimruntime = "" + } + ``` + - `root_dir` : + ```lua + see source file + ``` + + +## vls + +https://github.com/vlang/vls + +V language server. + +`v-language-server` can be installed by following the instructions [here](https://github.com/vlang/vls#installation). + +**By default, v-language-server doesn't have a `cmd` set.** This is because nvim-lspconfig does not make assumptions about your path. You must add the following to your init.vim or init.lua to set `cmd` to the absolute path ($HOME and ~ are not expanded) of your unzipped and compiled v-language-server. + +```lua +-- set the path to the vls installation; +local vls_root_path = vim.fn.stdpath('cache')..'/lspconfig/vls' +local vls_binary = vls_root_path.."/cmd/vls/vls" + +require'lspconfig'.vls.setup { + cmd = {vls_binary}, +} +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.vls.setup{} +``` + + +**Default values:** + - `filetypes` : + ```lua + { "vlang" } + ``` + - `root_dir` : + ```lua + root_pattern("v.mod", ".git") + ``` + + +## volar + +https://github.com/johnsoncodehk/volar/tree/master/packages/vue-language-server + +Volar language server for Vue + +Volar can be installed via npm: + +```sh +npm install -g @volar/vue-language-server +``` + +Volar by default supports Vue 3 projects. Vue 2 projects need [additional configuration](https://github.com/johnsoncodehk/volar/blob/master/extensions/vscode-vue-language-features/README.md?plain=1#L28-L63). + +**Take Over Mode** +Volar can serve as a language server for both Vue and TypeScript via [Take Over Mode](https://github.com/johnsoncodehk/volar/discussions/471). + +To enable Take Over Mode, override the default filetypes in `setup{}` as follows: + +```lua +require'lspconfig'.volar.setup{ + filetypes = {'typescript', 'javascript', 'javascriptreact', 'typescriptreact', 'vue', 'json'} +} +``` + +**Overriding the default TypeScript Server used by Volar** +The default config looks for TS in the local node_modules. The alternatives are: + +- use a global TypeScript Server installation + +```lua +require'lspconfig'.volar.setup{ + init_options = { + typescript = { + serverPath = '/path/to/.npm/lib/node_modules/typescript/lib/tsserverlib.js' + } + } +} +``` + +- use a global TypeScript Server installation if a local server is not found + +```lua +local util = require 'lspconfig.util' + +local function get_typescript_server_path(root_dir) + local project_root = util.find_node_modules_ancestor(root_dir) + + local local_tsserverlib = project_root ~= nil and util.path.join(project_root, 'node_modules', 'typescript', 'lib', 'tsserverlibrary.js') + local global_tsserverlib = '/home/[yourusernamehere]/.npm/lib/node_modules/typescript/lib/tsserverlibrary.js' + + if local_tsserverlib and util.path.exists(local_tsserverlib) then + return local_tsserverlib + else + return global_tsserverlib + end +end + +require'lspconfig'.volar.setup{ + on_new_config = function(new_config, new_root_dir) + new_config.init_options.typescript.serverPath = get_typescript_server_path(new_root_dir) + end, +} +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.volar.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "vue-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "vue" } + ``` + - `init_options` : + ```lua + { + documentFeatures = { + documentColor = false, + documentFormatting = { + defaultPrintWidth = 100 + }, + documentSymbol = true, + foldingRange = true, + linkedEditingRange = true, + selectionRange = true + }, + languageFeatures = { + callHierarchy = true, + codeAction = true, + codeLens = true, + completion = { + defaultAttrNameCase = "kebabCase", + defaultTagNameCase = "both" + }, + definition = true, + diagnostics = true, + documentHighlight = true, + documentLink = true, + hover = true, + implementation = true, + references = true, + rename = true, + renameFileRefactoring = true, + schemaRequestService = true, + semanticTokens = false, + signatureHelp = true, + typeDefinition = true + }, + typescript = { + serverPath = "" + } + } + ``` + - `on_new_config` : + ```lua + see source file + ``` + - `root_dir` : + ```lua + see source file + ``` + + +## vuels + +https://github.com/vuejs/vetur/tree/master/server + +Vue language server(vls) +`vue-language-server` can be installed via `npm`: +```sh +npm install -g vls +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.vuels.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "vls" } + ``` + - `filetypes` : + ```lua + { "vue" } + ``` + - `init_options` : + ```lua + { + config = { + css = {}, + emmet = {}, + html = { + suggest = {} + }, + javascript = { + format = {} + }, + stylusSupremacy = {}, + typescript = { + format = {} + }, + vetur = { + completion = { + autoImport = false, + tagCasing = "kebab", + useScaffoldSnippets = false + }, + format = { + defaultFormatter = { + js = "none", + ts = "none" + }, + defaultFormatterOptions = {}, + scriptInitialIndent = false, + styleInitialIndent = false + }, + useWorkspaceDependencies = false, + validation = { + script = true, + style = true, + template = true + } + } + } + } + ``` + - `root_dir` : + ```lua + root_pattern("package.json", "vue.config.js") + ``` + + +## yamlls + +https://github.com/redhat-developer/yaml-language-server + +`yaml-language-server` can be installed via `yarn`: +```sh +yarn global add yaml-language-server +``` + +To use a schema for validation, there are two options: + +1. Add a modeline to the file. A modeline is a comment of the form: + +``` +# yaml-language-server: $schema= +``` + +where the relative filepath is the path relative to the open yaml file, and the absolute filepath +is the filepath relative to the filesystem root ('/' on unix systems) + +2. Associated a schema url, relative , or absolute (to root of project, not to filesystem root) path to +the a glob pattern relative to the detected project root. Check `:LspInfo` to determine the resolved project +root. + +```lua +require('lspconfig').yamlls.setup { + ... -- other configuration for setup {} + settings = { + yaml = { + ... -- other settings. note this overrides the lspconfig defaults. + schemas = { + ["https://json.schemastore.org/github-workflow.json"] = "/.github/workflows/*" + ["../path/relative/to/file.yml"] = "/.github/workflows/*" + ["/path/from/root/of/project"] = "/.github/workflows/*" + }, + }, + } +} +``` + +Currently, kubernetes is special-cased in yammls, see the following upstream issues: +* [#211](https://github.com/redhat-developer/yaml-language-server/issues/211). +* [#307](https://github.com/redhat-developer/yaml-language-server/issues/307). + +To override a schema to use a specific k8s schema version (for example, to use 1.18): + +```lua +require('lspconfig').yamlls.setup { + ... -- other configuration for setup {} + settings = { + yaml = { + ... -- other settings. note this overrides the lspconfig defaults. + schemas = { + ["https://raw.githubusercontent.com/instrumenta/kubernetes-json-schema/master/v1.18.0-standalone-strict/all.json"] = "/*.k8s.yaml", + ... -- other schemas + }, + }, + } +} +``` + + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.yamlls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "yaml-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "yaml", "yaml.docker-compose" } + ``` + - `root_dir` : + ```lua + util.find_git_ancestor + ``` + - `settings` : + ```lua + { + redhat = { + telemetry = { + enabled = false + } + } + } + ``` + - `single_file_support` : + ```lua + true + ``` + + +## zeta_note + +https://github.com/artempyanykh/zeta-note + +Markdown LSP server for easy note-taking with cross-references and diagnostics. + +Binaries can be downloaded from https://github.com/artempyanykh/zeta-note/releases + +**By default, zeta-note doesn't have a `cmd` set.** This is because nvim-lspconfig does not make assumptions about your path. You must add the following to your init.vim or init.lua to set `cmd` to the absolute path ($HOME and ~ are not expanded) of your zeta-note binary. + +```lua +require'lspconfig'.zeta_note.setup{ + cmd = {'path/to/zeta-note'} +} +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.zeta_note.setup{} +``` + + +**Default values:** + - `filetypes` : + ```lua + { "markdown" } + ``` + - `root_dir` : + ```lua + root_pattern(".zeta.toml") + ``` + + +## zk + +github.com/mickael-menu/zk + +A plain text note-taking assistant + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.zk.setup{} +``` +**Commands:** +- ZkIndex: Index +- ZkNew: ZkNew + +**Default values:** + - `cmd` : + ```lua + { "zk", "lsp" } + ``` + - `filetypes` : + ```lua + { "markdown" } + ``` + - `root_dir` : + ```lua + root_pattern(".zk") + ``` + + +## zls + +https://github.com/zigtools/zls + +Zig LSP implementation + Zig Language Server + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.zls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "zls" } + ``` + - `filetypes` : + ```lua + { "zig", "zir" } + ``` + - `root_dir` : + ```lua + util.root_pattern("zls.json", ".git") + ``` + - `single_file_support` : + ```lua + true + ``` + + + +vim:ft=markdown diff --git a/start/lspconfig-0.1.3/doc/server_configurations.txt b/start/lspconfig-0.1.3/doc/server_configurations.txt new file mode 100644 index 0000000..426c422 --- /dev/null +++ b/start/lspconfig-0.1.3/doc/server_configurations.txt @@ -0,0 +1,6554 @@ +# Configurations + + +The following LSP configs are included. This documentation is autogenerated from the lua files. Follow a link to find documentation for +that config. This file is accessible in neovim via `:help lspconfig-server-configurations` + +- [als](#als) +- [angularls](#angularls) +- [ansiblels](#ansiblels) +- [arduino_language_server](#arduino_language_server) +- [asm_lsp](#asm_lsp) +- [awk_ls](#awk_ls) +- [bashls](#bashls) +- [beancount](#beancount) +- [bicep](#bicep) +- [bsl_ls](#bsl_ls) +- [ccls](#ccls) +- [clangd](#clangd) +- [clarity_lsp](#clarity_lsp) +- [clojure_lsp](#clojure_lsp) +- [cmake](#cmake) +- [codeqlls](#codeqlls) +- [crystalline](#crystalline) +- [csharp_ls](#csharp_ls) +- [cssls](#cssls) +- [cssmodules_ls](#cssmodules_ls) +- [cucumber_language_server](#cucumber_language_server) +- [dartls](#dartls) +- [denols](#denols) +- [dhall_lsp_server](#dhall_lsp_server) +- [diagnosticls](#diagnosticls) +- [dockerls](#dockerls) +- [dotls](#dotls) +- [efm](#efm) +- [elixirls](#elixirls) +- [elmls](#elmls) +- [ember](#ember) +- [emmet_ls](#emmet_ls) +- [erlangls](#erlangls) +- [esbonio](#esbonio) +- [eslint](#eslint) +- [flow](#flow) +- [flux_lsp](#flux_lsp) +- [foam_ls](#foam_ls) +- [fortls](#fortls) +- [fsautocomplete](#fsautocomplete) +- [fstar](#fstar) +- [gdscript](#gdscript) +- [ghcide](#ghcide) +- [golangci_lint_ls](#golangci_lint_ls) +- [gopls](#gopls) +- [gradle_ls](#gradle_ls) +- [grammarly](#grammarly) +- [graphql](#graphql) +- [groovyls](#groovyls) +- [haxe_language_server](#haxe_language_server) +- [hdl_checker](#hdl_checker) +- [hhvm](#hhvm) +- [hie](#hie) +- [hls](#hls) +- [hoon_ls](#hoon_ls) +- [html](#html) +- [idris2_lsp](#idris2_lsp) +- [intelephense](#intelephense) +- [java_language_server](#java_language_server) +- [jdtls](#jdtls) +- [jedi_language_server](#jedi_language_server) +- [jsonls](#jsonls) +- [jsonnet_ls](#jsonnet_ls) +- [julials](#julials) +- [kotlin_language_server](#kotlin_language_server) +- [lean3ls](#lean3ls) +- [leanls](#leanls) +- [lelwel_ls](#lelwel_ls) +- [lemminx](#lemminx) +- [ltex](#ltex) +- [metals](#metals) +- [mint](#mint) +- [mm0_ls](#mm0_ls) +- [nickel_ls](#nickel_ls) +- [nimls](#nimls) +- [ocamlls](#ocamlls) +- [ocamllsp](#ocamllsp) +- [ols](#ols) +- [omnisharp](#omnisharp) +- [opencl_ls](#opencl_ls) +- [openscad_ls](#openscad_ls) +- [pasls](#pasls) +- [perlls](#perlls) +- [perlnavigator](#perlnavigator) +- [perlpls](#perlpls) +- [phpactor](#phpactor) +- [please](#please) +- [powershell_es](#powershell_es) +- [prismals](#prismals) +- [prosemd_lsp](#prosemd_lsp) +- [psalm](#psalm) +- [puppet](#puppet) +- [purescriptls](#purescriptls) +- [pylsp](#pylsp) +- [pyre](#pyre) +- [pyright](#pyright) +- [quick_lint_js](#quick_lint_js) +- [r_language_server](#r_language_server) +- [racket_langserver](#racket_langserver) +- [reason_ls](#reason_ls) +- [remark_ls](#remark_ls) +- [rescriptls](#rescriptls) +- [rls](#rls) +- [rnix](#rnix) +- [robotframework_ls](#robotframework_ls) +- [rome](#rome) +- [rust_analyzer](#rust_analyzer) +- [salt_ls](#salt_ls) +- [scry](#scry) +- [serve_d](#serve_d) +- [sixtyfps](#sixtyfps) +- [slint_lsp](#slint_lsp) +- [solang](#solang) +- [solargraph](#solargraph) +- [solc](#solc) +- [solidity_ls](#solidity_ls) +- [sorbet](#sorbet) +- [sourcekit](#sourcekit) +- [sourcery](#sourcery) +- [spectral](#spectral) +- [sqlls](#sqlls) +- [sqls](#sqls) +- [stylelint_lsp](#stylelint_lsp) +- [sumneko_lua](#sumneko_lua) +- [svelte](#svelte) +- [svls](#svls) +- [tailwindcss](#tailwindcss) +- [taplo](#taplo) +- [teal_ls](#teal_ls) +- [terraform_lsp](#terraform_lsp) +- [terraformls](#terraformls) +- [texlab](#texlab) +- [tflint](#tflint) +- [theme_check](#theme_check) +- [tsserver](#tsserver) +- [typeprof](#typeprof) +- [vala_ls](#vala_ls) +- [vdmj](#vdmj) +- [verible](#verible) +- [vimls](#vimls) +- [vls](#vls) +- [volar](#volar) +- [vuels](#vuels) +- [yamlls](#yamlls) +- [zeta_note](#zeta_note) +- [zk](#zk) +- [zls](#zls) + +## als + +https://github.com/AdaCore/ada_language_server + +Installation instructions can be found [here](https://github.com/AdaCore/ada_language_server#Install). + +Can be configured by passing a "settings" object to `als.setup{}`: + +```lua +require('lspconfig').als.setup{ + settings = { + ada = { + projectFile = "project.gpr"; + scenarioVariables = { ... }; + } + } +} +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.als.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "ada_language_server" } + ``` + - `filetypes` : + ```lua + { "ada" } + ``` + - `root_dir` : + ```lua + util.root_pattern("Makefile", ".git", "*.gpr", "*.adc") + ``` + + +## angularls + +https://github.com/angular/vscode-ng-language-service + +`angular-language-server` can be installed via npm `npm install -g @angular/language-server`. + +Note, that if you override the default `cmd`, you must also update `on_new_config` to set `new_config.cmd` during startup. + +```lua +local project_library_path = "/path/to/project/lib" +local cmd = {"ngserver", "--stdio", "--tsProbeLocations", project_library_path , "--ngProbeLocations", project_library_path} + +require'lspconfig'.angularls.setup{ + cmd = cmd, + on_new_config = function(new_config,new_root_dir) + new_config.cmd = cmd + end, +} +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.angularls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "ngserver", "--stdio", "--tsProbeLocations", "", "--ngProbeLocations", "" } + ``` + - `filetypes` : + ```lua + { "typescript", "html", "typescriptreact", "typescript.tsx" } + ``` + - `root_dir` : + ```lua + root_pattern("angular.json", ".git") + ``` + + +## ansiblels + +https://github.com/ansible/ansible-language-server + +Language server for the ansible configuration management tool. + +`ansible-language-server` can be installed via `npm`: + +```sh +npm install -g @ansible/ansible-language-server +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.ansiblels.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "ansible-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "yaml.ansible" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `settings` : + ```lua + { + ansible = { + ansible = { + path = "ansible" + }, + ansibleLint = { + enabled = true, + path = "ansible-lint" + }, + executionEnvironment = { + enabled = false + }, + python = { + interpreterPath = "python" + } + } + } + ``` + - `single_file_support` : + ```lua + true + ``` + + +## arduino_language_server + +https://github.com/arduino/arduino-language-server + +Language server for Arduino + +The `arduino-language-server` can be installed by running: + go get -u github.com/arduino/arduino-language-server + +The `arduino-cli` tools must also be installed. Follow these instructions for your distro: + https://arduino.github.io/arduino-cli/latest/installation/ + +After installing the `arduino-cli` tools, follow these instructions for generating +a configuration file: + https://arduino.github.io/arduino-cli/latest/getting-started/#create-a-configuration-file +and make sure you install any relevant platforms libraries: + https://arduino.github.io/arduino-cli/latest/getting-started/#install-the-core-for-your-board + +The language server also requires `clangd` be installed. It will look for `clangd` by default but +the binary path can be overridden if need be. + +After all dependencies are installed you'll need to override the lspconfig command for the +language server in your setup function with the necessary configurations: + +```lua +lspconfig.arduino_language_server.setup({ + cmd = { + -- Required + "arduino-language-server", + "-cli-config", "/path/to/arduino-cli.yaml", + -- Optional + "-cli", "/path/to/arduino-cli", + "-clangd", "/path/to/clangd" + } +}) +``` + +For further instruction about configuration options, run `arduino-language-server --help`. + + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.arduino_language_server.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "arduino-language-server" } + ``` + - `filetypes` : + ```lua + { "arduino" } + ``` + - `root_dir` : + ```lua + see source file + ``` + + +## asm_lsp + +https://github.com/bergercookie/asm-lsp + +Language Server for GAS/GO Assembly + +`asm-lsp` can be installed via cargo: +cargo install asm-lsp + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.asm_lsp.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "asm-lsp" } + ``` + - `filetypes` : + ```lua + { "asm", "vmasm" } + ``` + - `root_dir` : + ```lua + see source file + ``` + + +## awk_ls + +https://github.com/Beaglefoot/awk-language-server/ + +`awk-language-server` can be installed via `npm`: +```sh +npm install -g awk-language-server +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.awk_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "awk-language-server" } + ``` + - `filetypes` : + ```lua + { "awk" } + ``` + - `single_file_support` : + ```lua + true + ``` + + +## bashls + +https://github.com/mads-hartmann/bash-language-server + +`bash-language-server` can be installed via `npm`: +```sh +npm i -g bash-language-server +``` + +Language server for bash, written using tree sitter in typescript. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.bashls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "bash-language-server", "start" } + ``` + - `cmd_env` : + ```lua + { + GLOB_PATTERN = "*@(.sh|.inc|.bash|.command)" + } + ``` + - `filetypes` : + ```lua + { "sh" } + ``` + - `root_dir` : + ```lua + util.find_git_ancestor + ``` + - `single_file_support` : + ```lua + true + ``` + + +## beancount + +https://github.com/polarmutex/beancount-language-server#installation + +See https://github.com/polarmutex/beancount-language-server#configuration for configuration options + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.beancount.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "beancount-langserver", "--stdio" } + ``` + - `filetypes` : + ```lua + { "beancount" } + ``` + - `init_options` : + ```lua + { + journalFile = "", + pythonPath = "python3" + } + ``` + - `root_dir` : + ```lua + root_pattern("elm.json") + ``` + - `single_file_support` : + ```lua + true + ``` + + +## bicep + +https://github.com/azure/bicep +Bicep language server + +Bicep language server can be installed by downloading and extracting a release of bicep-langserver.zip from [Bicep GitHub releases](https://github.com/Azure/bicep/releases). + +Bicep language server requires the [dotnet-sdk](https://dotnet.microsoft.com/download) to be installed. + +Neovim does not have built-in support for the bicep filetype which is required for lspconfig to automatically launch the language server. + +Filetype detection can be added via an autocmd: +```lua +vim.cmd [[ autocmd BufNewFile,BufRead *.bicep set filetype=bicep ]] +``` + +**By default, bicep language server does not have a `cmd` set.** This is because nvim-lspconfig does not make assumptions about your path. You must add the following to your init.vim or init.lua to set `cmd` to the absolute path ($HOME and ~ are not expanded) of the unzipped run script or binary. + +```lua +local bicep_lsp_bin = "/path/to/bicep-langserver/Bicep.LangServer.dll" +require'lspconfig'.bicep.setup{ + cmd = { "dotnet", bicep_lsp_bin }; + ... +} +``` + +To download the latest release and place in /usr/local/bin/bicep-langserver: +```bash +(cd $(mktemp -d) \ + && curl -fLO https://github.com/Azure/bicep/releases/latest/download/bicep-langserver.zip \ + && rm -rf /usr/local/bin/bicep-langserver \ + && unzip -d /usr/local/bin/bicep-langserver bicep-langserver.zip) +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.bicep.setup{} +``` + + +**Default values:** + - `filetypes` : + ```lua + { "bicep" } + ``` + - `init_options` : + ```lua + {} + ``` + - `root_dir` : + ```lua + util.find_git_ancestor + ``` + + +## bsl_ls + + https://github.com/1c-syntax/bsl-language-server + + Language Server Protocol implementation for 1C (BSL) - 1C:Enterprise 8 and OneScript languages. + + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.bsl_ls.setup{} +``` + + +**Default values:** + - `filetypes` : + ```lua + { "bsl", "os" } + ``` + - `root_dir` : + ```lua + root_pattern(".git") + ``` + + +## ccls + +https://github.com/MaskRay/ccls/wiki + +ccls relies on a [JSON compilation database](https://clang.llvm.org/docs/JSONCompilationDatabase.html) specified +as compile_commands.json or, for simpler projects, a .ccls. +For details on how to automatically generate one using CMake look [here](https://cmake.org/cmake/help/latest/variable/CMAKE_EXPORT_COMPILE_COMMANDS.html). Alternatively, you can use [Bear](https://github.com/rizsotto/Bear). + +Customization options are passed to ccls at initialization time via init_options, a list of available options can be found [here](https://github.com/MaskRay/ccls/wiki/Customization#initialization-options). For example: + +```lua +local lspconfig = require'lspconfig' +lspconfig.ccls.setup { + init_options = { + compilationDatabaseDirectory = "build"; + index = { + threads = 0; + }; + clang = { + excludeArgs = { "-frounding-math"} ; + }; + } +} + +``` + + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.ccls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "ccls" } + ``` + - `filetypes` : + ```lua + { "c", "cpp", "objc", "objcpp" } + ``` + - `offset_encoding` : + ```lua + "utf-32" + ``` + - `root_dir` : + ```lua + root_pattern("compile_commands.json", ".ccls", ".git") + ``` + - `single_file_support` : + ```lua + false + ``` + + +## clangd + +https://clangd.llvm.org/installation.html + +**NOTE:** Clang >= 11 is recommended! See [this issue for more](https://github.com/neovim/nvim-lsp/issues/23). + +clangd relies on a [JSON compilation database](https://clang.llvm.org/docs/JSONCompilationDatabase.html) specified as compile_commands.json, see https://clangd.llvm.org/installation#compile_commandsjson + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.clangd.setup{} +``` +**Commands:** +- ClangdSwitchSourceHeader: Switch between source/header + +**Default values:** + - `capabilities` : + ```lua + default capabilities, with offsetEncoding utf-8 + ``` + - `cmd` : + ```lua + { "clangd" } + ``` + - `filetypes` : + ```lua + { "c", "cpp", "objc", "objcpp" } + ``` + - `root_dir` : + ```lua + root_pattern( + '.clangd', + '.clang-tidy', + '.clang-format', + 'compile_commands.json', + 'compile_flags.txt', + 'configure.ac', + '.git' + ) + + ``` + - `single_file_support` : + ```lua + true + ``` + + +## clarity_lsp + +`clarity-lsp` is a language server for the Clarity language. Clarity is a decidable smart contract language that optimizes for predictability and security. Smart contracts allow developers to encode essential business logic on a blockchain. + +To learn how to configure the clarity language server, see the [clarity-lsp documentation](https://github.com/hirosystems/clarity-lsp). + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.clarity_lsp.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "clarity-lsp" } + ``` + - `filetypes` : + ```lua + { "clar", "clarity" } + ``` + - `root_dir` : + ```lua + root_pattern(".git") + ``` + + +## clojure_lsp + +https://github.com/snoe/clojure-lsp + +Clojure Language Server + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.clojure_lsp.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "clojure-lsp" } + ``` + - `filetypes` : + ```lua + { "clojure", "edn" } + ``` + - `root_dir` : + ```lua + root_pattern("project.clj", "deps.edn", "build.boot", "shadow-cljs.edn", ".git") + ``` + + +## cmake + +https://github.com/regen100/cmake-language-server + +CMake LSP Implementation + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.cmake.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "cmake-language-server" } + ``` + - `filetypes` : + ```lua + { "cmake" } + ``` + - `init_options` : + ```lua + { + buildDirectory = "build" + } + ``` + - `root_dir` : + ```lua + root_pattern(".git", "compile_commands.json", "build") + ``` + - `single_file_support` : + ```lua + true + ``` + + +## codeqlls + +Reference: +https://help.semmle.com/codeql/codeql-cli.html + +Binaries: +https://github.com/github/codeql-cli-binaries + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.codeqlls.setup{} +``` + + +**Default values:** + - `before_init` : + ```lua + see source file + ``` + - `cmd` : + ```lua + { "codeql", "execute", "language-server", "--check-errors", "ON_CHANGE", "-q" } + ``` + - `filetypes` : + ```lua + { "ql" } + ``` + - `log_level` : + ```lua + 2 + ``` + - `root_dir` : + ```lua + see source file + ``` + - `settings` : + ```lua + { + search_path = "list containing all search paths, eg: '~/codeql-home/codeql-repo'" + } + ``` + + +## crystalline + +https://github.com/elbywan/crystalline + +Crystal language server. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.crystalline.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "crystalline" } + ``` + - `filetypes` : + ```lua + { "crystal" } + ``` + - `root_dir` : + ```lua + root_pattern('shard.yml', '.git') + ``` + - `single_file_support` : + ```lua + true + ``` + + +## csharp_ls + +https://github.com/razzmatazz/csharp-language-server + +Language Server for C#. + +csharp-ls requires the [dotnet-sdk](https://dotnet.microsoft.com/download) to be installed. + +The preferred way to install csharp-ls is with `dotnet tool install --global csharp-ls`. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.csharp_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "csharp-ls" } + ``` + - `filetypes` : + ```lua + { "cs" } + ``` + - `init_options` : + ```lua + { + AutomaticWorkspaceInit = true + } + ``` + - `root_dir` : + ```lua + see source file + ``` + + +## cssls + + +https://github.com/hrsh7th/vscode-langservers-extracted + +`css-languageserver` can be installed via `npm`: + +```sh +npm i -g vscode-langservers-extracted +``` + +Neovim does not currently include built-in snippets. `vscode-css-language-server` only provides completions when snippet support is enabled. To enable completion, install a snippet plugin and add the following override to your language client capabilities during setup. + +```lua +--Enable (broadcasting) snippet capability for completion +local capabilities = vim.lsp.protocol.make_client_capabilities() +capabilities.textDocument.completion.completionItem.snippetSupport = true + +require'lspconfig'.cssls.setup { + capabilities = capabilities, +} +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.cssls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "vscode-css-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "css", "scss", "less" } + ``` + - `root_dir` : + ```lua + root_pattern("package.json", ".git") or bufdir + ``` + - `settings` : + ```lua + { + css = { + validate = true + }, + less = { + validate = true + }, + scss = { + validate = true + } + } + ``` + - `single_file_support` : + ```lua + true + ``` + + +## cssmodules_ls + +https://github.com/antonk52/cssmodules-language-server + +Language server for autocompletion and go-to-definition functionality for CSS modules. + +You can install cssmodules-language-server via npm: +```sh +npm install -g cssmodules-language-server +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.cssmodules_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "cssmodules-language-server" } + ``` + - `filetypes` : + ```lua + { "javascript", "javascriptreact", "typescript", "typescriptreact" } + ``` + - `root_dir` : + ```lua + root_pattern("package.json") + ``` + + +## cucumber_language_server + +https://cucumber.io +https://github.com/cucumber/common +https://www.npmjs.com/package/@cucumber/language-server + +Language server for Cucumber. + +`cucumber-language-server` can be installed via `npm`: +```sh +npm install -g @cucumber/language-server +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.cucumber_language_server.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "cucumber-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "cucumber" } + ``` + - `root_dir` : + ```lua + util.find_git_ancestor + ``` + + +## dartls + +https://github.com/dart-lang/sdk/tree/master/pkg/analysis_server/tool/lsp_spec + +Language server for dart. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.dartls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "dart", "./snapshots/analysis_server.dart.snapshot", "--lsp" } + ``` + - `filetypes` : + ```lua + { "dart" } + ``` + - `init_options` : + ```lua + { + closingLabels = true, + flutterOutline = true, + onlyAnalyzeProjectsWithOpenFiles = true, + outline = true, + suggestFromUnimportedLibraries = true + } + ``` + - `root_dir` : + ```lua + root_pattern("pubspec.yaml") + ``` + - `settings` : + ```lua + { + dart = { + completeFunctionCalls = true, + showTodos = true + } + } + ``` + + +## denols + +https://github.com/denoland/deno + +Deno's built-in language server + +To approrpiately highlight codefences returned from denols, you will need to augment vim.g.markdown_fenced languages + in your init.lua. Example: + +```lua +vim.g.markdown_fenced_languages = { + "ts=typescript" +} +``` + + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.denols.setup{} +``` +**Commands:** +- DenolsCache: Cache a module and all of its dependencies. + +**Default values:** + - `cmd` : + ```lua + { "deno", "lsp" } + ``` + - `filetypes` : + ```lua + { "javascript", "javascriptreact", "javascript.jsx", "typescript", "typescriptreact", "typescript.tsx" } + ``` + - `handlers` : + ```lua + { + ["textDocument/definition"] = , + ["textDocument/references"] = + } + ``` + - `init_options` : + ```lua + { + enable = true, + lint = false, + unstable = false + } + ``` + - `root_dir` : + ```lua + root_pattern("deno.json", "deno.jsonc", "tsconfig.json", ".git") + ``` + + +## dhall_lsp_server + +https://github.com/dhall-lang/dhall-haskell/tree/master/dhall-lsp-server + +language server for dhall + +`dhall-lsp-server` can be installed via cabal: +```sh +cabal install dhall-lsp-server +``` +prebuilt binaries can be found [here](https://github.com/dhall-lang/dhall-haskell/releases). + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.dhall_lsp_server.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "dhall-lsp-server" } + ``` + - `filetypes` : + ```lua + { "dhall" } + ``` + - `root_dir` : + ```lua + root_pattern(".git") + ``` + - `single_file_support` : + ```lua + true + ``` + + +## diagnosticls + +https://github.com/iamcco/diagnostic-languageserver + +Diagnostic language server integrate with linters. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.diagnosticls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "diagnostic-languageserver", "--stdio" } + ``` + - `filetypes` : + ```lua + Empty by default, override to add filetypes + ``` + - `root_dir` : + ```lua + Vim's starting directory + ``` + - `single_file_support` : + ```lua + true + ``` + + +## dockerls + +https://github.com/rcjsuen/dockerfile-language-server-nodejs + +`docker-langserver` can be installed via `npm`: +```sh +npm install -g dockerfile-language-server-nodejs +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.dockerls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "docker-langserver", "--stdio" } + ``` + - `filetypes` : + ```lua + { "dockerfile" } + ``` + - `root_dir` : + ```lua + root_pattern("Dockerfile") + ``` + - `single_file_support` : + ```lua + true + ``` + + +## dotls + +https://github.com/nikeee/dot-language-server + +`dot-language-server` can be installed via `npm`: +```sh +npm install -g dot-language-server +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.dotls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "dot-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "dot" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `single_file_support` : + ```lua + true + ``` + + +## efm + +https://github.com/mattn/efm-langserver + +General purpose Language Server that can use specified error message format generated from specified command. + +Requires at minimum EFM version [v0.0.38](https://github.com/mattn/efm-langserver/releases/tag/v0.0.38) to support +launching the language server on single files. If on an older version of EFM, disable single file support: + +```lua +require('lspconfig')['efm'].setup{ + settings = ..., -- You must populate this according to the EFM readme + filetypes = ..., -- Populate this according to the note below + single_file_support = false, -- This is the important line for supporting older version of EFM +} +``` + +Note: In order for neovim's built-in language server client to send the appropriate `languageId` to EFM, **you must +specify `filetypes` in your call to `setup{}`**. Otherwise `lspconfig` will launch EFM on the `BufEnter` instead +of the `FileType` autocommand, and the `filetype` variable used to populate the `languageId` will not yet be set. + +```lua +require('lspconfig')['efm'].setup{ + settings = ..., -- You must populate this according to the EFM readme + filetypes = { 'python','cpp','lua' } +} +``` + + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.efm.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "efm-langserver" } + ``` + - `root_dir` : + ```lua + util.root_pattern(".git") + ``` + - `single_file_support` : + ```lua + true + ``` + + +## elixirls + +https://github.com/elixir-lsp/elixir-ls + +`elixir-ls` can be installed by following the instructions [here](https://github.com/elixir-lsp/elixir-ls#building-and-running). + +```bash +curl -fLO https://github.com/elixir-lsp/elixir-ls/releases/latest/download/elixir-ls.zip +unzip elixir-ls.zip -d /path/to/elixir-ls +# Unix +chmod +x /path/to/elixir-ls/language_server.sh +``` + +**By default, elixir-ls doesn't have a `cmd` set.** This is because nvim-lspconfig does not make assumptions about your path. You must add the following to your init.vim or init.lua to set `cmd` to the absolute path ($HOME and ~ are not expanded) of your unzipped elixir-ls. + +```lua +require'lspconfig'.elixirls.setup{ + -- Unix + cmd = { "/path/to/elixir-ls/language_server.sh" }; + -- Windows + cmd = { "/path/to/elixir-ls/language_server.bat" }; + ... +} +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.elixirls.setup{} +``` + + +**Default values:** + - `filetypes` : + ```lua + { "elixir", "eelixir" } + ``` + - `root_dir` : + ```lua + root_pattern("mix.exs", ".git") or vim.loop.os_homedir() + ``` + + +## elmls + +https://github.com/elm-tooling/elm-language-server#installation + +If you don't want to use Nvim to install it, then you can use: +```sh +npm install -g elm elm-test elm-format @elm-tooling/elm-language-server +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.elmls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "elm-language-server" } + ``` + - `filetypes` : + ```lua + { "elm" } + ``` + - `init_options` : + ```lua + { + elmAnalyseTrigger = "change" + } + ``` + - `root_dir` : + ```lua + root_pattern("elm.json") + ``` + + +## ember + +https://github.com/lifeart/ember-language-server + +`ember-language-server` can be installed via `npm`: + +```sh +npm install -g @lifeart/ember-language-server +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.ember.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "ember-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "handlebars", "typescript", "javascript" } + ``` + - `root_dir` : + ```lua + root_pattern("ember-cli-build.js", ".git") + ``` + + +## emmet_ls + +https://github.com/aca/emmet-ls + +Package can be installed via `npm`: +```sh +npm install -g emmet-ls +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.emmet_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "emmet-ls", "--stdio" } + ``` + - `filetypes` : + ```lua + { "html", "css" } + ``` + - `root_dir` : + ```lua + git root + ``` + - `single_file_support` : + ```lua + true + ``` + + +## erlangls + +https://erlang-ls.github.io + +Language Server for Erlang. + +Clone [erlang_ls](https://github.com/erlang-ls/erlang_ls) +Compile the project with `make` and copy resulting binaries somewhere in your $PATH eg. `cp _build/*/bin/* ~/local/bin` + +Installation instruction can be found [here](https://github.com/erlang-ls/erlang_ls). + +Installation requirements: + - [Erlang OTP 21+](https://github.com/erlang/otp) + - [rebar3 3.9.1+](https://github.com/erlang/rebar3) + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.erlangls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "erlang_ls" } + ``` + - `filetypes` : + ```lua + { "erlang" } + ``` + - `root_dir` : + ```lua + root_pattern('rebar.config', 'erlang.mk', '.git') + ``` + - `single_file_support` : + ```lua + true + ``` + + +## esbonio + +https://github.com/swyddfa/esbonio + +Esbonio is a language server for [Sphinx](https://www.sphinx-doc.org/en/master/) documentation projects. +The language server can be installed via pip + +``` +pip install esbonio +``` + +Since Sphinx is highly extensible you will get best results if you install the language server in the same +Python environment as the one used to build your documentation. To ensure that the correct Python environment +is picked up, you can either launch `nvim` with the correct environment activated. + +``` +source env/bin/activate +nvim +``` + +Or you can modify the default `cmd` to include the full path to the Python interpreter. + +```lua +require'lspconfig'.esbonio.setup { + cmd = { '/path/to/virtualenv/bin/python', '-m', 'esbonio' } +} +``` + +Esbonio supports a number of config values passed as `init_options` on startup, for example. + +```lua +require'lspconfig'.esbonio.setup { + init_options = { + server = { + logLevel = "debug" + }, + sphinx = { + confDir = "/path/to/docs", + srcDir = "${confDir}/../docs-src" + } +} +``` + +A full list and explanation of the available options can be found [here](https://swyddfa.github.io/esbonio/docs/lsp/editors/index.html) + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.esbonio.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "python3", "-m", "esbonio" } + ``` + - `filetypes` : + ```lua + { "rst" } + ``` + - `root_dir` : + ```lua + see source file + ``` + + +## eslint + +https://github.com/hrsh7th/vscode-langservers-extracted + +vscode-eslint-language-server: A linting engine for JavaScript / Typescript + +`vscode-eslint-language-server` can be installed via `npm`: +```sh +npm i -g vscode-langservers-extracted +``` + +vscode-eslint-language-server provides an EslintFixAll command that can be used to format document on save +```vim +autocmd BufWritePre *.tsx,*.ts,*.jsx,*.js EslintFixAll +``` + +See [vscode-eslint](https://github.com/microsoft/vscode-eslint/blob/55871979d7af184bf09af491b6ea35ebd56822cf/server/src/eslintServer.ts#L216-L229) for configuration options. + +Additional messages you can handle: eslint/noConfig +Messages already handled in lspconfig: eslint/openDoc, eslint/confirmESLintExecution, eslint/probeFailed, eslint/noLibrary + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.eslint.setup{} +``` +**Commands:** +- EslintFixAll: Fix all eslint problems for this buffer + +**Default values:** + - `cmd` : + ```lua + { "vscode-eslint-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "javascript", "javascriptreact", "javascript.jsx", "typescript", "typescriptreact", "typescript.tsx", "vue" } + ``` + - `handlers` : + ```lua + { + ["eslint/confirmESLintExecution"] = , + ["eslint/noLibrary"] = , + ["eslint/openDoc"] = , + ["eslint/probeFailed"] = + } + ``` + - `on_new_config` : + ```lua + see source file + ``` + - `root_dir` : + ```lua + see source file + ``` + - `settings` : + ```lua + { + codeAction = { + disableRuleComment = { + enable = true, + location = "separateLine" + }, + showDocumentation = { + enable = true + } + }, + codeActionOnSave = { + enable = false, + mode = "all" + }, + format = true, + nodePath = "", + onIgnoredFiles = "off", + packageManager = "npm", + quiet = false, + rulesCustomizations = {}, + run = "onType", + useESLintClass = false, + validate = "on", + workingDirectory = { + mode = "location" + } + } + ``` + + +## flow + +https://flow.org/ +https://github.com/facebook/flow + +See below for how to setup Flow itself. +https://flow.org/en/docs/install/ + +See below for lsp command options. + +```sh +npx flow lsp --help +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.flow.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "npx", "--no-install", "flow", "lsp" } + ``` + - `filetypes` : + ```lua + { "javascript", "javascriptreact", "javascript.jsx" } + ``` + - `root_dir` : + ```lua + root_pattern(".flowconfig") + ``` + + +## flux_lsp + +https://github.com/influxdata/flux-lsp +`flux-lsp` can be installed via `cargo`: +```sh +cargo install --git https://github.com/influxdata/flux-lsp +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.flux_lsp.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "flux-lsp" } + ``` + - `filetypes` : + ```lua + { "flux" } + ``` + - `root_dir` : + ```lua + util.find_git_ancestor + ``` + - `single_file_support` : + ```lua + true + ``` + + +## foam_ls + +https://github.com/FoamScience/foam-language-server + +`foam-language-server` can be installed via `npm` +```sh +npm install -g foam-language-server +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.foam_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "foam-ls", "--stdio" } + ``` + - `filetypes` : + ```lua + { "foam", "OpenFOAM" } + ``` + - `root_dir` : + ```lua + see source file + ``` + + +## fortls + +https://github.com/hansec/fortran-language-server + +Fortran Language Server for the Language Server Protocol + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.fortls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "fortls" } + ``` + - `filetypes` : + ```lua + { "fortran" } + ``` + - `root_dir` : + ```lua + root_pattern(".fortls") + ``` + - `settings` : + ```lua + { + nthreads = 1 + } + ``` + + +## fsautocomplete + +https://github.com/fsharp/FsAutoComplete + +Language Server for F# provided by FsAutoComplete (FSAC). + +FsAutoComplete requires the [dotnet-sdk](https://dotnet.microsoft.com/download) to be installed. + +The preferred way to install FsAutoComplete is with `dotnet tool install --global fsautocomplete`. + +Instructions to compile from source are found on the main [repository](https://github.com/fsharp/FsAutoComplete). + +You may also need to configure the filetype as Vim defaults to Forth for `*.fs` files: + +`autocmd BufNewFile,BufRead *.fs,*.fsx,*.fsi set filetype=fsharp` + +This is automatically done by plugins such as [PhilT/vim-fsharp](https://github.com/PhilT/vim-fsharp), [fsharp/vim-fsharp](https://github.com/fsharp/vim-fsharp), and [adelarsq/neofsharp.vim](https://github.com/adelarsq/neofsharp.vim). + + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.fsautocomplete.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "fsautocomplete", "--background-service-enabled" } + ``` + - `filetypes` : + ```lua + { "fsharp" } + ``` + - `init_options` : + ```lua + { + AutomaticWorkspaceInit = true + } + ``` + - `root_dir` : + ```lua + see source file + ``` + + +## fstar + +https://github.com/FStarLang/FStar + +LSP support is included in FStar. Make sure `fstar.exe` is in your PATH. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.fstar.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "fstar.exe", "--lsp" } + ``` + - `filetypes` : + ```lua + { "fstar" } + ``` + - `root_dir` : + ```lua + util.find_git_ancestor + ``` + + +## gdscript + +https://github.com/godotengine/godot + +Language server for GDScript, used by Godot Engine. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.gdscript.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "nc", "localhost", "6008" } + ``` + - `filetypes` : + ```lua + { "gd", "gdscript", "gdscript3" } + ``` + - `root_dir` : + ```lua + util.root_pattern("project.godot", ".git") + ``` + + +## ghcide + +https://github.com/digital-asset/ghcide + +A library for building Haskell IDE tooling. +"ghcide" isn't for end users now. Use "haskell-language-server" instead of "ghcide". + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.ghcide.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "ghcide", "--lsp" } + ``` + - `filetypes` : + ```lua + { "haskell", "lhaskell" } + ``` + - `root_dir` : + ```lua + root_pattern("stack.yaml", "hie-bios", "BUILD.bazel", "cabal.config", "package.yaml") + ``` + + +## golangci_lint_ls + +Combination of both lint server and client + +https://github.com/nametake/golangci-lint-langserver +https://github.com/golangci/golangci-lint + + +Installation of binaries needed is done via + +``` +go install github.com/nametake/golangci-lint-langserver@latest +go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.42.1 +``` + + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.golangci_lint_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "golangci-lint-langserver" } + ``` + - `filetypes` : + ```lua + { "go", "gomod" } + ``` + - `init_options` : + ```lua + { + command = { "golangci-lint", "run", "--out-format", "json" } + } + ``` + - `root_dir` : + ```lua + root_pattern('go.work') or root_pattern('go.mod', '.golangci.yaml', '.git') + ``` + + +## gopls + +https://github.com/golang/tools/tree/master/gopls + +Google's lsp server for golang. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.gopls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "gopls" } + ``` + - `filetypes` : + ```lua + { "go", "gomod", "gotmpl" } + ``` + - `root_dir` : + ```lua + root_pattern("go.mod", ".git") + ``` + - `single_file_support` : + ```lua + true + ``` + + +## gradle_ls + +https://github.com/microsoft/vscode-gradle + +Microsoft's lsp server for gradle files + +If you're setting this up manually, build vscode-gradle using `./gradlew installDist` and point `cmd` to the `gradle-language-server` generated in the build directory + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.gradle_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "gradle-language-server" } + ``` + - `filetypes` : + ```lua + { "groovy" } + ``` + - `root_dir` : + ```lua + root_pattern("settings.gradle") + ``` + + +## grammarly + +https://github.com/emacs-grammarly/unofficial-grammarly-language-server + +`unofficial-grammarly-language-server` can be installed via `npm`: + +```sh +npm i -g @emacs-grammarly/unofficial-grammarly-language-server +``` + +WARNING: Since this language server uses Grammarly's API, any document you open with it running is shared with them. Please evaluate their [privacy policy](https://www.grammarly.com/privacy-policy) before using this. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.grammarly.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "unofficial-grammarly-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "markdown" } + ``` + - `handlers` : + ```lua + { + ["$/updateDocumentState"] = + } + ``` + - `root_dir` : + ```lua + util.find_git_ancestor + ``` + - `single_file_support` : + ```lua + true + ``` + + +## graphql + +https://github.com/graphql/graphiql/tree/main/packages/graphql-language-service-cli + +`graphql-lsp` can be installed via `npm`: + +```sh +npm install -g graphql-language-service-cli +``` + +Note that you must also have [the graphql package](https://github.com/graphql/graphql-js) installed and create a [GraphQL config file](https://www.graphql-config.com/docs/user/user-introduction). + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.graphql.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "graphql-lsp", "server", "-m", "stream" } + ``` + - `filetypes` : + ```lua + { "graphql", "typescriptreact", "javascriptreact" } + ``` + - `root_dir` : + ```lua + root_pattern('.git', '.graphqlrc*', '.graphql.config.*') + ``` + + +## groovyls + +https://github.com/prominic/groovy-language-server.git + +Requirements: + - Linux/macOS (for now) + - Java 11+ + +`groovyls` can be installed by following the instructions [here](https://github.com/prominic/groovy-language-server.git#build). + +If you have installed groovy language server, you can set the `cmd` custom path as follow: + +```lua +require'lspconfig'.groovyls.setup{ + -- Unix + cmd = { "java", "-jar", "path/to/groovyls/groovy-language-server-all.jar" }, + ... +} +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.groovyls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "java", "-jar", "groovy-language-server-all.jar" } + ``` + - `filetypes` : + ```lua + { "groovy" } + ``` + - `root_dir` : + ```lua + see source file + ``` + + +## haxe_language_server + +https://github.com/vshaxe/haxe-language-server + +The Haxe language server can be built by running the following commands from +the project's root directory: + + npm install + npx lix run vshaxe-build -t language-server + +This will create `bin/server.js`. Note that the server requires Haxe 3.4.0 or +higher. + +After building the language server, set the `cmd` setting in your setup +function: + +```lua +lspconfig.haxe_language_server.setup({ + cmd = {"node", "path/to/bin/server.js"}, +}) +``` + +By default, an HXML compiler arguments file named `build.hxml` is expected in +your project's root directory. If your file is named something different, +specify it using the `init_options.displayArguments` setting. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.haxe_language_server.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "haxe-language-server" } + ``` + - `filetypes` : + ```lua + { "haxe" } + ``` + - `init_options` : + ```lua + { + displayArguments = { "build.hxml" } + } + ``` + - `root_dir` : + ```lua + root_pattern("*.hxml") + ``` + - `settings` : + ```lua + { + haxe = { + executable = "haxe" + } + } + ``` + + +## hdl_checker + +https://github.com/suoto/hdl_checker +Language server for hdl-checker. +Install using: `pip install hdl-checker --upgrade` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.hdl_checker.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "hdl_checker", "--lsp" } + ``` + - `filetypes` : + ```lua + { "vhdl", "verilog", "systemverilog" } + ``` + - `root_dir` : + ```lua + util.find_git_ancestor + ``` + - `single_file_support` : + ```lua + true + ``` + + +## hhvm + +Language server for programs written in Hack +https://hhvm.com/ +https://github.com/facebook/hhvm +See below for how to setup HHVM & typechecker: +https://docs.hhvm.com/hhvm/getting-started/getting-started + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.hhvm.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "hh_client", "lsp" } + ``` + - `filetypes` : + ```lua + { "php", "hack" } + ``` + - `root_dir` : + ```lua + root_pattern(".hhconfig") + ``` + + +## hie + +https://github.com/haskell/haskell-ide-engine + +the following init_options are supported (see https://github.com/haskell/haskell-ide-engine#configuration): +```lua +init_options = { + languageServerHaskell = { + hlintOn = bool; + maxNumberOfProblems = number; + diagnosticsDebounceDuration = number; + liquidOn = bool (default false); + completionSnippetsOn = bool (default true); + formatOnImportOn = bool (default true); + formattingProvider = string (default "brittany", alternate "floskell"); + } +} +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.hie.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "hie-wrapper", "--lsp" } + ``` + - `filetypes` : + ```lua + { "haskell" } + ``` + - `root_dir` : + ```lua + root_pattern("stack.yaml", "package.yaml", ".git") + ``` + + +## hls + +https://github.com/haskell/haskell-language-server + +Haskell Language Server + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.hls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "haskell-language-server-wrapper", "--lsp" } + ``` + - `filetypes` : + ```lua + { "haskell", "lhaskell" } + ``` + - `lspinfo` : + ```lua + see source file + ``` + - `root_dir` : + ```lua + root_pattern("*.cabal", "stack.yaml", "cabal.project", "package.yaml", "hie.yaml") + ``` + - `settings` : + ```lua + { + haskell = { + formattingProvider = "ormolu" + } + } + ``` + - `single_file_support` : + ```lua + true + ``` + + +## hoon_ls + +https://github.com/urbit/hoon-language-server + +A language server for Hoon. + +The language server can be installed via `npm install -g @hoon-language-server` + +Start a fake ~zod with `urbit -F zod`. +Start the language server at the Urbit Dojo prompt with: `|start %language-server` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.hoon_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "hoon-language-server" } + ``` + - `filetypes` : + ```lua + { "hoon" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `single_file_support` : + ```lua + true + ``` + + +## html + +https://github.com/hrsh7th/vscode-langservers-extracted + +`vscode-html-language-server` can be installed via `npm`: +```sh +npm i -g vscode-langservers-extracted +``` + +Neovim does not currently include built-in snippets. `vscode-html-language-server` only provides completions when snippet support is enabled. +To enable completion, install a snippet plugin and add the following override to your language client capabilities during setup. + +The code-formatting feature of the lsp can be controlled with the `provideFormatter` option. + +```lua +--Enable (broadcasting) snippet capability for completion +local capabilities = vim.lsp.protocol.make_client_capabilities() +capabilities.textDocument.completion.completionItem.snippetSupport = true + +require'lspconfig'.html.setup { + capabilities = capabilities, +} +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.html.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "vscode-html-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "html" } + ``` + - `init_options` : + ```lua + { + configurationSection = { "html", "css", "javascript" }, + embeddedLanguages = { + css = true, + javascript = true + }, + provideFormatter = true + } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `settings` : + ```lua + {} + ``` + - `single_file_support` : + ```lua + true + ``` + + +## idris2_lsp + +https://github.com/idris-community/idris2-lsp + +The Idris 2 language server. + +Plugins for the Idris 2 filetype include +[Idris2-Vim](https://github.com/edwinb/idris2-vim) (fewer features, stable) and +[Nvim-Idris2](https://github.com/ShinKage/nvim-idris2) (cutting-edge, +experimental). + +Idris2-Lsp requires a build of Idris 2 that includes the "Idris 2 API" package. +Package managers with known support for this build include the +[AUR](https://aur.archlinux.org/packages/idris2-api-git/) and +[Homebrew](https://formulae.brew.sh/formula/idris2#default). + +If your package manager does not support the Idris 2 API, you will need to build +Idris 2 from source. Refer to the +[the Idris 2 installation instructions](https://github.com/idris-lang/Idris2/blob/main/INSTALL.md) +for details. Steps 5 and 8 are listed as "optional" in that guide, but they are +necessary in order to make the Idris 2 API available. + +You need to install a version of Idris2-Lsp that is compatible with your +version of Idris 2. There should be a branch corresponding to every released +Idris 2 version after v0.4.0. Use the latest commit on that branch. For example, +if you have Idris v0.5.1, you should use the v0.5.1 branch of Idris2-Lsp. + +If your Idris 2 version is newer than the newest Idris2-Lsp branch, use the +latest commit on the `master` branch, and set a reminder to check the Idris2-Lsp +repo for the release of a compatible versioned branch. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.idris2_lsp.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "idris2-lsp" } + ``` + - `filetypes` : + ```lua + { "idris2" } + ``` + - `root_dir` : + ```lua + see source file + ``` + + +## intelephense + +https://intelephense.com/ + +`intelephense` can be installed via `npm`: +```sh +npm install -g intelephense +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.intelephense.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "intelephense", "--stdio" } + ``` + - `filetypes` : + ```lua + { "php" } + ``` + - `root_dir` : + ```lua + root_pattern("composer.json", ".git") + ``` + + +## java_language_server + +https://github.com/georgewfraser/java-language-server + +Java language server + +Point `cmd` to `lang_server_linux.sh` or the equivalent script for macOS/Windows provided by java-language-server + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.java_language_server.setup{} +``` + + +**Default values:** + - `filetypes` : + ```lua + { "java" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `settings` : + ```lua + {} + ``` + + +## jdtls + +https://projects.eclipse.org/projects/eclipse.jdt.ls + +Language server for Java. + +IMPORTANT: If you want all the features jdtls has to offer, [nvim-jdtls](https://github.com/mfussenegger/nvim-jdtls) +is highly recommended. If all you need is diagnostics, completion, imports, gotos and formatting and some code actions +you can keep reading here. + +For manual installation you can download precompiled binaries from the +[official downloads site](http://download.eclipse.org/jdtls/snapshots/?d) + +Due to the nature of java, settings cannot be inferred. Please set the following +environmental variables to match your installation. If you need per-project configuration +[direnv](https://github.com/direnv/direnv) is highly recommended. + +```bash +# Mandatory: +# .bashrc +export JDTLS_HOME=/path/to/jdtls_root # Directory with the plugin and configs directories + +# Optional: +export JAVA_HOME=/path/to/java_home # In case you don't have java in path or want to use a version in particular +export WORKSPACE=/path/to/workspace # Defaults to $HOME/workspace +``` +```lua + -- init.lua + require'lspconfig'.jdtls.setup{} +``` + +For automatic installation you can use the following unofficial installers/launchers under your own risk: + - [jdtls-launcher](https://github.com/eruizc-dev/jdtls-launcher) (Includes lombok support by default) + ```lua + -- init.lua + require'lspconfig'.jdtls.setup{ cmd = { 'jdtls' } } + ``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.jdtls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "/usr/lib/jvm/temurin-11-jdk-amd64/bin/java", "-Declipse.application=org.eclipse.jdt.ls.core.id1", "-Dosgi.bundles.defaultStartLevel=4", "-Declipse.product=org.eclipse.jdt.ls.core.product", "-Dlog.protocol=true", "-Dlog.level=ALL", "-Xms1g", "-Xmx2G", "--add-modules=ALL-SYSTEM", "--add-opens", "java.base/java.util=ALL-UNNAMED", "--add-opens", "java.base/java.lang=ALL-UNNAMED", "-jar", "/plugins/org.eclipse.equinox.launcher_*.jar", "-configuration", "config_linux", "-data", "/home/runner/workspace" } + ``` + - `filetypes` : + ```lua + { "java" } + ``` + - `handlers` : + ```lua + { + ["language/status"] = , + ["textDocument/codeAction"] = , + ["textDocument/rename"] = , + ["workspace/applyEdit"] = + } + ``` + - `init_options` : + ```lua + { + jvm_args = {}, + workspace = "/home/runner/workspace" + } + ``` + - `root_dir` : + ```lua + { + -- Single-module projects + { + 'build.xml', -- Ant + 'pom.xml', -- Maven + 'settings.gradle', -- Gradle + 'settings.gradle.kts', -- Gradle + }, + -- Multi-module projects + { 'build.gradle', 'build.gradle.kts' }, + } or vim.fn.getcwd() + ``` + - `single_file_support` : + ```lua + true + ``` + + +## jedi_language_server + +https://github.com/pappasam/jedi-language-server + +`jedi-language-server`, a language server for Python, built on top of jedi + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.jedi_language_server.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "jedi-language-server" } + ``` + - `filetypes` : + ```lua + { "python" } + ``` + - `root_dir` : + ```lua + vim's starting directory + ``` + - `single_file_support` : + ```lua + true + ``` + + +## jsonls + +https://github.com/hrsh7th/vscode-langservers-extracted + +vscode-json-language-server, a language server for JSON and JSON schema + +`vscode-json-language-server` can be installed via `npm`: +```sh +npm i -g vscode-langservers-extracted +``` + +Neovim does not currently include built-in snippets. `vscode-json-language-server` only provides completions when snippet support is enabled. To enable completion, install a snippet plugin and add the following override to your language client capabilities during setup. + +```lua +--Enable (broadcasting) snippet capability for completion +local capabilities = vim.lsp.protocol.make_client_capabilities() +capabilities.textDocument.completion.completionItem.snippetSupport = true + +require'lspconfig'.jsonls.setup { + capabilities = capabilities, +} +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.jsonls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "vscode-json-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "json", "jsonc" } + ``` + - `init_options` : + ```lua + { + provideFormatter = true + } + ``` + - `root_dir` : + ```lua + util.find_git_ancestor + ``` + - `single_file_support` : + ```lua + true + ``` + + +## jsonnet_ls + +https://github.com/grafana/jsonnet-language-server + +A Language Server Protocol (LSP) server for Jsonnet. + +The language server can be installed with `go`: +```sh +go install github.com/grafana/jsonnet-language-server@latest +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.jsonnet_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "jsonnet-language-server" } + ``` + - `filetypes` : + ```lua + { "jsonnet", "libsonnet" } + ``` + - `on_new_config` : + ```lua + see source file + ``` + - `root_dir` : + ```lua + root_pattern("jsonnetfile.json") + ``` + + +## julials + +https://github.com/julia-vscode/julia-vscode + +LanguageServer.jl can be installed with `julia` and `Pkg`: +```sh +julia --project=~/.julia/environments/nvim-lspconfig -e 'using Pkg; Pkg.add("LanguageServer")' +``` +where `~/.julia/environments/nvim-lspconfig` is the location where +the default configuration expects LanguageServer.jl to be installed. + +To update an existing install, use the following command: +```sh +julia --project=~/.julia/environments/nvim-lspconfig -e 'using Pkg; Pkg.update()' +``` + +Note: In order to have LanguageServer.jl pick up installed packages or dependencies in a +Julia project, you must make sure that the project is instantiated: +```sh +julia --project=/path/to/my/project -e 'using Pkg; Pkg.instantiate()' +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.julials.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "julia", "--startup-file=no", "--history-file=no", "-e", ' # Load LanguageServer.jl: attempt to load from ~/.julia/environments/nvim-lspconfig\n # with the regular load path as a fallback\n ls_install_path = joinpath(\n get(DEPOT_PATH, 1, joinpath(homedir(), ".julia")),\n "environments", "nvim-lspconfig"\n )\n pushfirst!(LOAD_PATH, ls_install_path)\n using LanguageServer\n popfirst!(LOAD_PATH)\n depot_path = get(ENV, "JULIA_DEPOT_PATH", "")\n project_path = let\n dirname(something(\n ## 1. Finds an explicitly set project (JULIA_PROJECT)\n Base.load_path_expand((\n p = get(ENV, "JULIA_PROJECT", nothing);\n p === nothing ? nothing : isempty(p) ? nothing : p\n )),\n ## 2. Look for a Project.toml file in the current working directory,\n ## or parent directories, with $HOME as an upper boundary\n Base.current_project(),\n ## 3. First entry in the load path\n get(Base.load_path(), 1, nothing),\n ## 4. Fallback to default global environment,\n ## this is more or less unreachable\n Base.load_path_expand("@v#.#"),\n ))\n end\n @info "Running language server" VERSION pwd() project_path depot_path\n server = LanguageServer.LanguageServerInstance(stdin, stdout, project_path, depot_path)\n server.runlinter = true\n run(server)\n ' } + ``` + - `filetypes` : + ```lua + { "julia" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `single_file_support` : + ```lua + true + ``` + + +## kotlin_language_server + + A kotlin language server which was developed for internal usage and + released afterwards. Maintaining is not done by the original author, + but by fwcd. + + It is built via gradle and developed on github. + Source and additional description: + https://github.com/fwcd/kotlin-language-server + + This server requires vim to be aware of the kotlin-filetype. + You could refer for this capability to: + https://github.com/udalov/kotlin-vim (recommended) + Note that there is no LICENSE specified yet. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.kotlin_language_server.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "kotlin-language-server" } + ``` + - `filetypes` : + ```lua + { "kotlin" } + ``` + - `root_dir` : + ```lua + root_pattern("settings.gradle") + ``` + + +## lean3ls + +https://github.com/leanprover/lean-client-js/tree/master/lean-language-server + +Lean installation instructions can be found +[here](https://leanprover-community.github.io/get_started.html#regular-install). + +Once Lean is installed, you can install the Lean 3 language server by running +```sh +npm install -g lean-language-server +``` + +Note: that if you're using [lean.nvim](https://github.com/Julian/lean.nvim), +that plugin fully handles the setup of the Lean language server, +and you shouldn't set up `lean3ls` both with it and `lspconfig`. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.lean3ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "lean-language-server", "--stdio", "--", "-M", "4096", "-T", "100000" } + ``` + - `filetypes` : + ```lua + { "lean3" } + ``` + - `offset_encoding` : + ```lua + "utf-32" + ``` + - `root_dir` : + ```lua + root_pattern("leanpkg.toml") or root_pattern(".git") + ``` + - `single_file_support` : + ```lua + true + ``` + + +## leanls + +https://github.com/leanprover/lean4 + +Lean installation instructions can be found +[here](https://leanprover-community.github.io/get_started.html#regular-install). + +The Lean 4 language server is built-in with a Lean 4 install +(and can be manually run with, e.g., `lean --server`). + +Note: that if you're using [lean.nvim](https://github.com/Julian/lean.nvim), +that plugin fully handles the setup of the Lean language server, +and you shouldn't set up `leanls` both with it and `lspconfig`. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.leanls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "lake", "serve", "--" } + ``` + - `filetypes` : + ```lua + { "lean" } + ``` + - `on_new_config` : + ```lua + see source file + ``` + - `options` : + ```lua + { + no_lake_lsp_cmd = { "lean", "--server" } + } + ``` + - `root_dir` : + ```lua + root_pattern("lakefile.lean", "lean-toolchain", "leanpkg.toml", ".git") + ``` + - `single_file_support` : + ```lua + true + ``` + + +## lelwel_ls + +https://github.com/0x2a-42/lelwel + +Language server for lelwel grammars. + +You can install `lelwel-ls` via cargo: +```sh +cargo install --features="lsp" lelwel +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.lelwel_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "lelwel-ls" } + ``` + - `filetypes` : + ```lua + { "llw" } + ``` + - `root_dir` : + ```lua + see source file + ``` + + +## lemminx + +https://github.com/eclipse/lemminx + +The easiest way to install the server is to get a binary at https://download.jboss.org/jbosstools/vscode/stable/lemminx-binary/ and place it in your PATH. + +NOTE to macOS users: Binaries from unidentified developers are blocked by default. If you trust the downloaded binary from jboss.org, run it once, cancel the prompt, then remove the binary from Gatekeeper quarantine with `xattr -d com.apple.quarantine lemminx`. It should now run without being blocked. + + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.lemminx.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "lemminx" } + ``` + - `filetypes` : + ```lua + { "xml", "xsd", "xsl", "xslt", "svg" } + ``` + - `root_dir` : + ```lua + util.find_git_ancestor + ``` + - `single_file_support` : + ```lua + true + ``` + + +## ltex + +https://github.com/valentjn/ltex-ls + +LTeX Language Server: LSP language server for LanguageTool 🔍✔️ with support for LaTeX 🎓, Markdown 📝, and others + +To install, download the latest [release](https://github.com/valentjn/ltex-ls/releases) and ensure `ltex-ls` is on your path. + +To support org files or R sweave, users can define a custom filetype autocommand (or use a plugin which defines these filetypes): + +```lua +vim.cmd [[ autocmd BufRead,BufNewFile *.org set filetype=org ]] +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.ltex.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "ltex-ls" } + ``` + - `filetypes` : + ```lua + { "bib", "gitcommit", "markdown", "org", "plaintex", "rst", "rnoweb", "tex" } + ``` + - `get_language_id` : + ```lua + see source file + ``` + - `root_dir` : + ```lua + see source file + ``` + - `single_file_support` : + ```lua + true + ``` + + +## metals + +https://scalameta.org/metals/ + +Scala language server with rich IDE features. + +See full instructions in the Metals documentation: + +https://scalameta.org/metals/docs/editors/vim.html#using-an-alternative-lsp-client + +Note: that if you're using [nvim-metals](https://github.com/scalameta/nvim-metals), that plugin fully handles the setup and installation of Metals, and you shouldn't set up Metals both with it and `lspconfig`. + +To install Metals, make sure to have [coursier](https://get-coursier.io/docs/cli-installation) installed, and once you do you can install the latest Metals with `cs install metals`. You can also manually bootstrap Metals with the following command. + +```bash +cs bootstrap \ + --java-opt -Xss4m \ + --java-opt -Xms100m \ + org.scalameta:metals_2.12: \ + -r bintray:scalacenter/releases \ + -r sonatype:snapshots \ + -o /usr/local/bin/metals -f +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.metals.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "metals" } + ``` + - `filetypes` : + ```lua + { "scala" } + ``` + - `init_options` : + ```lua + { + compilerOptions = { + snippetAutoIndent = false + }, + isHttpEnabled = true, + statusBarProvider = "show-message" + } + ``` + - `message_level` : + ```lua + 4 + ``` + - `root_dir` : + ```lua + util.root_pattern("build.sbt", "build.sc", "build.gradle", "pom.xml") + ``` + + +## mint + +https://www.mint-lang.com + +Install Mint using the [instructions](https://www.mint-lang.com/install). +The language server is included since version 0.12.0. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.mint.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "mint", "ls" } + ``` + - `filetypes` : + ```lua + { "mint" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `single_file_support` : + ```lua + true + ``` + + +## mm0_ls + +https://github.com/digama0/mm0 + +Language Server for the metamath-zero theorem prover. + +Requires [mm0-rs](https://github.com/digama0/mm0/tree/master/mm0-rs) to be installed +and available on the `PATH`. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.mm0_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "mm0-rs", "server" } + ``` + - `filetypes` : + ```lua + { "metamath-zero" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `single_file_support` : + ```lua + true + ``` + + +## nickel_ls + +Nickel Language Server + +https://github.com/tweag/nickel + +`nls` can be installed with nix, or cargo, from the Nickel repository. +```sh +git clone https://github.com/tweag/nickel.git +``` + +Nix: +```sh +cd nickel +nix-env -f . -i +``` + +cargo: +```sh +cd nickel/lsp/nls +cargo install --path . +``` + +In order to have lspconfig detect Nickel filetypes (a prequisite for autostarting a server), +install the [Nickel vim plugin](https://github.com/nickel-lang/vim-nickel). + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.nickel_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "nls" } + ``` + - `filetypes` : + ```lua + { "ncl", "nickel" } + ``` + - `root_dir` : + ```lua + see source file + ``` + + +## nimls + +https://github.com/PMunch/nimlsp +`nimlsp` can be installed via the `nimble` package manager: +```sh +nimble install nimlsp +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.nimls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "nimlsp" } + ``` + - `filetypes` : + ```lua + { "nim" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `single_file_support` : + ```lua + true + ``` + + +## ocamlls + +https://github.com/ocaml-lsp/ocaml-language-server + +`ocaml-language-server` can be installed via `npm` +```sh +npm install -g ocaml-language-server +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.ocamlls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "ocaml-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "ocaml", "reason" } + ``` + - `root_dir` : + ```lua + root_pattern("*.opam", "esy.json", "package.json") + ``` + + +## ocamllsp + +https://github.com/ocaml/ocaml-lsp + +`ocaml-lsp` can be installed as described in [installation guide](https://github.com/ocaml/ocaml-lsp#installation). + +To install the lsp server in a particular opam switch: +```sh +opam pin add ocaml-lsp-server https://github.com/ocaml/ocaml-lsp.git +opam install ocaml-lsp-server +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.ocamllsp.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "ocamllsp" } + ``` + - `filetypes` : + ```lua + { "ocaml", "ocaml.menhir", "ocaml.interface", "ocaml.ocamllex", "reason" } + ``` + - `get_language_id` : + ```lua + see source file + ``` + - `root_dir` : + ```lua + root_pattern("*.opam", "esy.json", "package.json", ".git") + ``` + + +## ols + + https://github.com/DanielGavin/ols + + `Odin Language Server`. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.ols.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "ols" } + ``` + - `filetypes` : + ```lua + { "odin" } + ``` + - `root_dir` : + ```lua + util.root_pattern("ols.json", ".git") + ``` + - `single_file_support` : + ```lua + true + ``` + + +## omnisharp + +https://github.com/omnisharp/omnisharp-roslyn +OmniSharp server based on Roslyn workspaces + +`omnisharp-roslyn` can be installed by downloading and extracting a release from [here](https://github.com/OmniSharp/omnisharp-roslyn/releases). +Omnisharp can also be built from source by following the instructions [here](https://github.com/omnisharp/omnisharp-roslyn#downloading-omnisharp). + +Omnisharp requires the [dotnet-sdk](https://dotnet.microsoft.com/download) to be installed. + +**By default, omnisharp-roslyn doesn't have a `cmd` set.** This is because nvim-lspconfig does not make assumptions about your path. You must add the following to your init.vim or init.lua to set `cmd` to the absolute path ($HOME and ~ are not expanded) of the unzipped run script or binary. + +```lua +local pid = vim.fn.getpid() +-- On linux/darwin if using a release build, otherwise under scripts/OmniSharp(.Core)(.cmd) +local omnisharp_bin = "/path/to/omnisharp-repo/run" +-- on Windows +-- local omnisharp_bin = "/path/to/omnisharp/OmniSharp.exe" +require'lspconfig'.omnisharp.setup{ + cmd = { omnisharp_bin, "--languageserver" , "--hostPID", tostring(pid) }; + ... +} +``` + +Note, if you download the executable for darwin you will need to strip the quarantine label to run: +```bash +find /path/to/omnisharp-osx | xargs xattr -r -d com.apple.quarantine +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.omnisharp.setup{} +``` + + +**Default values:** + - `filetypes` : + ```lua + { "cs", "vb" } + ``` + - `init_options` : + ```lua + {} + ``` + - `on_new_config` : + ```lua + see source file + ``` + - `root_dir` : + ```lua + root_pattern(".sln") or root_pattern(".csproj") + ``` + + +## opencl_ls + +https://github.com/Galarius/opencl-language-server + +Build instructions can be found [here](https://github.com/Galarius/opencl-language-server/blob/main/_dev/build.md). + +Prebuilt binaries are available for Linux, macOS and Windows [here](https://github.com/Galarius/opencl-language-server/releases). + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.opencl_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "opencl-language-server" } + ``` + - `filetypes` : + ```lua + { "opencl" } + ``` + - `root_dir` : + ```lua + util.root_pattern(".git") + ``` + + +## openscad_ls + +https://github.com/dzhu/openscad-language-server + +A Language Server Protocol server for OpenSCAD + +You can build and install `openscad-language-server` binary with `cargo`: +```sh +cargo install openscad-language-server +``` + +Vim does not have built-in syntax for the `openscad` filetype currently. + +This can be added via an autocmd: + +```lua +vim.cmd [[ autocmd BufRead,BufNewFile *.scad set filetype=openscad ]] +``` + +or by installing a filetype plugin such as https://github.com/sirtaj/vim-openscad + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.openscad_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "openscad-language-server" } + ``` + - `filetypes` : + ```lua + { "openscad" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `single_file_support` : + ```lua + true + ``` + + +## pasls + +https://github.com/genericptr/pascal-language-server + +An LSP server implementation for Pascal variants that are supported by Free Pascal, including Object Pascal. It uses CodeTools from Lazarus as backend. + +First set `cmd` to the Pascal lsp binary. + +Customization options are passed to pasls as environment variables for example in your `.bashrc`: +```bash +export FPCDIR='/usr/lib/fpc/src' # FPC source directory (This is the only required option for the server to work). +export PP='/usr/lib/fpc/3.2.2/ppcx64' # Path to the Free Pascal compiler executable. +export LAZARUSDIR='/usr/lib/lazarus' # Path to the Lazarus sources. +export FPCTARGET='' # Target operating system for cross compiling. +export FPCTARGETCPU='x86_64' # Target CPU for cross compiling. +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.pasls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "pasls" } + ``` + - `filetypes` : + ```lua + { "pascal" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `single_file_support` : + ```lua + true + ``` + + +## perlls + +https://github.com/richterger/Perl-LanguageServer/tree/master/clients/vscode/perl + +`Perl-LanguageServer`, a language server for Perl. + +To use the language server, ensure that you have Perl::LanguageServer installed and perl command is on your path. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.perlls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "perl", "-MPerl::LanguageServer", "-e", "Perl::LanguageServer::run", "--", "--port 13603", "--nostdio 0", "--version 2.1.0" } + ``` + - `filetypes` : + ```lua + { "perl" } + ``` + - `root_dir` : + ```lua + vim's starting directory + ``` + - `settings` : + ```lua + { + perl = { + fileFilter = { ".pm", ".pl" }, + ignoreDirs = ".git", + perlCmd = "perl", + perlInc = " " + } + } + ``` + - `single_file_support` : + ```lua + true + ``` + + +## perlnavigator + +https://github.com/bscan/PerlNavigator + +A Perl language server + +**By default, perlnavigator doesn't have a `cmd` set.** This is because nvim-lspconfig does not make assumptions about your path. +You have to install the language server manually. + +Clone the PerlNavigator repo, install based on the [instructions](https://github.com/bscan/PerlNavigator#installation-for-other-editors), +and point `cmd` to `server.js` inside the `server/out` directory: + +```lua +cmd = {'node', '/server/out/server.js', '--stdio'} +``` + +At minimum, you will need `perl` in your path. If you want to use a non-standard `perl` you will need to set your configuration like so: +```lua +settings = { + perlnavigator = { + perlPath = '/some/odd/location/my-perl' + } +} +``` + +The `contributes.configuration.properties` section of `perlnavigator`'s `package.json` has all available configuration settings. All +settings have a reasonable default, but, at minimum, you may want to point `perlnavigator` at your `perltidy` and `perlcritic` configurations. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.perlnavigator.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + {} + ``` + - `filetypes` : + ```lua + { "perl" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `single_file_support` : + ```lua + true + ``` + + +## perlpls + +https://github.com/FractalBoy/perl-language-server +https://metacpan.org/pod/PLS + +`PLS`, another language server for Perl. + +To use the language server, ensure that you have PLS installed and that it is in your path + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.perlpls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "pls" } + ``` + - `filetypes` : + ```lua + { "perl" } + ``` + - `root_dir` : + ```lua + util.find_git_ancestor + ``` + - `settings` : + ```lua + { + perl = { + perlcritic = { + enabled = false + }, + syntax = { + enabled = true + } + } + } + ``` + - `single_file_support` : + ```lua + true + ``` + + +## phpactor + +https://github.com/phpactor/phpactor + +Installation: https://phpactor.readthedocs.io/en/master/usage/standalone.html#global-installation + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.phpactor.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "phpactor", "language-server" } + ``` + - `filetypes` : + ```lua + { "php" } + ``` + - `root_dir` : + ```lua + root_pattern("composer.json", ".git") + ``` + + +## please + +https://github.com/thought-machine/please + +High-performance extensible build system for reproducible multi-language builds. + +The `plz` binary will automatically install the LSP for you on first run + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.please.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "plz", "tool", "lps" } + ``` + - `filetypes` : + ```lua + { "bzl" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `single_file_support` : + ```lua + true + ``` + + +## powershell_es + +https://github.com/PowerShell/PowerShellEditorServices + +Language server for PowerShell. + +To install, download and extract PowerShellEditorServices.zip +from the [releases](https://github.com/PowerShell/PowerShellEditorServices/releases). +To configure the language server, set the property `bundle_path` to the root +of the extracted PowerShellEditorServices.zip. + +The default configuration doesn't set `cmd` unless `bundle_path` is specified. + +```lua +require'lspconfig'.powershell_es.setup{ + bundle_path = 'c:/w/PowerShellEditorServices', +} +``` + +By default the languageserver is started in `pwsh` (PowerShell Core). This can be changed by specifying `shell`. + +```lua +require'lspconfig'.powershell_es.setup{ + bundle_path = 'c:/w/PowerShellEditorServices', + shell = 'powershell.exe', +} +``` + +Note that the execution policy needs to be set to `Unrestricted` for the languageserver run under PowerShell + +If necessary, specific `cmd` can be defined instead of `bundle_path`. +See [PowerShellEditorServices](https://github.com/PowerShell/PowerShellEditorServices#stdio) +to learn more. + +```lua +require'lspconfig'.powershell_es.setup{ + cmd = {'pwsh', '-NoLogo', '-NoProfile', '-Command', "c:/PSES/Start-EditorServices.ps1 ..."} +} +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.powershell_es.setup{} +``` + + +**Default values:** + - `filetypes` : + ```lua + { "ps1" } + ``` + - `on_new_config` : + ```lua + see source file + ``` + - `root_dir` : + ```lua + git root or current directory + ``` + - `shell` : + ```lua + "pwsh" + ``` + - `single_file_support` : + ```lua + true + ``` + + +## prismals + +Language Server for the Prisma JavaScript and TypeScript ORM + +`@prisma/language-server` can be installed via npm +```sh +npm install -g @prisma/language-server +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.prismals.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "prisma-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "prisma" } + ``` + - `root_dir` : + ```lua + root_pattern(".git", "package.json") + ``` + - `settings` : + ```lua + { + prisma = { + prismaFmtBinPath = "" + } + } + ``` + + +## prosemd_lsp + +https://github.com/kitten/prosemd-lsp + +An experimental LSP for Markdown. + +Please see the manual installation instructions: https://github.com/kitten/prosemd-lsp#manual-installation + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.prosemd_lsp.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "prosemd-lsp", "--stdio" } + ``` + - `filetypes` : + ```lua + { "markdown" } + ``` + - `root_dir` : + ```lua + + ``` + - `single_file_support` : + ```lua + true + ``` + + +## psalm + +https://github.com/vimeo/psalm + +Can be installed with composer. +```sh +composer global require vimeo/psalm +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.psalm.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "psalm-language-server" } + ``` + - `filetypes` : + ```lua + { "php" } + ``` + - `root_dir` : + ```lua + root_pattern("psalm.xml", "psalm.xml.dist") + ``` + + +## puppet + +LSP server for Puppet. + +Installation: + +- Clone the editor-services repository: + https://github.com/puppetlabs/puppet-editor-services + +- Navigate into that directory and run: `bundle install` + +- Install the 'puppet-lint' gem: `gem install puppet-lint` + +- Add that repository to $PATH. + +- Ensure you can run `puppet-languageserver` from outside the editor-services directory. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.puppet.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "puppet-languageserver", "--stdio" } + ``` + - `filetypes` : + ```lua + { "puppet" } + ``` + - `root_dir` : + ```lua + root_pattern("manifests", ".puppet-lint.rc", "hiera.yaml", ".git") + ``` + - `single_file_support` : + ```lua + true + ``` + + +## purescriptls + +https://github.com/nwolverson/purescript-language-server +`purescript-language-server` can be installed via `npm` +```sh +npm install -g purescript-language-server +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.purescriptls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "purescript-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "purescript" } + ``` + - `root_dir` : + ```lua + root_pattern("spago.dhall, 'psc-package.json', bower.json") + ``` + + +## pylsp + +https://github.com/python-lsp/python-lsp-server + +A Python 3.6+ implementation of the Language Server Protocol. + +The language server can be installed via `pipx install 'python-lsp-server[all]'`. +Further instructions can be found in the [project's README](https://github.com/python-lsp/python-lsp-server). + +Note: This is a community fork of `pyls`. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.pylsp.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "pylsp" } + ``` + - `filetypes` : + ```lua + { "python" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `single_file_support` : + ```lua + true + ``` + + +## pyre + +https://pyre-check.org/ + +`pyre` a static type checker for Python 3. + +`pyre` offers an extremely limited featureset. It currently only supports diagnostics, +which are triggered on save. + +Do not report issues for missing features in `pyre` to `lspconfig`. + + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.pyre.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "pyre", "persistent" } + ``` + - `filetypes` : + ```lua + { "python" } + ``` + - `root_dir` : + ```lua + see source file + ``` + + +## pyright + +https://github.com/microsoft/pyright + +`pyright`, a static type checker and language server for python + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.pyright.setup{} +``` +**Commands:** +- PyrightOrganizeImports: Organize Imports + +**Default values:** + - `cmd` : + ```lua + { "pyright-langserver", "--stdio" } + ``` + - `filetypes` : + ```lua + { "python" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `settings` : + ```lua + { + python = { + analysis = { + autoSearchPaths = true, + diagnosticMode = "workspace", + useLibraryCodeForTypes = true + } + } + } + ``` + - `single_file_support` : + ```lua + true + ``` + + +## quick_lint_js + +https://quick-lint-js.com/ + +quick-lint-js finds bugs in JavaScript programs. + +See installation [instructions](https://quick-lint-js.com/install/) + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.quick_lint_js.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "quick-lint-js", "--lsp-server" } + ``` + - `filetypes` : + ```lua + { "javascript" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `single_file_support` : + ```lua + true + ``` + + +## r_language_server + +[languageserver](https://github.com/REditorSupport/languageserver) is an +implementation of the Microsoft's Language Server Protocol for the R +language. + +It is released on CRAN and can be easily installed by + +```R +install.packages("languageserver") +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.r_language_server.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "R", "--slave", "-e", "languageserver::run()" } + ``` + - `filetypes` : + ```lua + { "r", "rmd" } + ``` + - `log_level` : + ```lua + 2 + ``` + - `root_dir` : + ```lua + root_pattern(".git") or os_homedir + ``` + + +## racket_langserver + +[https://github.com/jeapostrophe/racket-langserver](https://github.com/jeapostrophe/racket-langserver) + +The Racket language server. This project seeks to use +[DrRacket](https://github.com/racket/drracket)'s public API to provide +functionality that mimics DrRacket's code tools as closely as possible. + +Install via `raco`: `raco pkg install racket-langserver` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.racket_langserver.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "racket", "--lib", "racket-langserver" } + ``` + - `filetypes` : + ```lua + { "racket", "scheme" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `single_file_support` : + ```lua + true + ``` + + +## reason_ls + +Reason language server + +**By default, reason_ls doesn't have a `cmd` set.** This is because nvim-lspconfig does not make assumptions about your path. +You have to install the language server manually. + +You can install reason language server from [reason-language-server](https://github.com/jaredly/reason-language-server) repository. + +```lua +cmd = {''} +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.reason_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "reason-language-server" } + ``` + - `filetypes` : + ```lua + { "reason" } + ``` + - `root_dir` : + ```lua + see source file + ``` + + +## remark_ls + +https://github.com/remarkjs/remark-language-server + +`remark-language-server` can be installed via `npm`: +```sh +npm install -g remark-language-server +``` + +`remark-language-server` uses the same +[configuration files](https://github.com/remarkjs/remark/tree/main/packages/remark-cli#example-config-files-json-yaml-js) +as `remark-cli`. + +This uses a plugin based system. Each plugin needs to be installed locally using `npm` or `yarn`. + +For example, given the following `.remarkrc.json`: + +```json +{ + "presets": [ + "remark-preset-lint-recommended" + ] +} +``` + +`remark-preset-lint-recommended` needs to be installed in the local project: + +```sh +npm install remark-preset-lint-recommended +``` + + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.remark_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "remark-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "markdown" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `single_file_support` : + ```lua + true + ``` + + +## rescriptls + +https://github.com/rescript-lang/rescript-vscode + +ReScript language server + +**By default, rescriptls doesn't have a `cmd` set.** This is because nvim-lspconfig does not make assumptions about your path. +You have to install the language server manually. + +You can use the bundled language server inside the [vim-rescript](https://github.com/rescript-lang/vim-rescript) repo. + +Clone the vim-rescript repo and point `cmd` to `server.js` inside `server/out` directory: + +```lua +cmd = {'node', '/server/out/server.js', '--stdio'} + +``` + +If you have vim-rescript installed you can also use that installation. for example if you're using packer.nvim you can set cmd to something like this: + +```lua +cmd = { + 'node', + '/home/username/.local/share/nvim/site/pack/packer/start/vim-rescript/server/out/server.js', + '--stdio' +} +``` + +Another option is to use vscode extension [release](https://github.com/rescript-lang/rescript-vscode/releases). +Take a look at [here](https://github.com/rescript-lang/rescript-vscode#use-with-other-editors) for instructions. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.rescriptls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + {} + ``` + - `filetypes` : + ```lua + { "rescript" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `settings` : + ```lua + {} + ``` + + +## rls + +https://github.com/rust-lang/rls + +rls, a language server for Rust + +See https://github.com/rust-lang/rls#setup to setup rls itself. +See https://github.com/rust-lang/rls#configuration for rls-specific settings. +All settings listed on the rls configuration section of the readme +must be set under settings.rust as follows: + +```lua +nvim_lsp.rls.setup { + settings = { + rust = { + unstable_features = true, + build_on_save = false, + all_features = true, + }, + }, +} +``` + +If you want to use rls for a particular build, eg nightly, set cmd as follows: + +```lua +cmd = {"rustup", "run", "nightly", "rls"} +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.rls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "rls" } + ``` + - `filetypes` : + ```lua + { "rust" } + ``` + - `root_dir` : + ```lua + root_pattern("Cargo.toml") + ``` + + +## rnix + +https://github.com/nix-community/rnix-lsp + +A language server for Nix providing basic completion and formatting via nixpkgs-fmt. + +To install manually, run `cargo install rnix-lsp`. If you are using nix, rnix-lsp is in nixpkgs. + +This server accepts configuration via the `settings` key. + + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.rnix.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "rnix-lsp" } + ``` + - `filetypes` : + ```lua + { "nix" } + ``` + - `init_options` : + ```lua + {} + ``` + - `root_dir` : + ```lua + vim's starting directory + ``` + - `settings` : + ```lua + {} + ``` + + +## robotframework_ls + +https://github.com/robocorp/robotframework-lsp + +Language Server Protocol implementation for Robot Framework. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.robotframework_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "robotframework_ls" } + ``` + - `filetypes` : + ```lua + { "robot" } + ``` + - `root_dir` : + ```lua + util.root_pattern('robotidy.toml', 'pyproject.toml')(fname) or util.find_git_ancestor(fname) + ``` + + +## rome + +https://rome.tools + +Language server for the Rome Frontend Toolchain. + +```sh +npm install [-g] rome +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.rome.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "rome", "lsp" } + ``` + - `filetypes` : + ```lua + { "javascript", "javascriptreact", "json", "typescript", "typescript.tsx", "typescriptreact" } + ``` + - `root_dir` : + ```lua + root_pattern('package.json', 'node_modules', '.git') + ``` + - `single_file_support` : + ```lua + true + ``` + + +## rust_analyzer + +https://github.com/rust-analyzer/rust-analyzer + +rust-analyzer (aka rls 2.0), a language server for Rust + +See [docs](https://github.com/rust-analyzer/rust-analyzer/tree/master/docs/user#settings) for extra settings. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.rust_analyzer.setup{} +``` +**Commands:** +- CargoReload: Reload current cargo workspace + +**Default values:** + - `cmd` : + ```lua + { "rust-analyzer" } + ``` + - `filetypes` : + ```lua + { "rust" } + ``` + - `root_dir` : + ```lua + root_pattern("Cargo.toml", "rust-project.json") + ``` + - `settings` : + ```lua + { + ["rust-analyzer"] = {} + } + ``` + + +## salt_ls + +Language server for Salt configuration files. +https://github.com/dcermak/salt-lsp + +The language server can be installed with `pip`: +```sh +pip install salt-lsp +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.salt_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "salt_lsp_server" } + ``` + - `filetypes` : + ```lua + { "sls" } + ``` + - `root_dir` : + ```lua + root_pattern('.git') + ``` + - `single_file_support` : + ```lua + true + ``` + + +## scry + +https://github.com/crystal-lang-tools/scry + +Crystal language server. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.scry.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "scry" } + ``` + - `filetypes` : + ```lua + { "crystal" } + ``` + - `root_dir` : + ```lua + root_pattern('shard.yml', '.git') + ``` + - `single_file_support` : + ```lua + true + ``` + + +## serve_d + + https://github.com/Pure-D/serve-d + + `Microsoft language server protocol implementation for D using workspace-d.` + Download a binary from https://github.com/Pure-D/serve-d/releases and put it in your $PATH. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.serve_d.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "serve-d" } + ``` + - `filetypes` : + ```lua + { "d" } + ``` + - `root_dir` : + ```lua + util.root_pattern("dub.json", "dub.sdl", ".git") + ``` + + +## sixtyfps + +https://github.com/sixtyfpsui/sixtyfps +`SixtyFPS`'s language server + +You can build and install `sixtyfps-lsp` binary with `cargo`: +```sh +cargo install sixtyfps-lsp +``` + +Vim does not have built-in syntax for the `sixtyfps` filetype currently. + +This can be added via an autocmd: + +```lua +vim.cmd [[ autocmd BufRead,BufNewFile *.60 set filetype=sixtyfps ]] +``` + +or by installing a filetype plugin such as https://github.com/RustemB/sixtyfps-vim + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.sixtyfps.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "sixtyfps-lsp" } + ``` + - `filetypes` : + ```lua + { "sixtyfps" } + ``` + - `single_file_support` : + ```lua + true + ``` + + +## slint_lsp + +https://github.com/slint-ui/slint +`Slint`'s language server + +You can build and install `slint-lsp` binary with `cargo`: +```sh +cargo install slint-lsp +``` + +Vim does not have built-in syntax for the `slint` filetype at this time. + +This can be added via an autocmd: + +```lua +vim.cmd [[ autocmd BufRead,BufNewFile *.slint set filetype=slint ]] +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.slint_lsp.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "slint-lsp" } + ``` + - `filetypes` : + ```lua + { "slint" } + ``` + - `single_file_support` : + ```lua + true + ``` + + +## solang + +A language server for Solidity + +See the [documentation](https://solang.readthedocs.io/en/latest/installing.html) for installation instructions. + +The language server only provides the following capabilities: +* Syntax highlighting +* Diagnostics +* Hover + +There is currently no support for completion, goto definition, references, or other functionality. + + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.solang.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "solang", "--language-server", "--target", "ewasm" } + ``` + - `filetypes` : + ```lua + { "solidity" } + ``` + - `root_dir` : + ```lua + util.find_git_ancestor + ``` + + +## solargraph + +https://solargraph.org/ + +solargraph, a language server for Ruby + +You can install solargraph via gem install. + +```sh +gem install --user-install solargraph +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.solargraph.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "solargraph", "stdio" } + ``` + - `filetypes` : + ```lua + { "ruby" } + ``` + - `init_options` : + ```lua + { + formatting = true + } + ``` + - `root_dir` : + ```lua + root_pattern("Gemfile", ".git") + ``` + - `settings` : + ```lua + { + solargraph = { + diagnostics = true + } + } + ``` + + +## solc + +https://docs.soliditylang.org/en/latest/installing-solidity.html + +solc is the native language server for the Solidity language. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.solc.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "solc", "--lsp" } + ``` + - `filetypes` : + ```lua + { "solidity" } + ``` + - `root_dir` : + ```lua + root_pattern(".git") + ``` + + +## solidity_ls + +npm install -g solidity-language-server + +solidity-language-server is a language server for the solidity language ported from the vscode solidity extension + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.solidity_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "solidity-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "solidity" } + ``` + - `root_dir` : + ```lua + root_pattern(".git", "package.json") + ``` + + +## sorbet + +https://sorbet.org + +Sorbet is a fast, powerful type checker designed for Ruby. + +You can install Sorbet via gem install. You might also be interested in how to set +Sorbet up for new projects: https://sorbet.org/docs/adopting. + +```sh +gem install sorbet +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.sorbet.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "srb", "tc", "--lsp" } + ``` + - `filetypes` : + ```lua + { "ruby" } + ``` + - `root_dir` : + ```lua + root_pattern("Gemfile", ".git") + ``` + + +## sourcekit + +https://github.com/apple/sourcekit-lsp + +Language server for Swift and C/C++/Objective-C. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.sourcekit.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "sourcekit-lsp" } + ``` + - `filetypes` : + ```lua + { "swift", "c", "cpp", "objective-c", "objective-cpp" } + ``` + - `root_dir` : + ```lua + root_pattern("Package.swift", ".git") + ``` + + +## sourcery + +https://github.com/sourcery-ai/sourcery + +Refactor Python instantly using the power of AI. + +It requires the initializationOptions param to be populated as shown below and will respond with the list of ServerCapabilities that it supports. + +init_options = { + --- The Sourcery token for authenticating the user. + --- This is retrieved from the Sourcery website and must be + --- provided by each user. The extension must provide a + --- configuration option for the user to provide this value. + token = + + --- The extension's name and version as defined by the extension. + extension_version = 'vim.lsp' + + --- The editor's name and version as defined by the editor. + editor_version = 'vim' +} + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.sourcery.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "sourcery", "lsp" } + ``` + - `filetypes` : + ```lua + { "python" } + ``` + - `init_options` : + ```lua + { + editor_version = "vim", + extension_version = "vim.lsp" + } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `single_file_support` : + ```lua + true + ``` + + +## spectral + +https://github.com/luizcorreia/spectral-language-server + `A flexible JSON/YAML linter for creating automated style guides, with baked in support for OpenAPI v2 & v3.` + +`spectral-language-server` can be installed via `npm`: +```sh +npm i -g spectral-language-server +``` +See [vscode-spectral](https://github.com/stoplightio/vscode-spectral#extension-settings) for configuration options. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.spectral.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "spectral-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "yaml", "json", "yml" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `settings` : + ```lua + { + enable = true, + run = "onType", + validateLanguages = { "yaml", "json", "yml" } + } + ``` + - `single_file_support` : + ```lua + true + ``` + + +## sqlls + +https://github.com/joe-re/sql-language-server + +This LSP can be installed via `npm`. Find further instructions on manual installation of the sql-language-server at [joe-re/sql-language-server](https://github.com/joe-re/sql-language-server). +
+ + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.sqlls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "sql-language-server", "up", "--method", "stdio" } + ``` + - `filetypes` : + ```lua + { "sql", "mysql" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `settings` : + ```lua + {} + ``` + + +## sqls + +https://github.com/lighttiger2505/sqls + +```lua +require'lspconfig'.sqls.setup{ + cmd = {"path/to/command", "-config", "path/to/config.yml"}; + ... +} +``` +Sqls can be installed via `go get github.com/lighttiger2505/sqls`. Instructions for compiling Sqls from the source can be found at [lighttiger2505/sqls](https://github.com/lighttiger2505/sqls). + + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.sqls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "sqls" } + ``` + - `filetypes` : + ```lua + { "sql", "mysql" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `settings` : + ```lua + {} + ``` + - `single_file_support` : + ```lua + true + ``` + + +## stylelint_lsp + +https://github.com/bmatcuk/stylelint-lsp + +`stylelint-lsp` can be installed via `npm`: + +```sh +npm i -g stylelint-lsp +``` + +Can be configured by passing a `settings.stylelintplus` object to `stylelint_lsp.setup`: + +```lua +require'lspconfig'.stylelint_lsp.setup{ + settings = { + stylelintplus = { + -- see available options in stylelint-lsp documentation + } + } +} +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.stylelint_lsp.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "stylelint-lsp", "--stdio" } + ``` + - `filetypes` : + ```lua + { "css", "less", "scss", "sugarss", "vue", "wxss", "javascript", "javascriptreact", "typescript", "typescriptreact" } + ``` + - `root_dir` : + ```lua + root_pattern('.stylelintrc', 'package.json') + ``` + - `settings` : + ```lua + {} + ``` + + +## sumneko_lua + +https://github.com/sumneko/lua-language-server + +Lua language server. + +`lua-language-server` can be installed by following the instructions [here](https://github.com/sumneko/lua-language-server/wiki/Build-and-Run). The default `cmd` assumes that the `lua-language-server` binary can be found in `$PATH`. + +```lua +local runtime_path = vim.split(package.path, ';') +table.insert(runtime_path, "lua/?.lua") +table.insert(runtime_path, "lua/?/init.lua") + +require'lspconfig'.sumneko_lua.setup { + settings = { + Lua = { + runtime = { + -- Tell the language server which version of Lua you're using (most likely LuaJIT in the case of Neovim) + version = 'LuaJIT', + -- Setup your lua path + path = runtime_path, + }, + diagnostics = { + -- Get the language server to recognize the `vim` global + globals = {'vim'}, + }, + workspace = { + -- Make the server aware of Neovim runtime files + library = vim.api.nvim_get_runtime_file("", true), + }, + -- Do not send telemetry data containing a randomized but unique identifier + telemetry = { + enable = false, + }, + }, + }, +} +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.sumneko_lua.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "lua-language-server" } + ``` + - `filetypes` : + ```lua + { "lua" } + ``` + - `log_level` : + ```lua + 2 + ``` + - `root_dir` : + ```lua + root_pattern(".luarc.json", ".luacheckrc", ".stylua.toml", "selene.toml", ".git") + ``` + - `settings` : + ```lua + { + Lua = { + telemetry = { + enable = false + } + } + } + ``` + - `single_file_support` : + ```lua + true + ``` + + +## svelte + +https://github.com/sveltejs/language-tools/tree/master/packages/language-server + +`svelte-language-server` can be installed via `npm`: +```sh +npm install -g svelte-language-server +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.svelte.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "svelteserver", "--stdio" } + ``` + - `filetypes` : + ```lua + { "svelte" } + ``` + - `root_dir` : + ```lua + root_pattern("package.json", ".git") + ``` + + +## svls + +https://github.com/dalance/svls + +Language server for verilog and SystemVerilog + +`svls` can be installed via `cargo`: + ```sh + cargo install svls + ``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.svls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "svls" } + ``` + - `filetypes` : + ```lua + { "verilog", "systemverilog" } + ``` + - `root_dir` : + ```lua + util.find_git_ancestor + ``` + + +## tailwindcss + +https://github.com/tailwindlabs/tailwindcss-intellisense + +Tailwind CSS Language Server can be installed via npm: +```sh +npm install -g @tailwindcss/language-server +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.tailwindcss.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "tailwindcss-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "aspnetcorerazor", "astro", "astro-markdown", "blade", "django-html", "htmldjango", "edge", "eelixir", "ejs", "erb", "eruby", "gohtml", "haml", "handlebars", "hbs", "html", "html-eex", "heex", "jade", "leaf", "liquid", "markdown", "mdx", "mustache", "njk", "nunjucks", "php", "razor", "slim", "twig", "css", "less", "postcss", "sass", "scss", "stylus", "sugarss", "javascript", "javascriptreact", "reason", "rescript", "typescript", "typescriptreact", "vue", "svelte" } + ``` + - `init_options` : + ```lua + { + userLanguages = { + eelixir = "html-eex", + eruby = "erb" + } + } + ``` + - `on_new_config` : + ```lua + see source file + ``` + - `root_dir` : + ```lua + root_pattern('tailwind.config.js', 'tailwind.config.ts', 'postcss.config.js', 'postcss.config.ts', 'package.json', 'node_modules', '.git') + ``` + - `settings` : + ```lua + { + tailwindCSS = { + classAttributes = { "class", "className", "classList", "ngClass" }, + lint = { + cssConflict = "warning", + invalidApply = "error", + invalidConfigPath = "error", + invalidScreen = "error", + invalidTailwindDirective = "error", + invalidVariant = "error", + recommendedVariantOrder = "warning" + }, + validate = true + } + } + ``` + + +## taplo + +https://taplo.tamasfe.dev/lsp/ + +Language server for Taplo, a TOML toolkit. + +`taplo-cli` can be installed via `cargo`: +```sh +cargo install --locked taplo-cli +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.taplo.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "taplo", "lsp", "stdio" } + ``` + - `filetypes` : + ```lua + { "toml" } + ``` + - `root_dir` : + ```lua + root_pattern("*.toml", ".git") + ``` + - `single_file_support` : + ```lua + true + ``` + + +## teal_ls + +https://github.com/teal-language/teal-language-server + +Install with: +``` +luarocks install --dev teal-language-server +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.teal_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "teal-language-server" } + ``` + - `filetypes` : + ```lua + { "teal" } + ``` + - `root_dir` : + ```lua + root_pattern("tlconfig.lua", ".git") + ``` + + +## terraform_lsp + +https://github.com/juliosueiras/terraform-lsp + +Terraform language server +Download a released binary from +https://github.com/juliosueiras/terraform-lsp/releases. + +From https://github.com/hashicorp/terraform-ls#terraform-ls-vs-terraform-lsp: + +Both HashiCorp and the maintainer of terraform-lsp expressed interest in +collaborating on a language server and are working towards a _long-term_ +goal of a single stable and feature-complete implementation. + +For the time being both projects continue to exist, giving users the +choice: + +- `terraform-ls` providing + - overall stability (by relying only on public APIs) + - compatibility with any provider and any Terraform >=0.12.0 currently + less features + - due to project being younger and relying on public APIs which may + not offer the same functionality yet + +- `terraform-lsp` providing + - currently more features + - compatibility with a single particular Terraform (0.12.20 at time of writing) + - configs designed for other 0.12 versions may work, but interpretation may be inaccurate + - less stability (due to reliance on Terraform's own internal packages) + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.terraform_lsp.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "terraform-lsp" } + ``` + - `filetypes` : + ```lua + { "terraform", "hcl" } + ``` + - `root_dir` : + ```lua + root_pattern(".terraform", ".git") + ``` + + +## terraformls + +https://github.com/hashicorp/terraform-ls + +Terraform language server +Download a released binary from https://github.com/hashicorp/terraform-ls/releases. + +From https://github.com/hashicorp/terraform-ls#terraform-ls-vs-terraform-lsp: + +Both HashiCorp and the maintainer of terraform-lsp expressed interest in +collaborating on a language server and are working towards a _long-term_ +goal of a single stable and feature-complete implementation. + +For the time being both projects continue to exist, giving users the +choice: + +- `terraform-ls` providing + - overall stability (by relying only on public APIs) + - compatibility with any provider and any Terraform >=0.12.0 currently + less features + - due to project being younger and relying on public APIs which may + not offer the same functionality yet + +- `terraform-lsp` providing + - currently more features + - compatibility with a single particular Terraform (0.12.20 at time of writing) + - configs designed for other 0.12 versions may work, but interpretation may be inaccurate + - less stability (due to reliance on Terraform's own internal packages) + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.terraformls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "terraform-ls", "serve" } + ``` + - `filetypes` : + ```lua + { "terraform" } + ``` + - `root_dir` : + ```lua + root_pattern(".terraform", ".git") + ``` + + +## texlab + +https://github.com/latex-lsp/texlab + +A completion engine built from scratch for (La)TeX. + +See https://github.com/latex-lsp/texlab/blob/master/docs/options.md for configuration options. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.texlab.setup{} +``` +**Commands:** +- TexlabBuild: Build the current buffer +- TexlabForward: Forward search from current position + +**Default values:** + - `cmd` : + ```lua + { "texlab" } + ``` + - `filetypes` : + ```lua + { "tex", "bib" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `settings` : + ```lua + { + texlab = { + auxDirectory = ".", + bibtexFormatter = "texlab", + build = { + args = { "-pdf", "-interaction=nonstopmode", "-synctex=1", "%f" }, + executable = "latexmk", + forwardSearchAfter = false, + onSave = false + }, + chktex = { + onEdit = false, + onOpenAndSave = false + }, + diagnosticsDelay = 300, + formatterLineLength = 80, + forwardSearch = { + args = {} + }, + latexFormatter = "latexindent", + latexindent = { + modifyLineBreaks = false + } + } + } + ``` + - `single_file_support` : + ```lua + true + ``` + + +## tflint + +https://github.com/terraform-linters/tflint + +A pluggable Terraform linter that can act as lsp server. +Installation instructions can be found in https://github.com/terraform-linters/tflint#installation. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.tflint.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "tflint", "--langserver" } + ``` + - `filetypes` : + ```lua + { "terraform" } + ``` + - `root_dir` : + ```lua + root_pattern(".terraform", ".git", ".tflint.hcl") + ``` + + +## theme_check + +https://github.com/Shopify/shopify-cli + +`theme-check-language-server` is bundled with `shopify-cli` or it can also be installed via + +https://github.com/Shopify/theme-check#installation + +**NOTE:** +If installed via Homebrew, `cmd` must be set to 'theme-check-liquid-server' + +```lua +require lspconfig.theme_check.setup { + cmd = { 'theme-check-liquid-server' } +} +``` + + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.theme_check.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "theme-check-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "liquid" } + ``` + - `root_dir` : + ```lua + see source file + ``` + - `settings` : + ```lua + {} + ``` + + +## tsserver + +https://github.com/theia-ide/typescript-language-server + +`typescript-language-server` depends on `typescript`. Both packages can be installed via `npm`: +```sh +npm install -g typescript typescript-language-server +``` + +To configure type language server, add a +[`tsconfig.json`](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html) or +[`jsconfig.json`](https://code.visualstudio.com/docs/languages/jsconfig) to the root of your +project. + +Here's an example that disables type checking in JavaScript files. + +```json +{ + "compilerOptions": { + "module": "commonjs", + "target": "es6", + "checkJs": false + }, + "exclude": [ + "node_modules" + ] +} +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.tsserver.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "typescript-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "javascript", "javascriptreact", "javascript.jsx", "typescript", "typescriptreact", "typescript.tsx" } + ``` + - `init_options` : + ```lua + { + hostInfo = "neovim" + } + ``` + - `root_dir` : + ```lua + root_pattern("package.json", "tsconfig.json", "jsconfig.json", ".git") + ``` + + +## typeprof + +https://github.com/ruby/typeprof + +`typeprof` is the built-in analysis and LSP tool for Ruby 3.1+. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.typeprof.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "typeprof", "--lsp", "--stdio" } + ``` + - `filetypes` : + ```lua + { "ruby", "eruby" } + ``` + - `root_dir` : + ```lua + root_pattern("Gemfile", ".git") + ``` + + +## vala_ls + +https://github.com/Prince781/vala-language-server + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.vala_ls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "vala-language-server" } + ``` + - `filetypes` : + ```lua + { "vala", "genie" } + ``` + - `root_dir` : + ```lua + root_pattern("meson.build", ".git") + ``` + - `single_file_support` : + ```lua + true + ``` + + +## vdmj + +https://github.com/nickbattle/vdmj + +The VDMJ language server can be installed by cloning the VDMJ repository and +running `mvn clean install`. + +Various options are provided to configure the language server (see below). In +particular: +- `annotation_paths` is a list of folders and/or jar file paths for annotations +that should be used with the language server; +- any value of `debugger_port` less than zero will disable the debugger; note +that if a non-zero value is used, only one instance of the server can be active +at a time. + +More settings for VDMJ can be changed in a file called `vdmj.properties` under +`root_dir/.vscode`. For a description of the available settings, see +[Section 7 of the VDMJ User Guide](https://raw.githubusercontent.com/nickbattle/vdmj/master/vdmj/documentation/UserGuide.pdf). + +Note: proof obligations and combinatorial testing are not currently supported +by neovim. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.vdmj.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + Generated from the options given + ``` + - `filetypes` : + ```lua + { "vdmsl", "vdmpp", "vdmrt" } + ``` + - `options` : + ```lua + { + annotation_paths = {}, + debugger_port = -1, + high_precision = false, + java = "$JAVA_HOME/bin/java", + java_opts = { "-Xmx3000m", "-Xss1m" }, + logfile = "path.join(vim.fn.stdpath 'cache', 'vdm-lsp.log')", + mavenrepo = "$HOME/.m2/repository/com/fujitsu", + version = "The latest version installed in `mavenrepo`" + } + ``` + - `root_dir` : + ```lua + util.find_git_ancestor(fname) or find_vscode_ancestor(fname) + ``` + + +## verible + +https://github.com/chipsalliance/verible + +A linter and formatter for verilog and SystemVerilog files. + +Release binaries can be downloaded from [here](https://github.com/chipsalliance/verible/releases) +and placed in a directory on PATH. + +See https://github.com/chipsalliance/verible/tree/master/verilog/tools/ls/README.md for options. + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.verible.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "verible-verilog-ls" } + ``` + - `filetypes` : + ```lua + { "systemverilog", "verilog" } + ``` + - `root_dir` : + ```lua + see source file + ``` + + +## vimls + +https://github.com/iamcco/vim-language-server + +You can install vim-language-server via npm: +```sh +npm install -g vim-language-server +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.vimls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "vim-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "vim" } + ``` + - `init_options` : + ```lua + { + diagnostic = { + enable = true + }, + indexes = { + count = 3, + gap = 100, + projectRootPatterns = { "runtime", "nvim", ".git", "autoload", "plugin" }, + runtimepath = true + }, + iskeyword = "@,48-57,_,192-255,-#", + runtimepath = "", + suggest = { + fromRuntimepath = true, + fromVimruntime = true + }, + vimruntime = "" + } + ``` + - `root_dir` : + ```lua + see source file + ``` + + +## vls + +https://github.com/vlang/vls + +V language server. + +`v-language-server` can be installed by following the instructions [here](https://github.com/vlang/vls#installation). + +**By default, v-language-server doesn't have a `cmd` set.** This is because nvim-lspconfig does not make assumptions about your path. You must add the following to your init.vim or init.lua to set `cmd` to the absolute path ($HOME and ~ are not expanded) of your unzipped and compiled v-language-server. + +```lua +-- set the path to the vls installation; +local vls_root_path = vim.fn.stdpath('cache')..'/lspconfig/vls' +local vls_binary = vls_root_path.."/cmd/vls/vls" + +require'lspconfig'.vls.setup { + cmd = {vls_binary}, +} +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.vls.setup{} +``` + + +**Default values:** + - `filetypes` : + ```lua + { "vlang" } + ``` + - `root_dir` : + ```lua + root_pattern("v.mod", ".git") + ``` + + +## volar + +https://github.com/johnsoncodehk/volar/tree/master/packages/vue-language-server + +Volar language server for Vue + +Volar can be installed via npm: + +```sh +npm install -g @volar/vue-language-server +``` + +Volar by default supports Vue 3 projects. Vue 2 projects need [additional configuration](https://github.com/johnsoncodehk/volar/blob/master/extensions/vscode-vue-language-features/README.md?plain=1#L28-L63). + +**Take Over Mode** +Volar can serve as a language server for both Vue and TypeScript via [Take Over Mode](https://github.com/johnsoncodehk/volar/discussions/471). + +To enable Take Over Mode, override the default filetypes in `setup{}` as follows: + +```lua +require'lspconfig'.volar.setup{ + filetypes = {'typescript', 'javascript', 'javascriptreact', 'typescriptreact', 'vue', 'json'} +} +``` + +**Overriding the default TypeScript Server used by Volar** +The default config looks for TS in the local node_modules. The alternatives are: + +- use a global TypeScript Server installation + +```lua +require'lspconfig'.volar.setup{ + init_options = { + typescript = { + serverPath = '/path/to/.npm/lib/node_modules/typescript/lib/tsserverlib.js' + } + } +} +``` + +- use a global TypeScript Server installation if a local server is not found + +```lua +local util = require 'lspconfig.util' + +local function get_typescript_server_path(root_dir) + local project_root = util.find_node_modules_ancestor(root_dir) + + local local_tsserverlib = project_root ~= nil and util.path.join(project_root, 'node_modules', 'typescript', 'lib', 'tsserverlibrary.js') + local global_tsserverlib = '/home/[yourusernamehere]/.npm/lib/node_modules/typescript/lib/tsserverlibrary.js' + + if local_tsserverlib and util.path.exists(local_tsserverlib) then + return local_tsserverlib + else + return global_tsserverlib + end +end + +require'lspconfig'.volar.setup{ + on_new_config = function(new_config, new_root_dir) + new_config.init_options.typescript.serverPath = get_typescript_server_path(new_root_dir) + end, +} +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.volar.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "vue-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "vue" } + ``` + - `init_options` : + ```lua + { + documentFeatures = { + documentColor = false, + documentFormatting = { + defaultPrintWidth = 100 + }, + documentSymbol = true, + foldingRange = true, + linkedEditingRange = true, + selectionRange = true + }, + languageFeatures = { + callHierarchy = true, + codeAction = true, + codeLens = true, + completion = { + defaultAttrNameCase = "kebabCase", + defaultTagNameCase = "both" + }, + definition = true, + diagnostics = true, + documentHighlight = true, + documentLink = true, + hover = true, + implementation = true, + references = true, + rename = true, + renameFileRefactoring = true, + schemaRequestService = true, + semanticTokens = false, + signatureHelp = true, + typeDefinition = true + }, + typescript = { + serverPath = "" + } + } + ``` + - `on_new_config` : + ```lua + see source file + ``` + - `root_dir` : + ```lua + see source file + ``` + + +## vuels + +https://github.com/vuejs/vetur/tree/master/server + +Vue language server(vls) +`vue-language-server` can be installed via `npm`: +```sh +npm install -g vls +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.vuels.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "vls" } + ``` + - `filetypes` : + ```lua + { "vue" } + ``` + - `init_options` : + ```lua + { + config = { + css = {}, + emmet = {}, + html = { + suggest = {} + }, + javascript = { + format = {} + }, + stylusSupremacy = {}, + typescript = { + format = {} + }, + vetur = { + completion = { + autoImport = false, + tagCasing = "kebab", + useScaffoldSnippets = false + }, + format = { + defaultFormatter = { + js = "none", + ts = "none" + }, + defaultFormatterOptions = {}, + scriptInitialIndent = false, + styleInitialIndent = false + }, + useWorkspaceDependencies = false, + validation = { + script = true, + style = true, + template = true + } + } + } + } + ``` + - `root_dir` : + ```lua + root_pattern("package.json", "vue.config.js") + ``` + + +## yamlls + +https://github.com/redhat-developer/yaml-language-server + +`yaml-language-server` can be installed via `yarn`: +```sh +yarn global add yaml-language-server +``` + +To use a schema for validation, there are two options: + +1. Add a modeline to the file. A modeline is a comment of the form: + +``` +# yaml-language-server: $schema= +``` + +where the relative filepath is the path relative to the open yaml file, and the absolute filepath +is the filepath relative to the filesystem root ('/' on unix systems) + +2. Associated a schema url, relative , or absolute (to root of project, not to filesystem root) path to +the a glob pattern relative to the detected project root. Check `:LspInfo` to determine the resolved project +root. + +```lua +require('lspconfig').yamlls.setup { + ... -- other configuration for setup {} + settings = { + yaml = { + ... -- other settings. note this overrides the lspconfig defaults. + schemas = { + ["https://json.schemastore.org/github-workflow.json"] = "/.github/workflows/*" + ["../path/relative/to/file.yml"] = "/.github/workflows/*" + ["/path/from/root/of/project"] = "/.github/workflows/*" + }, + }, + } +} +``` + +Currently, kubernetes is special-cased in yammls, see the following upstream issues: +* [#211](https://github.com/redhat-developer/yaml-language-server/issues/211). +* [#307](https://github.com/redhat-developer/yaml-language-server/issues/307). + +To override a schema to use a specific k8s schema version (for example, to use 1.18): + +```lua +require('lspconfig').yamlls.setup { + ... -- other configuration for setup {} + settings = { + yaml = { + ... -- other settings. note this overrides the lspconfig defaults. + schemas = { + ["https://raw.githubusercontent.com/instrumenta/kubernetes-json-schema/master/v1.18.0-standalone-strict/all.json"] = "/*.k8s.yaml", + ... -- other schemas + }, + }, + } +} +``` + + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.yamlls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "yaml-language-server", "--stdio" } + ``` + - `filetypes` : + ```lua + { "yaml", "yaml.docker-compose" } + ``` + - `root_dir` : + ```lua + util.find_git_ancestor + ``` + - `settings` : + ```lua + { + redhat = { + telemetry = { + enabled = false + } + } + } + ``` + - `single_file_support` : + ```lua + true + ``` + + +## zeta_note + +https://github.com/artempyanykh/zeta-note + +Markdown LSP server for easy note-taking with cross-references and diagnostics. + +Binaries can be downloaded from https://github.com/artempyanykh/zeta-note/releases + +**By default, zeta-note doesn't have a `cmd` set.** This is because nvim-lspconfig does not make assumptions about your path. You must add the following to your init.vim or init.lua to set `cmd` to the absolute path ($HOME and ~ are not expanded) of your zeta-note binary. + +```lua +require'lspconfig'.zeta_note.setup{ + cmd = {'path/to/zeta-note'} +} +``` + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.zeta_note.setup{} +``` + + +**Default values:** + - `filetypes` : + ```lua + { "markdown" } + ``` + - `root_dir` : + ```lua + root_pattern(".zeta.toml") + ``` + + +## zk + +github.com/mickael-menu/zk + +A plain text note-taking assistant + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.zk.setup{} +``` +**Commands:** +- ZkIndex: Index +- ZkNew: ZkNew + +**Default values:** + - `cmd` : + ```lua + { "zk", "lsp" } + ``` + - `filetypes` : + ```lua + { "markdown" } + ``` + - `root_dir` : + ```lua + root_pattern(".zk") + ``` + + +## zls + +https://github.com/zigtools/zls + +Zig LSP implementation + Zig Language Server + + + +**Snippet to enable the language server:** +```lua +require'lspconfig'.zls.setup{} +``` + + +**Default values:** + - `cmd` : + ```lua + { "zls" } + ``` + - `filetypes` : + ```lua + { "zig", "zir" } + ``` + - `root_dir` : + ```lua + util.root_pattern("zls.json", ".git") + ``` + - `single_file_support` : + ```lua + true + ``` + + + +vim:ft=markdown diff --git a/start/lspconfig-0.1.3/lua/lspconfig.lua b/start/lspconfig-0.1.3/lua/lspconfig.lua new file mode 100644 index 0000000..8404632 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig.lua @@ -0,0 +1,92 @@ +local configs = require 'lspconfig.configs' + +local M = { + util = require 'lspconfig.util', +} + +M._root = {} + +function M.available_servers() + return vim.tbl_keys(configs) +end + +-- Called from plugin/lspconfig.vim because it requires knowing that the last +-- script in scriptnames to be executed is lspconfig. +function M._root._setup() + M._root.commands = { + LspInfo = { + function() + require 'lspconfig.ui.lspinfo'() + end, + '-nargs=0', + description = '`:LspInfo` Displays attached, active, and configured language servers', + }, + LspStart = { + function(server_name) + if server_name then + if configs[server_name] then + configs[server_name].launch() + end + else + local buffer_filetype = vim.bo.filetype + for _, config in pairs(configs) do + for _, filetype_match in ipairs(config.filetypes or {}) do + if buffer_filetype == filetype_match then + config.launch() + end + end + end + end + end, + '-nargs=? -complete=custom,v:lua.lsp_complete_configured_servers', + description = '`:LspStart` Manually launches a language server.', + }, + LspStop = { + function(cmd_args) + for _, client in ipairs(M.util.get_clients_from_cmd_args(cmd_args)) do + client.stop() + end + end, + '-nargs=? -complete=customlist,v:lua.lsp_get_active_client_ids', + description = '`:LspStop` Manually stops the given language client(s).', + }, + LspRestart = { + function(cmd_args) + for _, client in ipairs(M.util.get_clients_from_cmd_args(cmd_args)) do + client.stop() + vim.defer_fn(function() + configs[client.name].launch() + end, 500) + end + end, + '-nargs=? -complete=customlist,v:lua.lsp_get_active_client_ids', + description = '`:LspRestart` Manually restart the given language client(s).', + }, + } + + M.util.create_module_commands('_root', M._root.commands) +end + +local mt = {} +function mt:__index(k) + if configs[k] == nil then + local success, config = pcall(require, 'lspconfig.server_configurations.' .. k) + if success then + configs[k] = config + else + vim.notify( + string.format( + '[lspconfig] Cannot access configuration for %s. Ensure this server is listed in ' + .. '`server_configurations.md` or added as a custom server.', + k + ), + vim.log.levels.WARN + ) + -- Return a dummy function for compatibility with user configs + return { setup = function() end } + end + end + return configs[k] +end + +return setmetatable(M, mt) diff --git a/start/lspconfig-0.1.3/lua/lspconfig/configs.lua b/start/lspconfig-0.1.3/lua/lspconfig/configs.lua new file mode 100644 index 0000000..a47ecba --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/configs.lua @@ -0,0 +1,295 @@ +local util = require 'lspconfig.util' +local api, validate, lsp = vim.api, vim.validate, vim.lsp +local tbl_extend = vim.tbl_extend + +local configs = {} + +function configs.__newindex(t, config_name, config_def) + validate { + name = { config_name, 's' }, + default_config = { config_def.default_config, 't' }, + on_new_config = { config_def.on_new_config, 'f', true }, + on_attach = { config_def.on_attach, 'f', true }, + commands = { config_def.commands, 't', true }, + } + if config_def.commands then + for k, v in pairs(config_def.commands) do + validate { + ['command.name'] = { k, 's' }, + ['command.fn'] = { v[1], 'f' }, + } + end + else + config_def.commands = {} + end + + local M = {} + + local default_config = tbl_extend('keep', config_def.default_config, util.default_config) + + -- Force this part. + default_config.name = config_name + + function M.setup(config) + validate { + cmd = { config.cmd, 't', true }, + root_dir = { config.root_dir, 'f', true }, + filetypes = { config.filetype, 't', true }, + on_new_config = { config.on_new_config, 'f', true }, + on_attach = { config.on_attach, 'f', true }, + commands = { config.commands, 't', true }, + } + if config.commands then + for k, v in pairs(config.commands) do + validate { + ['command.name'] = { k, 's' }, + ['command.fn'] = { v[1], 'f' }, + } + end + end + + config = tbl_extend('keep', config, default_config) + + if util.on_setup then + pcall(util.on_setup, config) + end + + if config.autostart == true then + local event + local pattern + if config.filetypes then + event = 'FileType' + pattern = table.concat(config.filetypes, ',') + else + event = 'BufReadPost' + pattern = '*' + end + api.nvim_command( + string.format( + "autocmd %s %s unsilent lua require'lspconfig'[%q].manager.try_add()", + event, + pattern, + config.name + ) + ) + end + + local get_root_dir = config.root_dir + + function M.launch() + local root_dir + if get_root_dir then + local bufnr = api.nvim_get_current_buf() + local bufname = api.nvim_buf_get_name(bufnr) + if not util.bufname_valid(bufname) then + return + end + root_dir = get_root_dir(util.path.sanitize(bufname), bufnr) + end + + if root_dir then + api.nvim_command( + string.format( + "autocmd BufReadPost %s/* unsilent lua require'lspconfig'[%q].manager.try_add_wrapper()", + vim.fn.fnameescape(root_dir), + config.name + ) + ) + for _, bufnr in ipairs(vim.api.nvim_list_bufs()) do + local bufname = api.nvim_buf_get_name(bufnr) + if util.bufname_valid(bufname) then + local buf_dir = util.path.sanitize(bufname) + if buf_dir:sub(1, root_dir:len()) == root_dir then + M.manager.try_add_wrapper(bufnr) + end + end + end + elseif config.single_file_support then + -- This allows on_new_config to use the parent directory of the file + -- Effectively this is the root from lspconfig's perspective, as we use + -- this to attach additional files in the same parent folder to the same server. + -- We just no longer send rootDirectory or workspaceFolders during initialization. + local bufname = api.nvim_buf_get_name(0) + if not util.bufname_valid(bufname) then + return + end + local pseudo_root = util.path.dirname(util.path.sanitize(bufname)) + local client_id = M.manager.add(pseudo_root, true) + vim.lsp.buf_attach_client(vim.api.nvim_get_current_buf(), client_id) + end + end + + -- Used by :LspInfo + M.get_root_dir = get_root_dir + M.filetypes = config.filetypes + M.handlers = config.handlers + M.cmd = config.cmd + M.autostart = config.autostart + + -- In the case of a reload, close existing things. + local reload = false + if M.manager then + for _, client in ipairs(M.manager.clients()) do + client.stop(true) + end + reload = true + M.manager = nil + end + + local make_config = function(root_dir) + local new_config = vim.tbl_deep_extend('keep', vim.empty_dict(), config) + new_config = vim.tbl_deep_extend('keep', new_config, default_config) + new_config.capabilities = new_config.capabilities or lsp.protocol.make_client_capabilities() + new_config.capabilities = vim.tbl_deep_extend('keep', new_config.capabilities, { + workspace = { + configuration = true, + }, + }) + + if config_def.on_new_config then + pcall(config_def.on_new_config, new_config, root_dir) + end + if config.on_new_config then + pcall(config.on_new_config, new_config, root_dir) + end + + new_config.on_init = util.add_hook_after(new_config.on_init, function(client, result) + -- Handle offset encoding by default + if result.offsetEncoding then + client.offset_encoding = result.offsetEncoding + end + + -- Send `settings to server via workspace/didChangeConfiguration + function client.workspace_did_change_configuration(settings) + if not settings then + return + end + if vim.tbl_isempty(settings) then + settings = { [vim.type_idx] = vim.types.dictionary } + end + return client.notify('workspace/didChangeConfiguration', { + settings = settings, + }) + end + if not vim.tbl_isempty(new_config.settings) then + client.workspace_did_change_configuration(new_config.settings) + end + end) + + -- Save the old _on_attach so that we can reference it via the BufEnter. + new_config._on_attach = new_config.on_attach + new_config.on_attach = vim.schedule_wrap(function(client, bufnr) + if bufnr == api.nvim_get_current_buf() then + M._setup_buffer(client.id, bufnr) + else + api.nvim_command( + string.format( + "autocmd BufEnter ++once lua require'lspconfig'[%q]._setup_buffer(%d,%d)", + bufnr, + config_name, + client.id, + bufnr + ) + ) + end + end) + + new_config.root_dir = root_dir + new_config.workspace_folders = { + { + uri = vim.uri_from_fname(root_dir), + name = string.format('%s', root_dir), + }, + } + return new_config + end + + local manager = util.server_per_root_dir_manager(function(root_dir) + return make_config(root_dir) + end) + + function manager.try_add(bufnr) + bufnr = bufnr or api.nvim_get_current_buf() + + if vim.api.nvim_buf_get_option(bufnr, 'buftype') == 'nofile' then + return + end + + local id + local root_dir + + local bufname = api.nvim_buf_get_name(bufnr) + if not util.bufname_valid(bufname) then + return + end + local buf_path = util.path.sanitize(bufname) + + if get_root_dir then + root_dir = get_root_dir(buf_path, bufnr) + end + + if root_dir then + id = manager.add(root_dir, false) + elseif config.single_file_support then + local pseudo_root = util.path.dirname(buf_path) + id = manager.add(pseudo_root, true) + end + + if id then + lsp.buf_attach_client(bufnr, id) + end + end + + function manager.try_add_wrapper(bufnr) + bufnr = bufnr or api.nvim_get_current_buf() + local buf_filetype = vim.api.nvim_buf_get_option(bufnr, 'filetype') + if config.filetypes then + for _, filetype in ipairs(config.filetypes) do + if buf_filetype == filetype then + manager.try_add(bufnr) + return + end + end + else + manager.try_add(bufnr) + end + end + + M.manager = manager + M.make_config = make_config + if reload and config.autostart ~= false then + for _, bufnr in ipairs(vim.api.nvim_list_bufs()) do + manager.try_add_wrapper(bufnr) + end + end + end + + function M._setup_buffer(client_id, bufnr) + local client = lsp.get_client_by_id(client_id) + if not client then + return + end + if client.config._on_attach then + client.config._on_attach(client, bufnr) + end + if client.config.commands and not vim.tbl_isempty(client.config.commands) then + M.commands = vim.tbl_deep_extend('force', M.commands, client.config.commands) + end + if not M.commands_created and not vim.tbl_isempty(M.commands) then + -- Create the module commands + util.create_module_commands(config_name, M.commands) + M.commands_created = true + end + end + + M.commands_created = false + M.commands = config_def.commands + M.name = config_name + M.document_config = config_def + + rawset(t, config_name, M) + + return M +end + +return setmetatable({}, configs) diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/als.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/als.lua new file mode 100644 index 0000000..7d916ad --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/als.lua @@ -0,0 +1,37 @@ +local util = require 'lspconfig.util' +local bin_name = 'ada_language_server' + +if vim.fn.has 'win32' == 1 then + bin_name = 'ada_language_server.exe' +end + +return { + default_config = { + cmd = { bin_name }, + filetypes = { 'ada' }, + root_dir = util.root_pattern('Makefile', '.git', '*.gpr', '*.adc'), + }, + docs = { + description = [[ +https://github.com/AdaCore/ada_language_server + +Installation instructions can be found [here](https://github.com/AdaCore/ada_language_server#Install). + +Can be configured by passing a "settings" object to `als.setup{}`: + +```lua +require('lspconfig').als.setup{ + settings = { + ada = { + projectFile = "project.gpr"; + scenarioVariables = { ... }; + } + } +} +``` +]], + default_config = { + root_dir = [[util.root_pattern("Makefile", ".git", "*.gpr", "*.adc")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/angularls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/angularls.lua new file mode 100644 index 0000000..4d30de7 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/angularls.lua @@ -0,0 +1,75 @@ +local util = require 'lspconfig.util' + +-- Angular requires a node_modules directory to probe for @angular/language-service and typescript +-- in order to use your projects configured versions. +-- This defaults to the vim cwd, but will get overwritten by the resolved root of the file. +local function get_probe_dir(root_dir) + local project_root = util.find_node_modules_ancestor(root_dir) + + return project_root and (project_root .. '/node_modules') or '' +end + +local default_probe_dir = get_probe_dir(vim.fn.getcwd()) + +local bin_name = 'ngserver' +local args = { + '--stdio', + '--tsProbeLocations', + default_probe_dir, + '--ngProbeLocations', + default_probe_dir, +} + +local cmd = { bin_name, unpack(args) } + +if vim.fn.has 'win32' == 1 then + cmd = { 'cmd.exe', '/C', bin_name, unpack(args) } +end + +return { + default_config = { + cmd = cmd, + filetypes = { 'typescript', 'html', 'typescriptreact', 'typescript.tsx' }, + -- Check for angular.json or .git first since that is the root of the project. + -- Don't check for tsconfig.json or package.json since there are multiple of these + -- in an angular monorepo setup. + root_dir = util.root_pattern('angular.json', '.git'), + }, + on_new_config = function(new_config, new_root_dir) + local new_probe_dir = get_probe_dir(new_root_dir) + + -- We need to check our probe directories because they may have changed. + new_config.cmd = { + 'ngserver', + '--stdio', + '--tsProbeLocations', + new_probe_dir, + '--ngProbeLocations', + new_probe_dir, + } + end, + docs = { + description = [[ +https://github.com/angular/vscode-ng-language-service + +`angular-language-server` can be installed via npm `npm install -g @angular/language-server`. + +Note, that if you override the default `cmd`, you must also update `on_new_config` to set `new_config.cmd` during startup. + +```lua +local project_library_path = "/path/to/project/lib" +local cmd = {"ngserver", "--stdio", "--tsProbeLocations", project_library_path , "--ngProbeLocations", project_library_path} + +require'lspconfig'.angularls.setup{ + cmd = cmd, + on_new_config = function(new_config,new_root_dir) + new_config.cmd = cmd + end, +} +``` + ]], + default_config = { + root_dir = [[root_pattern("angular.json", ".git")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/ansiblels.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/ansiblels.lua new file mode 100644 index 0000000..b4bb324 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/ansiblels.lua @@ -0,0 +1,47 @@ +local util = require 'lspconfig.util' + +local bin_name = 'ansible-language-server' +local cmd = { bin_name, '--stdio' } + +if vim.fn.has 'win32' == 1 then + cmd = { 'cmd.exe', '/C', bin_name, '--stdio' } +end + +return { + default_config = { + cmd = cmd, + settings = { + ansible = { + python = { + interpreterPath = 'python', + }, + ansibleLint = { + path = 'ansible-lint', + enabled = true, + }, + ansible = { + path = 'ansible', + }, + executionEnvironment = { + enabled = false, + }, + }, + }, + filetypes = { 'yaml.ansible' }, + root_dir = util.root_pattern('ansible.cfg', '.ansible-lint'), + single_file_support = true, + }, + docs = { + description = [[ +https://github.com/ansible/ansible-language-server + +Language server for the ansible configuration management tool. + +`ansible-language-server` can be installed via `npm`: + +```sh +npm install -g @ansible/ansible-language-server +``` +]], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/arduino_language_server.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/arduino_language_server.lua new file mode 100644 index 0000000..72f48a1 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/arduino_language_server.lua @@ -0,0 +1,50 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'arduino-language-server' }, + filetypes = { 'arduino' }, + root_dir = util.root_pattern '*.ino', + }, + docs = { + description = [[ +https://github.com/arduino/arduino-language-server + +Language server for Arduino + +The `arduino-language-server` can be installed by running: + go get -u github.com/arduino/arduino-language-server + +The `arduino-cli` tools must also be installed. Follow these instructions for your distro: + https://arduino.github.io/arduino-cli/latest/installation/ + +After installing the `arduino-cli` tools, follow these instructions for generating +a configuration file: + https://arduino.github.io/arduino-cli/latest/getting-started/#create-a-configuration-file +and make sure you install any relevant platforms libraries: + https://arduino.github.io/arduino-cli/latest/getting-started/#install-the-core-for-your-board + +The language server also requires `clangd` be installed. It will look for `clangd` by default but +the binary path can be overridden if need be. + +After all dependencies are installed you'll need to override the lspconfig command for the +language server in your setup function with the necessary configurations: + +```lua +lspconfig.arduino_language_server.setup({ + cmd = { + -- Required + "arduino-language-server", + "-cli-config", "/path/to/arduino-cli.yaml", + -- Optional + "-cli", "/path/to/arduino-cli", + "-clangd", "/path/to/clangd" + } +}) +``` + +For further instruction about configuration options, run `arduino-language-server --help`. + +]], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/asm_lsp.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/asm_lsp.lua new file mode 100644 index 0000000..102bcba --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/asm_lsp.lua @@ -0,0 +1,19 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'asm-lsp' }, + filetypes = { 'asm', 'vmasm' }, + root_dir = util.find_git_ancestor, + }, + docs = { + description = [[ +https://github.com/bergercookie/asm-lsp + +Language Server for GAS/GO Assembly + +`asm-lsp` can be installed via cargo: +cargo install asm-lsp +]], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/awk_ls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/awk_ls.lua new file mode 100644 index 0000000..ff1087d --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/awk_ls.lua @@ -0,0 +1,22 @@ +if vim.version().major == 0 and vim.version().minor < 7 then + vim.notify('The AWK language server requires nvim >= 0.7', vim.log.levels.ERROR) + return +end + +return { + default_config = { + cmd = { 'awk-language-server' }, + filetypes = { 'awk' }, + single_file_support = true, + }, + docs = { + description = [[ +https://github.com/Beaglefoot/awk-language-server/ + +`awk-language-server` can be installed via `npm`: +```sh +npm install -g awk-language-server +``` +]], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/bashls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/bashls.lua new file mode 100644 index 0000000..3f25c76 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/bashls.lua @@ -0,0 +1,39 @@ +local util = require 'lspconfig.util' + +local bin_name = 'bash-language-server' +local cmd = { bin_name, 'start' } + +if vim.fn.has 'win32' == 1 then + cmd = { 'cmd.exe', '/C', bin_name, 'start' } +end + +return { + default_config = { + cmd = cmd, + cmd_env = { + -- Prevent recursive scanning which will cause issues when opening a file + -- directly in the home directory (e.g. ~/foo.sh). + -- + -- Default upstream pattern is "**/*@(.sh|.inc|.bash|.command)". + GLOB_PATTERN = vim.env.GLOB_PATTERN or '*@(.sh|.inc|.bash|.command)', + }, + filetypes = { 'sh' }, + root_dir = util.find_git_ancestor, + single_file_support = true, + }, + docs = { + description = [[ +https://github.com/mads-hartmann/bash-language-server + +`bash-language-server` can be installed via `npm`: +```sh +npm i -g bash-language-server +``` + +Language server for bash, written using tree sitter in typescript. +]], + default_config = { + root_dir = [[util.find_git_ancestor]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/beancount.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/beancount.lua new file mode 100644 index 0000000..1d86d34 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/beancount.lua @@ -0,0 +1,26 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'beancount-langserver', '--stdio' }, + filetypes = { 'beancount' }, + root_dir = util.find_git_ancestor, + single_file_support = true, + init_options = { + -- this is the path to the beancout journal file + journalFile = '', + -- this is the path to the python binary with beancount installed + pythonPath = 'python3', + }, + }, + docs = { + description = [[ +https://github.com/polarmutex/beancount-language-server#installation + +See https://github.com/polarmutex/beancount-language-server#configuration for configuration options +]], + default_config = { + root_dir = [[root_pattern("elm.json")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/bicep.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/bicep.lua new file mode 100644 index 0000000..1ec7032 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/bicep.lua @@ -0,0 +1,47 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + filetypes = { 'bicep' }, + root_dir = util.find_git_ancestor, + init_options = {}, + }, + docs = { + description = [=[ +https://github.com/azure/bicep +Bicep language server + +Bicep language server can be installed by downloading and extracting a release of bicep-langserver.zip from [Bicep GitHub releases](https://github.com/Azure/bicep/releases). + +Bicep language server requires the [dotnet-sdk](https://dotnet.microsoft.com/download) to be installed. + +Neovim does not have built-in support for the bicep filetype which is required for lspconfig to automatically launch the language server. + +Filetype detection can be added via an autocmd: +```lua +vim.cmd [[ autocmd BufNewFile,BufRead *.bicep set filetype=bicep ]] +``` + +**By default, bicep language server does not have a `cmd` set.** This is because nvim-lspconfig does not make assumptions about your path. You must add the following to your init.vim or init.lua to set `cmd` to the absolute path ($HOME and ~ are not expanded) of the unzipped run script or binary. + +```lua +local bicep_lsp_bin = "/path/to/bicep-langserver/Bicep.LangServer.dll" +require'lspconfig'.bicep.setup{ + cmd = { "dotnet", bicep_lsp_bin }; + ... +} +``` + +To download the latest release and place in /usr/local/bin/bicep-langserver: +```bash +(cd $(mktemp -d) \ + && curl -fLO https://github.com/Azure/bicep/releases/latest/download/bicep-langserver.zip \ + && rm -rf /usr/local/bin/bicep-langserver \ + && unzip -d /usr/local/bin/bicep-langserver bicep-langserver.zip) +``` +]=], + default_config = { + root_dir = [[util.find_git_ancestor]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/bsl_ls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/bsl_ls.lua new file mode 100644 index 0000000..fef15f9 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/bsl_ls.lua @@ -0,0 +1,19 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + filetypes = { 'bsl', 'os' }, + root_dir = util.find_git_ancestor, + }, + docs = { + description = [[ + https://github.com/1c-syntax/bsl-language-server + + Language Server Protocol implementation for 1C (BSL) - 1C:Enterprise 8 and OneScript languages. + + ]], + default_config = { + root_dir = [[root_pattern(".git")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/ccls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/ccls.lua new file mode 100644 index 0000000..dd642db --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/ccls.lua @@ -0,0 +1,43 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'ccls' }, + filetypes = { 'c', 'cpp', 'objc', 'objcpp' }, + root_dir = util.root_pattern('compile_commands.json', '.ccls', '.git'), + offset_encoding = 'utf-32', + -- ccls does not support sending a null root directory + single_file_support = false, + }, + docs = { + description = [[ +https://github.com/MaskRay/ccls/wiki + +ccls relies on a [JSON compilation database](https://clang.llvm.org/docs/JSONCompilationDatabase.html) specified +as compile_commands.json or, for simpler projects, a .ccls. +For details on how to automatically generate one using CMake look [here](https://cmake.org/cmake/help/latest/variable/CMAKE_EXPORT_COMPILE_COMMANDS.html). Alternatively, you can use [Bear](https://github.com/rizsotto/Bear). + +Customization options are passed to ccls at initialization time via init_options, a list of available options can be found [here](https://github.com/MaskRay/ccls/wiki/Customization#initialization-options). For example: + +```lua +local lspconfig = require'lspconfig' +lspconfig.ccls.setup { + init_options = { + compilationDatabaseDirectory = "build"; + index = { + threads = 0; + }; + clang = { + excludeArgs = { "-frounding-math"} ; + }; + } +} + +``` + +]], + default_config = { + root_dir = [[root_pattern("compile_commands.json", ".ccls", ".git")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/clangd.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/clangd.lua new file mode 100644 index 0000000..4e0f2d7 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/clangd.lua @@ -0,0 +1,87 @@ +local util = require 'lspconfig.util' + +-- https://clangd.llvm.org/extensions.html#switch-between-sourceheader +local function switch_source_header(bufnr) + bufnr = util.validate_bufnr(bufnr) + local clangd_client = util.get_active_client_by_name(bufnr, 'clangd') + local params = { uri = vim.uri_from_bufnr(bufnr) } + if clangd_client then + clangd_client.request('textDocument/switchSourceHeader', params, function(err, result) + if err then + error(tostring(err)) + end + if not result then + print 'Corresponding file cannot be determined' + return + end + vim.api.nvim_command('edit ' .. vim.uri_to_fname(result)) + end, bufnr) + else + print 'method textDocument/switchSourceHeader is not supported by any servers active on the current buffer' + end +end + +local root_files = { + '.clangd', + '.clang-tidy', + '.clang-format', + 'compile_commands.json', + 'compile_flags.txt', + 'configure.ac', -- AutoTools +} + +local default_capabilities = vim.tbl_deep_extend( + 'force', + util.default_config.capabilities or vim.lsp.protocol.make_client_capabilities(), + { + textDocument = { + completion = { + editsNearCursor = true, + }, + }, + offsetEncoding = { 'utf-8', 'utf-16' }, + } +) + +return { + default_config = { + cmd = { 'clangd' }, + filetypes = { 'c', 'cpp', 'objc', 'objcpp' }, + root_dir = function(fname) + return util.root_pattern(unpack(root_files))(fname) or util.find_git_ancestor(fname) + end, + single_file_support = true, + capabilities = default_capabilities, + }, + commands = { + ClangdSwitchSourceHeader = { + function() + switch_source_header(0) + end, + description = 'Switch between source/header', + }, + }, + docs = { + description = [[ +https://clangd.llvm.org/installation.html + +**NOTE:** Clang >= 11 is recommended! See [this issue for more](https://github.com/neovim/nvim-lsp/issues/23). + +clangd relies on a [JSON compilation database](https://clang.llvm.org/docs/JSONCompilationDatabase.html) specified as compile_commands.json, see https://clangd.llvm.org/installation#compile_commandsjson +]], + default_config = { + root_dir = [[ + root_pattern( + '.clangd', + '.clang-tidy', + '.clang-format', + 'compile_commands.json', + 'compile_flags.txt', + 'configure.ac', + '.git' + ) + ]], + capabilities = [[default capabilities, with offsetEncoding utf-8]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/clarity_lsp.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/clarity_lsp.lua new file mode 100644 index 0000000..72a6197 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/clarity_lsp.lua @@ -0,0 +1,19 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'clarity-lsp' }, + filetypes = { 'clar', 'clarity' }, + root_dir = util.root_pattern '.git', + }, + docs = { + description = [[ +`clarity-lsp` is a language server for the Clarity language. Clarity is a decidable smart contract language that optimizes for predictability and security. Smart contracts allow developers to encode essential business logic on a blockchain. + +To learn how to configure the clarity language server, see the [clarity-lsp documentation](https://github.com/hirosystems/clarity-lsp). +]], + default_config = { + root_dir = [[root_pattern(".git")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/clojure_lsp.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/clojure_lsp.lua new file mode 100644 index 0000000..5340693 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/clojure_lsp.lua @@ -0,0 +1,19 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'clojure-lsp' }, + filetypes = { 'clojure', 'edn' }, + root_dir = util.root_pattern('project.clj', 'deps.edn', 'build.boot', 'shadow-cljs.edn', '.git'), + }, + docs = { + description = [[ +https://github.com/snoe/clojure-lsp + +Clojure Language Server +]], + default_config = { + root_dir = [[root_pattern("project.clj", "deps.edn", "build.boot", "shadow-cljs.edn", ".git")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/cmake.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/cmake.lua new file mode 100644 index 0000000..d334535 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/cmake.lua @@ -0,0 +1,26 @@ +local util = require 'lspconfig.util' + +local root_files = { 'CMakeLists.txt', 'cmake' } +return { + default_config = { + cmd = { 'cmake-language-server' }, + filetypes = { 'cmake' }, + root_dir = function(fname) + return util.root_pattern(unpack(root_files))(fname) or util.find_git_ancestor(fname) + end, + single_file_support = true, + init_options = { + buildDirectory = 'build', + }, + }, + docs = { + description = [[ +https://github.com/regen100/cmake-language-server + +CMake LSP Implementation +]], + default_config = { + root_dir = [[root_pattern(".git", "compile_commands.json", "build")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/codeqlls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/codeqlls.lua new file mode 100644 index 0000000..9184d2f --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/codeqlls.lua @@ -0,0 +1,46 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'codeql', 'execute', 'language-server', '--check-errors', 'ON_CHANGE', '-q' }, + filetypes = { 'ql' }, + root_dir = util.root_pattern 'qlpack.yml', + log_level = vim.lsp.protocol.MessageType.Warning, + before_init = function(initialize_params) + initialize_params['workspaceFolders'] = { + { + name = 'workspace', + uri = initialize_params['rootUri'], + }, + } + end, + settings = { + search_path = vim.empty_dict(), + }, + }, + docs = { + description = [[ +Reference: +https://help.semmle.com/codeql/codeql-cli.html + +Binaries: +https://github.com/github/codeql-cli-binaries + ]], + default_config = { + settings = { + search_path = [[list containing all search paths, eg: '~/codeql-home/codeql-repo']], + }, + }, + }, + on_new_config = function(config) + if type(config.settings.search_path) == 'table' and not vim.tbl_isempty(config.settings.search_path) then + local search_path = '--search-path=' + for _, path in ipairs(config.settings.search_path) do + search_path = search_path .. vim.fn.expand(path) .. ':' + end + config.cmd = { 'codeql', 'execute', 'language-server', '--check-errors', 'ON_CHANGE', '-q', search_path } + else + config.cmd = { 'codeql', 'execute', 'language-server', '--check-errors', 'ON_CHANGE', '-q' } + end + end, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/crystalline.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/crystalline.lua new file mode 100644 index 0000000..ef4d6bc --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/crystalline.lua @@ -0,0 +1,20 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'crystalline' }, + filetypes = { 'crystal' }, + root_dir = util.root_pattern 'shard.yml' or util.find_git_ancestor, + single_file_support = true, + }, + docs = { + description = [[ +https://github.com/elbywan/crystalline + +Crystal language server. +]], + default_config = { + root_dir = [[root_pattern('shard.yml', '.git')]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/csharp_ls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/csharp_ls.lua new file mode 100644 index 0000000..828cba4 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/csharp_ls.lua @@ -0,0 +1,23 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'csharp-ls' }, + root_dir = util.root_pattern('*.sln', '*.csproj', '.git'), + filetypes = { 'cs' }, + init_options = { + AutomaticWorkspaceInit = true, + }, + }, + docs = { + description = [[ +https://github.com/razzmatazz/csharp-language-server + +Language Server for C#. + +csharp-ls requires the [dotnet-sdk](https://dotnet.microsoft.com/download) to be installed. + +The preferred way to install csharp-ls is with `dotnet tool install --global csharp-ls`. + ]], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/cssls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/cssls.lua new file mode 100644 index 0000000..41c38e6 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/cssls.lua @@ -0,0 +1,49 @@ +local util = require 'lspconfig.util' + +local bin_name = 'vscode-css-language-server' +local cmd = { bin_name, '--stdio' } + +if vim.fn.has 'win32' == 1 then + cmd = { 'cmd.exe', '/C', bin_name, '--stdio' } +end + +return { + default_config = { + cmd = cmd, + filetypes = { 'css', 'scss', 'less' }, + root_dir = util.root_pattern('package.json', '.git'), + single_file_support = true, + settings = { + css = { validate = true }, + scss = { validate = true }, + less = { validate = true }, + }, + }, + docs = { + description = [[ + +https://github.com/hrsh7th/vscode-langservers-extracted + +`css-languageserver` can be installed via `npm`: + +```sh +npm i -g vscode-langservers-extracted +``` + +Neovim does not currently include built-in snippets. `vscode-css-language-server` only provides completions when snippet support is enabled. To enable completion, install a snippet plugin and add the following override to your language client capabilities during setup. + +```lua +--Enable (broadcasting) snippet capability for completion +local capabilities = vim.lsp.protocol.make_client_capabilities() +capabilities.textDocument.completion.completionItem.snippetSupport = true + +require'lspconfig'.cssls.setup { + capabilities = capabilities, +} +``` +]], + default_config = { + root_dir = [[root_pattern("package.json", ".git") or bufdir]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/cssmodules_ls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/cssmodules_ls.lua new file mode 100644 index 0000000..3107b75 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/cssmodules_ls.lua @@ -0,0 +1,31 @@ +local util = require 'lspconfig.util' + +local bin_name = 'cssmodules-language-server' +local cmd = { bin_name } + +if vim.fn.has 'win32' == 1 then + cmd = { 'cmd.exe', '/C', bin_name } +end + +return { + default_config = { + cmd = cmd, + filetypes = { 'javascript', 'javascriptreact', 'typescript', 'typescriptreact' }, + root_dir = util.find_package_json_ancestor, + }, + docs = { + description = [[ +https://github.com/antonk52/cssmodules-language-server + +Language server for autocompletion and go-to-definition functionality for CSS modules. + +You can install cssmodules-language-server via npm: +```sh +npm install -g cssmodules-language-server +``` + ]], + default_config = { + root_dir = [[root_pattern("package.json")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/cucumber_language_server.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/cucumber_language_server.lua new file mode 100644 index 0000000..0783206 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/cucumber_language_server.lua @@ -0,0 +1,33 @@ +local util = require 'lspconfig.util' + +local bin_name = 'cucumber-language-server' +local cmd = { bin_name, '--stdio' } + +if vim.fn.has 'win32' == 1 then + cmd = { 'cmd.exe', '/C', bin_name, '--stdio' } +end + +return { + default_config = { + cmd = cmd, + filetypes = { 'cucumber' }, + root_dir = util.find_git_ancestor, + }, + docs = { + description = [[ +https://cucumber.io +https://github.com/cucumber/common +https://www.npmjs.com/package/@cucumber/language-server + +Language server for Cucumber. + +`cucumber-language-server` can be installed via `npm`: +```sh +npm install -g @cucumber/language-server +``` + ]], + default_config = { + root_dir = [[util.find_git_ancestor]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/dartls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/dartls.lua new file mode 100644 index 0000000..eecb0b7 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/dartls.lua @@ -0,0 +1,60 @@ +local util = require 'lspconfig.util' + +local bin_name = 'dart' + +local find_dart_sdk_root_path = function() + if os.getenv 'FLUTTER_SDK' then + local flutter_path = os.getenv 'FLUTTER_SDK' + return util.path.join(flutter_path, 'cache', 'dart-sdk', 'bin', 'dart') + elseif vim.fn['executable'] 'flutter' == 1 then + local flutter_path = vim.fn['resolve'](vim.fn['exepath'] 'flutter') + local flutter_bin = vim.fn['fnamemodify'](flutter_path, ':h') + return util.path.join(flutter_bin, 'cache', 'dart-sdk', 'bin', 'dart') + elseif vim.fn['executable'] 'dart' == 1 then + return vim.fn['resolve'](vim.fn['exepath'] 'dart') + else + return '' + end +end + +local analysis_server_snapshot_path = function() + local dart_sdk_root_path = vim.fn['fnamemodify'](find_dart_sdk_root_path(), ':h') + local snapshot = util.path.join(dart_sdk_root_path, 'snapshots', 'analysis_server.dart.snapshot') + + if vim.fn['has'] 'win32' == 1 or vim.fn['has'] 'win64' == 1 then + snapshot = snapshot:gsub('/', '\\') + end + + return snapshot +end + +return { + default_config = { + cmd = { bin_name, analysis_server_snapshot_path(), '--lsp' }, + filetypes = { 'dart' }, + root_dir = util.root_pattern 'pubspec.yaml', + init_options = { + onlyAnalyzeProjectsWithOpenFiles = true, + suggestFromUnimportedLibraries = true, + closingLabels = true, + outline = true, + flutterOutline = true, + }, + settings = { + dart = { + completeFunctionCalls = true, + showTodos = true, + }, + }, + }, + docs = { + description = [[ +https://github.com/dart-lang/sdk/tree/master/pkg/analysis_server/tool/lsp_spec + +Language server for dart. +]], + default_config = { + root_dir = [[root_pattern("pubspec.yaml")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/denols.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/denols.lua new file mode 100644 index 0000000..a7bed35 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/denols.lua @@ -0,0 +1,114 @@ +local util = require 'lspconfig.util' +local lsp = vim.lsp + +local function buf_cache(bufnr) + local params = {} + params['referrer'] = { uri = vim.uri_from_bufnr(bufnr) } + params['uris'] = {} + lsp.buf_request(bufnr, 'deno/cache', params, function(err) + if err then + error(tostring(err)) + end + end) +end + +local function virtual_text_document_handler(uri, result) + if not result then + return nil + end + + for client_id, res in pairs(result) do + local lines = vim.split(res.result, '\n') + local bufnr = vim.uri_to_bufnr(uri) + + local current_buf = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false) + if #current_buf ~= 0 then + return nil + end + + vim.api.nvim_buf_set_lines(bufnr, 0, -1, nil, lines) + vim.api.nvim_buf_set_option(bufnr, 'readonly', true) + vim.api.nvim_buf_set_option(bufnr, 'modified', false) + vim.api.nvim_buf_set_option(bufnr, 'modifiable', false) + lsp.buf_attach_client(bufnr, client_id) + end +end + +local function virtual_text_document(uri) + local params = { + textDocument = { + uri = uri, + }, + } + local result = lsp.buf_request_sync(0, 'deno/virtualTextDocument', params) + virtual_text_document_handler(uri, result) +end + +local function denols_handler(err, result, ctx) + if not result or vim.tbl_isempty(result) then + return nil + end + + for _, res in pairs(result) do + local uri = res.uri or res.targetUri + if uri:match '^deno:' then + virtual_text_document(uri) + res['uri'] = uri + res['targetUri'] = uri + end + end + + lsp.handlers[ctx.method](err, result, ctx) +end + +return { + default_config = { + cmd = { 'deno', 'lsp' }, + filetypes = { + 'javascript', + 'javascriptreact', + 'javascript.jsx', + 'typescript', + 'typescriptreact', + 'typescript.tsx', + }, + root_dir = util.root_pattern('deno.json', 'deno.jsonc', 'tsconfig.json', '.git'), + init_options = { + enable = true, + lint = false, + unstable = false, + }, + handlers = { + ['textDocument/definition'] = denols_handler, + ['textDocument/references'] = denols_handler, + }, + }, + commands = { + DenolsCache = { + function() + buf_cache(0) + end, + description = 'Cache a module and all of its dependencies.', + }, + }, + docs = { + description = [[ +https://github.com/denoland/deno + +Deno's built-in language server + +To approrpiately highlight codefences returned from denols, you will need to augment vim.g.markdown_fenced languages + in your init.lua. Example: + +```lua +vim.g.markdown_fenced_languages = { + "ts=typescript" +} +``` + +]], + default_config = { + root_dir = [[root_pattern("deno.json", "deno.jsonc", "tsconfig.json", ".git")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/dhall_lsp_server.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/dhall_lsp_server.lua new file mode 100644 index 0000000..af910f3 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/dhall_lsp_server.lua @@ -0,0 +1,26 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'dhall-lsp-server' }, + filetypes = { 'dhall' }, + root_dir = util.find_git_ancestor, + single_file_support = true, + }, + docs = { + description = [[ +https://github.com/dhall-lang/dhall-haskell/tree/master/dhall-lsp-server + +language server for dhall + +`dhall-lsp-server` can be installed via cabal: +```sh +cabal install dhall-lsp-server +``` +prebuilt binaries can be found [here](https://github.com/dhall-lang/dhall-haskell/releases). +]], + default_config = { + root_dir = [[root_pattern(".git")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/diagnosticls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/diagnosticls.lua new file mode 100644 index 0000000..8f0476b --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/diagnosticls.lua @@ -0,0 +1,29 @@ +local util = require 'lspconfig.util' + +local bin_name = 'diagnostic-languageserver' +local cmd = { bin_name, '--stdio' } + +if vim.fn.has 'win32' == 1 then + cmd = { 'cmd.exe', '/C', bin_name, '--stdio' } +end + +return { + default_config = { + cmd = cmd, + root_dir = util.find_git_ancestor, + single_file_support = true, + filetypes = {}, + }, + docs = { + description = [[ +https://github.com/iamcco/diagnostic-languageserver + +Diagnostic language server integrate with linters. +]], + default_config = { + filetypes = 'Empty by default, override to add filetypes', + root_dir = "Vim's starting directory", + init_options = 'Configuration from https://github.com/iamcco/diagnostic-languageserver#config--document', + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/dockerls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/dockerls.lua new file mode 100644 index 0000000..6d1cfc7 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/dockerls.lua @@ -0,0 +1,30 @@ +local util = require 'lspconfig.util' + +local bin_name = 'docker-langserver' +local cmd = { bin_name, '--stdio' } + +if vim.fn.has 'win32' == 1 then + cmd = { 'cmd.exe', '/C', bin_name, '--stdio' } +end + +return { + default_config = { + cmd = cmd, + filetypes = { 'dockerfile' }, + root_dir = util.root_pattern 'Dockerfile', + single_file_support = true, + }, + docs = { + description = [[ +https://github.com/rcjsuen/dockerfile-language-server-nodejs + +`docker-langserver` can be installed via `npm`: +```sh +npm install -g dockerfile-language-server-nodejs +``` + ]], + default_config = { + root_dir = [[root_pattern("Dockerfile")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/dotls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/dotls.lua new file mode 100644 index 0000000..dff14b9 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/dotls.lua @@ -0,0 +1,27 @@ +local util = require 'lspconfig.util' + +local bin_name = 'dot-language-server' +local cmd = { bin_name, '--stdio' } + +if vim.fn.has 'win32' == 1 then + cmd = { 'cmd.exe', '/C', bin_name, '--stdio' } +end + +return { + default_config = { + cmd = cmd, + filetypes = { 'dot' }, + root_dir = util.find_git_ancestor, + single_file_support = true, + }, + docs = { + description = [[ +https://github.com/nikeee/dot-language-server + +`dot-language-server` can be installed via `npm`: +```sh +npm install -g dot-language-server +``` + ]], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/efm.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/efm.lua new file mode 100644 index 0000000..f5f74ed --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/efm.lua @@ -0,0 +1,43 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'efm-langserver' }, + root_dir = util.find_git_ancestor, + single_file_support = true, + }, + + docs = { + description = [[ +https://github.com/mattn/efm-langserver + +General purpose Language Server that can use specified error message format generated from specified command. + +Requires at minimum EFM version [v0.0.38](https://github.com/mattn/efm-langserver/releases/tag/v0.0.38) to support +launching the language server on single files. If on an older version of EFM, disable single file support: + +```lua +require('lspconfig')['efm'].setup{ + settings = ..., -- You must populate this according to the EFM readme + filetypes = ..., -- Populate this according to the note below + single_file_support = false, -- This is the important line for supporting older version of EFM +} +``` + +Note: In order for neovim's built-in language server client to send the appropriate `languageId` to EFM, **you must +specify `filetypes` in your call to `setup{}`**. Otherwise `lspconfig` will launch EFM on the `BufEnter` instead +of the `FileType` autocommand, and the `filetype` variable used to populate the `languageId` will not yet be set. + +```lua +require('lspconfig')['efm'].setup{ + settings = ..., -- You must populate this according to the EFM readme + filetypes = { 'python','cpp','lua' } +} +``` + +]], + default_config = { + root_dir = [[util.root_pattern(".git")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/elixirls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/elixirls.lua new file mode 100644 index 0000000..d51aa50 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/elixirls.lua @@ -0,0 +1,39 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + filetypes = { 'elixir', 'eelixir' }, + root_dir = function(fname) + return util.root_pattern('mix.exs', '.git')(fname) or vim.loop.os_homedir() + end, + }, + docs = { + description = [[ +https://github.com/elixir-lsp/elixir-ls + +`elixir-ls` can be installed by following the instructions [here](https://github.com/elixir-lsp/elixir-ls#building-and-running). + +```bash +curl -fLO https://github.com/elixir-lsp/elixir-ls/releases/latest/download/elixir-ls.zip +unzip elixir-ls.zip -d /path/to/elixir-ls +# Unix +chmod +x /path/to/elixir-ls/language_server.sh +``` + +**By default, elixir-ls doesn't have a `cmd` set.** This is because nvim-lspconfig does not make assumptions about your path. You must add the following to your init.vim or init.lua to set `cmd` to the absolute path ($HOME and ~ are not expanded) of your unzipped elixir-ls. + +```lua +require'lspconfig'.elixirls.setup{ + -- Unix + cmd = { "/path/to/elixir-ls/language_server.sh" }; + -- Windows + cmd = { "/path/to/elixir-ls/language_server.bat" }; + ... +} +``` +]], + default_config = { + root_dir = [[root_pattern("mix.exs", ".git") or vim.loop.os_homedir()]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/elmls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/elmls.lua new file mode 100644 index 0000000..2718c88 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/elmls.lua @@ -0,0 +1,44 @@ +local util = require 'lspconfig.util' +local lsp = vim.lsp +local api = vim.api + +local bin_name = 'elm-language-server' +local cmd = { bin_name } + +if vim.fn.has 'win32' == 1 then + cmd = { 'cmd.exe', '/C', bin_name } +end + +local default_capabilities = lsp.protocol.make_client_capabilities() +default_capabilities.offsetEncoding = { 'utf-8', 'utf-16' } +local elm_root_pattern = util.root_pattern 'elm.json' + +return { + default_config = { + cmd = cmd, + -- TODO(ashkan) if we comment this out, it will allow elmls to operate on elm.json. It seems like it could do that, but no other editor allows it right now. + filetypes = { 'elm' }, + root_dir = function(fname) + local filetype = api.nvim_buf_get_option(0, 'filetype') + if filetype == 'elm' or (filetype == 'json' and fname:match 'elm%.json$') then + return elm_root_pattern(fname) + end + end, + init_options = { + elmAnalyseTrigger = 'change', + }, + }, + docs = { + description = [[ +https://github.com/elm-tooling/elm-language-server#installation + +If you don't want to use Nvim to install it, then you can use: +```sh +npm install -g elm elm-test elm-format @elm-tooling/elm-language-server +``` +]], + default_config = { + root_dir = [[root_pattern("elm.json")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/ember.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/ember.lua new file mode 100644 index 0000000..e6ce1ea --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/ember.lua @@ -0,0 +1,30 @@ +local util = require 'lspconfig.util' + +local bin_name = 'ember-language-server' +local cmd = { bin_name, '--stdio' } + +if vim.fn.has 'win32' == 1 then + cmd = { 'cmd.exe', '/C', bin_name, '--stdio' } +end + +return { + default_config = { + cmd = cmd, + filetypes = { 'handlebars', 'typescript', 'javascript' }, + root_dir = util.root_pattern('ember-cli-build.js', '.git'), + }, + docs = { + description = [[ +https://github.com/lifeart/ember-language-server + +`ember-language-server` can be installed via `npm`: + +```sh +npm install -g @lifeart/ember-language-server +``` +]], + default_config = { + root_dir = [[root_pattern("ember-cli-build.js", ".git")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/emmet_ls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/emmet_ls.lua new file mode 100644 index 0000000..3750ae5 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/emmet_ls.lua @@ -0,0 +1,31 @@ +local util = require 'lspconfig.util' + +local bin_name = 'emmet-ls' +local cmd = { bin_name, '--stdio' } + +if vim.fn.has 'win32' == 1 then + cmd = { 'cmd.exe', '/C', bin_name, '--stdio' } +end + +return { + default_config = { + cmd = cmd, + filetypes = { 'html', 'css' }, + root_dir = util.find_git_ancestor, + single_file_support = true, + }, + docs = { + description = [[ +https://github.com/aca/emmet-ls + +Package can be installed via `npm`: +```sh +npm install -g emmet-ls +``` +]], + default_config = { + root_dir = 'git root', + single_file_support = true, + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/erlangls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/erlangls.lua new file mode 100644 index 0000000..cec1928 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/erlangls.lua @@ -0,0 +1,34 @@ +local util = require 'lspconfig.util' + +local cmd = { 'erlang_ls' } +if vim.fn.has 'win32' == 1 then + cmd = { 'cmd.exe', '/C', 'erlang_ls.cmd' } +end + +return { + default_config = { + cmd = cmd, + filetypes = { 'erlang' }, + root_dir = util.root_pattern('rebar.config', 'erlang.mk', '.git'), + single_file_support = true, + }, + docs = { + description = [[ +https://erlang-ls.github.io + +Language Server for Erlang. + +Clone [erlang_ls](https://github.com/erlang-ls/erlang_ls) +Compile the project with `make` and copy resulting binaries somewhere in your $PATH eg. `cp _build/*/bin/* ~/local/bin` + +Installation instruction can be found [here](https://github.com/erlang-ls/erlang_ls). + +Installation requirements: + - [Erlang OTP 21+](https://github.com/erlang/otp) + - [rebar3 3.9.1+](https://github.com/erlang/rebar3) +]], + default_config = { + root_dir = [[root_pattern('rebar.config', 'erlang.mk', '.git')]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/esbonio.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/esbonio.lua new file mode 100644 index 0000000..a97c26b --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/esbonio.lua @@ -0,0 +1,55 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'python3', '-m', 'esbonio' }, + filetypes = { 'rst' }, + root_dir = util.find_git_ancestor, + }, + docs = { + description = [[ +https://github.com/swyddfa/esbonio + +Esbonio is a language server for [Sphinx](https://www.sphinx-doc.org/en/master/) documentation projects. +The language server can be installed via pip + +``` +pip install esbonio +``` + +Since Sphinx is highly extensible you will get best results if you install the language server in the same +Python environment as the one used to build your documentation. To ensure that the correct Python environment +is picked up, you can either launch `nvim` with the correct environment activated. + +``` +source env/bin/activate +nvim +``` + +Or you can modify the default `cmd` to include the full path to the Python interpreter. + +```lua +require'lspconfig'.esbonio.setup { + cmd = { '/path/to/virtualenv/bin/python', '-m', 'esbonio' } +} +``` + +Esbonio supports a number of config values passed as `init_options` on startup, for example. + +```lua +require'lspconfig'.esbonio.setup { + init_options = { + server = { + logLevel = "debug" + }, + sphinx = { + confDir = "/path/to/docs", + srcDir = "${confDir}/../docs-src" + } +} +``` + +A full list and explanation of the available options can be found [here](https://swyddfa.github.io/esbonio/docs/lsp/editors/index.html) +]], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/eslint.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/eslint.lua new file mode 100644 index 0000000..925cdfe --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/eslint.lua @@ -0,0 +1,172 @@ +local util = require 'lspconfig.util' +local lsp = vim.lsp + +local get_eslint_client = function() + local active_clients = lsp.get_active_clients() + for _, client in ipairs(active_clients) do + if client.name == 'eslint' then + return client + end + end + return nil +end + +local function fix_all(opts) + opts = opts or {} + + local eslint_lsp_client = get_eslint_client() + if eslint_lsp_client == nil then + return + end + + local request + if opts.sync then + request = function(bufnr, method, params) + eslint_lsp_client.request_sync(method, params, nil, bufnr) + end + else + request = function(bufnr, method, params) + eslint_lsp_client.request(method, params, nil, bufnr) + end + end + + local bufnr = util.validate_bufnr(opts.bufnr or 0) + request(0, 'workspace/executeCommand', { + command = 'eslint.applyAllFixes', + arguments = { + { + uri = vim.uri_from_bufnr(bufnr), + version = lsp.util.buf_versions[bufnr], + }, + }, + }) +end + +local bin_name = 'vscode-eslint-language-server' +local cmd = { bin_name, '--stdio' } + +if vim.fn.has 'win32' == 1 then + cmd = { 'cmd.exe', '/C', bin_name, '--stdio' } +end + +return { + default_config = { + cmd = cmd, + filetypes = { + 'javascript', + 'javascriptreact', + 'javascript.jsx', + 'typescript', + 'typescriptreact', + 'typescript.tsx', + 'vue', + }, + -- https://eslint.org/docs/user-guide/configuring/configuration-files#configuration-file-formats + root_dir = util.root_pattern( + '.eslintrc.js', + '.eslintrc.cjs', + '.eslintrc.yaml', + '.eslintrc.yml', + '.eslintrc.json', + 'package.json' + ), + -- Refer to https://github.com/Microsoft/vscode-eslint#settings-options for documentation. + settings = { + validate = 'on', + packageManager = 'npm', + useESLintClass = false, + codeActionOnSave = { + enable = false, + mode = 'all', + }, + format = true, + quiet = false, + onIgnoredFiles = 'off', + rulesCustomizations = {}, + run = 'onType', + -- nodePath configures the directory in which the eslint server should start its node_modules resolution. + -- This path is relative to the workspace folder (root dir) of the server instance. + nodePath = '', + -- use the workspace folder location or the file location (if no workspace folder is open) as the working directory + workingDirectory = { mode = 'location' }, + codeAction = { + disableRuleComment = { + enable = true, + location = 'separateLine', + }, + showDocumentation = { + enable = true, + }, + }, + }, + on_new_config = function(config, new_root_dir) + -- The "workspaceFolder" is a VSCode concept. It limits how far the + -- server will traverse the file system when locating the ESLint config + -- file (e.g., .eslintrc). + config.settings.workspaceFolder = { + uri = new_root_dir, + name = vim.fn.fnamemodify(new_root_dir, ':t'), + } + end, + handlers = { + ['eslint/openDoc'] = function(_, result) + if not result then + return + end + local sysname = vim.loop.os_uname().sysname + if sysname:match 'Windows' then + os.execute(string.format('start %q', result.url)) + elseif sysname:match 'Linux' then + os.execute(string.format('xdg-open %q', result.url)) + else + os.execute(string.format('open %q', result.url)) + end + return {} + end, + ['eslint/confirmESLintExecution'] = function(_, result) + if not result then + return + end + return 4 -- approved + end, + ['eslint/probeFailed'] = function() + vim.notify('[lspconfig] ESLint probe failed.', vim.log.levels.WARN) + return {} + end, + ['eslint/noLibrary'] = function() + vim.notify('[lspconfig] Unable to find ESLint library.', vim.log.levels.WARN) + return {} + end, + }, + }, + commands = { + EslintFixAll = { + function() + fix_all { sync = true, bufnr = 0 } + end, + description = 'Fix all eslint problems for this buffer', + }, + }, + docs = { + description = [[ +https://github.com/hrsh7th/vscode-langservers-extracted + +vscode-eslint-language-server: A linting engine for JavaScript / Typescript + +`vscode-eslint-language-server` can be installed via `npm`: +```sh +npm i -g vscode-langservers-extracted +``` + +vscode-eslint-language-server provides an EslintFixAll command that can be used to format document on save +```vim +autocmd BufWritePre *.tsx,*.ts,*.jsx,*.js EslintFixAll +``` + +See [vscode-eslint](https://github.com/microsoft/vscode-eslint/blob/55871979d7af184bf09af491b6ea35ebd56822cf/server/src/eslintServer.ts#L216-L229) for configuration options. + +Additional messages you can handle: eslint/noConfig +Messages already handled in lspconfig: eslint/openDoc, eslint/confirmESLintExecution, eslint/probeFailed, eslint/noLibrary +]], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/flow.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/flow.lua new file mode 100644 index 0000000..3ac59aa --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/flow.lua @@ -0,0 +1,27 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'npx', '--no-install', 'flow', 'lsp' }, + filetypes = { 'javascript', 'javascriptreact', 'javascript.jsx' }, + root_dir = util.root_pattern '.flowconfig', + }, + docs = { + description = [[ +https://flow.org/ +https://github.com/facebook/flow + +See below for how to setup Flow itself. +https://flow.org/en/docs/install/ + +See below for lsp command options. + +```sh +npx flow lsp --help +``` + ]], + default_config = { + root_dir = [[root_pattern(".flowconfig")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/flux_lsp.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/flux_lsp.lua new file mode 100644 index 0000000..3be9a1b --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/flux_lsp.lua @@ -0,0 +1,22 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'flux-lsp' }, + filetypes = { 'flux' }, + root_dir = util.find_git_ancestor, + single_file_support = true, + }, + docs = { + description = [[ +https://github.com/influxdata/flux-lsp +`flux-lsp` can be installed via `cargo`: +```sh +cargo install --git https://github.com/influxdata/flux-lsp +``` +]], + default_config = { + root_dir = [[util.find_git_ancestor]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/foam_ls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/foam_ls.lua new file mode 100644 index 0000000..1f0d7fc --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/foam_ls.lua @@ -0,0 +1,31 @@ +local util = require 'lspconfig.util' +local bin_name = 'foam-ls' +local cmd = { bin_name, '--stdio' } + +if vim.fn.has 'win32' == 1 then + cmd = { 'cmd.exe', '/C', bin_name, '--stdio' } +end + +return { + default_config = { + cmd = cmd, + filetypes = { 'foam', 'OpenFOAM' }, + root_dir = function(fname) + return util.search_ancestors(fname, function(path) + if util.path.exists(util.path.join(path, 'system', 'controlDict')) then + return path + end + end) + end, + }, + docs = { + description = [[ +https://github.com/FoamScience/foam-language-server + +`foam-language-server` can be installed via `npm` +```sh +npm install -g foam-language-server +``` +]], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/fortls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/fortls.lua new file mode 100644 index 0000000..5879139 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/fortls.lua @@ -0,0 +1,24 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'fortls' }, + filetypes = { 'fortran' }, + root_dir = function(fname) + return util.root_pattern '.fortls'(fname) or util.find_git_ancestor(fname) + end, + settings = { + nthreads = 1, + }, + }, + docs = { + description = [[ +https://github.com/hansec/fortran-language-server + +Fortran Language Server for the Language Server Protocol + ]], + default_config = { + root_dir = [[root_pattern(".fortls")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/fsautocomplete.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/fsautocomplete.lua new file mode 100644 index 0000000..1a1d4c5 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/fsautocomplete.lua @@ -0,0 +1,32 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'fsautocomplete', '--background-service-enabled' }, + root_dir = util.root_pattern('*.sln', '*.fsproj', '.git'), + filetypes = { 'fsharp' }, + init_options = { + AutomaticWorkspaceInit = true, + }, + }, + docs = { + description = [[ +https://github.com/fsharp/FsAutoComplete + +Language Server for F# provided by FsAutoComplete (FSAC). + +FsAutoComplete requires the [dotnet-sdk](https://dotnet.microsoft.com/download) to be installed. + +The preferred way to install FsAutoComplete is with `dotnet tool install --global fsautocomplete`. + +Instructions to compile from source are found on the main [repository](https://github.com/fsharp/FsAutoComplete). + +You may also need to configure the filetype as Vim defaults to Forth for `*.fs` files: + +`autocmd BufNewFile,BufRead *.fs,*.fsx,*.fsi set filetype=fsharp` + +This is automatically done by plugins such as [PhilT/vim-fsharp](https://github.com/PhilT/vim-fsharp), [fsharp/vim-fsharp](https://github.com/fsharp/vim-fsharp), and [adelarsq/neofsharp.vim](https://github.com/adelarsq/neofsharp.vim). + + ]], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/fstar.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/fstar.lua new file mode 100644 index 0000000..d866c54 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/fstar.lua @@ -0,0 +1,19 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'fstar.exe', '--lsp' }, + filetypes = { 'fstar' }, + root_dir = util.find_git_ancestor, + }, + docs = { + description = [[ +https://github.com/FStarLang/FStar + +LSP support is included in FStar. Make sure `fstar.exe` is in your PATH. +]], + default_config = { + root_dir = [[util.find_git_ancestor]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/gdscript.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/gdscript.lua new file mode 100644 index 0000000..d6d697f --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/gdscript.lua @@ -0,0 +1,19 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'nc', 'localhost', '6008' }, + filetypes = { 'gd', 'gdscript', 'gdscript3' }, + root_dir = util.root_pattern('project.godot', '.git'), + }, + docs = { + description = [[ +https://github.com/godotengine/godot + +Language server for GDScript, used by Godot Engine. +]], + default_config = { + root_dir = [[util.root_pattern("project.godot", ".git")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/ghcide.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/ghcide.lua new file mode 100644 index 0000000..7f9307b --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/ghcide.lua @@ -0,0 +1,21 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'ghcide', '--lsp' }, + filetypes = { 'haskell', 'lhaskell' }, + root_dir = util.root_pattern('stack.yaml', 'hie-bios', 'BUILD.bazel', 'cabal.config', 'package.yaml'), + }, + + docs = { + description = [[ +https://github.com/digital-asset/ghcide + +A library for building Haskell IDE tooling. +"ghcide" isn't for end users now. Use "haskell-language-server" instead of "ghcide". +]], + default_config = { + root_dir = [[root_pattern("stack.yaml", "hie-bios", "BUILD.bazel", "cabal.config", "package.yaml")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/golangci_lint_ls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/golangci_lint_ls.lua new file mode 100644 index 0000000..8eaa015 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/golangci_lint_ls.lua @@ -0,0 +1,34 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'golangci-lint-langserver' }, + filetypes = { 'go', 'gomod' }, + init_options = { + command = { 'golangci-lint', 'run', '--out-format', 'json' }, + }, + root_dir = function(fname) + return util.root_pattern 'go.work'(fname) or util.root_pattern('go.mod', '.golangci.yaml', '.git')(fname) + end, + }, + docs = { + description = [[ +Combination of both lint server and client + +https://github.com/nametake/golangci-lint-langserver +https://github.com/golangci/golangci-lint + + +Installation of binaries needed is done via + +``` +go install github.com/nametake/golangci-lint-langserver@latest +go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.42.1 +``` + +]], + default_config = { + root_dir = [[root_pattern('go.work') or root_pattern('go.mod', '.golangci.yaml', '.git')]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/gopls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/gopls.lua new file mode 100644 index 0000000..f6a085d --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/gopls.lua @@ -0,0 +1,22 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'gopls' }, + filetypes = { 'go', 'gomod', 'gotmpl' }, + root_dir = function(fname) + return util.root_pattern 'go.work'(fname) or util.root_pattern('go.mod', '.git')(fname) + end, + single_file_support = true, + }, + docs = { + description = [[ +https://github.com/golang/tools/tree/master/gopls + +Google's lsp server for golang. +]], + default_config = { + root_dir = [[root_pattern("go.mod", ".git")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/gradle_ls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/gradle_ls.lua new file mode 100644 index 0000000..b23b599 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/gradle_ls.lua @@ -0,0 +1,37 @@ +local util = require 'lspconfig.util' + +local bin_name = 'gradle-language-server' +if vim.fn.has 'win32' == 1 then + bin_name = bin_name .. '.bat' +end + +local root_files = { + 'settings.gradle', -- Gradle (multi-project) +} + +local fallback_root_files = { + 'build.gradle', -- Gradle +} + +return { + default_config = { + filetypes = { 'groovy' }, + root_dir = function(fname) + return util.root_pattern(unpack(root_files))(fname) or util.root_pattern(unpack(fallback_root_files))(fname) + end, + cmd = { bin_name }, + }, + docs = { + description = [[ +https://github.com/microsoft/vscode-gradle + +Microsoft's lsp server for gradle files + +If you're setting this up manually, build vscode-gradle using `./gradlew installDist` and point `cmd` to the `gradle-language-server` generated in the build directory +]], + default_config = { + root_dir = [[root_pattern("settings.gradle")]], + cmd = { 'gradle-language-server' }, + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/grammarly.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/grammarly.lua new file mode 100644 index 0000000..675169d --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/grammarly.lua @@ -0,0 +1,38 @@ +local util = require 'lspconfig.util' + +local bin_name = 'unofficial-grammarly-language-server' +local cmd = { bin_name, '--stdio' } + +if vim.fn.has 'win32' == 1 then + cmd = { 'cmd.exe', '/C', bin_name, '--stdio' } +end + +return { + default_config = { + cmd = cmd, + filetypes = { 'markdown' }, + root_dir = util.find_git_ancestor, + single_file_support = true, + handlers = { + ['$/updateDocumentState'] = function() + return '' + end, + }, + }, + docs = { + description = [[ +https://github.com/emacs-grammarly/unofficial-grammarly-language-server + +`unofficial-grammarly-language-server` can be installed via `npm`: + +```sh +npm i -g @emacs-grammarly/unofficial-grammarly-language-server +``` + +WARNING: Since this language server uses Grammarly's API, any document you open with it running is shared with them. Please evaluate their [privacy policy](https://www.grammarly.com/privacy-policy) before using this. +]], + default_config = { + root_dir = [[util.find_git_ancestor]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/graphql.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/graphql.lua new file mode 100644 index 0000000..d34881c --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/graphql.lua @@ -0,0 +1,33 @@ +local util = require 'lspconfig.util' + +local bin_name = 'graphql-lsp' +local cmd = { bin_name, 'server', '-m', 'stream' } + +if vim.fn.has 'win32' == 1 then + cmd = { 'cmd.exe', '/C', bin_name, 'server', '-m', 'stream' } +end + +return { + default_config = { + cmd = cmd, + filetypes = { 'graphql', 'typescriptreact', 'javascriptreact' }, + root_dir = util.root_pattern('.git', '.graphqlrc*', '.graphql.config.*', 'graphql.config.*'), + }, + + docs = { + description = [[ +https://github.com/graphql/graphiql/tree/main/packages/graphql-language-service-cli + +`graphql-lsp` can be installed via `npm`: + +```sh +npm install -g graphql-language-service-cli +``` + +Note that you must also have [the graphql package](https://github.com/graphql/graphql-js) installed and create a [GraphQL config file](https://www.graphql-config.com/docs/user/user-introduction). +]], + default_config = { + root_dir = [[root_pattern('.git', '.graphqlrc*', '.graphql.config.*')]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/groovyls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/groovyls.lua new file mode 100644 index 0000000..b4182f4 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/groovyls.lua @@ -0,0 +1,36 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { + 'java', + '-jar', + 'groovy-language-server-all.jar', + }, + filetypes = { 'groovy' }, + root_dir = function(fname) + return util.root_pattern 'Jenkinsfile'(fname) or util.find_git_ancestor(fname) + end, + }, + docs = { + description = [[ +https://github.com/prominic/groovy-language-server.git + +Requirements: + - Linux/macOS (for now) + - Java 11+ + +`groovyls` can be installed by following the instructions [here](https://github.com/prominic/groovy-language-server.git#build). + +If you have installed groovy language server, you can set the `cmd` custom path as follow: + +```lua +require'lspconfig'.groovyls.setup{ + -- Unix + cmd = { "java", "-jar", "path/to/groovyls/groovy-language-server-all.jar" }, + ... +} +``` +]], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/haxe_language_server.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/haxe_language_server.lua new file mode 100644 index 0000000..1589c7b --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/haxe_language_server.lua @@ -0,0 +1,47 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'haxe-language-server' }, + filetypes = { 'haxe' }, + root_dir = util.root_pattern '*.hxml', + settings = { + haxe = { + executable = 'haxe', + }, + }, + init_options = { + displayArguments = { 'build.hxml' }, + }, + }, + docs = { + description = [[ +https://github.com/vshaxe/haxe-language-server + +The Haxe language server can be built by running the following commands from +the project's root directory: + + npm install + npx lix run vshaxe-build -t language-server + +This will create `bin/server.js`. Note that the server requires Haxe 3.4.0 or +higher. + +After building the language server, set the `cmd` setting in your setup +function: + +```lua +lspconfig.haxe_language_server.setup({ + cmd = {"node", "path/to/bin/server.js"}, +}) +``` + +By default, an HXML compiler arguments file named `build.hxml` is expected in +your project's root directory. If your file is named something different, +specify it using the `init_options.displayArguments` setting. +]], + default_config = { + root_dir = [[root_pattern("*.hxml")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/hdl_checker.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/hdl_checker.lua new file mode 100644 index 0000000..5cf2941 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/hdl_checker.lua @@ -0,0 +1,20 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'hdl_checker', '--lsp' }, + filetypes = { 'vhdl', 'verilog', 'systemverilog' }, + root_dir = util.find_git_ancestor, + single_file_support = true, + }, + docs = { + description = [[ +https://github.com/suoto/hdl_checker +Language server for hdl-checker. +Install using: `pip install hdl-checker --upgrade` +]], + default_config = { + root_dir = [[util.find_git_ancestor]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/hhvm.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/hhvm.lua new file mode 100644 index 0000000..0e8ac5c --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/hhvm.lua @@ -0,0 +1,21 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'hh_client', 'lsp' }, + filetypes = { 'php', 'hack' }, + root_dir = util.root_pattern '.hhconfig', + }, + docs = { + description = [[ +Language server for programs written in Hack +https://hhvm.com/ +https://github.com/facebook/hhvm +See below for how to setup HHVM & typechecker: +https://docs.hhvm.com/hhvm/getting-started/getting-started + ]], + default_config = { + root_dir = [[root_pattern(".hhconfig")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/hie.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/hie.lua new file mode 100644 index 0000000..96148ad --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/hie.lua @@ -0,0 +1,34 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'hie-wrapper', '--lsp' }, + filetypes = { 'haskell' }, + root_dir = util.root_pattern('stack.yaml', 'package.yaml', '.git'), + }, + + docs = { + description = [[ +https://github.com/haskell/haskell-ide-engine + +the following init_options are supported (see https://github.com/haskell/haskell-ide-engine#configuration): +```lua +init_options = { + languageServerHaskell = { + hlintOn = bool; + maxNumberOfProblems = number; + diagnosticsDebounceDuration = number; + liquidOn = bool (default false); + completionSnippetsOn = bool (default true); + formatOnImportOn = bool (default true); + formattingProvider = string (default "brittany", alternate "floskell"); + } +} +``` + ]], + + default_config = { + root_dir = [[root_pattern("stack.yaml", "package.yaml", ".git")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/hls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/hls.lua new file mode 100644 index 0000000..32b3ea2 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/hls.lua @@ -0,0 +1,43 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'haskell-language-server-wrapper', '--lsp' }, + filetypes = { 'haskell', 'lhaskell' }, + root_dir = util.root_pattern('*.cabal', 'stack.yaml', 'cabal.project', 'package.yaml', 'hie.yaml'), + single_file_support = true, + settings = { + haskell = { + formattingProvider = 'ormolu', + }, + }, + lspinfo = function(cfg) + local extra = {} + local function on_stdout(_, data, _) + local version = data[1] + table.insert(extra, 'version: ' .. version) + end + + local opts = { + cwd = cfg.cwd, + stdout_buffered = true, + on_stdout = on_stdout, + } + local chanid = vim.fn.jobstart({ cfg.cmd[1], '--version' }, opts) + vim.fn.jobwait { chanid } + return extra + end, + }, + + docs = { + description = [[ +https://github.com/haskell/haskell-language-server + +Haskell Language Server + ]], + + default_config = { + root_dir = [[root_pattern("*.cabal", "stack.yaml", "cabal.project", "package.yaml", "hie.yaml")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/hoon_ls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/hoon_ls.lua new file mode 100644 index 0000000..80092db --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/hoon_ls.lua @@ -0,0 +1,29 @@ +local util = require 'lspconfig.util' + +local bin_name = 'hoon-language-server' +local cmd = { bin_name } + +if vim.fn.has 'win32' == 1 then + cmd = { 'cmd.exe', '/C', bin_name } +end + +return { + default_config = { + cmd = cmd, + filetypes = { 'hoon' }, + root_dir = util.find_git_ancestor, + single_file_support = true, + }, + docs = { + description = [[ +https://github.com/urbit/hoon-language-server + +A language server for Hoon. + +The language server can be installed via `npm install -g @hoon-language-server` + +Start a fake ~zod with `urbit -F zod`. +Start the language server at the Urbit Dojo prompt with: `|start %language-server` +]], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/html.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/html.lua new file mode 100644 index 0000000..2f8214f --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/html.lua @@ -0,0 +1,48 @@ +local util = require 'lspconfig.util' + +local bin_name = 'vscode-html-language-server' +local cmd = { bin_name, '--stdio' } + +if vim.fn.has 'win32' == 1 then + cmd = { 'cmd.exe', '/C', bin_name, '--stdio' } +end + +return { + default_config = { + cmd = cmd, + filetypes = { 'html' }, + root_dir = util.root_pattern('package.json', '.git'), + single_file_support = true, + settings = {}, + init_options = { + provideFormatter = true, + embeddedLanguages = { css = true, javascript = true }, + configurationSection = { 'html', 'css', 'javascript' }, + }, + }, + docs = { + description = [[ +https://github.com/hrsh7th/vscode-langservers-extracted + +`vscode-html-language-server` can be installed via `npm`: +```sh +npm i -g vscode-langservers-extracted +``` + +Neovim does not currently include built-in snippets. `vscode-html-language-server` only provides completions when snippet support is enabled. +To enable completion, install a snippet plugin and add the following override to your language client capabilities during setup. + +The code-formatting feature of the lsp can be controlled with the `provideFormatter` option. + +```lua +--Enable (broadcasting) snippet capability for completion +local capabilities = vim.lsp.protocol.make_client_capabilities() +capabilities.textDocument.completion.completionItem.snippetSupport = true + +require'lspconfig'.html.setup { + capabilities = capabilities, +} +``` +]], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/idris2_lsp.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/idris2_lsp.lua new file mode 100644 index 0000000..d6efdd1 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/idris2_lsp.lua @@ -0,0 +1,41 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'idris2-lsp' }, + filetypes = { 'idris2' }, + root_dir = util.root_pattern '*.ipkg', + }, + docs = { + description = [[ +https://github.com/idris-community/idris2-lsp + +The Idris 2 language server. + +Plugins for the Idris 2 filetype include +[Idris2-Vim](https://github.com/edwinb/idris2-vim) (fewer features, stable) and +[Nvim-Idris2](https://github.com/ShinKage/nvim-idris2) (cutting-edge, +experimental). + +Idris2-Lsp requires a build of Idris 2 that includes the "Idris 2 API" package. +Package managers with known support for this build include the +[AUR](https://aur.archlinux.org/packages/idris2-api-git/) and +[Homebrew](https://formulae.brew.sh/formula/idris2#default). + +If your package manager does not support the Idris 2 API, you will need to build +Idris 2 from source. Refer to the +[the Idris 2 installation instructions](https://github.com/idris-lang/Idris2/blob/main/INSTALL.md) +for details. Steps 5 and 8 are listed as "optional" in that guide, but they are +necessary in order to make the Idris 2 API available. + +You need to install a version of Idris2-Lsp that is compatible with your +version of Idris 2. There should be a branch corresponding to every released +Idris 2 version after v0.4.0. Use the latest commit on that branch. For example, +if you have Idris v0.5.1, you should use the v0.5.1 branch of Idris2-Lsp. + +If your Idris 2 version is newer than the newest Idris2-Lsp branch, use the +latest commit on the `master` branch, and set a reminder to check the Idris2-Lsp +repo for the release of a compatible versioned branch. +]], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/intelephense.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/intelephense.lua new file mode 100644 index 0000000..c9e35b9 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/intelephense.lua @@ -0,0 +1,50 @@ +local util = require 'lspconfig.util' + +local bin_name = 'intelephense' +local cmd = { bin_name, '--stdio' } + +if vim.fn.has 'win32' == 1 then + cmd = { 'cmd.exe', '/C', bin_name, '--stdio' } +end + +return { + default_config = { + cmd = cmd, + filetypes = { 'php' }, + root_dir = function(pattern) + local cwd = vim.loop.cwd() + local root = util.root_pattern('composer.json', '.git')(pattern) + + -- prefer cwd if root is a descendant + return util.path.is_descendant(cwd, root) and cwd or root + end, + }, + docs = { + description = [[ +https://intelephense.com/ + +`intelephense` can be installed via `npm`: +```sh +npm install -g intelephense +``` +]], + default_config = { + root_dir = [[root_pattern("composer.json", ".git")]], + init_options = [[{ + storagePath = Optional absolute path to storage dir. Defaults to os.tmpdir(). + globalStoragePath = Optional absolute path to a global storage dir. Defaults to os.homedir(). + licenceKey = Optional licence key or absolute path to a text file containing the licence key. + clearCache = Optional flag to clear server state. State can also be cleared by deleting {storagePath}/intelephense + -- See https://github.com/bmewburn/intelephense-docs/blob/master/installation.md#initialisation-options + }]], + settings = [[{ + intelephense = { + files = { + maxSize = 1000000; + }; + }; + -- See https://github.com/bmewburn/intelephense-docs + }]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/java_language_server.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/java_language_server.lua new file mode 100644 index 0000000..3ddf4b1 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/java_language_server.lua @@ -0,0 +1,18 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + filetypes = { 'java' }, + root_dir = util.root_pattern('build.gradle', 'pom.xml', '.git'), + settings = {}, + }, + docs = { + description = [[ +https://github.com/georgewfraser/java-language-server + +Java language server + +Point `cmd` to `lang_server_linux.sh` or the equivalent script for macOS/Windows provided by java-language-server +]], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/jdtls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/jdtls.lua new file mode 100644 index 0000000..d740572 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/jdtls.lua @@ -0,0 +1,193 @@ +local util = require 'lspconfig.util' +local handlers = require 'vim.lsp.handlers' + +local sysname = vim.loop.os_uname().sysname +local env = { + HOME = vim.loop.os_homedir(), + JAVA_HOME = os.getenv 'JAVA_HOME', + JDTLS_HOME = os.getenv 'JDTLS_HOME', + WORKSPACE = os.getenv 'WORKSPACE', +} + +local function get_java_executable() + local executable = env.JAVA_HOME and util.path.join(env.JAVA_HOME, 'bin', 'java') or 'java' + + return sysname:match 'Windows' and executable .. '.exe' or executable +end + +local function get_workspace_dir() + return env.WORKSPACE and env.WORKSPACE or util.path.join(env.HOME, 'workspace') +end + +local function get_jdtls_jar() + return vim.fn.expand '$JDTLS_HOME/plugins/org.eclipse.equinox.launcher_*.jar' +end + +local function get_jdtls_config() + if sysname:match 'Linux' then + return util.path.join(env.JDTLS_HOME, 'config_linux') + elseif sysname:match 'Darwin' then + return util.path.join(env.JDTLS_HOME, 'config_mac') + elseif sysname:match 'Windows' then + return util.path.join(env.JDTLS_HOME, 'config_win') + else + return util.path.join(env.JDTLS_HOME, 'config_linux') + end +end + +-- TextDocument version is reported as 0, override with nil so that +-- the client doesn't think the document is newer and refuses to update +-- See: https://github.com/eclipse/eclipse.jdt.ls/issues/1695 +local function fix_zero_version(workspace_edit) + if workspace_edit and workspace_edit.documentChanges then + for _, change in pairs(workspace_edit.documentChanges) do + local text_document = change.textDocument + if text_document and text_document.version and text_document.version == 0 then + text_document.version = nil + end + end + end + return workspace_edit +end + +local function on_textdocument_codeaction(err, actions, ctx) + for _, action in ipairs(actions) do + -- TODO: (steelsojka) Handle more than one edit? + if action.command == 'java.apply.workspaceEdit' then -- 'action' is Command in java format + action.edit = fix_zero_version(action.edit or action.arguments[1]) + elseif type(action.command) == 'table' and action.command.command == 'java.apply.workspaceEdit' then -- 'action' is CodeAction in java format + action.edit = fix_zero_version(action.edit or action.command.arguments[1]) + end + end + + handlers[ctx.method](err, actions, ctx) +end + +local function on_textdocument_rename(err, workspace_edit, ctx) + handlers[ctx.method](err, fix_zero_version(workspace_edit), ctx) +end + +local function on_workspace_applyedit(err, workspace_edit, ctx) + handlers[ctx.method](err, fix_zero_version(workspace_edit), ctx) +end + +-- Non-standard notification that can be used to display progress +local function on_language_status(_, result) + local command = vim.api.nvim_command + command 'echohl ModeMsg' + command(string.format('echo "%s"', result.message)) + command 'echohl None' +end + +local root_files = { + -- Single-module projects + { + 'build.xml', -- Ant + 'pom.xml', -- Maven + 'settings.gradle', -- Gradle + 'settings.gradle.kts', -- Gradle + }, + -- Multi-module projects + { 'build.gradle', 'build.gradle.kts' }, +} + +return { + default_config = { + cmd = { + get_java_executable(), + '-Declipse.application=org.eclipse.jdt.ls.core.id1', + '-Dosgi.bundles.defaultStartLevel=4', + '-Declipse.product=org.eclipse.jdt.ls.core.product', + '-Dlog.protocol=true', + '-Dlog.level=ALL', + '-Xms1g', + '-Xmx2G', + '--add-modules=ALL-SYSTEM', + '--add-opens', + 'java.base/java.util=ALL-UNNAMED', + '--add-opens', + 'java.base/java.lang=ALL-UNNAMED', + '-jar', + get_jdtls_jar(), + '-configuration', + get_jdtls_config(), + '-data', + get_workspace_dir(), + }, + filetypes = { 'java' }, + root_dir = function(fname) + for _, patterns in ipairs(root_files) do + local root = util.root_pattern(unpack(patterns))(fname) + if root then + return root + end + end + end, + single_file_support = true, + init_options = { + workspace = get_workspace_dir(), + jvm_args = {}, + os_config = nil, + }, + handlers = { + -- Due to an invalid protocol implementation in the jdtls we have to conform these to be spec compliant. + -- https://github.com/eclipse/eclipse.jdt.ls/issues/376 + ['textDocument/codeAction'] = on_textdocument_codeaction, + ['textDocument/rename'] = on_textdocument_rename, + ['workspace/applyEdit'] = on_workspace_applyedit, + ['language/status'] = vim.schedule_wrap(on_language_status), + }, + }, + docs = { + description = [[ +https://projects.eclipse.org/projects/eclipse.jdt.ls + +Language server for Java. + +IMPORTANT: If you want all the features jdtls has to offer, [nvim-jdtls](https://github.com/mfussenegger/nvim-jdtls) +is highly recommended. If all you need is diagnostics, completion, imports, gotos and formatting and some code actions +you can keep reading here. + +For manual installation you can download precompiled binaries from the +[official downloads site](http://download.eclipse.org/jdtls/snapshots/?d) + +Due to the nature of java, settings cannot be inferred. Please set the following +environmental variables to match your installation. If you need per-project configuration +[direnv](https://github.com/direnv/direnv) is highly recommended. + +```bash +# Mandatory: +# .bashrc +export JDTLS_HOME=/path/to/jdtls_root # Directory with the plugin and configs directories + +# Optional: +export JAVA_HOME=/path/to/java_home # In case you don't have java in path or want to use a version in particular +export WORKSPACE=/path/to/workspace # Defaults to $HOME/workspace +``` +```lua + -- init.lua + require'lspconfig'.jdtls.setup{} +``` + +For automatic installation you can use the following unofficial installers/launchers under your own risk: + - [jdtls-launcher](https://github.com/eruizc-dev/jdtls-launcher) (Includes lombok support by default) + ```lua + -- init.lua + require'lspconfig'.jdtls.setup{ cmd = { 'jdtls' } } + ``` + ]], + default_config = { + root_dir = [[{ + -- Single-module projects + { + 'build.xml', -- Ant + 'pom.xml', -- Maven + 'settings.gradle', -- Gradle + 'settings.gradle.kts', -- Gradle + }, + -- Multi-module projects + { 'build.gradle', 'build.gradle.kts' }, + } or vim.fn.getcwd()]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/jedi_language_server.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/jedi_language_server.lua new file mode 100644 index 0000000..30cf8f5 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/jedi_language_server.lua @@ -0,0 +1,28 @@ +local util = require 'lspconfig.util' + +local root_files = { + 'pyproject.toml', + 'setup.py', + 'setup.cfg', + 'requirements.txt', + 'Pipfile', +} + +return { + default_config = { + cmd = { 'jedi-language-server' }, + filetypes = { 'python' }, + root_dir = util.root_pattern(unpack(root_files)), + single_file_support = true, + }, + docs = { + description = [[ +https://github.com/pappasam/jedi-language-server + +`jedi-language-server`, a language server for Python, built on top of jedi + ]], + default_config = { + root_dir = "vim's starting directory", + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/jsonls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/jsonls.lua new file mode 100644 index 0000000..a62a715 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/jsonls.lua @@ -0,0 +1,48 @@ +local util = require 'lspconfig.util' + +local bin_name = 'vscode-json-language-server' +local cmd = { bin_name, '--stdio' } + +if vim.fn.has 'win32' == 1 then + cmd = { 'cmd.exe', '/C', bin_name, '--stdio' } +end + +return { + default_config = { + cmd = cmd, + filetypes = { 'json', 'jsonc' }, + init_options = { + provideFormatter = true, + }, + root_dir = util.find_git_ancestor, + single_file_support = true, + }, + docs = { + -- this language server config is in VSCode built-in package.json + description = [[ +https://github.com/hrsh7th/vscode-langservers-extracted + +vscode-json-language-server, a language server for JSON and JSON schema + +`vscode-json-language-server` can be installed via `npm`: +```sh +npm i -g vscode-langservers-extracted +``` + +Neovim does not currently include built-in snippets. `vscode-json-language-server` only provides completions when snippet support is enabled. To enable completion, install a snippet plugin and add the following override to your language client capabilities during setup. + +```lua +--Enable (broadcasting) snippet capability for completion +local capabilities = vim.lsp.protocol.make_client_capabilities() +capabilities.textDocument.completion.completionItem.snippetSupport = true + +require'lspconfig'.jsonls.setup { + capabilities = capabilities, +} +``` +]], + default_config = { + root_dir = [[util.find_git_ancestor]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/jsonnet_ls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/jsonnet_ls.lua new file mode 100644 index 0000000..3493e7e --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/jsonnet_ls.lua @@ -0,0 +1,40 @@ +local util = require 'lspconfig.util' + +-- common jsonnet library paths +local function jsonnet_path(root_dir) + local paths = { + util.path.join(root_dir, 'lib'), + util.path.join(root_dir, 'vendor'), + } + return table.concat(paths, ':') +end + +return { + default_config = { + cmd = { 'jsonnet-language-server' }, + filetypes = { 'jsonnet', 'libsonnet' }, + root_dir = function(fname) + return util.root_pattern 'jsonnetfile.json'(fname) or util.find_git_ancestor(fname) + end, + on_new_config = function(new_config, root_dir) + new_config.cmd_env = { + JSONNET_PATH = jsonnet_path(root_dir), + } + end, + }, + docs = { + description = [[ +https://github.com/grafana/jsonnet-language-server + +A Language Server Protocol (LSP) server for Jsonnet. + +The language server can be installed with `go`: +```sh +go install github.com/grafana/jsonnet-language-server@latest +``` +]], + default_config = { + root_dir = [[root_pattern("jsonnetfile.json")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/julials.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/julials.lua new file mode 100644 index 0000000..44360c7 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/julials.lua @@ -0,0 +1,75 @@ +local util = require 'lspconfig.util' + +local cmd = { + 'julia', + '--startup-file=no', + '--history-file=no', + '-e', + [[ + # Load LanguageServer.jl: attempt to load from ~/.julia/environments/nvim-lspconfig + # with the regular load path as a fallback + ls_install_path = joinpath( + get(DEPOT_PATH, 1, joinpath(homedir(), ".julia")), + "environments", "nvim-lspconfig" + ) + pushfirst!(LOAD_PATH, ls_install_path) + using LanguageServer + popfirst!(LOAD_PATH) + depot_path = get(ENV, "JULIA_DEPOT_PATH", "") + project_path = let + dirname(something( + ## 1. Finds an explicitly set project (JULIA_PROJECT) + Base.load_path_expand(( + p = get(ENV, "JULIA_PROJECT", nothing); + p === nothing ? nothing : isempty(p) ? nothing : p + )), + ## 2. Look for a Project.toml file in the current working directory, + ## or parent directories, with $HOME as an upper boundary + Base.current_project(), + ## 3. First entry in the load path + get(Base.load_path(), 1, nothing), + ## 4. Fallback to default global environment, + ## this is more or less unreachable + Base.load_path_expand("@v#.#"), + )) + end + @info "Running language server" VERSION pwd() project_path depot_path + server = LanguageServer.LanguageServerInstance(stdin, stdout, project_path, depot_path) + server.runlinter = true + run(server) + ]], +} + +return { + default_config = { + cmd = cmd, + filetypes = { 'julia' }, + root_dir = function(fname) + return util.root_pattern 'Project.toml'(fname) or util.find_git_ancestor(fname) + end, + single_file_support = true, + }, + docs = { + description = [[ +https://github.com/julia-vscode/julia-vscode + +LanguageServer.jl can be installed with `julia` and `Pkg`: +```sh +julia --project=~/.julia/environments/nvim-lspconfig -e 'using Pkg; Pkg.add("LanguageServer")' +``` +where `~/.julia/environments/nvim-lspconfig` is the location where +the default configuration expects LanguageServer.jl to be installed. + +To update an existing install, use the following command: +```sh +julia --project=~/.julia/environments/nvim-lspconfig -e 'using Pkg; Pkg.update()' +``` + +Note: In order to have LanguageServer.jl pick up installed packages or dependencies in a +Julia project, you must make sure that the project is instantiated: +```sh +julia --project=/path/to/my/project -e 'using Pkg; Pkg.instantiate()' +``` + ]], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/kotlin_language_server.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/kotlin_language_server.lua new file mode 100644 index 0000000..a955fe6 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/kotlin_language_server.lua @@ -0,0 +1,71 @@ +local util = require 'lspconfig.util' + +local bin_name = 'kotlin-language-server' +if vim.fn.has 'win32' == 1 then + bin_name = bin_name .. '.bat' +end + +--- The presence of one of these files indicates a project root directory +-- +-- These are configuration files for the various build systems supported by +-- Kotlin. I am not sure whether the language server supports Ant projects, +-- but I'm keeping it here as well since Ant does support Kotlin. +local root_files = { + 'settings.gradle', -- Gradle (multi-project) + 'settings.gradle.kts', -- Gradle (multi-project) + 'build.xml', -- Ant + 'pom.xml', -- Maven +} + +local fallback_root_files = { + 'build.gradle', -- Gradle + 'build.gradle.kts', -- Gradle +} + +return { + default_config = { + filetypes = { 'kotlin' }, + root_dir = function(fname) + return util.root_pattern(unpack(root_files))(fname) or util.root_pattern(unpack(fallback_root_files))(fname) + end, + cmd = { bin_name }, + }, + docs = { + description = [[ + A kotlin language server which was developed for internal usage and + released afterwards. Maintaining is not done by the original author, + but by fwcd. + + It is built via gradle and developed on github. + Source and additional description: + https://github.com/fwcd/kotlin-language-server + + This server requires vim to be aware of the kotlin-filetype. + You could refer for this capability to: + https://github.com/udalov/kotlin-vim (recommended) + Note that there is no LICENSE specified yet. + ]], + default_config = { + root_dir = [[root_pattern("settings.gradle")]], + cmd = { 'kotlin-language-server' }, + capabilities = [[ + smart code completion, + diagnostics, + hover, + document symbols, + definition lookup, + method signature help, + dependency resolution, + additional plugins from: https://github.com/fwcd + + Snipped of License (refer to source for full License): + + The MIT License (MIT) + + Copyright (c) 2016 George Fraser + Copyright (c) 2018 fwcd + + ]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/lean3ls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/lean3ls.lua new file mode 100644 index 0000000..b35a693 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/lean3ls.lua @@ -0,0 +1,54 @@ +local util = require 'lspconfig.util' + +local bin_name = 'lean-language-server' +local args = { '--stdio', '--', '-M', '4096', '-T', '100000' } +local cmd = { bin_name, unpack(args) } + +if vim.fn.has 'win32' == 1 then + cmd = { 'cmd.exe', '/C', bin_name, unpack(args) } +end + +return { + default_config = { + cmd = cmd, + filetypes = { 'lean3' }, + offset_encoding = 'utf-32', + root_dir = function(fname) + fname = util.path.sanitize(fname) + -- check if inside elan stdlib + local stdlib_dir + do + local _, endpos = fname:find '/lean/library' + if endpos then + stdlib_dir = fname:sub(1, endpos) + end + end + + return util.root_pattern 'leanpkg.toml'(fname) + or util.root_pattern 'leanpkg.path'(fname) + or stdlib_dir + or util.find_git_ancestor(fname) + end, + single_file_support = true, + }, + docs = { + description = [[ +https://github.com/leanprover/lean-client-js/tree/master/lean-language-server + +Lean installation instructions can be found +[here](https://leanprover-community.github.io/get_started.html#regular-install). + +Once Lean is installed, you can install the Lean 3 language server by running +```sh +npm install -g lean-language-server +``` + +Note: that if you're using [lean.nvim](https://github.com/Julian/lean.nvim), +that plugin fully handles the setup of the Lean language server, +and you shouldn't set up `lean3ls` both with it and `lspconfig`. + ]], + default_config = { + root_dir = [[root_pattern("leanpkg.toml") or root_pattern(".git")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/leanls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/leanls.lua new file mode 100644 index 0000000..208598a --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/leanls.lua @@ -0,0 +1,77 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'lake', 'serve', '--' }, + filetypes = { 'lean' }, + root_dir = function(fname) + -- check if inside elan stdlib + fname = util.path.sanitize(fname) + local stdlib_dir + do + local _, endpos = fname:find '/src/lean' + if endpos then + stdlib_dir = fname:sub(1, endpos) + end + end + if not stdlib_dir then + local _, endpos = fname:find '/lib/lean' + if endpos then + stdlib_dir = fname:sub(1, endpos) + end + end + + return util.root_pattern('lakefile.lean', 'lean-toolchain', 'leanpkg.toml')(fname) + or stdlib_dir + or util.find_git_ancestor(fname) + end, + options = { + -- Only Lake 3.0+ supports lake serve, so for old enough Lean 4, + -- or core Lean itself, this command (typically using the in-built + -- Lean 4 language server) will be used instead. + no_lake_lsp_cmd = { 'lean', '--server' }, + }, + on_new_config = function(config, root_dir) + local use_lake_serve = false + if util.path.exists(util.path.join(root_dir, 'lakefile.lean')) then + local lake_version = '' + local lake_job = vim.fn.jobstart({ 'lake', '--version' }, { + on_stdout = function(_, d, _) + lake_version = table.concat(d, '\n') + end, + stdout_buffered = true, + }) + if lake_job > 0 and vim.fn.jobwait({ lake_job })[1] == 0 then + local major = lake_version:match 'Lake version (%d).' + if major and tonumber(major) >= 3 then + use_lake_serve = true + end + end + end + if not use_lake_serve then + config.cmd = config.options.no_lake_lsp_cmd + end + -- add root dir as command-line argument for `ps aux` + table.insert(config.cmd, root_dir) + end, + single_file_support = true, + }, + docs = { + description = [[ +https://github.com/leanprover/lean4 + +Lean installation instructions can be found +[here](https://leanprover-community.github.io/get_started.html#regular-install). + +The Lean 4 language server is built-in with a Lean 4 install +(and can be manually run with, e.g., `lean --server`). + +Note: that if you're using [lean.nvim](https://github.com/Julian/lean.nvim), +that plugin fully handles the setup of the Lean language server, +and you shouldn't set up `leanls` both with it and `lspconfig`. + ]], + default_config = { + root_dir = [[root_pattern("lakefile.lean", "lean-toolchain", "leanpkg.toml", ".git")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/lelwel_ls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/lelwel_ls.lua new file mode 100644 index 0000000..ac8c456 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/lelwel_ls.lua @@ -0,0 +1,21 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'lelwel-ls' }, + filetypes = { 'llw' }, + root_dir = util.find_git_ancestor, + }, + docs = { + description = [[ +https://github.com/0x2a-42/lelwel + +Language server for lelwel grammars. + +You can install `lelwel-ls` via cargo: +```sh +cargo install --features="lsp" lelwel +``` +]], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/lemminx.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/lemminx.lua new file mode 100644 index 0000000..5bcf1cf --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/lemminx.lua @@ -0,0 +1,23 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'lemminx' }, + filetypes = { 'xml', 'xsd', 'xsl', 'xslt', 'svg' }, + root_dir = util.find_git_ancestor, + single_file_support = true, + }, + docs = { + description = [[ +https://github.com/eclipse/lemminx + +The easiest way to install the server is to get a binary at https://download.jboss.org/jbosstools/vscode/stable/lemminx-binary/ and place it in your PATH. + +NOTE to macOS users: Binaries from unidentified developers are blocked by default. If you trust the downloaded binary from jboss.org, run it once, cancel the prompt, then remove the binary from Gatekeeper quarantine with `xattr -d com.apple.quarantine lemminx`. It should now run without being blocked. + +]], + default_config = { + root_dir = [[util.find_git_ancestor]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/ltex.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/ltex.lua new file mode 100644 index 0000000..0aeb387 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/ltex.lua @@ -0,0 +1,47 @@ +local util = require 'lspconfig.util' + +local language_id_mapping = { + bib = 'bibtex', + plaintex = 'tex', + rnoweb = 'sweave', + rst = 'restructuredtext', + tex = 'latex', + xhtml = 'xhtml', +} + +local bin_name = 'ltex-ls' +if vim.fn.has 'win32' == 1 then + bin_name = bin_name .. '.bat' +end + +return { + default_config = { + cmd = { bin_name }, + filetypes = { 'bib', 'gitcommit', 'markdown', 'org', 'plaintex', 'rst', 'rnoweb', 'tex' }, + root_dir = util.find_git_ancestor, + single_file_support = true, + get_language_id = function(_, filetype) + local language_id = language_id_mapping[filetype] + if language_id then + return language_id + else + return filetype + end + end, + }, + docs = { + description = [=[ +https://github.com/valentjn/ltex-ls + +LTeX Language Server: LSP language server for LanguageTool 🔍✔️ with support for LaTeX 🎓, Markdown 📝, and others + +To install, download the latest [release](https://github.com/valentjn/ltex-ls/releases) and ensure `ltex-ls` is on your path. + +To support org files or R sweave, users can define a custom filetype autocommand (or use a plugin which defines these filetypes): + +```lua +vim.cmd [[ autocmd BufRead,BufNewFile *.org set filetype=org ]] +``` +]=], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/metals.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/metals.lua new file mode 100644 index 0000000..b05db5c --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/metals.lua @@ -0,0 +1,45 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'metals' }, + filetypes = { 'scala' }, + root_dir = util.root_pattern('build.sbt', 'build.sc', 'build.gradle', 'pom.xml'), + message_level = vim.lsp.protocol.MessageType.Log, + init_options = { + statusBarProvider = 'show-message', + isHttpEnabled = true, + compilerOptions = { + snippetAutoIndent = false, + }, + }, + }, + docs = { + description = [[ +https://scalameta.org/metals/ + +Scala language server with rich IDE features. + +See full instructions in the Metals documentation: + +https://scalameta.org/metals/docs/editors/vim.html#using-an-alternative-lsp-client + +Note: that if you're using [nvim-metals](https://github.com/scalameta/nvim-metals), that plugin fully handles the setup and installation of Metals, and you shouldn't set up Metals both with it and `lspconfig`. + +To install Metals, make sure to have [coursier](https://get-coursier.io/docs/cli-installation) installed, and once you do you can install the latest Metals with `cs install metals`. You can also manually bootstrap Metals with the following command. + +```bash +cs bootstrap \ + --java-opt -Xss4m \ + --java-opt -Xms100m \ + org.scalameta:metals_2.12: \ + -r bintray:scalacenter/releases \ + -r sonatype:snapshots \ + -o /usr/local/bin/metals -f +``` +]], + default_config = { + root_dir = [[util.root_pattern("build.sbt", "build.sc", "build.gradle", "pom.xml")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/mint.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/mint.lua new file mode 100644 index 0000000..7fde1c4 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/mint.lua @@ -0,0 +1,20 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'mint', 'ls' }, + filetypes = { 'mint' }, + root_dir = function(fname) + return util.root_pattern 'mint.json'(fname) or util.find_git_ancestor(fname) + end, + single_file_support = true, + }, + docs = { + description = [[ +https://www.mint-lang.com + +Install Mint using the [instructions](https://www.mint-lang.com/install). +The language server is included since version 0.12.0. +]], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/mm0_ls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/mm0_ls.lua new file mode 100644 index 0000000..513bbeb --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/mm0_ls.lua @@ -0,0 +1,20 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'mm0-rs', 'server' }, + root_dir = util.find_git_ancestor, + filetypes = { 'metamath-zero' }, + single_file_support = true, + }, + docs = { + description = [[ +https://github.com/digama0/mm0 + +Language Server for the metamath-zero theorem prover. + +Requires [mm0-rs](https://github.com/digama0/mm0/tree/master/mm0-rs) to be installed +and available on the `PATH`. + ]], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/nickel_ls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/nickel_ls.lua new file mode 100644 index 0000000..3a9387e --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/nickel_ls.lua @@ -0,0 +1,37 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'nls' }, + filetypes = { 'ncl', 'nickel' }, + root_dir = util.find_git_ancestor, + }, + + docs = { + description = [[ +Nickel Language Server + +https://github.com/tweag/nickel + +`nls` can be installed with nix, or cargo, from the Nickel repository. +```sh +git clone https://github.com/tweag/nickel.git +``` + +Nix: +```sh +cd nickel +nix-env -f . -i +``` + +cargo: +```sh +cd nickel/lsp/nls +cargo install --path . +``` + +In order to have lspconfig detect Nickel filetypes (a prequisite for autostarting a server), +install the [Nickel vim plugin](https://github.com/nickel-lang/vim-nickel). + ]], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/nimls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/nimls.lua new file mode 100644 index 0000000..f10b002 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/nimls.lua @@ -0,0 +1,21 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'nimlsp' }, + filetypes = { 'nim' }, + root_dir = function(fname) + return util.root_pattern '*.nimble'(fname) or util.find_git_ancestor(fname) + end, + single_file_support = true, + }, + docs = { + description = [[ +https://github.com/PMunch/nimlsp +`nimlsp` can be installed via the `nimble` package manager: +```sh +nimble install nimlsp +``` + ]], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/ocamlls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/ocamlls.lua new file mode 100644 index 0000000..fcc25db --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/ocamlls.lua @@ -0,0 +1,28 @@ +local util = require 'lspconfig.util' + +local bin_name = 'ocaml-language-server' +local cmd = { bin_name, '--stdio' } + +if vim.fn.has 'win32' == 1 then + cmd = { 'cmd.exe', '/C', bin_name, '--stdio' } +end +return { + default_config = { + cmd = cmd, + filetypes = { 'ocaml', 'reason' }, + root_dir = util.root_pattern('*.opam', 'esy.json', 'package.json'), + }, + docs = { + description = [[ +https://github.com/ocaml-lsp/ocaml-language-server + +`ocaml-language-server` can be installed via `npm` +```sh +npm install -g ocaml-language-server +``` + ]], + default_config = { + root_dir = [[root_pattern("*.opam", "esy.json", "package.json")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/ocamllsp.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/ocamllsp.lua new file mode 100644 index 0000000..1528471 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/ocamllsp.lua @@ -0,0 +1,38 @@ +local util = require 'lspconfig.util' + +local language_id_of = { + menhir = 'ocaml.menhir', + ocaml = 'ocaml', + ocamlinterface = 'ocaml.interface', + ocamllex = 'ocaml.ocamllex', + reason = 'reason', +} + +local get_language_id = function(_, ftype) + return language_id_of[ftype] +end + +return { + default_config = { + cmd = { 'ocamllsp' }, + filetypes = { 'ocaml', 'ocaml.menhir', 'ocaml.interface', 'ocaml.ocamllex', 'reason' }, + root_dir = util.root_pattern('*.opam', 'esy.json', 'package.json', '.git'), + get_language_id = get_language_id, + }, + docs = { + description = [[ +https://github.com/ocaml/ocaml-lsp + +`ocaml-lsp` can be installed as described in [installation guide](https://github.com/ocaml/ocaml-lsp#installation). + +To install the lsp server in a particular opam switch: +```sh +opam pin add ocaml-lsp-server https://github.com/ocaml/ocaml-lsp.git +opam install ocaml-lsp-server +``` + ]], + default_config = { + root_dir = [[root_pattern("*.opam", "esy.json", "package.json", ".git")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/ols.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/ols.lua new file mode 100644 index 0000000..65dd085 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/ols.lua @@ -0,0 +1,20 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'ols' }, + filetypes = { 'odin' }, + root_dir = util.root_pattern('ols.json', '.git'), + single_file_support = true, + }, + docs = { + description = [[ + https://github.com/DanielGavin/ols + + `Odin Language Server`. + ]], + default_config = { + root_dir = [[util.root_pattern("ols.json", ".git")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/omnisharp.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/omnisharp.lua new file mode 100644 index 0000000..b51d898 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/omnisharp.lua @@ -0,0 +1,52 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + filetypes = { 'cs', 'vb' }, + root_dir = function(fname) + return util.root_pattern '*.sln'(fname) or util.root_pattern '*.csproj'(fname) + end, + on_new_config = function(new_config, new_root_dir) + if new_root_dir then + table.insert(new_config.cmd, '-s') + table.insert(new_config.cmd, new_root_dir) + end + end, + init_options = {}, + }, + -- on_new_config = function(new_config) end; + -- on_attach = function(client, bufnr) end; + docs = { + description = [[ +https://github.com/omnisharp/omnisharp-roslyn +OmniSharp server based on Roslyn workspaces + +`omnisharp-roslyn` can be installed by downloading and extracting a release from [here](https://github.com/OmniSharp/omnisharp-roslyn/releases). +Omnisharp can also be built from source by following the instructions [here](https://github.com/omnisharp/omnisharp-roslyn#downloading-omnisharp). + +Omnisharp requires the [dotnet-sdk](https://dotnet.microsoft.com/download) to be installed. + +**By default, omnisharp-roslyn doesn't have a `cmd` set.** This is because nvim-lspconfig does not make assumptions about your path. You must add the following to your init.vim or init.lua to set `cmd` to the absolute path ($HOME and ~ are not expanded) of the unzipped run script or binary. + +```lua +local pid = vim.fn.getpid() +-- On linux/darwin if using a release build, otherwise under scripts/OmniSharp(.Core)(.cmd) +local omnisharp_bin = "/path/to/omnisharp-repo/run" +-- on Windows +-- local omnisharp_bin = "/path/to/omnisharp/OmniSharp.exe" +require'lspconfig'.omnisharp.setup{ + cmd = { omnisharp_bin, "--languageserver" , "--hostPID", tostring(pid) }; + ... +} +``` + +Note, if you download the executable for darwin you will need to strip the quarantine label to run: +```bash +find /path/to/omnisharp-osx | xargs xattr -r -d com.apple.quarantine +``` +]], + default_config = { + root_dir = [[root_pattern(".sln") or root_pattern(".csproj")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/opencl_ls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/opencl_ls.lua new file mode 100644 index 0000000..dc88d24 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/opencl_ls.lua @@ -0,0 +1,21 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'opencl-language-server' }, + filetypes = { 'opencl' }, + root_dir = util.find_git_ancestor, + }, + docs = { + description = [[ +https://github.com/Galarius/opencl-language-server + +Build instructions can be found [here](https://github.com/Galarius/opencl-language-server/blob/main/_dev/build.md). + +Prebuilt binaries are available for Linux, macOS and Windows [here](https://github.com/Galarius/opencl-language-server/releases). +]], + default_config = { + root_dir = [[util.root_pattern(".git")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/openscad_ls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/openscad_ls.lua new file mode 100644 index 0000000..e5ca9ca --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/openscad_ls.lua @@ -0,0 +1,32 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'openscad-language-server' }, + filetypes = { 'openscad' }, + root_dir = util.find_git_ancestor, + single_file_support = true, + }, + docs = { + description = [=[ +https://github.com/dzhu/openscad-language-server + +A Language Server Protocol server for OpenSCAD + +You can build and install `openscad-language-server` binary with `cargo`: +```sh +cargo install openscad-language-server +``` + +Vim does not have built-in syntax for the `openscad` filetype currently. + +This can be added via an autocmd: + +```lua +vim.cmd [[ autocmd BufRead,BufNewFile *.scad set filetype=openscad ]] +``` + +or by installing a filetype plugin such as https://github.com/sirtaj/vim-openscad +]=], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/pasls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/pasls.lua new file mode 100644 index 0000000..5758c82 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/pasls.lua @@ -0,0 +1,28 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'pasls' }, + filetypes = { 'pascal' }, + root_dir = util.find_git_ancestor, + single_file_support = true, + }, + docs = { + description = [[ +https://github.com/genericptr/pascal-language-server + +An LSP server implementation for Pascal variants that are supported by Free Pascal, including Object Pascal. It uses CodeTools from Lazarus as backend. + +First set `cmd` to the Pascal lsp binary. + +Customization options are passed to pasls as environment variables for example in your `.bashrc`: +```bash +export FPCDIR='/usr/lib/fpc/src' # FPC source directory (This is the only required option for the server to work). +export PP='/usr/lib/fpc/3.2.2/ppcx64' # Path to the Free Pascal compiler executable. +export LAZARUSDIR='/usr/lib/lazarus' # Path to the Lazarus sources. +export FPCTARGET='' # Target operating system for cross compiling. +export FPCTARGETCPU='x86_64' # Target CPU for cross compiling. +``` +]], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/perlls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/perlls.lua new file mode 100644 index 0000000..5d241a5 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/perlls.lua @@ -0,0 +1,39 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { + 'perl', + '-MPerl::LanguageServer', + '-e', + 'Perl::LanguageServer::run', + '--', + '--port 13603', + '--nostdio 0', + '--version 2.1.0', + }, + settings = { + perl = { + perlCmd = 'perl', + perlInc = ' ', + fileFilter = { '.pm', '.pl' }, + ignoreDirs = '.git', + }, + }, + filetypes = { 'perl' }, + root_dir = util.find_git_ancestor, + single_file_support = true, + }, + docs = { + description = [[ +https://github.com/richterger/Perl-LanguageServer/tree/master/clients/vscode/perl + +`Perl-LanguageServer`, a language server for Perl. + +To use the language server, ensure that you have Perl::LanguageServer installed and perl command is on your path. +]], + default_config = { + root_dir = "vim's starting directory", + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/perlnavigator.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/perlnavigator.lua new file mode 100644 index 0000000..7ba3895 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/perlnavigator.lua @@ -0,0 +1,39 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = {}, + filetypes = { 'perl' }, + root_dir = util.find_git_ancestor, + single_file_support = true, + }, + docs = { + description = [[ +https://github.com/bscan/PerlNavigator + +A Perl language server + +**By default, perlnavigator doesn't have a `cmd` set.** This is because nvim-lspconfig does not make assumptions about your path. +You have to install the language server manually. + +Clone the PerlNavigator repo, install based on the [instructions](https://github.com/bscan/PerlNavigator#installation-for-other-editors), +and point `cmd` to `server.js` inside the `server/out` directory: + +```lua +cmd = {'node', '/server/out/server.js', '--stdio'} +``` + +At minimum, you will need `perl` in your path. If you want to use a non-standard `perl` you will need to set your configuration like so: +```lua +settings = { + perlnavigator = { + perlPath = '/some/odd/location/my-perl' + } +} +``` + +The `contributes.configuration.properties` section of `perlnavigator`'s `package.json` has all available configuration settings. All +settings have a reasonable default, but, at minimum, you may want to point `perlnavigator` at your `perltidy` and `perlcritic` configurations. +]], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/perlpls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/perlpls.lua new file mode 100644 index 0000000..3326028 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/perlpls.lua @@ -0,0 +1,29 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'pls' }, + settings = { + perl = { + perlcritic = { enabled = false }, + syntax = { enabled = true }, + }, + }, + filetypes = { 'perl' }, + root_dir = util.find_git_ancestor, + single_file_support = true, + }, + docs = { + description = [[ +https://github.com/FractalBoy/perl-language-server +https://metacpan.org/pod/PLS + +`PLS`, another language server for Perl. + +To use the language server, ensure that you have PLS installed and that it is in your path +]], + default_config = { + root_dir = [[util.find_git_ancestor]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/phpactor.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/phpactor.lua new file mode 100644 index 0000000..5a1f0d1 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/phpactor.lua @@ -0,0 +1,26 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'phpactor', 'language-server' }, + filetypes = { 'php' }, + root_dir = function(pattern) + local cwd = vim.loop.cwd() + local root = util.root_pattern('composer.json', '.git')(pattern) + + -- prefer cwd if root is a descendant + return util.path.is_descendant(cwd, root) and cwd or root + end, + }, + docs = { + description = [[ +https://github.com/phpactor/phpactor + +Installation: https://phpactor.readthedocs.io/en/master/usage/standalone.html#global-installation +]], + default_config = { + cmd = { 'phpactor', 'language-server' }, + root_dir = [[root_pattern("composer.json", ".git")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/please.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/please.lua new file mode 100644 index 0000000..085d1e7 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/please.lua @@ -0,0 +1,19 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'plz', 'tool', 'lps' }, + filetypes = { 'bzl' }, + root_dir = util.root_pattern '.plzconfig', + single_file_support = true, + }, + docs = { + description = [[ +https://github.com/thought-machine/please + +High-performance extensible build system for reproducible multi-language builds. + +The `plz` binary will automatically install the LSP for you on first run +]], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/powershell_es.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/powershell_es.lua new file mode 100644 index 0000000..ac723f4 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/powershell_es.lua @@ -0,0 +1,72 @@ +local util = require 'lspconfig.util' + +local temp_path = vim.fn.stdpath 'cache' + +local function make_cmd(new_config) + if new_config.bundle_path ~= nil then + local command_fmt = + [[%s/PowerShellEditorServices/Start-EditorServices.ps1 -BundledModulesPath %s -LogPath %s/powershell_es.log -SessionDetailsPath %s/powershell_es.session.json -FeatureFlags @() -AdditionalModules @() -HostName nvim -HostProfileId 0 -HostVersion 1.0.0 -Stdio -LogLevel Normal]] + local command = command_fmt:format(new_config.bundle_path, new_config.bundle_path, temp_path, temp_path) + return { new_config.shell, '-NoLogo', '-NoProfile', '-Command', command } + end +end + +return { + default_config = { + shell = 'pwsh', + on_new_config = function(new_config, _) + -- Don't overwrite cmd if already set + if not new_config.cmd then + new_config.cmd = make_cmd(new_config) + end + end, + + filetypes = { 'ps1' }, + root_dir = util.find_git_ancestor, + single_file_support = true, + }, + docs = { + description = [[ +https://github.com/PowerShell/PowerShellEditorServices + +Language server for PowerShell. + +To install, download and extract PowerShellEditorServices.zip +from the [releases](https://github.com/PowerShell/PowerShellEditorServices/releases). +To configure the language server, set the property `bundle_path` to the root +of the extracted PowerShellEditorServices.zip. + +The default configuration doesn't set `cmd` unless `bundle_path` is specified. + +```lua +require'lspconfig'.powershell_es.setup{ + bundle_path = 'c:/w/PowerShellEditorServices', +} +``` + +By default the languageserver is started in `pwsh` (PowerShell Core). This can be changed by specifying `shell`. + +```lua +require'lspconfig'.powershell_es.setup{ + bundle_path = 'c:/w/PowerShellEditorServices', + shell = 'powershell.exe', +} +``` + +Note that the execution policy needs to be set to `Unrestricted` for the languageserver run under PowerShell + +If necessary, specific `cmd` can be defined instead of `bundle_path`. +See [PowerShellEditorServices](https://github.com/PowerShell/PowerShellEditorServices#stdio) +to learn more. + +```lua +require'lspconfig'.powershell_es.setup{ + cmd = {'pwsh', '-NoLogo', '-NoProfile', '-Command', "c:/PSES/Start-EditorServices.ps1 ..."} +} +``` +]], + default_config = { + root_dir = 'git root or current directory', + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/prismals.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/prismals.lua new file mode 100644 index 0000000..f330e25 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/prismals.lua @@ -0,0 +1,34 @@ +local util = require 'lspconfig.util' + +local bin_name = 'prisma-language-server' +local cmd = { bin_name, '--stdio' } + +if vim.fn.has 'win32' == 1 then + cmd = { 'cmd.exe', '/C', bin_name, '--stdio' } +end + +return { + default_config = { + cmd = cmd, + filetypes = { 'prisma' }, + settings = { + prisma = { + prismaFmtBinPath = '', + }, + }, + root_dir = util.root_pattern('.git', 'package.json'), + }, + docs = { + description = [[ +Language Server for the Prisma JavaScript and TypeScript ORM + +`@prisma/language-server` can be installed via npm +```sh +npm install -g @prisma/language-server +``` +]], + default_config = { + root_dir = [[root_pattern(".git", "package.json")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/prosemd_lsp.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/prosemd_lsp.lua new file mode 100644 index 0000000..048e4b4 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/prosemd_lsp.lua @@ -0,0 +1,22 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'prosemd-lsp', '--stdio' }, + filetypes = { 'markdown' }, + root_dir = util.find_git_ancestor, + single_file_support = true, + }, + docs = { + description = [[ +https://github.com/kitten/prosemd-lsp + +An experimental LSP for Markdown. + +Please see the manual installation instructions: https://github.com/kitten/prosemd-lsp#manual-installation +]], + default_config = { + root_dir = util.find_git_ancestor, + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/psalm.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/psalm.lua new file mode 100644 index 0000000..01f7581 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/psalm.lua @@ -0,0 +1,29 @@ +local util = require 'lspconfig.util' + +local bin_name = 'psalm-language-server' + +if vim.fn.has 'win32' == 1 then + bin_name = bin_name .. '.bat' +end + +return { + default_config = { + cmd = { bin_name }, + filetypes = { 'php' }, + root_dir = util.root_pattern('psalm.xml', 'psalm.xml.dist'), + }, + docs = { + description = [[ +https://github.com/vimeo/psalm + +Can be installed with composer. +```sh +composer global require vimeo/psalm +``` +]], + default_config = { + cmd = { 'psalm-language-server' }, + root_dir = [[root_pattern("psalm.xml", "psalm.xml.dist")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/puppet.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/puppet.lua new file mode 100644 index 0000000..18a1532 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/puppet.lua @@ -0,0 +1,38 @@ +local util = require 'lspconfig.util' + +local root_files = { + 'manifests', + '.puppet-lint.rc', + 'hiera.yaml', + '.git', +} + +return { + default_config = { + cmd = { 'puppet-languageserver', '--stdio' }, + filetypes = { 'puppet' }, + root_dir = util.root_pattern(unpack(root_files)), + single_file_support = true, + }, + docs = { + description = [[ +LSP server for Puppet. + +Installation: + +- Clone the editor-services repository: + https://github.com/puppetlabs/puppet-editor-services + +- Navigate into that directory and run: `bundle install` + +- Install the 'puppet-lint' gem: `gem install puppet-lint` + +- Add that repository to $PATH. + +- Ensure you can run `puppet-languageserver` from outside the editor-services directory. +]], + default_config = { + root_dir = [[root_pattern("manifests", ".puppet-lint.rc", "hiera.yaml", ".git")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/purescriptls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/purescriptls.lua new file mode 100644 index 0000000..495133d --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/purescriptls.lua @@ -0,0 +1,28 @@ +local util = require 'lspconfig.util' + +local bin_name = 'purescript-language-server' +local cmd = { bin_name, '--stdio' } + +if vim.fn.has 'win32' == 1 then + cmd = { 'cmd.exe', '/C', bin_name, '--stdio' } +end + +return { + default_config = { + cmd = cmd, + filetypes = { 'purescript' }, + root_dir = util.root_pattern('bower.json', 'psc-package.json', 'spago.dhall'), + }, + docs = { + description = [[ +https://github.com/nwolverson/purescript-language-server +`purescript-language-server` can be installed via `npm` +```sh +npm install -g purescript-language-server +``` +]], + default_config = { + root_dir = [[root_pattern("spago.dhall, 'psc-package.json', bower.json")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/pylsp.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/pylsp.lua new file mode 100644 index 0000000..7284fac --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/pylsp.lua @@ -0,0 +1,31 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'pylsp' }, + filetypes = { 'python' }, + root_dir = function(fname) + local root_files = { + 'pyproject.toml', + 'setup.py', + 'setup.cfg', + 'requirements.txt', + 'Pipfile', + } + return util.root_pattern(unpack(root_files))(fname) or util.find_git_ancestor(fname) + end, + single_file_support = true, + }, + docs = { + description = [[ +https://github.com/python-lsp/python-lsp-server + +A Python 3.6+ implementation of the Language Server Protocol. + +The language server can be installed via `pipx install 'python-lsp-server[all]'`. +Further instructions can be found in the [project's README](https://github.com/python-lsp/python-lsp-server). + +Note: This is a community fork of `pyls`. + ]], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/pyre.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/pyre.lua new file mode 100644 index 0000000..5c2f8fb --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/pyre.lua @@ -0,0 +1,22 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'pyre', 'persistent' }, + filetypes = { 'python' }, + root_dir = util.root_pattern '.pyre_configuration', + }, + docs = { + description = [[ +https://pyre-check.org/ + +`pyre` a static type checker for Python 3. + +`pyre` offers an extremely limited featureset. It currently only supports diagnostics, +which are triggered on save. + +Do not report issues for missing features in `pyre` to `lspconfig`. + +]], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/pyright.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/pyright.lua new file mode 100644 index 0000000..a198477 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/pyright.lua @@ -0,0 +1,56 @@ +local util = require 'lspconfig.util' + +local bin_name = 'pyright-langserver' +local cmd = { bin_name, '--stdio' } + +if vim.fn.has 'win32' == 1 then + cmd = { 'cmd.exe', '/C', bin_name, '--stdio' } +end + +local root_files = { + 'pyproject.toml', + 'setup.py', + 'setup.cfg', + 'requirements.txt', + 'Pipfile', + 'pyrightconfig.json', +} + +local function organize_imports() + local params = { + command = 'pyright.organizeimports', + arguments = { vim.uri_from_bufnr(0) }, + } + vim.lsp.buf.execute_command(params) +end + +return { + default_config = { + cmd = cmd, + filetypes = { 'python' }, + root_dir = util.root_pattern(unpack(root_files)), + single_file_support = true, + settings = { + python = { + analysis = { + autoSearchPaths = true, + useLibraryCodeForTypes = true, + diagnosticMode = 'workspace', + }, + }, + }, + }, + commands = { + PyrightOrganizeImports = { + organize_imports, + description = 'Organize Imports', + }, + }, + docs = { + description = [[ +https://github.com/microsoft/pyright + +`pyright`, a static type checker and language server for python +]], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/quick_lint_js.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/quick_lint_js.lua new file mode 100644 index 0000000..29daa96 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/quick_lint_js.lua @@ -0,0 +1,19 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'quick-lint-js', '--lsp-server' }, + filetypes = { 'javascript' }, + root_dir = util.root_pattern('package.json', 'jsconfig.json', '.git'), + single_file_support = true, + }, + docs = { + description = [[ +https://quick-lint-js.com/ + +quick-lint-js finds bugs in JavaScript programs. + +See installation [instructions](https://quick-lint-js.com/install/) +]], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/r_language_server.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/r_language_server.lua new file mode 100644 index 0000000..7e1e3f3 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/r_language_server.lua @@ -0,0 +1,28 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'R', '--slave', '-e', 'languageserver::run()' }, + filetypes = { 'r', 'rmd' }, + root_dir = function(fname) + return util.find_git_ancestor(fname) or vim.loop.os_homedir() + end, + log_level = vim.lsp.protocol.MessageType.Warning, + }, + docs = { + description = [[ +[languageserver](https://github.com/REditorSupport/languageserver) is an +implementation of the Microsoft's Language Server Protocol for the R +language. + +It is released on CRAN and can be easily installed by + +```R +install.packages("languageserver") +``` +]], + default_config = { + root_dir = [[root_pattern(".git") or os_homedir]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/racket_langserver.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/racket_langserver.lua new file mode 100644 index 0000000..25bd0ab --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/racket_langserver.lua @@ -0,0 +1,21 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'racket', '--lib', 'racket-langserver' }, + filetypes = { 'racket', 'scheme' }, + root_dir = util.find_git_ancestor, + single_file_support = true, + }, + docs = { + description = [[ +[https://github.com/jeapostrophe/racket-langserver](https://github.com/jeapostrophe/racket-langserver) + +The Racket language server. This project seeks to use +[DrRacket](https://github.com/racket/drracket)'s public API to provide +functionality that mimics DrRacket's code tools as closely as possible. + +Install via `raco`: `raco pkg install racket-langserver` +]], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/reason_ls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/reason_ls.lua new file mode 100644 index 0000000..45e7d0b --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/reason_ls.lua @@ -0,0 +1,23 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'reason-language-server' }, + filetypes = { 'reason' }, + root_dir = util.root_pattern('bsconfig.json', '.git'), + }, + docs = { + description = [[ +Reason language server + +**By default, reason_ls doesn't have a `cmd` set.** This is because nvim-lspconfig does not make assumptions about your path. +You have to install the language server manually. + +You can install reason language server from [reason-language-server](https://github.com/jaredly/reason-language-server) repository. + +```lua +cmd = {''} +``` +]], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/remark_ls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/remark_ls.lua new file mode 100644 index 0000000..4ef3717 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/remark_ls.lua @@ -0,0 +1,50 @@ +local util = require 'lspconfig.util' + +local bin_name = 'remark-language-server' +local cmd = { bin_name, '--stdio' } + +if vim.fn.has 'win32' == 1 then + cmd = { 'cmd.exe', '/C', bin_name, '--stdio' } +end + +return { + default_config = { + cmd = cmd, + filetypes = { 'markdown' }, + root_dir = util.find_git_ancestor, + single_file_support = true, + }, + docs = { + description = [[ +https://github.com/remarkjs/remark-language-server + +`remark-language-server` can be installed via `npm`: +```sh +npm install -g remark-language-server +``` + +`remark-language-server` uses the same +[configuration files](https://github.com/remarkjs/remark/tree/main/packages/remark-cli#example-config-files-json-yaml-js) +as `remark-cli`. + +This uses a plugin based system. Each plugin needs to be installed locally using `npm` or `yarn`. + +For example, given the following `.remarkrc.json`: + +```json +{ + "presets": [ + "remark-preset-lint-recommended" + ] +} +``` + +`remark-preset-lint-recommended` needs to be installed in the local project: + +```sh +npm install remark-preset-lint-recommended +``` + +]], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/rescriptls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/rescriptls.lua new file mode 100644 index 0000000..1c80ada --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/rescriptls.lua @@ -0,0 +1,42 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = {}, + filetypes = { 'rescript' }, + root_dir = util.root_pattern('bsconfig.json', '.git'), + settings = {}, + }, + docs = { + description = [[ +https://github.com/rescript-lang/rescript-vscode + +ReScript language server + +**By default, rescriptls doesn't have a `cmd` set.** This is because nvim-lspconfig does not make assumptions about your path. +You have to install the language server manually. + +You can use the bundled language server inside the [vim-rescript](https://github.com/rescript-lang/vim-rescript) repo. + +Clone the vim-rescript repo and point `cmd` to `server.js` inside `server/out` directory: + +```lua +cmd = {'node', '/server/out/server.js', '--stdio'} + +``` + +If you have vim-rescript installed you can also use that installation. for example if you're using packer.nvim you can set cmd to something like this: + +```lua +cmd = { + 'node', + '/home/username/.local/share/nvim/site/pack/packer/start/vim-rescript/server/out/server.js', + '--stdio' +} +``` + +Another option is to use vscode extension [release](https://github.com/rescript-lang/rescript-vscode/releases). +Take a look at [here](https://github.com/rescript-lang/rescript-vscode#use-with-other-editors) for instructions. +]], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/rls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/rls.lua new file mode 100644 index 0000000..363b81d --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/rls.lua @@ -0,0 +1,42 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'rls' }, + filetypes = { 'rust' }, + root_dir = util.root_pattern 'Cargo.toml', + }, + docs = { + description = [[ +https://github.com/rust-lang/rls + +rls, a language server for Rust + +See https://github.com/rust-lang/rls#setup to setup rls itself. +See https://github.com/rust-lang/rls#configuration for rls-specific settings. +All settings listed on the rls configuration section of the readme +must be set under settings.rust as follows: + +```lua +nvim_lsp.rls.setup { + settings = { + rust = { + unstable_features = true, + build_on_save = false, + all_features = true, + }, + }, +} +``` + +If you want to use rls for a particular build, eg nightly, set cmd as follows: + +```lua +cmd = {"rustup", "run", "nightly", "rls"} +``` + ]], + default_config = { + root_dir = [[root_pattern("Cargo.toml")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/rnix.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/rnix.lua new file mode 100644 index 0000000..aa7f00e --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/rnix.lua @@ -0,0 +1,28 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'rnix-lsp' }, + filetypes = { 'nix' }, + root_dir = function(fname) + return util.find_git_ancestor(fname) or vim.loop.os_homedir() + end, + settings = {}, + init_options = {}, + }, + docs = { + description = [[ +https://github.com/nix-community/rnix-lsp + +A language server for Nix providing basic completion and formatting via nixpkgs-fmt. + +To install manually, run `cargo install rnix-lsp`. If you are using nix, rnix-lsp is in nixpkgs. + +This server accepts configuration via the `settings` key. + + ]], + default_config = { + root_dir = "vim's starting directory", + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/robotframework_ls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/robotframework_ls.lua new file mode 100644 index 0000000..7cb772b --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/robotframework_ls.lua @@ -0,0 +1,21 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'robotframework_ls' }, + filetypes = { 'robot' }, + root_dir = function(fname) + return util.root_pattern('robotidy.toml', 'pyproject.toml')(fname) or util.find_git_ancestor(fname) + end, + }, + docs = { + description = [[ +https://github.com/robocorp/robotframework-lsp + +Language Server Protocol implementation for Robot Framework. +]], + default_config = { + root_dir = "util.root_pattern('robotidy.toml', 'pyproject.toml')(fname) or util.find_git_ancestor(fname)", + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/rome.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/rome.lua new file mode 100644 index 0000000..075d31a --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/rome.lua @@ -0,0 +1,42 @@ +local util = require 'lspconfig.util' + +local bin_name = 'rome' +local cmd = { bin_name, 'lsp' } + +if vim.fn.has 'win32' == 1 then + cmd = { 'cmd.exe', '/C', bin_name, 'lsp' } +end + +return { + default_config = { + cmd = cmd, + filetypes = { + 'javascript', + 'javascriptreact', + 'json', + 'typescript', + 'typescript.tsx', + 'typescriptreact', + }, + root_dir = function(fname) + return util.find_package_json_ancestor(fname) + or util.find_node_modules_ancestor(fname) + or util.find_git_ancestor(fname) + end, + single_file_support = true, + }, + docs = { + description = [[ +https://rome.tools + +Language server for the Rome Frontend Toolchain. + +```sh +npm install [-g] rome +``` +]], + default_config = { + root_dir = [[root_pattern('package.json', 'node_modules', '.git')]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/rust_analyzer.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/rust_analyzer.lua new file mode 100644 index 0000000..6331cf5 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/rust_analyzer.lua @@ -0,0 +1,79 @@ +local util = require 'lspconfig.util' + +local function reload_workspace(bufnr) + bufnr = util.validate_bufnr(bufnr) + vim.lsp.buf_request(bufnr, 'rust-analyzer/reloadWorkspace', nil, function(err) + if err then + error(tostring(err)) + end + vim.notify 'Cargo workspace reloaded' + end) +end + +return { + default_config = { + cmd = { 'rust-analyzer' }, + filetypes = { 'rust' }, + root_dir = function(fname) + local cargo_crate_dir = util.root_pattern 'Cargo.toml'(fname) + local cmd = { 'cargo', 'metadata', '--no-deps', '--format-version', '1' } + if cargo_crate_dir ~= nil then + cmd[#cmd + 1] = '--manifest-path' + cmd[#cmd + 1] = util.path.join(cargo_crate_dir, 'Cargo.toml') + end + local cargo_metadata = '' + local cargo_metadata_err = '' + local cm = vim.fn.jobstart(cmd, { + on_stdout = function(_, d, _) + cargo_metadata = table.concat(d, '\n') + end, + on_stderr = function(_, d, _) + cargo_metadata_err = table.concat(d, '\n') + end, + stdout_buffered = true, + stderr_buffered = true, + }) + if cm > 0 then + cm = vim.fn.jobwait({ cm })[1] + else + cm = -1 + end + local cargo_workspace_dir = nil + if cm == 0 then + cargo_workspace_dir = vim.fn.json_decode(cargo_metadata)['workspace_root'] + else + vim.notify( + string.format('[lspconfig] cmd (%q) failed:\n%s', table.concat(cmd, ' '), cargo_metadata_err), + vim.log.levels.WARN + ) + end + return cargo_workspace_dir + or cargo_crate_dir + or util.root_pattern 'rust-project.json'(fname) + or util.find_git_ancestor(fname) + end, + settings = { + ['rust-analyzer'] = {}, + }, + }, + commands = { + CargoReload = { + function() + reload_workspace(0) + end, + description = 'Reload current cargo workspace', + }, + }, + docs = { + description = [[ +https://github.com/rust-analyzer/rust-analyzer + +rust-analyzer (aka rls 2.0), a language server for Rust + +See [docs](https://github.com/rust-analyzer/rust-analyzer/tree/master/docs/user#settings) for extra settings. + ]], + default_config = { + root_dir = [[root_pattern("Cargo.toml", "rust-project.json")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/salt_ls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/salt_ls.lua new file mode 100644 index 0000000..65d1d32 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/salt_ls.lua @@ -0,0 +1,24 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'salt_lsp_server' }, + filetypes = { 'sls' }, + root_dir = util.find_git_ancestor, + single_file_support = true, + }, + docs = { + description = [[ +Language server for Salt configuration files. +https://github.com/dcermak/salt-lsp + +The language server can be installed with `pip`: +```sh +pip install salt-lsp +``` + ]], + default_config = { + root_dir = [[root_pattern('.git')]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/scry.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/scry.lua new file mode 100644 index 0000000..8350a43 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/scry.lua @@ -0,0 +1,22 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'scry' }, + filetypes = { 'crystal' }, + root_dir = function(fname) + return util.root_pattern 'shard.yml'(fname) or util.find_git_ancestor(fname) + end, + single_file_support = true, + }, + docs = { + description = [[ +https://github.com/crystal-lang-tools/scry + +Crystal language server. +]], + default_config = { + root_dir = [[root_pattern('shard.yml', '.git')]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/serve_d.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/serve_d.lua new file mode 100644 index 0000000..09d1b10 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/serve_d.lua @@ -0,0 +1,20 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'serve-d' }, + filetypes = { 'd' }, + root_dir = util.root_pattern('dub.json', 'dub.sdl', '.git'), + }, + docs = { + description = [[ + https://github.com/Pure-D/serve-d + + `Microsoft language server protocol implementation for D using workspace-d.` + Download a binary from https://github.com/Pure-D/serve-d/releases and put it in your $PATH. + ]], + default_config = { + root_dir = [[util.root_pattern("dub.json", "dub.sdl", ".git")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/sixtyfps.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/sixtyfps.lua new file mode 100644 index 0000000..da90fe3 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/sixtyfps.lua @@ -0,0 +1,28 @@ +return { + default_config = { + cmd = { 'sixtyfps-lsp' }, + filetypes = { 'sixtyfps' }, + single_file_support = true, + }, + docs = { + description = [=[ +https://github.com/sixtyfpsui/sixtyfps +`SixtyFPS`'s language server + +You can build and install `sixtyfps-lsp` binary with `cargo`: +```sh +cargo install sixtyfps-lsp +``` + +Vim does not have built-in syntax for the `sixtyfps` filetype currently. + +This can be added via an autocmd: + +```lua +vim.cmd [[ autocmd BufRead,BufNewFile *.60 set filetype=sixtyfps ]] +``` + +or by installing a filetype plugin such as https://github.com/RustemB/sixtyfps-vim +]=], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/slint_lsp.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/slint_lsp.lua new file mode 100644 index 0000000..e921cb6 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/slint_lsp.lua @@ -0,0 +1,26 @@ +return { + default_config = { + cmd = { 'slint-lsp' }, + filetypes = { 'slint' }, + single_file_support = true, + }, + docs = { + description = [=[ +https://github.com/slint-ui/slint +`Slint`'s language server + +You can build and install `slint-lsp` binary with `cargo`: +```sh +cargo install slint-lsp +``` + +Vim does not have built-in syntax for the `slint` filetype at this time. + +This can be added via an autocmd: + +```lua +vim.cmd [[ autocmd BufRead,BufNewFile *.slint set filetype=slint ]] +``` +]=], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/solang.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/solang.lua new file mode 100644 index 0000000..be1d1ec --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/solang.lua @@ -0,0 +1,27 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'solang', '--language-server', '--target', 'ewasm' }, + filetypes = { 'solidity' }, + root_dir = util.find_git_ancestor, + }, + docs = { + description = [[ +A language server for Solidity + +See the [documentation](https://solang.readthedocs.io/en/latest/installing.html) for installation instructions. + +The language server only provides the following capabilities: +* Syntax highlighting +* Diagnostics +* Hover + +There is currently no support for completion, goto definition, references, or other functionality. + +]], + default_config = { + root_dir = [[util.find_git_ancestor]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/solargraph.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/solargraph.lua new file mode 100644 index 0000000..4fba400 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/solargraph.lua @@ -0,0 +1,38 @@ +local util = require 'lspconfig.util' + +local bin_name = 'solargraph' +local cmd = { bin_name, 'stdio' } + +if vim.fn.has 'win32' == 1 then + cmd = { 'cmd.exe', '/C', bin_name, 'stdio' } +end + +return { + default_config = { + cmd = cmd, + settings = { + solargraph = { + diagnostics = true, + }, + }, + init_options = { formatting = true }, + filetypes = { 'ruby' }, + root_dir = util.root_pattern('Gemfile', '.git'), + }, + docs = { + description = [[ +https://solargraph.org/ + +solargraph, a language server for Ruby + +You can install solargraph via gem install. + +```sh +gem install --user-install solargraph +``` + ]], + default_config = { + root_dir = [[root_pattern("Gemfile", ".git")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/solc.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/solc.lua new file mode 100644 index 0000000..42e44fe --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/solc.lua @@ -0,0 +1,19 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'solc', '--lsp' }, + filetypes = { 'solidity' }, + root_dir = util.root_pattern '.git', + }, + docs = { + description = [[ +https://docs.soliditylang.org/en/latest/installing-solidity.html + +solc is the native language server for the Solidity language. +]], + default_config = { + root_dir = [[root_pattern(".git")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/solidity_ls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/solidity_ls.lua new file mode 100644 index 0000000..4d4c490 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/solidity_ls.lua @@ -0,0 +1,24 @@ +local util = require 'lspconfig.util' + +local bin_name = 'solidity-language-server' +if vim.fn.has 'win32' == 1 then + bin_name = bin_name .. '.cmd' +end + +return { + default_config = { + cmd = { bin_name, '--stdio' }, + filetypes = { 'solidity' }, + root_dir = util.root_pattern('.git', 'package.json'), + }, + docs = { + description = [[ +npm install -g solidity-language-server + +solidity-language-server is a language server for the solidity language ported from the vscode solidity extension +]], + default_config = { + root_dir = [[root_pattern(".git", "package.json")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/sorbet.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/sorbet.lua new file mode 100644 index 0000000..86d3443 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/sorbet.lua @@ -0,0 +1,26 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'srb', 'tc', '--lsp' }, + filetypes = { 'ruby' }, + root_dir = util.root_pattern('Gemfile', '.git'), + }, + docs = { + description = [[ +https://sorbet.org + +Sorbet is a fast, powerful type checker designed for Ruby. + +You can install Sorbet via gem install. You might also be interested in how to set +Sorbet up for new projects: https://sorbet.org/docs/adopting. + +```sh +gem install sorbet +``` + ]], + default_config = { + root_dir = [[root_pattern("Gemfile", ".git")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/sourcekit.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/sourcekit.lua new file mode 100644 index 0000000..d90b30a --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/sourcekit.lua @@ -0,0 +1,19 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'sourcekit-lsp' }, + filetypes = { 'swift', 'c', 'cpp', 'objective-c', 'objective-cpp' }, + root_dir = util.root_pattern('Package.swift', '.git'), + }, + docs = { + description = [[ +https://github.com/apple/sourcekit-lsp + +Language server for Swift and C/C++/Objective-C. + ]], + default_config = { + root_dir = [[root_pattern("Package.swift", ".git")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/sourcery.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/sourcery.lua new file mode 100644 index 0000000..9100c5a --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/sourcery.lua @@ -0,0 +1,55 @@ +local util = require 'lspconfig/util' + +local root_files = { + 'pyproject.toml', + 'setup.py', + 'setup.cfg', + 'requirements.txt', + 'Pipfile', + 'pyrightconfig.json', +} + +return { + default_config = { + cmd = { 'sourcery', 'lsp' }, + filetypes = { 'python' }, + init_options = { + editor_version = 'vim', + extension_version = 'vim.lsp', + token = nil, + }, + root_dir = function(fname) + return util.root_pattern(unpack(root_files))(fname) or util.find_git_ancestor(fname) + end, + single_file_support = true, + }, + on_new_config = function(new_config, _) + if not new_config.init_options.token then + local notify = vim.notify_once or vim.notify + notify('[lspconfig] The authentication token must be provided in config.init_options', vim.log.levels.ERROR) + end + end, + docs = { + description = [[ +https://github.com/sourcery-ai/sourcery + +Refactor Python instantly using the power of AI. + +It requires the initializationOptions param to be populated as shown below and will respond with the list of ServerCapabilities that it supports. + +init_options = { + --- The Sourcery token for authenticating the user. + --- This is retrieved from the Sourcery website and must be + --- provided by each user. The extension must provide a + --- configuration option for the user to provide this value. + token = + + --- The extension's name and version as defined by the extension. + extension_version = 'vim.lsp' + + --- The editor's name and version as defined by the editor. + editor_version = 'vim' +} +]], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/spectral.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/spectral.lua new file mode 100644 index 0000000..e21b6cb --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/spectral.lua @@ -0,0 +1,29 @@ +local util = require 'lspconfig.util' + +local bin_name = 'spectral-language-server' + +return { + default_config = { + cmd = { bin_name, '--stdio' }, + filetypes = { 'yaml', 'json', 'yml' }, + root_dir = util.root_pattern('.spectral.yaml', '.spectral.yml', '.spectral.json', '.spectral.js'), + single_file_support = true, + settings = { + enable = true, + run = 'onType', + validateLanguages = { 'yaml', 'json', 'yml' }, + }, + }, + docs = { + description = [[ +https://github.com/luizcorreia/spectral-language-server + `A flexible JSON/YAML linter for creating automated style guides, with baked in support for OpenAPI v2 & v3.` + +`spectral-language-server` can be installed via `npm`: +```sh +npm i -g spectral-language-server +``` +See [vscode-spectral](https://github.com/stoplightio/vscode-spectral#extension-settings) for configuration options. +]], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/sqlls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/sqlls.lua new file mode 100644 index 0000000..434a7ce --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/sqlls.lua @@ -0,0 +1,18 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'sql-language-server', 'up', '--method', 'stdio' }, + filetypes = { 'sql', 'mysql' }, + root_dir = util.root_pattern '.sqllsrc.json', + settings = {}, + }, + docs = { + description = [[ +https://github.com/joe-re/sql-language-server + +This LSP can be installed via `npm`. Find further instructions on manual installation of the sql-language-server at [joe-re/sql-language-server](https://github.com/joe-re/sql-language-server). +
+ ]], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/sqls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/sqls.lua new file mode 100644 index 0000000..2680253 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/sqls.lua @@ -0,0 +1,25 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'sqls' }, + filetypes = { 'sql', 'mysql' }, + root_dir = util.root_pattern 'config.yml', + single_file_support = true, + settings = {}, + }, + docs = { + description = [[ +https://github.com/lighttiger2505/sqls + +```lua +require'lspconfig'.sqls.setup{ + cmd = {"path/to/command", "-config", "path/to/config.yml"}; + ... +} +``` +Sqls can be installed via `go get github.com/lighttiger2505/sqls`. Instructions for compiling Sqls from the source can be found at [lighttiger2505/sqls](https://github.com/lighttiger2505/sqls). + + ]], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/stylelint_lsp.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/stylelint_lsp.lua new file mode 100644 index 0000000..d471d26 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/stylelint_lsp.lua @@ -0,0 +1,54 @@ +local util = require 'lspconfig.util' + +local bin_name = 'stylelint-lsp' +local cmd = { bin_name, '--stdio' } + +if vim.fn.has 'win32' == 1 then + cmd = { 'cmd.exe', '/C', bin_name, '--stdio' } +end + +return { + default_config = { + cmd = cmd, + filetypes = { + 'css', + 'less', + 'scss', + 'sugarss', + 'vue', + 'wxss', + 'javascript', + 'javascriptreact', + 'typescript', + 'typescriptreact', + }, + root_dir = util.root_pattern('.stylelintrc', 'package.json'), + settings = {}, + }, + docs = { + description = [[ +https://github.com/bmatcuk/stylelint-lsp + +`stylelint-lsp` can be installed via `npm`: + +```sh +npm i -g stylelint-lsp +``` + +Can be configured by passing a `settings.stylelintplus` object to `stylelint_lsp.setup`: + +```lua +require'lspconfig'.stylelint_lsp.setup{ + settings = { + stylelintplus = { + -- see available options in stylelint-lsp documentation + } + } +} +``` +]], + default_config = { + root_dir = [[ root_pattern('.stylelintrc', 'package.json') ]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/sumneko_lua.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/sumneko_lua.lua new file mode 100644 index 0000000..6338095 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/sumneko_lua.lua @@ -0,0 +1,63 @@ +local util = require 'lspconfig.util' + +local root_files = { + '.luarc.json', + '.luacheckrc', + '.stylua.toml', + 'selene.toml', +} +return { + default_config = { + cmd = { 'lua-language-server' }, + filetypes = { 'lua' }, + root_dir = function(fname) + return util.root_pattern(unpack(root_files))(fname) or util.find_git_ancestor(fname) + end, + single_file_support = true, + log_level = vim.lsp.protocol.MessageType.Warning, + settings = { Lua = { telemetry = { enable = false } } }, + }, + docs = { + description = [[ +https://github.com/sumneko/lua-language-server + +Lua language server. + +`lua-language-server` can be installed by following the instructions [here](https://github.com/sumneko/lua-language-server/wiki/Build-and-Run). The default `cmd` assumes that the `lua-language-server` binary can be found in `$PATH`. + +```lua +local runtime_path = vim.split(package.path, ';') +table.insert(runtime_path, "lua/?.lua") +table.insert(runtime_path, "lua/?/init.lua") + +require'lspconfig'.sumneko_lua.setup { + settings = { + Lua = { + runtime = { + -- Tell the language server which version of Lua you're using (most likely LuaJIT in the case of Neovim) + version = 'LuaJIT', + -- Setup your lua path + path = runtime_path, + }, + diagnostics = { + -- Get the language server to recognize the `vim` global + globals = {'vim'}, + }, + workspace = { + -- Make the server aware of Neovim runtime files + library = vim.api.nvim_get_runtime_file("", true), + }, + -- Do not send telemetry data containing a randomized but unique identifier + telemetry = { + enable = false, + }, + }, + }, +} +``` +]], + default_config = { + root_dir = [[root_pattern(".luarc.json", ".luacheckrc", ".stylua.toml", "selene.toml", ".git")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/svelte.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/svelte.lua new file mode 100644 index 0000000..14db192 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/svelte.lua @@ -0,0 +1,29 @@ +local util = require 'lspconfig.util' + +local bin_name = 'svelteserver' +local cmd = { bin_name, '--stdio' } + +if vim.fn.has 'win32' == 1 then + cmd = { 'cmd.exe', '/C', bin_name, '--stdio' } +end + +return { + default_config = { + cmd = cmd, + filetypes = { 'svelte' }, + root_dir = util.root_pattern('package.json', '.git'), + }, + docs = { + description = [[ +https://github.com/sveltejs/language-tools/tree/master/packages/language-server + +`svelte-language-server` can be installed via `npm`: +```sh +npm install -g svelte-language-server +``` +]], + default_config = { + root_dir = [[root_pattern("package.json", ".git")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/svls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/svls.lua new file mode 100644 index 0000000..ff4d810 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/svls.lua @@ -0,0 +1,24 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'svls' }, + filetypes = { 'verilog', 'systemverilog' }, + root_dir = util.find_git_ancestor, + }, + docs = { + description = [[ +https://github.com/dalance/svls + +Language server for verilog and SystemVerilog + +`svls` can be installed via `cargo`: + ```sh + cargo install svls + ``` + ]], + default_config = { + root_dir = [[util.find_git_ancestor]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/tailwindcss.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/tailwindcss.lua new file mode 100644 index 0000000..5a5abc0 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/tailwindcss.lua @@ -0,0 +1,126 @@ +local util = require 'lspconfig.util' + +local bin_name = 'tailwindcss-language-server' +local cmd = { bin_name, '--stdio' } + +if vim.fn.has 'win32' == 1 then + cmd = { 'cmd.exe', '/C', bin_name, '--stdio' } +end + +return { + default_config = { + cmd = cmd, + -- filetypes copied and adjusted from tailwindcss-intellisense + filetypes = { + -- html + 'aspnetcorerazor', + 'astro', + 'astro-markdown', + 'blade', + 'django-html', + 'htmldjango', + 'edge', + 'eelixir', -- vim ft + 'ejs', + 'erb', + 'eruby', -- vim ft + 'gohtml', + 'haml', + 'handlebars', + 'hbs', + 'html', + -- 'HTML (Eex)', + -- 'HTML (EEx)', + 'html-eex', + 'heex', + 'jade', + 'leaf', + 'liquid', + 'markdown', + 'mdx', + 'mustache', + 'njk', + 'nunjucks', + 'php', + 'razor', + 'slim', + 'twig', + -- css + 'css', + 'less', + 'postcss', + 'sass', + 'scss', + 'stylus', + 'sugarss', + -- js + 'javascript', + 'javascriptreact', + 'reason', + 'rescript', + 'typescript', + 'typescriptreact', + -- mixed + 'vue', + 'svelte', + }, + init_options = { + userLanguages = { + eelixir = 'html-eex', + eruby = 'erb', + }, + }, + settings = { + tailwindCSS = { + validate = true, + lint = { + cssConflict = 'warning', + invalidApply = 'error', + invalidScreen = 'error', + invalidVariant = 'error', + invalidConfigPath = 'error', + invalidTailwindDirective = 'error', + recommendedVariantOrder = 'warning', + }, + classAttributes = { + 'class', + 'className', + 'classList', + 'ngClass', + }, + }, + }, + on_new_config = function(new_config) + if not new_config.settings then + new_config.settings = {} + end + if not new_config.settings.editor then + new_config.settings.editor = {} + end + if not new_config.settings.editor.tabSize then + -- set tab size for hover + new_config.settings.editor.tabSize = vim.lsp.util.get_effective_tabstop() + end + end, + root_dir = function(fname) + return util.root_pattern('tailwind.config.js', 'tailwind.config.ts')(fname) + or util.root_pattern('postcss.config.js', 'postcss.config.ts')(fname) + or util.find_package_json_ancestor(fname) + or util.find_node_modules_ancestor(fname) + or util.find_git_ancestor(fname) + end, + }, + docs = { + description = [[ +https://github.com/tailwindlabs/tailwindcss-intellisense + +Tailwind CSS Language Server can be installed via npm: +```sh +npm install -g @tailwindcss/language-server +``` +]], + default_config = { + root_dir = [[root_pattern('tailwind.config.js', 'tailwind.config.ts', 'postcss.config.js', 'postcss.config.ts', 'package.json', 'node_modules', '.git')]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/taplo.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/taplo.lua new file mode 100644 index 0000000..320ced9 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/taplo.lua @@ -0,0 +1,27 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'taplo', 'lsp', 'stdio' }, + filetypes = { 'toml' }, + root_dir = function(fname) + return util.root_pattern '*.toml'(fname) or util.find_git_ancestor(fname) + end, + single_file_support = true, + }, + docs = { + description = [[ +https://taplo.tamasfe.dev/lsp/ + +Language server for Taplo, a TOML toolkit. + +`taplo-cli` can be installed via `cargo`: +```sh +cargo install --locked taplo-cli +``` + ]], + default_config = { + root_dir = [[root_pattern("*.toml", ".git")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/teal_ls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/teal_ls.lua new file mode 100644 index 0000000..b554add --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/teal_ls.lua @@ -0,0 +1,29 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { + 'teal-language-server', + -- use this to enable logging in /tmp/teal-language-server.log + -- "logging=on", + }, + filetypes = { + 'teal', + -- "lua", -- Also works for lua, but you may get type errors that cannot be resolved within lua itself + }, + root_dir = util.root_pattern('tlconfig.lua', '.git'), + }, + docs = { + description = [[ +https://github.com/teal-language/teal-language-server + +Install with: +``` +luarocks install --dev teal-language-server +``` +]], + default_config = { + root_dir = [[root_pattern("tlconfig.lua", ".git")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/terraform_lsp.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/terraform_lsp.lua new file mode 100644 index 0000000..48a6fc5 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/terraform_lsp.lua @@ -0,0 +1,43 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'terraform-lsp' }, + filetypes = { 'terraform', 'hcl' }, + root_dir = util.root_pattern('.terraform', '.git'), + }, + docs = { + description = [[ +https://github.com/juliosueiras/terraform-lsp + +Terraform language server +Download a released binary from +https://github.com/juliosueiras/terraform-lsp/releases. + +From https://github.com/hashicorp/terraform-ls#terraform-ls-vs-terraform-lsp: + +Both HashiCorp and the maintainer of terraform-lsp expressed interest in +collaborating on a language server and are working towards a _long-term_ +goal of a single stable and feature-complete implementation. + +For the time being both projects continue to exist, giving users the +choice: + +- `terraform-ls` providing + - overall stability (by relying only on public APIs) + - compatibility with any provider and any Terraform >=0.12.0 currently + less features + - due to project being younger and relying on public APIs which may + not offer the same functionality yet + +- `terraform-lsp` providing + - currently more features + - compatibility with a single particular Terraform (0.12.20 at time of writing) + - configs designed for other 0.12 versions may work, but interpretation may be inaccurate + - less stability (due to reliance on Terraform's own internal packages) +]], + default_config = { + root_dir = [[root_pattern(".terraform", ".git")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/terraformls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/terraformls.lua new file mode 100644 index 0000000..3eb4a1c --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/terraformls.lua @@ -0,0 +1,42 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'terraform-ls', 'serve' }, + filetypes = { 'terraform' }, + root_dir = util.root_pattern('.terraform', '.git'), + }, + docs = { + description = [[ +https://github.com/hashicorp/terraform-ls + +Terraform language server +Download a released binary from https://github.com/hashicorp/terraform-ls/releases. + +From https://github.com/hashicorp/terraform-ls#terraform-ls-vs-terraform-lsp: + +Both HashiCorp and the maintainer of terraform-lsp expressed interest in +collaborating on a language server and are working towards a _long-term_ +goal of a single stable and feature-complete implementation. + +For the time being both projects continue to exist, giving users the +choice: + +- `terraform-ls` providing + - overall stability (by relying only on public APIs) + - compatibility with any provider and any Terraform >=0.12.0 currently + less features + - due to project being younger and relying on public APIs which may + not offer the same functionality yet + +- `terraform-lsp` providing + - currently more features + - compatibility with a single particular Terraform (0.12.20 at time of writing) + - configs designed for other 0.12 versions may work, but interpretation may be inaccurate + - less stability (due to reliance on Terraform's own internal packages) +]], + default_config = { + root_dir = [[root_pattern(".terraform", ".git")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/texlab.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/texlab.lua new file mode 100644 index 0000000..88bfa20 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/texlab.lua @@ -0,0 +1,126 @@ +local util = require 'lspconfig.util' + +local texlab_build_status = vim.tbl_add_reverse_lookup { + Success = 0, + Error = 1, + Failure = 2, + Cancelled = 3, +} + +local texlab_forward_status = vim.tbl_add_reverse_lookup { + Success = 0, + Error = 1, + Failure = 2, + Unconfigured = 3, +} + +local function buf_build(bufnr) + bufnr = util.validate_bufnr(bufnr) + local texlab_client = util.get_active_client_by_name(bufnr, 'texlab') + local params = { + textDocument = { uri = vim.uri_from_bufnr(bufnr) }, + } + if texlab_client then + texlab_client.request('textDocument/build', params, function(err, result) + if err then + error(tostring(err)) + end + print('Build ' .. texlab_build_status[result.status]) + end, bufnr) + else + print 'method textDocument/build is not supported by any servers active on the current buffer' + end +end + +local function buf_search(bufnr) + bufnr = util.validate_bufnr(bufnr) + local texlab_client = util.get_active_client_by_name(bufnr, 'texlab') + local params = { + textDocument = { uri = vim.uri_from_bufnr(bufnr) }, + position = { line = vim.fn.line '.' - 1, character = vim.fn.col '.' }, + } + if texlab_client then + texlab_client.request('textDocument/forwardSearch', params, function(err, result) + if err then + error(tostring(err)) + end + print('Search ' .. texlab_forward_status[result.status]) + end, bufnr) + else + print 'method textDocument/forwardSearch is not supported by any servers active on the current buffer' + end +end + +-- bufnr isn't actually required here, but we need a valid buffer in order to +-- be able to find the client for buf_request. +-- TODO find a client by looking through buffers for a valid client? +-- local function build_cancel_all(bufnr) +-- bufnr = util.validate_bufnr(bufnr) +-- local params = { token = "texlab-build-*" } +-- lsp.buf_request(bufnr, 'window/progress/cancel', params, function(err, method, result, client_id) +-- if err then error(tostring(err)) end +-- print("Cancel result", vim.inspect(result)) +-- end) +-- end + +return { + default_config = { + cmd = { 'texlab' }, + filetypes = { 'tex', 'bib' }, + root_dir = function(fname) + return util.root_pattern '.latexmkrc'(fname) or util.find_git_ancestor(fname) + end, + single_file_support = true, + settings = { + texlab = { + rootDirectory = nil, + build = { + executable = 'latexmk', + args = { '-pdf', '-interaction=nonstopmode', '-synctex=1', '%f' }, + onSave = false, + forwardSearchAfter = false, + }, + auxDirectory = '.', + forwardSearch = { + executable = nil, + args = {}, + }, + chktex = { + onOpenAndSave = false, + onEdit = false, + }, + diagnosticsDelay = 300, + latexFormatter = 'latexindent', + latexindent = { + ['local'] = nil, -- local is a reserved keyword + modifyLineBreaks = false, + }, + bibtexFormatter = 'texlab', + formatterLineLength = 80, + }, + }, + }, + commands = { + TexlabBuild = { + function() + buf_build(0) + end, + description = 'Build the current buffer', + }, + TexlabForward = { + function() + buf_search(0) + end, + description = 'Forward search from current position', + }, + }, + docs = { + description = [[ +https://github.com/latex-lsp/texlab + +A completion engine built from scratch for (La)TeX. + +See https://github.com/latex-lsp/texlab/blob/master/docs/options.md for configuration options. +]], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/tflint.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/tflint.lua new file mode 100644 index 0000000..de2a1d8 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/tflint.lua @@ -0,0 +1,20 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'tflint', '--langserver' }, + filetypes = { 'terraform' }, + root_dir = util.root_pattern('.terraform', '.git', '.tflint.hcl'), + }, + docs = { + description = [[ +https://github.com/terraform-linters/tflint + +A pluggable Terraform linter that can act as lsp server. +Installation instructions can be found in https://github.com/terraform-linters/tflint#installation. +]], + default_config = { + root_dir = [[root_pattern(".terraform", ".git", ".tflint.hcl")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/theme_check.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/theme_check.lua new file mode 100644 index 0000000..94d6774 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/theme_check.lua @@ -0,0 +1,31 @@ +local util = require 'lspconfig.util' + +local bin_name = 'theme-check-language-server' + +return { + default_config = { + cmd = { bin_name, '--stdio' }, + filetypes = { 'liquid' }, + root_dir = util.root_pattern '.theme-check.yml', + settings = {}, + }, + docs = { + description = [[ +https://github.com/Shopify/shopify-cli + +`theme-check-language-server` is bundled with `shopify-cli` or it can also be installed via + +https://github.com/Shopify/theme-check#installation + +**NOTE:** +If installed via Homebrew, `cmd` must be set to 'theme-check-liquid-server' + +```lua +require lspconfig.theme_check.setup { + cmd = { 'theme-check-liquid-server' } +} +``` + +]], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/tsserver.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/tsserver.lua new file mode 100644 index 0000000..0f916fe --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/tsserver.lua @@ -0,0 +1,60 @@ +local util = require 'lspconfig.util' + +local bin_name = 'typescript-language-server' +local cmd = { bin_name, '--stdio' } + +if vim.fn.has 'win32' == 1 then + cmd = { 'cmd.exe', '/C', bin_name, '--stdio' } +end + +return { + default_config = { + init_options = { hostInfo = 'neovim' }, + cmd = cmd, + filetypes = { + 'javascript', + 'javascriptreact', + 'javascript.jsx', + 'typescript', + 'typescriptreact', + 'typescript.tsx', + }, + root_dir = function(fname) + return util.root_pattern 'tsconfig.json'(fname) + or util.root_pattern('package.json', 'jsconfig.json', '.git')(fname) + end, + }, + docs = { + description = [[ +https://github.com/theia-ide/typescript-language-server + +`typescript-language-server` depends on `typescript`. Both packages can be installed via `npm`: +```sh +npm install -g typescript typescript-language-server +``` + +To configure type language server, add a +[`tsconfig.json`](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html) or +[`jsconfig.json`](https://code.visualstudio.com/docs/languages/jsconfig) to the root of your +project. + +Here's an example that disables type checking in JavaScript files. + +```json +{ + "compilerOptions": { + "module": "commonjs", + "target": "es6", + "checkJs": false + }, + "exclude": [ + "node_modules" + ] +} +``` +]], + default_config = { + root_dir = [[root_pattern("package.json", "tsconfig.json", "jsconfig.json", ".git")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/typeprof.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/typeprof.lua new file mode 100644 index 0000000..ab9dc8e --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/typeprof.lua @@ -0,0 +1,19 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'typeprof', '--lsp', '--stdio' }, + filetypes = { 'ruby', 'eruby' }, + root_dir = util.root_pattern('Gemfile', '.git'), + }, + docs = { + description = [[ +https://github.com/ruby/typeprof + +`typeprof` is the built-in analysis and LSP tool for Ruby 3.1+. + ]], + default_config = { + root_dir = [[root_pattern("Gemfile", ".git")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/vala_ls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/vala_ls.lua new file mode 100644 index 0000000..842c561 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/vala_ls.lua @@ -0,0 +1,40 @@ +local util = require 'lspconfig.util' + +local meson_matcher = function(path) + local pattern = 'meson.build' + local f = vim.fn.glob(util.path.join(path, pattern)) + if f == '' then + return nil + end + for line in io.lines(f) do + -- skip meson comments + if not line:match '^%s*#.*' then + local str = line:gsub('%s+', '') + if str ~= '' then + if str:match '^project%(' then + return path + else + break + end + end + end + end +end + +return { + default_config = { + cmd = { 'vala-language-server' }, + filetypes = { 'vala', 'genie' }, + root_dir = function(fname) + local root = util.search_ancestors(fname, meson_matcher) + return root or util.find_git_ancestor(fname) + end, + single_file_support = true, + }, + docs = { + description = 'https://github.com/Prince781/vala-language-server', + default_config = { + root_dir = [[root_pattern("meson.build", ".git")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/vdmj.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/vdmj.lua new file mode 100644 index 0000000..9699b93 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/vdmj.lua @@ -0,0 +1,128 @@ +local util = require 'lspconfig.util' + +local mavenrepo = util.path.join(vim.env.HOME, '.m2', 'repository', 'com', 'fujitsu') + +local function get_jar_path(config, package, version) + return util.path.join(config.options.mavenrepo, package, version, package .. '-' .. version .. '.jar') +end + +local function with_precision(version, is_high_precision) + return is_high_precision and version:gsub('([%d.]+)', '%1-P') or version +end + +local function get_latest_installed_version(repo) + local path = util.path.join(repo, 'lsp') + local sort = vim.fn.sort + + local subdirs = function(file) + local stat = vim.loop.fs_stat(util.path.join(path, file)) + return stat.type == 'directory' and 1 or 0 + end + + local candidates = vim.fn.readdir(path, subdirs) + local sorted = sort(sort(candidates, 'l'), 'N') + return sorted[#sorted] +end + +-- Special case, as vdmj store particular settings under root_dir/.vscode +local function find_vscode_ancestor(startpath) + return util.search_ancestors(startpath, function(path) + if util.path.is_dir(util.path.join(path, '.vscode')) then + return path + end + end) +end + +return { + default_config = { + cmd = { 'java' }, + filetypes = { 'vdmsl', 'vdmpp', 'vdmrt' }, + root_dir = function(fname) + return util.find_git_ancestor(fname) or find_vscode_ancestor(fname) + end, + options = { + java = vim.env.JAVA_HOME and util.path.join(vim.env.JAVA_HOME, 'bin', 'java') or 'java', + java_opts = { '-Xmx3000m', '-Xss1m' }, + annotation_paths = {}, + mavenrepo = mavenrepo, + version = get_latest_installed_version(mavenrepo), + logfile = util.path.join(vim.fn.stdpath 'cache', 'vdm-lsp.log'), + debugger_port = -1, + high_precision = false, + }, + }, + docs = { + description = [[ +https://github.com/nickbattle/vdmj + +The VDMJ language server can be installed by cloning the VDMJ repository and +running `mvn clean install`. + +Various options are provided to configure the language server (see below). In +particular: +- `annotation_paths` is a list of folders and/or jar file paths for annotations +that should be used with the language server; +- any value of `debugger_port` less than zero will disable the debugger; note +that if a non-zero value is used, only one instance of the server can be active +at a time. + +More settings for VDMJ can be changed in a file called `vdmj.properties` under +`root_dir/.vscode`. For a description of the available settings, see +[Section 7 of the VDMJ User Guide](https://raw.githubusercontent.com/nickbattle/vdmj/master/vdmj/documentation/UserGuide.pdf). + +Note: proof obligations and combinatorial testing are not currently supported +by neovim. +]], + default_config = { + cmd = 'Generated from the options given', + root_dir = 'util.find_git_ancestor(fname) or find_vscode_ancestor(fname)', + options = { + java = '$JAVA_HOME/bin/java', + java_opts = { '-Xmx3000m', '-Xss1m' }, + annotation_paths = {}, + mavenrepo = '$HOME/.m2/repository/com/fujitsu', + version = 'The latest version installed in `mavenrepo`', + logfile = "path.join(vim.fn.stdpath 'cache', 'vdm-lsp.log')", + debugger_port = -1, + high_precision = false, + }, + }, + }, + on_new_config = function(config, root_dir) + local version = with_precision( + config.options.version or get_latest_installed_version(config.options.mavenrepo), + config.options.high_precision + ) + + local classpath = table.concat({ + get_jar_path(config, 'vdmj', version), + get_jar_path(config, 'annotations', version), + get_jar_path(config, 'lsp', version), + util.path.join(root_dir, '.vscode'), + unpack(config.options.annotation_paths), + }, ':') + + local java_cmd = { + config.options.java, + config.options.java_opts, + '-Dlsp.log.filename=' .. config.options.logfile, + '-cp', + classpath, + } + + local dap = {} + + if config.options.debugger_port >= 0 then + -- TODO: LS will fail to start if port is already in use + dap = { '-dap', tostring(config.options.debugger_port) } + end + + local vdmj_cmd = { + 'lsp.LSPServerStdio', + '-' .. vim.bo.filetype, + dap, + } + + config.cmd = vim.tbl_flatten { java_cmd, vdmj_cmd } + end, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/verible.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/verible.lua new file mode 100644 index 0000000..3c4823a --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/verible.lua @@ -0,0 +1,21 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'verible-verilog-ls' }, + filetypes = { 'systemverilog', 'verilog' }, + root_dir = util.find_git_ancestor, + }, + docs = { + description = [[ +https://github.com/chipsalliance/verible + +A linter and formatter for verilog and SystemVerilog files. + +Release binaries can be downloaded from [here](https://github.com/chipsalliance/verible/releases) +and placed in a directory on PATH. + +See https://github.com/chipsalliance/verible/tree/master/verilog/tools/ls/README.md for options. + ]], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/vimls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/vimls.lua new file mode 100644 index 0000000..4f0d1d9 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/vimls.lua @@ -0,0 +1,41 @@ +local util = require 'lspconfig.util' + +local bin_name = 'vim-language-server' +local cmd = { bin_name, '--stdio' } + +if vim.fn.has 'win32' == 1 then + cmd = { 'cmd.exe', '/C', bin_name, '--stdio' } +end + +return { + default_config = { + cmd = cmd, + filetypes = { 'vim' }, + root_dir = function(fname) + return util.find_git_ancestor(fname) or vim.fn.getcwd() + end, + init_options = { + iskeyword = '@,48-57,_,192-255,-#', + vimruntime = '', + runtimepath = '', + diagnostic = { enable = true }, + indexes = { + runtimepath = true, + gap = 100, + count = 3, + projectRootPatterns = { 'runtime', 'nvim', '.git', 'autoload', 'plugin' }, + }, + suggest = { fromVimruntime = true, fromRuntimepath = true }, + }, + }, + docs = { + description = [[ +https://github.com/iamcco/vim-language-server + +You can install vim-language-server via npm: +```sh +npm install -g vim-language-server +``` +]], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/vls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/vls.lua new file mode 100644 index 0000000..36255c0 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/vls.lua @@ -0,0 +1,32 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + filetypes = { 'vlang' }, + root_dir = util.root_pattern('v.mod', '.git'), + }, + docs = { + description = [[ +https://github.com/vlang/vls + +V language server. + +`v-language-server` can be installed by following the instructions [here](https://github.com/vlang/vls#installation). + +**By default, v-language-server doesn't have a `cmd` set.** This is because nvim-lspconfig does not make assumptions about your path. You must add the following to your init.vim or init.lua to set `cmd` to the absolute path ($HOME and ~ are not expanded) of your unzipped and compiled v-language-server. + +```lua +-- set the path to the vls installation; +local vls_root_path = vim.fn.stdpath('cache')..'/lspconfig/vls' +local vls_binary = vls_root_path.."/cmd/vls/vls" + +require'lspconfig'.vls.setup { + cmd = {vls_binary}, +} +``` +]], + default_config = { + root_dir = [[root_pattern("v.mod", ".git")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/volar.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/volar.lua new file mode 100644 index 0000000..7742757 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/volar.lua @@ -0,0 +1,138 @@ +local util = require 'lspconfig.util' + +local function get_typescript_server_path(root_dir) + local project_root = util.find_node_modules_ancestor(root_dir) + return project_root and (util.path.join(project_root, 'node_modules', 'typescript', 'lib', 'tsserverlibrary.js')) + or '' +end + +-- https://github.com/johnsoncodehk/volar/blob/master/packages/shared/src/types.ts +local volar_init_options = { + typescript = { + serverPath = '', + }, + languageFeatures = { + implementation = true, + -- not supported - https://github.com/neovim/neovim/pull/14122 + semanticTokens = false, + references = true, + definition = true, + typeDefinition = true, + callHierarchy = true, + hover = true, + rename = true, + renameFileRefactoring = true, + signatureHelp = true, + codeAction = true, + completion = { + defaultTagNameCase = 'both', + defaultAttrNameCase = 'kebabCase', + }, + schemaRequestService = true, + documentHighlight = true, + documentLink = true, + codeLens = true, + diagnostics = true, + }, + documentFeatures = { + -- not supported - https://github.com/neovim/neovim/pull/13654 + documentColor = false, + selectionRange = true, + foldingRange = true, + linkedEditingRange = true, + documentSymbol = true, + documentFormatting = { + defaultPrintWidth = 100, + }, + }, +} + +local bin_name = 'vue-language-server' +local cmd = { bin_name, '--stdio' } + +if vim.fn.has 'win32' == 1 then + cmd = { 'cmd.exe', '/C', bin_name, '--stdio' } +end +return { + default_config = { + cmd = cmd, + filetypes = { 'vue' }, + root_dir = util.root_pattern 'package.json', + init_options = volar_init_options, + on_new_config = function(new_config, new_root_dir) + if + new_config.init_options + and new_config.init_options.typescript + and new_config.init_options.typescript.serverPath == '' + then + new_config.init_options.typescript.serverPath = get_typescript_server_path(new_root_dir) + end + end, + }, + docs = { + description = [[ +https://github.com/johnsoncodehk/volar/tree/master/packages/vue-language-server + +Volar language server for Vue + +Volar can be installed via npm: + +```sh +npm install -g @volar/vue-language-server +``` + +Volar by default supports Vue 3 projects. Vue 2 projects need [additional configuration](https://github.com/johnsoncodehk/volar/blob/master/extensions/vscode-vue-language-features/README.md?plain=1#L28-L63). + +**Take Over Mode** +Volar can serve as a language server for both Vue and TypeScript via [Take Over Mode](https://github.com/johnsoncodehk/volar/discussions/471). + +To enable Take Over Mode, override the default filetypes in `setup{}` as follows: + +```lua +require'lspconfig'.volar.setup{ + filetypes = {'typescript', 'javascript', 'javascriptreact', 'typescriptreact', 'vue', 'json'} +} +``` + +**Overriding the default TypeScript Server used by Volar** +The default config looks for TS in the local node_modules. The alternatives are: + +- use a global TypeScript Server installation + +```lua +require'lspconfig'.volar.setup{ + init_options = { + typescript = { + serverPath = '/path/to/.npm/lib/node_modules/typescript/lib/tsserverlib.js' + } + } +} +``` + +- use a global TypeScript Server installation if a local server is not found + +```lua +local util = require 'lspconfig.util' + +local function get_typescript_server_path(root_dir) + local project_root = util.find_node_modules_ancestor(root_dir) + + local local_tsserverlib = project_root ~= nil and util.path.join(project_root, 'node_modules', 'typescript', 'lib', 'tsserverlibrary.js') + local global_tsserverlib = '/home/[yourusernamehere]/.npm/lib/node_modules/typescript/lib/tsserverlibrary.js' + + if local_tsserverlib and util.path.exists(local_tsserverlib) then + return local_tsserverlib + else + return global_tsserverlib + end +end + +require'lspconfig'.volar.setup{ + on_new_config = function(new_config, new_root_dir) + new_config.init_options.typescript.serverPath = get_typescript_server_path(new_root_dir) + end, +} +``` + ]], + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/vuels.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/vuels.lua new file mode 100644 index 0000000..d3d2d92 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/vuels.lua @@ -0,0 +1,68 @@ +local util = require 'lspconfig.util' + +local bin_name = 'vls' +local cmd = { bin_name } + +if vim.fn.has 'win32' == 1 then + cmd = { 'cmd.exe', '/C', bin_name } +end + +return { + default_config = { + cmd = cmd, + filetypes = { 'vue' }, + root_dir = util.root_pattern('package.json', 'vue.config.js'), + init_options = { + config = { + vetur = { + useWorkspaceDependencies = false, + validation = { + template = true, + style = true, + script = true, + }, + completion = { + autoImport = false, + useScaffoldSnippets = false, + tagCasing = 'kebab', + }, + format = { + defaultFormatter = { + js = 'none', + ts = 'none', + }, + defaultFormatterOptions = {}, + scriptInitialIndent = false, + styleInitialIndent = false, + }, + }, + css = {}, + html = { + suggest = {}, + }, + javascript = { + format = {}, + }, + typescript = { + format = {}, + }, + emmet = {}, + stylusSupremacy = {}, + }, + }, + }, + docs = { + description = [[ +https://github.com/vuejs/vetur/tree/master/server + +Vue language server(vls) +`vue-language-server` can be installed via `npm`: +```sh +npm install -g vls +``` +]], + default_config = { + root_dir = [[root_pattern("package.json", "vue.config.js")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/yamlls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/yamlls.lua new file mode 100644 index 0000000..52d8e6f --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/yamlls.lua @@ -0,0 +1,87 @@ +local util = require 'lspconfig.util' + +local bin_name = 'yaml-language-server' +local cmd = { bin_name, '--stdio' } + +if vim.fn.has 'win32' == 1 then + cmd = { 'cmd.exe', '/C', bin_name, '--stdio' } +end + +return { + default_config = { + cmd = cmd, + filetypes = { 'yaml', 'yaml.docker-compose' }, + root_dir = util.find_git_ancestor, + single_file_support = true, + settings = { + -- https://github.com/redhat-developer/vscode-redhat-telemetry#how-to-disable-telemetry-reporting + redhat = { telemetry = { enabled = false } }, + }, + }, + docs = { + description = [[ +https://github.com/redhat-developer/yaml-language-server + +`yaml-language-server` can be installed via `yarn`: +```sh +yarn global add yaml-language-server +``` + +To use a schema for validation, there are two options: + +1. Add a modeline to the file. A modeline is a comment of the form: + +``` +# yaml-language-server: $schema= +``` + +where the relative filepath is the path relative to the open yaml file, and the absolute filepath +is the filepath relative to the filesystem root ('/' on unix systems) + +2. Associated a schema url, relative , or absolute (to root of project, not to filesystem root) path to +the a glob pattern relative to the detected project root. Check `:LspInfo` to determine the resolved project +root. + +```lua +require('lspconfig').yamlls.setup { + ... -- other configuration for setup {} + settings = { + yaml = { + ... -- other settings. note this overrides the lspconfig defaults. + schemas = { + ["https://json.schemastore.org/github-workflow.json"] = "/.github/workflows/*" + ["../path/relative/to/file.yml"] = "/.github/workflows/*" + ["/path/from/root/of/project"] = "/.github/workflows/*" + }, + }, + } +} +``` + +Currently, kubernetes is special-cased in yammls, see the following upstream issues: +* [#211](https://github.com/redhat-developer/yaml-language-server/issues/211). +* [#307](https://github.com/redhat-developer/yaml-language-server/issues/307). + +To override a schema to use a specific k8s schema version (for example, to use 1.18): + +```lua +require('lspconfig').yamlls.setup { + ... -- other configuration for setup {} + settings = { + yaml = { + ... -- other settings. note this overrides the lspconfig defaults. + schemas = { + ["https://raw.githubusercontent.com/instrumenta/kubernetes-json-schema/master/v1.18.0-standalone-strict/all.json"] = "/*.k8s.yaml", + ... -- other schemas + }, + }, + } +} +``` + +]], + default_config = { + root_dir = [[util.find_git_ancestor]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/zeta_note.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/zeta_note.lua new file mode 100644 index 0000000..9798af9 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/zeta_note.lua @@ -0,0 +1,28 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + filetypes = { 'markdown' }, + root_dir = util.root_pattern '.zeta.toml', + }, + docs = { + description = [[ +https://github.com/artempyanykh/zeta-note + +Markdown LSP server for easy note-taking with cross-references and diagnostics. + +Binaries can be downloaded from https://github.com/artempyanykh/zeta-note/releases + +**By default, zeta-note doesn't have a `cmd` set.** This is because nvim-lspconfig does not make assumptions about your path. You must add the following to your init.vim or init.lua to set `cmd` to the absolute path ($HOME and ~ are not expanded) of your zeta-note binary. + +```lua +require'lspconfig'.zeta_note.setup{ + cmd = {'path/to/zeta-note'} +} +``` +]], + default_config = { + root_dir = [[root_pattern(".zeta.toml")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/zk.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/zk.lua new file mode 100644 index 0000000..c289045 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/zk.lua @@ -0,0 +1,48 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'zk', 'lsp' }, + filetypes = { 'markdown' }, + root_dir = util.root_pattern '.zk', + }, + commands = { + ZkIndex = { + function() + vim.lsp.buf.execute_command { + command = 'zk.index', + arguments = { vim.api.nvim_buf_get_name(0) }, + } + end, + description = 'Index', + }, + ZkNew = { + function(...) + vim.lsp.buf_request(0, 'workspace/executeCommand', { + command = 'zk.new', + arguments = { + vim.api.nvim_buf_get_name(0), + ..., + }, + }, function(_, result, _, _) + if not (result and result.path) then + return + end + vim.cmd('edit ' .. result.path) + end) + end, + + description = 'ZkNew', + }, + }, + docs = { + description = [[ +github.com/mickael-menu/zk + +A plain text note-taking assistant +]], + default_config = { + root_dir = [[root_pattern(".zk")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/zls.lua b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/zls.lua new file mode 100644 index 0000000..d890fb6 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/server_configurations/zls.lua @@ -0,0 +1,20 @@ +local util = require 'lspconfig.util' + +return { + default_config = { + cmd = { 'zls' }, + filetypes = { 'zig', 'zir' }, + root_dir = util.root_pattern('zls.json', '.git'), + single_file_support = true, + }, + docs = { + description = [[ +https://github.com/zigtools/zls + +Zig LSP implementation + Zig Language Server + ]], + default_config = { + root_dir = [[util.root_pattern("zls.json", ".git")]], + }, + }, +} diff --git a/start/lspconfig-0.1.3/lua/lspconfig/ui/lspinfo.lua b/start/lspconfig-0.1.3/lua/lspconfig/ui/lspinfo.lua new file mode 100644 index 0000000..42a7fed --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/ui/lspinfo.lua @@ -0,0 +1,225 @@ +local configs = require 'lspconfig.configs' +local windows = require 'lspconfig.ui.windows' +local util = require 'lspconfig.util' + +local error_messages = { + cmd_not_found = 'Unable to find executable. Please check your path and ensure the server is installed', + no_filetype_defined = 'No filetypes defined, Please define filetypes in setup()', +} + +local function trim_blankspace(cmd) + local trimmed_cmd = {} + for _, str in pairs(cmd) do + table.insert(trimmed_cmd, str:match '^%s*(.*)') + end + return trimmed_cmd +end + +local function indent_lines(lines, offset) + return vim.tbl_map(function(val) + return offset .. val + end, lines) +end + +local function remove_newlines(cmd) + cmd = trim_blankspace(cmd) + cmd = table.concat(cmd, ' ') + cmd = vim.split(cmd, '\n') + cmd = trim_blankspace(cmd) + cmd = table.concat(cmd, ' ') + return cmd +end + +local function make_config_info(config) + local config_info = {} + config_info.name = config.name + if config.cmd then + config_info.cmd = remove_newlines(config.cmd) + if vim.fn.executable(config.cmd[1]) == 1 then + config_info.cmd_is_executable = 'true' + else + config_info.cmd_is_executable = error_messages.cmd_not_found + end + else + config_info.cmd = 'cmd not defined' + config_info.cmd_is_executable = 'NA' + end + + local buffer_dir = vim.fn.expand '%:p:h' + config_info.root_dir = config.get_root_dir(buffer_dir) or 'NA' + config_info.autostart = (config.autostart and 'true') or 'false' + config_info.handlers = table.concat(vim.tbl_keys(config.handlers), ', ') + config_info.filetypes = table.concat(config.filetypes or {}, ', ') + + local lines = { + 'Config: ' .. config_info.name, + } + + local info_lines = { + 'filetypes: ' .. config_info.filetypes, + 'root directory: ' .. config_info.root_dir, + 'cmd: ' .. config_info.cmd, + 'cmd is executable: ' .. config_info.cmd_is_executable, + 'autostart: ' .. config_info.autostart, + 'custom handlers: ' .. config_info.handlers, + } + + vim.list_extend(lines, indent_lines(info_lines, '\t')) + + return lines +end + +local function make_client_info(client) + local client_info = {} + + client_info.cmd = remove_newlines(client.config.cmd) + if client.workspaceFolders then + client_info.root_dir = client.workspaceFolders[1].name + else + client_info.root_dir = 'Running in single file mode.' + end + client_info.filetypes = table.concat(client.config.filetypes or {}, ', ') + client_info.autostart = (client.config.autostart and 'true') or 'false' + client_info.attached_buffers_list = table.concat(vim.lsp.get_buffers_by_client_id(client.id), ', ') + + local lines = { + '', + 'Client: ' + .. client.name + .. ' (id: ' + .. tostring(client.id) + .. ', pid: ' + .. tostring(client.rpc.pid) + .. ', bufnr: [' + .. client_info.attached_buffers_list + .. '])', + } + + local info_lines = { + 'filetypes: ' .. client_info.filetypes, + 'autostart: ' .. client_info.autostart, + 'root directory: ' .. client_info.root_dir, + 'cmd: ' .. client_info.cmd, + } + + if client.config.lspinfo then + local server_specific_info = client.config.lspinfo(client.config) + info_lines = vim.list_extend(info_lines, server_specific_info) + end + + vim.list_extend(lines, indent_lines(info_lines, '\t')) + + return lines +end + +return function() + -- These options need to be cached before switching to the floating + -- buffer. + local buf_clients = vim.lsp.buf_get_clients() + local clients = vim.lsp.get_active_clients() + local buffer_filetype = vim.bo.filetype + + local win_info = windows.percentage_range_window(0.8, 0.7) + local bufnr, win_id = win_info.bufnr, win_info.win_id + + local buf_lines = {} + + local buf_client_names = {} + for _, client in pairs(buf_clients) do + table.insert(buf_client_names, client.name) + end + + local buf_client_ids = {} + for _, client in pairs(buf_clients) do + table.insert(buf_client_ids, client.id) + end + + local other_active_clients = {} + local client_names = {} + for _, client in pairs(clients) do + if not vim.tbl_contains(buf_client_ids, client.id) then + table.insert(other_active_clients, client) + end + table.insert(client_names, client.name) + end + + local header = { + '', + 'Language client log: ' .. (vim.lsp.get_log_path()), + 'Detected filetype: ' .. buffer_filetype, + } + vim.list_extend(buf_lines, header) + + local buffer_clients_header = { + '', + tostring(#vim.tbl_keys(buf_clients)) .. ' client(s) attached to this buffer: ', + } + + vim.list_extend(buf_lines, buffer_clients_header) + for _, client in pairs(buf_clients) do + local client_info = make_client_info(client) + vim.list_extend(buf_lines, client_info) + end + + local other_active_section_header = { + '', + tostring(#other_active_clients) .. ' active client(s) not attached to this buffer: ', + } + if not vim.tbl_isempty(other_active_clients) then + vim.list_extend(buf_lines, other_active_section_header) + end + for _, client in pairs(other_active_clients) do + local client_info = make_client_info(client) + vim.list_extend(buf_lines, client_info) + end + + local other_matching_configs_header = { + '', + 'Other clients that match the filetype: ' .. buffer_filetype, + '', + } + + local other_matching_configs = util.get_other_matching_providers(buffer_filetype) + + if not vim.tbl_isempty(other_matching_configs) then + vim.list_extend(buf_lines, other_matching_configs_header) + for _, config in pairs(other_matching_configs) do + vim.list_extend(buf_lines, make_config_info(config)) + end + end + + local matching_config_header = { + '', + 'Configured servers list: ' .. table.concat(vim.tbl_keys(configs), ', '), + } + vim.list_extend(buf_lines, matching_config_header) + + local fmt_buf_lines = indent_lines(buf_lines, ' ') + + fmt_buf_lines = vim.lsp.util._trim(fmt_buf_lines, {}) + + vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, fmt_buf_lines) + vim.api.nvim_buf_set_option(bufnr, 'modifiable', false) + vim.api.nvim_buf_set_option(bufnr, 'filetype', 'lspinfo') + + vim.api.nvim_buf_set_keymap(bufnr, 'n', '', 'bd', { noremap = true }) + vim.api.nvim_command( + string.format('autocmd BufHidden,BufLeave ++once lua pcall(vim.api.nvim_win_close, %d, true)', win_id) + ) + + vim.fn.matchadd( + 'Error', + error_messages.no_filetype_defined .. '.\\|' .. 'cmd not defined\\|' .. error_messages.cmd_not_found + ) + vim.cmd 'let m=matchadd("string", "true")' + vim.cmd 'let m=matchadd("error", "false")' + for _, config in pairs(configs) do + vim.fn.matchadd('Title', '\\%(Client\\|Config\\):.*\\zs' .. config.name .. '\\ze') + vim.fn.matchadd('Visual', 'list:.*\\zs' .. config.name .. '\\ze') + if config.filetypes then + for _, ft in pairs(config.filetypes) do + vim.fn.matchadd('Type', '\\%(filetypes\\|filetype\\):.*\\zs' .. ft .. '\\ze') + end + end + end +end diff --git a/start/lspconfig-0.1.3/lua/lspconfig/ui/windows.lua b/start/lspconfig-0.1.3/lua/lspconfig/ui/windows.lua new file mode 100644 index 0000000..8a39204 --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/ui/windows.lua @@ -0,0 +1,117 @@ +-- The following is extracted and modified from plenary.vnim by +-- TJ Devries. It is not a stable API, and is expected to change +-- +local function apply_defaults(original, defaults) + if original == nil then + original = {} + end + + original = vim.deepcopy(original) + + for k, v in pairs(defaults) do + if original[k] == nil then + original[k] = v + end + end + + return original +end + +local win_float = {} + +win_float.default_options = { + winblend = 15, + percentage = 0.9, +} + +function win_float.default_opts(options) + options = apply_defaults(options, win_float.default_options) + + local width = math.floor(vim.o.columns * options.percentage) + local height = math.floor(vim.o.lines * options.percentage) + + local top = math.floor(((vim.o.lines - height) / 2) - 1) + local left = math.floor((vim.o.columns - width) / 2) + + local opts = { + relative = 'editor', + row = top, + col = left, + width = width, + height = height, + style = 'minimal', + border = { + { ' ', 'NormalFloat' }, + { ' ', 'NormalFloat' }, + { ' ', 'NormalFloat' }, + { ' ', 'NormalFloat' }, + { ' ', 'NormalFloat' }, + { ' ', 'NormalFloat' }, + { ' ', 'NormalFloat' }, + { ' ', 'NormalFloat' }, + }, + } + + return opts +end + +--- Create window that takes up certain percentags of the current screen. +--- +--- Works regardless of current buffers, tabs, splits, etc. +--@param col_range number | Table: +-- If number, then center the window taking up this percentage of the screen. +-- If table, first index should be start, second_index should be end +--@param row_range number | Table: +-- If number, then center the window taking up this percentage of the screen. +-- If table, first index should be start, second_index should be end +function win_float.percentage_range_window(col_range, row_range, options) + options = apply_defaults(options, win_float.default_options) + + local win_opts = win_float.default_opts(options) + win_opts.relative = 'editor' + + local height_percentage, row_start_percentage + if type(row_range) == 'number' then + assert(row_range <= 1) + assert(row_range > 0) + height_percentage = row_range + row_start_percentage = (1 - height_percentage) / 2 + elseif type(row_range) == 'table' then + height_percentage = row_range[2] - row_range[1] + row_start_percentage = row_range[1] + else + error(string.format("Invalid type for 'row_range': %p", row_range)) + end + + win_opts.height = math.ceil(vim.o.lines * height_percentage) + win_opts.row = math.ceil(vim.o.lines * row_start_percentage) + + local width_percentage, col_start_percentage + if type(col_range) == 'number' then + assert(col_range <= 1) + assert(col_range > 0) + width_percentage = col_range + col_start_percentage = (1 - width_percentage) / 2 + elseif type(col_range) == 'table' then + width_percentage = col_range[2] - col_range[1] + col_start_percentage = col_range[1] + else + error(string.format("Invalid type for 'col_range': %p", col_range)) + end + + win_opts.col = math.floor(vim.o.columns * col_start_percentage) + win_opts.width = math.floor(vim.o.columns * width_percentage) + + local bufnr = options.bufnr or vim.api.nvim_create_buf(false, true) + local win_id = vim.api.nvim_open_win(bufnr, true, win_opts) + vim.api.nvim_win_set_buf(win_id, bufnr) + + vim.cmd 'setlocal nocursorcolumn ts=2 sw=2' + + return { + bufnr = bufnr, + win_id = win_id, + } +end + +return win_float diff --git a/start/lspconfig-0.1.3/lua/lspconfig/util.lua b/start/lspconfig-0.1.3/lua/lspconfig/util.lua new file mode 100644 index 0000000..3febafc --- /dev/null +++ b/start/lspconfig-0.1.3/lua/lspconfig/util.lua @@ -0,0 +1,426 @@ +local vim = vim +local validate = vim.validate +local api = vim.api +local lsp = vim.lsp +local uv = vim.loop +local fn = vim.fn + +local M = {} + +M.default_config = { + log_level = lsp.protocol.MessageType.Warning, + message_level = lsp.protocol.MessageType.Warning, + settings = vim.empty_dict(), + init_options = vim.empty_dict(), + handlers = {}, + autostart = true, +} + +-- global on_setup hook +M.on_setup = nil + +function M.bufname_valid(bufname) + if bufname and bufname ~= '' and (bufname:match '^([a-zA-Z]:).*' or bufname:match '^/') then + return true + else + return false + end +end + +function M.validate_bufnr(bufnr) + validate { + bufnr = { bufnr, 'n' }, + } + return bufnr == 0 and api.nvim_get_current_buf() or bufnr +end + +function M.add_hook_before(func, new_fn) + if func then + return function(...) + -- TODO which result? + new_fn(...) + return func(...) + end + else + return new_fn + end +end + +function M.add_hook_after(func, new_fn) + if func then + return function(...) + -- TODO which result? + func(...) + return new_fn(...) + end + else + return new_fn + end +end + +function M.create_module_commands(module_name, commands) + for command_name, def in pairs(commands) do + local parts = { 'command!' } + -- Insert attributes. + for k, v in pairs(def) do + if type(k) == 'string' and type(v) == 'boolean' and v then + table.insert(parts, '-' .. k) + elseif type(k) == 'number' and type(v) == 'string' and v:match '^%-' then + table.insert(parts, v) + end + end + table.insert(parts, command_name) + -- The command definition. + table.insert( + parts, + string.format("lua require'lspconfig'[%q].commands[%q][1]()", module_name, command_name) + ) + api.nvim_command(table.concat(parts, ' ')) + end +end + +function M.has_bins(...) + for i = 1, select('#', ...) do + if 0 == fn.executable((select(i, ...))) then + return false + end + end + return true +end + +M.script_path = function() + local str = debug.getinfo(2, 'S').source:sub(2) + return str:match '(.*[/\\])' +end + +-- Some path utilities +M.path = (function() + local is_windows = uv.os_uname().version:match 'Windows' + + local function sanitize(path) + if is_windows then + path = path:sub(1, 1):upper() .. path:sub(2) + path = path:gsub('\\', '/') + end + return path + end + + local function exists(filename) + local stat = uv.fs_stat(filename) + return stat and stat.type or false + end + + local function is_dir(filename) + return exists(filename) == 'directory' + end + + local function is_file(filename) + return exists(filename) == 'file' + end + + local function is_fs_root(path) + if is_windows then + return path:match '^%a:$' + else + return path == '/' + end + end + + local function is_absolute(filename) + if is_windows then + return filename:match '^%a:' or filename:match '^\\\\' + else + return filename:match '^/' + end + end + + local function dirname(path) + local strip_dir_pat = '/([^/]+)$' + local strip_sep_pat = '/$' + if not path or #path == 0 then + return + end + local result = path:gsub(strip_sep_pat, ''):gsub(strip_dir_pat, '') + if #result == 0 then + if is_windows then + return path:sub(1, 2):upper() + else + return '/' + end + end + return result + end + + local function path_join(...) + return table.concat(vim.tbl_flatten { ... }, '/') + end + + -- Traverse the path calling cb along the way. + local function traverse_parents(path, cb) + path = uv.fs_realpath(path) + local dir = path + -- Just in case our algo is buggy, don't infinite loop. + for _ = 1, 100 do + dir = dirname(dir) + if not dir then + return + end + -- If we can't ascend further, then stop looking. + if cb(dir, path) then + return dir, path + end + if is_fs_root(dir) then + break + end + end + end + + -- Iterate the path until we find the rootdir. + local function iterate_parents(path) + local function it(_, v) + if v and not is_fs_root(v) then + v = dirname(v) + else + return + end + if v and uv.fs_realpath(v) then + return v, path + else + return + end + end + return it, path, path + end + + local function is_descendant(root, path) + if not path then + return false + end + + local function cb(dir, _) + return dir == root + end + + local dir, _ = traverse_parents(path, cb) + + return dir == root + end + + return { + is_dir = is_dir, + is_file = is_file, + is_absolute = is_absolute, + exists = exists, + dirname = dirname, + join = path_join, + sanitize = sanitize, + traverse_parents = traverse_parents, + iterate_parents = iterate_parents, + is_descendant = is_descendant, + } +end)() + +-- Returns a function(root_dir), which, when called with a root_dir it hasn't +-- seen before, will call make_config(root_dir) and start a new client. +function M.server_per_root_dir_manager(make_config) + local clients = {} + local single_file_clients = {} + local manager = {} + + function manager.add(root_dir, single_file) + local client_id + -- This is technically unnecessary, as lspconfig's path utilities should be hermetic, + -- however users are free to return strings in custom root resolvers. + root_dir = M.path.sanitize(root_dir) + if single_file then + client_id = single_file_clients[root_dir] + elseif root_dir and M.path.is_dir(root_dir) then + client_id = clients[root_dir] + else + return + end + + -- Check if we have a client already or start and store it. + if not client_id then + local new_config = make_config(root_dir) + -- do nothing if the client is not enabled + if new_config.enabled == false then + return + end + if not new_config.cmd then + vim.notify( + string.format( + '[lspconfig] cmd not defined for %q. Manually set cmd in the setup {} call according to server_configurations.md, see :help lspconfig-index.', + new_config.name + ), + vim.log.levels.ERROR + ) + return + end + new_config.on_exit = M.add_hook_before(new_config.on_exit, function() + clients[root_dir] = nil + single_file_clients[root_dir] = nil + end) + + -- Launch the server in the root directory used internally by lspconfig, if otherwise unset + -- also check that the path exist + if not new_config.cmd_cwd and uv.fs_realpath(root_dir) then + new_config.cmd_cwd = root_dir + end + + -- Sending rootDirectory and workspaceFolders as null is not explicitly + -- codified in the spec. Certain servers crash if initialized with a NULL + -- root directory. + if single_file then + new_config.root_dir = nil + new_config.workspace_folders = nil + end + client_id = lsp.start_client(new_config) + + -- Handle failures in start_client + if not client_id then + return + end + + if single_file then + single_file_clients[root_dir] = client_id + else + clients[root_dir] = client_id + end + end + return client_id + end + + function manager.clients() + local res = {} + for _, id in pairs(clients) do + local client = lsp.get_client_by_id(id) + if client then + table.insert(res, client) + end + end + return res + end + + return manager +end + +function M.search_ancestors(startpath, func) + validate { func = { func, 'f' } } + if func(startpath) then + return startpath + end + local guard = 100 + for path in M.path.iterate_parents(startpath) do + -- Prevent infinite recursion if our algorithm breaks + guard = guard - 1 + if guard == 0 then + return + end + + if func(path) then + return path + end + end +end + +function M.root_pattern(...) + local patterns = vim.tbl_flatten { ... } + local function matcher(path) + for _, pattern in ipairs(patterns) do + for _, p in ipairs(vim.fn.glob(M.path.join(path, pattern), true, true)) do + if M.path.exists(p) then + return path + end + end + end + end + return function(startpath) + return M.search_ancestors(startpath, matcher) + end +end +function M.find_git_ancestor(startpath) + return M.search_ancestors(startpath, function(path) + -- Support git directories and git files (worktrees) + if M.path.is_dir(M.path.join(path, '.git')) or M.path.is_file(M.path.join(path, '.git')) then + return path + end + end) +end +function M.find_node_modules_ancestor(startpath) + return M.search_ancestors(startpath, function(path) + if M.path.is_dir(M.path.join(path, 'node_modules')) then + return path + end + end) +end +function M.find_package_json_ancestor(startpath) + return M.search_ancestors(startpath, function(path) + if M.path.is_file(M.path.join(path, 'package.json')) then + return path + end + end) +end + +function M.get_active_clients_list_by_ft(filetype) + local clients = vim.lsp.get_active_clients() + local clients_list = {} + for _, client in pairs(clients) do + local filetypes = client.config.filetypes or {} + for _, ft in pairs(filetypes) do + if ft == filetype then + table.insert(clients_list, client.name) + end + end + end + return clients_list +end + +function M.get_other_matching_providers(filetype) + local configs = require 'lspconfig.configs' + local active_clients_list = M.get_active_clients_list_by_ft(filetype) + local other_matching_configs = {} + for _, config in pairs(configs) do + if not vim.tbl_contains(active_clients_list, config.name) then + local filetypes = config.filetypes or {} + for _, ft in pairs(filetypes) do + if ft == filetype then + table.insert(other_matching_configs, config) + end + end + end + end + return other_matching_configs +end + +function M.get_clients_from_cmd_args(arg) + local result = {} + for id in (arg or ''):gmatch '(%d+)' do + result[id] = vim.lsp.get_client_by_id(tonumber(id)) + end + if vim.tbl_isempty(result) then + return M.get_managed_clients() + end + return vim.tbl_values(result) +end + +function M.get_active_client_by_name(bufnr, servername) + for _, client in pairs(vim.lsp.buf_get_clients(bufnr)) do + if client.name == servername then + return client + end + end +end + +function M.get_managed_clients() + local configs = require 'lspconfig.configs' + local clients = {} + for _, config in pairs(configs) do + if config.manager then + vim.list_extend(clients, config.manager.clients()) + end + end + return clients +end + +return M diff --git a/start/lspconfig-0.1.3/plugin/lspconfig.vim b/start/lspconfig-0.1.3/plugin/lspconfig.vim new file mode 100644 index 0000000..5c52d4e --- /dev/null +++ b/start/lspconfig-0.1.3/plugin/lspconfig.vim @@ -0,0 +1,16 @@ +if exists('g:lspconfig') + finish +endif +let g:lspconfig = 1 + +lua << EOF +lsp_complete_configured_servers = function() + return table.concat(require'lspconfig'.available_servers(), '\n') +end +lsp_get_active_client_ids = function() + return vim.tbl_map(function(client) + return ("%d (%s)"):format(client.id, client.name) + end, require'lspconfig.util'.get_managed_clients()) +end +require'lspconfig'._root._setup() +EOF diff --git a/start/repeat/README.markdown b/start/repeat/README.markdown new file mode 100644 index 0000000..f8b4469 --- /dev/null +++ b/start/repeat/README.markdown @@ -0,0 +1,47 @@ +# repeat.vim + +If you've ever tried using the `.` command after a plugin map, you were +likely disappointed to discover it only repeated the last native command +inside that map, rather than the map as a whole. That disappointment +ends today. Repeat.vim remaps `.` in a way that plugins can tap into +it. + +The following plugins support repeat.vim: + +* [surround.vim](https://github.com/tpope/vim-surround) +* [speeddating.vim](https://github.com/tpope/vim-speeddating) +* [unimpaired.vim](https://github.com/tpope/vim-unimpaired) +* [vim-easyclip](https://github.com/svermeulen/vim-easyclip) + +Adding support to a plugin is generally as simple as the following +command at the end of your map functions. + + silent! call repeat#set("\MyWonderfulMap", v:count) + +## Installation + +Install using your favorite package manager, or use Vim's built-in package +support: + + mkdir -p ~/.vim/pack/tpope/start + cd ~/.vim/pack/tpope/start + git clone https://tpope.io/vim/repeat.git + +## Contributing + +See the contribution guidelines for +[pathogen.vim](https://github.com/tpope/vim-pathogen#readme). + +## Self-Promotion + +Like repeat.vim? Follow the repository on +[GitHub](https://github.com/tpope/vim-repeat) and vote for it on +[vim.org](http://www.vim.org/scripts/script.php?script_id=2136). And if +you're feeling especially charitable, follow [tpope](http://tpo.pe/) on +[Twitter](http://twitter.com/tpope) and +[GitHub](https://github.com/tpope). + +## License + +Copyright (c) Tim Pope. Distributed under the same terms as Vim itself. +See `:help license`. diff --git a/start/repeat/autoload/repeat.vim b/start/repeat/autoload/repeat.vim new file mode 100644 index 0000000..ce2141b --- /dev/null +++ b/start/repeat/autoload/repeat.vim @@ -0,0 +1,145 @@ +" repeat.vim - Let the repeat command repeat plugin maps +" Maintainer: Tim Pope +" Version: 1.2 +" GetLatestVimScripts: 2136 1 :AutoInstall: repeat.vim + +" Installation: +" Place in either ~/.vim/plugin/repeat.vim (to load at start up) or +" ~/.vim/autoload/repeat.vim (to load automatically as needed). +" +" License: +" Copyright (c) Tim Pope. Distributed under the same terms as Vim itself. +" See :help license +" +" Developers: +" Basic usage is as follows: +" +" silent! call repeat#set("\MappingToRepeatCommand",3) +" +" The first argument is the mapping that will be invoked when the |.| key is +" pressed. Typically, it will be the same as the mapping the user invoked. +" This sequence will be stuffed into the input queue literally. Thus you must +" encode special keys by prefixing them with a backslash inside double quotes. +" +" The second argument is the default count. This is the number that will be +" prefixed to the mapping if no explicit numeric argument was given. The +" value of the v:count variable is usually correct and it will be used if the +" second parameter is omitted. If your mapping doesn't accept a numeric +" argument and you never want to receive one, pass a value of -1. +" +" Make sure to call the repeat#set function _after_ making changes to the +" file. +" +" For mappings that use a register and want the same register used on +" repetition, use: +" +" silent! call repeat#setreg("\MappingToRepeatCommand", v:register) +" +" This function can (and probably needs to be) called before making changes to +" the file (as those typically clear v:register). Therefore, the call sequence +" in your mapping will look like this: +" +" nnoremap MyMap +" \ :silent! call repeat#setreg("\Plug>MyMap", v:register) +" \ call MyFunction(v:register, ...) +" \ silent! call repeat#set("\Plug>MyMap") + +if exists("g:loaded_repeat") || &cp || v:version < 700 + finish +endif +let g:loaded_repeat = 1 + +let g:repeat_tick = -1 +let g:repeat_reg = ['', ''] + +" Special function to avoid spurious repeats in a related, naturally repeating +" mapping when your repeatable mapping doesn't increase b:changedtick. +function! repeat#invalidate() + autocmd! repeat_custom_motion + let g:repeat_tick = -1 +endfunction + +function! repeat#set(sequence,...) + let g:repeat_sequence = a:sequence + let g:repeat_count = a:0 ? a:1 : v:count + let g:repeat_tick = b:changedtick + augroup repeat_custom_motion + autocmd! + autocmd CursorMoved let g:repeat_tick = b:changedtick | autocmd! repeat_custom_motion + augroup END +endfunction + +function! repeat#setreg(sequence,register) + let g:repeat_reg = [a:sequence, a:register] +endfunction + +function! repeat#run(count) + try + if g:repeat_tick == b:changedtick + let r = '' + if g:repeat_reg[0] ==# g:repeat_sequence && !empty(g:repeat_reg[1]) + if g:repeat_reg[1] ==# '=' + " This causes a re-evaluation of the expression on repeat, which + " is what we want. + let r = '"=' . getreg('=', 1) . "\" + else + let r = '"' . g:repeat_reg[1] + endif + endif + + let c = g:repeat_count + let s = g:repeat_sequence + let cnt = c == -1 ? "" : (a:count ? a:count : (c ? c : '')) + if ((v:version == 703 && has('patch100')) || (v:version == 704 && !has('patch601'))) + exe 'norm ' . r . cnt . s + else + call feedkeys(s, 'i') + call feedkeys(r . cnt, 'ni') + endif + else + if ((v:version == 703 && has('patch100')) || (v:version == 704 && !has('patch601'))) + exe 'norm! '.(a:count ? a:count : '') . '.' + else + call feedkeys((a:count ? a:count : '') . '.', 'ni') + endif + endif + catch /^Vim(normal):/ + return 'echoerr v:errmsg' + endtry + return '' +endfunction + +function! repeat#wrap(command,count) + let preserve = (g:repeat_tick == b:changedtick) + call feedkeys((a:count ? a:count : '').a:command, 'n') + exe (&foldopen =~# 'undo\|all' ? 'norm! zv' : '') + if preserve + let g:repeat_tick = b:changedtick + endif +endfunction + +nnoremap (RepeatDot) :exe repeat#run(v:count) +nnoremap (RepeatUndo) :call repeat#wrap('u',v:count) +nnoremap (RepeatUndoLine) :call repeat#wrap('U',v:count) +nnoremap (RepeatRedo) :call repeat#wrap("\C-R>",v:count) + +if !hasmapto('(RepeatDot)', 'n') + nmap . (RepeatDot) +endif +if !hasmapto('(RepeatUndo)', 'n') + nmap u (RepeatUndo) +endif +if maparg('U','n') ==# '' && !hasmapto('(RepeatUndoLine)', 'n') + nmap U (RepeatUndoLine) +endif +if !hasmapto('(RepeatRedo)', 'n') + nmap (RepeatRedo) +endif + +augroup repeatPlugin + autocmd! + autocmd BufLeave,BufWritePre,BufReadPre * let g:repeat_tick = (g:repeat_tick == b:changedtick || g:repeat_tick == 0) ? 0 : -1 + autocmd BufEnter,BufWritePost * if g:repeat_tick == 0|let g:repeat_tick = b:changedtick|endif +augroup END + +" vim:set ft=vim et sw=4 sts=4: diff --git a/start/signify/LICENSE b/start/signify/LICENSE new file mode 100644 index 0000000..f5b3716 --- /dev/null +++ b/start/signify/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2015 Marco Hinz + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/start/signify/README.md b/start/signify/README.md new file mode 100644 index 0000000..c15d0d5 --- /dev/null +++ b/start/signify/README.md @@ -0,0 +1,54 @@ +![vim-signify](https://raw.githubusercontent.com/mhinz/vim-signify/master/pictures/signify-logo.png) + +--- + +_Signify (or just Sy) uses the sign column to indicate added, modified and +removed lines in a file that is managed by a version control system (VCS)._ + +--- + +- Supports **git**, **mercurial**, **darcs**, **bazaar**, **subversion**, + **cvs**, **rcs**, **fossil**, **accurev**, **perforce**, **tfs**. +- **Asynchronous** execution of VCS tools for Vim 7.4.1967+ and Neovim. +- **Preserves signs** from other plugins. +- Handles **nested repositories** controlled by different VCS. +- Provides mappings for **navigating hunks** ("blocks of changed lines"). +- Provides an **operator** that acts on hunks. +- Alternative workflow: Disable the plugin by default and **toggle it per + buffer** on demand. +- Optional **line highlighting**. +- Optional **skipping of filetypes/filenames**. +- Optional **stats in the statusline**. +- **Works out of the box**, but allows fine-grained configuration. +- **Great documentation** and **handsome maintainers**! + +--- + +_Similar plugin for git: [vim-gitgutter](https://github.com/airblade/vim-gitgutter)_ + +## Installation + +Use your favorite [plugin +manager](https://github.com/mhinz/vim-galore#managing-plugins), e.g. using +[vim-plug](https://github.com/junegunn/vim-plug): + + Plug 'mhinz/vim-signify' + +## Documentation + +1. Understand how the plugin works: + [`:h signify-modus-operandi`](https://github.com/mhinz/vim-signify/blob/master/doc/signify.txt#L52) +1. Spare the plugin some work and read: `:h g:signify_vcs_list` + +## Demo + +![Example:signify in action](https://raw.githubusercontent.com/mhinz/vim-signify/master/pictures/signify-demo.gif) + +## Author and Feedback + +If you like this plugin, star it! It's a great way of getting feedback. The same +goes for reporting issues or feature requests. + +Contact: [Twitter](https://twitter.com/_mhinz_) + +Co-maintainer: [@jamessan](https://github.com/jamessan) diff --git a/start/signify/autoload/sy.vim b/start/signify/autoload/sy.vim new file mode 100644 index 0000000..b994aff --- /dev/null +++ b/start/signify/autoload/sy.vim @@ -0,0 +1,199 @@ +" vim: et sw=2 sts=2 + +scriptencoding utf-8 + +" Init: values {{{1 +let s:has_doau_modeline = v:version > 703 || v:version == 703 && has('patch442') + +" Function: #start {{{1 +function! sy#start() abort + if g:signify_locked + call sy#verbose('Locked.') + return + endif + + let sy_path = resolve(expand('%:p')) + if has('win32') + let sy_path = substitute(sy_path, '\v^(\w):\\\\', '\1:\\', '') + endif + + if s:skip(sy_path) + call sy#verbose('Skip file: '. sy_path) + if exists('b:sy') + call sy#sign#remove_all_signs(bufnr('')) + unlet! b:sy + endif + return + endif + + if !exists('b:sy') || b:sy.path != sy_path + call sy#verbose('Register new file: '. sy_path) + let b:sy = { + \ 'path': sy_path, + \ 'buffer': bufnr(''), + \ 'active': 0, + \ 'detecting': 0, + \ 'vcs': [], + \ 'hunks': [], + \ 'signid': 0x100, + \ 'updated_by': '', + \ 'stats': [-1, -1, -1], + \ 'info': { + \ 'dir': fnamemodify(sy_path, ':p:h'), + \ 'path': sy#util#escape(sy_path), + \ 'file': sy#util#escape(fnamemodify(sy_path, ':t')) + \ }} + if get(g:, 'signify_disable_by_default') + call sy#verbose('Disabled by default.') + return + endif + let b:sy.active = 1 + call sy#repo#detect() + elseif has('vim_starting') + call sy#verbose("Don't run Sy more than once during startup.") + return + elseif !b:sy.active + call sy#verbose('Inactive buffer.') + return + elseif empty(b:sy.vcs) + if get(b:sy, 'retry') + let b:sy.retry = 0 + call sy#verbose('Redetecting VCS.') + call sy#repo#detect() + else + if get(b:sy, 'detecting') + call sy#verbose('Detection is already in progress.') + else + call sy#verbose('No VCS found. Disabling.') + call sy#disable() + endif + endif + else + for vcs in b:sy.vcs + let job_id = get(b:, 'sy_job_id_'. vcs) + if type(job_id) != type(0) || job_id > 0 + call sy#verbose('Update is already in progress.', vcs) + else + call sy#verbose('Updating signs.', vcs) + call sy#repo#get_diff_start(vcs) + endif + endfor + endif +endfunction + +" Function: #set_signs {{{1 +function! sy#set_signs(sy, vcs, diff) abort + call sy#verbose('set_signs()', a:vcs) + + if a:sy.stats == [-1, -1, -1] + let a:sy.stats = [0, 0, 0] + endif + + if empty(a:diff) + call sy#verbose('No changes found.', a:vcs) + let a:sy.stats = [0, 0, 0] + call sy#sign#remove_all_signs(a:sy.buffer) + return + endif + + if get(g:, 'signify_line_highlight') + call sy#highlight#line_enable() + else + call sy#highlight#line_disable() + endif + + call sy#sign#process_diff(a:sy, a:vcs, a:diff) + + if exists('#User#Signify') + execute 'doautocmd' (s:has_doau_modeline ? '' : '') 'User Signify' + endif +endfunction + +" Function: #stop {{{1 +function! sy#stop(bufnr) abort + let sy = getbufvar(a:bufnr, 'sy') + if empty(sy) + return + endif + + call sy#sign#remove_all_signs(a:bufnr) +endfunction + +" Function: #enable {{{1 +function! sy#enable() abort + if !exists('b:sy') + call sy#start() + return + endif + + if !b:sy.active + let b:sy.active = 1 + let b:sy.retry = 1 + call sy#start() + endif +endfunction + +" Function: #disable {{{1 +function! sy#disable() abort + if exists('b:sy') && b:sy.active + call sy#stop(b:sy.buffer) + let b:sy.active = 0 + let b:sy.stats = [-1, -1, -1] + endif +endfunction + +" Function: #toggle {{{1 +function! sy#toggle() abort + if !exists('b:sy') || !b:sy.active + call sy#enable() + else + call sy#disable() + endif +endfunction + +" Function: #buffer_is_active {{{1 +function! sy#buffer_is_active() + return exists('b:sy') && b:sy.active +endfunction + +" Function: #verbose {{{1 +function! sy#verbose(msg, ...) abort + if &verbose + if type(a:msg) == type([]) + for msg in a:msg + echomsg printf('[sy%s] %s', (a:0 ? ':'.a:1 : ''), msg) + endfor + else + echomsg printf('[sy%s] %s', (a:0 ? ':'.a:1 : ''), a:msg) + endif + endif +endfunction + +" Function: s:skip {{{1 +function! s:skip(path) + if &diff || !filereadable(a:path) + return 1 + endif + + if exists('g:signify_skip_filetype') + if has_key(g:signify_skip_filetype, &filetype) + return 1 + elseif has_key(g:signify_skip_filetype, 'help') && (&buftype == 'help') + return 1 + endif + endif + + if exists('g:signify_skip_filename') && has_key(g:signify_skip_filename, a:path) + return 1 + endif + + if exists('g:signify_skip_filename_pattern') + for pattern in g:signify_skip_filename_pattern + if a:path =~ pattern + return 1 + endif + endfor + endif + + return 0 +endfunction diff --git a/start/signify/autoload/sy/debug.vim b/start/signify/autoload/sy/debug.vim new file mode 100644 index 0000000..5beafd5 --- /dev/null +++ b/start/signify/autoload/sy/debug.vim @@ -0,0 +1,48 @@ +" vim: et sw=2 sts=2 + +scriptencoding utf-8 + +" Function: #list_active_buffers {{{1 +function! sy#debug#list_active_buffers() abort + for b in range(1, bufnr('$')) + if !buflisted(b) || empty(getbufvar(b, 'sy')) + continue + endif + + let sy = copy(getbufvar(b, 'sy')) + let path = remove(sy, 'path') + + echo "\n". path ."\n". repeat('=', strlen(path)) + + for k in ['active', 'buffer', 'vcs', 'stats', 'signid'] + if k == 'stats' + echo printf("%10s = %d added, %d changed, %d removed\n", + \ k, + \ sy.stats[0], + \ sy.stats[1], + \ sy.stats[2]) + else + echo printf("%10s = %s\n", k, string(sy[k])) + endif + endfor + + if empty(sy.hunks) + echo printf("%10s = %s\n", 'hunks', '[]') + else + for i in range(len(sy.hunks)) + if i == 0 + echo printf("%10s = start: %d, end: %d, IDs: %s\n", + \ 'hunks', + \ sy.hunks[i].start, + \ sy.hunks[i].end, + \ string(sy.hunks[i].ids)) + else + echo printf("%20s: %d, %s: %d, %s: %s\n", + \ 'start', sy.hunks[i].start, + \ 'end', sy.hunks[i].end, + \ 'IDs', string(sy.hunks[i].ids)) + endif + endfor + endif + endfor +endfunction diff --git a/start/signify/autoload/sy/fold.vim b/start/signify/autoload/sy/fold.vim new file mode 100644 index 0000000..e3afb97 --- /dev/null +++ b/start/signify/autoload/sy/fold.vim @@ -0,0 +1,125 @@ +" vim: et sw=2 sts=2 + +" Function: SignifyFoldExpr {{{1 +function! SignifyFoldExpr(lnum) + return s:levels[a:lnum] +endfunction + +" Function: SignifyFoldText {{{1 +function! SignifyFoldText() + let linelen = &textwidth ? &textwidth : 80 + let marker = &foldmarker[:stridx(&foldmarker, ',')-1] + let range = foldclosedend(v:foldstart) - foldclosed(v:foldstart) + 1 + + let left = substitute(getline(v:foldstart), marker, '', '') + let leftlen = len(left) + + let right = printf('%d [%d]', range, v:foldlevel) + let rightlen = len(right) + + let tmp = strpart(left, 0, linelen - rightlen) + let tmplen = len(tmp) + + if leftlen > tmplen + let left = strpart(tmp, 0, tmplen - 4) . '... ' + let leftlen = tmplen + endif + + let fill = repeat(' ', linelen - (leftlen + rightlen)) + + " return left . fill . right . repeat(' ', 100) + return left . fill . right +endfunction + +" Function: #dispatch {{{1 +function! sy#fold#dispatch(do_tab) abort + if a:do_tab + call sy#fold#enable(1) + else + call sy#fold#toggle() + endif +endfunction + +" Function: #enable {{{1 +function! sy#fold#enable(do_tab) abort + execute sy#util#return_if_no_changes() + + if a:do_tab + tabedit % + endif + + let [s:context0, s:context1] = get(g:, 'signify_fold_context', [3, 8]) + let s:levels = s:get_levels(s:get_lines()) + + setlocal foldexpr=SignifyFoldExpr(v:lnum) + setlocal foldtext=SignifyFoldText() + setlocal foldmethod=expr + setlocal foldlevel=0 +endfunction + +" Function: #disable {{{1 +function! sy#fold#disable() abort + let &l:foldmethod = b:sy_folded.method + let &l:foldtext = b:sy_folded.text + normal! zv +endfunction + +" Function: #toggle {{{1 +function! sy#fold#toggle() abort + if exists('b:sy_folded') + call sy#fold#disable() + if b:sy_folded.method == 'manual' + loadview + endif + unlet b:sy_folded + else + let b:sy_folded = { 'method': &foldmethod, 'text': &foldtext } + if &foldmethod == 'manual' + let old_vop = &viewoptions + mkview + let &viewoptions = old_vop + endif + call sy#fold#enable(0) + endif + + redraw! + call sy#start() +endfunction + +" Function: s:get_lines {{{1 +function! s:get_lines() abort + let signlist = sy#util#execute('sign place buffer='. b:sy.buffer) + + let lines = [] + for line in split(signlist, '\n')[2:] + call insert(lines, matchlist(line, '\v^\s+line\=(\d+)')[1], 0) + endfor + + return reverse(lines) +endfunction +" }}} + +" Function: s:get_levels {{{1 +function! s:get_levels(lines) abort + let levels = {} + + for line in range(1, line('$')) + let levels[line] = 2 + endfor + + for line in a:lines + for l in range(line - s:context1, line + s:context1) + if (l < 1) || (l > line('$')) + continue + endif + if levels[l] == 2 + let levels[l] = 1 + endif + for ll in range(line - s:context0, line + s:context0) + let levels[ll] = 0 + endfor + endfor + endfor + + return levels +endfunction diff --git a/start/signify/autoload/sy/highlight.vim b/start/signify/autoload/sy/highlight.vim new file mode 100644 index 0000000..2ebe507 --- /dev/null +++ b/start/signify/autoload/sy/highlight.vim @@ -0,0 +1,94 @@ +" vim: et sw=2 sts=2 + +scriptencoding utf-8 + +" Init: values {{{1 +if get(g:, 'signify_sign_show_text', 1) + let s:sign_add = get(g:, 'signify_sign_add', '+') + let s:sign_delete_first_line = get(g:, 'signify_sign_delete_first_line', '‾') + let s:sign_change = get(g:, 'signify_sign_change', '!') + let s:sign_changedelete = get(g:, 'signify_sign_changedelete', s:sign_change) +else + let s:sign_add = ' ' + let s:sign_delete_first_line = ' ' + let s:sign_change = ' ' + let s:sign_changedelete = ' ' +endif + +let s:sign_show_count = get(g:, 'signify_sign_show_count', 1) + +" Function: #setup {{{1 +function! sy#highlight#setup() abort + highlight default link SignifyLineAdd DiffAdd + highlight default link SignifyLineDelete DiffDelete + highlight default link SignifyLineDeleteFirstLine SignifyLineDelete + highlight default link SignifyLineChange DiffChange + highlight default link SignifyLineChangeDelete SignifyLineChange + + highlight default link SignifySignAdd DiffAdd + highlight default link SignifySignDelete DiffDelete + highlight default link SignifySignDeleteFirstLine SignifySignDelete + highlight default link SignifySignChange DiffChange + highlight default link SignifySignChangeDelete SignifySignChange +endfunction + +" Function: #line_enable {{{1 +function! sy#highlight#line_enable() abort + execute 'sign define SignifyAdd text='. s:sign_add 'texthl=SignifySignAdd linehl=SignifyLineAdd' + execute 'sign define SignifyChange text='. s:sign_change 'texthl=SignifySignChange linehl=SignifyLineChange' + execute 'sign define SignifyRemoveFirstLine text='. s:sign_delete_first_line 'texthl=SignifySignDeleteFirstLine linehl=SignifyLineDeleteFirstLine' + + if s:sign_show_count + let s:sign_changedelete = substitute(s:sign_changedelete, '^.\zs.*', '', '') + for n in range(1, 9) + execute 'sign define SignifyChangeDelete'. n 'text='. s:sign_changedelete . n 'texthl=SignifySignChangeDelete linehl=SignifyLineChangeDelete' + endfor + execute 'sign define SignifyChangeDeleteMore text='. s:sign_changedelete .'> texthl=SignifySignChangeDelete linehl=SignifyLineChangeDelete' + else + for n in range(1, 9) + execute 'sign define SignifyChangeDelete'. n 'text='. s:sign_changedelete 'texthl=SignifySignChangeDelete linehl=SignifyLineChangeDelete' + endfor + execute 'sign define SignifyChangeDeleteMore text='. s:sign_changedelete 'texthl=SignifySignChangeDelete linehl=SignifyLineChangeDelete' + endif + + let g:signify_line_highlight = 1 +endfunction + +" Function: #line_disable {{{1 +function! sy#highlight#line_disable() abort + execute 'sign define SignifyAdd text='. s:sign_add 'texthl=SignifySignAdd linehl=' + execute 'sign define SignifyChange text='. s:sign_change 'texthl=SignifySignChange linehl=' + execute 'sign define SignifyRemoveFirstLine text='. s:sign_delete_first_line 'texthl=SignifySignDeleteFirstLine linehl=' + + if s:sign_show_count + while strwidth(s:sign_changedelete) > 1 + let s:sign_changedelete = substitute(s:sign_changedelete, '.', '', '') + endwhile + for n in range(1, 9) + execute 'sign define SignifyChangeDelete'. n 'text='. s:sign_changedelete . n 'texthl=SignifySignChangeDelete linehl=' + endfor + execute 'sign define SignifyChangeDeleteMore text='. s:sign_changedelete .'> texthl=SignifySignChangeDelete linehl=' + else + for n in range(1, 9) + execute 'sign define SignifyChangeDelete'. n 'text='. s:sign_changedelete 'texthl=SignifySignChangeDelete linehl=' + endfor + execute 'sign define SignifyChangeDeleteMore text='. s:sign_changedelete 'texthl=SignifySignChangeDelete linehl=' + endif + + let g:signify_line_highlight = 0 +endfunction + +" Function: #line_toggle {{{1 +function! sy#highlight#line_toggle() abort + if get(g:, 'signify_line_highlight') + call sy#highlight#line_disable() + else + call sy#highlight#line_enable() + endif + + redraw! + call sy#start() +endfunction +" }}} + +call sy#highlight#setup() diff --git a/start/signify/autoload/sy/jump.vim b/start/signify/autoload/sy/jump.vim new file mode 100644 index 0000000..69756b1 --- /dev/null +++ b/start/signify/autoload/sy/jump.vim @@ -0,0 +1,29 @@ +" vim: et sw=2 sts=2 + +scriptencoding utf-8 + +" Function: #next_hunk {{{1 +function! sy#jump#next_hunk(count) + execute sy#util#return_if_no_changes() + + let lnum = line('.') + let hunks = filter(copy(b:sy.hunks), 'v:val.start > lnum') + let hunk = get(hunks, a:count - 1, get(hunks, -1, {})) + + if !empty(hunk) + execute 'sign jump '. hunk.ids[0] .' buffer='. b:sy.buffer + endif +endfunction + +" Function: #prev_hunk {{{1 +function! sy#jump#prev_hunk(count) + execute sy#util#return_if_no_changes() + + let lnum = line('.') + let hunks = filter(copy(b:sy.hunks), 'v:val.start < lnum') + let hunk = get(hunks, 0 - a:count, get(hunks, 0, {})) + + if !empty(hunk) + execute 'sign jump '. hunk.ids[0] .' buffer='. b:sy.buffer + endif +endfunction diff --git a/start/signify/autoload/sy/repo.vim b/start/signify/autoload/sy/repo.vim new file mode 100644 index 0000000..64bf07a --- /dev/null +++ b/start/signify/autoload/sy/repo.vim @@ -0,0 +1,512 @@ +" vim: et sw=2 sts=2 + +scriptencoding utf-8 + +" Function: #detect {{{1 +function! sy#repo#detect() abort + for vcs in s:vcs_list + let b:sy.detecting += 1 + call sy#repo#get_diff_start(vcs) + endfor +endfunction + +" Function: s:callback_nvim_stdout{{{1 +function! s:callback_nvim_stdout(_job_id, data, _event) dict abort + if empty(self.stdoutbuf) || empty(self.stdoutbuf[-1]) + let self.stdoutbuf += a:data + else + let self.stdoutbuf = self.stdoutbuf[:-2] + \ + [self.stdoutbuf[-1] . get(a:data, 0, '')] + \ + a:data[1:] + endif +endfunction + +" Function: s:callback_nvim_exit {{{1 +function! s:callback_nvim_exit(_job_id, exitval, _event) dict abort + call s:job_exit(self.bufnr, self.vcs, a:exitval, self.stdoutbuf) +endfunction + +" Function: s:callback_vim_stdout {{{1 +function! s:callback_vim_stdout(_job_id, data) dict abort + let self.stdoutbuf += [a:data] +endfunction + +" Function: s:callback_vim_close {{{1 +function! s:callback_vim_close(channel) dict abort + let job = ch_getjob(a:channel) + while 1 + if job_status(job) == 'dead' + let exitval = job_info(job).exitval + break + endif + sleep 10m + endwhile + call s:job_exit(self.bufnr, self.vcs, exitval, self.stdoutbuf) +endfunction + +" Function: s:job_exit {{{1 +function! s:job_exit(bufnr, vcs, exitval, diff) abort + call sy#verbose('job_exit()', a:vcs) + let sy = getbufvar(a:bufnr, 'sy') + if empty(sy) + call sy#verbose(printf('No b:sy found for %s', bufname(a:bufnr)), a:vcs) + return + elseif !empty(sy.updated_by) && sy.updated_by != a:vcs + call sy#verbose(printf('Signs already got updated by %s.', sy.updated_by), a:vcs) + return + elseif empty(sy.vcs) && sy.active + let sy.detecting -= 1 + endif + call sy#repo#get_diff_{a:vcs}(sy, a:exitval, a:diff) + call setbufvar(a:bufnr, 'sy_job_id_'.a:vcs, 0) +endfunction + +" Function: sy#get_diff_start {{{1 +function! sy#repo#get_diff_start(vcs) abort + call sy#verbose('get_diff_start()', a:vcs) + + let job_id = get(b:, 'sy_job_id_'.a:vcs) + " Neovim + if has('nvim') + if job_id + silent! call jobstop(job_id) + endif + + let [cmd, options] = s:initialize_job(a:vcs) + let [cwd, chdir] = sy#util#chdir() + + call sy#verbose(['CMD: '. string(cmd), 'CMD DIR: '. b:sy.info.dir, 'ORIG DIR: '. cwd], a:vcs) + + try + execute chdir fnameescape(b:sy.info.dir) + catch + echohl ErrorMsg + echomsg 'signify: Changing directory failed: '. b:sy.info.dir + echohl NONE + return + endtry + let b:sy_job_id_{a:vcs} = jobstart(cmd, extend(options, { + \ 'on_stdout': function('s:callback_nvim_stdout'), + \ 'on_exit': function('s:callback_nvim_exit'), + \ })) + execute chdir fnameescape(cwd) + + " Newer Vim + elseif has('patch-7.4.1967') + if type(job_id) != type(0) + silent! call job_stop(job_id) + endif + + let [cmd, options] = s:initialize_job(a:vcs) + let [cwd, chdir] = sy#util#chdir() + + call sy#verbose(['CMD: '. string(cmd), 'CMD DIR: '. b:sy.info.dir, 'ORIG DIR: '. cwd], a:vcs) + + try + execute chdir fnameescape(b:sy.info.dir) + catch + echohl ErrorMsg + echomsg 'signify: Changing directory failed: '. b:sy.info.dir + echohl NONE + return + endtry + let opts = { + \ 'in_io': 'null', + \ 'out_cb': function('s:callback_vim_stdout', options), + \ 'close_cb': function('s:callback_vim_close', options), + \ } + let b:sy_job_id_{a:vcs} = job_start(cmd, opts) + execute chdir fnameescape(cwd) + + " Older Vim + else + let diff = split(s:run(a:vcs), '\n') + call sy#repo#get_diff_{a:vcs}(b:sy, v:shell_error, diff) + endif +endfunction + +" Function: s:get_diff_end {{{1 +function! s:get_diff_end(sy, found_diff, vcs, diff) abort + call sy#verbose('get_diff_end()', a:vcs) + if a:found_diff + if index(a:sy.vcs, a:vcs) == -1 + let a:sy.vcs += [a:vcs] + endif + call sy#set_signs(a:sy, a:vcs, a:diff) + else + call sy#verbose('No valid diff found. Disabling this VCS.', a:vcs) + endif +endfunction + +" Function: #get_diff_git {{{1 +function! sy#repo#get_diff_git(sy, exitval, diff) abort + call sy#verbose('get_diff_git()', 'git') + let [found_diff, diff] = a:exitval ? [0, []] : [1, a:diff] + call s:get_diff_end(a:sy, found_diff, 'git', diff) +endfunction + +" Function: #get_diff_hg {{{1 +function! sy#repo#get_diff_hg(sy, exitval, diff) abort + call sy#verbose('get_diff_hg()', 'hg') + let [found_diff, diff] = a:exitval ? [0, []] : [1, a:diff] + call s:get_diff_end(a:sy, found_diff, 'hg', diff) +endfunction + +" Function: #get_diff_svn {{{1 +function! sy#repo#get_diff_svn(sy, exitval, diff) abort + call sy#verbose('get_diff_svn()', 'svn') + let [found_diff, diff] = a:exitval ? [0, []] : [1, a:diff] + call s:get_diff_end(a:sy, found_diff, 'svn', diff) +endfunction + +" Function: #get_diff_bzr {{{1 +function! sy#repo#get_diff_bzr(sy, exitval, diff) abort + call sy#verbose('get_diff_bzr()', 'bzr') + let [found_diff, diff] = (a:exitval =~ '[012]') ? [1, a:diff] : [0, []] + call s:get_diff_end(a:sy, found_diff, 'bzr', diff) +endfunction + +" Function: #get_diff_darcs {{{1 +function! sy#repo#get_diff_darcs(sy, exitval, diff) abort + call sy#verbose('get_diff_darcs()', 'darcs') + let [found_diff, diff] = a:exitval ? [0, []] : [1, a:diff] + call s:get_diff_end(a:sy, found_diff, 'darcs', diff) +endfunction + +" Function: #get_diff_fossil {{{1 +function! sy#repo#get_diff_fossil(sy, exitval, diff) abort + call sy#verbose('get_diff_fossil()', 'fossil') + let [found_diff, diff] = a:exitval ? [0, []] : [1, a:diff] + call s:get_diff_end(a:sy, found_diff, 'fossil', diff) +endfunction + +" Function: #get_diff_cvs {{{1 +function! sy#repo#get_diff_cvs(sy, exitval, diff) abort + call sy#verbose('get_diff_cvs()', 'cvs') + let [found_diff, diff] = [0, []] + if a:exitval == 1 + for diffline in a:diff + if diffline =~ '^+++' + let [found_diff, diff] = [1, a:diff] + break + endif + endfor + elseif a:exitval == 0 && len(a:diff) == 0 + let found_diff = 1 + endif + call s:get_diff_end(a:sy, found_diff, 'cvs', diff) +endfunction + +" Function: #get_diff_rcs {{{1 +function! sy#repo#get_diff_rcs(sy, exitval, diff) abort + call sy#verbose('get_diff_rcs()', 'rcs') + let [found_diff, diff] = a:exitval == 2 ? [0, []] : [1, a:diff] + call s:get_diff_end(a:sy, found_diff, 'rcs', diff) +endfunction + +" Function: #get_diff_accurev {{{1 +function! sy#repo#get_diff_accurev(sy, exitval, diff) abort + call sy#verbose('get_diff_accurev()', 'accurev') + let [found_diff, diff] = (a:exitval >= 2) ? [0, []] : [1, a:diff] + call s:get_diff_end(a:sy, found_diff, 'accurev', diff) +endfunction + +" Function: #get_diff_perforce {{{1 +function! sy#repo#get_diff_perforce(sy, exitval, diff) abort + call sy#verbose('get_diff_perforce()', 'perforce') + let [found_diff, diff] = a:exitval ? [0, []] : [1, a:diff] + call s:get_diff_end(a:sy, found_diff, 'perforce', diff) +endfunction + +" Function: #get_diff_tfs {{{1 +function! sy#repo#get_diff_tfs(sy, exitval, diff) abort + call sy#verbose('get_diff_tfs()', 'tfs') + let [found_diff, diff] = a:exitval ? [0, []] : [1, s:strip_context(a:diff)] + call s:get_diff_end(a:sy, found_diff, 'tfs', diff) +endfunction + +" Function: #get_stats {{{1 +function! sy#repo#get_stats() abort + return exists('b:sy') ? b:sy.stats : [-1, -1, -1] +endfunction + +" Function: #debug_detection {{{1 +function! sy#repo#debug_detection() + if !exists('b:sy') + echomsg 'signify: I cannot detect any changes!' + return + endif + + for vcs in s:vcs_list + let cmd = s:expand_cmd(vcs, g:signify_vcs_cmds) + echohl Statement + echo cmd + echo repeat('=', len(cmd)) + echohl NONE + + let diff = s:run(vcs) + if v:shell_error + echohl ErrorMsg + echo diff + echohl NONE + else + echo empty(diff) ? "" : diff + endif + echo "\n" + endfor +endfunction + +" Function: #diffmode {{{1 +function! sy#repo#diffmode(do_tab) abort + execute sy#util#return_if_no_changes() + + let vcs = b:sy.updated_by + if !has_key(g:signify_vcs_cmds_diffmode, vcs) + echomsg 'SignifyDiff has no support for: '. vcs + echomsg 'Open an issue for it at: https://github.com/mhinz/vim-signify/issues' + return + endif + let cmd = s:expand_cmd(vcs, g:signify_vcs_cmds_diffmode) + call sy#verbose('SignifyDiff: '. cmd, vcs) + let ft = &filetype + let fenc = &fenc + if a:do_tab + tabedit % + endif + diffthis + let [cwd, chdir] = sy#util#chdir() + try + execute chdir fnameescape(b:sy.info.dir) + leftabove vnew + if has('iconv') + silent put =iconv(system(cmd), fenc, &enc) + else + silent put =system(cmd) + endif + finally + execute chdir fnameescape(cwd) + endtry + silent 1delete + set buftype=nofile bufhidden=wipe nomodified + let &filetype = ft + diffthis + wincmd p + normal! ]czt +endfunction + +" Function: s:initialize_job {{{1 +function! s:initialize_job(vcs) abort + let vcs_cmd = s:expand_cmd(a:vcs, g:signify_vcs_cmds) + if has('win32') + if has('nvim') + let cmd = &shell =~ '\v%(cmd|powershell)' ? vcs_cmd : ['sh', '-c', vcs_cmd] + else + if &shell =~ 'cmd' + let cmd = vcs_cmd + elseif empty(&shellxquote) + let cmd = join([&shell, &shellcmdflag, &shellquote, vcs_cmd, &shellquote]) + else + let cmd = join([&shell, &shellcmdflag, &shellxquote, vcs_cmd, &shellxquote]) + endif + endif + else + let cmd = ['sh', '-c', vcs_cmd] + endif + let options = { + \ 'stdoutbuf': [], + \ 'vcs': a:vcs, + \ 'bufnr': bufnr('%'), + \ } + return [cmd, options] +endfunction + +" Function: s:get_vcs_path {{{1 +function! s:get_vcs_path(vcs) abort + return (a:vcs =~# '\v(git|cvs|accurev|tfs)') ? b:sy.info.file : b:sy.info.path +endfunction + +" Function: s:expand_cmd {{{1 +function! s:expand_cmd(vcs, vcs_cmds) abort + let cmd = a:vcs_cmds[a:vcs] + let cmd = s:replace(cmd, '%f', s:get_vcs_path(a:vcs)) + let cmd = s:replace(cmd, '%d', s:difftool) + let cmd = s:replace(cmd, '%n', s:devnull) + return cmd +endfunction + +" Function: s:run {{{1 +function! s:run(vcs) + let [cwd, chdir] = sy#util#chdir() + try + execute chdir fnameescape(b:sy.info.dir) + let ret = system(s:expand_cmd(a:vcs, g:signify_vcs_cmds)) + catch + " This exception message can be seen via :SignifyDebugUnknown. + " E.g. unquoted VCS programs in vcd_cmds can lead to E484. + let ret = v:exception .' at '. v:throwpoint + finally + execute chdir fnameescape(cwd) + return ret + endtry +endfunction + +" Function: s:replace {{{1 +function! s:replace(cmd, pat, sub) + let parts = split(a:cmd, a:pat, 1) + return join(parts, a:sub) +endfunction + +" Function: s:strip_context {{{1 +function! s:strip_context(context) + let diff = [] + let hunk = [] + let state = 0 + let lines = a:context + let linenr = 0 + + while linenr < len(lines) + let line = lines[linenr] + + if state == 0 + if line =~ "^@@ " + let tokens = matchlist(line, '^@@ -\v(\d+),?(\d*) \+(\d+),?(\d*)') + let old_line = str2nr(tokens[1]) + let new_line = str2nr(tokens[3]) + let old_count = empty(tokens[2]) ? 1 : str2nr(tokens[2]) + let new_count = empty(tokens[4]) ? 1 : str2nr(tokens[4]) + let hunk = [] + let state = 1 + else + call add(diff,line) + endif + let linenr += 1 + elseif index([1,2,3],state) >= 0 && index(['\','/'],line[0]) >= 0 + let linenr += 1 + call add(hunk,line) + elseif state == 1 + if line[0] == ' ' + let old_line += 1 + let new_line += 1 + let old_count -= 1 + let new_count -= 1 + let linenr += 1 + else + let old_count_part = 0 + let new_count_part = 0 + let state = 2 + endif + elseif state == 2 + if line[0] == '-' + call add(hunk,line) + let old_count_part += 1 + let linenr += 1 + else + let state = 3 + endif + elseif state == 3 + if line[0] == '+' + call add(hunk,line) + let new_count_part += 1 + let linenr += 1 + else + call add(diff, printf("@@ -%d%s +%d%s @@",(old_count_part == 0 && old_line > 0) ? old_line -1 : old_line, old_count_part == 1 ? "" : printf(",%d", old_count_part), (new_count_part == 0 && new_line > 0) ? new_line - 1 : new_line, new_count_part == 1 ? "" : printf(",%d", new_count_part))) + let diff += hunk + let hunk = [] + let old_count -= old_count_part + let new_count -= new_count_part + let old_line += old_count_part + let new_line += new_count_part + let state = 1 + endif + endif + + if state > 0 && new_count <= 0 && old_count <= 0 + if len(hunk) > 0 + call add(diff, printf("@@ -%d%s +%d%s @@",(old_count_part == 0 && old_line > 0) ? old_line -1 : old_line, old_count_part == 1 ? "" : printf(",%d", old_count_part), (new_count_part == 0 && new_line > 0) ? new_line - 1 : new_line, new_count_part == 1 ? "" : printf(",%d", new_count_part))) + let diff = diff + hunk + let hunk = [] + endif + let state = 0 + endif + endwhile + if len(hunk) > 0 + call add(diff, printf("@@ -%d%s +%d%s @@",(old_count_part == 0 && old_line > 0) ? old_line -1 : old_line, old_count_part == 1 ? "" : printf(",%d", old_count_part), (new_count_part == 0 && new_line > 0) ? new_line - 1 : new_line, new_count_part == 1 ? "" : printf(",%d", new_count_part))) + let diff = diff + hunk + let hunk = [] + endif + return diff +endfunction + +" Variables {{{1 +let s:difftool = get(g:, 'signify_difftool', 'diff') +if executable(s:difftool) + let s:vcs_dict = { + \ 'git': 'git', + \ 'hg': 'hg', + \ 'svn': 'svn', + \ 'darcs': 'darcs', + \ 'bzr': 'bzr', + \ 'fossil': 'fossil', + \ 'cvs': 'cvs', + \ 'rcs': 'rcsdiff', + \ 'accurev': 'accurev', + \ 'perforce': 'p4', + \ 'tfs': 'tf' + \ } +else + call sy#verbose('No "diff" executable found. Disable support for svn, darcs, bzr.') + let s:vcs_dict = { + \ 'git': 'git', + \ 'hg': 'hg', + \ 'fossil': 'fossil', + \ 'cvs': 'cvs', + \ 'rcs': 'rcsdiff', + \ 'accurev': 'accurev', + \ 'perforce': 'p4', + \ 'tfs': 'tf' + \ } +endif + +let s:vcs_list = get(g:, 'signify_vcs_list', []) +if empty(s:vcs_list) + let s:vcs_list = keys(filter(s:vcs_dict, 'executable(v:val)')) +endif + +let s:default_vcs_cmds = { + \ 'git': 'git diff --no-color --no-ext-diff -U0 -- %f', + \ 'hg': 'hg diff --color=never --config aliases.diff= --nodates -U0 -- %f', + \ 'svn': 'svn diff --diff-cmd %d -x -U0 -- %f', + \ 'bzr': 'bzr diff --using %d --diff-options=-U0 -- %f', + \ 'darcs': 'darcs diff --no-pause-for-gui --no-unified --diff-opts=-U0 -- %f', + \ 'fossil': 'fossil diff --unified -c 0 -- %f', + \ 'cvs': 'cvs diff -U0 -- %f', + \ 'rcs': 'rcsdiff -U0 %f 2>%n', + \ 'accurev': 'accurev diff %f -- -U0', + \ 'perforce': 'p4 info '. sy#util#shell_redirect('%n') . (has('win32') ? ' &&' : ' && env P4DIFF= P4COLORS=') .' p4 diff -du0 %f', + \ 'tfs': 'tf diff -version:W -noprompt -format:Unified %f' + \ } + +let s:default_vcs_cmds_diffmode = { + \ 'git': 'git show HEAD:./%f', + \ 'hg': 'hg cat %f', + \ 'svn': 'svn cat %f', + \ 'bzr': 'bzr cat %f', + \ 'darcs': 'darcs show contents -- %f', + \ 'fossil': 'fossil cat %f', + \ 'cvs': 'cvs up -p -- %f 2>%n', + \ 'perforce': 'p4 print %f', + \ } + +if exists('g:signify_vcs_cmds') + call extend(g:signify_vcs_cmds, s:default_vcs_cmds, 'keep') +else + let g:signify_vcs_cmds = s:default_vcs_cmds +endif +if exists('g:signify_vcs_cmds_diffmode') + call extend(g:signify_vcs_cmds_diffmode, s:default_vcs_cmds_diffmode, 'keep') +else + let g:signify_vcs_cmds_diffmode = s:default_vcs_cmds_diffmode +endif + +let s:difftool = sy#util#escape(s:difftool) +let s:devnull = has('win32') || has ('win64') ? 'NUL' : '/dev/null' diff --git a/start/signify/autoload/sy/sign.vim b/start/signify/autoload/sy/sign.vim new file mode 100644 index 0000000..23b7038 --- /dev/null +++ b/start/signify/autoload/sy/sign.vim @@ -0,0 +1,275 @@ +" vim: et sw=2 sts=2 + +scriptencoding utf-8 + +" Init: values {{{1 +if get(g:, 'signify_sign_show_text', 1) + let s:sign_delete = get(g:, 'signify_sign_delete', '_') +else + let s:sign_delete = ' ' +endif + +let s:sign_show_count = get(g:, 'signify_sign_show_count', 1) +let s:delete_highlight = ['', 'SignifyLineDelete'] + +" Function: #id_next {{{1 +function! sy#sign#id_next(sy) abort + let id = a:sy.signid + let a:sy.signid += 1 + return id +endfunction + +" Function: #get_current_signs {{{1 +function! sy#sign#get_current_signs(sy) abort + let a:sy.internal = {} + let a:sy.external = {} + + let signlist = sy#util#execute('sign place buffer='. a:sy.buffer) + + for signline in split(signlist, '\n')[2:] + let tokens = matchlist(signline, '\v^\s+\S+\=(\d+)\s+\S+\=(\d+)\s+\S+\=(.*)$') + let line = str2nr(tokens[1]) + let id = str2nr(tokens[2]) + let type = tokens[3] + + if type =~# '^Signify' + " Handle ambiguous signs. Assume you have signs on line 3 and 4. + " Removing line 3 would lead to the second sign to be shifted up + " to line 3. Now there are still 2 signs, both one line 3. + if has_key(a:sy.internal, line) + execute 'sign unplace' a:sy.internal[line].id 'buffer='.a:sy.buffer + endif + let a:sy.internal[line] = { 'type': type, 'id': id } + else + let a:sy.external[line] = id + endif + endfor +endfunction + + +" Function: #process_diff {{{1 +function! sy#sign#process_diff(sy, vcs, diff) abort + let a:sy.signtable = {} + let a:sy.hunks = [] + let [added, modified, deleted] = [0, 0, 0] + + call sy#sign#get_current_signs(a:sy) + + " Determine where we have to put our signs. + for line in filter(a:diff, 'v:val =~ "^@@ "') + let a:sy.lines = [] + let ids = [] + + let tokens = matchlist(line, '^@@ -\v(\d+),?(\d*) \+(\d+),?(\d*)') + + let old_line = str2nr(tokens[1]) + let new_line = str2nr(tokens[3]) + + let old_count = empty(tokens[2]) ? 1 : str2nr(tokens[2]) + let new_count = empty(tokens[4]) ? 1 : str2nr(tokens[4]) + + " Workaround for non-conventional diff output in older Fossil versions: + " https://fossil-scm.org/forum/forumpost/834ce0f1e1 + " Fixed as of: https://fossil-scm.org/index.html/info/7fd2a3652ea7368a + if a:vcs == 'fossil' && new_line == 0 + let new_line = old_line - 1 - deleted + endif + + " 2 lines added: + + " @@ -5,0 +6,2 @@ this is line 5 + " +this is line 5 + " +this is line 5 + if (old_count == 0) && (new_count >= 1) + let added += new_count + let offset = 0 + while offset < new_count + let line = new_line + offset + let offset += 1 + if s:external_sign_present(a:sy, line) | continue | endif + call add(ids, s:add_sign(a:sy, line, 'SignifyAdd')) + endwhile + + " 2 lines removed: + + " @@ -6,2 +5,0 @@ this is line 5 + " -this is line 6 + " -this is line 7 + elseif (old_count >= 1) && (new_count == 0) + if s:external_sign_present(a:sy, new_line) | continue | endif + let deleted += old_count + if new_line == 0 + call add(ids, s:add_sign(a:sy, 1, 'SignifyRemoveFirstLine')) + elseif s:sign_show_count + let text = s:sign_delete . (old_count <= 99 ? old_count : '>') + while strwidth(text) > 2 + let text = substitute(text, '.', '', '') + endwhile + call add(ids, s:add_sign(a:sy, new_line, 'SignifyDelete'. old_count, text)) + else + call add(ids, s:add_sign(a:sy, new_line, 'SignifyDeleteMore', s:sign_delete)) + endif + + " 2 lines changed: + + " @@ -5,2 +5,2 @@ this is line 4 + " -this is line 5 + " -this is line 6 + " +this os line 5 + " +this os line 6 + elseif old_count == new_count + let modified += old_count + let offset = 0 + while offset < new_count + let line = new_line + offset + let offset += 1 + if s:external_sign_present(a:sy, line) | continue | endif + call add(ids, s:add_sign(a:sy, line, 'SignifyChange')) + endwhile + else + + " 2 lines changed; 2 lines removed: + + " @@ -5,4 +5,2 @@ this is line 4 + " -this is line 5 + " -this is line 6 + " -this is line 7 + " -this is line 8 + " +this os line 5 + " +this os line 6 + if old_count > new_count + let modified += new_count + let removed = old_count - new_count + let deleted += removed + let offset = 0 + while offset < new_count - 1 + let line = new_line + offset + let offset += 1 + if s:external_sign_present(a:sy, line) | continue | endif + call add(ids, s:add_sign(a:sy, line, 'SignifyChange')) + endwhile + let line = new_line + offset + if s:external_sign_present(a:sy, line) | continue | endif + call add(ids, s:add_sign(a:sy, line, (removed > 9) + \ ? 'SignifyChangeDeleteMore' + \ : 'SignifyChangeDelete'. removed)) + + " lines changed and added: + + " @@ -5 +5,3 @@ this is line 4 + " -this is line 5 + " +this os line 5 + " +this is line 42 + " +this is line 666 + else + let modified += old_count + let offset = 0 + while offset < old_count + let line = new_line + offset + let offset += 1 + if s:external_sign_present(a:sy, line) | continue | endif + call add(ids, s:add_sign(a:sy, line, 'SignifyChange')) + endwhile + while offset < new_count + let added += 1 + let line = new_line + offset + let offset += 1 + if s:external_sign_present(a:sy, line) | continue | endif + call add(ids, s:add_sign(a:sy, line, 'SignifyAdd')) + endwhile + endif + endif + + if !empty(ids) + call add(a:sy.hunks, { + \ 'ids' : ids, + \ 'start': a:sy.lines[0], + \ 'end' : a:sy.lines[-1] }) + endif + endfor + + " Remove obsoleted signs. + for line in filter(keys(a:sy.internal), '!has_key(a:sy.signtable, v:val)') + execute 'sign unplace' a:sy.internal[line].id 'buffer='.a:sy.buffer + endfor + + if has('gui_macvim') && has('gui_running') && mode() == 'n' + " MacVim needs an extra kick in the butt, when setting signs from the + " exit handler. :redraw would trigger a "hanging cursor" issue. + call feedkeys("\", 'n') + endif + + if empty(a:sy.updated_by) && empty(a:sy.hunks) + call sy#verbose('Successful exit value, but no diff. Keep VCS for time being.', a:vcs) + return + endif + + call sy#verbose('Signs updated.', a:vcs) + let a:sy.updated_by = a:vcs + if len(a:sy.vcs) > 1 + call sy#verbose('Disable all other VCS.', a:vcs) + let a:sy.vcs = [a:vcs] + endif + + let a:sy.stats = [added, modified, deleted] +endfunction + +" Function: #remove_all_signs {{{1 +function! sy#sign#remove_all_signs(bufnr) abort + let sy = getbufvar(a:bufnr, 'sy') + + for hunk in sy.hunks + for id in hunk.ids + execute 'sign unplace' id 'buffer='.a:bufnr + endfor + endfor + + let sy.hunks = [] +endfunction + +" Function: s:add_sign {{{1 +function! s:add_sign(sy, line, type, ...) abort + call add(a:sy.lines, a:line) + let a:sy.signtable[a:line] = 1 + + if has_key(a:sy.internal, a:line) + " There is a sign on this line already. + if a:type == a:sy.internal[a:line].type + " Keep current sign since the new one is of the same type. + return a:sy.internal[a:line].id + else + " Update sign by overwriting the ID of the current sign. + let id = a:sy.internal[a:line].id + endif + endif + + if !exists('id') + let id = sy#sign#id_next(a:sy) + endif + + if a:type =~# 'SignifyDelete' + execute printf('sign define %s text=%s texthl=SignifySignDelete linehl=%s', + \ a:type, + \ a:1, + \ s:delete_highlight[g:signify_line_highlight]) + endif + execute printf('sign place %d line=%d name=%s buffer=%s', + \ id, + \ a:line, + \ a:type, + \ a:sy.buffer) + + return id +endfunction + +" Function: s:external_sign_present {{{1 +function! s:external_sign_present(sy, line) abort + if has_key(a:sy.external, a:line) + if has_key(a:sy.internal, a:line) + " Remove Sy signs from lines with other signs. + execute 'sign unplace' a:sy.internal[a:line].id 'buffer='.a:sy.buffer + endif + return 1 + endif +endfunction + diff --git a/start/signify/autoload/sy/util.vim b/start/signify/autoload/sy/util.vim new file mode 100644 index 0000000..43a9cc6 --- /dev/null +++ b/start/signify/autoload/sy/util.vim @@ -0,0 +1,109 @@ +" vim: et sw=2 sts=2 + +scriptencoding utf-8 + +" Function: #escape {{{1 +function! sy#util#escape(path) abort + if exists('+shellslash') + let old_ssl = &shellslash + if fnamemodify(&shell, ':t') == 'cmd.exe' + set noshellslash + else + set shellslash + endif + endif + + let path = shellescape(a:path) + + if exists('old_ssl') + let &shellslash = old_ssl + endif + + return path +endfunction + +" Function: #refresh_windows {{{1 +function! sy#util#refresh_windows() abort + if exists('*win_getid') + let winid = win_getid() + else + let winnr = winnr() + endif + + if !get(g:, 'signify_cmdwin_active') + keepjumps windo if exists('b:sy') | call sy#start() | endif + endif + + if exists('winid') + call win_gotoid(winid) + else + execute winnr .'wincmd w' + endif +endfunction + +" Function: #hunk_text_object {{{1 +function! sy#util#hunk_text_object(emptylines) abort + execute sy#util#return_if_no_changes() + + let lnum = line('.') + let hunks = filter(copy(b:sy.hunks), 'v:val.start <= lnum && v:val.end >= lnum') + + if empty(hunks) + echomsg 'signify: Here is no hunk.' + return + endif + + execute hunks[0].start + normal! V + + if a:emptylines + let lnum = hunks[0].end + while getline(lnum+1) =~ '^$' + let lnum += 1 + endwhile + execute lnum + else + execute hunks[0].end + endif +endfunction + +" Function: #shell_redirect {{{1 +function! sy#util#shell_redirect(path) abort + " if shellredir contains a %s it is replaced with the path + " otherwise, just append it (from :help shellredir: + " The name of the temporary file can be represented by '%s' if necessary + " (the file name is appended automatically if no %s appears in the value + " of this option) + if &shellredir =~# '%s' + return substitute(&shellredir, '\C%s', a:path, 'g') + else + return &shellredir .' '. a:path + endif +endfunction + +" Function: #chdir {{{1 +function! sy#util#chdir() abort + let chdir = haslocaldir() + \ ? 'lcd' + \ : (exists(':tcd') && haslocaldir(-1, 0)) ? 'tcd' : 'cd' + return [getcwd(), chdir] +endfunction + +" Function: #has_changes {{{1 +function! sy#util#return_if_no_changes() abort + if !exists('b:sy') || empty(b:sy.hunks) + echomsg 'signify: There are no changes.' + return 'return' + endif + return '' +endfunction + +" Function: #execute {{{1 +function! sy#util#execute(cmd) abort + let lang = v:lang + redir => output + silent! execute a:cmd + redir END + silent! execute 'language message' lang + return output +endfunction diff --git a/start/signify/doc/signify.txt b/start/signify/doc/signify.txt new file mode 100644 index 0000000..4d4e07d --- /dev/null +++ b/start/signify/doc/signify.txt @@ -0,0 +1,689 @@ +*signify.txt* Indicate changed lines within a file using a VCS. +*signify* +> + ___ + __ __ /'___\ + ____/\_\ __ ___ /\_\/\ \__/ __ __ + /',__\/\ \ /'_ `\ /' _ `\/\ \ \ ,__\/\ \/\ \ + /\__, `\ \ \/\ \L\ \/\ \/\ \ \ \ \ \_/\ \ \_\ \ + \/\____/\ \_\ \____ \ \_\ \_\ \_\ \_\ \/`____ \ + \/___/ \/_/\/___L\ \/_/\/_/\/_/\/_/ `/___/> \ + /\____/ /\___/ + \_/__/ \/__/ +< + by Marco Hinz~ + +============================================================================== +TOC *signify-contents* + + INTRO .......................... |signify-intro| + MODUS OPERANDI ................. |signify-modus-operandi| + DEBUG .......................... |signify-debug| + SIGNS .......................... |signify-signs| + OPTIONS ........................ |signify-options| + COMMANDS ....................... |signify-commands| + AUTOCOMMAND .................... |signify-autocommand| + MAPPINGS ....................... |signify-mappings| + COLORS ......................... |signify-colors| + FAQ ............................ |signify-faq| + EXAMPLE ........................ |signify-example| + +============================================================================== +INTRO *signify-intro* + +Signify uses the sign column to indicate added, modified and removed lines +based on the data of an underlying version control system. + +Supported VCS:~ +> + git + mercurial + darcs + bzr + subversion + cvs + rcs + fossil + accurev + perforce + tfs +< +============================================================================== +MODUS OPERANDI *signify-modus-operandi* + +When you open a new buffer, Sy registers it as `active` and tries to figure out +whether the underlying file is controlled by a VCS (version control system) or +not. + +For that, it asynchronously tries all the `diff` subcommands of all the VCS +tools that are supported and executable. It's recommended to set +|g:signify_vcs_list| to limit the VCS to test for. + +If one of the checks produces a proper diff, that VCS will automatically be +used for all successive calls to Sy. + +If none of the checks produces a proper diff, the VCS will be set to `unknown`. +The next time Sy gets run, the buffer will be marked as `inactive`, so it won't +look for changes anymore. + +Or you set |g:signify_disable_by_default|, which registers all new buffers as +`inactive`, and enable Sy on demand using |signify-:SignifyToggle|. + +By default, Sy is rather conservative and only updates signs when opening a +new buffer or writing it. If you want more agressive sign updating, have a +look at |g:signify_realtime|. + +Use |signify-:SignifyList| to list all buffers managed by Sy and their current +state. + +============================================================================== +DEBUG *signify-debug* + +If signs aren't showing up as expected, see if |signify-:SignifyDebug| shows +anything suspicious. It will try all VCS and shows either errors or a diff for +each VCS. + +If the output looks fine though, create an issue on Github: + + https://github.com/mhinz/vim-signify/issues/new + +Make sure to mention your Vim version and which Sy version you use (latest +release or master). + +Additionally, include the output of |:messages| after executing one of the +following: + + - opening the buffer via `vim -V1 ` + - or running `:verb w` in the buffer + +============================================================================== +SIGNS *signify-signs* + + `+` This line was added. + + `!` This line was modified. + + `_1` The number of deleted lines below this sign. If the number is larger + `99` than 9, the `_` will be omitted. For numbers larger than 99, `_>` + `_>` will be shown instead. + + `!1` This line was modified and a number of lines below were deleted. + `!>` It is a combination of `!` and `_`. If the number is larger than 9, + `!>` will be shown instead. + + `‾` The first line was removed. It's a special case of the `_` sign. + +See |g:signify_sign_add| on how to use different signs. + +============================================================================== +OPTIONS *signify-options* + +Put these variables into your vimrc. The provided examples also indicate the +default values, as long as no "Default:" section is given. + +Most important options:~ + + |g:signify_vcs_list| + |g:signify_realtime| + +Other options:~ + + |g:signify_vcs_cmds| + |g:signify_vcs_cmds_diffmode| + |g:signify_disable_by_default| + |g:signify_skip_filetype| + |g:signify_skip_filename| + |g:signify_skip_filename_pattern| + |g:signify_update_on_bufenter| + |g:signify_update_on_focusgained| + |g:signify_line_highlight| + |g:signify_sign_add| + |g:signify_sign_delete| + |g:signify_sign_delete_first_line| + |g:signify_sign_change| + |g:signify_sign_changedelete| + |g:signify_sign_show_count| + |g:signify_sign_show_text| + |g:signify_cursorhold_normal| + |g:signify_cursorhold_insert| + |g:signify_difftool| + |g:signify_fold_context| + +------------------------------------------------------------------------------ + *g:signify_vcs_list* > + let g:signify_vcs_list = [ 'git', 'hg' ] +< +Default: empty +Possible values: 'accurev' + 'bzr' + 'cvs' + 'darcs' + 'fossil' + 'git' + 'hg' + 'perforce' + 'rcs' + 'svn' + 'tfs' + +NOTE: This is the most important option, so read closely. + +This option determines what VCS to check for. + +This can improve buffer loading time, since by default all supported and +installed VCS will be checked for. This only happens once, when signs get set +the first time. Afterwards, the VCS will either be remembered or registered as +inactive when no VCS was found. + +If your Vim is recent enough, these checks will happen asynchronously. + +NOTE: If you don't set this option, updating signs for a non-VCS file can lead +to a significant delay since all supported and installed VCS will be tested +for. (But this also happens only once, afterwards the buffer is registered as +inactive.) + +NOTE: Some VCS rely on a an external diff tool to work properly (svn, darcs, +bzr, fossil), thus you have to make sure that Vim can find a valid diff tool. +So either the one you set through |g:signify_difftool| or "diff" by default. + +------------------------------------------------------------------------------ + *g:signify_realtime* > + let g:signify_realtime = 0 +< +By default, the plugin is quite conservative and only updates on: + + |BufRead| Opening a buffer. + |BufWritePost| Saving a buffer. + +When this option is set, you get more aggressive sign updates: + + |BufEnter| Opening or switching to another buffer. + |WinEnter| Opening or switching to another window. + |BufWritePost| Saving a buffer. + |FocusGained| When the window containing Vim gains focus. + Disable with |g:signify_update_on_focusgained|. + |CursorHold| After 'updatetime' milliseconds without moving the cursor + in normal mode. Disable with |g:signify_cursorhold_normal|. + This also saves the buffer!~ + |CursorHoldI| After 'updatetime' milliseconds without moving the cursor + in insert mode. Disable with |g:signify_cursorhold_insert|. + This also saves the buffer!~ + +You can check the autocmds yourself: `:au signify` + +NOTE: Running Sy on all these events would block too often for older Vim +versions, thus this option requires Vim 7.4.1967+, which is the minimum +version needed for asynchronous execution. Older Vim versions silently ignore +this option. + +------------------------------------------------------------------------------ + *g:signify_vcs_cmds* > + let g:signify_vcs_cmds = { + \ 'cvs': 'cvs -d '. $CVSROOT .' diff -U0 -- %f' } +< +This is a |dict|. They key is any version control system from |g:signify_vcs_list| +and the value is the corresponding command-line. + +Modifiers:~ + + %f actual filepath + %d |g:signify_difftool| + %n Unix: `/dev/null`, Windows: `NUL` + +Redirection: Instead of `>foo` use `sy#util#shell_redirect('foo')`. This +helper function takes 'shellredir' into account. + +The output format mustn't change, otherwise Sy won't give any reasonable +results. It's probably wise to start with the respective default values. + +If your VCS program is not in `$PATH` and you have to specify an absolute path, +escape spaces by quoting, e.g.: +> + let g:signify_vcs_cmds = { + \ 'git': '"C:\Program Files (x86)\Git\bin\git.exe" diff --no-color --no-ext-diff -U0 -- %f' + \ } +< +NOTE: Always test these commands on the shell first and make sure that no +colors are emitted. Our parser expects lines in the diff output to start with +"@@", but with colors the line starts with escape sequences instead. + +Default: +> + let g:signify_vcs_cmds = { + \ 'git': 'git diff --no-color --no-ext-diff -U0 -- %f', + \ 'hg': 'hg diff --config extensions.color=! --config defaults.diff= --nodates -U0 -- %f', + \ 'svn': 'svn diff --diff-cmd %d -x -U0 -- %f', + \ 'bzr': 'bzr diff --using %d --diff-options=-U0 -- %f', + \ 'darcs': 'darcs diff --no-pause-for-gui --diff-command="%d -U0 %1 %2" -- %f', + \ 'fossil': 'fossil diff --unified -c 0 -- %f', + \ 'cvs': 'cvs diff -U0 -- %f', + \ 'rcs': 'rcsdiff -U0 %f 2>%n', + \ 'accurev': 'accurev diff %f -- -U0', + \ 'perforce': 'p4 info '. sy#util#shell_redirect('%n') . (has('win32') ? ' &&' : ' && env P4DIFF= P4COLORS=') .' p4 diff -du0 %f', + \ 'tfs': 'tf diff -version:W -noprompt %f', + \ } +< +------------------------------------------------------------------------------ + *g:signify_vcs_cmds_diffmode* > + let g:signify_vcs_cmds_diffmode = { + \ 'git': 'git show HEAD:./%f', + \ 'hg': 'hg cat %f', + \ 'svn': 'svn cat %f', + \ 'bzr': 'bzr cat %f', + \ 'darcs': 'darcs show contents -- %f', + \ 'cvs': 'cvs up -p -- %f 2>%n', + \ 'perforce': 'p4 print %f', + \ } +< +The command to use for |:SignifyDiff|. This option takes the same format as +|g:signify_vcs_cmds|. + +------------------------------------------------------------------------------ + *g:signify_disable_by_default* > + let g:signify_disable_by_default = 0 +< +This makes Sy not looking for changes for each new buffer. You can easily +enable it later using |signify-:SignifyToggle|. + +------------------------------------------------------------------------------ + *g:signify_skip_filename_pattern* + *g:signify_skip_filename* + *g:signify_skip_filetype* +> + let g:signify_skip_filetype = { 'vim': 1, 'c': 1 } + let g:signify_skip_filename = { '/home/user/.vimrc': 1 } +< +Don't activate the plugin for these filetypes and/or filenames. Filenames have +to be absolute paths. + +These options must be |Dict|s for faster lookup. +> + let g:signify_skip_filename_pattern = [ 'foo.*bar', 'tmp' ] +< +Don't activate the plugin for filenames matching these patterns. + +Default: + +------------------------------------------------------------------------------ + *g:signify_update_on_bufenter* > + let g:signify_update_on_bufenter = 0 +< +Update signs when entering a buffer that was modified. + +NOTE: This also saves the buffer to disk! + +------------------------------------------------------------------------------ + *g:signify_update_on_focusgained* > + let g:signify_update_on_focusgained = 0 +< +Update the signs on |FocusGained|, thus when the window holding Vim gains focus. +It does so by executing |signify-:SignifyRefresh|. + +NOTE: The |FocusGained| event is fired for all GUIs and even a few terminal +emulators. If you use tmux, put `set-option -g focus-events on` in your +tmux.conf. + +------------------------------------------------------------------------------ + *g:signify_line_highlight* > + let g:signify_line_highlight = 0 +< +Enable line highlighting in addition to using signs by default. + +------------------------------------------------------------------------------ + *g:signify_sign_add* + *g:signify_sign_delete* + *g:signify_sign_delete_first_line* + *g:signify_sign_change* + *g:signify_sign_changedelete* +> + let g:signify_sign_add = '+' + let g:signify_sign_delete = '_' + let g:signify_sign_delete_first_line = '‾' + let g:signify_sign_change = '!' + let g:signify_sign_changedelete = g:signify_sign_change +< +The sign to use if a line was added, deleted or changed or a combination of +these. + +You can use unicode characters, but signs must not take up more than two +cells. Otherwise |E239| is thrown. + +If |g:signify_sign_show_count| is set, |g:signify_sign_delete| and +|g:signify_sign_changedelete| get truncated as needed. + +------------------------------------------------------------------------------ + *g:signify_sign_show_count* > + let g:signify_sign_show_count = 1 +< +Add the number of deleted lines to |g:signify_sign_delete| (up to 99) and +|g:signify_sign_changedelete| (up to 9). Otherwise only the normal signs will +be shown. + +------------------------------------------------------------------------------ + *g:signify_sign_show_text* > + let g:signify_sign_show_text = 1 +< +Don't show any text in the sign column. (Actually it will show a non-breaking +space.) + +This is useful if you only want to see colors instead. If your colorscheme +doesn't do it for you, you can set the background color of a particular sign +yourself: |signify-colors|. + +If you want no sign column at all and use Vim 7.4.2201+, use 'signcolumn'. + +------------------------------------------------------------------------------ + *g:signify_cursorhold_normal* + *g:signify_cursorhold_insert* > + let g:signify_cursorhold_normal = 0 + let g:signify_cursorhold_insert = 0 +< +Additionally trigger sign updates in normal or insert mode after 'updatetime' +miliseconds without any keypresses. This fires only once between keypresses, +thus not every 'updatetime' miliseconds. + +NOTE: This also saves the buffer to disk! + +------------------------------------------------------------------------------ + *g:signify_difftool* > + let g:signify_difftool = 'gnudiff' +< +This will avoid the attempt to find the proper diff tool for version control +systems that rely on an external diff tool that supports the -U0 flag. These +are: svn, bzr, darcs, fossil. + +Default: "diff" + +------------------------------------------------------------------------------ + *g:signify_fold_context* > + let g:signify_fold_context = [0, 3] +< +This changes the number of lines of context that |signify-:SignifyFold| should +use. The first element describes the context at foldlevel 0 and the second the +context at foldlevel 1. + +Example:~ + +Using "[0,3]" means that after using :SignifyFold, only changed lines will be +unfolded. Using |zo| (and similar |fold-commands|) on a folded line will reveal +3 more lines of context. Using |zo| a second time will reveal everything. + +Default: [3, 8] + +============================================================================== +COMMAND *signify-commands* + *signify-:SignifyEnable* > + :SignifyEnable +< +Enable the plugin for the current buffer only. + +Can also be used to when a repository was initialized while Sy was already +loaded. + +------------------------------------------------------------------------------ + *signify-:SignifyDisable* > + :SignifyDisable +< +Disable the plugin for the current buffer only. + +------------------------------------------------------------------------------ + *signify-:SignifyToggle* > + :SignifyToggle +< +Toggle the plugin for the current buffer only. + +------------------------------------------------------------------------------ + *signify-:SignifyToggleHighlight* > + :SignifyToggleHighlight +< +Toggle line highlighting for lines containing changes. + +------------------------------------------------------------------------------ + *signify-:SignifyRefresh* > + :SignifyRefresh +< +Refresh signs in all windows. + +NOTE: Nothing will happen, if :SignifyRefresh is used from the |cmdline-window|. + +------------------------------------------------------------------------------ + *signify-:SignifyDiff* > + :SignifyDiff[!] +< +Open a new tab with two windows using |diff-mode| to show the differences +between the current file and its version that was last checked in. + +With [!], no new tab will be opened. + +Also see |g:signify_vcs_cmds_diffmode|. + +------------------------------------------------------------------------------ + *signify-:SignifyFold* > + :SignifyFold[!] +< +Open the current buffer in a new tabpage and set 'foldexpr' so that only +changed lines with their surrounding context are unfolded. + +The number of lines per context can be changed via |g:signify_fold_context|. + +The |foldtext| will be set so that the left side shows the first line in the +fold and the right side shows something like "50 [1]" which whereas "50" +stands for the number of folded lines and the "1" is the foldlevel. + +If [!] is given, Sy will do the same without opening an extra tabpage. Another +":SignifyFold!" will toggle back to the previous settings. + +See |folds| to learn more about folding. + +------------------------------------------------------------------------------ + *signify-:SignifyList* > + :SignifyList +< +Outputs debug info for all managed buffers. + +------------------------------------------------------------------------------ + *signify-:SignifyDebug* > + :SignifyDebug +< +In case no signs are shown, although the buffer contains a file controlled by +a supported VCS, use this command. + +It will show all tried commands and their output. Errors will be highlighted +via |hl-ErrorMsg|. + +============================================================================== +AUTOCOMMAND *signify-autocommand* + +User SignifySetup~ + + This event fires at the end of `plugin/signify.vim`, in case you want to + change any of the default autocmds, commands, or mappings. + +User Signify~ + + This event fires when Sy updated the signs. + +NOTE: Autocmds don't nest by default. If you use any command that triggers new +events, make sure to use |autocmd-nested|. + +============================================================================== +MAPPINGS *signify-mappings* + +------------------------------------------------------------------------------ +Hunk jumping:~ + + ]c Jump to next hunk. + [c Jump to previous hunk. + + ]C Jump to last hunk. + [C Jump to first hunk. + +These keys only get mapped by default when: + + - The keys are not mapped already (by you or another plugin). + - There are no other keys that are mapped to do the same (to avoid duplicate + mappings). + +Mapping other keys: +> + nmap gj (signify-next-hunk) + nmap gk (signify-prev-hunk) + nmap gJ 9999gj + nmap gK 9999gk +< +------------------------------------------------------------------------------ +Hunk text object:~ +> + omap ic (signify-motion-inner-pending) + xmap ic (signify-motion-inner-visual) + omap ac (signify-motion-outer-pending) + xmap ac (signify-motion-outer-visual) +< +"ic" operates on all lines of the current hunk. "ac" does the same, but also +removes all trailing empty lines. + +NOTE: Don't be surprised that this also works with "deleted lines". + +============================================================================== +COLORS *signify-colors* + +This plugin defines highlighting groups for two different places: for lines +and signs. Per default these don't really exist but are linked to the standard +highlighting groups: |hl-DiffAdd|, |hl-DiffChange|, |hl-DiffDelete|: +> + highlight link SignifyLineAdd DiffAdd + highlight link SignifyLineChange DiffChange + highlight link SignifyLineDelete DiffDelete + highlight link SignifyLineChangeDelete SignifyLineChange + highlight link SignifyLineDeleteFirstLine SignifyLineDelete + + highlight link SignifySignAdd DiffAdd + highlight link SignifySignChange DiffChange + highlight link SignifySignDelete DiffDelete + highlight link SignifySignChangeDelete SignifySignChange + highlight link SignifySignDeleteFirstLine SignifySignDelete +< +Thus if you do not want to change the standard highlighting groups, but want +different colors for either your signs or lines, you can overwrite these +highlighting groups in your vimrc. + +Assuming you prefer |hl-DiffText| over |hl-DiffChange| for changed lines: +> + highlight link SignifyLineChange DiffText +< +Personally I use (256 colors terminal): +> + " highlight lines in Sy and vimdiff etc.) + + highlight DiffAdd cterm=bold ctermbg=none ctermfg=119 + highlight DiffDelete cterm=bold ctermbg=none ctermfg=167 + highlight DiffChange cterm=bold ctermbg=none ctermfg=227 + + " highlight signs in Sy + + highlight SignifySignAdd cterm=bold ctermbg=237 ctermfg=119 + highlight SignifySignDelete cterm=bold ctermbg=237 ctermfg=167 + highlight SignifySignChange cterm=bold ctermbg=237 ctermfg=227 +< +For Unix people there is a small script, showcolors.bash, in the repo that +shows all 256 colors available to the terminal. That makes picking the right +numbers much easier. + +Default highlight groups:~ + +The sign column (often mistakenly called "gutter") itself (all lines without +signs) is highlighted by |hl-SignColumn|. Some colorschemes define no background +color for |hl-Normal| but for |hl-SignColumn|. To avoid that visible difference: +> + highlight SignColumn ctermbg=NONE cterm=NONE guibg=NONE gui=NONE +< +============================================================================== +FAQ *signify-faq* + + |signify-faq-01| What about vim-flagship support? + |signify-faq-02| The plugin is slow! + |signify-faq-03| Line highlighting without showing signs? + +------------------------------------------------------------------------------ + *signify-faq-01* +What about vim-flagship support?~ + +sy#repo#get_stats() returns a list with 3 integers for added, modified and +removed lines. Create a wrapper function around it and return a string: +> + function! s:sy_stats_wrapper() + let symbols = ['+', '-', '~'] + let [added, modified, removed] = sy#repo#get_stats() + let stats = [added, removed, modified] " reorder + let hunkline = '' + + for i in range(3) + if stats[i] > 0 + let hunkline .= printf('%s%s ', symbols[i], stats[i]) + endif + endfor + + if !empty(hunkline) + let hunkline = printf('[%s]', hunkline[:-2]) + endif + + return hunkline + endfunction + + autocmd User Flags call Hoist('buffer', function('s:sy_stats_wrapper')) +< +------------------------------------------------------------------------------ + *signify-faq-02* +The plugin is slow!~ + + * Set |g:signify_vcs_list|. Always. + + * Sy relies on external tools. Check if these are the bottleneck. + + If you use a centralized VCS like Subversion, is the connection to the + server slow? + + If you use a decentralized VCS like Git, are you working on a slow remote + file system? + + * Vim its sign handling code is known to be slow. If the delay is very long, + chances are the diff is just huge. This often happens after adding (or + removing) a huge file to the repo. + +------------------------------------------------------------------------------ + *signify-faq-03* +Line highlighting without showing signs?~ + +The line highlighting relies on signs being placed. The sign column is being +shown automatically if there are placed signs. + +With a recent Vim, you can change that behaviour using 'signcolumn'. + +============================================================================== +EXAMPLE *signify-example* + +An example configuration for Sy: +> + let g:signify_vcs_list = [ 'git', 'hg' ] + let g:signify_cursorhold_insert = 1 + let g:signify_cursorhold_normal = 1 + let g:signify_update_on_bufenter = 0 + let g:signify_update_on_focusgained = 1 + + nnoremap gt :SignifyToggle + nnoremap gh :SignifyToggleHighlight + nnoremap gr :SignifyRefresh + nnoremap gd :SignifyDebug + + " hunk jumping + nmap gj (signify-next-hunk) + nmap gk (signify-prev-hunk) + + " hunk text object + omap ic (signify-motion-inner-pending) + xmap ic (signify-motion-inner-visual) + omap ac (signify-motion-outer-pending) + xmap ac (signify-motion-outer-visual) +< +============================================================================== +vim: et tw=78 diff --git a/start/signify/plugin/signify.vim b/start/signify/plugin/signify.vim new file mode 100644 index 0000000..3a13442 --- /dev/null +++ b/start/signify/plugin/signify.vim @@ -0,0 +1,120 @@ +" vim: et sw=2 sts=2 + +scriptencoding utf-8 + +if exists('g:loaded_signify') || !has('signs') || &compatible + finish +endif + +" Init: values {{{1 +let g:loaded_signify = 1 +let g:signify_locked = 0 +let s:has_doau_modeline = v:version > 703 || v:version == 703 && has('patch442') + +" Init: autocmds {{{1 +augroup signify + autocmd! + + autocmd QuickFixCmdPre *vimgrep* let g:signify_locked = 1 + autocmd QuickFixCmdPost *vimgrep* let g:signify_locked = 0 + + autocmd CmdwinEnter * let g:signify_cmdwin_active = 1 + autocmd CmdwinLeave * let g:signify_cmdwin_active = 0 + + autocmd BufWritePost * call sy#start() + + if get(g:, 'signify_realtime') && has('patch-7.4.1967') + autocmd WinEnter * call sy#start() + if get(g:, 'signify_update_on_bufenter') + autocmd BufEnter * nested call s:save() + else + autocmd BufEnter * call sy#start() + endif + if get(g:, 'signify_cursorhold_normal', 1) + autocmd CursorHold * nested call s:save() + endif + if get(g:, 'signify_cursorhold_insert', 1) + autocmd CursorHoldI * nested call s:save() + endif + if get(g:, 'signify_update_on_focusgained', 1) + autocmd FocusGained * SignifyRefresh + endif + else + autocmd BufRead * call sy#start() + if get(g:, 'signify_update_on_bufenter') + autocmd BufEnter * nested call s:save() + endif + if get(g:, 'signify_cursorhold_normal') + autocmd CursorHold * nested call s:save() + endif + if get(g:, 'signify_cursorhold_insert') + autocmd CursorHoldI * nested call s:save() + endif + if get(g:, 'signify_update_on_focusgained') + autocmd FocusGained * SignifyRefresh + endif + endif + + if has('gui_running') && has('win32') && argc() + " Fix 'no signs at start' race. + autocmd GUIEnter * redraw + endif +augroup END + +" Init: commands {{{1 + +command! -nargs=0 -bar SignifyList call sy#debug#list_active_buffers() +command! -nargs=0 -bar SignifyDebug call sy#repo#debug_detection() +command! -nargs=0 -bar -bang SignifyFold call sy#fold#dispatch(1) +command! -nargs=0 -bar -bang SignifyDiff call sy#repo#diffmode(1) +command! -nargs=0 -bar SignifyRefresh call sy#util#refresh_windows() +command! -nargs=0 -bar SignifyEnable call sy#enable() +command! -nargs=0 -bar SignifyDisable call sy#disable() +command! -nargs=0 -bar SignifyToggle call sy#toggle() +command! -nargs=0 -bar SignifyToggleHighlight call sy#highlight#line_toggle() + +" Init: mappings {{{1 +let s:cpoptions = &cpoptions +set cpoptions+=B + +" hunk jumping +nnoremap (signify-next-hunk) &diff + \ ? ']c' + \ : ":\call sy#jump#next_hunk(v:count1)\" +nnoremap (signify-prev-hunk) &diff + \ ? '[c' + \ : ":\call sy#jump#prev_hunk(v:count1)\" + +if empty(maparg(']c', 'n')) && !hasmapto('(signify-next-hunk)', 'n') + nmap ]c (signify-next-hunk) + if empty(maparg(']C', 'n')) && !hasmapto('9999]c', 'n') + nmap ]C 9999]c + endif +endif +if empty(maparg('[c', 'n')) && !hasmapto('(signify-prev-hunk)', 'n') + nmap [c (signify-prev-hunk) + if empty(maparg('[C', 'n')) && !hasmapto('9999[c', 'n') + nmap [C 9999[c + end +endif + +" hunk text object +onoremap (signify-motion-inner-pending) :call sy#util#hunk_text_object(0) +xnoremap (signify-motion-inner-visual) :call sy#util#hunk_text_object(0) +onoremap (signify-motion-outer-pending) :call sy#util#hunk_text_object(1) +xnoremap (signify-motion-outer-visual) :call sy#util#hunk_text_object(1) + +let &cpoptions = s:cpoptions +unlet s:cpoptions + +" Function: save {{{1 + +function! s:save() + if exists('b:sy') && b:sy.active && &modified && &modifiable && ! &readonly + write + endif +endfunction + +if exists('#User#SignifySetup') + execute 'doautocmd' (s:has_doau_modeline ? '' : '') 'User SignifySetup' +endif -- cgit v1.2.3