4 #include "text-motions.h"
7 static void keyaction_free(KeyAction
*action
) {
10 free((char*)action
->name
);
11 free(VIS_HELP_USE((char*)action
->help
));
15 KeyAction
*vis_action_new(Vis
*vis
, const char *name
, const char *help
, KeyActionFunction
*func
, Arg arg
) {
16 KeyAction
*action
= calloc(1, sizeof *action
);
19 if (name
&& !(action
->name
= strdup(name
)))
22 if (help
&& !(action
->help
= strdup(help
)))
27 if (!array_add_ptr(&vis
->actions_user
, action
))
31 keyaction_free(action
);
35 void vis_action_free(Vis
*vis
, KeyAction
*action
) {
38 size_t len
= array_length(&vis
->actions_user
);
39 for (size_t i
= 0; i
< len
; i
++) {
40 if (action
== array_get_ptr(&vis
->actions_user
, i
)) {
41 keyaction_free(action
);
42 array_remove(&vis
->actions_user
, i
);
48 KeyBinding
*vis_binding_new(Vis
*vis
) {
49 KeyBinding
*binding
= calloc(1, sizeof *binding
);
50 if (binding
&& array_add_ptr(&vis
->bindings
, binding
))
56 void vis_binding_free(Vis
*vis
, KeyBinding
*binding
) {
59 size_t len
= array_length(&vis
->bindings
);
60 for (size_t i
= 0; i
< len
; i
++) {
61 if (binding
== array_get_ptr(&vis
->bindings
, i
)) {
63 free((char*)binding
->alias
);
64 if (binding
->action
&& !binding
->action
->name
)
65 vis_action_free(vis
, (KeyAction
*)binding
->action
);
67 array_remove(&vis
->bindings
, i
);
73 Mode
*mode_get(Vis
*vis
, enum VisMode mode
) {
74 if (mode
< LENGTH(vis_modes
))
75 return &vis_modes
[mode
];
79 void mode_set(Vis
*vis
, Mode
*new_mode
) {
80 if (vis
->mode
== new_mode
)
83 vis
->mode
->leave(vis
, new_mode
);
84 if (vis
->mode
!= &vis_modes
[VIS_MODE_OPERATOR_PENDING
])
85 vis
->mode_prev
= vis
->mode
;
88 new_mode
->enter(vis
, vis
->mode_prev
);
91 void vis_mode_switch(Vis
*vis
, enum VisMode mode
) {
92 if (mode
< LENGTH(vis_modes
))
93 mode_set(vis
, &vis_modes
[mode
]);
96 enum VisMode
vis_mode_from(Vis
*vis
, const char *name
) {
97 for (size_t i
= 0; name
&& i
< LENGTH(vis_modes
); i
++) {
98 Mode
*mode
= &vis_modes
[i
];
99 if (!strcasecmp(mode
->name
, name
))
102 return VIS_MODE_INVALID
;
105 enum VisMode
vis_mode_get(Vis
*vis
) {
106 return vis
->mode
->id
;
109 static bool mode_unmap(Mode
*mode
, const char *key
) {
110 return mode
&& mode
->bindings
&& map_delete(mode
->bindings
, key
);
113 bool vis_mode_unmap(Vis
*vis
, enum VisMode id
, const char *key
) {
114 return id
< LENGTH(vis_modes
) && mode_unmap(&vis_modes
[id
], key
);
117 bool vis_window_mode_unmap(Win
*win
, enum VisMode id
, const char *key
) {
118 return id
< LENGTH(win
->modes
) && mode_unmap(&win
->modes
[id
], key
);
121 static bool mode_map(Vis
*vis
, Mode
*mode
, bool force
, const char *key
, const KeyBinding
*binding
) {
124 if (binding
->alias
&& key
[0] != '<' && strncmp(key
, binding
->alias
, strlen(key
)) == 0)
126 if (!mode
->bindings
&& !(mode
->bindings
= map_new()))
129 map_delete(mode
->bindings
, key
);
130 return map_put(mode
->bindings
, key
, binding
);
133 bool vis_mode_map(Vis
*vis
, enum VisMode id
, bool force
, const char *key
, const KeyBinding
*binding
) {
134 return id
< LENGTH(vis_modes
) && mode_map(vis
, &vis_modes
[id
], force
, key
, binding
);
137 bool vis_window_mode_map(Win
*win
, enum VisMode id
, bool force
, const char *key
, const KeyBinding
*binding
) {
138 return id
< LENGTH(win
->modes
) && mode_map(win
->vis
, &win
->modes
[id
], force
, key
, binding
);
141 /** mode switching event handlers */
143 static void vis_mode_normal_enter(Vis
*vis
, Mode
*old
) {
147 if (old
!= mode_get(vis
, VIS_MODE_INSERT
) && old
!= mode_get(vis
, VIS_MODE_REPLACE
))
149 if (vis
->autoindent
&& strcmp(vis
->key_prev
, "<Enter>") == 0) {
150 Text
*txt
= win
->file
->text
;
151 for (Selection
*s
= view_selections(win
->view
); s
; s
= view_selections_next(s
)) {
152 size_t pos
= view_cursors_pos(s
);
153 size_t start
= text_line_start(txt
, pos
);
154 size_t end
= text_line_end(txt
, pos
);
155 if (start
== pos
&& start
== end
) {
156 size_t begin
= text_line_begin(txt
, pos
);
157 size_t len
= start
- begin
;
159 text_delete(txt
, begin
, len
);
160 view_cursors_to(s
, pos
-len
);
165 macro_operator_stop(vis
);
166 if (!win
->parent
&& vis
->action_prev
.op
== &vis_operators
[VIS_OP_MODESWITCH
] &&
167 vis
->action_prev
.count
> 1) {
168 /* temporarily disable motion, in something like `5atext`
169 * we should only move the cursor once then insert the text */
170 const Movement
*motion
= vis
->action_prev
.movement
;
172 vis
->action_prev
.movement
= &vis_motions
[VIS_MOVE_NOP
];
173 /* we already inserted the text once, so temporarily decrease count */
174 vis
->action_prev
.count
--;
176 vis
->action_prev
.count
++;
177 vis
->action_prev
.movement
= motion
;
179 /* make sure we can recover the current state after an editing operation */
180 vis_file_snapshot(vis
, win
->file
);
183 static void vis_mode_operator_input(Vis
*vis
, const char *str
, size_t len
) {
184 /* invalid operator */
186 mode_set(vis
, vis
->mode_prev
);
189 static void vis_mode_visual_enter(Vis
*vis
, Mode
*old
) {
191 if (!old
->visual
&& win
) {
192 for (Selection
*s
= view_selections(win
->view
); s
; s
= view_selections_next(s
))
193 view_selections_anchor(s
, true);
197 static void vis_mode_visual_line_enter(Vis
*vis
, Mode
*old
) {
199 if (!old
->visual
&& win
) {
200 for (Selection
*s
= view_selections(win
->view
); s
; s
= view_selections_next(s
))
201 view_selections_anchor(s
, true);
204 vis_motion(vis
, VIS_MOVE_NOP
);
207 static void vis_mode_visual_line_leave(Vis
*vis
, Mode
*new) {
213 window_selection_save(win
);
214 view_selections_clear_all(win
->view
);
216 view_cursor_to(win
->view
, view_cursor_get(win
->view
));
220 static void vis_mode_visual_leave(Vis
*vis
, Mode
*new) {
222 if (!new->visual
&& win
) {
224 window_selection_save(win
);
225 view_selections_clear_all(win
->view
);
229 static void vis_mode_insert_replace_enter(Vis
*vis
, Mode
*old
) {
230 if (!vis
->win
|| vis
->win
->parent
)
232 if (!vis
->action
.op
) {
233 action_reset(&vis
->action_prev
);
234 vis
->action_prev
.op
= &vis_operators
[VIS_OP_MODESWITCH
];
235 vis
->action_prev
.mode
= vis
->mode
->id
;
237 macro_operator_record(vis
);
240 static void vis_mode_insert_idle(Vis
*vis
) {
243 vis_file_snapshot(vis
, win
->file
);
246 static void vis_mode_insert_input(Vis
*vis
, const char *str
, size_t len
) {
247 vis_insert_key(vis
, str
, len
);
250 static void vis_mode_replace_input(Vis
*vis
, const char *str
, size_t len
) {
251 vis_replace_key(vis
, str
, len
);
255 [VIS_MODE_OPERATOR_PENDING
] = {
256 .id
= VIS_MODE_OPERATOR_PENDING
,
257 .name
= "OPERATOR-PENDING",
258 .input
= vis_mode_operator_input
,
261 [VIS_MODE_NORMAL
] = {
262 .id
= VIS_MODE_NORMAL
,
265 .enter
= vis_mode_normal_enter
,
267 [VIS_MODE_VISUAL
] = {
268 .id
= VIS_MODE_VISUAL
,
272 .enter
= vis_mode_visual_enter
,
273 .leave
= vis_mode_visual_leave
,
276 [VIS_MODE_VISUAL_LINE
] = {
277 .id
= VIS_MODE_VISUAL_LINE
,
278 .name
= "VISUAL-LINE",
279 .parent
= &vis_modes
[VIS_MODE_VISUAL
],
280 .status
= "VISUAL-LINE",
282 .enter
= vis_mode_visual_line_enter
,
283 .leave
= vis_mode_visual_line_leave
,
286 [VIS_MODE_INSERT
] = {
287 .id
= VIS_MODE_INSERT
,
291 .enter
= vis_mode_insert_replace_enter
,
292 .input
= vis_mode_insert_input
,
293 .idle
= vis_mode_insert_idle
,
296 [VIS_MODE_REPLACE
] = {
297 .id
= VIS_MODE_REPLACE
,
299 .parent
= &vis_modes
[VIS_MODE_INSERT
],
302 .enter
= vis_mode_insert_replace_enter
,
303 .input
= vis_mode_replace_input
,
304 .idle
= vis_mode_insert_idle
,