-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathvi_visual.lua
146 lines (127 loc) · 3.5 KB
/
vi_visual.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
-- Support for visual mode.
local M = {}
local vi_motion = require('textadept-vi.vi_motion')
local vi_ops = require('textadept-vi.vi_ops')
local state -- This will be vi_mode.state later (but import time is too early)
local function visual_update(pos)
local s = state.visual.s
local e = pos or state.visual.pos
state.visual.pos = e
-- Adjust one end to make it inclusive
if s < e then
e = e+1
end
buffer.set_selection(s, e)
end
M.VISUAL = 'visual'
local function exit_visual()
enter_mode(mode_command)
end
local function visual_range()
local s, e = state.visual.s, state.visual.pos
if s>e then
s, e = e, s
end
return s, e+1
end
-- Take an operator function (which takes startpos, endpos, movtype)
-- and return a key sym for visual mode.
local function wrap_op(opfunc)
return function()
local s, e = visual_range()
local movement = {
s=s,
e=e,
movtype=state.visual.movtype,
}
opfunc(movement)
exit_visual()
end
end
local function wrap_op_linewise(opfunc)
return function()
local s, e = visual_range()
local movement = {
s=s,
e=e,
movtype='linewise',
raws=s,
rawe=e,
}
opfunc(movement)
exit_visual()
end
end
local handle_v_r = setmetatable({}, {
__index = function(t, sym)
if string.match(sym, "^.$") then
return wrap_op(function(s, e, t) vi_ops.replace_char(sym, s, e, t) end)
end
end,
})
local mode_visual = {
name = M.VISUAL,
bindings = {
esc = function()
exit_visual()
end,
v = function()
exit_visual()
end,
x = wrap_op(vi_ops.cut),
d = wrap_op(vi_ops.cut),
['~'] = wrap_op(vi_ops.revcase),
u = wrap_op(vi_ops.lowercase),
U = wrap_op(vi_ops.uppercase),
y = wrap_op(vi_ops.yank),
r = handle_v_r,
g = {
q = wrap_op(vi_ops.wrap),
},
--[[ Vim operators not yet implemented here:
c, <, >, !, =
other commands:
:, s, C, S, R, D, X, Y, p, J, ^], I, A
]]
},
init = function()
state = vi_mode.state
local pos = buffer.current_pos
state.visual.pos = pos -- current location
state.visual.s = pos -- other end.
state.visual.movtype = MOV_INC -- Possible linewise support later
visual_update()
end,
}
local function motion2visualkey(m)
return function()
local f = vi_mode.motion2key(m)
buffer.goto_pos(state.visual.pos)
f()
visual_update(buffer.current_pos)
end
end
setmetatable(mode_visual.bindings, {
__index = function(t,k)
local m = vi_motion.motions[k]
if type(m) == 'table' and m[1] then
return motion2visualkey(m)
elseif type(m) == 'table' then
return vi_motion.wrap_table(m, motion2visualkey)
end
end
})
local function set_default_visual_key(k)
if mode_visual.bindings[k] == nil then
mode_visual.bindings[k] = function()
vi_mode.err("Unbound visual key: <" .. tostring(k) .. ">")
end
end
end
for i = 0,25 do
k = string.char(i + string.byte("a"))
set_default_visual_key(k)
set_default_visual_key(string.upper(k))
end
M.mode_visual = mode_visual
return M