LuaSnip icon indicating copy to clipboard operation
LuaSnip copied to clipboard

include in C will add > or "

Open NEX-S opened this issue 2 years ago • 11 comments

https://user-images.githubusercontent.com/97107165/185115434-43060269-861b-4164-8360-a455682467b4.mp4

NEX-S avatar Aug 17 '22 12:08 NEX-S

That seems to be caused by lsp.. Are you using clangd? I think it comes with an include-snippet without this quirk

L3MON4D3 avatar Aug 17 '22 12:08 L3MON4D3

Yes, i'm using clangd, clangd completion and snippetd completion have the same problem :( , is there any ways can fix this strange problem?

NEX-S avatar Aug 17 '22 12:08 NEX-S

Mhmm, I don't experience this issue, what args are you passing to clangd, what version is it?

L3MON4D3 avatar Aug 17 '22 12:08 L3MON4D3

lspconfig.clangd.setup {
    on_attach = M.on_attach,
    capabilities = M.capabilities,
    single_file_support = true,
}
 ~/.c/n/l/LSP [ clangd --version                                                                                                                                                     ] 09:35:38 PM
clangd version 14.0.6
Features: linux
Platform: x86_64-pc-linux-gnu

NEX-S avatar Aug 17 '22 13:08 NEX-S

btw, my clangd autoformat always make indent = 2, is there any ways can let it autoformat indent = 4?

NEX-S avatar Aug 17 '22 13:08 NEX-S

Oh, if autoformat is enabled, that's probably it. I think there's a global config somewhere, would be surprised if such stuff can't be changed in there. Maybe clangd also respects editorconfig

L3MON4D3 avatar Aug 17 '22 15:08 L3MON4D3

Clangd is sending the completion items with the matching quote/bracket. I have tried working around this by conditionally inserting " or > with a match node but I would sometimes end up with single " or >s that were really hard to delete (e.g. when deleting the include line, and they would reappear over and over). My current solution is expanding the snippet to #include <.

kmarius avatar Aug 17 '22 22:08 kmarius

Ahh, that makes sense too.

really hard to delete (e.g. when deleting the include line, and they would reappear over and over).

That's functionNode for you xD I think the only way out is to delete the entire snippet :/

A cool, maybe overcomplicated, way to solve this would be modifying the completion-items sent by clangd, the general approach would be similar to this, but instead of modifying snippets, the include-completion-items would have to be detected and the >/" removed.

L3MON4D3 avatar Aug 18 '22 08:08 L3MON4D3

I hacked together

local function char_after_cursor()
	local pos = require("luasnip.util.util").get_cursor_0ind()
	local line = vim.api.nvim_buf_get_lines(0, pos[1], pos[1] + 1, false)
	return string.sub(line[1], pos[2]+1, pos[2]+1)
end

-- ...

on_attach = function(client)
	local orig_rpc_request = client.rpc.request
	function client.rpc.request(method, params, handler, ...)
		local orig_handler = handler
		if method == 'textDocument/completion' then
			handler = function(...)
				local char = char_after_cursor()
				if char and char == "\"" or char == ">" then
					local err, result = ...
					if not err and result then
						local items = result.items or result
						for _, item in ipairs(items) do
							if item.kind == vim.lsp.protocol.CompletionItemKind.File and item.textEdit then
								local text = item.textEdit.newText
								if char == text:sub(-1, -1) then
									item.textEdit.newText = string.sub(text, 1, -2)
								end
							end
						end
					end
				end
				return orig_handler(...)
			end
		end
		return orig_rpc_request(method, params, handler, ...)
	end
end,

It checks the char after the cursor for" or > and strips it from the completion candidates.

kmarius avatar Aug 18 '22 17:08 kmarius

Nice, the check is a sensible addition :+1:

L3MON4D3 avatar Aug 18 '22 18:08 L3MON4D3

Maybe this is easier (not tested, I'm not a clangd user)

 cmp.setup({
    snippet = {

      expand = function(args)
             local pos =  vim.api.nvim_win_get_cursor(0)
             local  line = vim.api.nvim_buf_get_lines(0, pos[1] - 1, pos[1] , false)[1]
             if vim.startswith(line, "#include") then 
                   return args.body:sub(1, -2)
             else
                   require('luasnip').lsp_expand(args.body)
             end
         end
         .....

More complex preprocessing can be done there (like checking for the lsp servers that are active or the filetype), using your own snippets if the body matches a certain pattern...

leiserfg avatar Aug 18 '22 18:08 leiserfg