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
22 * \brief Source: cooledit.bindings file parser
23 * \author Vitja Makarov
35 #include <sys/types.h>
39 #include "../src/global.h"
41 #include "../src/tty/tty.h" /* keys */
42 #include "../src/tty/key.h" /* KEY_M_* */
44 #include "edit-impl.h"
45 #include "edit-widget.h"
46 #include "editcmddef.h" /* list of commands */
49 #include "../src/wtools.h"
50 #include "../src/widget.h" /* buttonbar_redraw() */
52 typedef struct NameMap
{
57 typedef struct Config
{
58 time_t mtime
; /* mtime at the moment we read config file */
64 typedef struct Command
{
66 int (*handler
) (config_t
*cfg
, int argc
, char *argv
[]);
69 static char error_msg
[200] = "Nobody see this";
71 static const name_map_t key_names
[] = {
72 {"backspace", KEY_BACKSPACE
},
86 {"scancel", KEY_SCANCEL
},
103 static const name_map_t command_names
[] = {
104 {"No-Command", CK_Ignore_Key
},
105 {"Ignore-Key", CK_Ignore_Key
},
106 {"BackSpace", CK_BackSpace
},
107 {"Delete", CK_Delete
},
109 {"Page-Up", CK_Page_Up
},
110 {"Page-Down", CK_Page_Down
},
113 {"Word-Left", CK_Word_Left
},
114 {"Word-Right", CK_Word_Right
},
121 {"Beginning-Of-Text", CK_Beginning_Of_Text
},
122 {"End-Of-Text", CK_End_Of_Text
},
123 {"Scroll-Up", CK_Scroll_Up
},
124 {"Scroll-Down", CK_Scroll_Down
},
125 {"Return", CK_Return
},
126 {"Begin-Page", CK_Begin_Page
},
127 {"End-Page", CK_End_Page
},
128 {"Delete-Word-Left", CK_Delete_Word_Left
},
129 {"Delete-Word-Right", CK_Delete_Word_Right
},
130 {"Paragraph-Up", CK_Paragraph_Up
},
131 {"Paragraph-Down", CK_Paragraph_Down
},
135 {"Save-as", CK_Save_As
},
139 {"Remove", CK_Remove
},
140 {"Unmark", CK_Unmark
},
141 {"Save-Block", CK_Save_Block
},
142 {"Column-Mark", CK_Column_Mark
},
144 {"Find-Again", CK_Find_Again
},
145 {"Replace", CK_Replace
},
146 {"Replace-Again", CK_Replace_Again
},
147 {"Complete-Word", CK_Complete_Word
},
148 {"Debug-Start", CK_Debug_Start
},
149 {"Debug-Stop", CK_Debug_Stop
},
150 {"Debug-Toggle-Break", CK_Debug_Toggle_Break
},
151 {"Debug-Clear", CK_Debug_Clear
},
152 {"Debug-Next", CK_Debug_Next
},
153 {"Debug-Step", CK_Debug_Step
},
154 {"Debug-Back-Trace", CK_Debug_Back_Trace
},
155 {"Debug-Continue", CK_Debug_Continue
},
156 {"Debug-Enter-Command", CK_Debug_Enter_Command
},
157 {"Debug-Until-Curser", CK_Debug_Until_Curser
},
158 {"Insert-File", CK_Insert_File
},
160 {"Toggle-Insert", CK_Toggle_Insert
},
163 {"Refresh", CK_Refresh
},
165 {"Delete-Line", CK_Delete_Line
},
166 {"Delete-To-Line-End", CK_Delete_To_Line_End
},
167 {"Delete-To-Line-Begin", CK_Delete_To_Line_Begin
},
168 {"Man-Page", CK_Man_Page
},
171 {"Cancel", CK_Cancel
},
172 {"Complete", CK_Complete
},
173 {"Paragraph-Format", CK_Paragraph_Format
},
175 {"Type-Load-Python", CK_Type_Load_Python
},
176 {"Find-File", CK_Find_File
},
178 {"Match-Bracket", CK_Match_Bracket
},
179 {"Terminal", CK_Terminal
},
180 {"Terminal-App", CK_Terminal_App
},
181 {"ExtCmd", CK_ExtCmd
},
182 {"User-Menu", CK_User_Menu
},
183 {"Save-Desktop", CK_Save_Desktop
},
184 {"New-Window", CK_New_Window
},
187 {"Save-And-Quit", CK_Save_And_Quit
},
188 {"Run-Another", CK_Run_Another
},
189 {"Check-Save-And-Quit", CK_Check_Save_And_Quit
},
190 {"Maximize", CK_Maximize
},
191 {"Begin-Record-Macro", CK_Begin_Record_Macro
},
192 {"End-Record-Macro", CK_End_Record_Macro
},
193 {"Delete-Macro", CK_Delete_Macro
},
194 {"Toggle-Bookmark", CK_Toggle_Bookmark
},
195 {"Flush-Bookmarks", CK_Flush_Bookmarks
},
196 {"Next-Bookmark", CK_Next_Bookmark
},
197 {"Prev-Bookmark", CK_Prev_Bookmark
},
198 {"Page-Up-Highlight", CK_Page_Up_Highlight
},
199 {"Page-Down-Highlight", CK_Page_Down_Highlight
},
200 {"Left-Highlight", CK_Left_Highlight
},
201 {"Right-Highlight", CK_Right_Highlight
},
202 {"Word-Left-Highlight", CK_Word_Left_Highlight
},
203 {"Word-Right-Highlight", CK_Word_Right_Highlight
},
204 {"Up-Highlight", CK_Up_Highlight
},
205 {"Down-Highlight", CK_Down_Highlight
},
206 {"Home-Highlight", CK_Home_Highlight
},
207 {"End-Highlight", CK_End_Highlight
},
208 {"Beginning-Of-Text-Highlight", CK_Beginning_Of_Text_Highlight
},
209 {"End-Of-Text_Highlight", CK_End_Of_Text_Highlight
},
210 {"Begin-Page-Highlight", CK_Begin_Page_Highlight
},
211 {"End-Page-Highlight", CK_End_Page_Highlight
},
212 {"Scroll-Up-Highlight", CK_Scroll_Up_Highlight
},
213 {"Scroll-Down-Highlight", CK_Scroll_Down_Highlight
},
214 {"Paragraph-Up-Highlight", CK_Paragraph_Up_Highlight
},
215 {"Paragraph-Down-Highlight", CK_Paragraph_Down_Highlight
},
216 {"XStore", CK_XStore
},
218 {"XPaste", CK_XPaste
},
219 {"Selection-History", CK_Selection_History
},
221 {"Select-Codepage", CK_Select_Codepage
},
222 {"Insert-Literal", CK_Insert_Literal
},
223 {"Execute-Macro", CK_Execute_Macro
},
224 {"Begin-or-End-Macro", CK_Begin_End_Macro
},
225 {"Ext-mode", CK_Ext_Mode
},
226 {"Toggle-Line-State", CK_Toggle_Line_State
},
228 {"Focus-Next", CK_Focus_Next
},
229 {"Focus-Prev", CK_Focus_Prev
},
230 {"Height-Inc", CK_Height_Inc
},
231 {"Height-Dec", CK_Height_Dec
},
233 {"Error-Next", CK_Error_Next
},
234 {"Error-Prev", CK_Error_Prev
},
240 cfg_free_maps(config_t
*cfg
)
245 g_array_free(cfg
->keymap
, TRUE
);
248 g_array_free(cfg
->ext_keymap
, TRUE
);
249 cfg
->ext_keymap
= NULL
;
251 for (i
= 0; i
< 10; i
++)
252 g_free(cfg
->labels
[i
]);
255 /* Returns an array containing the words in str. WARNING: As long as
256 * the result is used, str[...] must be valid memory. This function
257 * modifies str[...] and uses it, so the caller should not use it until
258 * g_ptr_array_free() is called for the returned result.
261 split_line(char *str
)
263 gboolean inside_quote
= FALSE
;
267 args
= g_ptr_array_new();
270 while (isspace((unsigned char) *str
))
273 g_ptr_array_add(args
, str
);
277 case '#': /* cut off comments */
282 case '\n': /* end of line */
285 if (str
== g_ptr_array_index(args
, args
->len
- 1))
286 g_ptr_array_remove_index(args
, args
->len
- 1);
288 *(str
- move
) = '\0';
291 case '"': /* quote */
293 inside_quote
= !inside_quote
;
297 case ' ': /* spaces */
302 *(str
++ - move
) = '\0';
306 while (isspace((unsigned char) *str
))
309 g_ptr_array_add(args
, str
--);
328 *(str
- move
) = *str
;
334 keymap_add(GArray
*keymap
, int key
, int cmd
)
336 edit_key_map_type new_one
, *map
;
339 map
= &(g_array_index(keymap
, edit_key_map_type
, 0));
340 for (i
= 0; i
< keymap
->len
; i
++) {
341 if (map
[i
].key
== key
) {
342 map
[i
].command
= cmd
;
348 new_one
.command
= cmd
;
349 g_array_append_val(keymap
, new_one
);
352 /* bind <key> <command> */
354 cmd_bind(config_t
*cfg
, int argc
, char *argv
[])
356 char *keyname
, *command
;
357 const name_map_t
*key
= key_names
;
358 const name_map_t
*cmd
= command_names
;
359 int mod
= 0, k
= -1, m
= 0;
362 snprintf(error_msg
, sizeof(error_msg
),
363 _("bind: Wrong argument number, bind <key> <command>"));
371 switch (*keyname
++) {
383 if (!m
) { /* incorrect key */
384 snprintf(error_msg
, sizeof(error_msg
),
385 _("bind: Bad key value `%s'"), keyname
);
397 if (keyname
[0] == '\0') {
398 snprintf(error_msg
, sizeof(error_msg
), _("bind: Ehh...no key?"));
403 if (keyname
[1] == '\0') {
406 while (key
->name
&& strcasecmp(key
->name
, keyname
) != 0)
410 if (k
< 0 && !key
->name
) {
411 snprintf(error_msg
, sizeof(error_msg
),
412 _("bind: Unknown key: `%s'"), keyname
);
416 while (cmd
->name
&& strcasecmp(cmd
->name
, command
) != 0)
420 snprintf(error_msg
, sizeof(error_msg
),
421 _("bind: Unknown command: `%s'"), command
);
425 if (mod
& KEY_M_CTRL
) {
435 if (mod
& KEY_M_SHIFT
)
438 if (!strcasecmp("bind-ext", argv
[0]))
439 keymap_add(cfg
->ext_keymap
, k
, cmd
->val
);
441 keymap_add(cfg
->keymap
, k
, cmd
->val
);
448 static void cmd_F ## x (WEdit * edit) \
450 send_message ((Widget *) edit, WIDGET_KEY, KEY_F (x)); \
464 void (*cmd_Fx
[]) (WEdit
*) = {
465 cmd_F1
, cmd_F2
, cmd_F3
, cmd_F4
, cmd_F5
,
466 cmd_F6
, cmd_F7
, cmd_F8
, cmd_F9
, cmd_F10
470 static void edit_my_define (Dlg_head
* h
, int idx
, const char *text
,
471 void (*fn
) (WEdit
*), WEdit
* edit
)
473 /* function-cast ok */
474 buttonbar_set_label_data (h
, idx
, text
, (buttonbarfn
) fn
, edit
);
478 /* label <number> <command> <label> */
480 cmd_label(config_t
*cfg
, int argc
, char *argv
[])
482 const name_map_t
*cmd
= command_names
;
483 const char *command
, *label
;
487 snprintf(error_msg
, sizeof(error_msg
),
488 _("%s: Syntax: %s <n> <command> <label>"),
493 fn
= strtol(argv
[1], NULL
, 0);
497 while (cmd
->name
&& strcasecmp(cmd
->name
, command
) != 0)
501 snprintf(error_msg
, sizeof(error_msg
),
502 _("%s: Unknown command: `%s'"), argv
[0], command
);
506 if (fn
< 1 || fn
> 10) {
507 snprintf(error_msg
, sizeof(error_msg
),
508 _("%s: fn should be 1-10"), argv
[0]);
512 keymap_add(cfg
->keymap
, KEY_F(fn
), cmd
->val
);
513 cfg
->labels
[fn
- 1] = g_strdup(label
);
520 parse_file(config_t
*cfg
, const char *file
, const command_t
*cmd
)
525 FILE *fp
= fopen(file
, "r");
528 snprintf(error_msg
, sizeof(error_msg
), _("%s: fopen(): %s"),
529 file
, strerror(errno
));
533 while (fgets(buf
, sizeof(buf
), fp
)) {
534 const command_t
*c
= cmd
;
540 args
= split_line(buf
);
541 argv
= (char **) args
->pdata
;
543 if (args
->len
== 0) {
544 g_ptr_array_free(args
, TRUE
);
548 while (c
->name
!= NULL
&& strcasecmp(c
->name
, argv
[0]) != 0)
551 if (c
->name
== NULL
) {
552 snprintf(error_msg
, sizeof(error_msg
),
553 _("%s:%d: unknown command `%s'"), file
, line
,
555 g_ptr_array_free(args
, TRUE
);
560 if (!(c
->handler(cfg
, args
->len
, argv
))) {
561 char *ss
= g_strdup(error_msg
);
562 snprintf(error_msg
, sizeof(error_msg
),
563 _("%s:%d: %s"), file
, line
, ss
);
565 g_ptr_array_free(args
, TRUE
);
569 g_ptr_array_free(args
, TRUE
);
577 load_user_keymap(config_t
*cfg
, const char *file
)
579 const command_t cmd
[] = {
581 {"bind-ext", cmd_bind
},
582 {"label", cmd_label
},
586 cfg
->keymap
= g_array_new(TRUE
, FALSE
, sizeof(edit_key_map_type
));
587 cfg
->ext_keymap
= g_array_new(TRUE
, FALSE
, sizeof(edit_key_map_type
));
589 if (!parse_file(cfg
, file
, cmd
)) {
597 edit_load_user_map(WEdit
*edit
)
604 if (edit_key_emulation
!= EDIT_KEY_EMULATION_USER
)
607 file
= concat_dir_and_file(home_dir
, MC_USERMAP
);
609 if (stat(file
, &s
) < 0) {
610 char *msg
= g_strdup_printf(_("%s not found!"), file
);
611 edit_error_dialog(_("Error"), msg
);
617 if (s
.st_mtime
!= cfg
.mtime
) {
618 memset(&new_cfg
, 0, sizeof(new_cfg
));
619 new_cfg
.mtime
= s
.st_mtime
;
621 if (!load_user_keymap(&new_cfg
, file
)) {
622 edit_error_dialog(_("Error"), error_msg
);
623 cfg_free_maps(&new_cfg
);
632 edit
->user_map
= (edit_key_map_type
*) cfg
.keymap
->data
;
633 edit
->ext_map
= (edit_key_map_type
*) cfg
.ext_keymap
->data
;
634 memcpy(edit
->labels
, cfg
.labels
, sizeof(edit
->labels
));