06_[nvim0.5+从0单排]_Native LSP 自动补全、语法检查、code action、代码段—TypeScript篇

2023-05-16

视频与目录

项目
教程目录https://blog.csdn.net/lxyoucan/article/details/120641546
视频全屏https://www.bilibili.com/video/BV19T4y1Z7VB/
视频

06Native LSP 自动补全、语法检查、code action、代码段—TypeScript篇

06_[nvim0.5+从0单排]_Native LSP 自动补全、语法检查、code action、代码段—TypeScript篇

本文地址:
https://blog.csdn.net/lxyoucan/article/details/120632264

大家好,我是ITKEY欢迎来到nvim0.5+从0单排系列第6期。
本期以TypeScript为例,把nvim打造成一个功能强大的IDE。

版本

nvim 版本必须在 0.5.0以上,低版本是不支持Native LSP的。低版本想实现类似的效果可以使用neoclide/coc.nvim插件。

核心插件安装

--Nvim LSP 客户端的快速入门配置
use "neovim/nvim-lspconfig"
use {
"hrsh7th/nvim-cmp",
requires = {
"hrsh7th/cmp-nvim-lsp", --neovim 内置 LSP 客户端的 nvim-cmp 源
--以下插件可选,可以根据个人喜好删减
"onsails/lspkind-nvim", --美化自动完成提示信息
"hrsh7th/cmp-buffer", --从buffer中智能提示
"hrsh7th/cmp-nvim-lua", --nvim-cmp source for neovim Lua API.
"octaltree/cmp-look", --用于完成英语单词
"hrsh7th/cmp-path", --自动提示硬盘上的文件
"hrsh7th/cmp-calc", --输入数学算式(如1+1=)自动计算
"f3fora/cmp-spell", --nvim-cmp 的拼写源基于 vim 的拼写建议
"hrsh7th/cmp-emoji", --输入: 可以显示表情
}
}

-- 代码段提示
use {
"L3MON4D3/LuaSnip",
requires = {
"saadparwaiz1/cmp_luasnip", -- Snippets source for nvim-cmp
"rafamadriz/friendly-snippets" --代码段合集
}
}


typescript-language-server安装

首先需要安装node.js,安装方法可以参考:https://blog.csdn.net/lxyoucan/article/details/120466390

npm安装方式:

npm i -g typescript typescript-language-server

yarn安装方式:

yarn global add typescript typescript-language-server

lspconfig 配置

新增配置文件

~/.config/nvim/after/plugin/lspconfig.rc.vim

文件内容如下:


if !exists('g:lspconfig')
  finish
endif
lua << EOF
--提示信息自定义图标
-- icon
vim.lsp.handlers["textDocument/publishDiagnostics"] = vim.lsp.with(
  vim.lsp.diagnostic.on_publish_diagnostics, {
    underline = true,
    -- This sets the spacing and the prefix, obviously.
    virtual_text = {
      spacing = 4,
      prefix = ''
    }
  }
)
EOF

nvim-cmp配置

自动补全类的插件有很多选择,我为什么选择了nvim-cmp呢?主要还是因为lspconfig的wiki中是以这个插件为例说明的。用起来还行,所以就用它了。

typescript相关配置

新增配置文件

~/.config/nvim/lua/lspconf/typescript.lua

文件内容如下:

local nvim_lsp = require('lspconfig')

-- 在语言服务器附加到当前缓冲区之后
-- 使用 on_attach 函数仅映射以下键
 Itkey_on_attach = function(client, bufnr)
	local function buf_set_keymap(...) vim.api.nvim_buf_set_keymap(bufnr, ...) end
	local function buf_set_option(...) vim.api.nvim_buf_set_option(bufnr, ...) end

	--Enable completion triggered by <c-x><c-o>
	buf_set_option('omnifunc', 'v:lua.vim.lsp.omnifunc')

	-- Mappings.
	local opts = { noremap=true, silent=true }

	-- See `:help vim.lsp.*` for documentation on any of the below functions
	buf_set_keymap('n', 'gD', '<Cmd>lua vim.lsp.buf.declaration()<CR>', opts)
	buf_set_keymap('n', 'gd', '<Cmd>lua vim.lsp.buf.definition()<CR>', opts)
	--buf_set_keymap('n', 'K', '<Cmd>lua vim.lsp.buf.hover()<CR>', opts)
	buf_set_keymap('n', 'gi', '<cmd>lua vim.lsp.buf.implementation()<CR>', opts)
	--buf_set_keymap('i', '<C-k>', '<cmd>lua vim.lsp.buf.signature_help()<CR>', opts)
	buf_set_keymap('n', '<space>wa', '<cmd>lua vim.lsp.buf.add_workspace_folder()<CR>', opts)
	buf_set_keymap('n', '<space>wr', '<cmd>lua vim.lsp.buf.remove_workspace_folder()<CR>', opts)
	buf_set_keymap('n', '<space>wl', '<cmd>lua print(vim.inspect(vim.lsp.buf.list_workspace_folders()))<CR>', opts)
	buf_set_keymap('n', '<space>D', '<cmd>lua vim.lsp.buf.type_definition()<CR>', opts)
	--重命名
	buf_set_keymap('n', '<space>rn', '<cmd>lua vim.lsp.buf.rename()<CR>', opts)
	--智能提醒,比如:自动导包 已经用lspsaga里的功能替换了
	--buf_set_keymap('n', '<space>ca', '<cmd>lua vim.lsp.buf.code_action()<CR>', opts)
	buf_set_keymap('n', 'gr', '<cmd>lua vim.lsp.buf.references()<CR>', opts)
	buf_set_keymap('n', '<space>e', '<cmd>lua vim.lsp.diagnostic.show_line_diagnostics()<CR>', opts)
	--buf_set_keymap('n', '<C-j>', '<cmd>lua vim.lsp.diagnostic.goto_prev()<CR>', opts)
	buf_set_keymap('n', '<S-C-j>', '<cmd>lua vim.lsp.diagnostic.goto_next()<CR>', opts)
	buf_set_keymap('n', '<space>q', '<cmd>lua vim.lsp.diagnostic.set_loclist()<CR>', opts)
	buf_set_keymap("n", "<leader>f", "<cmd>lua vim.lsp.buf.formatting()<CR>", opts)

	-- 代码保存自动格式化formatting
	if client.resolved_capabilities.document_formatting then
		vim.api.nvim_command [[augroup Format]]
		vim.api.nvim_command [[autocmd! * <buffer>]]
		vim.api.nvim_command [[autocmd BufWritePre <buffer> lua vim.lsp.buf.formatting_seq_sync()]]
		vim.api.nvim_command [[augroup END]]
	end
end

-- Add additional capabilities supported by nvim-cmp
local capabilities = vim.lsp.protocol.make_client_capabilities()
capabilities.textDocument.completion.completionItem.documentationFormat = { 'markdown', 'plaintext' }
capabilities.textDocument.completion.completionItem.snippetSupport = true
capabilities.textDocument.completion.completionItem.preselectSupport = true
capabilities.textDocument.completion.completionItem.insertReplaceSupport = true
capabilities.textDocument.completion.completionItem.labelDetailsSupport = true
capabilities.textDocument.completion.completionItem.deprecatedSupport = true
capabilities.textDocument.completion.completionItem.commitCharactersSupport = true
capabilities.textDocument.completion.completionItem.tagSupport = { valueSet = { 1 } }
capabilities.textDocument.completion.completionItem.resolveSupport = {
	properties = {
		'documentation',
		'detail',
		'additionalTextEdits',
	},
}
Itkey_capabilities = capabilities


-- Enable some language servers with the additional completion capabilities offered by nvim-cmp
local servers = {'tsserver'}
for _, lsp in ipairs(servers) do
	nvim_lsp[lsp].setup {
		on_attach = Itkey_on_attach,
		capabilities = Itkey_capabilities,
	}
end

nvim-cmp配置

2021年10月12日配置调整说明,以下内容与视频中稍有出入,但是影响不大。主要让配置兼容新版的nvim-cmp

新增配置文件

~/.config/nvim/after/plugin/nvim-cmp.lua

文件内容如下:

local status, nvim_lsp = pcall(require, "lspconfig")
if (not status) then
  return
end

--local nvim_lsp = require('lspconfig')
--typescript支持
require("lspconf.typescript")
--json支持
--require("lspconf.json")
--lua
--require("lspconf.lua")
--普通的语言支持
--require("lspconf.common")

-- Set completeopt to have a better completion experience
vim.o.completeopt = "menuone,noselect"

-- luasnip setup
local luasnip = require "luasnip"
local lspkind = require("lspkind")

-- nvim-cmp setup
local cmp = require "cmp"

-- 自动提示1 详情信息
local cmpFormat1 = function(entry, vim_item)
  -- fancy icons and a name of kind
  vim_item.kind = require("lspkind").presets.default[vim_item.kind] .. " " .. vim_item.kind
  -- set a name for each source
  vim_item.menu =
    ({
    buffer = "[Buffer]",
    nvim_lsp = "[LSP]",
    ultisnips = "[UltiSnips]",
    nvim_lua = "[Lua]",
    cmp_tabnine = "[TabNine]",
    look = "[Look]",
    path = "[Path]",
    spell = "[Spell]",
    calc = "[Calc]",
    emoji = "[Emoji]"
  })[entry.source.name]
  return vim_item
end

-- 自动提示2 简洁信息
local cmpFormat2 = function(entry, vim_item)
  vim_item.kind = lspkind.presets.default[vim_item.kind]
  return vim_item
end

-- 自动提示3 详情信息
local cmpFormat3 = function(entry, vim_item)
  -- fancy icons and a name of kind
  vim_item.kind = require("lspkind").presets.default[vim_item.kind] .. ""
  -- set a name for each source
  vim_item.menu =
    ({
    buffer = "[Buffer]",
    nvim_lsp = "",
    ultisnips = "[UltiSnips]",
    nvim_lua = "[Lua]",
    cmp_tabnine = "[TabNine]",
    look = "[Look]",
    path = "[Path]",
    spell = "[Spell]",
    calc = "[Calc]",
    emoji = "[Emoji]"
  })[entry.source.name]
  return vim_item
end

------修复2021年10月12日 nvim-cmp.luaattempt to index field 'menu' (a nil value)---------
--重写插件方法,为了实现function 后,自动追加()
local keymap = require("cmp.utils.keymap")
cmp.confirm = function(option)
  option = option or {}
  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()
        local myContext = cmp.core:get_context({reason = cmp.ContextReason.TriggerOnly})
        cmp.core:complete(myContext)
        --function() 自动增加()
        if
          e and e.resolved_completion_item and
            (e.resolved_completion_item.kind == 3 or e.resolved_completion_item.kind == 2)
         then
          vim.api.nvim_feedkeys(keymap.t("()<Left>"), "n", true)
        end
      end
    )
    return true
  else
    if vim.fn.complete_info({"selected"}).selected ~= -1 then
      keymap.feedkeys(keymap.t("<C-y>"), "n")
      return true
    end
    return false
  end
end
---------------

cmp.setup {
  formatting = {
    format = cmpFormat1
  },
  snippet = {
    expand = function(args)
      require("luasnip").lsp_expand(args.body)
    end
  },
  mapping = {
    ["<C-p>"] = cmp.mapping.select_prev_item(),
    ["<C-n>"] = cmp.mapping.select_next_item(),
    ["<C-d>"] = cmp.mapping.scroll_docs(-4),
    ["<C-f>"] = cmp.mapping.scroll_docs(4),
    ["<C-Space>"] = cmp.mapping.complete(),
    ["<C-e>"] = cmp.mapping.close(),
    ["<CR>"] = cmp.mapping.confirm {
      behavior = cmp.ConfirmBehavior.Replace,
      select = false
    },
	['<Tab>'] = function(fallback)
      if cmp.visible() then
        cmp.select_next_item()
      elseif luasnip.expand_or_jumpable() then
        vim.fn.feedkeys(vim.api.nvim_replace_termcodes('<Plug>luasnip-expand-or-jump', true, true, true), '')
      else
        fallback()
      end
    end,
	['<S-Tab>'] = function(fallback)
      if cmp.visible() then
        cmp.select_prev_item()
      elseif luasnip.jumpable(-1) then
        vim.fn.feedkeys(vim.api.nvim_replace_termcodes('<Plug>luasnip-jump-prev', true, true, true), '')
      else
        fallback()
      end
    end

  },
  sources = {
    {name = "nvim_lsp"},
    {name = "luasnip"}, --{name = "nvim_lua"},
    {
      name = "buffer",
      option = {
        get_bufnrs = function()
          return vim.api.nvim_list_bufs()
        end
      }
    },
    --{name = "look"},
    {name = "path"}
    --{name = "cmp_tabnine"},
    --{name = "calc"},
    --{name = "spell"},
    --{name = "emoji"}
  }
}


L3MON4D3/LuaSnip配置

新增配置文件

~/.config/nvim/after/plugin/snippets.lua

文件内容如下:


local ls = require("luasnip")
-- some shorthands...
local s = ls.snippet
local sn = ls.snippet_node
local t = ls.text_node
local i = ls.insert_node
local f = ls.function_node
local c = ls.choice_node
local d = ls.dynamic_node
local l = require("luasnip.extras").lambda
local r = require("luasnip.extras").rep
local p = require("luasnip.extras").partial
local m = require("luasnip.extras").match
local n = require("luasnip.extras").nonempty
local dl = require("luasnip.extras").dynamic_lambda
local fmt = require("luasnip.extras.fmt").fmt
local fmta = require("luasnip.extras.fmt").fmta
local types = require("luasnip.util.types")
local conds = require("luasnip.extras.expand_conditions")

-- Every unspecified option will be set to the default.
ls.config.set_config({
	history = true,
	-- Update more often, :h events for more info.
	updateevents = "TextChanged,TextChangedI",
	ext_opts = {
		[types.choiceNode] = {
			active = {
				virt_text = { { "choiceNode", "Comment" } },
			},
		},
	},
	-- treesitter-hl has 100, use something higher (default is 200).
	ext_base_prio = 300,
	-- minimal increase in priority.
	ext_prio_increase = 1,
	enable_autosnippets = true,
})

-- args is a table, where 1 is the text in Placeholder 1, 2 the text in
-- placeholder 2,...
local function copy(args)
	return args[1]
end

-- 'recursive' dynamic snippet. Expands to some text followed by itself.
local rec_ls
rec_ls = function()
	return sn(
		nil,
		c(1, {
			-- Order is important, sn(...) first would cause infinite loop of expansion.
			t(""),
			sn(nil, { t({ "", "\t\\item " }), i(1), d(2, rec_ls, {}) }),
		})
	)
end

-- complicated function for dynamicNode.
local function jdocsnip(args, _, old_state)
	local nodes = {
		t({ "/**", " * " }),
		i(1, "A short Description"),
		t({ "", "" }),
	}

	-- These will be merged with the snippet; that way, should the snippet be updated,
	-- some user input eg. text can be referred to in the new snippet.
	local param_nodes = {}

	if old_state then
		nodes[2] = i(1, old_state.descr:get_text())
	end
	param_nodes.descr = nodes[2]

	-- At least one param.
	if string.find(args[2][1], ", ") then
		vim.list_extend(nodes, { t({ " * ", "" }) })
	end

	local insert = 2
	for indx, arg in ipairs(vim.split(args[2][1], ", ", true)) do
		-- Get actual name parameter.
		arg = vim.split(arg, " ", true)[2]
		if arg then
			local inode
			-- if there was some text in this parameter, use it as static_text for this new snippet.
			if old_state and old_state[arg] then
				inode = i(insert, old_state["arg" .. arg]:get_text())
			else
				inode = i(insert)
			end
			vim.list_extend(
				nodes,
				{ t({ " * @param " .. arg .. " " }), inode, t({ "", "" }) }
			)
			param_nodes["arg" .. arg] = inode

			insert = insert + 1
		end
	end

	if args[1][1] ~= "void" then
		local inode
		if old_state and old_state.ret then
			inode = i(insert, old_state.ret:get_text())
		else
			inode = i(insert)
		end

		vim.list_extend(
			nodes,
			{ t({ " * ", " * @return " }), inode, t({ "", "" }) }
		)
		param_nodes.ret = inode
		insert = insert + 1
	end

	if vim.tbl_count(args[3]) ~= 1 then
		local exc = string.gsub(args[3][2], " throws ", "")
		local ins
		if old_state and old_state.ex then
			ins = i(insert, old_state.ex:get_text())
		else
			ins = i(insert)
		end
		vim.list_extend(
			nodes,
			{ t({ " * ", " * @throws " .. exc .. " " }), ins, t({ "", "" }) }
		)
		param_nodes.ex = ins
		insert = insert + 1
	end

	vim.list_extend(nodes, { t({ " */" }) })

	local snip = sn(nil, nodes)
	-- Error on attempting overwrite.
	snip.old_state = param_nodes
	return snip
end

-- Make sure to not pass an invalid command, as io.popen() may write over nvim-text.
local function bash(_, _, command)
	local file = io.popen(command, "r")
	local res = {}
	for line in file:lines() do
		table.insert(res, line)
	end
	return res
end

-- Returns a snippet_node wrapped around an insert_node whose initial
-- text value is set to the current date in the desired format.
local date_input = function(args, state, fmt)
	local fmt = fmt or "%Y-%m-%d"
	return sn(nil, i(1, os.date(fmt)))
end

ls.snippets = {
	-- When trying to expand a snippet, luasnip first searches the tables for
	-- each filetype specified in 'filetype' followed by 'all'.
	-- If ie. the filetype is 'lua.c'
	--     - luasnip.lua
	--     - luasnip.c
	--     - luasnip.all
	-- are searched in that order.
	all = {
		-- trigger is fn.
		s("fn", {
			-- Simple static text.
			t("//Parameters: "),
			-- function, first parameter is the function, second the Placeholders
			-- whose text it gets as input.
			f(copy, 2),
			t({ "", "function " }),
			-- Placeholder/Insert.
			i(1),
			t("("),
			-- Placeholder with initial text.
			i(2, "int foo"),
			-- Linebreak
			t({ ") {", "\t" }),
			-- Last Placeholder, exit Point of the snippet. EVERY 'outer' SNIPPET NEEDS Placeholder 0.
			i(0),
			t({ "", "}" }),
		}),
		s("class", {
			-- Choice: Switch between two different Nodes, first parameter is its position, second a list of nodes.
			c(1, {
				t("public "),
				t("private "),
			}),
			t("class "),
			i(2),
			t(" "),
			c(3, {
				t("{"),
				-- sn: Nested Snippet. Instead of a trigger, it has a position, just like insert-nodes. !!! These don't expect a 0-node!!!!
				-- Inside Choices, Nodes don't need a position as the choice node is the one being jumped to.
				sn(nil, {
					t("extends "),
					i(1),
					t(" {"),
				}),
				sn(nil, {
					t("implements "),
					i(1),
					t(" {"),
				}),
			}),
			t({ "", "\t" }),
			i(0),
			t({ "", "}" }),
		}),
		-- Use a dynamic_node to interpolate the output of a
		-- function (see date_input above) into the initial
		-- value of an insert_node.
		s("novel", {
			t("It was a dark and stormy night on "),
			d(1, date_input, {}, "%A, %B %d of %Y"),
			t(" and the clocks were striking thirteen."),
		}),
		-- Parsing snippets: First parameter: Snippet-Trigger, Second: Snippet body.
		-- Placeholders are parsed into choices with 1. the placeholder text(as a snippet) and 2. an empty string.
		-- This means they are not SELECTed like in other editors/Snippet engines.
		ls.parser.parse_snippet(
			"lspsyn",
			"Wow! This ${1:Stuff} really ${2:works. ${3:Well, a bit.}}"
		),

		-- When wordTrig is set to false, snippets may also expand inside other words.
		ls.parser.parse_snippet(
			{ trig = "te", wordTrig = false },
			"${1:cond} ? ${2:true} : ${3:false}"
		),

		-- When regTrig is set, trig is treated like a pattern, this snippet will expand after any number.
		ls.parser.parse_snippet({ trig = "%d", regTrig = true }, "A Number!!"),
		-- Using the condition, it's possible to allow expansion only in specific cases.
		s("cond", {
			t("will only expand in c-style comments"),
		}, {
			condition = function(line_to_cursor, matched_trigger, captures)
				-- optional whitespace followed by //
				return line_to_cursor:match("%s*//")
			end,
		}),
		-- there's some built-in conditions in "luasnip.extras.expand_conditions".
		s("cond2", {
			t("will only expand at the beginning of the line"),
		}, {
			condition = conds.line_begin,
		}),
		-- The last entry of args passed to the user-function is the surrounding snippet.
		s(
			{ trig = "a%d", regTrig = true },
			f(function(_, snip)
				return "Triggered with " .. snip.trigger .. "."
			end, {})
		),
		-- It's possible to use capture-groups inside regex-triggers.
		s(
			{ trig = "b(%d)", regTrig = true },
			f(function(_, snip)
				return "Captured Text: " .. snip.captures[1] .. "."
			end, {})
		),
		s({ trig = "c(%d+)", regTrig = true }, {
			t("will only expand for even numbers"),
		}, {
			condition = function(line_to_cursor, matched_trigger, captures)
				return tonumber(captures[1]) % 2 == 0
			end,
		}),
		-- Use a function to execute any shell command and print its text.
		s("bash", f(bash, {}, "ls")),
		-- Short version for applying String transformations using function nodes.
		s("transform", {
			i(1, "initial text"),
			t({ "", "" }),
			-- lambda nodes accept an l._1,2,3,4,5, which in turn accept any string transformations.
			-- This list will be applied in order to the first node given in the second argument.
			l(l._1:match("[^i]*$"):gsub("i", "o"):gsub(" ", "_"):upper(), 1),
		}),
		s("transform2", {
			i(1, "initial text"),
			t("::"),
			i(2, "replacement for e"),
			t({ "", "" }),
			-- Lambdas can also apply transforms USING the text of other nodes:
			l(l._1:gsub("e", l._2), { 1, 2 }),
		}),
		s({ trig = "trafo(%d+)", regTrig = true }, {
			-- env-variables and captures can also be used:
			l(l.CAPTURE1:gsub("1", l.TM_FILENAME), {}),
		}),
		-- Set store_selection_keys = "<Tab>" (for example) in your
		-- luasnip.config.setup() call to access TM_SELECTED_TEXT. In
		-- this case, select a URL, hit Tab, then expand this snippet.
		s("link_url", {
			t('<a href="'),
			f(function(_, snip)
				return snip.env.TM_SELECTED_TEXT[1] or {}
			end, {}),
			t('">'),
			i(1),
			t("</a>"),
			i(0),
		}),
		-- Shorthand for repeating the text in a given node.
		s("repeat", { i(1, "text"), t({ "", "" }), r(1) }),
		-- Directly insert the ouput from a function evaluated at runtime.
		s("part", p(os.date, "%Y")),
		-- use matchNodes to insert text based on a pattern/function/lambda-evaluation.
		s("mat", {
			i(1, { "sample_text" }),
			t(": "),
			m(1, "%d", "contains a number", "no number :("),
		}),
		-- The inserted text defaults to the first capture group/the entire
		-- match if there are none
		s("mat2", {
			i(1, { "sample_text" }),
			t(": "),
			m(1, "[abc][abc][abc]"),
		}),
		-- It is even possible to apply gsubs' or other transformations
		-- before matching.
		s("mat3", {
			i(1, { "sample_text" }),
			t(": "),
			m(
				1,
				l._1:gsub("[123]", ""):match("%d"),
				"contains a number that isn't 1, 2 or 3!"
			),
		}),
		-- `match` also accepts a function, which in turn accepts a string
		-- (text in node, \n-concatted) and returns any non-nil value to match.
		-- If that value is a string, it is used for the default-inserted text.
		s("mat4", {
			i(1, { "sample_text" }),
			t(": "),
			m(1, function(text)
				return (#text % 2 == 0 and text) or nil
			end),
		}),
		-- The nonempty-node inserts text depending on whether the arg-node is
		-- empty.
		s("nempty", {
			i(1, "sample_text"),
			n(1, "i(1) is not empty!"),
		}),
		-- dynamic lambdas work exactly like regular lambdas, except that they
		-- don't return a textNode, but a dynamicNode containing one insertNode.
		-- This makes it easier to dynamically set preset-text for insertNodes.
		s("dl1", {
			i(1, "sample_text"),
			t({ ":", "" }),
			dl(2, l._1, 1),
		}),
		-- Obviously, it's also possible to apply transformations, just like lambdas.
		s("dl2", {
			i(1, "sample_text"),
			i(2, "sample_text_2"),
			t({ "", "" }),
			dl(3, l._1:gsub("\n", " linebreak ") .. l._2, { 1, 2 }),
		}),
		-- Alternative printf-like notation for defining snippets. It uses format
		-- string with placeholders similar to the ones used with Python's .format().
		s(
			"fmt1",
			fmt("To {title} {} {}.", {
				i(2, "Name"),
				i(3, "Surname"),
				title = c(1, { t("Mr."), t("Ms.") }),
			})
		),
		-- To escape delimiters use double them, e.g. `{}` -> `{{}}`.
		-- Multi-line format strings by default have empty first/last line removed.
		-- Indent common to all lines is also removed. Use the third `opts` argument
		-- to control this behaviour.
		s(
			"fmt2",
			fmt(
				[[
			foo({1}, {3}) {{
				return {2} * {4}
			}}
			]],
				{
					i(1, "x"),
					r(1),
					i(2, "y"),
					r(2),
				}
			)
		),
		-- Empty placeholders are numbered automatically starting from 1 or the last
		-- value of a numbered placeholder. Named placeholders do not affect numbering.
		s(
			"fmt3",
			fmt("{} {a} {} {1} {}", {
				t("1"),
				t("2"),
				a = t("A"),
			})
		),
		-- The delimiters can be changed from the default `{}` to something else.
		s("fmt4", fmt("foo() { return []; }", i(1, "x"), { delimiters = "[]" })),
		-- `fmta` is a convenient wrapper that uses `<>` instead of `{}`.
		s("fmt5", fmta("foo() { return <>; }", i(1, "x"))),
		-- By default all args must be used. Use strict=false to disable the check
		s(
			"fmt6",
			fmt("use {} only", { t("this"), t("not this") }, { strict = false })
		),
	},
	java = {
		-- Very long example for a java class.
		s("fn", {
			d(6, jdocsnip, { 2, 4, 5 }),
			t({ "", "" }),
			c(1, {
				t("public "),
				t("private "),
			}),
			c(2, {
				t("void"),
				t("String"),
				t("char"),
				t("int"),
				t("double"),
				t("boolean"),
				i(nil, ""),
			}),
			t(" "),
			i(3, "myFunc"),
			t("("),
			i(4),
			t(")"),
			c(5, {
				t(""),
				sn(nil, {
					t({ "", " throws " }),
					i(1),
				}),
			}),
			t({ " {", "\t" }),
			i(0),
			t({ "", "}" }),
		}),
	},
	tex = {
		-- rec_ls is self-referencing. That makes this snippet 'infinite' eg. have as many
		-- \item as necessary by utilizing a choiceNode.
		s("ls", {
			t({ "\\begin{itemize}", "\t\\item " }),
			i(1),
			d(2, rec_ls, {}),
			t({ "", "\\end{itemize}" }),
		}),
	},
}

-- autotriggered snippets have to be defined in a separate table, luasnip.autosnippets.
ls.autosnippets = {
	all = {
		s("autotrigger", {
			t("autosnippet"),
		}),
	},
}

-- in a lua file: search lua-, then c-, then all-snippets.
ls.filetype_extend("lua", { "c" })
-- in a cpp file: search c-snippets, then all-snippets only (no cpp-snippets!!).
ls.filetype_set("cpp", { "c" })
--[[
-- 除了定义你自己的代码片段,你还可以从“类似 vscode”的包中加载代码片段
-- 在 json 文件中公开片段,例如 <https://github.com/rafamadriz/friendly-snippets>.
-- 请注意,这将扩展 `ls.snippets`,因此您需要在您自己的代码片段之后执行此操作,或者您
-- 需要自己扩展表格而不是设置一个新表格。
]]
--require("luasnip/loaders/from_vscode").load({ include = { "javascript" } }) -- Load only python snippets
require("luasnip/loaders/from_vscode").load() -- Load only python snippets
-- The directories will have to be structured like eg. <https://github.com/rafamadriz/friendly-snippets> (include
-- a similar `package.json`)
--require("luasnip/loaders/from_vscode").load({ paths = { "./my-snippets" } }) -- Load snippets from my-snippets folder
--require("luasnip/loaders/from_vscode").load({ paths = { "/Users/itkey/Documents/my-snippets/" } }) -- Load snippets from my-snippets folder

-- You can also use lazy loading so you only get in memory snippets of languages you use
--require("luasnip/loaders/from_vscode").lazy_load() -- You can pass { paths = "./my-snippets/"} as well

更新说明

2021年11月1日更新
由于相关插件更新,导致配置文件微调

  • 微调~/.config/nvim/after/plugin/snippets.lua
  • 微调 ~/.config/nvim/after/plugin/nvim-cmp.lua

相关地址

  • nvim-lspconfig github主页
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

06_[nvim0.5+从0单排]_Native LSP 自动补全、语法检查、code action、代码段—TypeScript篇 的相关文章

  • Android JNI 本机 C 函数调用杀死活动

    什么有效 我有一个运行 TUN TAP 服务的 c 可执行文件 以及两个在终端中运行良好的 shell 脚本 用于配置 ip 路由 和 iptables 全部以 root 身份运行 什么不起作用 我正在尝试创建一个 Android 应用程序
  • 鼠标监听器和动作监听器之间的区别?

    有什么不同 什么时候会使用鼠标监听器 或者动作监听器 谢谢 麻烦您了 第一个区别是 MouseEvent 是真正的系统事件 而 ActionEvent 是合成事件 它由系统事件触发 当 a 您对事件详细信息 即 x y 单击点 感兴趣或您使
  • 停止调用 JNI 函数的 Java 线程

    在这里我想停止我的线程或杀死我的线程它是在Java层创建的 该线程正在调用JNI函数 有时根据我的应用程序要求 我必须停止此操作JNI函数执行在某些条件下 如果它正在进行 否则不会 new Thread new Runnable Overr
  • 创建新的 Rails 操作不起作用?

    我有一个控制器 应用程序 它由一个动作 索引 组成 现在我想添加一个名为 购买 的新操作 def buy respond to do format format html end end 我在视图中添加了 buy html erb 但是当浏
  • 动作和动作监听器之间的区别

    有什么区别action and actionListener 我应该什么时候使用action versus actionListener 动作监听器 Use actionListener如果你想要一个钩子before真正的业务行动得到执行
  • 在自己的函数中响应导航 onPress

    我已经实现了教程中的 React Navigation 示例https reactnavigation org docs intro https reactnavigation org docs intro 而且效果很好
  • 提交时设置表单的操作属性?

    单击提交按钮后如何立即更改表单的操作属性
  • CryptAPI 与 .NET 代码的本机互操作

    我已成功使用 Crypto API 以本机代码加密数据 并使用 RC2 算法和 SHA 创建密钥 以 NET C 代码对其进行解密 这是本机代码 在本例中为 Delphi Get handle to CSP If Not CryptAcqu
  • Symfony 1.4 更改管理生成器操作或模板

    如何修改管理员生成的模块 操作和模板 它们存储在缓存中 但我需要修改它们 模板 有可能吗 问候 当然可以 只需将模板文件从缓存复制到相关的module templates后台文件夹中的模板 然后修改 扩展 对于操作 将相同命名的操作添加到m
  • Ruby on Rails:使用控制器、操作和参数获取路线

    我对 RoR 很陌生 我正在寻找一种获取给定控制器 操作和参数的路线的方法 类似于 url for 但没有域和协议 可以说我有 params controller gt controller action gt edit project i
  • 访问 Microsoft.Win32.UnsafeNativeMethods?

    Microsoft 在 NET 框架中包含了一个非常好的 Windows API 包装器 它存储在Microsoft Win32 UnsafeNativeMethods Microsoft Win32 SafeNativeMethods a
  • 如何使用 MuPDF 在受密码保护的 pdf 上保存注释

    我正在尝试保存受密码保护的 pdf 的注释 我能够绘制注释并保存它 但是 一旦我返回并再次进行活动 我就看不到我的注释 然而奇怪的是 我可以看到注释框 但看不到绘制的路径 它适用于普通 pdf 无密码 pdf 知道如何保存受密码保护的 pd
  • 适用于 Android 的本机 OpenCV 示例抛出 UnsatisfiedLinkError

    我尝试在模拟器上运行 opencv android 示例 带有本机代码的示例 例如示例 教程 2 高级 1 添加本机 OpenCV 失败 我有一个Win7 x86系统 我可以构建本机库 但如果运行示例 我总是会遇到以下异常 10 04 08
  • 如何在 android 中创建自定义开关,并在开关轨道两侧和拇指上显示文本?

    如何在 android 中设计自定义开关 如下图所示 当它打开时 它需要看起来像这样 我还需要在两个类别之间切换时显示切换动画效果 我怎样才能实现它 是否有可用的第三方 SDK 或库 目前我已经用自定义线性布局设计它 如下所示 my lay
  • 更改重复键阈值 C++

    我正在构建一个 C 俄罗斯方块游戏 不是 C Net 我感觉我的控制很奇怪 我想要做到这一点 以便当用户按下其中一个箭头键时 按住它大约 10 毫秒将启动 Windows 的重复功能 默认设置为 500 毫秒左右 对于我的游戏来说太延迟了
  • C# 中调用另一个 Button 的代码

    我需要知道是否可以从另一个按钮调用单击按钮 private void myAction Click object sender EventArgs e int x private void Go Click object sender Ev
  • 以调试器友好的方式从 RAM 加载本机 C++ .dll

    问题目前仅涉及 Windows 其他操作系统目前不太相关 只需通过快速谷歌搜索 就可以从 RAM 加载本机 dll 例如有以下库 https www joachim bauch de tutorials loading a dll from
  • 来自本机的 Android O 设备序列号

    在 Android O 上从本机获取序列号而不调用 Java 的正确方法是什么Build getSerial 在 Android string serial read property ro boot serialno string rea
  • 反射性能 - 创建委托(C# 属性)

    我在使用反射时遇到性能问题 所以我决定为我的对象的属性创建委托 到目前为止得到了 TestClass cwp new TestClass var propertyInt typeof TestClass GetProperties Sing
  • 如何获取spring data jpa中更新记录的数量?

    我使用 spring data jpa 和 hibernate 作为 jpa 持久性提供程序 我在我的应用程序中使用本机查询 有一些更新查询 我想在执行更新查询时获取更新的实际记录数 spring data jpa 有没有办法做到这一点 我

随机推荐

  • coc-lua安装报错解决办法

    项目地址 xff1a https github com josa42 coc lua 现象 macOS中使用正常CentOS7有异常 环境CentOS7中 执行命令 CocInstall coc lua成功安装后 xff0c 重启nvim
  • Lua学习笔记

    neovim 0 5正式版本已经发布了 xff0c 现在学习Lua语言还来的及吧 lua替换vim脚本渐渐成为了趋势了 Lua学习下来 xff0c 感觉与javascript特别的像 就是代码块不是使用 分割 xff0c 而是end xff
  • neovim0.5笔记

    neovim0 5版本更新比较大 xff0c 有一些大佬开始抛弃coc xff0c 而使用native lsp了 学习一下记录一下 我参考的是 xff1a https github com craftzdog dotfiles public
  • vim-airline底部状态栏不显示图标的解决办法

    现象 正常的 以前我使用的airline都是有图标显示的 xff0c 如下图所示 不正常的 最近刚升级neovim0 5 尽可能的使用lua配置 xff0c 把环境重新配置了一下 后来就发现我的nvim下面的状态栏 xff0c 不显示图标了
  • LuaSnip代码段使用的正确姿势

    自己升级了neovim 0 5 以来各种尝试从coc切换到native lsp 在coc中代码段配置非常的简单 我之前有文章记录过 vim自动关闭标签 https blog csdn net lxyoucan article details
  • python一键删除误触复制的文件

    现在拍照有时候多选照片不小心变成了复制 xff0c 一个个删除太麻烦 xff0c 就出现了如下脚本 import os for file in os listdir 39 39 if 39 副本 39 in file os remove f
  • 在 neovim 中使用 Lua

    原文 xff1a https github com glepnir nvim lua guide zh nvim lua guide 中文版简易教程 译者 Neovim Core Developer 文章目录 在 neovim 中使用 Lu
  • github加速你可能不知道的小技巧

    在国内的网络环境下 使用github就是一个字 慢 有没有什么没有门槛 很简单的办法能够加速呢 有 方法一 使用csdn的镜像 https codechina csdn net mirrors 对一些知名的项目 也就是说Stars比较多的项
  • 安卓电视ssh应用

    有时下班回家没带电脑 xff0c 又突然想写两行代码 家里的大屏电视就是不错的选择 经过我这段时间的使用 xff0c 有几种实用方案分享给大家 手机投屏 这个方案是我用的最久 xff0c 也是最容易使用的方案 通过乐播投屏之类的方式把手机的
  • nvim-cmp插件function自动补()

    背景 之前使用的coc 最近刚转到NVIM native 方式的lsp 自动补全用的是nvim cmp插件 整体都不错 很满意 就是有一点不习惯 自动补全的function 或method不能自动在末尾加上 每次都要手动输入 有些麻烦 与是
  • oracle instant-client下载与安装sqlplus

    在下面的地址 xff0c 选择你的操作系统版本下载 https www oracle com database technologies instant client downloads html 比如我这里选的是 xff1a https
  • lua读取文本并去掉重复行

    需求 有一个文本文件 里面有大量的重复行 要求把重复的部分去掉 我本想用我的老本行java来实现的 感觉挺简单的 拿lua练一下手吧 源文本如下 column XH format a9 column XM format a9 column
  • 01_[nvim0.5+从0单排]_neovim安装与Pynvim安装

    视频与目录 项目值教程目录https blog csdn net lxyoucan article details 120641546视频全屏https www bilibili com video BV12f4y1E7Hy 视频 01 n
  • 02_[nvim0.5+从0单排]_配置、按键映射与packer插件管理器

    视频与目录 项目值教程目录https blog csdn net lxyoucan article details 120641546视频全屏https www bilibili com video BV1rf4y1E7dr 视频 02 配
  • iTerm2禁用Command+Enter 全屏

    因为我在vim中使用到了Command 43 Enter快捷键 xff0c 所以想把iTerm2自带的快捷键禁用一下 找了半天没找到 xff0c 原来需要增加按键配置 xff0c 忽略这个组合键 步骤 Preferences 61 gt K
  • 03_[nvim0.5+从0单排]_界面美化与主题

    视频与目录 项目值教程目录https blog csdn net lxyoucan article details 120641546视频全屏https www bilibili com video BV1sh411H7JE 视频 03 界
  • 自动化渗透测试&&自动化挖掘src

    文章目录 前言思路资产收集资产收集http服务自动攻击利用 前言 好久没有写blog了 xff0c 最近在上班干活 xff0c 最近抽空研究了一下自动化渗透测试 xff0c 下面分享一下 思路 资产收集 传统的资产收集都是跟域名挂钩 xff
  • 04_[nvim0.5+从0单排]_vim文件管理插件---ranger

    视频与目录 项目值教程目录https blog csdn net lxyoucan article details 120641546视频全屏https www bilibili com video BV1bq4y1P7j5 视频 04vi
  • 05_[nvim0.5+从0单排]_vim文件管理插件defx与窗口选择工具 vim-choosewin

    视频与目录 项目值教程目录https blog csdn net lxyoucan article details 120641546视频全屏https www bilibili com video BV1XR4y1n78z 视频 05vi
  • 06_[nvim0.5+从0单排]_Native LSP 自动补全、语法检查、code action、代码段—TypeScript篇

    视频与目录 项目值教程目录https blog csdn net lxyoucan article details 120641546视频全屏https www bilibili com video BV19T4y1Z7VB 视频 06Na