1 /* Ex-mode-like commandline support */
2 
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
6 
7 #include <ctype.h>
8 #include <string.h>
9 
10 #include "elinks.h"
11 
12 #include "bfu/dialog.h"
13 #include "config/conf.h"
14 #include "config/kbdbind.h"
15 #include "config/options.h"
16 #include "dialogs/exmode.h"
17 #include "intl/gettext/libintl.h"
18 #include "main/module.h"
19 #include "session/session.h"
20 #include "session/task.h"
21 #include "terminal/terminal.h"
22 #include "util/error.h"
23 #include "util/memory.h"
24 #include "util/string.h"
25 #include "viewer/action.h"
26 
27 
28 /* The Ex-mode commandline is that blue-yellow thing which appears at the
29  * bottom of the screen when you press ':' and lets you enter various commands
30  * (just like in vi), especially actions, events (where they make sense) and
31  * config-file commands. */
32 
33 
34 #define EXMODE_HISTORY_FILENAME		"exmodehist"
35 
36 static INIT_INPUT_HISTORY(exmode_history);
37 
38 typedef int (*exmode_handler_T)(struct session *, unsigned char *, unsigned char *);
39 
40 static int
exmode_action_handler(struct session * ses,unsigned char * command,unsigned char * args)41 exmode_action_handler(struct session *ses, unsigned char *command,
42 		      unsigned char *args)
43 {
44 	enum main_action action_id = get_action_from_string(KEYMAP_MAIN, command);
45 
46 	if (action_id == ACT_MAIN_NONE) return 0;
47 	if (action_id == ACT_MAIN_QUIT) action_id = ACT_MAIN_REALLY_QUIT;
48 
49 	if (!*args)
50 		return do_action(ses, action_id, 0) != FRAME_EVENT_IGNORED;
51 
52 	switch (action_id) {
53 		case ACT_MAIN_GOTO_URL:
54 			goto_url_with_hook(ses, args);
55 			return 1;
56 		default:
57 			break;
58 	}
59 	return 0;
60 }
61 
62 static int
exmode_confcmd_handler(struct session * ses,unsigned char * command,unsigned char * args)63 exmode_confcmd_handler(struct session *ses, unsigned char *command,
64 			unsigned char *args)
65 {
66 	enum parse_error err;
67 
68 	assert(ses && command && args);
69 
70 	if (get_cmd_opt_bool("anonymous"))
71 		return 0;
72 
73 	/* Undo the arguments separation. */
74 	if (*args) *(--args) = ' ';
75 
76 	err = parse_config_exmode_command(command);
77 	return err;
78 }
79 
80 static const exmode_handler_T exmode_handlers[] = {
81 	exmode_action_handler,
82 	exmode_confcmd_handler,
83 	NULL,
84 };
85 
86 static void
exmode_exec(struct session * ses,unsigned char buffer[INPUT_LINE_BUFFER_SIZE])87 exmode_exec(struct session *ses, unsigned char buffer[INPUT_LINE_BUFFER_SIZE])
88 {
89 	/* First look it up as action, then try it as an event (but the event
90 	 * part should be thought out somehow yet, I s'pose... let's leave it
91 	 * off for now). Then try to evaluate it as configfile command. Then at
92 	 * least pop up an error. */
93 	unsigned char *command = buffer;
94 	unsigned char *args = command;
95 	int i;
96 
97 	while (*command == ':') command++;
98 
99 	if (!*command) return;
100 
101 	add_to_input_history(&exmode_history, command, 1);
102 
103 	skip_nonspace(args);
104 	if (*args) *args++ = 0;
105 
106 	for (i = 0; exmode_handlers[i]; i++) {
107 		if (exmode_handlers[i](ses, command, args))
108 			break;
109 	}
110 }
111 
112 
113 static enum input_line_code
exmode_input_handler(struct input_line * input_line,int action_id)114 exmode_input_handler(struct input_line *input_line, int action_id)
115 {
116 	switch (action_id) {
117 		case ACT_EDIT_ENTER:
118 			exmode_exec(input_line->ses, input_line->buffer);
119 			return INPUT_LINE_CANCEL;
120 
121 		default:
122 			return INPUT_LINE_PROCEED;
123 	}
124 }
125 
126 void
exmode_start(struct session * ses)127 exmode_start(struct session *ses)
128 {
129 	input_field_line(ses, ":", NULL, &exmode_history, exmode_input_handler);
130 }
131 
132 
133 static void
init_exmode(struct module * module)134 init_exmode(struct module *module)
135 {
136 	load_input_history(&exmode_history, EXMODE_HISTORY_FILENAME);
137 }
138 
139 static void
done_exmode(struct module * module)140 done_exmode(struct module *module)
141 {
142 	save_input_history(&exmode_history, EXMODE_HISTORY_FILENAME);
143 	free_list(exmode_history.entries);
144 }
145 
146 struct module exmode_module = struct_module(
147 	/* name: */		N_("Exmode"),
148 	/* options: */		NULL,
149 	/* hooks: */		NULL,
150 	/* submodules: */	NULL,
151 	/* data: */		NULL,
152 	/* init: */		init_exmode,
153 	/* done: */		done_exmode
154 );
155