First preliminary implementation of vim-mode

The basic is there and sort-of-work but largely incomplete and not
yet usable.
This commit is contained in:
Francesco Abbate 2021-03-23 11:58:56 +01:00
parent 3810b6ba6c
commit 97a00f946d
5 changed files with 107 additions and 6 deletions

View File

@ -58,6 +58,18 @@ function command.perform(...)
end
function command.perform_many(n, name)
local cmd = command.map[name]
if not cmd or not cmd.predicate() then return false end
pcall(function()
for i = 1, n do
cmd.perform()
end
end)
return true
end
function command.add_defaults()
local reg = { "core", "root", "command", "doc", "findreplace", "files" }
for _, name in ipairs(reg) do

View File

@ -171,4 +171,16 @@ command.add(nil, {
return common.home_encode_list(common.dir_list_suggest(text, dir_list))
end)
end,
["core:set-insert-mode"] = function()
core.mode = 'insert'
end,
["core:set-command-mode"] = function()
core.mode = 'command'
end,
["core:set-standard-mode"] = function()
core.mode = 'standard'
end,
})

View File

@ -394,6 +394,7 @@ function core.init()
core.clip_rect_stack = {{ 0,0,0,0 }}
core.log_items = {}
core.docs = {}
core.mode = 'standard'
core.threads = setmetatable({}, { __mode = "k" })
local project_dir_abs = system.absolute_path(project_dir)
@ -716,12 +717,12 @@ end
function core.on_event(type, ...)
local did_keymap = false
if type == "textinput" then
if type == "textinput" and (core.mode == 'insert' or core.mode == 'standard') then
core.root_view:on_text_input(...)
elseif type == "keypressed" then
did_keymap = keymap.on_key_pressed(...)
did_keymap = keymap.on_key_pressed(core.mode, ...)
elseif type == "keyreleased" then
keymap.on_key_released(...)
keymap.on_key_released(core.mode, ...)
elseif type == "mousemoved" then
core.root_view:on_mouse_moved(...)
elseif type == "mousepressed" then

View File

@ -1,3 +1,4 @@
local core = require "core"
local command = require "core.command"
local keymap = {}
@ -14,6 +15,57 @@ local modkey_map = {
["right alt"] = "altgr",
}
function keymap.reset_vim_command()
keymap.command_verb = '.'
keymap.command_mult = 1
end
local function table_find(t, e)
for i = 1, #t do
if t[i] == e then return i end
end
end
keymap.vim_verbs_obj = {'d', 'c'}
keymap.vim_verbs_imm = {'y', 'p', 'h', 'j', 'k', 'l', 'x', 'i'}
keymap.vim_objects = {'w', '$'}
local vim_object_map = {
['w'] = 'end-of-word',
['$'] = 'end-of-line',
}
function keymap.vim_execute(verb, mult, object)
if verb == '.' then
return command.perform_many(mult, 'doc:move-to-' .. vim_object_map[object])
elseif verb == 'd' then
return command.perform_many(mult, 'doc:delete-to-' .. vim_object_map[object])
elseif verb == 'c' then
command.perform_many(mult, 'doc:select-to-' .. vim_object_map[object])
command.perform('doc:copy')
command.perform('doc:cut')
command.perform('core:set-insert-mode')
elseif verb == 'h' then
command.perform_many(mult, 'doc:move-to-previous-char')
elseif verb == 'j' then
command.perform_many(mult, 'doc:move-to-next-line')
elseif verb == 'k' then
command.perform_many(mult, 'doc:move-to-previous-line')
elseif verb == 'l' then
command.perform_many(mult, 'doc:move-to-next-char')
elseif verb == 'x' then
command.perform_many(mult, 'doc:delete')
elseif verb == 'i' then
command.perform('core:set-insert-mode')
else
return false
end
return true
end
keymap.reset_vim_command()
local modkeys = { "ctrl", "alt", "altgr", "shift" }
local function key_to_stroke(k)
@ -52,7 +104,7 @@ function keymap.get_binding(cmd)
end
function keymap.on_key_pressed(k)
function keymap.on_key_pressed(editor_mode, k)
local mk = modkey_map[k]
if mk then
keymap.modkeys[mk] = true
@ -62,6 +114,29 @@ function keymap.on_key_pressed(k)
end
else
local stroke = key_to_stroke(k)
if editor_mode == 'command' then
if keymap.command_verb == '.' and table_find(keymap.vim_verbs_imm, stroke) then
keymap.vim_execute(stroke, keymap.command_mult)
keymap.reset_vim_command()
return true
elseif keymap.command_verb == '.' and table_find(keymap.vim_verbs_obj, stroke) then
keymap.command_verb = stroke
return true
elseif string.byte(stroke) >= string.byte(1) and string.byte(stroke) <= string.byte(9) then
keymap.command_mult = tonumber(stroke)
return true
elseif table_find(keymap.vim_objects, stroke) then
keymap.vim_execute(keymap.command_verb, keymap.command_mult, stroke)
keymap.reset_vim_command()
return true
end
elseif editor_mode == 'insert' then
if stroke == 'escape' then
core.mode = 'command'
return true
end
return false
end
local commands = keymap.map[stroke]
if commands then
for _, cmd in ipairs(commands) do
@ -75,7 +150,7 @@ function keymap.on_key_pressed(k)
end
function keymap.on_key_released(k)
function keymap.on_key_released(editor_mode, k)
local mk = modkey_map[k]
if mk then
keymap.modkeys[mk] = false

View File

@ -124,7 +124,8 @@ function StatusView:get_items()
self.separator,
string.format("%d%%", line / #dv.doc.lines * 100),
}, {
style.text, indent_label, indent_size,
style.caret, core.mode ~= 'standard' and string.upper(core.mode) or '', style.text, self.separator2,
indent_label, indent_size,
style.dim, self.separator2, style.text,
style.icon_font, "g",
style.font, style.dim, self.separator2, style.text,