4 Mode
*mode_get(Vis
*vis
, enum VisMode mode
) {
5 if (mode
< LENGTH(vis_modes
))
6 return &vis_modes
[mode
];
10 void mode_set(Vis
*vis
, Mode
*new_mode
) {
11 if (vis
->mode
== new_mode
)
14 vis
->mode
->leave(vis
, new_mode
);
15 if (vis
->mode
->isuser
)
16 vis
->mode_prev
= vis
->mode
;
19 new_mode
->enter(vis
, vis
->mode_prev
);
20 vis
->win
->ui
->draw_status(vis
->win
->ui
);
23 static bool mode_map(Mode
*mode
, const char *key
, KeyBinding
*binding
) {
24 return map_put(mode
->bindings
, key
, binding
);
27 bool vis_mode_map(Vis
*vis
, enum VisMode modeid
, const char *key
, KeyBinding
*binding
) {
28 Mode
*mode
= mode_get(vis
, modeid
);
29 return mode
&& mode_map(mode
, key
, binding
);
32 bool vis_mode_bindings(Vis
*vis
, enum VisMode modeid
, KeyBinding
**bindings
) {
33 Mode
*mode
= mode_get(vis
, modeid
);
37 for (KeyBinding
*kb
= *bindings
; kb
->key
; kb
++) {
38 if (!mode_map(mode
, kb
->key
, kb
))
44 bool vis_mode_unmap(Vis
*vis
, enum VisMode modeid
, const char *key
) {
45 Mode
*mode
= mode_get(vis
, modeid
);
46 return mode
&& map_delete(mode
->bindings
, key
);
49 /** mode switching event handlers */
51 static void vis_mode_operator_enter(Vis
*vis
, Mode
*old
) {
52 vis_modes
[VIS_MODE_OPERATOR
].parent
= &vis_modes
[VIS_MODE_OPERATOR_OPTION
];
55 static void vis_mode_operator_leave(Vis
*vis
, Mode
*new) {
56 vis_modes
[VIS_MODE_OPERATOR
].parent
= &vis_modes
[VIS_MODE_MOVE
];
59 static void vis_mode_operator_input(Vis
*vis
, const char *str
, size_t len
) {
60 /* invalid operator */
62 mode_set(vis
, vis
->mode_prev
);
65 static void vis_mode_visual_enter(Vis
*vis
, Mode
*old
) {
67 for (Cursor
*c
= view_cursors(vis
->win
->view
); c
; c
= view_cursors_next(c
))
68 view_cursors_selection_start(c
);
69 vis_modes
[VIS_MODE_OPERATOR
].parent
= &vis_modes
[VIS_MODE_TEXTOBJ
];
73 static void vis_mode_visual_line_enter(Vis
*vis
, Mode
*old
) {
75 for (Cursor
*c
= view_cursors(vis
->win
->view
); c
; c
= view_cursors_next(c
))
76 view_cursors_selection_start(c
);
77 vis_modes
[VIS_MODE_OPERATOR
].parent
= &vis_modes
[VIS_MODE_TEXTOBJ
];
79 vis_motion(vis
, VIS_MOVE_LINE_END
);
82 static void vis_mode_visual_line_leave(Vis
*vis
, Mode
*new) {
84 view_selections_clear(vis
->win
->view
);
85 vis_modes
[VIS_MODE_OPERATOR
].parent
= &vis_modes
[VIS_MODE_MOVE
];
87 view_cursor_to(vis
->win
->view
, view_cursor_get(vis
->win
->view
));
91 static void vis_mode_visual_leave(Vis
*vis
, Mode
*new) {
93 view_selections_clear(vis
->win
->view
);
94 vis_modes
[VIS_MODE_OPERATOR
].parent
= &vis_modes
[VIS_MODE_MOVE
];
98 static void vis_mode_prompt_input(Vis
*vis
, const char *str
, size_t len
) {
99 vis_insert_key(vis
, str
, len
);
102 static void vis_mode_prompt_enter(Vis
*vis
, Mode
*old
) {
103 if (old
->isuser
&& old
!= &vis_modes
[VIS_MODE_PROMPT
])
104 vis
->mode_before_prompt
= old
;
107 static void vis_mode_prompt_leave(Vis
*vis
, Mode
*new) {
109 vis_prompt_hide(vis
);
112 static void vis_mode_insert_enter(Vis
*vis
, Mode
*old
) {
113 if (!vis
->macro_operator
) {
114 macro_operator_record(vis
);
115 action_reset(&vis
->action_prev
);
116 vis
->action_prev
.macro
= vis
->macro_operator
;
117 vis
->action_prev
.op
= &ops
[VIS_OP_INSERT
];
121 static void vis_mode_insert_leave(Vis
*vis
, Mode
*new) {
122 /* make sure we can recover the current state after an editing operation */
123 text_snapshot(vis
->win
->file
->text
);
124 if (new == mode_get(vis
, VIS_MODE_NORMAL
))
125 macro_operator_stop(vis
);
128 static void vis_mode_insert_idle(Vis
*vis
) {
129 text_snapshot(vis
->win
->file
->text
);
132 static void vis_mode_insert_input(Vis
*vis
, const char *str
, size_t len
) {
133 vis_insert_key(vis
, str
, len
);
136 static void vis_mode_replace_enter(Vis
*vis
, Mode
*old
) {
137 if (!vis
->macro_operator
) {
138 macro_operator_record(vis
);
139 action_reset(&vis
->action_prev
);
140 vis
->action_prev
.macro
= vis
->macro_operator
;
141 vis
->action_prev
.op
= &ops
[VIS_OP_REPLACE
];
145 static void vis_mode_replace_leave(Vis
*vis
, Mode
*new) {
146 /* make sure we can recover the current state after an editing operation */
147 text_snapshot(vis
->win
->file
->text
);
148 if (new == mode_get(vis
, VIS_MODE_NORMAL
))
149 macro_operator_stop(vis
);
152 static void vis_mode_replace_input(Vis
*vis
, const char *str
, size_t len
) {
153 vis_replace_key(vis
, str
, len
);
159 * the tree of modes currently looks like this. the double line between OPERATOR-OPTION
160 * and OPERATOR is only in effect once an operator is detected. that is when entering the
161 * OPERATOR mode its parent is set to OPERATOR-OPTION which makes {INNER-,}TEXTOBJ
162 * reachable. once the operator is processed (i.e. the OPERATOR mode is left) its parent
163 * mode is reset back to MOVE.
165 * Similarly the +-ed line between OPERATOR and TEXTOBJ is only active within the visual
172 * /-------------------/ |
175 * / \ | \-----------------\
177 * INSERT PROMPT OPERATOR ++++ INNER-TEXTOBJ
178 * | (history etc) (d,c,y,p ..) + (i [wsp[]()b<>{}B"'`] )
181 * REPLACE NORMAL \\ + TEXTOBJ
182 * | \\ + (a [wsp[]()b<>{}B"'`] )
185 * VISUAL \\ OPERATOR-OPTION
199 .parent
= &vis_modes
[VIS_MODE_BASIC
],
201 [VIS_MODE_TEXTOBJ
] = {
202 .name
= "TEXT-OBJECTS",
203 .parent
= &vis_modes
[VIS_MODE_MOVE
],
205 [VIS_MODE_OPERATOR_OPTION
] = {
206 .name
= "OPERATOR-OPTION",
207 .parent
= &vis_modes
[VIS_MODE_TEXTOBJ
],
209 [VIS_MODE_OPERATOR
] = {
211 .parent
= &vis_modes
[VIS_MODE_MOVE
],
212 .enter
= vis_mode_operator_enter
,
213 .leave
= vis_mode_operator_leave
,
214 .input
= vis_mode_operator_input
,
216 [VIS_MODE_NORMAL
] = {
221 .parent
= &vis_modes
[VIS_MODE_OPERATOR
],
223 [VIS_MODE_VISUAL
] = {
225 .status
= "--VISUAL--",
228 .parent
= &vis_modes
[VIS_MODE_OPERATOR
],
229 .enter
= vis_mode_visual_enter
,
230 .leave
= vis_mode_visual_leave
,
233 [VIS_MODE_VISUAL_LINE
] = {
234 .name
= "VISUAL LINE",
235 .status
= "--VISUAL LINE--",
238 .parent
= &vis_modes
[VIS_MODE_VISUAL
],
239 .enter
= vis_mode_visual_line_enter
,
240 .leave
= vis_mode_visual_line_leave
,
243 [VIS_MODE_READLINE
] = {
245 .parent
= &vis_modes
[VIS_MODE_BASIC
],
247 [VIS_MODE_PROMPT
] = {
251 .parent
= &vis_modes
[VIS_MODE_READLINE
],
252 .input
= vis_mode_prompt_input
,
253 .enter
= vis_mode_prompt_enter
,
254 .leave
= vis_mode_prompt_leave
,
256 [VIS_MODE_INSERT
] = {
258 .status
= "--INSERT--",
261 .parent
= &vis_modes
[VIS_MODE_READLINE
],
262 .enter
= vis_mode_insert_enter
,
263 .leave
= vis_mode_insert_leave
,
264 .input
= vis_mode_insert_input
,
265 .idle
= vis_mode_insert_idle
,
268 [VIS_MODE_REPLACE
] = {
270 .status
= "--REPLACE--",
273 .parent
= &vis_modes
[VIS_MODE_INSERT
],
274 .enter
= vis_mode_replace_enter
,
275 .leave
= vis_mode_replace_leave
,
276 .input
= vis_mode_replace_input
,
277 .idle
= vis_mode_insert_idle
,