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
;
105 /* prompt manipulations e.g. <Backspace> should not affect default register */
106 Register tmp
= vis
->registers
[VIS_REG_PROMPT
];
107 vis
->registers
[VIS_REG_PROMPT
] = vis
->registers
[VIS_REG_DEFAULT
];
108 vis
->registers
[VIS_REG_DEFAULT
] = tmp
;
112 static void vis_mode_prompt_leave(Vis
*vis
, Mode
*new) {
114 vis_prompt_hide(vis
);
115 Register tmp
= vis
->registers
[VIS_REG_DEFAULT
];
116 vis
->registers
[VIS_REG_DEFAULT
] = vis
->registers
[VIS_REG_PROMPT
];
117 vis
->registers
[VIS_REG_PROMPT
] = tmp
;
121 static void vis_mode_insert_enter(Vis
*vis
, Mode
*old
) {
122 if (!vis
->macro_operator
) {
123 macro_operator_record(vis
);
124 action_reset(&vis
->action_prev
);
125 vis
->action_prev
.macro
= vis
->macro_operator
;
126 vis
->action_prev
.op
= &ops
[VIS_OP_INSERT
];
130 static void vis_mode_insert_leave(Vis
*vis
, Mode
*new) {
131 /* make sure we can recover the current state after an editing operation */
132 text_snapshot(vis
->win
->file
->text
);
133 if (new == mode_get(vis
, VIS_MODE_NORMAL
))
134 macro_operator_stop(vis
);
137 static void vis_mode_insert_idle(Vis
*vis
) {
138 text_snapshot(vis
->win
->file
->text
);
141 static void vis_mode_insert_input(Vis
*vis
, const char *str
, size_t len
) {
142 vis_insert_key(vis
, str
, len
);
145 static void vis_mode_replace_enter(Vis
*vis
, Mode
*old
) {
146 if (!vis
->macro_operator
) {
147 macro_operator_record(vis
);
148 action_reset(&vis
->action_prev
);
149 vis
->action_prev
.macro
= vis
->macro_operator
;
150 vis
->action_prev
.op
= &ops
[VIS_OP_REPLACE
];
154 static void vis_mode_replace_leave(Vis
*vis
, Mode
*new) {
155 /* make sure we can recover the current state after an editing operation */
156 text_snapshot(vis
->win
->file
->text
);
157 if (new == mode_get(vis
, VIS_MODE_NORMAL
))
158 macro_operator_stop(vis
);
161 static void vis_mode_replace_input(Vis
*vis
, const char *str
, size_t len
) {
162 vis_replace_key(vis
, str
, len
);
168 * the tree of modes currently looks like this. the double line between OPERATOR-OPTION
169 * and OPERATOR is only in effect once an operator is detected. that is when entering the
170 * OPERATOR mode its parent is set to OPERATOR-OPTION which makes {INNER-,}TEXTOBJ
171 * reachable. once the operator is processed (i.e. the OPERATOR mode is left) its parent
172 * mode is reset back to MOVE.
174 * Similarly the +-ed line between OPERATOR and TEXTOBJ is only active within the visual
181 * /-------------------/ |
184 * / \ | \-----------------\
186 * INSERT PROMPT OPERATOR ++++ INNER-TEXTOBJ
187 * | (history etc) (d,c,y,p ..) + (i [wsp[]()b<>{}B"'`] )
190 * REPLACE NORMAL \\ + TEXTOBJ
191 * | \\ + (a [wsp[]()b<>{}B"'`] )
194 * VISUAL \\ OPERATOR-OPTION
208 .parent
= &vis_modes
[VIS_MODE_BASIC
],
210 [VIS_MODE_TEXTOBJ
] = {
211 .name
= "TEXT-OBJECTS",
212 .parent
= &vis_modes
[VIS_MODE_MOVE
],
214 [VIS_MODE_OPERATOR_OPTION
] = {
215 .name
= "OPERATOR-OPTION",
216 .parent
= &vis_modes
[VIS_MODE_TEXTOBJ
],
218 [VIS_MODE_OPERATOR
] = {
220 .parent
= &vis_modes
[VIS_MODE_MOVE
],
221 .enter
= vis_mode_operator_enter
,
222 .leave
= vis_mode_operator_leave
,
223 .input
= vis_mode_operator_input
,
225 [VIS_MODE_NORMAL
] = {
230 .parent
= &vis_modes
[VIS_MODE_OPERATOR
],
232 [VIS_MODE_VISUAL
] = {
234 .status
= "--VISUAL--",
237 .parent
= &vis_modes
[VIS_MODE_OPERATOR
],
238 .enter
= vis_mode_visual_enter
,
239 .leave
= vis_mode_visual_leave
,
242 [VIS_MODE_VISUAL_LINE
] = {
243 .name
= "VISUAL LINE",
244 .status
= "--VISUAL LINE--",
247 .parent
= &vis_modes
[VIS_MODE_VISUAL
],
248 .enter
= vis_mode_visual_line_enter
,
249 .leave
= vis_mode_visual_line_leave
,
252 [VIS_MODE_READLINE
] = {
254 .parent
= &vis_modes
[VIS_MODE_BASIC
],
256 [VIS_MODE_PROMPT
] = {
260 .parent
= &vis_modes
[VIS_MODE_READLINE
],
261 .input
= vis_mode_prompt_input
,
262 .enter
= vis_mode_prompt_enter
,
263 .leave
= vis_mode_prompt_leave
,
265 [VIS_MODE_INSERT
] = {
267 .status
= "--INSERT--",
270 .parent
= &vis_modes
[VIS_MODE_READLINE
],
271 .enter
= vis_mode_insert_enter
,
272 .leave
= vis_mode_insert_leave
,
273 .input
= vis_mode_insert_input
,
274 .idle
= vis_mode_insert_idle
,
277 [VIS_MODE_REPLACE
] = {
279 .status
= "--REPLACE--",
282 .parent
= &vis_modes
[VIS_MODE_INSERT
],
283 .enter
= vis_mode_replace_enter
,
284 .leave
= vis_mode_replace_leave
,
285 .input
= vis_mode_replace_input
,
286 .idle
= vis_mode_insert_idle
,