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 int cflags
= REG_EXTENDED
|REG_NEWLINE
|(REG_ICASE
*vis
->ignorecase
);
67 if (pattern
&& regex
&& text_regex_compile(regex
, pattern
, cflags
) == 0) {
68 size_t end
= text_line_end(txt
, pos
);
69 size_t prev
= text_search_backward(txt
, end
, regex
);
72 size_t next
= text_search_forward(txt
, pos
, regex
);
74 next
= text_size(txt
);
75 range
= text_range_new(prev
, next
);
77 text_regex_free(regex
);
79 if (text_range_valid(&range
))
80 cmd
= text_bytes_alloc0(txt
, range
.start
, text_range_size(&range
));
84 vis_info_show(vis
, "Prompt window invalid");
86 vis_info_show(vis
, "Failed to detect command");
87 prompt_restore(prompt
);
93 size_t len
= strlen(cmd
);
94 if (len
> 0 && cmd
[len
-1] == '\n')
97 bool lastline
= (range
.end
== text_size(txt
));
99 prompt_restore(prompt
);
100 if (vis_prompt_cmd(vis
, cmd
)) {
103 text_delete(txt
, range
.start
, text_range_size(&range
));
104 text_appendf(txt
, "%s\n", cmd
);
108 vis
->mode
= &vis_modes
[VIS_MODE_INSERT
];
115 static const char *prompt_esc(Vis
*vis
, const char *keys
, const Arg
*arg
) {
116 Win
*prompt
= vis
->win
;
117 if (view_selections_count(prompt
->view
) > 1) {
118 view_selections_dispose_all(prompt
->view
);
120 prompt_restore(prompt
);
126 static const char *prompt_up(Vis
*vis
, const char *keys
, const Arg
*arg
) {
127 vis_motion(vis
, VIS_MOVE_LINE_UP
);
128 vis_window_mode_unmap(vis
->win
, VIS_MODE_INSERT
, "<Up>");
129 view_options_set(vis
->win
->view
, UI_OPTION_SYMBOL_EOF
);
133 static const KeyBinding prompt_enter_binding
= {
135 .action
= &(KeyAction
){
136 .func
= prompt_enter
,
140 static const KeyBinding prompt_esc_binding
= {
142 .action
= &(KeyAction
){
147 static const KeyBinding prompt_up_binding
= {
149 .action
= &(KeyAction
){
154 static const KeyBinding prompt_tab_binding
= {
156 .alias
= "<C-x><C-o>",
159 void vis_prompt_show(Vis
*vis
, const char *title
) {
160 Win
*active
= vis
->win
;
161 Win
*prompt
= window_new_file(vis
, title
[0] == ':' ? vis
->command_file
: vis
->search_file
,
165 Text
*txt
= prompt
->file
->text
;
166 text_appendf(txt
, "%s\n", title
);
167 Selection
*sel
= view_selections_primary_get(prompt
->view
);
168 view_cursors_scroll_to(sel
, text_size(txt
)-1);
169 prompt
->parent
= active
;
170 prompt
->parent_mode
= vis
->mode
;
171 vis_window_mode_map(prompt
, VIS_MODE_NORMAL
, true, "<Enter>", &prompt_enter_binding
);
172 vis_window_mode_map(prompt
, VIS_MODE_INSERT
, true, "<Enter>", &prompt_enter_binding
);
173 vis_window_mode_map(prompt
, VIS_MODE_INSERT
, true, "<C-j>", &prompt_enter_binding
);
174 vis_window_mode_map(prompt
, VIS_MODE_VISUAL
, true, "<Enter>", &prompt_enter_binding
);
175 vis_window_mode_map(prompt
, VIS_MODE_NORMAL
, true, "<Escape>", &prompt_esc_binding
);
176 vis_window_mode_map(prompt
, VIS_MODE_INSERT
, true, "<Up>", &prompt_up_binding
);
178 vis_window_mode_map(prompt
, VIS_MODE_INSERT
, true, "<Tab>", &prompt_tab_binding
);
179 vis_mode_switch(vis
, VIS_MODE_INSERT
);
182 void vis_info_show(Vis
*vis
, const char *msg
, ...) {
185 vis
->ui
->info(vis
->ui
, msg
, ap
);
189 void vis_info_hide(Vis
*vis
) {
190 vis
->ui
->info_hide(vis
->ui
);
193 void vis_message_show(Vis
*vis
, const char *msg
) {
196 if (!vis
->message_window
)
197 vis
->message_window
= window_new_file(vis
, vis
->error_file
, UI_OPTION_STATUSBAR
);
198 Win
*win
= vis
->message_window
;
201 Text
*txt
= win
->file
->text
;
202 size_t pos
= text_size(txt
);
203 text_appendf(txt
, "%s\n", msg
);
204 text_save(txt
, NULL
);
205 view_cursor_to(win
->view
, pos
);
206 vis_window_focus(win
);
209 void vis_message_hide(Vis
*vis
) {
210 if (!vis
->message_window
)
212 vis_window_close(vis
->message_window
);
213 vis
->message_window
= NULL
;