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) {
67 size_t end
= text_line_end(txt
, pos
);
68 size_t prev
= text_search_backward(txt
, end
, regex
);
71 size_t next
= text_search_forward(txt
, pos
, regex
);
73 next
= text_size(txt
);
74 range
= text_range_new(prev
, next
);
76 text_regex_free(regex
);
78 if (text_range_valid(&range
))
79 cmd
= text_bytes_alloc0(txt
, range
.start
, text_range_size(&range
));
83 vis_info_show(vis
, "Prompt window invalid");
85 vis_info_show(vis
, "Failed to detect command");
86 prompt_restore(prompt
);
92 size_t len
= strlen(cmd
);
93 if (len
> 0 && cmd
[len
-1] == '\n')
96 bool lastline
= (range
.end
== text_size(txt
));
98 prompt_restore(prompt
);
99 if (vis_prompt_cmd(vis
, cmd
)) {
102 text_delete(txt
, range
.start
, text_range_size(&range
));
103 text_appendf(txt
, "%s\n", cmd
);
107 vis
->mode
= &vis_modes
[VIS_MODE_INSERT
];
114 static const char *prompt_esc(Vis
*vis
, const char *keys
, const Arg
*arg
) {
115 Win
*prompt
= vis
->win
;
116 if (view_selections_count(prompt
->view
) > 1) {
117 view_selections_dispose_all(prompt
->view
);
119 prompt_restore(prompt
);
125 static const char *prompt_up(Vis
*vis
, const char *keys
, const Arg
*arg
) {
126 vis_motion(vis
, VIS_MOVE_LINE_UP
);
127 vis_window_mode_unmap(vis
->win
, VIS_MODE_INSERT
, "<Up>");
128 view_options_set(vis
->win
->view
, UI_OPTION_SYMBOL_EOF
);
132 static const KeyBinding prompt_enter_binding
= {
134 .action
= &(KeyAction
){
135 .func
= prompt_enter
,
139 static const KeyBinding prompt_esc_binding
= {
141 .action
= &(KeyAction
){
146 static const KeyBinding prompt_up_binding
= {
148 .action
= &(KeyAction
){
153 static const KeyBinding prompt_tab_binding
= {
155 .alias
= "<C-x><C-o>",
158 void vis_prompt_show(Vis
*vis
, const char *title
) {
159 Win
*active
= vis
->win
;
160 Win
*prompt
= window_new_file(vis
, title
[0] == ':' ? vis
->command_file
: vis
->search_file
,
164 Text
*txt
= prompt
->file
->text
;
165 text_appendf(txt
, "%s\n", title
);
166 Selection
*sel
= view_selections_primary_get(prompt
->view
);
167 view_cursors_scroll_to(sel
, text_size(txt
)-1);
168 prompt
->parent
= active
;
169 prompt
->parent_mode
= vis
->mode
;
170 vis_window_mode_map(prompt
, VIS_MODE_NORMAL
, true, "<Enter>", &prompt_enter_binding
);
171 vis_window_mode_map(prompt
, VIS_MODE_INSERT
, true, "<Enter>", &prompt_enter_binding
);
172 vis_window_mode_map(prompt
, VIS_MODE_INSERT
, true, "<C-j>", &prompt_enter_binding
);
173 vis_window_mode_map(prompt
, VIS_MODE_VISUAL
, true, "<Enter>", &prompt_enter_binding
);
174 vis_window_mode_map(prompt
, VIS_MODE_NORMAL
, true, "<Escape>", &prompt_esc_binding
);
175 vis_window_mode_map(prompt
, VIS_MODE_INSERT
, true, "<Up>", &prompt_up_binding
);
177 vis_window_mode_map(prompt
, VIS_MODE_INSERT
, true, "<Tab>", &prompt_tab_binding
);
178 vis_mode_switch(vis
, VIS_MODE_INSERT
);
181 void vis_info_show(Vis
*vis
, const char *msg
, ...) {
184 vis
->ui
->info(vis
->ui
, msg
, ap
);
188 void vis_info_hide(Vis
*vis
) {
189 vis
->ui
->info_hide(vis
->ui
);
192 void vis_message_show(Vis
*vis
, const char *msg
) {
195 if (!vis
->message_window
)
196 vis
->message_window
= window_new_file(vis
, vis
->error_file
, UI_OPTION_STATUSBAR
);
197 Win
*win
= vis
->message_window
;
200 Text
*txt
= win
->file
->text
;
201 size_t pos
= text_size(txt
);
202 text_appendf(txt
, "%s\n", msg
);
203 text_save(txt
, NULL
);
204 view_cursor_to(win
->view
, pos
);
205 vis_window_focus(win
);
208 void vis_message_hide(Vis
*vis
) {
209 if (!vis
->message_window
)
211 vis_window_close(vis
->message_window
);
212 vis
->message_window
= NULL
;