1 /* cooledit.bindings file parser
3 Authors: 2005 Vitja Makarov
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
29 #include <sys/types.h>
33 #include <mhl/string.h>
35 #include "../src/global.h"
38 #include "edit-widget.h"
39 #include "editcmddef.h" /* list of commands */
41 #include "../src/key.h" /* KEY_M_* */
42 #include "../src/tty.h" /* keys */
43 #include "../src/wtools.h"
44 #include "../src/widget.h" /* buttonbar_redraw() */
46 typedef struct NameMap
{
51 typedef struct Config
{
52 time_t mtime
; /* mtime at the moment we read config file */
58 typedef struct Command
{
60 int (*handler
) (config_t
*cfg
, int argc
, char *argv
[]);
63 static char error_msg
[200] = "Nobody see this";
65 static const name_map_t key_names
[] = {
66 {"backspace", KEY_BACKSPACE
},
80 {"scancel", KEY_SCANCEL
},
97 static const name_map_t command_names
[] = {
98 {"No-Command", CK_Ignore_Key
},
99 {"Ignore-Key", CK_Ignore_Key
},
100 {"BackSpace", CK_BackSpace
},
101 {"Delete", CK_Delete
},
103 {"Page-Up", CK_Page_Up
},
104 {"Page-Down", CK_Page_Down
},
107 {"Word-Left", CK_Word_Left
},
108 {"Word-Right", CK_Word_Right
},
115 {"Beginning-Of-Text", CK_Beginning_Of_Text
},
116 {"End-Of-Text", CK_End_Of_Text
},
117 {"Scroll-Up", CK_Scroll_Up
},
118 {"Scroll-Down", CK_Scroll_Down
},
119 {"Return", CK_Return
},
120 {"Begin-Page", CK_Begin_Page
},
121 {"End-Page", CK_End_Page
},
122 {"Delete-Word-Left", CK_Delete_Word_Left
},
123 {"Delete-Word-Right", CK_Delete_Word_Right
},
124 {"Paragraph-Up", CK_Paragraph_Up
},
125 {"Paragraph-Down", CK_Paragraph_Down
},
129 {"Save-as", CK_Save_As
},
133 {"Remove", CK_Remove
},
134 {"Unmark", CK_Unmark
},
135 {"Save-Block", CK_Save_Block
},
136 {"Column-Mark", CK_Column_Mark
},
138 {"Find-Again", CK_Find_Again
},
139 {"Replace", CK_Replace
},
140 {"Replace-Again", CK_Replace_Again
},
141 {"Complete-Word", CK_Complete_Word
},
142 {"Debug-Start", CK_Debug_Start
},
143 {"Debug-Stop", CK_Debug_Stop
},
144 {"Debug-Toggle-Break", CK_Debug_Toggle_Break
},
145 {"Debug-Clear", CK_Debug_Clear
},
146 {"Debug-Next", CK_Debug_Next
},
147 {"Debug-Step", CK_Debug_Step
},
148 {"Debug-Back-Trace", CK_Debug_Back_Trace
},
149 {"Debug-Continue", CK_Debug_Continue
},
150 {"Debug-Enter-Command", CK_Debug_Enter_Command
},
151 {"Debug-Until-Curser", CK_Debug_Until_Curser
},
152 {"Insert-File", CK_Insert_File
},
154 {"Toggle-Insert", CK_Toggle_Insert
},
157 {"Refresh", CK_Refresh
},
159 {"Delete-Line", CK_Delete_Line
},
160 {"Delete-To-Line-End", CK_Delete_To_Line_End
},
161 {"Delete-To-Line-Begin", CK_Delete_To_Line_Begin
},
162 {"Man-Page", CK_Man_Page
},
165 {"Cancel", CK_Cancel
},
166 {"Complete", CK_Complete
},
167 {"Paragraph-Format", CK_Paragraph_Format
},
169 {"Type-Load-Python", CK_Type_Load_Python
},
170 {"Find-File", CK_Find_File
},
172 {"Match-Bracket", CK_Match_Bracket
},
173 {"Terminal", CK_Terminal
},
174 {"Terminal-App", CK_Terminal_App
},
175 {"ExtCmd", CK_ExtCmd
},
176 {"User-Menu", CK_User_Menu
},
177 {"Save-Desktop", CK_Save_Desktop
},
178 {"New-Window", CK_New_Window
},
181 {"Save-And-Quit", CK_Save_And_Quit
},
182 {"Run-Another", CK_Run_Another
},
183 {"Check-Save-And-Quit", CK_Check_Save_And_Quit
},
184 {"Maximize", CK_Maximize
},
185 {"Begin-Record-Macro", CK_Begin_Record_Macro
},
186 {"End-Record-Macro", CK_End_Record_Macro
},
187 {"Delete-Macro", CK_Delete_Macro
},
188 {"Toggle-Bookmark", CK_Toggle_Bookmark
},
189 {"Flush-Bookmarks", CK_Flush_Bookmarks
},
190 {"Next-Bookmark", CK_Next_Bookmark
},
191 {"Prev-Bookmark", CK_Prev_Bookmark
},
192 {"Page-Up-Highlight", CK_Page_Up_Highlight
},
193 {"Page-Down-Highlight", CK_Page_Down_Highlight
},
194 {"Left-Highlight", CK_Left_Highlight
},
195 {"Right-Highlight", CK_Right_Highlight
},
196 {"Word-Left-Highlight", CK_Word_Left_Highlight
},
197 {"Word-Right-Highlight", CK_Word_Right_Highlight
},
198 {"Up-Highlight", CK_Up_Highlight
},
199 {"Down-Highlight", CK_Down_Highlight
},
200 {"Home-Highlight", CK_Home_Highlight
},
201 {"End-Highlight", CK_End_Highlight
},
202 {"Beginning-Of-Text-Highlight", CK_Beginning_Of_Text_Highlight
},
203 {"End-Of-Text_Highlight", CK_End_Of_Text_Highlight
},
204 {"Begin-Page-Highlight", CK_Begin_Page_Highlight
},
205 {"End-Page-Highlight", CK_End_Page_Highlight
},
206 {"Scroll-Up-Highlight", CK_Scroll_Up_Highlight
},
207 {"Scroll-Down-Highlight", CK_Scroll_Down_Highlight
},
208 {"Paragraph-Up-Highlight", CK_Paragraph_Up_Highlight
},
209 {"Paragraph-Down-Highlight", CK_Paragraph_Down_Highlight
},
210 {"XStore", CK_XStore
},
212 {"XPaste", CK_XPaste
},
213 {"Selection-History", CK_Selection_History
},
215 {"Select-Codepage", CK_Select_Codepage
},
216 {"Insert-Literal", CK_Insert_Literal
},
217 {"Execute-Macro", CK_Execute_Macro
},
218 {"Begin-or-End-Macro", CK_Begin_End_Macro
},
219 {"Ext-mode", CK_Ext_Mode
},
221 {"Focus-Next", CK_Focus_Next
},
222 {"Focus-Prev", CK_Focus_Prev
},
223 {"Height-Inc", CK_Height_Inc
},
224 {"Height-Dec", CK_Height_Dec
},
226 {"Error-Next", CK_Error_Next
},
227 {"Error-Prev", CK_Error_Prev
},
233 cfg_free_maps(config_t
*cfg
)
238 g_array_free(cfg
->keymap
, TRUE
);
241 g_array_free(cfg
->ext_keymap
, TRUE
);
242 cfg
->ext_keymap
= NULL
;
244 for (i
= 0; i
< 10; i
++)
245 g_free(cfg
->labels
[i
]);
248 /* Returns an array containing the words in str. WARNING: As long as
249 * the result is used, str[...] must be valid memory. This function
250 * modifies str[...] and uses it, so the caller should not use it until
251 * g_ptr_array_free() is called for the returned result.
254 split_line(char *str
)
256 gboolean inside_quote
= FALSE
;
260 args
= g_ptr_array_new();
263 while (isspace((unsigned char) *str
))
266 g_ptr_array_add(args
, str
);
270 case '#': /* cut off comments */
275 case '\n': /* end of line */
278 if (str
== g_ptr_array_index(args
, args
->len
- 1))
279 g_ptr_array_remove_index(args
, args
->len
- 1);
281 *(str
- move
) = '\0';
284 case '"': /* quote */
286 inside_quote
= !inside_quote
;
290 case ' ': /* spaces */
295 *(str
++ - move
) = '\0';
299 while (isspace((unsigned char) *str
))
302 g_ptr_array_add(args
, str
--);
321 *(str
- move
) = *str
;
327 keymap_add(GArray
*keymap
, int key
, int cmd
)
329 edit_key_map_type new_one
, *map
;
332 map
= &(g_array_index(keymap
, edit_key_map_type
, 0));
333 for (i
= 0; i
< keymap
->len
; i
++) {
334 if (map
[i
].key
== key
) {
335 map
[i
].command
= cmd
;
341 new_one
.command
= cmd
;
342 g_array_append_val(keymap
, new_one
);
345 /* bind <key> <command> */
347 cmd_bind(config_t
*cfg
, int argc
, char *argv
[])
349 char *keyname
, *command
;
350 const name_map_t
*key
= key_names
;
351 const name_map_t
*cmd
= command_names
;
352 int mod
= 0, k
= -1, m
= 0;
355 snprintf(error_msg
, sizeof(error_msg
),
356 _("bind: Wrong argument number, bind <key> <command>"));
364 switch (*keyname
++) {
376 if (!m
) { /* incorrect key */
377 snprintf(error_msg
, sizeof(error_msg
),
378 _("bind: Bad key value `%s'"), keyname
);
390 if (keyname
[0] == '\0') {
391 snprintf(error_msg
, sizeof(error_msg
), _("bind: Ehh...no key?"));
396 if (keyname
[1] == '\0') {
399 while (key
->name
&& strcasecmp(key
->name
, keyname
) != 0)
403 if (k
< 0 && !key
->name
) {
404 snprintf(error_msg
, sizeof(error_msg
),
405 _("bind: Unknown key: `%s'"), keyname
);
409 while (cmd
->name
&& strcasecmp(cmd
->name
, command
) != 0)
413 snprintf(error_msg
, sizeof(error_msg
),
414 _("bind: Unknown command: `%s'"), command
);
418 if (mod
& KEY_M_CTRL
) {
428 if (mod
& KEY_M_SHIFT
)
431 if (!strcasecmp("bind-ext", argv
[0]))
432 keymap_add(cfg
->ext_keymap
, k
, cmd
->val
);
434 keymap_add(cfg
->keymap
, k
, cmd
->val
);
441 static void cmd_F ## x (WEdit * edit) \
443 send_message ((Widget *) edit, WIDGET_KEY, KEY_F (x)); \
457 void (*cmd_Fx
[]) (WEdit
*) = {
458 cmd_F1
, cmd_F2
, cmd_F3
, cmd_F4
, cmd_F5
,
459 cmd_F6
, cmd_F7
, cmd_F8
, cmd_F9
, cmd_F10
463 static void edit_my_define (Dlg_head
* h
, int idx
, const char *text
,
464 void (*fn
) (WEdit
*), WEdit
* edit
)
466 /* function-cast ok */
467 buttonbar_set_label_data (h
, idx
, text
, (buttonbarfn
) fn
, edit
);
471 /* label <number> <command> <label> */
473 cmd_label(config_t
*cfg
, int argc
, char *argv
[])
475 const name_map_t
*cmd
= command_names
;
476 const char *command
, *label
;
480 snprintf(error_msg
, sizeof(error_msg
),
481 _("%s: Syntax: %s <n> <command> <label>"),
486 fn
= strtol(argv
[1], NULL
, 0);
490 while (cmd
->name
&& strcasecmp(cmd
->name
, command
) != 0)
494 snprintf(error_msg
, sizeof(error_msg
),
495 _("%s: Unknown command: `%s'"), argv
[0], command
);
499 if (fn
< 1 || fn
> 10) {
500 snprintf(error_msg
, sizeof(error_msg
),
501 _("%s: fn should be 1-10"), argv
[0]);
505 keymap_add(cfg
->keymap
, KEY_F(fn
), cmd
->val
);
506 cfg
->labels
[fn
- 1] = g_strdup(label
);
513 parse_file(config_t
*cfg
, const char *file
, const command_t
*cmd
)
518 FILE *fp
= fopen(file
, "r");
521 snprintf(error_msg
, sizeof(error_msg
), _("%s: fopen(): %s"),
522 file
, strerror(errno
));
526 while (fgets(buf
, sizeof(buf
), fp
)) {
527 const command_t
*c
= cmd
;
533 args
= split_line(buf
);
534 argv
= (char **) args
->pdata
;
536 if (args
->len
== 0) {
537 g_ptr_array_free(args
, TRUE
);
541 while (c
->name
!= NULL
&& strcasecmp(c
->name
, argv
[0]) != 0)
544 if (c
->name
== NULL
) {
545 snprintf(error_msg
, sizeof(error_msg
),
546 _("%s:%d: unknown command `%s'"), file
, line
,
548 g_ptr_array_free(args
, TRUE
);
553 if (!(c
->handler(cfg
, args
->len
, argv
))) {
554 char *ss
= g_strdup(error_msg
);
555 snprintf(error_msg
, sizeof(error_msg
),
556 _("%s:%d: %s"), file
, line
, ss
);
558 g_ptr_array_free(args
, TRUE
);
562 g_ptr_array_free(args
, TRUE
);
570 load_user_keymap(config_t
*cfg
, const char *file
)
572 const command_t cmd
[] = {
574 {"bind-ext", cmd_bind
},
575 {"label", cmd_label
},
579 cfg
->keymap
= g_array_new(TRUE
, FALSE
, sizeof(edit_key_map_type
));
580 cfg
->ext_keymap
= g_array_new(TRUE
, FALSE
, sizeof(edit_key_map_type
));
582 if (!parse_file(cfg
, file
, cmd
)) {
590 edit_load_user_map(WEdit
*edit
)
597 if (edit_key_emulation
!= EDIT_KEY_EMULATION_USER
)
600 file
= mhl_str_dir_plus_file(home_dir
, MC_USERMAP
);
602 if (stat(file
, &s
) < 0) {
603 char *msg
= g_strdup_printf(_("%s not found!"), file
);
604 edit_error_dialog(_("Error"), msg
);
610 if (s
.st_mtime
!= cfg
.mtime
) {
611 memset(&new_cfg
, 0, sizeof(new_cfg
));
612 new_cfg
.mtime
= s
.st_mtime
;
614 if (!load_user_keymap(&new_cfg
, file
)) {
615 edit_error_dialog(_("Error"), error_msg
);
616 cfg_free_maps(&new_cfg
);
625 edit
->user_map
= (edit_key_map_type
*) cfg
.keymap
->data
;
626 edit
->ext_map
= (edit_key_map_type
*) cfg
.ext_keymap
->data
;
627 memcpy(edit
->labels
, cfg
.labels
, sizeof(edit
->labels
));