lexer: add systemd unit file LPeg lexer
[vis.git] / vis-prompt.c
blob01dc91666532f0110eaa06c99cbc494a19708ae7
1 #include <string.h>
2 #include "vis-core.h"
3 #include "text-objects.h"
4 #include "text-util.h"
6 bool vis_prompt_cmd(Vis *vis, const char *cmd) {
7 if (!cmd || !cmd[0] || !cmd[1])
8 return true;
9 switch (cmd[0]) {
10 case '/':
11 return vis_motion(vis, VIS_MOVE_SEARCH_FORWARD, cmd+1);
12 case '?':
13 return vis_motion(vis, VIS_MOVE_SEARCH_BACKWARD, cmd+1);
14 case '+':
15 case ':':
16 register_put0(vis, &vis->registers[VIS_REG_COMMAND], cmd+1);
17 return vis_cmd(vis, cmd+1);
18 default:
19 return false;
23 static void prompt_hide(Win *win) {
24 Text *txt = win->file->text;
25 size_t size = text_size(txt);
26 /* make sure that file is new line terminated */
27 char lastchar;
28 if (size > 1 && text_byte_get(txt, size-1, &lastchar) && lastchar != '\n')
29 text_insert(txt, size, "\n", 1);
30 /* remove empty entries */
31 Filerange line = text_object_line(txt, size);
32 size_t line_size = text_range_size(&line);
33 if (line_size <= 2)
34 text_delete(txt, line.start, line_size);
35 vis_window_close(win);
38 static void prompt_restore(Win *win) {
39 Vis *vis = win->vis;
40 /* restore window and mode which was active before the prompt window
41 * we deliberately don't use vis_mode_switch because we do not want
42 * to invoke the modes enter/leave functions */
43 if (win->parent)
44 vis->win = win->parent;
45 vis->mode = win->parent_mode;
48 static const char *prompt_enter(Vis *vis, const char *keys, const Arg *arg) {
49 Win *prompt = vis->win;
50 View *view = prompt->view;
51 Text *txt = prompt->file->text;
52 Win *win = prompt->parent;
53 char *cmd = NULL;
55 Filerange range = view_selection_get(view);
56 if (!text_range_valid(&range))
57 range = text_object_line(txt, view_cursor_get(view));
58 if (text_range_valid(&range))
59 cmd = text_bytes_alloc0(txt, range.start, text_range_size(&range));
61 if (!win || !cmd) {
62 vis_info_show(vis, "Prompt window invalid\n");
63 prompt_restore(prompt);
64 prompt_hide(prompt);
65 free(cmd);
66 return keys;
69 size_t len = strlen(cmd);
70 if (len > 0 && cmd[len-1] == '\n')
71 cmd[len-1] = '\0';
73 bool lastline = (range.end == text_size(txt));
75 prompt_restore(prompt);
76 if (vis_prompt_cmd(vis, cmd)) {
77 prompt_hide(prompt);
78 if (!lastline) {
79 text_delete(txt, range.start, text_range_size(&range));
80 text_appendf(txt, "%s\n", cmd);
82 } else {
83 vis->win = prompt;
84 vis->mode = &vis_modes[VIS_MODE_INSERT];
86 free(cmd);
87 vis_draw(vis);
88 return keys;
91 static const char *prompt_esc(Vis *vis, const char *keys, const Arg *arg) {
92 Win *prompt = vis->win;
93 if (view_cursors_multiple(prompt->view)) {
94 view_cursors_clear(prompt->view);
95 } else {
96 prompt_restore(prompt);
97 prompt_hide(prompt);
99 return keys;
102 static const char *prompt_up(Vis *vis, const char *keys, const Arg *arg) {
103 vis_motion(vis, VIS_MOVE_LINE_UP);
104 vis_window_mode_unmap(vis->win, VIS_MODE_INSERT, "<Up>");
105 view_options_set(vis->win->view, UI_OPTION_NONE);
106 return keys;
109 static const char *prompt_backspace(Vis *vis, const char *keys, const Arg *arg) {
110 Win *prompt = vis->win;
111 Text *txt = prompt->file->text;
112 size_t size = text_size(txt);
113 size_t pos = view_cursor_get(prompt->view);
114 char c;
115 if (pos == size && (pos == 1 || (size >= 2 && text_byte_get(txt, size-2, &c) && c == '\n'))) {
116 prompt_restore(prompt);
117 prompt_hide(prompt);
118 } else {
119 vis_operator(vis, VIS_OP_DELETE);
120 vis_motion(vis, VIS_MOVE_CHAR_PREV);
122 return keys;
125 static const KeyBinding prompt_enter_binding = {
126 .key = "<Enter>",
127 .action = &(KeyAction){
128 .func = prompt_enter,
132 static const KeyBinding prompt_esc_binding = {
133 .key = "<Escape>",
134 .action = &(KeyAction){
135 .func = prompt_esc,
139 static const KeyBinding prompt_up_binding = {
140 .key = "<Up>",
141 .action = &(KeyAction){
142 .func = prompt_up,
146 static const KeyBinding prompt_backspace_binding = {
147 .key = "<Enter>",
148 .action = &(KeyAction){
149 .func = prompt_backspace,
153 void vis_prompt_show(Vis *vis, const char *title) {
154 Win *active = vis->win;
155 Win *prompt = window_new_file(vis, title[0] == ':' ? vis->command_file : vis->search_file);
156 if (!prompt)
157 return;
158 if (vis->mode->visual)
159 window_selection_save(active);
160 view_options_set(prompt->view, UI_OPTION_ONELINE);
161 Text *txt = prompt->file->text;
162 text_insert(txt, text_size(txt), title, strlen(title));
163 Cursor *cursor = view_cursors_primary_get(prompt->view);
164 view_cursors_scroll_to(cursor, text_size(txt));
165 view_draw(prompt->view);
166 prompt->parent = active;
167 prompt->parent_mode = vis->mode;
168 vis_window_mode_map(prompt, VIS_MODE_NORMAL, "<Enter>", &prompt_enter_binding);
169 vis_window_mode_map(prompt, VIS_MODE_INSERT, "<Enter>", &prompt_enter_binding);
170 vis_window_mode_map(prompt, VIS_MODE_VISUAL, "<Enter>", &prompt_enter_binding);
171 vis_window_mode_map(prompt, VIS_MODE_NORMAL, "<Escape>", &prompt_esc_binding);
172 vis_window_mode_map(prompt, VIS_MODE_INSERT, "<Up>", &prompt_up_binding);
173 vis_window_mode_map(prompt, VIS_MODE_INSERT, "<Backspace>", &prompt_backspace_binding);
174 vis_mode_switch(vis, VIS_MODE_INSERT);
175 vis_draw(vis);
178 void vis_info_show(Vis *vis, const char *msg, ...) {
179 va_list ap;
180 va_start(ap, msg);
181 vis->ui->info(vis->ui, msg, ap);
182 va_end(ap);
185 void vis_info_hide(Vis *vis) {
186 vis->ui->info_hide(vis->ui);
189 void vis_message_show(Vis *vis, const char *msg) {
190 if (!msg)
191 return;
192 if (!vis->message_window)
193 vis->message_window = window_new_file(vis, vis->error_file);
194 Win *win = vis->message_window;
195 if (!win)
196 return;
197 Text *txt = win->file->text;
198 size_t pos = text_size(txt);
199 text_appendf(txt, "%s\n", msg);
200 text_save(txt, NULL);
201 view_cursor_to(win->view, pos);
202 vis_window_focus(win);
205 void vis_message_hide(Vis *vis) {
206 if (!vis->message_window)
207 return;
208 vis_window_close(vis->message_window);
209 vis->message_window = NULL;