Closed j-barnak closed 10 months ago
-- add <> pairs if not in a statement
npairs.add_rules({
rule("<", ">", "cpp"):with_pair(ts_conds.is_not_ts_node({ "compound_statement"})),
})
sadly this doesn't work in cases like this
std::vector<int> a = std::vector<int>{1,2,3};
compound_statement-----
the second vector won't get pairs but that cases is rare and am not sure we can do better with treesitter
u can check it out yourself if u want
local ts_utils = require('nvim-treesitter.ts_utils')
vim.keymap.set("i", "<C-q>", function()
print(ts_utils.get_node_at_cursor())
end)
hmm this actually seems like a good idea for cmp completion
@Sam-programs
It seems that the suggested doesn't work for for
std::cout << "foo";
Attempting the above will generate
std::cout <> "foo";
Additionally, I've been trying to write a rule to pairs {
and };
for classes and structs. And I've tried
npairs.add_rules({
rule("{", "};", "cpp"):with_pair(
ts_conds.is_ts_node({ "class_specifier", "type_identifier", "field_declaration_list" })
),
})
And a combination of those 3 nodes and no luck?
@j-barnak for the second issue i use this
local cpp_cond = function ()
local line = vim.api.nvim_get_current_line()
-- match for() while() functions()
-- the regex won't work if 'magic' is not set
local pattern = '^.*(.*)'
if vim.fn.match({ line }, pattern) == 0 then
return false
end
end
npairs.add_rules({
rule("{", "};", "cpp"):with_pair(
cpp_cond
),
})
i am trying to figure out a way for the first one we might have to restore to checking if template is on the line rather than using treesitter
@Sam-programs Thanks!
i am trying to figure out a way for the first one we might have to restore to checking if template is on the line rather than using treesitter
I've been scratching my head over this problem for the past few days and I couldn't come up with anything.
Is it possible to just escape the pairs and not complete the pair. For example, with mini.pairs, the following does just that.
require("mini.pairs").map(
"i",
"<",
{ action = "open", pair = "<>", neigh_pattern = "\r.", register = { cr = false } }
)
require("mini.pairs").map("i", ">", { action = "close", pair = "<>", register = { cr = false } })
i don't really understand what the mini example is doing and i almost got a working one
local pair_cond = function ()
local line = vim.api.nvim_get_current_line()
-- only variable inits and structs/classes need semicolons
local pattern = '^\\s*template'
local c_node = ts_utils.get_node_at_cursor():type()
if vim.fn.match({ line }, pattern) ~= 0 and
(c_node ~= "initializer_list")
then
return false
end
end
it is just missing global templated variables actually it still doesn't work with cout nvm
i just tested the mini example it's only putting the pairs at the start of the line if that's what u want then this should do
local pair_cond = function()
return vim.api.nvim_win_get_cursor(0)[2] == 0
end
npairs.add_rules({
rule("<", ">", "cpp"):with_pair(
pair_cond
),
})
@j-barnak
@Sam-programs
I was under the impression that the mini.pairs
snippet just allowed you to escape <>
pair by pressing >
.
actually it still doesn't work with cout nvm
I also ran into bumps when dealing with the less than operator.
@j-barnak
i think i found something that could be helpful
cmp returns this as the label for vector
vector<typename Tp, typename Alloc>
which has a > at the end
WE COULD CHECK FOR THAT TO ADD THE PAIR!
and for the case of writing a template we could check for a template match
local cmp = require('cmp')
local function template_on_confirm(event)
if vim.o.filetype ~= "cpp" then
return
end
local entry = event.entry
local item = entry:get_completion_item()
local pairs = '<>'
local functionsig = item.label
if functionsig:sub(#functionsig, #functionsig) == '>' or functionsig == ' template' then
pairs = vim.api.nvim_replace_termcodes(pairs .. "<left>", true, false, true)
vim.api.nvim_feedkeys(pairs, "n", false)
end
end
cmp.event:on('confirm_done', template_on_confirm)
best part is you don't even have to write the pairs anymore
@j-barnak sorry if the mentions are annoying
@Sam-programs No worries about the mentions. I appreciate them.
Awesome work. Do you know if it's possible to add a with_move
to escape the <>
pair?
I'm currently using mini.pairs
, but only using
require("mini.pairs").map("i", ">", { action = "close", pair = "<>", register = { cr = false } })
to escape the <>
pairing.
I'm doing this for the preproc_include
rule
local rule = require("nvim-autopairs.rule")
local cond = require("nvim-autopairs.conds")
local npairs = require("nvim-autopairs")
npairs.add_rules({
rule("<", ">", "cpp")
:with_pair(ts_conds.is_ts_node({ "preproc_include" }))
:with_move(cond.not_before_regex(">", 1)),
})
And one last small thing, when you select the snipped for for #include
, it creates (the |
represents the cursor)
`#include<|>`
Is it possible to do generate
`#include <|> // Note the space
Thanks for everything. Huge help!
the #include
was an accidental side effect lol
@j-barnak for escaping you can add this rule
rule("<", ">", "cpp"):
with_pair(conds.none()): -- never add the end pair
with_move(conds.done()), -- move when endpair is pressed
and here is a modified version of template_on_confirm
that adds a space for include
local kind = cmp.lsp.CompletionItemKind
local function template_on_confirm(event)
if not (vim.o.filetype == "c" or vim.o.filetype == "cpp") then
return
end
local entry = event.entry
local item = entry:get_completion_item()
local _, c = unpack(vim.api.nvim_win_get_cursor(0))
local line = vim.api.nvim_get_current_line()
local pairs = ''
local functionsig = item.label
local is_function = item.kind == kind.Function
if line:sub(c, c) ~= '>' and
(vim.fn.match(functionsig,'<.*>') ~= -1 or
functionsig == ' template')
then
if functionsig:sub(2, 8) == 'include' then
pairs = ' '
end
pairs = pairs .. '<>'
local old_lz = vim.o.lz
vim.o.lz = true
pairs = vim.api.nvim_replace_termcodes(
(is_function and "<C-g>u<left>" or "") .. pairs .. "<C-g>u<left>" .. "<cmd>lua vim.o.lz =" .. (old_lz and "true" or "false") .. "<cr>", true, false, true)
vim.api.nvim_feedkeys(pairs, "n", false)
end
end
also you can do ```LANG ``` to highlight syntax
i think i should make a pr with something like this it seems really useful
hold your horses the first check is failing
update:
was an off by 1 error
fun fact i didn't know that escaping meant pressing the endpair moves the cursor
because i have 1 hotkey that moves the cursor 1 column
alt-l <A-l>
since most pair keys are far from letters i think this is a better idea
@Sam-programs Awesome stuff! I'll test it in the morning.
And just to clarify, we include with_pair(conds.none())
for the following snippet
rule("<", ">", "cpp"):
with_pair(conds.none())-- never add the end pair
with_move(conds.done()), -- move when endpair is pressed
because template_on_confirm
is used to complete the pairing.
And with_move(conds.done())
enables escaping the <>
pair by typing >
?
yes
great...
12 void foo(){
13 std::vector<int> a;
14 std::vector<int> b;
15 std::vector
16 } vector<typename Tp, typename Alloc> Class
~ vector(…) Constructor
// NOT A >
i think there could be a work around with cmp's sorting i haven't used it before tho
yea this
sorting = {
comparators = {function (entry1,entry2)
local item1 = entry1.completion_item
local item2 = entry2.completion_item
if item1.kind == item2.kind then
return nil
end
if math.max(item1.kind,item2.kind) == item1.kind then
return true
end
return false
end}
},
not sure of a nice way to make it fit into autopairs and i don't suggest using this for now because it might make cmp's results ugly i am gonna try to find a good range/way to sort them (or yoink cmp's)
local config = require('cmp.config')
local cmp_comparetors = config.get().sorting.comparators
local unpack = unpack or table.unpack
local function cpp_sort_cmp(entry1, entry2)
local kind1 = entry1.completion_item.kind
local kind2 = entry2.completion_item.kind
if vim.o.filetype ~= "cpp" then
return nil
end
if kind1 == kind.Constructor and kind2 == kind.Class then
return false
end
if kind1 == kind.Class and kind2 == kind.Constructor then
return true
end
return nil
end
cmp.setup({
sorting = {
comparators = {
cpp_sort_cmp,
unpack(cmp_comparetors),
}
}
})
this seems to work best
sadly i couldn't check if cpp_sort_cmp
was already in the comparator list
i hope windwp doesn't think of this as too shady
after learning how to interact with lsp i found that this actually gives the template signature when under a templated class
vim.keymap.set("i", "<C-q>", function()
vim.lsp.handlers["textDocument/signatureHelp"] = function (_,info)
print(info.signatures[1].label)
end
vim.lsp.buf.signature_help()
end)
which would make it possible for the <>
pairs to work on their own
but i think it's way too overkill tho
not gonna stop me for making it in case anyone is curious
-- only works for templated variables those are the hard part
local is_tempalate = function()
local line = vim.api.nvim_get_current_line()
line = line .. '<'
vim.api.nvim_set_current_line(line)
local r,c = unpack(vim.api.nvim_win_get_cursor(0))
vim.api.nvim_win_set_cursor(0,{r,c + 1})
vim.cmd("redraw") -- redraw to add the first <
local old_handler = vim.lsp.handlers["textDocument/signatureHelp"]
vim.lsp.handlers["textDocument/signatureHelp"] = function(_, info)
if info then
if info.signatures[1] then
local functionsig = info.signatures[1].label
if vim.fn.match({functionsig},'^\\w\\+<') == 0 then
vim.api.nvim_set_current_line(line .. '>')
end
end
end
end
vim.lsp.buf.signature_help()
vim.lsp.handlers["textDocument/signatureHelp"] = old_handler
end
vim.keymap.set("i","<",is_tempalate)
i need to learn to shut up this is the most relevant comment https://github.com/windwp/nvim-autopairs/issues/405#issuecomment-1762761811
@Sam-programs
Thanks for everything. I'll test this to see if it works well. I'll also test #407 as well!
Thanks
which would make it possible for the <> pairs to work on their own but i think it's way too overkill tho not gonna stop me for making it in case anyone is curious
That'd be awesome if you got this to work!
sadly i couldn't check if cpp_sort_cmp was already in the comparator list
Maybe adjust the priority so that it's at the top?
Just having the following:
local conds = require("nvim-autopairs.conds")
local rule = require("nvim-autopairs.rule")
rule("<", ">", "cpp"):with_pair(conds.none()):with_move(conds.done())
doesn't seem to work?
@Sam-programs A small correction. It seems that unpack
was deprecated in lua 5.4. Changing it to table.unpack
fixes it.
Edit: Seems like you address this in the PR. My bad!
i almost got the function working just losing my sanity with lua 1 indexing rn
https://github.com/windwp/nvim-autopairs/issues/405#issuecomment-1762973584 i am not sure what isn't working it shouldn't place a pair in that case i haven't done too much testing but this huge snippet should fix everything
local is_tempalate = function()
local line = vim.api.nvim_get_current_line()
local r, c = unpack(vim.api.nvim_win_get_cursor(0))
if not (vim.o.filetype == "cpp" or vim.o.filetype == "c") then
line = line:sub(1, c) .. '<' .. line:sub(c + 1)
vim.api.nvim_set_current_line(line)
vim.api.nvim_win_set_cursor(0, { r, c + 1 })
return
end
if vim.fn.match({ line }, 'template') == 0 then
-- c - 1 = 2 chars before the cursor
line = line:sub(1, c) .. '<>' .. line:sub(c + 1)
vim.api.nvim_set_current_line(line)
vim.api.nvim_win_set_cursor(0, { r, c + 1 })
return
end
if vim.fn.match({ line }, '#include') == 0 then
line = line:sub(1, c) .. '<>' .. line:sub(c + 1)
if line:sub(c, c) ~= ' ' then
line = line:sub(1, c) .. ' ' .. line:sub(c + 1)
c = c + 1
end
vim.api.nvim_set_current_line(line)
vim.api.nvim_win_set_cursor(0, { r, c + 1 })
return
end
if vim.fn.match({ line:sub(0, c) }, 'cast\\s*$') == 0 then
-- c - 1 = 2 chars before the cursor
line = line:sub(1, c) .. '<>' .. line:sub(c + 1)
vim.api.nvim_set_current_line(line)
vim.api.nvim_win_set_cursor(0, { r, c + 1 })
return
end
-- c is 1 before the cursor
line = line:sub(1, c) .. '<' .. line:sub(c + 1)
vim.api.nvim_set_current_line(line)
vim.api.nvim_win_set_cursor(0, { r, c + 1 })
vim.cmd("redraw") -- redraw to add the first <
-- since we added < the lsp can detect it
local old_handler = vim.lsp.handlers["textDocument/signatureHelp"]
vim.lsp.handlers["textDocument/signatureHelp"] = function(_, info)
if info and info.signatures and info.signatures[1] and info.signatures[1].label then
local functionsig = info.signatures[1].label
if vim.fn.match({ functionsig }, '^\\w\\+<') == 0 then
-- c + 1 is after including the openning pair very shady code lol
vim.api.nvim_set_current_line(line:sub(0, c + 1) .. '>' .. line:sub(c + 2))
end
end
end
vim.lsp.buf.signature_help()
vim.lsp.handlers["textDocument/signatureHelp"] = old_handler
end
vim.keymap.set("i", "<", is_tempalate)
@j-barnak
sadly i couldn't check if cpp_sort_cmp was already in the comparator list
that's also fixed in the pr with a global variable also don't worry about unpack
DAMN IT COUT BROKE AGAIN
changing the info if statement to check everything fixes it
if info and info.signatures and info.signatures[1] and info.signatures[1].label then
Replacing
local r, c = unpack(vim.api.nvim_win_get_cursor(0))
with
@Sam-programs
local r, c = table.unpack(vim.api.nvim_win_get_cursor(0))
yields the following error
E5108: Error executing lua: /home/jared/.config/nvim/lua/plugins/pair.lua:19: attempt to call upvalue 'unpack' (a nil value)
stack traceback:
/home/jared/.config/nvim/lua/plugins/pair.lua:19: in function </home/jared/.config/nvim/lua/plugins/pair.lua:17>
I opted to switch unpack
with table.unpack
because I got an error say that unpack
was deprecated.
@Sam-programs
And just noting,
npairs.add_rules({
rule("<",">"):
with_pair(cond.none()):
with_move(cond.done()):
use_key('<kPoint>') -- a random key so it doesn't map <
})
The above doesn't allow you to escape the end pair >
.
oh i didn't notice the that
i have no clue why but this works
npairs.add_rules({
rule("<",">"):
with_pair(cond.none()):
with_move(cond.done()):
use_key('>') -- a random key so it doesn't map <
})
@j-barnak use this if u really care about that warning
local unpack = unpack or table.unpack
@Sam-programs
With regards to this
npairs.add_rules({
rule("<",">"):
with_pair(cond.none()):
with_move(cond.done()):
use_key('>') -- a random key so it doesn't map <
})
I think this works because the move
is triggered when the pair is completed and use_key
triggers the completion. I'll let you know if this runs into errors.
i thought it meant pair start trigger because that key is used in the completion to add the () pair https://github.com/windwp/nvim-autopairs/blob/master/lua/nvim-autopairs/completion/handlers.lua#L52 also the completion starting has nothing to do with npairs unless you mean end pair completion then you are correct
@Sam-programs
I've done some testing with this snippet and it's been working great. Thanks for the awesome work!
Anything you want to add or should I close the issue? Is there anything you want to add or should I wait until #407 gets merged?
@j-barnak good to know that snippet works ,i am curious to why u prefer it over the cmp snippet https://github.com/windwp/nvim-autopairs/issues/405#issuecomment-1762690355 because it feels like it's worse than cmp's
@Sam-programs
i am curious to why u prefer it over the cmp snippet
I was under the impression that this was better
Edit: it works. Though, is there any reason you specifically prefer this one?
And personally
local npairs = require("nvim-autopairs")
local cmp = require("cmp")
npairs.setup(opts)
local function template_on_confirm(event)
if not (vim.o.filetype == "c" or vim.o.filetype == "cpp") then
return
end
local entry = event.entry
local item = entry:get_completion_item()
local _, c = unpack(vim.api.nvim_win_get_cursor(0))
local line = vim.api.nvim_get_current_line()
local pairs = ""
local functionsig = item.label
if
line:sub(c, c) ~= ">"
and (functionsig:sub(#functionsig, #functionsig) == ">" or functionsig == " template")
then
if functionsig:sub(2, 8) == "include" then
pairs = " "
end
pairs = pairs .. "<>"
pairs = vim.api.nvim_replace_termcodes(pairs .. "<left>", true, false, true)
vim.api.nvim_feedkeys(pairs, "n", false)
end
end
cmp.event:on("confirm_done", template_on_confirm)
~This didn't work for me.~
@Sam-programs
because i have 1 hotkey that moves the cursor 1 column alt-l
<A-l>
Mind sharing this hotkey?
@j-barnak https://github.com/windwp/nvim-autopairs/issues/405#issuecomment-1763449711
~This didn't work for me~
phew the pr is safe to merge
maybe you were messing the sorter here https://github.com/windwp/nvim-autopairs/issues/405#issuecomment-1762761811
without the sorter it sometimes doesn't add the <> pairs
add the last cmp.setup
after your own cmp.setup
or you can just wait until the pr gets merged
Mind sharing this hotkey?
damn you learnt vim properly and didn't use the arrow keys unlike me lol
vim.keymap.set({ "i", "c" }, "<A-l>", "<right>") -- the c mode is command mode
edit:
Edit: it works. Though, is there any reason you specifically prefer this one?
not having to press <
@Sam-programs Thanks! You might also want to add to your config
npairs.add_rules({
rule("{", "}", "cpp"):with_pair(ts_conds.is_ts_node({ "namespace_definition" })),
})
because
local cpp_cond = function ()
local line = vim.api.nvim_get_current_line()
-- match for() while() functions()
-- the regex won't work if 'magic' is not set
local pattern = '^.*(.*)'
if vim.fn.match({ line }, pattern) == 0 then
return false
end
end
npairs.add_rules({
rule("{", "};", "cpp"):with_pair(
cpp_cond
),
})
triggers{};
when you type namespace.
thanks @j-barnak i actually thought it was required there
i also noticed that the cmp autocomplete doesn't detect static_cast and other kinds of casts i fixed it by using a regex to detect templated stuff the thing is i am having a hard time making it not conflict with the existing pair adder for functions i got a work around by making it reverse the cursor position for now https://github.com/windwp/nvim-autopairs/issues/405#issuecomment-1762690355
u will need to add the template_on_confirm to cmp's events after autopairs for functions
cmp.event:on("confirm_done",cmp_autopairs.on_confirm_done())
cmp.event:on('confirm_done', template_on_confirm)
but now template_on_confirm sadly doesn't work on it's own
@Sam-programs Thanks!
How would you make casts work with this rule?
Thank you so much! You've been awesome.
i am really not sure how to make it work as i won't have access to cmp's entry but maybe i could find a lsp method to detect that i made it look if the last few characters are cast to detect casts for now updated
that might conflict with a variable ending with cast but i don't have that much time to read/test the lsp requests for now
edit: i don't really write much c++ so please tell me if there are cases that aren't covered ill fix them when i can
@j-barnak mention lol
@Sam-programs That works! My one and last problem is that I when I mix these two
local cpp_cond = function ()
local line = vim.api.nvim_get_current_line()
-- match for() while() functions()
-- the regex won't work if 'magic' is not set
local pattern = '^.*(.*)'
if vim.fn.match({ line }, pattern) == 0 then
return false
end
end
npairs.add_rules({
rule("{", "};", "cpp"):with_pair(
cpp_cond
),
})
pairs.add_rules({
rule("{", "}", "cpp"):with_pair(ts_conds.is_ts_node({ "namespace_identifier" })),
})
The cpp_cond
rule gets overwritten and no longer works.
Description
I am trying to add a treesitter rule that creates the
<>
pairThe only time I don't want
<>
to pair is when it's used as a binary expression. By that, I mean for the bitshift operator (<<
) and the less than operator (<
). Here's what I meanThe bitshift operator and less than operator are both binary expressions so I thought I could encapsulate the pairing with the following
but this doesn't work.
I've also tried to manually add all the instances of where the bracket is used as a pair with
This works for
preproc_include
, but nottemplate_declaration
. The AST for templates look likeAnd this is what it looks like for templated class declarations
How could I get this rule to work?
Mapping bug
1.If you report a bug about indent. Please remember that plugin doesn't do anything about indent. It just trigger the indent of your vim config so if you have wrong indent config then it will do wrong indent. You can check by select a block of code and press
==
:verbose imap <cr>
.Steps to reproduce
No response
Minimal config