I am building custom text object in lua. With the following code, I am able to change content within certain symbols. This is my code:
local in_symbol = function(start_symbol, end_symbol, mode)
local v = vim.api
local currentLineNum = v.nvim_win_get_cursor(0)[1]
local end_match = vim.api.nvim_call_function("searchpos", {start_symbol, "", currentLineNum})
local start_match = vim.api.nvim_call_function("searchpos", {start_symbol, "b", currentLineNum})
if start_match[1] == 0 then
return
end
if end_match[1] == 0 then
end_match = vim.api.nvim_call_function("searchpos", {start_symbol, "n", currentLineNum})
end
if end_match[1] == 0 then
return
end
local end_symbol_length = string.len(end_symbol)
local end_offset = mode == 'i' and end_match[2] - end_symbol_length - 1 or end_match[2] - 1
local start_symbol_length = string.len(start_symbol)
local start_offset = mode == 'i' and start_match[2] or start_match[2]
if end_match[2] - start_match[2] == 1 then
v.nvim_win_set_cursor(0, { currentLineNum, start_offset - 1})
print('no content')
return
end
v.nvim_win_set_cursor(0, { currentLineNum, start_offset})
vim.cmd('normal! v')
v.nvim_win_set_cursor(0, { currentLineNum, end_offset})
end
return {
in_symbol = in_symbol,
}
For a custom text object for *
(i.e. ci*
), I have the following mapping
vim.cmd [[xnoremap <silent> i* :lua require('plugins.custom_text_objects').in_symbol('*' ,'*', 'i')<cr>]]
vim.cmd [[onoremap <silent> i* :lua require('plugins.custom_text_objects').in_symbol('*' ,'*', 'i')<cr>]]
This works well with a sentence like this:
*hello*
But when there is no content (i.e. **
), it will just eat up the first or the second *
on ci*
. How can I fix this behavior? I cannot think of a good solution right now.
start_offset
the result of boolean expressionmode == 'i' and start_match[2] or start_match[2]
. That's a redundant way of sayingstart_match[2]
. ;)i*
etc. It will find the most appropriate one (if you're in it, sitting on the last character, find next one in line if you're not inside one) and in many cases properly handle multiple pairs of occurrences in the same line. (If you havethis *word* and that *word*
it will not select the ` and that ` part if you use ani*
there, since*word*
is the appropriate match.)