Implement vim edit inside delimiters

This commit is contained in:
Francesco Abbate 2021-04-02 18:01:14 +02:00
parent 87613a7619
commit 3986233b5c
3 changed files with 88 additions and 9 deletions

View File

@ -3,6 +3,7 @@ local Highlighter = require "core.doc.highlighter"
local syntax = require "core.syntax"
local config = require "core.config"
local common = require "core.common"
local translate = require "core.doc.translate"
local Doc = Object:extend()
@ -399,4 +400,10 @@ function Doc:select_to(...)
end
function Doc:select_with_delimiters(delims, outer)
local line, col = self:get_selection()
self:set_selection(self:position_offset(line, col, translate.inside_delimiters, delims, outer))
end
return Doc

View File

@ -145,4 +145,45 @@ function translate.end_of_doc(doc, line, col)
end
function translate.inside_delimiters(doc, line, col, delims, outer)
print('translate.inside_delimiters', delims[2], outer)
local line1, col1 = line, col
while true do
local lineb, colb = doc:position_offset(line1, col1, -1)
local char = doc:get_char(lineb, colb)
if char == delims[1]
or line1 == lineb and col1 == colb then
break
end
line1, col1 = lineb, colb
end
if outer then
line1, col1 = doc:position_offset(line1, col1, -1)
end
local line2, col2 = line, col
while true do
local linef, colf = doc:position_offset(line2, col2, 1)
local char = doc:get_char(line2, col2)
if char == delims[2]
or linef == line2 and colf == col2 then
break
end
line2, col2 = linef, colf
end
if outer then
line2, col2 = doc:position_offset(line2, col2, 1)
while doc:get_char(line2, col2) == ' ' do
local nline2, ncol2 = doc:position_offset(line2, col2, 1)
if nline2 == line2 and ncol2 == col2 then break end
line2, col2 = nline2, ncol2
end
end
return line1, col1, line2, col2
end
return translate

View File

@ -3,11 +3,12 @@ local command = require "core.command"
local vim = {}
local command_buffer = {verb = '.', mult_accu = ''}
local command_buffer = {verb = '.', mult_accu = '', inside = ''}
function command_buffer:reset()
self.verb = '.'
self.mult_accu = ''
self.inside = ''
end
function command_buffer:mult()
@ -28,7 +29,7 @@ local verbs_obj = {'c', 'd', 'y'}
local verbs_imm = {'a', 'h', 'i', 'j', 'k', 'l', 'o', 'p', 'u', 'v', 'x', 'O',
'left', 'right', 'up', 'down', 'escape'}
local vim_objects = {'b', 'd', 'e', 'w', 'y', '^', '0', '$'}
local vim_objects = {'a', 'b', 'd', 'e', 'i', 'w', 'y', '^', '0', '$'}
local vim_object_map = {
['b'] = 'start-of-word',
@ -39,6 +40,15 @@ local vim_object_map = {
['0'] = 'start-of-line',
}
local inside_delims = {
[')'] = {'(', ')'},
[']'] = {'[', ']'},
['}'] = {'{', '}'},
['>'] = {'<', '>'},
['"'] = {'"', '"'},
["'"] = {"'", "'"},
}
local function doc_command(action, command)
return 'doc:' .. action .. '-' .. command
end
@ -125,27 +135,48 @@ local function vim_execute(mode, verb, mult, object)
return true
end
function vim.on_text_input(mode, text, stroke)
text = text or stroke
function vim.on_text_input(mode, text_raw, stroke)
local text = text_raw or stroke
if mode == 'command' or mode == 'visual' then
if command_buffer.verb == '.' and table_find(verbs_imm, text) then
if command_buffer.inside ~= '' and inside_delims[text] then
-- got character for inside delimiter edits
local view = core.active_view
local outer = command_buffer.inside == 'a'
view.doc:select_with_delimiters(inside_delims[text], outer)
command.perform('doc:delete')
if command_buffer.verb == 'c' then
view:set_editing_mode('insert')
end
command_buffer:reset()
return true
elseif command_buffer.verb == '.' and table_find(verbs_imm, text) then
-- execute immediate vim command
vim_execute(mode, text, command_buffer:mult())
command_buffer:reset()
return true
elseif command_buffer.verb == '.' and table_find(verbs_obj, text) then
-- vim command that takes an object
if mode == 'command' then
-- store the command without executing
command_buffer.verb = text
else
-- visual mode: execute the command
vim_execute(mode, text, command_buffer:mult())
command_buffer:reset()
end
return true
elseif string.byte(text) >= string.byte('0') and string.byte(text) <= string.byte('9') then
command_buffer:add_mult_char(text)
elseif text_raw and string.byte(text_raw) >= string.byte('0') and string.byte(text_raw) <= string.byte('9') then
-- numeric command multiplier
command_buffer:add_mult_char(text_raw)
return true
elseif table_find(vim_objects, text) then
vim_execute(mode, command_buffer.verb, command_buffer:mult(), text)
command_buffer:reset()
-- object of a verb
if text == 'i' or text == 'a' then
command_buffer.inside = text
else
vim_execute(mode, command_buffer.verb, command_buffer:mult(), text)
command_buffer:reset()
end
return true
elseif stroke == 'escape' then
core.active_view:set_editing_mode('command')