lexer: add systemd unit file LPeg lexer
[vis.git] / vis-modes.c
blob62a9541741c37d93477492ae938dda10c1828558
1 #include <string.h>
2 #include "vis-core.h"
3 #include "util.h"
5 static Mode *mode_get(Vis *vis, enum VisMode mode) {
6 if (mode < LENGTH(vis_modes))
7 return &vis_modes[mode];
8 return NULL;
11 void mode_set(Vis *vis, Mode *new_mode) {
12 if (vis->mode == new_mode)
13 return;
14 if (vis->mode->leave)
15 vis->mode->leave(vis, new_mode);
16 if (vis->mode != &vis_modes[VIS_MODE_OPERATOR_PENDING])
17 vis->mode_prev = vis->mode;
18 vis->mode = new_mode;
19 if (new_mode->enter)
20 new_mode->enter(vis, vis->mode_prev);
21 vis->win->ui->draw_status(vis->win->ui);
24 void vis_mode_switch(Vis *vis, enum VisMode mode) {
25 mode_set(vis, &vis_modes[mode]);
28 static bool mode_map(Mode *mode, const char *key, const KeyBinding *binding) {
29 if (!mode)
30 return false;
31 if (binding->alias && key[0] != '<' && strncmp(key, binding->alias, strlen(key)) == 0)
32 return false;
33 if (!mode->bindings) {
34 mode->bindings = map_new();
35 if (!mode->bindings)
36 return false;
38 return (strcmp(key, "<") == 0 || !map_contains(mode->bindings, key)) && map_put(mode->bindings, key, binding);
41 bool vis_mode_map(Vis *vis, enum VisMode id, const char *key, const KeyBinding *binding) {
42 return id < LENGTH(vis_modes) && mode_map(&vis_modes[id], key, binding);
45 bool vis_window_mode_map(Win *win, enum VisMode id, const char *key, const KeyBinding *binding) {
46 return id < LENGTH(win->modes) && mode_map(&win->modes[id], key, binding);
49 static bool mode_unmap(Mode *mode, const char *key) {
50 return mode && mode->bindings && map_delete(mode->bindings, key);
53 bool vis_mode_unmap(Vis *vis, enum VisMode id, const char *key) {
54 return id < LENGTH(vis_modes) && mode_unmap(&vis_modes[id], key);
57 bool vis_window_mode_unmap(Win *win, enum VisMode id, const char *key) {
58 return id < LENGTH(win->modes) && mode_unmap(&win->modes[id], key);
61 /** mode switching event handlers */
63 static void vis_mode_operator_input(Vis *vis, const char *str, size_t len) {
64 /* invalid operator */
65 vis_cancel(vis);
66 mode_set(vis, vis->mode_prev);
69 static void vis_mode_visual_enter(Vis *vis, Mode *old) {
70 if (!old->visual) {
71 for (Cursor *c = view_cursors(vis->win->view); c; c = view_cursors_next(c))
72 view_cursors_selection_start(c);
76 static void vis_mode_visual_line_enter(Vis *vis, Mode *old) {
77 if (!old->visual) {
78 for (Cursor *c = view_cursors(vis->win->view); c; c = view_cursors_next(c))
79 view_cursors_selection_start(c);
81 if (!vis->action.op)
82 vis_motion(vis, VIS_MOVE_NOP);
85 static void vis_mode_visual_line_leave(Vis *vis, Mode *new) {
86 if (!new->visual) {
87 window_selection_save(vis->win);
88 view_selections_clear(vis->win->view);
89 } else {
90 view_cursor_to(vis->win->view, view_cursor_get(vis->win->view));
94 static void vis_mode_visual_leave(Vis *vis, Mode *new) {
95 if (!new->visual) {
96 window_selection_save(vis->win);
97 view_selections_clear(vis->win->view);
101 static void vis_mode_insert_enter(Vis *vis, Mode *old) {
102 if (!vis->macro_operator) {
103 macro_operator_record(vis);
104 action_reset(&vis->action_prev);
105 vis->action_prev.macro = vis->macro_operator;
106 vis->action_prev.op = &vis_operators[VIS_OP_INSERT];
110 static void vis_mode_insert_leave(Vis *vis, Mode *new) {
111 /* make sure we can recover the current state after an editing operation */
112 text_snapshot(vis->win->file->text);
113 if (new == mode_get(vis, VIS_MODE_NORMAL))
114 macro_operator_stop(vis);
117 static void vis_mode_insert_idle(Vis *vis) {
118 text_snapshot(vis->win->file->text);
121 static void vis_mode_insert_input(Vis *vis, const char *str, size_t len) {
122 vis_insert_key(vis, str, len);
125 static void vis_mode_replace_enter(Vis *vis, Mode *old) {
126 if (!vis->macro_operator) {
127 macro_operator_record(vis);
128 action_reset(&vis->action_prev);
129 vis->action_prev.macro = vis->macro_operator;
130 vis->action_prev.op = &vis_operators[VIS_OP_REPLACE];
134 static void vis_mode_replace_leave(Vis *vis, Mode *new) {
135 /* make sure we can recover the current state after an editing operation */
136 text_snapshot(vis->win->file->text);
137 if (new == mode_get(vis, VIS_MODE_NORMAL))
138 macro_operator_stop(vis);
141 static void vis_mode_replace_input(Vis *vis, const char *str, size_t len) {
142 vis_replace_key(vis, str, len);
145 Mode vis_modes[] = {
146 [VIS_MODE_OPERATOR_PENDING] = {
147 .id = VIS_MODE_OPERATOR_PENDING,
148 .name = "OPERATOR-PENDING",
149 .input = vis_mode_operator_input,
150 .help = "",
152 [VIS_MODE_NORMAL] = {
153 .id = VIS_MODE_NORMAL,
154 .name = "NORMAL",
155 .status = "",
156 .help = "",
158 [VIS_MODE_VISUAL] = {
159 .id = VIS_MODE_VISUAL,
160 .name = "VISUAL",
161 .status = "--VISUAL--",
162 .help = "",
163 .enter = vis_mode_visual_enter,
164 .leave = vis_mode_visual_leave,
165 .visual = true,
167 [VIS_MODE_VISUAL_LINE] = {
168 .id = VIS_MODE_VISUAL_LINE,
169 .name = "VISUAL LINE",
170 .parent = &vis_modes[VIS_MODE_VISUAL],
171 .status = "--VISUAL LINE--",
172 .help = "",
173 .enter = vis_mode_visual_line_enter,
174 .leave = vis_mode_visual_line_leave,
175 .visual = true,
177 [VIS_MODE_INSERT] = {
178 .id = VIS_MODE_INSERT,
179 .name = "INSERT",
180 .status = "--INSERT--",
181 .help = "",
182 .enter = vis_mode_insert_enter,
183 .leave = vis_mode_insert_leave,
184 .input = vis_mode_insert_input,
185 .idle = vis_mode_insert_idle,
186 .idle_timeout = 3,
188 [VIS_MODE_REPLACE] = {
189 .id = VIS_MODE_REPLACE,
190 .name = "REPLACE",
191 .parent = &vis_modes[VIS_MODE_INSERT],
192 .status = "--REPLACE--",
193 .help = "",
194 .enter = vis_mode_replace_enter,
195 .leave = vis_mode_replace_leave,
196 .input = vis_mode_replace_input,
197 .idle = vis_mode_insert_idle,
198 .idle_timeout = 3,