Regenerate nvim config
This commit is contained in:
@ -0,0 +1,13 @@
|
||||
---@diagnostic disable: undefined-field
|
||||
local empty = {
|
||||
debug = function(_) end,
|
||||
info = function(_) end,
|
||||
error = function(_) end,
|
||||
}
|
||||
if _G.__is_log then
|
||||
return require('plenary.log').new {
|
||||
plugin = 'nvim-autopairs',
|
||||
level = (_G.__is_log == true and 'debug') or 'warn',
|
||||
} or empty
|
||||
end
|
||||
return empty
|
||||
@ -0,0 +1,97 @@
|
||||
local autopairs = require('nvim-autopairs')
|
||||
local handlers = require('nvim-autopairs.completion.handlers')
|
||||
local cmp = require('cmp')
|
||||
|
||||
local Kind = cmp.lsp.CompletionItemKind
|
||||
|
||||
local M = {}
|
||||
|
||||
M.filetypes = {
|
||||
-- Alias to all filetypes
|
||||
["*"] = {
|
||||
["("] = {
|
||||
kind = { Kind.Function, Kind.Method },
|
||||
handler = handlers["*"]
|
||||
}
|
||||
},
|
||||
python = {
|
||||
["("] = {
|
||||
kind = { Kind.Function, Kind.Method },
|
||||
handler = handlers.python
|
||||
}
|
||||
},
|
||||
clojure = {
|
||||
["("] = {
|
||||
kind = { Kind.Function, Kind.Method },
|
||||
handler = handlers.lisp
|
||||
}
|
||||
},
|
||||
clojurescript = {
|
||||
["("] = {
|
||||
kind = { Kind.Function, Kind.Method },
|
||||
handler = handlers.lisp
|
||||
}
|
||||
},
|
||||
fennel = {
|
||||
["("] = {
|
||||
kind = { Kind.Function, Kind.Method },
|
||||
handler = handlers.lisp
|
||||
}
|
||||
},
|
||||
janet = {
|
||||
["("] = {
|
||||
kind = { Kind.Function, Kind.Method },
|
||||
handler = handlers.lisp
|
||||
}
|
||||
},
|
||||
tex = false,
|
||||
plaintex = false,
|
||||
context = false,
|
||||
haskell = false,
|
||||
purescript = false,
|
||||
sh = false,
|
||||
bash = false,
|
||||
nix = false
|
||||
}
|
||||
|
||||
M.on_confirm_done = function(opts)
|
||||
opts = vim.tbl_deep_extend('force', {
|
||||
filetypes = M.filetypes
|
||||
}, opts or {})
|
||||
|
||||
return function(evt)
|
||||
if evt.commit_character then
|
||||
return
|
||||
end
|
||||
|
||||
local entry = evt.entry
|
||||
local commit_character = entry:get_commit_characters()
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
local filetype = vim.api.nvim_buf_get_option(bufnr, 'filetype')
|
||||
local item = entry:get_completion_item()
|
||||
|
||||
-- Without options and fallback
|
||||
if not opts.filetypes[filetype] and not opts.filetypes["*"] then
|
||||
return
|
||||
end
|
||||
|
||||
if opts.filetypes[filetype] == false then
|
||||
return
|
||||
end
|
||||
|
||||
-- If filetype is nil then use *
|
||||
local completion_options = opts.filetypes[filetype] or opts.filetypes["*"]
|
||||
|
||||
local rules = vim.tbl_filter(function(rule)
|
||||
return completion_options[rule.key_map]
|
||||
end, autopairs.get_buf_rules(bufnr))
|
||||
|
||||
for char, value in pairs(completion_options) do
|
||||
if vim.tbl_contains(value.kind, item.kind) then
|
||||
value.handler(char, item, bufnr, rules, commit_character)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
@ -0,0 +1,86 @@
|
||||
local npairs = require('nvim-autopairs')
|
||||
local Completion = require('compe.completion')
|
||||
local utils = require('nvim-autopairs.utils')
|
||||
|
||||
local method_kind = nil
|
||||
local function_kind = nil
|
||||
|
||||
local options = {}
|
||||
|
||||
local M = {}
|
||||
M.completion_done = function()
|
||||
local line = utils.text_get_current_line(0)
|
||||
local _, col = utils.get_cursor()
|
||||
local prev_char, next_char = utils.text_cusor_line(line, col, 1, 1, false)
|
||||
|
||||
local filetype = vim.bo.filetype
|
||||
local char = options.map_char[filetype] or options.map_char["all"] or '('
|
||||
if char == '' then return end
|
||||
|
||||
if prev_char ~= char and next_char ~= char then
|
||||
if method_kind == nil then
|
||||
method_kind = require('vim.lsp.protocol').CompletionItemKind[2]
|
||||
function_kind = require('vim.lsp.protocol').CompletionItemKind[3]
|
||||
end
|
||||
local item = Completion._confirm_item
|
||||
if item.kind == method_kind or item.kind == function_kind then
|
||||
-- check insert text have ( from snippet
|
||||
local completion_item = item.user_data.compe.completion_item
|
||||
if
|
||||
(
|
||||
completion_item.textEdit
|
||||
and completion_item.textEdit.newText
|
||||
and completion_item.textEdit.newText:match('[%(%[%$]')
|
||||
)
|
||||
or (completion_item.insertText and completion_item.insertText:match('[%(%[%$]'))
|
||||
then
|
||||
return
|
||||
end
|
||||
vim.api.nvim_feedkeys(char, 'i', true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
M.setup = function(opt)
|
||||
opt = opt or { map_cr = true, map_complete = true, auto_select = false, map_char = {all = '('}}
|
||||
if not opt.map_char then opt.map_char = {} end
|
||||
options = opt
|
||||
local map_cr = opt.map_cr
|
||||
local map_complete = opt.map_complete
|
||||
vim.g.completion_confirm_key = ''
|
||||
if map_cr then
|
||||
vim.api.nvim_set_keymap(
|
||||
'i',
|
||||
'<CR>',
|
||||
'',
|
||||
{ callback = M.completion_confirm, expr = true, noremap = true }
|
||||
)
|
||||
end
|
||||
if opt.auto_select then
|
||||
M.completion_confirm = function()
|
||||
if vim.fn.pumvisible() ~= 0 then
|
||||
return vim.fn['compe#confirm']({ keys = '<CR>', select = true })
|
||||
else
|
||||
return npairs.autopairs_cr()
|
||||
end
|
||||
end
|
||||
else
|
||||
M.completion_confirm = function()
|
||||
if vim.fn.pumvisible() ~= 0 and vim.fn.complete_info()['selected'] ~= -1 then
|
||||
return vim.fn['compe#confirm'](npairs.esc('<cr>'))
|
||||
else
|
||||
return npairs.autopairs_cr()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if map_complete then
|
||||
vim.cmd([[
|
||||
augroup autopairs_compe
|
||||
autocmd!
|
||||
autocmd User CompeConfirmDone lua require'nvim-autopairs.completion.compe'.completion_done()
|
||||
augroup end
|
||||
]])
|
||||
end
|
||||
end
|
||||
return M
|
||||
@ -0,0 +1,91 @@
|
||||
local autopairs = require('nvim-autopairs')
|
||||
local utils = require('nvim-autopairs.utils')
|
||||
|
||||
local M = {}
|
||||
|
||||
---@param char string
|
||||
---@param item table
|
||||
---@param bufnr number
|
||||
---@param rules table
|
||||
---@param commit_character table<string>
|
||||
M["*"] = function(char, item, bufnr, rules, _)
|
||||
local line = utils.text_get_current_line(bufnr)
|
||||
local _, col = utils.get_cursor()
|
||||
local char_before, char_after = utils.text_cusor_line(line, col, 1, 1, false)
|
||||
|
||||
if char == '' or char_before == char or char_after == char
|
||||
or (item.data and type(item.data) == 'table' and item.data.funcParensDisabled)
|
||||
or (item.textEdit and item.textEdit.newText and item.textEdit.newText:match "[%(%[%$]")
|
||||
or (item.insertText and item.insertText:match "[%(%[%$]")
|
||||
then
|
||||
return
|
||||
end
|
||||
|
||||
if vim.tbl_isempty(rules) then
|
||||
return
|
||||
end
|
||||
|
||||
local new_text = ''
|
||||
local add_char = 1
|
||||
|
||||
for _, rule in pairs(rules) do
|
||||
if rule.start_pair then
|
||||
local prev_char, next_char = utils.text_cusor_line(
|
||||
new_text,
|
||||
col + add_char,
|
||||
#rule.start_pair,
|
||||
#rule.end_pair,
|
||||
rule.is_regex
|
||||
)
|
||||
local cond_opt = {
|
||||
ts_node = autopairs.state.ts_node,
|
||||
text = new_text,
|
||||
rule = rule,
|
||||
bufnr = bufnr,
|
||||
col = col + 1,
|
||||
char = char,
|
||||
line = line,
|
||||
prev_char = prev_char,
|
||||
next_char = next_char,
|
||||
}
|
||||
if rule.key_map and rule:can_pair(cond_opt) then
|
||||
vim.api.nvim_feedkeys(rule.key_map, "i", true)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---Handler with "clojure", "clojurescript", "fennel", "janet
|
||||
M.lisp = function (char, item, bufnr, _, _)
|
||||
local line = utils.text_get_current_line(bufnr)
|
||||
local _, col = utils.get_cursor()
|
||||
local char_before, char_after = utils.text_cusor_line(line, col, 1, 1, false)
|
||||
local length = #item.label
|
||||
|
||||
if char == '' or char_before == char or char_after == char
|
||||
or (item.data and item.data.funcParensDisabled)
|
||||
or (item.textEdit and item.textEdit.newText and item.textEdit.newText:match "[%(%[%$]")
|
||||
or (item.insertText and item.insertText:match "[%(%[%$]")
|
||||
then
|
||||
return
|
||||
end
|
||||
|
||||
if utils.text_sub_char(line, col - length, 1) == "(" then
|
||||
utils.feed("<Space>")
|
||||
return
|
||||
end
|
||||
utils.feed(utils.key.left, length)
|
||||
utils.feed(char)
|
||||
utils.feed(utils.key.right, length)
|
||||
utils.feed("<Space>")
|
||||
end
|
||||
|
||||
M.python = function(char, item, bufnr, rules, _)
|
||||
if item.data then
|
||||
item.data.funcParensDisabled = false
|
||||
end
|
||||
M["*"](char,item,bufnr,rules)
|
||||
end
|
||||
|
||||
return M
|
||||
@ -0,0 +1,350 @@
|
||||
local utils = require('nvim-autopairs.utils')
|
||||
local log = require('nvim-autopairs._log')
|
||||
---@class CondOpts
|
||||
---@field ts_node table
|
||||
---@field text string
|
||||
---@field rule table
|
||||
---@field bufnr number
|
||||
---@field col number
|
||||
---@field char string
|
||||
---@field line string
|
||||
---@field prev_char string
|
||||
---@field next_char string
|
||||
---@field is_endwise string
|
||||
|
||||
local cond = {}
|
||||
|
||||
-- cond
|
||||
-- @return false when it is not correct
|
||||
-- true when it is correct
|
||||
-- nil when it is not determine
|
||||
-- stylua: ignore
|
||||
cond.none = function()
|
||||
return function() return false end
|
||||
end
|
||||
-- stylua: ignore
|
||||
cond.done = function()
|
||||
return function() return true end
|
||||
end
|
||||
|
||||
cond.invert = function(func)
|
||||
return function(...)
|
||||
local result = func(...)
|
||||
if result ~= nil then
|
||||
return not result
|
||||
end
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
cond.before_regex = function(regex, length)
|
||||
length = length or 1
|
||||
if length < 0 then length = nil end
|
||||
length = length and -length
|
||||
---@param opts CondOpts
|
||||
return function(opts)
|
||||
log.debug('before_regex')
|
||||
local str = utils.text_sub_char(opts.line, opts.col - 1, length or -opts.col)
|
||||
if str:match(regex) then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
cond.before_text = function(text)
|
||||
local length = #text
|
||||
---@param opts CondOpts
|
||||
return function(opts)
|
||||
log.debug('before_text')
|
||||
local str = utils.text_sub_char(opts.line, opts.col - 1, -length)
|
||||
if str == text then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
cond.after_text = function(text)
|
||||
local length = #text
|
||||
---@param opts CondOpts
|
||||
return function(opts)
|
||||
log.debug('after_text')
|
||||
local str = utils.text_sub_char(opts.line, opts.col, length)
|
||||
if str == text then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
cond.after_regex = function(regex, length)
|
||||
length = length or 1
|
||||
if length < 0 then length = nil end
|
||||
---@param opts CondOpts
|
||||
return function(opts)
|
||||
log.debug('after_regex')
|
||||
local str = utils.text_sub_char(opts.line, opts.col, length or #opts.line)
|
||||
if str:match(regex) then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
cond.not_before_text = function(text)
|
||||
local length = #text
|
||||
return function(opts)
|
||||
log.debug('not_before_text')
|
||||
local str = utils.text_sub_char(opts.line, opts.col - 1, -length)
|
||||
if str == text then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
cond.not_after_text = function(text)
|
||||
local length = #text
|
||||
---@param opts CondOpts
|
||||
return function(opts)
|
||||
log.debug('not_after_text')
|
||||
local str = utils.text_sub_char(opts.line, opts.col, length)
|
||||
if str == text then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
cond.not_before_regex = function(regex, length)
|
||||
length = length or 1
|
||||
if length < 0 then length = nil end
|
||||
length = length and -length
|
||||
---@param opts CondOpts
|
||||
return function(opts)
|
||||
log.debug('not_before_regex')
|
||||
log.debug(length)
|
||||
local str = utils.text_sub_char(opts.line, opts.col - 1, length or -opts.col)
|
||||
if str:match(regex) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
cond.not_after_regex = function(regex, length)
|
||||
length = length or 1
|
||||
if length < 0 then length = nil end
|
||||
---@param opts CondOpts
|
||||
return function(opts)
|
||||
log.debug('not_after_regex')
|
||||
local str = utils.text_sub_char(opts.line, opts.col, length or #opts.line)
|
||||
if str:match(regex) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function count_bracket_char(line, prev_char, next_char)
|
||||
local count_prev_char = 0
|
||||
local count_next_char = 0
|
||||
for i = 1, #line, 1 do
|
||||
local c = line:sub(i, i)
|
||||
if c == prev_char then
|
||||
count_prev_char = count_prev_char + 1
|
||||
elseif c == next_char then
|
||||
count_next_char = count_next_char + 1
|
||||
end
|
||||
end
|
||||
return count_prev_char, count_next_char
|
||||
end
|
||||
|
||||
-- Checks if bracket chars are balanced around specific postion.
|
||||
---@param line string
|
||||
---@param open_char string
|
||||
---@param close_char string
|
||||
---@param col integer position
|
||||
local function is_brackets_balanced_around_position(line, open_char, close_char, col)
|
||||
local balance = 0
|
||||
for i = 1, #line, 1 do
|
||||
local c = line:sub(i, i)
|
||||
if c == open_char then
|
||||
balance = balance + 1
|
||||
elseif balance > 0 and c == close_char then
|
||||
balance = balance - 1
|
||||
if col <= i and balance == 0 then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
return balance == 0
|
||||
end
|
||||
|
||||
cond.is_bracket_line = function()
|
||||
---@param opts CondOpts
|
||||
return function(opts)
|
||||
log.debug('is_bracket_line')
|
||||
if utils.is_bracket(opts.char) and
|
||||
(opts.next_char == opts.rule.end_pair
|
||||
or opts.next_char == opts.rule.start_pair)
|
||||
then
|
||||
-- (( many char |)) => add
|
||||
-- ( many char |)) => not add
|
||||
local count_prev_char, count_next_char = count_bracket_char(
|
||||
opts.line,
|
||||
opts.rule.start_pair,
|
||||
opts.rule.end_pair
|
||||
)
|
||||
if count_prev_char ~= count_next_char then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
cond.is_bracket_line_move = function()
|
||||
---@param opts CondOpts
|
||||
return function(opts)
|
||||
log.debug('is_bracket_line_move')
|
||||
if utils.is_close_bracket(opts.char)
|
||||
and opts.char == opts.rule.end_pair
|
||||
then
|
||||
-- (( many char |)) => move
|
||||
-- (( many char |) => not move
|
||||
local is_balanced = is_brackets_balanced_around_position(
|
||||
opts.line,
|
||||
opts.rule.start_pair,
|
||||
opts.char,
|
||||
opts.col
|
||||
)
|
||||
return is_balanced
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
cond.not_inside_quote = function()
|
||||
---@param opts CondOpts
|
||||
return function(opts)
|
||||
log.debug('not_inside_quote')
|
||||
if utils.is_in_quotes(opts.text, opts.col - 1) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
cond.is_inside_quote = function()
|
||||
---@param opts CondOpts
|
||||
return function(opts)
|
||||
log.debug('is_inside_quote')
|
||||
if utils.is_in_quotes(opts.text, opts.col - 1) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
cond.not_add_quote_inside_quote = function()
|
||||
---@param opts CondOpts
|
||||
return function(opts)
|
||||
log.debug('not_add_quote_inside_quote')
|
||||
if utils.is_quote(opts.char)
|
||||
and utils.is_in_quotes(opts.text, opts.col - 1)
|
||||
then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
cond.move_right = function()
|
||||
---@param opts CondOpts
|
||||
return function(opts)
|
||||
log.debug('move_right')
|
||||
if opts.next_char == opts.char then
|
||||
if utils.is_close_bracket(opts.char) then
|
||||
return
|
||||
end
|
||||
-- move right when have quote on end line or in quote
|
||||
-- situtaion |" => "|
|
||||
if utils.is_quote(opts.char) then
|
||||
if opts.col == string.len(opts.line) then
|
||||
return
|
||||
end
|
||||
-- ("|") => (""|)
|
||||
-- "" |" " => "" "| "
|
||||
if utils.is_in_quotes(opts.line, opts.col - 1, opts.char) then
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
cond.is_end_line = function()
|
||||
---@param opts CondOpts
|
||||
return function(opts)
|
||||
log.debug('is_end_line')
|
||||
local end_text = opts.line:sub(opts.col + 1)
|
||||
-- end text is blank
|
||||
if end_text ~= '' and end_text:match('^%s+$') == nil then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Check the next char is quote and cursor is inside quote
|
||||
cond.is_bracket_in_quote = function()
|
||||
---@param opts CondOpts
|
||||
return function(opts)
|
||||
log.debug("is_bracket_in_quote")
|
||||
if utils.is_bracket(opts.char)
|
||||
and utils.is_quote(opts.next_char)
|
||||
and utils.is_in_quotes(opts.line, opts.col - 1, opts.next_char)
|
||||
then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
cond.not_filetypes = function(filetypes)
|
||||
return function()
|
||||
log.debug('not_filetypes')
|
||||
for _, filetype in pairs(filetypes) do
|
||||
if vim.bo.filetype == filetype then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Check the character before the cursor is not equal
|
||||
---@param char string character to compare
|
||||
---@param index number the position of character before current curosr
|
||||
cond.not_before_char = function(char, index)
|
||||
index = index or 1
|
||||
---@param opts CondOpts
|
||||
return function(opts)
|
||||
log.debug('not_before_char')
|
||||
local match_char = #opts.line > index
|
||||
and opts.line:sub(#opts.line - index, #opts.line - index) or ''
|
||||
if match_char == char and match_char ~= "" then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@deprecated
|
||||
cond.not_after_regex_check = cond.not_after_regex
|
||||
---@deprecated
|
||||
cond.after_regex_check = cond.after_regex
|
||||
---@deprecated
|
||||
cond.before_regex_check = cond.before_regex
|
||||
---@deprecated
|
||||
cond.not_before_regex_check = cond.not_before_regex
|
||||
---@deprecated
|
||||
cond.after_text_check = cond.after_text
|
||||
---@deprecated
|
||||
cond.not_after_text_check = cond.not_after_text
|
||||
---@deprecated
|
||||
cond.before_text_check = cond.before_text
|
||||
---@deprecated
|
||||
cond.not_before_text_check = cond.not_before_text
|
||||
|
||||
return cond
|
||||
@ -0,0 +1,222 @@
|
||||
local utils = require('nvim-autopairs.utils')
|
||||
local log = require('nvim-autopairs._log')
|
||||
local npairs = require('nvim-autopairs')
|
||||
local M = {}
|
||||
|
||||
local default_config = {
|
||||
map = '<M-e>',
|
||||
chars = { '{', '[', '(', '"', "'" },
|
||||
pattern = [=[[%'%"%>%]%)%}%,%`]]=],
|
||||
end_key = '$',
|
||||
before_key = 'h',
|
||||
after_key = 'l',
|
||||
cursor_pos_before = true,
|
||||
keys = 'qwertyuiopzxcvbnmasdfghjkl',
|
||||
highlight = 'Search',
|
||||
highlight_grey = 'Comment',
|
||||
manual_position = true,
|
||||
use_virt_lines = true
|
||||
}
|
||||
|
||||
M.ns_fast_wrap = vim.api.nvim_create_namespace('autopairs_fastwrap')
|
||||
|
||||
local config = {}
|
||||
|
||||
M.setup = function(cfg)
|
||||
if config.chars == nil then
|
||||
config = vim.tbl_extend('force', default_config, cfg or {}) or {}
|
||||
npairs.config.fast_wrap = config
|
||||
end
|
||||
end
|
||||
|
||||
function M.getchar_handler()
|
||||
local ok, key = pcall(vim.fn.getchar)
|
||||
if not ok then
|
||||
return nil
|
||||
end
|
||||
if key ~= 27 and type(key) == 'number' then
|
||||
local key_str = vim.fn.nr2char(key)
|
||||
return key_str
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
M.show = function(line)
|
||||
line = line or utils.text_get_current_line(0)
|
||||
log.debug(line)
|
||||
local row, col = utils.get_cursor()
|
||||
local prev_char = utils.text_cusor_line(line, col, 1, 1, false)
|
||||
local end_pair = ''
|
||||
if utils.is_in_table(config.chars, prev_char) then
|
||||
local rules = npairs.get_buf_rules()
|
||||
for _, rule in pairs(rules) do
|
||||
if rule.start_pair == prev_char then
|
||||
end_pair = rule.end_pair
|
||||
end
|
||||
end
|
||||
if end_pair == '' then
|
||||
return
|
||||
end
|
||||
local list_pos = {}
|
||||
local index = 1
|
||||
local str_length = #line
|
||||
local offset = -1
|
||||
for i = col + 2, #line, 1 do
|
||||
local char = line:sub(i, i)
|
||||
local char2 = line:sub(i - 1, i)
|
||||
if string.match(char, config.pattern)
|
||||
or (char == ' ' and string.match(char2, '%w'))
|
||||
then
|
||||
local key = config.keys:sub(index, index)
|
||||
index = index + 1
|
||||
if not config.manual_position and (
|
||||
utils.is_quote(char)
|
||||
or (
|
||||
utils.is_close_bracket(char)
|
||||
and utils.is_in_quotes(line, col, prev_char)
|
||||
)
|
||||
)
|
||||
then
|
||||
offset = 0
|
||||
end
|
||||
|
||||
if config.manual_position and i == str_length then
|
||||
key = config.end_key
|
||||
end
|
||||
|
||||
table.insert(
|
||||
list_pos,
|
||||
{ col = i + offset, key = key, char = char, pos = i }
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
local end_col, end_pos
|
||||
if config.manual_position then
|
||||
end_col = str_length + offset
|
||||
end_pos = str_length
|
||||
else
|
||||
end_col = str_length + 1
|
||||
end_pos = str_length + 1
|
||||
end
|
||||
-- add end_key to list extmark
|
||||
if #list_pos == 0 or list_pos[#list_pos].key ~= config.end_key then
|
||||
table.insert(
|
||||
list_pos,
|
||||
{ col = end_col, key = config.end_key, pos = end_pos, char = config.end_key }
|
||||
)
|
||||
end
|
||||
|
||||
-- Create a whitespace string for the current line which replaces every non whitespace
|
||||
-- character with a space and preserves tabs, so we can use it for highlighting with
|
||||
-- virtual lines so that highlighting lines up correctly.
|
||||
-- The string is limited to the last position in list_pos
|
||||
local whitespace_line = line:sub(1, list_pos[#list_pos].end_pos):gsub("[^ \t]", " ")
|
||||
|
||||
M.highlight_wrap(list_pos, row, col, #line, whitespace_line)
|
||||
vim.defer_fn(function()
|
||||
-- get the first char
|
||||
local char = #list_pos == 1 and config.end_key or M.getchar_handler()
|
||||
vim.api.nvim_buf_clear_namespace(0, M.ns_fast_wrap, row, row + 1)
|
||||
for _, pos in pairs(list_pos) do
|
||||
local hl_mark = {
|
||||
{ pos = pos.pos - 1, key = config.before_key },
|
||||
{ pos = pos.pos + 1, key = config.after_key },
|
||||
}
|
||||
if config.manual_position and (char == pos.key or char == string.upper(pos.key)) then
|
||||
M.highlight_wrap(hl_mark, row, col, #line, whitespace_line)
|
||||
M.choose_pos(row, line, pos, end_pair)
|
||||
break
|
||||
end
|
||||
if char == pos.key then
|
||||
M.move_bracket(line, pos.col, end_pair, false)
|
||||
break
|
||||
end
|
||||
if char == string.upper(pos.key) then
|
||||
M.move_bracket(line, pos.col, end_pair, true)
|
||||
break
|
||||
end
|
||||
end
|
||||
vim.cmd('startinsert')
|
||||
end, 10)
|
||||
return
|
||||
end
|
||||
vim.cmd('startinsert')
|
||||
end
|
||||
|
||||
M.choose_pos = function(row, line, pos, end_pair)
|
||||
vim.defer_fn(function()
|
||||
-- select a second key
|
||||
local char =
|
||||
pos.char == nil and config.before_key
|
||||
or pos.char == config.end_key and config.after_key
|
||||
or M.getchar_handler()
|
||||
vim.api.nvim_buf_clear_namespace(0, M.ns_fast_wrap, row, row + 1)
|
||||
if not char then return end
|
||||
local change_pos = false
|
||||
local col = pos.col
|
||||
if char == string.upper(config.before_key) or char == string.upper(config.after_key) then
|
||||
change_pos = true
|
||||
end
|
||||
if char == config.after_key or char == string.upper(config.after_key) then
|
||||
col = pos.col + 1
|
||||
end
|
||||
M.move_bracket(line, col, end_pair, change_pos)
|
||||
vim.cmd('startinsert')
|
||||
end, 10)
|
||||
end
|
||||
|
||||
M.move_bracket = function(line, target_pos, end_pair, change_pos)
|
||||
log.debug(target_pos)
|
||||
line = line or utils.text_get_current_line(0)
|
||||
local row, col = utils.get_cursor()
|
||||
local _, next_char = utils.text_cusor_line(line, col, 1, 1, false)
|
||||
-- remove an autopairs if that exist
|
||||
if next_char == end_pair then
|
||||
line = line:sub(1, col) .. line:sub(col + 2, #line)
|
||||
target_pos = target_pos - 1
|
||||
end
|
||||
|
||||
line = line:sub(1, target_pos) .. end_pair .. line:sub(target_pos + 1, #line)
|
||||
vim.api.nvim_set_current_line(line)
|
||||
if change_pos then
|
||||
vim.api.nvim_win_set_cursor(0, { row + 1, target_pos + (config.cursor_pos_before and 0 or 1) })
|
||||
end
|
||||
end
|
||||
|
||||
M.highlight_wrap = function(tbl_pos, row, col, end_col, whitespace_line)
|
||||
local bufnr = vim.api.nvim_win_get_buf(0)
|
||||
if config.use_virt_lines then
|
||||
local virt_lines = {}
|
||||
local start = 0
|
||||
for _, pos in ipairs(tbl_pos) do
|
||||
virt_lines[#virt_lines + 1] = { whitespace_line:sub(start + 1, pos.pos - 1), 'Normal' }
|
||||
virt_lines[#virt_lines + 1] = { pos.key, config.highlight }
|
||||
start = pos.pos
|
||||
end
|
||||
vim.api.nvim_buf_set_extmark(bufnr, M.ns_fast_wrap, row, 0, {
|
||||
virt_lines = { virt_lines },
|
||||
hl_mode = 'blend',
|
||||
})
|
||||
else
|
||||
if config.highlight_grey then
|
||||
vim.highlight.range(
|
||||
bufnr,
|
||||
M.ns_fast_wrap,
|
||||
config.highlight_grey,
|
||||
{ row, col },
|
||||
{ row, end_col },
|
||||
{}
|
||||
)
|
||||
end
|
||||
for _, pos in ipairs(tbl_pos) do
|
||||
vim.api.nvim_buf_set_extmark(bufnr, M.ns_fast_wrap, row, pos.pos - 1, {
|
||||
virt_text = { { pos.key, config.highlight } },
|
||||
virt_text_pos = 'overlay',
|
||||
hl_mode = 'blend',
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
@ -0,0 +1,224 @@
|
||||
local Cond = require('nvim-autopairs.conds')
|
||||
|
||||
--- @class Rule
|
||||
--- @field start_pair string
|
||||
--- @field end_pair string
|
||||
--- @field end_pair_func function dynamic change end_pair
|
||||
--- @field map_cr_func function dynamic change mapping_cr
|
||||
--- @field end_pair_length number change end_pair length for key map like <left>
|
||||
--- @field key_map string|nil equal nil mean it will skip on autopairs map
|
||||
--- @field filetypes table|nil
|
||||
--- @field not_filetypes table|nil
|
||||
--- @field is_regex boolean use regex to compare
|
||||
--- @field is_multibyte boolean
|
||||
--- @field is_endwise boolean only use on end_wise
|
||||
--- @field is_undo boolean add break undo sequence
|
||||
|
||||
local Rule = setmetatable({}, {
|
||||
__call = function(self, ...)
|
||||
return self.new(...)
|
||||
end,
|
||||
})
|
||||
|
||||
---@return Rule
|
||||
function Rule.new(...)
|
||||
local params = { ... }
|
||||
local opt = {}
|
||||
if type(params[1]) == 'table' then
|
||||
opt = params[1]
|
||||
else
|
||||
opt.start_pair = params[1]
|
||||
opt.end_pair = params[2]
|
||||
if type(params[3]) == 'string' then
|
||||
opt.filetypes = { params[3] }
|
||||
else
|
||||
opt.filetypes = params[3]
|
||||
end
|
||||
end
|
||||
opt = vim.tbl_extend('force', {
|
||||
key_map = "",
|
||||
start_pair = nil,
|
||||
end_pair = nil,
|
||||
end_pair_func = false,
|
||||
filetypes = nil,
|
||||
not_filetypes = nil,
|
||||
move_cond = nil,
|
||||
del_cond = {},
|
||||
cr_cond = {},
|
||||
pair_cond = {},
|
||||
is_endwise = false,
|
||||
is_regex = false,
|
||||
is_multibyte = false,
|
||||
end_pair_length = nil,
|
||||
}, opt) or {}
|
||||
|
||||
---@param rule Rule
|
||||
local function constructor(rule)
|
||||
-- check multibyte
|
||||
if #rule.start_pair ~= vim.api.nvim_strwidth(rule.start_pair) then
|
||||
rule:use_multibyte()
|
||||
end
|
||||
-- check filetypes and not_filetypes
|
||||
-- if have something like "-vim" it will add to not_filetypes
|
||||
if rule.filetypes then
|
||||
local ft, not_ft = {}, {}
|
||||
for _, value in pairs(rule.filetypes) do
|
||||
if value:sub(1, 1) == '-' then
|
||||
table.insert(not_ft, value:sub(2, #value))
|
||||
else
|
||||
table.insert(ft, value)
|
||||
end
|
||||
end
|
||||
rule.filetypes = #ft > 0 and ft or nil
|
||||
rule.not_filetypes = #not_ft > 0 and not_ft or nil
|
||||
end
|
||||
return rule
|
||||
end
|
||||
|
||||
local r = setmetatable(opt, { __index = Rule })
|
||||
return constructor(r)
|
||||
end
|
||||
|
||||
function Rule:use_regex(value, key_map)
|
||||
self.is_regex = value
|
||||
self.key_map = key_map or ''
|
||||
return self
|
||||
end
|
||||
|
||||
function Rule:use_key(key_map)
|
||||
self.key_map = key_map or ''
|
||||
return self
|
||||
end
|
||||
|
||||
function Rule:use_undo(value)
|
||||
self.is_undo = value
|
||||
return self
|
||||
end
|
||||
|
||||
function Rule:use_multibyte()
|
||||
self.is_multibyte = true
|
||||
self.end_pair_length = vim.fn.strdisplaywidth(self.end_pair)
|
||||
self.key_map = string.match(self.start_pair, "[^\128-\191][\128-\191]*$")
|
||||
self.key_end = string.match(self.end_pair, "[%z\1-\127\194-\244][\128-\191]*")
|
||||
return self
|
||||
end
|
||||
|
||||
function Rule:get_end_pair(opts)
|
||||
if self.end_pair_func then
|
||||
return self.end_pair_func(opts)
|
||||
end
|
||||
return self.end_pair
|
||||
end
|
||||
|
||||
function Rule:get_map_cr(opts)
|
||||
if self.map_cr_func then
|
||||
return self.map_cr_func(opts)
|
||||
end
|
||||
return '<c-g>u<CR><CMD>normal! ====<CR><up><end><CR>'
|
||||
end
|
||||
function Rule:replace_map_cr(value)
|
||||
self.map_cr_func = value
|
||||
return self
|
||||
end
|
||||
|
||||
function Rule:get_end_pair_length(opts)
|
||||
if self.end_pair_length then
|
||||
return self.end_pair_length
|
||||
end
|
||||
if type(opts) == 'string' then
|
||||
return #opts
|
||||
end
|
||||
return #self.get_end_pair(opts)
|
||||
end
|
||||
|
||||
function Rule:replace_endpair(value, check_pair)
|
||||
self.end_pair_func = value
|
||||
if check_pair ~= nil then
|
||||
if check_pair == true then
|
||||
self:with_pair(Cond.after_text(self.end_pair))
|
||||
else
|
||||
self:with_pair(check_pair)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
function Rule:set_end_pair_length(length)
|
||||
self.end_pair_length = length
|
||||
return self
|
||||
end
|
||||
|
||||
function Rule:with_move(cond)
|
||||
if self.move_cond == nil then self.move_cond = {} end
|
||||
table.insert(self.move_cond, cond)
|
||||
return self
|
||||
end
|
||||
|
||||
function Rule:with_del(cond)
|
||||
if self.del_cond == nil then self.del_cond = {} end
|
||||
table.insert(self.del_cond, cond)
|
||||
return self
|
||||
end
|
||||
|
||||
function Rule:with_cr(cond)
|
||||
if self.cr_cond == nil then self.cr_cond = {} end
|
||||
table.insert(self.cr_cond, cond)
|
||||
return self
|
||||
end
|
||||
|
||||
---add condition to rule
|
||||
---@param cond any
|
||||
---@param pos number|nil = 1. It have higher priority to another condition
|
||||
---@return Rule
|
||||
function Rule:with_pair(cond, pos)
|
||||
if self.pair_cond == nil then self.pair_cond = {} end
|
||||
self.pair_cond[pos or (#self.pair_cond + 1)] = cond
|
||||
return self
|
||||
end
|
||||
|
||||
function Rule:only_cr(cond)
|
||||
self.key_map = nil
|
||||
self.pair_cond = false
|
||||
self.move_cond = false
|
||||
self.del_cond = false
|
||||
if cond then return self:with_cr(cond) end
|
||||
return self
|
||||
end
|
||||
|
||||
function Rule:end_wise(cond)
|
||||
self.is_endwise = true
|
||||
return self:only_cr(cond)
|
||||
end
|
||||
|
||||
local function can_do(conds, opt)
|
||||
if type(conds) == 'table' then
|
||||
for _, cond in pairs(conds) do
|
||||
local result = cond(opt)
|
||||
if result ~= nil then
|
||||
return result
|
||||
end
|
||||
end
|
||||
return true
|
||||
elseif type(conds) == 'function' then
|
||||
return conds(opt) == true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function Rule:can_pair(opt)
|
||||
return can_do(self.pair_cond, opt)
|
||||
end
|
||||
|
||||
function Rule:can_move(opt)
|
||||
return can_do(self.move_cond, opt)
|
||||
end
|
||||
|
||||
function Rule:can_del(opt)
|
||||
return can_do(self.del_cond, opt)
|
||||
end
|
||||
|
||||
function Rule:can_cr(opt)
|
||||
return can_do(self.cr_cond, opt)
|
||||
end
|
||||
|
||||
return Rule
|
||||
@ -0,0 +1,86 @@
|
||||
local Rule = require("nvim-autopairs.rule")
|
||||
local cond = require("nvim-autopairs.conds")
|
||||
local utils = require('nvim-autopairs.utils')
|
||||
|
||||
local function quote_creator(opt)
|
||||
local quote = function(...)
|
||||
local move_func = opt.enable_moveright and cond.move_right or cond.none
|
||||
local rule = Rule(...)
|
||||
:with_move(move_func())
|
||||
:with_pair(cond.not_add_quote_inside_quote())
|
||||
|
||||
if #opt.ignored_next_char > 1 then
|
||||
rule:with_pair(cond.not_after_regex(opt.ignored_next_char))
|
||||
end
|
||||
rule:use_undo(opt.break_undo)
|
||||
return rule
|
||||
end
|
||||
return quote
|
||||
end
|
||||
|
||||
local function bracket_creator(opt)
|
||||
local quote = quote_creator(opt)
|
||||
local bracket = function(...)
|
||||
local rule = quote(...)
|
||||
if opt.enable_check_bracket_line == true then
|
||||
rule:with_pair(cond.is_bracket_line())
|
||||
:with_move(cond.is_bracket_line_move())
|
||||
end
|
||||
if opt.enable_bracket_in_quote then
|
||||
-- still add bracket if text is quote "|" and next_char have "
|
||||
rule:with_pair(cond.is_bracket_in_quote(), 1)
|
||||
end
|
||||
return rule
|
||||
end
|
||||
return bracket
|
||||
end
|
||||
|
||||
local function setup(opt)
|
||||
local quote = quote_creator(opt)
|
||||
local bracket = bracket_creator(opt)
|
||||
local rules = {
|
||||
Rule("<!--", "-->", { "html", "markdown" }):with_cr(cond.none()),
|
||||
Rule("```", "```", { "markdown", "vimwiki", "rmarkdown", "rmd", "pandoc" }),
|
||||
Rule("```.*$", "```", { "markdown", "vimwiki", "rmarkdown", "rmd", "pandoc" }):only_cr():use_regex(true),
|
||||
Rule('"""', '"""', { "python", "elixir", "julia", "kotlin" }):with_pair(cond.not_before_char('"', 3)),
|
||||
Rule("'''", "'''", { "python" }):with_pair(cond.not_before_char('"', 3)),
|
||||
quote("'", "'", { "-rust", "-nix" })
|
||||
:with_pair(function(opts)
|
||||
-- python literals string
|
||||
local str = utils.text_sub_char(opts.line, opts.col - 1, 1)
|
||||
if vim.bo.filetype == 'python' and str:match("[frbuFRBU]") then
|
||||
return true
|
||||
end
|
||||
end)
|
||||
:with_pair(cond.not_before_regex("%w")),
|
||||
quote("'", "'", "rust"):with_pair(cond.not_before_regex("[%w<&]")):with_pair(cond.not_after_text(">")),
|
||||
Rule("''", "''", 'nix'):with_move(cond.after_text("'")),
|
||||
quote("`", "`"),
|
||||
quote('"', '"', "-vim"),
|
||||
quote('"', '"', "vim"):with_pair(cond.not_before_regex("^%s*$", -1)),
|
||||
bracket("(", ")"),
|
||||
bracket("[", "]"),
|
||||
bracket("{", "}"),
|
||||
Rule(
|
||||
">[%w%s]*$",
|
||||
"^%s*</",
|
||||
{
|
||||
"html",
|
||||
"htmldjango",
|
||||
"php",
|
||||
"typescript",
|
||||
"typescriptreact",
|
||||
"javascript",
|
||||
"javascriptreact",
|
||||
"svelte",
|
||||
"vue",
|
||||
"xml",
|
||||
"rescript",
|
||||
"astro",
|
||||
}
|
||||
):only_cr():use_regex(true),
|
||||
}
|
||||
return rules
|
||||
end
|
||||
|
||||
return { setup = setup, quote_creator = quote_creator, bracket_creator = bracket_creator }
|
||||
@ -0,0 +1,9 @@
|
||||
local endwise = require('nvim-autopairs.ts-rule').endwise
|
||||
|
||||
local rules = {
|
||||
endwise('%sdo$', 'end', 'elixir', nil),
|
||||
endwise('fn$', 'end', 'elixir', nil),
|
||||
endwise('fn.*->$', 'end', 'elixir', nil),
|
||||
}
|
||||
|
||||
return rules
|
||||
@ -0,0 +1,9 @@
|
||||
local endwise = require('nvim-autopairs.ts-rule').endwise
|
||||
|
||||
local rules = {
|
||||
endwise('then$', 'end', 'lua', 'if_statement'),
|
||||
endwise('function.*%(.*%)$', 'end', 'lua', {'function_declaration', 'local_function', 'function'}),
|
||||
}
|
||||
|
||||
|
||||
return rules
|
||||
@ -0,0 +1,17 @@
|
||||
local endwise = require('nvim-autopairs.ts-rule').endwise
|
||||
|
||||
local rules = {
|
||||
endwise('%sdo$', 'end', 'ruby', nil),
|
||||
endwise('%sdo%s|.*|$', 'end', 'ruby', nil),
|
||||
endwise('begin$', 'end', 'ruby', nil),
|
||||
endwise('def%s.+$', 'end', 'ruby', nil),
|
||||
endwise('module%s.+$', 'end', 'ruby', nil),
|
||||
endwise('class%s.+$', 'end', 'ruby', nil),
|
||||
endwise('[%s=]%sif%s.+$', 'end', 'ruby', nil),
|
||||
endwise('[%s=]%sunless%s.+$', 'end', 'ruby', nil),
|
||||
endwise('[%s=]%scase%s.+$', 'end', 'ruby', nil),
|
||||
endwise('[%s=]%swhile%s.+$', 'end', 'ruby', nil),
|
||||
endwise('[%s=]%suntil%s.+$', 'end', 'ruby', nil),
|
||||
}
|
||||
|
||||
return rules
|
||||
@ -0,0 +1,22 @@
|
||||
local basic = require('nvim-autopairs.rules.basic')
|
||||
local utils = require('nvim-autopairs.utils')
|
||||
local ts_conds = require('nvim-autopairs.ts-conds')
|
||||
local ts_extend = {
|
||||
"'",
|
||||
'"',
|
||||
'(',
|
||||
'[',
|
||||
'{',
|
||||
'`',
|
||||
}
|
||||
return {
|
||||
setup = function (config)
|
||||
local rules=basic.setup(config)
|
||||
for _, rule in pairs(rules) do
|
||||
if utils.is_in_table(ts_extend, rule.start_pair) then
|
||||
rule:with_pair(ts_conds.is_not_ts_node_comment())
|
||||
end
|
||||
end
|
||||
return rules
|
||||
end
|
||||
}
|
||||
@ -0,0 +1,159 @@
|
||||
local log = require('nvim-autopairs._log')
|
||||
local utils = require('nvim-autopairs.utils')
|
||||
local ts_get_node_text = vim.treesitter.get_node_text or vim.treesitter.query.get_node_text
|
||||
|
||||
local conds = {}
|
||||
|
||||
conds.is_endwise_node = function(nodes)
|
||||
if nodes == nil then return function() return true end end
|
||||
if type(nodes) == 'string' then nodes = {nodes} end
|
||||
|
||||
return function (opts)
|
||||
log.debug('is_endwise_node')
|
||||
if not opts.check_endwise_ts then return true end
|
||||
if nodes == nil then return true end
|
||||
if #nodes == 0 then return true end
|
||||
|
||||
vim.treesitter.get_parser():parse()
|
||||
local target = vim.treesitter.get_node({ ignore_injections = false })
|
||||
if target ~= nil and utils.is_in_table(nodes, target:type()) then
|
||||
local text = ts_get_node_text(target) or {""}
|
||||
local last = text[#text]:match(opts.rule.end_pair)
|
||||
-- check last character is match with end_pair
|
||||
if last == nil then
|
||||
return true
|
||||
end
|
||||
-- log.debug('last:' .. last)
|
||||
-- if match then we need tocheck parent node
|
||||
-- some time treesiter is group 2 node then we need check that
|
||||
local begin_target,_, end_target = target:range()
|
||||
local begin_parent,_, end_parent = target:parent():range()
|
||||
-- log.debug(target:range())
|
||||
-- log.debug(ts_get_node_text(target))
|
||||
-- log.debug(target:parent():range())
|
||||
-- log.debug(ts_get_node_text(target:parent()))
|
||||
if
|
||||
(
|
||||
begin_target ~= begin_parent
|
||||
and end_target == end_parent
|
||||
)
|
||||
or
|
||||
(end_parent - end_target == 1)
|
||||
then
|
||||
return true
|
||||
end
|
||||
-- return true
|
||||
else
|
||||
end
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
conds.is_in_range = function(callback, position)
|
||||
assert(
|
||||
type(callback) == 'function' and type(position) == 'function',
|
||||
'callback and position should be a function'
|
||||
)
|
||||
return function(opts)
|
||||
log.debug('is_in_range')
|
||||
-- `parser` will be a table (on success) or a string (error message)
|
||||
local _, parser = pcall(vim.treesitter.get_parser)
|
||||
if not type(parser) == 'string' then
|
||||
return
|
||||
end
|
||||
local cursor = position()
|
||||
assert(
|
||||
type(cursor) == 'table' and #cursor == 2,
|
||||
'position should be return a table like {line, col}'
|
||||
)
|
||||
local line = cursor[1]
|
||||
local col = cursor[2]
|
||||
|
||||
local bufnr = 0
|
||||
local root_lang_tree = vim.treesitter.get_parser(bufnr)
|
||||
local lang_tree = root_lang_tree:language_for_range({ line, col, line, col })
|
||||
|
||||
local result
|
||||
|
||||
for _, tree in ipairs(lang_tree:trees()) do
|
||||
local root = tree:root()
|
||||
if root and vim.treesitter.is_in_node_range(root, line, col) then
|
||||
local node = root:named_descendant_for_range(line, col, line, col)
|
||||
local anonymous_node = root:descendant_for_range(
|
||||
line,
|
||||
col,
|
||||
line,
|
||||
col
|
||||
)
|
||||
|
||||
result = {
|
||||
node = node,
|
||||
lang = lang_tree:lang(),
|
||||
type = node:type(),
|
||||
cursor = vim.api.nvim_win_get_cursor(0),
|
||||
line = vim.api.nvim_buf_get_lines(bufnr, line, line + 1, true)[1],
|
||||
range = { node:range() },
|
||||
anonymous = anonymous_node:type(),
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
return callback(result)
|
||||
end
|
||||
end
|
||||
|
||||
conds.is_ts_node = function(nodes)
|
||||
if type(nodes) == 'string' then nodes = {nodes} end
|
||||
assert(nodes ~= nil, "ts nodes should be string or table")
|
||||
return function (opts)
|
||||
log.debug('is_ts_node')
|
||||
if #nodes == 0 then return end
|
||||
|
||||
vim.treesitter.get_parser():parse()
|
||||
local target = vim.treesitter.get_node({ ignore_injections = false })
|
||||
if target ~= nil and utils.is_in_table(nodes, target:type()) then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
conds.is_not_ts_node = function(nodes)
|
||||
if type(nodes) == 'string' then nodes = {nodes} end
|
||||
assert(nodes ~= nil, "ts nodes should be string or table")
|
||||
return function (opts)
|
||||
log.debug('is_not_ts_node')
|
||||
if #nodes == 0 then return end
|
||||
|
||||
vim.treesitter.get_parser():parse()
|
||||
local target = vim.treesitter.get_node({ ignore_injections = false })
|
||||
if target ~= nil and utils.is_in_table(nodes, target:type()) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
conds.is_not_ts_node_comment = function()
|
||||
return function(opts)
|
||||
log.debug('not_in_ts_node_comment')
|
||||
if not opts.ts_node then return end
|
||||
|
||||
vim.treesitter.get_parser():parse()
|
||||
local target = vim.treesitter.get_node({ ignore_injections = false })
|
||||
if target ~= nil and utils.is_in_table(opts.ts_node, target:type()) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
conds.is_not_in_context = function()
|
||||
return function(opts)
|
||||
local context = require("nvim-autopairs.ts-utils")
|
||||
.get_language_tree_at_position({ utils.get_cursor() })
|
||||
if not vim.tbl_contains(opts.rule.filetypes, context:lang()) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return conds
|
||||
@ -0,0 +1,18 @@
|
||||
local Rule = require('nvim-autopairs.rule')
|
||||
local cond = require('nvim-autopairs.conds')
|
||||
local ts_conds = require('nvim-autopairs.ts-conds')
|
||||
|
||||
return {
|
||||
endwise = function (...)
|
||||
local params = {...}
|
||||
local rule = Rule(...)
|
||||
:use_regex(true)
|
||||
:end_wise(cond.is_end_line())
|
||||
if params[4] then
|
||||
-- rule:with_cr(ts_conds.is_endwise_node(params[4]))
|
||||
rule:with_cr(ts_conds.is_ts_node(params[4]))
|
||||
end
|
||||
return rule
|
||||
end
|
||||
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
local ts_get_node_text = vim.treesitter.get_node_text or vim.treesitter.query.get_node_text
|
||||
local M = {}
|
||||
|
||||
--- Returns the language tree at the given position.
|
||||
---@return LanguageTree
|
||||
function M.get_language_tree_at_position(position)
|
||||
local language_tree = vim.treesitter.get_parser()
|
||||
language_tree:for_each_tree(function(_, tree)
|
||||
if tree:contains(vim.tbl_flatten({ position, position })) then
|
||||
language_tree = tree
|
||||
end
|
||||
end)
|
||||
return language_tree
|
||||
end
|
||||
|
||||
function M.get_tag_name(node)
|
||||
local tag_name = nil
|
||||
if node ~=nil then
|
||||
tag_name = ts_get_node_text(node)
|
||||
end
|
||||
return tag_name
|
||||
end
|
||||
|
||||
return M
|
||||
@ -0,0 +1,198 @@
|
||||
local M = {}
|
||||
local api = vim.api
|
||||
local log = require('nvim-autopairs._log')
|
||||
|
||||
M.key = {
|
||||
del = "<del>",
|
||||
bs = "<bs>",
|
||||
c_h = "<C-h>",
|
||||
left = "<left>",
|
||||
right = "<right>",
|
||||
join_left = "<c-g>U<left>",
|
||||
join_right = "<c-g>U<right>",
|
||||
undo_sequence = "<c-g>u",
|
||||
noundo_sequence = "<c-g>U",
|
||||
abbr = "<c-]>"
|
||||
}
|
||||
|
||||
M.set_vchar = function(text)
|
||||
text = text:gsub('"', '\\"')
|
||||
vim.v.char = text
|
||||
end
|
||||
|
||||
|
||||
M.is_quote = function(char)
|
||||
return char == "'" or char == '"' or char == '`'
|
||||
end
|
||||
|
||||
M.is_bracket = function(char)
|
||||
return char == "(" or char == '[' or char == '{' or char == '<'
|
||||
end
|
||||
|
||||
|
||||
M.is_close_bracket = function(char)
|
||||
return char == ")" or char == ']' or char == '}' or char == '>'
|
||||
end
|
||||
|
||||
M.compare = function(value, text, is_regex)
|
||||
if is_regex and string.match(text, value) then
|
||||
return true
|
||||
elseif text == value then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
---check cursor is inside a quote
|
||||
---@param line string
|
||||
---@param pos number position in line
|
||||
---@param quote_type nil|string specify a quote
|
||||
---@return boolean
|
||||
M.is_in_quotes = function(line, pos, quote_type)
|
||||
local cIndex = 0
|
||||
local result = false
|
||||
local last_char = quote_type or ''
|
||||
|
||||
while cIndex < string.len(line) and cIndex < pos do
|
||||
cIndex = cIndex + 1
|
||||
local char = line:sub(cIndex, cIndex)
|
||||
local prev_char = line:sub(cIndex - 1, cIndex - 1)
|
||||
if
|
||||
result == true
|
||||
and char == last_char
|
||||
and prev_char ~= "\\"
|
||||
then
|
||||
result = false
|
||||
last_char = quote_type or ''
|
||||
elseif
|
||||
result == false
|
||||
and M.is_quote(char)
|
||||
and (not quote_type or char == quote_type)
|
||||
--a single quote with a word before is not count unless it is a
|
||||
-- prefixed string in python (e.g. f'string {with_brackets}')
|
||||
and not (
|
||||
char == "'"
|
||||
and prev_char:match('%w')
|
||||
and (vim.bo.filetype ~= 'python' or prev_char:match('[^frbuFRBU]'))
|
||||
)
|
||||
then
|
||||
last_char = quote_type or char
|
||||
result = true
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
M.is_attached = function(bufnr)
|
||||
local _, check = pcall(api.nvim_buf_get_var, bufnr or 0, "nvim-autopairs")
|
||||
return check == 1
|
||||
end
|
||||
|
||||
|
||||
M.set_attach = function(bufnr, value)
|
||||
api.nvim_buf_set_var(bufnr or 0, "nvim-autopairs", value)
|
||||
end
|
||||
|
||||
M.is_in_table = function(tbl, val)
|
||||
if tbl == nil then return false end
|
||||
for _, value in pairs(tbl) do
|
||||
if val == value then return true end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
M.check_filetype = function(tbl, filetype)
|
||||
if tbl == nil then return true end
|
||||
return M.is_in_table(tbl, filetype)
|
||||
end
|
||||
|
||||
M.check_not_filetype = function(tbl, filetype)
|
||||
if tbl == nil then return true end
|
||||
return not M.is_in_table(tbl, filetype)
|
||||
end
|
||||
|
||||
M.is_in_range = function(row, col, range)
|
||||
local start_row, start_col, end_row, end_col = unpack(range)
|
||||
|
||||
return (row > start_row or (start_row == row and col >= start_col))
|
||||
and (row < end_row or (row == end_row and col <= end_col))
|
||||
end
|
||||
|
||||
M.get_cursor = function(bufnr)
|
||||
local row, col = unpack(api.nvim_win_get_cursor(bufnr or 0))
|
||||
return row - 1, col
|
||||
end
|
||||
M.text_get_line = function(bufnr, lnum)
|
||||
return api.nvim_buf_get_lines(bufnr, lnum, lnum + 1, false)[1] or ''
|
||||
end
|
||||
|
||||
M.text_get_current_line = function(bufnr)
|
||||
local row = unpack(api.nvim_win_get_cursor(0)) or 1
|
||||
return M.text_get_line(bufnr, row - 1)
|
||||
end
|
||||
|
||||
M.repeat_key = function(key, num)
|
||||
local text = ''
|
||||
for _ = 1, num, 1 do
|
||||
text = text .. key
|
||||
end
|
||||
return text
|
||||
end
|
||||
--- cut text from position with number character
|
||||
---@param line string text
|
||||
---@param col number position of text
|
||||
---@param prev_count number number char previous
|
||||
---@param next_count number number char next
|
||||
---@param is_regex boolean if it is regex then will cut all
|
||||
M.text_cusor_line = function(line, col, prev_count, next_count, is_regex)
|
||||
if is_regex then
|
||||
prev_count = col
|
||||
next_count = #line - col
|
||||
end
|
||||
local prev = M.text_sub_char(line, col, -prev_count)
|
||||
local next = M.text_sub_char(line, col + 1, next_count)
|
||||
return prev, next
|
||||
end
|
||||
|
||||
M.text_sub_char = function(line, start, num)
|
||||
local finish = start
|
||||
if num < 0 then
|
||||
start = start + num + 1
|
||||
else
|
||||
finish = start + num - 1
|
||||
end
|
||||
return string.sub(line, start, finish)
|
||||
end
|
||||
|
||||
-- P(M.text_sub_char("aa'' aaa", 3, -1))
|
||||
M.insert_char = function(text)
|
||||
api.nvim_put({ text }, "c", false, true)
|
||||
end
|
||||
|
||||
M.feed = function(text, num)
|
||||
num = num or 1
|
||||
if num < 1 then num = 1 end
|
||||
local result = ''
|
||||
for _ = 1, num, 1 do
|
||||
result = result .. text
|
||||
end
|
||||
log.debug("result" .. result)
|
||||
api.nvim_feedkeys(api.nvim_replace_termcodes(
|
||||
result, true, false, true),
|
||||
"n", true)
|
||||
end
|
||||
|
||||
M.esc = function(cmd)
|
||||
return vim.api.nvim_replace_termcodes(cmd, true, false, true)
|
||||
end
|
||||
|
||||
M.is_block_wise_mode = function()
|
||||
return vim.fn.visualmode() == ''
|
||||
end
|
||||
|
||||
--- get prev_char with out key_map
|
||||
M.get_prev_char = function(opt)
|
||||
return opt.line:sub(opt.col - 1, opt.col + #opt.rule.start_pair - 2)
|
||||
end
|
||||
|
||||
return M
|
||||
Reference in New Issue
Block a user