3 #include "text-motions.h"
4 #include "text-objects.h"
7 bool vis_prompt_cmd(Vis
*vis
, const char *cmd
) {
8 if (!cmd
|| !cmd
[0] || !cmd
[1])
12 return vis_motion(vis
, VIS_MOVE_SEARCH_FORWARD
, cmd
+1);
14 return vis_motion(vis
, VIS_MOVE_SEARCH_BACKWARD
, cmd
+1);
17 register_put0(vis
, &vis
->registers
[VIS_REG_COMMAND
], cmd
+1);
18 return vis_cmd(vis
, cmd
+1);
24 static void prompt_hide(Win
*win
) {
25 Text
*txt
= win
->file
->text
;
26 size_t size
= text_size(txt
);
27 /* make sure that file is new line terminated */
29 if (size
>= 1 && text_byte_get(txt
, size
-1, &lastchar
) && lastchar
!= '\n')
30 text_insert(txt
, size
, "\n", 1);
31 /* remove empty entries */
32 Filerange line_range
= text_object_line(txt
, text_size(txt
)-1);
33 char *line
= text_bytes_alloc0(txt
, line_range
.start
, text_range_size(&line_range
));
34 if (line
&& (line
[0] == '\n' || (strchr(":/?", line
[0]) && (line
[1] == '\n' || line
[1] == '\0'))))
35 text_delete_range(txt
, &line_range
);
37 vis_window_close(win
);
40 static void prompt_restore(Win
*win
) {
42 /* restore window and mode which was active before the prompt window
43 * we deliberately don't use vis_mode_switch because we do not want
44 * to invoke the modes enter/leave functions */
46 vis
->win
= win
->parent
;
47 vis
->mode
= win
->parent_mode
;
50 static const char *prompt_enter(Vis
*vis
, const char *keys
, const Arg
*arg
) {
51 Win
*prompt
= vis
->win
;
52 View
*view
= prompt
->view
;
53 Text
*txt
= prompt
->file
->text
;
54 Win
*win
= prompt
->parent
;
57 Filerange range
= view_selection_get(view
);
58 if (!vis
->mode
->visual
) {
59 const char *pattern
= NULL
;
60 Regex
*regex
= text_regex_new();
61 size_t pos
= view_cursor_get(view
);
62 if (prompt
->file
== vis
->command_file
)
64 else if (prompt
->file
== vis
->search_file
)
66 if (pattern
&& regex
&& text_regex_compile(regex
, pattern
, REG_EXTENDED
|REG_NEWLINE
) == 0) {
69 if (text_byte_get(txt
, pos
, &c
) && (c
== ':' || c
== '/' || c
== '?'))
72 prev
= text_search_backward(txt
, pos
, regex
);
75 size_t next
= text_search_forward(txt
, pos
, regex
);
77 next
= text_size(txt
);
78 range
= text_range_new(prev
, next
);
80 text_regex_free(regex
);
82 if (text_range_valid(&range
))
83 cmd
= text_bytes_alloc0(txt
, range
.start
, text_range_size(&range
));
87 vis_info_show(vis
, "Prompt window invalid");
89 vis_info_show(vis
, "Failed to detect command");
90 prompt_restore(prompt
);
96 size_t len
= strlen(cmd
);
97 if (len
> 0 && cmd
[len
-1] == '\n')
100 bool lastline
= (range
.end
== text_size(txt
));
102 prompt_restore(prompt
);
103 if (vis_prompt_cmd(vis
, cmd
)) {
106 text_delete(txt
, range
.start
, text_range_size(&range
));
107 text_appendf(txt
, "%s\n", cmd
);
111 vis
->mode
= &vis_modes
[VIS_MODE_INSERT
];
118 static const char *prompt_esc(Vis
*vis
, const char *keys
, const Arg
*arg
) {
119 Win
*prompt
= vis
->win
;
120 if (view_selections_count(prompt
->view
) > 1) {
121 view_selections_dispose_all(prompt
->view
);
123 prompt_restore(prompt
);
129 static const char *prompt_up(Vis
*vis
, const char *keys
, const Arg
*arg
) {
130 vis_motion(vis
, VIS_MOVE_LINE_UP
);
131 vis_window_mode_unmap(vis
->win
, VIS_MODE_INSERT
, "<Up>");
132 view_options_set(vis
->win
->view
, UI_OPTION_NONE
);
136 static const KeyBinding prompt_enter_binding
= {
138 .action
= &(KeyAction
){
139 .func
= prompt_enter
,
143 static const KeyBinding prompt_esc_binding
= {
145 .action
= &(KeyAction
){
150 static const KeyBinding prompt_up_binding
= {
152 .action
= &(KeyAction
){
157 static const KeyBinding prompt_tab_binding
= {
159 .alias
= "<C-x><C-o>",
162 void vis_prompt_show(Vis
*vis
, const char *title
) {
163 Win
*active
= vis
->win
;
164 Win
*prompt
= window_new_file(vis
, title
[0] == ':' ? vis
->command_file
: vis
->search_file
,
168 if (vis
->mode
->visual
)
169 window_selection_save(active
);
170 Text
*txt
= prompt
->file
->text
;
171 text_appendf(txt
, "%s\n", title
);
172 Selection
*sel
= view_selections_primary_get(prompt
->view
);
173 view_cursors_scroll_to(sel
, text_size(txt
)-1);
174 prompt
->parent
= active
;
175 prompt
->parent_mode
= vis
->mode
;
176 vis_window_mode_map(prompt
, VIS_MODE_NORMAL
, true, "<Enter>", &prompt_enter_binding
);
177 vis_window_mode_map(prompt
, VIS_MODE_INSERT
, true, "<Enter>", &prompt_enter_binding
);
178 vis_window_mode_map(prompt
, VIS_MODE_VISUAL
, true, "<Enter>", &prompt_enter_binding
);
179 vis_window_mode_map(prompt
, VIS_MODE_NORMAL
, true, "<Escape>", &prompt_esc_binding
);
180 vis_window_mode_map(prompt
, VIS_MODE_INSERT
, true, "<Up>", &prompt_up_binding
);
182 vis_window_mode_map(prompt
, VIS_MODE_INSERT
, true, "<Tab>", &prompt_tab_binding
);
183 vis_mode_switch(vis
, VIS_MODE_INSERT
);
186 void vis_info_show(Vis
*vis
, const char *msg
, ...) {
189 vis
->ui
->info(vis
->ui
, msg
, ap
);
193 void vis_info_hide(Vis
*vis
) {
194 vis
->ui
->info_hide(vis
->ui
);
197 void vis_message_show(Vis
*vis
, const char *msg
) {
200 if (!vis
->message_window
)
201 vis
->message_window
= window_new_file(vis
, vis
->error_file
, UI_OPTION_STATUSBAR
);
202 Win
*win
= vis
->message_window
;
205 Text
*txt
= win
->file
->text
;
206 size_t pos
= text_size(txt
);
207 text_appendf(txt
, "%s\n", msg
);
208 text_save(txt
, NULL
);
209 view_cursor_to(win
->view
, pos
);
210 vis_window_focus(win
);
213 void vis_message_hide(Vis
*vis
) {
214 if (!vis
->message_window
)
216 vis_window_close(vis
->message_window
);
217 vis
->message_window
= NULL
;