mirror of
				https://github.com/NotAShelf/nvf.git
				synced 2025-10-31 02:52:37 +00:00 
			
		
		
		
	language/ts: migrate to vim.lsp.servers
This commit is contained in:
		
					parent
					
						
							
								a2ce78fa90
							
						
					
				
			
			
				commit
				
					
						76c031bbda
					
				
			
		
					 1 changed files with 169 additions and 63 deletions
				
			
		|  | @ -4,73 +4,177 @@ | |||
|   lib, | ||||
|   ... | ||||
| }: let | ||||
|   inherit (builtins) attrNames; | ||||
|   inherit (builtins) attrNames elem; | ||||
|   inherit (lib.options) mkEnableOption mkOption; | ||||
|   inherit (lib.modules) mkIf mkMerge; | ||||
|   inherit (lib.lists) isList; | ||||
|   inherit (lib.meta) getExe; | ||||
|   inherit (lib.types) enum either listOf package str bool; | ||||
|   inherit (lib.nvim.lua) expToLua toLuaObject; | ||||
|   inherit (lib.types) enum listOf package bool; | ||||
|   inherit (lib.generators) mkLuaInline; | ||||
|   inherit (lib.nvim.attrsets) mapListToAttrs; | ||||
|   inherit (lib.nvim.lua) toLuaObject; | ||||
|   inherit (lib.nvim.types) mkGrammarOption diagnostics mkPluginSetupOption; | ||||
|   inherit (lib.nvim.dag) entryAnywhere; | ||||
|   inherit (lib.nvim.dag) entryAnywhere entryBefore; | ||||
| 
 | ||||
|   cfg = config.vim.languages.ts; | ||||
| 
 | ||||
|   defaultServer = "ts_ls"; | ||||
|   servers = { | ||||
|   defaultServers = ["ts_ls"]; | ||||
|   servers = let | ||||
|     ts_ls = { | ||||
|       package = pkgs.typescript-language-server; | ||||
|       lspConfig = '' | ||||
|         lspconfig.ts_ls.setup { | ||||
|           capabilities = capabilities, | ||||
|           on_attach = function(client, bufnr) | ||||
|             attach_keymaps(client, bufnr); | ||||
|             client.server_capabilities.documentFormattingProvider = false; | ||||
|           end, | ||||
|           cmd = ${ | ||||
|           if isList cfg.lsp.package | ||||
|           then expToLua cfg.lsp.package | ||||
|           else ''{"${cfg.lsp.package}/bin/typescript-language-server", "--stdio"}'' | ||||
|         } | ||||
|         } | ||||
|       cmd = [(getExe pkgs.typescript-language-server) "--stdio"]; | ||||
|       init_options = {hostInfo = "neovim";}; | ||||
|       filetypes = [ | ||||
|         "javascript" | ||||
|         "javascriptreact" | ||||
|         "javascript.jsx" | ||||
|         "typescript" | ||||
|         "typescriptreact" | ||||
|         "typescript.tsx" | ||||
|       ]; | ||||
|       root_markers = ["tsconfig.json" "jsconfig.json" "package.json" ".git"]; | ||||
|       handlers = { | ||||
|         # handle rename request for certain code actions like extracting functions / types | ||||
|         "_typescript.rename" = mkLuaInline '' | ||||
|           function(_, result, ctx) | ||||
|             local client = assert(vim.lsp.get_client_by_id(ctx.client_id)) | ||||
|             vim.lsp.util.show_document({ | ||||
|               uri = result.textDocument.uri, | ||||
|               range = { | ||||
|                 start = result.position, | ||||
|                 ['end'] = result.position, | ||||
|               }, | ||||
|             }, client.offset_encoding) | ||||
|             vim.lsp.buf.rename() | ||||
|             return vim.NIL | ||||
|           end | ||||
|         ''; | ||||
|       }; | ||||
|       on_attach = mkLuaInline '' | ||||
|         function(client, bufnr) | ||||
|           default_on_attach(client, bufnr); | ||||
| 
 | ||||
|     denols = { | ||||
|       package = pkgs.deno; | ||||
|       lspConfig = '' | ||||
|         vim.g.markdown_fenced_languages = { "ts=typescript" } | ||||
|         lspconfig.denols.setup { | ||||
|           capabilities = capabilities; | ||||
|           on_attach = attach_keymaps, | ||||
|           cmd = ${ | ||||
|           if isList cfg.lsp.package | ||||
|           then expToLua cfg.lsp.package | ||||
|           else ''{"${cfg.lsp.package}/bin/deno", "lsp"}'' | ||||
|         } | ||||
|         } | ||||
|           -- ts_ls provides `source.*` code actions that apply to the whole file. These only appear in | ||||
|           -- `vim.lsp.buf.code_action()` if specified in `context.only`. | ||||
|           vim.api.nvim_buf_create_user_command(0, 'LspTypescriptSourceAction', function() | ||||
|             local source_actions = vim.tbl_filter(function(action) | ||||
|               return vim.startswith(action, 'source.') | ||||
|             end, client.server_capabilities.codeActionProvider.codeActionKinds) | ||||
| 
 | ||||
|             vim.lsp.buf.code_action({ | ||||
|               context = { | ||||
|                 only = source_actions, | ||||
|               }, | ||||
|             }) | ||||
|           end, {}) | ||||
|         end | ||||
|       ''; | ||||
|     }; | ||||
| 
 | ||||
|   in { | ||||
|     inherit ts_ls; | ||||
|     # Here for backwards compatibility. Still consider tsserver a valid | ||||
|     # configuration in the enum, but assert if it's set to *properly* | ||||
|     # redirect the user to the correct server. | ||||
|     tsserver = { | ||||
|       package = pkgs.typescript-language-server; | ||||
|       lspConfig = '' | ||||
|         lspconfig.ts_ls.setup { | ||||
|           capabilities = capabilities; | ||||
|           on_attach = attach_keymaps, | ||||
|           cmd = ${ | ||||
|           if isList cfg.lsp.package | ||||
|           then expToLua cfg.lsp.package | ||||
|           else ''{"${cfg.lsp.package}/bin/typescript-language-server", "--stdio"}'' | ||||
|         } | ||||
|         } | ||||
|     tsserver = ts_ls; | ||||
| 
 | ||||
|     denols = { | ||||
|       cmd = [(getExe pkgs.deno) "lsp"]; | ||||
|       cmd_env = {NO_COLOR = true;}; | ||||
|       filetypes = [ | ||||
|         "javascript" | ||||
|         "javascriptreact" | ||||
|         "javascript.jsx" | ||||
|         "typescript" | ||||
|         "typescriptreact" | ||||
|         "typescript.tsx" | ||||
|       ]; | ||||
|       root_markers = ["deno.json" "deno.jsonc" ".git"]; | ||||
|       settings = { | ||||
|         deno = { | ||||
|           enable = true; | ||||
|           suggest = { | ||||
|             imports = { | ||||
|               hosts = { | ||||
|                 "https://deno.land" = true; | ||||
|               }; | ||||
|             }; | ||||
|           }; | ||||
|         }; | ||||
|       }; | ||||
|       handlers = { | ||||
|         "textDocument/definition" = mkLuaInline "nvf_denols_handler"; | ||||
|         "textDocument/typeDefinition" = mkLuaInline "nvf_denols_handler"; | ||||
|         "textDocument/references" = mkLuaInline "nvf_denols_handler"; | ||||
|       }; | ||||
|       on_attach = mkLuaInline '' | ||||
|         function(client, bufnr) | ||||
|           default_on_attach(client, bufnr) | ||||
|           vim.api.nvim_buf_create_user_command(0, 'LspDenolsCache', function() | ||||
|             client:exec_cmd({ | ||||
|               command = 'deno.cache', | ||||
|               arguments = { {}, vim.uri_from_bufnr(bufnr) }, | ||||
|             }, { bufnr = bufnr }, function(err, _result, ctx) | ||||
|               if err then | ||||
|                 local uri = ctx.params.arguments[2] | ||||
|                 vim.api.nvim_err_writeln('cache command failed for ' .. vim.uri_to_fname(uri)) | ||||
|               end | ||||
|             end) | ||||
|           end, { | ||||
|             desc = 'Cache a module and all of its dependencies.', | ||||
|           }) | ||||
|         end | ||||
|       ''; | ||||
|     }; | ||||
|   }; | ||||
| 
 | ||||
|   denols_handlers = '' | ||||
|     local function nvf_denols_virtual_text_document_handler(uri, res, client) | ||||
|       if not res then | ||||
|         return nil | ||||
|       end | ||||
| 
 | ||||
|       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, false, lines) | ||||
|       vim.api.nvim_set_option_value('readonly', true, { buf = bufnr }) | ||||
|       vim.api.nvim_set_option_value('modified', false, { buf = bufnr }) | ||||
|       vim.api.nvim_set_option_value('modifiable', false, { buf = bufnr }) | ||||
|       vim.lsp.buf_attach_client(bufnr, client.id) | ||||
|     end | ||||
| 
 | ||||
|     local function nvf_denols_virtual_text_document(uri, client) | ||||
|       local params = { | ||||
|         textDocument = { | ||||
|           uri = uri, | ||||
|         }, | ||||
|       } | ||||
|       local result = client.request_sync('deno/virtualTextDocument', params) | ||||
|       nvf_denols_virtual_text_document_handler(uri, result, client) | ||||
|     end | ||||
| 
 | ||||
|     local function nvf_denols_handler(err, result, ctx, config) | ||||
|       if not result or vim.tbl_isempty(result) then | ||||
|         return nil | ||||
|       end | ||||
| 
 | ||||
|       local client = vim.lsp.get_client_by_id(ctx.client_id) | ||||
|       for _, res in pairs(result) do | ||||
|         local uri = res.uri or res.targetUri | ||||
|         if uri:match '^deno:' then | ||||
|           nvf_denols_virtual_text_document(uri, client) | ||||
|           res['uri'] = uri | ||||
|           res['targetUri'] = uri | ||||
|         end | ||||
|       end | ||||
| 
 | ||||
|       vim.lsp.handlers[ctx.method](err, result, ctx, config) | ||||
|     end | ||||
|   ''; | ||||
| 
 | ||||
|   # TODO: specify packages | ||||
|   defaultFormat = "prettier"; | ||||
|   formats = { | ||||
|  | @ -122,17 +226,10 @@ in { | |||
|     lsp = { | ||||
|       enable = mkEnableOption "Typescript/Javascript LSP support" // {default = config.vim.lsp.enable;}; | ||||
| 
 | ||||
|       server = mkOption { | ||||
|       servers = mkOption { | ||||
|         type = singleOrListOf (enum (attrNames servers)); | ||||
|         default = defaultServers; | ||||
|         description = "Typescript/Javascript LSP server to use"; | ||||
|         type = enum (attrNames servers); | ||||
|         default = defaultServer; | ||||
|       }; | ||||
| 
 | ||||
|       package = mkOption { | ||||
|         description = "Typescript/Javascript LSP server package, or the command to run as a list of strings"; | ||||
|         example = ''[lib.getExe pkgs.jdt-language-server "-data" "~/.cache/jdtls/workspace"]''; | ||||
|         type = either package (listOf str); | ||||
|         default = servers.${cfg.lsp.server}.package; | ||||
|       }; | ||||
|     }; | ||||
| 
 | ||||
|  | @ -190,8 +287,17 @@ in { | |||
|     }) | ||||
| 
 | ||||
|     (mkIf cfg.lsp.enable { | ||||
|       vim.lsp.lspconfig.enable = true; | ||||
|       vim.lsp.lspconfig.sources.ts-lsp = servers.${cfg.lsp.server}.lspConfig; | ||||
|       vim.lsp.servers = | ||||
|         mapListToAttrs (name: { | ||||
|           inherit name; | ||||
|           value = servers.${name}; | ||||
|         }) | ||||
|         cfg.lsp.servers; | ||||
|     }) | ||||
| 
 | ||||
|     (mkIf (cfg.lsp.enable && elem "denols" cfg.lsp.servers) { | ||||
|       vim.globals.markdown_fenced_languages = ["ts=typescript"]; | ||||
|       vim.luaConfigRC.denols_handlers = entryBefore ["lsp-servers"] denols_handlers; | ||||
|     }) | ||||
| 
 | ||||
|     (mkIf cfg.format.enable { | ||||
|  | @ -234,7 +340,7 @@ in { | |||
|     { | ||||
|       assertions = [ | ||||
|         { | ||||
|           assertion = cfg.lsp.enable -> cfg.lsp.server != "tsserver"; | ||||
|           assertion = cfg.lsp.enable -> !(elem "tsserver" cfg.lsp.servers); | ||||
|           message = '' | ||||
|             As of a recent lspconfig update, the `tsserver` configuration has been renamed | ||||
|             to `ts_ls` to match upstream behaviour of `lspconfig`, and the name `tsserver` | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Ching Pei Yang
				Ching Pei Yang