Ticket #4196: InstructionStation_v3.8.patch
File InstructionStation_v3.8.patch, 71.6 KB (added by psprint, 4 years ago) |
---|
-
lib/global.h
From 4d62b9b1d16ff99a9d9cbc6033d0b58a24c2696b Mon Sep 17 00:00:00 2001 From: Sebastian Gniazdowski <sgniazdowski@gmail.com> Date: Wed, 17 Feb 2021 15:02:15 -0600 Subject: CLI window for MCEdit --- lib/global.h | 3 + lib/keybind.c | 1 + lib/keybind.h | 1 + lib/tty/key.c | 10 +- lib/widget/wtools.c | 40 +- lib/widget/wtools.h | 4 + misc/mc.default.keymap | 1 + misc/mc.emacs.keymap | 1 + src/editor/Makefile.am | 1 + src/editor/edit-impl.h | 24 +- src/editor/edit.c | 27 +- src/editor/editcmd.c | 41 +- src/editor/editdraw.c | 1 - src/editor/editmenu.c | 3 + src/editor/editwidget.c | 550 +++++++++++----------- src/editor/editwidget.h | 3 + src/editor/instr_station.c | 902 +++++++++++++++++++++++++++++++++++++ src/editor/instr_station.h | 92 ++++ src/keybind-defaults.c | 1 + 19 files changed, 1416 insertions(+), 290 deletions(-) create mode 100644 src/editor/instr_station.c create mode 100644 src/editor/instr_station.h diff --git a/lib/global.h b/lib/global.h index c60063faa..05d88cbb4 100644
a b 103 103 #include "lib/logging.h" 104 104 #endif 105 105 106 #define has_flag(x,y) (((x) & (y)) != 0) 107 #define set_flag_in(x,y) ((x) |= (y)) 108 106 109 /* Just for keeping Your's brains from invention a proper size of the buffer :-) */ 107 110 #define BUF_10K 10240L 108 111 #define BUF_8K 8192L -
lib/keybind.c
diff --git a/lib/keybind.c b/lib/keybind.c index abd44d3e2..40e25466c 100644
a b static name_keymap_t command_names[] = { 290 290 ADD_KEYMAP_NAME (EditMail), 291 291 ADD_KEYMAP_NAME (ParagraphFormat), 292 292 ADD_KEYMAP_NAME (MatchBracket), 293 ADD_KEYMAP_NAME (InstructionStation), 293 294 ADD_KEYMAP_NAME (ExternalCommand), 294 295 ADD_KEYMAP_NAME (MacroStartRecord), 295 296 ADD_KEYMAP_NAME (MacroStopRecord), -
lib/keybind.h
diff --git a/lib/keybind.h b/lib/keybind.h index af019df09..e99181ec6 100644
a b enum 314 314 CK_SyntaxOnOff, 315 315 CK_SyntaxChoose, 316 316 CK_InsertLiteral, 317 CK_InstructionStation, 317 318 CK_ExternalCommand, 318 319 CK_Date, 319 320 CK_EditMail, -
lib/tty/key.c
diff --git a/lib/tty/key.c b/lib/tty/key.c index 4abfc71d7..8876fbf82 100644
a b tty_get_event (struct Gpm_Event *event, gboolean redo_event, gboolean block) 2031 2031 time_out.tv_sec = 0; 2032 2032 time_out.tv_usec = 0; 2033 2033 } 2034 2034 else if (time_addr == NULL) 2035 { 2036 /* Standard timeout to call GLib main loop */ 2037 time_addr = &time_out; 2038 time_addr->tv_sec = 0; 2039 time_addr->tv_usec = 200000; 2040 } 2035 2041 tty_enable_interrupt_key (); 2036 2042 flag = select (nfd, &select_set, NULL, NULL, time_addr); 2037 2043 tty_disable_interrupt_key (); … … tty_get_event (struct Gpm_Event *event, gboolean redo_event, gboolean block) 2043 2049 */ 2044 2050 if (flag == 0) 2045 2051 { 2052 /* Provide CPU time to GLib main loop's default context */ 2053 g_main_context_iteration (NULL, FALSE); 2046 2054 if (redo_event) 2047 2055 return EV_MOUSE; 2048 2056 if (!block || tty_got_winch ()) -
lib/widget/wtools.c
diff --git a/lib/widget/wtools.c b/lib/widget/wtools.c index 5c5dc4487..bc5937111 100644
a b bg_message (int dummy, int *flags, char *title, const char *text) 184 184 static char * 185 185 fg_input_dialog_help (const char *header, const char *text, const char *help, 186 186 const char *history_name, const char *def_text, gboolean strip_password, 187 input_complete_t completion_flags )187 input_complete_t completion_flags, quick_widget_t * add_w) 188 188 { 189 189 char *p_text; 190 190 char histname[64] = "inp|"; … … fg_input_dialog_help (const char *header, const char *text, const char *help, 209 209 } 210 210 211 211 { 212 quick_widget_t quick_widgets[] = { 212 int i = 1, norm_i = 0, add_i = 0; 213 quick_widget_t quick_widgets[15] = { 213 214 /* *INDENT-OFF* */ 214 215 QUICK_LABELED_INPUT (p_text, input_label_above, def_text, histname, &my_str, 215 NULL, is_passwd, strip_password, completion_flags), 216 QUICK_BUTTONS_OK_CANCEL, 217 QUICK_END 216 NULL, is_passwd, strip_password, completion_flags) 218 217 /* *INDENT-ON* */ 219 218 }; 220 219 quick_widget_t press_end[] = { QUICK_BUTTONS_OK_CANCEL, QUICK_END }; 221 220 quick_dialog_t qdlg = { 222 221 -1, -1, COLS / 2, header, 223 222 help, quick_widgets, NULL, NULL 224 223 }; 225 224 225 /* Handling of additional widgets optionally passed via last argument `add_w` */ 226 227 /* Copy/append any extra widgets (max 10) */ 228 while (add_w != NULL && add_w[add_i].widget_type != quick_end && i < 15) 229 quick_widgets[i++] = add_w[add_i++]; 230 231 /* Copy normal buttons */ 232 while (norm_i < sizeof (press_end) / sizeof (quick_widget_t) && i < 15) 233 quick_widgets[i++] = press_end[norm_i++]; 234 226 235 ret = quick_dialog (&qdlg); 227 236 } 228 237 … … input_dialog_help (const char *header, const char *text, const char *help, 479 488 { 480 489 void *p; 481 490 char *(*f) (const char *, const char *, const char *, const char *, const char *, 482 gboolean, input_complete_t );491 gboolean, input_complete_t, quick_widget_t * add_w); 483 492 } func; 484 493 func.f = fg_input_dialog_help; 485 return wtools_parent_call_string (func.p, 7,494 return wtools_parent_call_string (func.p, 8, 486 495 strlen (header), header, strlen (text), 487 496 text, strlen (help), help, 488 497 strlen (history_name), history_name, 489 498 strlen (def_text), def_text, 490 499 sizeof (gboolean), strip_password, 491 sizeof (input_complete_t), completion_flags); 500 sizeof (input_complete_t), completion_flags, 501 sizeof (quick_widget_t *), NULL); 492 502 } 493 503 else 494 504 #endif /* ENABLE_BACKGROUND */ 495 505 return fg_input_dialog_help (header, text, help, history_name, def_text, strip_password, 496 completion_flags );506 completion_flags, NULL); 497 507 } 498 508 499 509 /* --------------------------------------------------------------------------------------------- */ … … input_dialog (const char *header, const char *text, const char *history_name, co 509 519 510 520 /* --------------------------------------------------------------------------------------------- */ 511 521 522 char * 523 input_dialog_ext (const char *header, const char *text, const char *history_name, 524 const char *def_text, input_complete_t completion_flags, quick_widget_t * add_w) 525 { 526 return fg_input_dialog_help (header, text, "[Input Line Keys]", history_name, def_text, FALSE, 527 completion_flags, add_w); 528 } 529 530 /* --------------------------------------------------------------------------------------------- */ 531 512 532 char * 513 533 input_expand_dialog (const char *header, const char *text, 514 534 const char *history_name, const char *def_text, -
lib/widget/wtools.h
diff --git a/lib/widget/wtools.h b/lib/widget/wtools.h index cd0bc3253..d5a39971b 100644
a b struct simple_status_msg_t 65 65 char *input_dialog (const char *header, const char *text, 66 66 const char *history_name, const char *def_text, 67 67 input_complete_t completion_flags); 68 /* The input dialogs */ 69 char *input_dialog_ext (const char *header, const char *text, 70 const char *history_name, const char *def_text, 71 input_complete_t completion_flags, quick_widget_t * add_w); 68 72 char *input_dialog_help (const char *header, const char *text, const char *help, 69 73 const char *history_name, const char *def_text, gboolean strip_password, 70 74 input_complete_t completion_flags); -
misc/mc.default.keymap
diff --git a/misc/mc.default.keymap b/misc/mc.default.keymap index 2931ddd0a..af2ddc59d 100644
a b Sort = alt-t 350 350 Mail = alt-m 351 351 ParagraphFormat = alt-p 352 352 MatchBracket = alt-b 353 InstructionStation = alt-i 353 354 ExternalCommand = alt-u 354 355 UserMenu = f11 355 356 Menu = f9 -
misc/mc.emacs.keymap
diff --git a/misc/mc.emacs.keymap b/misc/mc.emacs.keymap index 7cc305db7..e0e1a9173 100644
a b Sort = alt-t 349 349 # Mail = 350 350 ParagraphFormat = alt-p 351 351 # MatchBracket = 352 InstructionStation = alt-i 352 353 ExternalCommand = alt-u 353 354 UserMenu = f11 354 355 Menu = f9 -
src/editor/Makefile.am
diff --git a/src/editor/Makefile.am b/src/editor/Makefile.am index 235ed76af..0ac4b4af7 100644
a b libedit_la_SOURCES = \ 18 18 editmenu.c \ 19 19 editoptions.c \ 20 20 editwidget.c editwidget.h \ 21 instr_station.c instr_station.h \ 21 22 etags.c etags.h \ 22 23 format.c \ 23 24 syntax.c -
src/editor/edit-impl.h
diff --git a/src/editor/edit-impl.h b/src/editor/edit-impl.h index 3ad04dbea..8f8dce2f1 100644
a b typedef enum 87 87 LB_MAC 88 88 } LineBreaks; 89 89 90 typedef enum 91 { 92 EDIT_DO_INIT_BASE_CLASS = 1 << 0, 93 94 } edit_init_flags_t; 95 96 typedef enum instr_stn_flags 97 { 98 INSTR_STN_NO_FLAGS = 0, 99 INSTR_STN_NO_STDIN = 1 << 17, 100 INSTR_STN_NO_PROMPT = 1 << 18 101 } instr_stn_flags_t; 102 90 103 typedef enum 91 104 { 92 105 EDIT_QUICK_SAVE = 0, … … extern char *edit_window_state_char; 135 148 extern char *edit_window_close_char; 136 149 137 150 /*** declarations of public functions ************************************************************/ 151 cb_ret_t edit_dialog_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data); 152 cb_ret_t edit_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data); 153 cb_ret_t edit_dialog_command_execute (WDialog * h, long command, void *data); 154 155 void edit_mouse_callback (Widget * w, mouse_msg_t msg, mouse_event_t * event); 138 156 139 157 gboolean edit_add_window (WDialog * h, int y, int x, int lines, int cols, 140 158 const vfs_path_t * f, long fline); … … void edit_move_to_prev_col (WEdit * edit, off_t p); 158 176 long edit_get_col (const WEdit * edit); 159 177 void edit_update_curs_row (WEdit * edit); 160 178 void edit_update_curs_col (WEdit * edit); 179 gboolean edit_newline_end_check_only (const WEdit * edit); 161 180 void edit_find_bracket (WEdit * edit); 162 181 gboolean edit_reload_line (WEdit * edit, const vfs_path_t * filename_vpath, long line); 163 182 void edit_set_codeset (WEdit * edit); … … void edit_delete_line (WEdit * edit); 169 188 170 189 int edit_delete (WEdit * edit, gboolean byte_delete); 171 190 int edit_backspace (WEdit * edit, gboolean byte_delete); 191 void edit_insert_string (WEdit * edit, char *str_text, gsize len); 172 192 void edit_insert (WEdit * edit, int c); 173 193 void edit_insert_over (WEdit * edit); 174 194 void edit_cursor_move (WEdit * edit, off_t increment); … … char *edit_get_write_filter (const vfs_path_t * write_name_vpath, 182 202 gboolean edit_save_confirm_cmd (WEdit * edit); 183 203 gboolean edit_save_as_cmd (WEdit * edit); 184 204 WEdit *edit_init (WEdit * edit, int y, int x, int lines, int cols, 185 const vfs_path_t * filename_vpath, long line );205 const vfs_path_t * filename_vpath, long line, edit_init_flags_t flags); 186 206 gboolean edit_clean (WEdit * edit); 187 207 gboolean edit_ok_to_exit (WEdit * edit); 188 208 gboolean edit_load_cmd (WDialog * h); … … void edit_move_to_line (WEdit * e, long line); 236 256 void edit_move_display (WEdit * e, long line); 237 257 void edit_word_wrap (WEdit * edit); 238 258 int edit_sort_cmd (WEdit * edit); 259 gboolean edit_add_instr_stn_window (WDialog * h, instr_stn_flags_t flags, void *data); 260 239 261 int edit_ext_cmd (WEdit * edit); 240 262 241 263 int edit_store_macro_cmd (WEdit * edit); -
src/editor/edit.c
diff --git a/src/editor/edit.c b/src/editor/edit.c index edda1f832..56653700b 100644
a b edit_modification (WEdit * edit) 621 621 { 622 622 edit->caches_valid = FALSE; 623 623 624 /* raise lock when file modified */625 if ( !edit->modified && !edit->delete_file)624 /* raise lock when file is about to be modified */ 625 if (edit->filename_vpath && !edit->modified && !edit->delete_file) 626 626 edit->locked = lock_file (edit->filename_vpath); 627 627 edit->modified = 1; 628 628 } … … edit_insert_file (WEdit * edit, const vfs_path_t * filename_vpath) 2075 2075 2076 2076 WEdit * 2077 2077 edit_init (WEdit * edit, int y, int x, int lines, int cols, const vfs_path_t * filename_vpath, 2078 long line )2078 long line, edit_init_flags_t flags) 2079 2079 { 2080 2080 gboolean to_free = FALSE; 2081 2081 … … edit_init (WEdit * edit, int y, int x, int lines, int cols, const vfs_path_t * f 2097 2097 edit->fullscreen = fullscreen; 2098 2098 edit->loc_prev = loc_prev; 2099 2099 } 2100 else2100 if (has_flag (flags, EDIT_DO_INIT_BASE_CLASS) || edit == NULL) 2101 2101 { 2102 2102 Widget *w; 2103 edit = g_malloc0 (sizeof (WEdit)); 2104 to_free = TRUE; 2103 if (edit == NULL) 2104 { 2105 edit = g_malloc0 (sizeof (WEdit)); 2106 to_free = TRUE; 2107 } 2105 2108 2106 2109 w = WIDGET (edit); 2107 2110 widget_init (w, y, x, lines, cols, NULL, NULL); … … edit_reload_line (WEdit * edit, const vfs_path_t * filename_vpath, long line) 2238 2241 e->fullscreen = edit->fullscreen; 2239 2242 e->loc_prev = edit->loc_prev; 2240 2243 2241 if (edit_init (e, w->y, w->x, w->lines, w->cols, filename_vpath, line ) == NULL)2244 if (edit_init (e, w->y, w->x, w->lines, w->cols, filename_vpath, line, 0) == NULL) 2242 2245 { 2243 2246 g_free (e); 2244 2247 return FALSE; … … edit_push_redo_action (WEdit * edit, long c) 2495 2498 edit->redo_stack_bottom = edit->redo_stack_pointer = 0; 2496 2499 } 2497 2500 2501 /* --------------------------------------------------------------------------------------------- */ 2502 2503 void 2504 edit_insert_string (WEdit * edit, char *str_text, gsize len) 2505 { 2506 size_t i; 2507 for (i = 0; i < len; i++) 2508 edit_insert (edit, str_text[i]); 2509 } 2510 2498 2511 /* --------------------------------------------------------------------------------------------- */ 2499 2512 /** 2500 2513 Basic low level single character buffer alterations and movements at the cursor. -
src/editor/editcmd.c
diff --git a/src/editor/editcmd.c b/src/editor/editcmd.c index 0d2caa923..080bfad24 100644
a b edit_complete_word_insert_recoded_completion (WEdit * edit, char *completion, gs 1529 1529 /*** public functions ****************************************************************************/ 1530 1530 /* --------------------------------------------------------------------------------------------- */ 1531 1531 1532 gboolean 1533 edit_newline_end_check_only (const WEdit * e) 1534 { 1535 const edit_buffer_t *buf = &e->buffer; 1536 return (buf->size > 0 && edit_buffer_get_byte (buf, buf->size - 1) == '\n'); 1537 } 1538 1539 /* --------------------------------------------------------------------------------------------- */ 1540 1532 1541 void 1533 1542 edit_refresh_cmd (void) 1534 1543 { … … edit_close_cmd (WEdit * edit) 2251 2260 group_remove_widget (w); 2252 2261 widget_destroy (w); 2253 2262 2254 if (edit_widget_is_editor (CONST_WIDGET (g->current->data))) 2263 if (edit_widget_is_editor (CONST_WIDGET (g->current->data)) 2264 || edit_widget_is_cli (CONST_WIDGET (g->current->data))) 2255 2265 edit = (WEdit *) (g->current->data); 2256 2266 else 2257 2267 { 2268 /* Look for a file window or a CLI window */ 2258 2269 edit = find_editor (DIALOG (g)); 2270 if (!edit) 2271 edit = find_cli (DIALOG (g)); 2259 2272 if (edit != NULL) 2260 2273 widget_select (w); 2261 2274 } … … edit_ext_cmd (WEdit * edit) 3225 3238 { 3226 3239 char *exp, *tmp, *tmp_edit_temp_file; 3227 3240 int e; 3241 gboolean run_in_cli = FALSE; 3242 3243 quick_widget_t chbox[3] = { QUICK_SEPARATOR (TRUE), 3244 QUICK_CHECKBOX ("&Open in CLI window", &run_in_cli, NULL), 3245 QUICK_END 3246 }; 3228 3247 3229 3248 exp = 3230 input_dialog (_("Paste output of external command"), 3231 _("Enter shell command(s):"), MC_HISTORY_EDIT_PASTE_EXTCMD, INPUT_LAST_TEXT, 3232 INPUT_COMPLETE_FILENAMES | INPUT_COMPLETE_VARIABLES | INPUT_COMPLETE_USERNAMES 3233 | INPUT_COMPLETE_HOSTNAMES | INPUT_COMPLETE_CD | INPUT_COMPLETE_COMMANDS | 3234 INPUT_COMPLETE_SHELL_ESC); 3249 input_dialog_ext (_("Paste output of external command"), 3250 _("Enter shell command(s):"), MC_HISTORY_EDIT_PASTE_EXTCMD, 3251 INPUT_LAST_TEXT, 3252 INPUT_COMPLETE_FILENAMES | INPUT_COMPLETE_VARIABLES | 3253 INPUT_COMPLETE_USERNAMES | INPUT_COMPLETE_HOSTNAMES | INPUT_COMPLETE_CD | 3254 INPUT_COMPLETE_COMMANDS | INPUT_COMPLETE_SHELL_ESC, chbox); 3235 3255 3236 3256 if (!exp) 3237 3257 return 1; 3238 3258 3259 /* Should start a CLI window with the command ? */ 3260 if (run_in_cli) 3261 { 3262 edit_add_instr_stn_window (DIALOG (WIDGET (edit)->owner), 3263 INSTR_STN_NO_STDIN | INSTR_STN_NO_PROMPT, exp); 3264 g_free (exp); 3265 return 0; 3266 } 3267 3239 3268 tmp_edit_temp_file = mc_config_get_full_path (EDIT_HOME_TEMP_FILE); 3240 3269 tmp = g_strconcat (exp, " > ", tmp_edit_temp_file, (char *) NULL); 3241 3270 g_free (tmp_edit_temp_file); -
src/editor/editdraw.c
diff --git a/src/editor/editdraw.c b/src/editor/editdraw.c index 248128b68..d2fddc13d 100644
a b edit_draw_this_line (WEdit * edit, off_t b, long row, long start_col, long end_c 820 820 } 821 821 822 822 p->ch = 0; 823 824 823 print_to_widget (edit, row, start_col, start_col_real, end_col, line, line_stat, book_mark); 825 824 } 826 825 -
src/editor/editmenu.c
diff --git a/src/editor/editmenu.c b/src/editor/editmenu.c index 489893849..02bf43aa3 100644
a b create_window_menu (void) 236 236 entries = g_list_prepend (entries, menu_entry_create (_("&Next"), CK_WindowNext)); 237 237 entries = g_list_prepend (entries, menu_entry_create (_("&Previous"), CK_WindowPrev)); 238 238 entries = g_list_prepend (entries, menu_entry_create (_("&List..."), CK_WindowList)); 239 entries = 240 g_list_prepend (entries, 241 menu_entry_create (_("Instr&uction Station"), CK_InstructionStation)); 239 242 240 243 return g_list_reverse (entries); 241 244 } -
src/editor/editwidget.c
diff --git a/src/editor/editwidget.c b/src/editor/editwidget.c index 18ac00e66..2e49fe3ed 100644
a b 67 67 #ifdef HAVE_ASPELL 68 68 #include "spell.h" 69 69 #endif 70 #include "src/editor/instr_station.h" 70 71 71 72 /*** global variables ****************************************************************************/ 72 73 … … static unsigned int edit_dlg_init_refcounter = 0; 85 86 86 87 /*** file scope functions ************************************************************************/ 87 88 88 static cb_ret_t edit_dialog_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm,89 void *data);90 91 89 /* --------------------------------------------------------------------------------------------- */ 92 90 /** 93 91 * Init the 'edit' subsystem … … edit_get_title (const WDialog * h, size_t len) 376 374 return g_strconcat (_("Edit: "), modified, file_label, (char *) NULL); 377 375 } 378 376 379 /* --------------------------------------------------------------------------------------------- */380 381 static cb_ret_t382 edit_dialog_command_execute (WDialog * h, long command)383 {384 WGroup *g = GROUP (h);385 Widget *wh = WIDGET (h);386 cb_ret_t ret = MSG_HANDLED;387 388 switch (command)389 {390 case CK_EditNew:391 edit_add_window (h, wh->y + 1, wh->x, wh->lines - 2, wh->cols, NULL, 0);392 break;393 case CK_EditFile:394 edit_load_cmd (h);395 break;396 case CK_History:397 edit_load_file_from_history (h);398 break;399 case CK_EditSyntaxFile:400 edit_load_syntax_file (h);401 break;402 case CK_EditUserMenu:403 edit_load_menu_file (h);404 break;405 case CK_Close:406 /* if there are no opened files anymore, close MC editor */407 if (edit_widget_is_editor (CONST_WIDGET (g->current->data)) &&408 edit_close_cmd ((WEdit *) g->current->data) && find_editor (h) == NULL)409 dlg_stop (h);410 break;411 case CK_Help:412 edit_help ();413 /* edit->force |= REDRAW_COMPLETELY; */414 break;415 case CK_Menu:416 edit_menu_cmd (h);417 break;418 case CK_Quit:419 case CK_Cancel:420 /* don't close editor due to SIGINT, but stop move/resize window */421 {422 Widget *w = WIDGET (g->current->data);423 424 if (edit_widget_is_editor (w) && ((WEdit *) w)->drag_state != MCEDIT_DRAG_NONE)425 edit_restore_size ((WEdit *) w);426 else if (command == CK_Quit)427 dlg_stop (h);428 }429 break;430 case CK_About:431 edit_about ();432 break;433 case CK_SyntaxOnOff:434 edit_syntax_onoff_cmd (h);435 break;436 case CK_ShowTabTws:437 edit_show_tabs_tws_cmd (h);438 break;439 case CK_ShowMargin:440 edit_show_margin_cmd (h);441 break;442 case CK_ShowNumbers:443 edit_show_numbers_cmd (h);444 break;445 case CK_Refresh:446 edit_refresh_cmd ();447 break;448 case CK_Shell:449 toggle_subshell ();450 break;451 case CK_LearnKeys:452 learn_keys ();453 break;454 case CK_WindowMove:455 case CK_WindowResize:456 if (edit_widget_is_editor (CONST_WIDGET (g->current->data)))457 edit_handle_move_resize ((WEdit *) g->current->data, command);458 break;459 case CK_WindowList:460 edit_window_list (h);461 break;462 case CK_WindowNext:463 group_select_next_widget (g);464 break;465 case CK_WindowPrev:466 group_select_prev_widget (g);467 break;468 case CK_Options:469 edit_options_dialog (h);470 break;471 case CK_OptionsSaveMode:472 edit_save_mode_cmd ();473 break;474 case CK_SaveSetup:475 save_setup_cmd ();476 break;477 default:478 ret = MSG_NOT_HANDLED;479 break;480 }481 482 return ret;483 }484 485 377 /* --------------------------------------------------------------------------------------------- */ 486 378 /* 487 379 * Translate the keycode into either 'command' or 'char_for_insertion'. … … edit_update_cursor (WEdit * edit, const mouse_event_t * event) 739 631 return done; 740 632 } 741 633 742 /* --------------------------------------------------------------------------------------------- */743 /** Callback for the edit dialog */744 745 static cb_ret_t746 edit_dialog_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)747 {748 WGroup *g = GROUP (w);749 WDialog *h = DIALOG (w);750 751 switch (msg)752 {753 case MSG_INIT:754 edit_dlg_init ();755 return MSG_HANDLED;756 757 case MSG_RESIZE:758 dlg_default_callback (w, NULL, MSG_RESIZE, 0, NULL);759 menubar_arrange (find_menubar (h));760 return MSG_HANDLED;761 762 case MSG_ACTION:763 {764 /* Handle shortcuts, menu, and buttonbar. */765 766 cb_ret_t result;767 768 result = edit_dialog_command_execute (h, parm);769 770 /* We forward any commands coming from the menu, and which haven't been771 handled by the dialog, to the focused WEdit window. */772 if (result == MSG_NOT_HANDLED && sender == WIDGET (find_menubar (h)))773 result = send_message (g->current->data, NULL, MSG_ACTION, parm, NULL);774 775 return result;776 }777 778 case MSG_KEY:779 {780 Widget *we = WIDGET (g->current->data);781 cb_ret_t ret = MSG_NOT_HANDLED;782 783 if (edit_widget_is_editor (we))784 {785 gboolean ext_mode;786 long command;787 788 /* keep and then extmod flag */789 ext_mode = we->ext_mode;790 command = widget_lookup_key (we, parm);791 we->ext_mode = ext_mode;792 793 if (command == CK_IgnoreKey)794 we->ext_mode = FALSE;795 else796 {797 ret = edit_dialog_command_execute (h, command);798 /* if command was not handled, keep the extended mode799 for the further key processing */800 if (ret == MSG_HANDLED)801 we->ext_mode = FALSE;802 }803 }804 805 /*806 * Due to the "end of bracket" escape the editor sees input with is_idle() == false807 * (expects more characters) and hence doesn't yet refresh the screen, but then808 * no further characters arrive (there's only an "end of bracket" which is swallowed809 * by tty_get_event()), so you end up with a screen that's not refreshed after pasting.810 * So let's trigger an IDLE signal.811 */812 if (!is_idle ())813 widget_idle (w, TRUE);814 return ret;815 }816 817 /* hardcoded menu hotkeys (see edit_drop_hotkey_menu) */818 case MSG_UNHANDLED_KEY:819 return edit_drop_hotkey_menu (h, parm) ? MSG_HANDLED : MSG_NOT_HANDLED;820 821 case MSG_VALIDATE:822 edit_quit (h);823 return MSG_HANDLED;824 825 case MSG_END:826 edit_dlg_deinit ();827 return MSG_HANDLED;828 829 case MSG_IDLE:830 widget_idle (w, FALSE);831 return send_message (g->current->data, NULL, MSG_IDLE, 0, NULL);832 833 default:834 return dlg_default_callback (w, sender, msg, parm, data);835 }836 }837 838 634 /* --------------------------------------------------------------------------------------------- */ 839 635 840 636 /** … … edit_dialog_bg_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm 929 725 930 726 /* --------------------------------------------------------------------------------------------- */ 931 727 932 static cb_ret_t 728 /** 729 * Handle move/resize mouse events. 730 */ 731 static void 732 edit_mouse_handle_move_resize (Widget * w, mouse_msg_t msg, mouse_event_t * event) 733 { 734 WEdit *edit = (WEdit *) (w); 735 Widget *h = WIDGET (w->owner); 736 int global_x, global_y; 737 738 if (msg == MSG_MOUSE_UP) 739 { 740 /* Exit move/resize mode. */ 741 edit_execute_cmd (edit, CK_Enter, -1); 742 edit_update_screen (edit); /* Paint the buttonbar over our possibly overlapping frame. */ 743 return; 744 } 745 746 if (msg != MSG_MOUSE_DRAG) 747 /** 748 * We ignore any other events. Specifically, MSG_MOUSE_DOWN. 749 * 750 * When the move/resize is initiated by the menu, we let the user 751 * stop it by clicking with the mouse. Which is why we don't want 752 * a mouse down to affect the window. 753 */ 754 return; 755 756 /* Convert point to global coordinates for easier calculations. */ 757 global_x = event->x + w->x; 758 global_y = event->y + w->y; 759 760 /* Clamp the point to the dialog's client area. */ 761 global_y = CLAMP (global_y, h->y + 1, h->y + h->lines - 2); /* Status line, buttonbar */ 762 global_x = CLAMP (global_x, h->x, h->x + h->cols - 1); /* Currently a no-op, as the dialog has no left/right margins. */ 763 764 if (edit->drag_state == MCEDIT_DRAG_MOVE) 765 { 766 w->y = global_y; 767 w->x = global_x - edit->drag_state_start; 768 } 769 else if (edit->drag_state == MCEDIT_DRAG_RESIZE) 770 { 771 w->lines = MAX (WINDOW_MIN_LINES, global_y - w->y + 1); 772 w->cols = MAX (WINDOW_MIN_COLS, global_x - w->x + 1); 773 } 774 775 edit->force |= REDRAW_COMPLETELY; /* Not really needed as WEdit's MSG_DRAW already does this. */ 776 777 /* We draw the whole dialog because dragging/resizing exposes area beneath. */ 778 widget_draw (WIDGET (w->owner)); 779 } 780 781 /* --------------------------------------------------------------------------------------------- */ 782 /*** public functions ****************************************************************************/ 783 /* --------------------------------------------------------------------------------------------- */ 784 785 cb_ret_t 786 edit_dialog_command_execute (WDialog * h, long command, void *data) 787 { 788 WGroup *g = GROUP (h); 789 Widget *wh = WIDGET (h); 790 cb_ret_t ret = MSG_HANDLED; 791 792 switch (command) 793 { 794 case CK_EditNew: 795 edit_add_window (h, wh->y + 1, wh->x, wh->lines - 2, wh->cols, NULL, 0); 796 break; 797 case CK_EditFile: 798 edit_load_cmd (h); 799 break; 800 case CK_History: 801 edit_load_file_from_history (h); 802 break; 803 case CK_EditSyntaxFile: 804 edit_load_syntax_file (h); 805 break; 806 case CK_EditUserMenu: 807 edit_load_menu_file (h); 808 break; 809 case CK_Close: 810 /* if there are no opened files anymore, close MC editor */ 811 if ((edit_widget_is_editor (CONST_WIDGET (g->current->data)) || 812 edit_widget_is_cli (CONST_WIDGET (g->current->data))) && 813 edit_close_cmd ((WEdit *) g->current->data) && find_editor (h) == NULL) 814 dlg_stop (h); 815 break; 816 case CK_Help: 817 edit_help (); 818 /* edit->force |= REDRAW_COMPLETELY; */ 819 break; 820 case CK_Menu: 821 edit_menu_cmd (h); 822 break; 823 case CK_Quit: 824 case CK_Cancel: 825 /* don't close editor due to SIGINT, but stop move/resize window */ 826 { 827 Widget *w = WIDGET (g->current->data); 828 829 if (edit_widget_is_editor (w) && ((WEdit *) w)->drag_state != MCEDIT_DRAG_NONE) 830 edit_restore_size ((WEdit *) w); 831 else if (command == CK_Quit) 832 dlg_stop (h); 833 } 834 break; 835 case CK_About: 836 edit_about (); 837 break; 838 case CK_SyntaxOnOff: 839 edit_syntax_onoff_cmd (h); 840 break; 841 case CK_ShowTabTws: 842 edit_show_tabs_tws_cmd (h); 843 break; 844 case CK_ShowMargin: 845 edit_show_margin_cmd (h); 846 break; 847 case CK_ShowNumbers: 848 edit_show_numbers_cmd (h); 849 break; 850 case CK_Refresh: 851 edit_refresh_cmd (); 852 break; 853 case CK_InstructionStation: 854 edit_add_instr_stn_window (h, INSTR_STN_NO_FLAGS, data); 855 break; 856 case CK_Shell: 857 toggle_subshell (); 858 break; 859 case CK_LearnKeys: 860 learn_keys (); 861 break; 862 case CK_WindowMove: 863 case CK_WindowResize: 864 if (edit_widget_is_editor (CONST_WIDGET (g->current->data))) 865 edit_handle_move_resize ((WEdit *) g->current->data, command); 866 break; 867 case CK_WindowList: 868 edit_window_list (h); 869 break; 870 case CK_WindowNext: 871 group_select_next_widget (g); 872 break; 873 case CK_WindowPrev: 874 group_select_prev_widget (g); 875 break; 876 case CK_Options: 877 edit_options_dialog (h); 878 break; 879 case CK_OptionsSaveMode: 880 edit_save_mode_cmd (); 881 break; 882 case CK_SaveSetup: 883 save_setup_cmd (); 884 break; 885 default: 886 ret = MSG_NOT_HANDLED; 887 break; 888 } 889 890 return ret; 891 } 892 893 /* --------------------------------------------------------------------------------------------- */ 894 /** Callback for the edit dialog */ 895 896 cb_ret_t 897 edit_dialog_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data) 898 { 899 WGroup *g = GROUP (w); 900 WDialog *h = DIALOG (w); 901 902 switch (msg) 903 { 904 case MSG_INIT: 905 edit_dlg_init (); 906 return MSG_HANDLED; 907 908 case MSG_RESIZE: 909 dlg_default_callback (w, NULL, MSG_RESIZE, 0, NULL); 910 menubar_arrange (find_menubar (h)); 911 return MSG_HANDLED; 912 913 case MSG_ACTION: 914 { 915 /* Handle shortcuts, menu, and buttonbar. */ 916 917 cb_ret_t result; 918 919 result = edit_dialog_command_execute (h, parm, data); 920 921 /* We forward any commands coming from the menu, and which haven't been 922 handled by the dialog, to the focused WEdit window. */ 923 if (result == MSG_NOT_HANDLED && sender == WIDGET (find_menubar (h))) 924 result = send_message (g->current->data, NULL, MSG_ACTION, parm, NULL); 925 926 return result; 927 } 928 929 case MSG_KEY: 930 { 931 Widget *we = WIDGET (g->current->data); 932 cb_ret_t ret = MSG_NOT_HANDLED; 933 934 if (edit_widget_is_editor (we)) 935 { 936 gboolean ext_mode; 937 long command; 938 939 /* keep and then extmod flag */ 940 ext_mode = we->ext_mode; 941 command = widget_lookup_key (we, parm); 942 we->ext_mode = ext_mode; 943 944 if (command == CK_IgnoreKey) 945 we->ext_mode = FALSE; 946 else 947 { 948 ret = edit_dialog_command_execute (h, command, data); 949 /* if command was not handled, keep the extended mode 950 for the further key processing */ 951 if (ret == MSG_HANDLED) 952 we->ext_mode = FALSE; 953 } 954 } 955 956 /* 957 * Due to the "end of bracket" escape the editor sees input with is_idle() == false 958 * (expects more characters) and hence doesn't yet refresh the screen, but then 959 * no further characters arrive (there's only an "end of bracket" which is swallowed 960 * by tty_get_event()), so you end up with a screen that's not refreshed after pasting. 961 * So let's trigger an IDLE signal. 962 */ 963 if (!is_idle ()) 964 widget_idle (w, TRUE); 965 return ret; 966 } 967 968 /* hardcoded menu hotkeys (see edit_drop_hotkey_menu) */ 969 case MSG_UNHANDLED_KEY: 970 return edit_drop_hotkey_menu (h, parm) ? MSG_HANDLED : MSG_NOT_HANDLED; 971 972 case MSG_VALIDATE: 973 edit_quit (h); 974 return MSG_HANDLED; 975 976 case MSG_END: 977 edit_dlg_deinit (); 978 return MSG_HANDLED; 979 980 case MSG_IDLE: 981 widget_idle (w, FALSE); 982 return send_message (g->current->data, NULL, MSG_IDLE, 0, NULL); 983 984 default: 985 return dlg_default_callback (w, sender, msg, parm, data); 986 } 987 } 988 989 /* --------------------------------------------------------------------------------------------- */ 990 991 cb_ret_t 933 992 edit_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data) 934 993 { 935 994 WEdit *e = (WEdit *) w; … … edit_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *da 999 1058 1000 1059 /* --------------------------------------------------------------------------------------------- */ 1001 1060 1002 /**1003 * Handle move/resize mouse events.1004 */1005 static void1006 edit_mouse_handle_move_resize (Widget * w, mouse_msg_t msg, mouse_event_t * event)1007 {1008 WEdit *edit = (WEdit *) (w);1009 Widget *h = WIDGET (w->owner);1010 int global_x, global_y;1011 1012 if (msg == MSG_MOUSE_UP)1013 {1014 /* Exit move/resize mode. */1015 edit_execute_cmd (edit, CK_Enter, -1);1016 edit_update_screen (edit); /* Paint the buttonbar over our possibly overlapping frame. */1017 return;1018 }1019 1020 if (msg != MSG_MOUSE_DRAG)1021 /**1022 * We ignore any other events. Specifically, MSG_MOUSE_DOWN.1023 *1024 * When the move/resize is initiated by the menu, we let the user1025 * stop it by clicking with the mouse. Which is why we don't want1026 * a mouse down to affect the window.1027 */1028 return;1029 1030 /* Convert point to global coordinates for easier calculations. */1031 global_x = event->x + w->x;1032 global_y = event->y + w->y;1033 1034 /* Clamp the point to the dialog's client area. */1035 global_y = CLAMP (global_y, h->y + 1, h->y + h->lines - 2); /* Status line, buttonbar */1036 global_x = CLAMP (global_x, h->x, h->x + h->cols - 1); /* Currently a no-op, as the dialog has no left/right margins. */1037 1038 if (edit->drag_state == MCEDIT_DRAG_MOVE)1039 {1040 w->y = global_y;1041 w->x = global_x - edit->drag_state_start;1042 }1043 else if (edit->drag_state == MCEDIT_DRAG_RESIZE)1044 {1045 w->lines = MAX (WINDOW_MIN_LINES, global_y - w->y + 1);1046 w->cols = MAX (WINDOW_MIN_COLS, global_x - w->x + 1);1047 }1048 1049 edit->force |= REDRAW_COMPLETELY; /* Not really needed as WEdit's MSG_DRAW already does this. */1050 1051 /* We draw the whole dialog because dragging/resizing exposes area beneath. */1052 widget_draw (WIDGET (w->owner));1053 }1054 1055 /* --------------------------------------------------------------------------------------------- */1056 1057 1061 /** 1058 1062 * Handle mouse events of editor window 1059 1063 * … … edit_mouse_handle_move_resize (Widget * w, mouse_msg_t msg, mouse_event_t * even 1061 1065 * @param msg mouse event message 1062 1066 * @param event mouse event data 1063 1067 */ 1064 staticvoid1068 void 1065 1069 edit_mouse_callback (Widget * w, mouse_msg_t msg, mouse_event_t * event) 1066 1070 { 1067 1071 WEdit *edit = (WEdit *) w; … … edit_mouse_callback (Widget * w, mouse_msg_t msg, mouse_event_t * event) 1176 1180 } 1177 1181 1178 1182 /* --------------------------------------------------------------------------------------------- */ 1179 /*** public functions ****************************************************************************/ 1183 /* Creates a CLI special window, windowed (not fullscreen) */ 1184 1185 gboolean 1186 edit_add_instr_stn_window (WDialog * h, instr_stn_flags_t flags, void *data) 1187 { 1188 WInstructionStation *ip; 1189 1190 /* Note passing of data - ability to alter program that's run in this station */ 1191 ip = instr_stn_create (3, 10, 17, 80, flags, (const char *) data); 1192 1193 if (ip == NULL) 1194 return FALSE; 1195 1196 /* Add CLI-extended editor window (extending WEdit) to front dialog */ 1197 group_add_widget_autopos (GROUP (h), ip, WPOS_KEEP_ALL, NULL); 1198 widget_draw (WIDGET (h)); 1199 return TRUE; 1200 } 1201 1180 1202 /* --------------------------------------------------------------------------------------------- */ 1181 1203 /** 1182 1204 * Edit one file. … … edit_add_window (WDialog * h, int y, int x, int lines, int cols, const vfs_path_ 1369 1391 WEdit *edit; 1370 1392 Widget *w; 1371 1393 1372 edit = edit_init (NULL, y, x, lines, cols, f, fline );1394 edit = edit_init (NULL, y, x, lines, cols, f, fline, 0); 1373 1395 if (edit == NULL) 1374 1396 return FALSE; 1375 1397 -
src/editor/editwidget.h
diff --git a/src/editor/editwidget.h b/src/editor/editwidget.h index 446ef07ac..e8d1586e2 100644
a b 13 13 14 14 /*** typedefs(not structures) and defined constants **********************************************/ 15 15 16 #define EDIT(x) ((WEdit *)(x)) 17 #define CONST_EDIT(x) ((const WEdit *)(x)) 18 16 19 #define N_LINE_CACHES 32 17 20 18 21 /*** enums ***************************************************************************************/ -
new file src/editor/instr_station.c
diff --git a/src/editor/instr_station.c b/src/editor/instr_station.c new file mode 100644 index 000000000..e4bb6ad65
- + 1 /* 2 Implementation of a CLI window for MCEdit. 3 4 Copyright (C) 2021 5 Free Software Foundation, Inc. 6 7 Written by: 8 Sebastian Gniazdowski <sgniazdowski@gmail.com>, 2021. 9 10 This file is part of the Midnight Commander. 11 12 The Midnight Commander is free software: you can redistribute it 13 and/or modify it under the terms of the GNU General Public License as 14 published by the Free Software Foundation, either version 3 of the License, 15 or (at your option) any later version. 16 17 The Midnight Commander is distributed in the hope that it will be useful, 18 but WITHOUT ANY WARRANTY; without even the implied warranty of 19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 GNU General Public License for more details. 21 22 You should have received a copy of the GNU General Public License 23 along with this program. If not, see <http://www.gnu.org/licenses/>. 24 */ 25 26 /** \file instr_station.c 27 * \brief Implementation of a CLI special window for MCEdit. 28 * \author Sebastian Gniazdowski 29 * \date 2021 30 * 31 * Such window runs a set up program (/bin/bash by default) allowing to 32 * provide an input to it and read its output. 33 */ 34 35 #include <config.h> 36 37 #include "lib/global.h" 38 39 #include <sys/types.h> 40 #include <sys/wait.h> 41 42 #include "src/editor/editwidget.h" 43 44 #include "lib/util.h" 45 #include "lib/tty/key.h" 46 #include "lib/widget.h" 47 #include "src/editor/instr_station.h" 48 49 /*** global variables ****************************************************************************/ 50 51 /*** file scope macro definitions ****************************************************************/ 52 53 /*** file scope type declarations ****************************************************************/ 54 55 typedef enum instr_stn_io_type 56 { 57 STDIN = 0, 58 STDOUT, 59 STDERR 60 } instr_stn_io_type_t; 61 62 /*** file scope variables ************************************************************************/ 63 64 static gboolean alt_prog_first_run = TRUE; 65 66 /*** file scope functions ************************************************************************/ 67 /* --------------------------------------------------------------------------------------------- */ 68 69 static char * 70 instr_stn_get_instruction_text (WInstructionStation * ip) 71 { 72 char *ret_str; 73 GString *instr; 74 off_t bol, eol, begin_instr; 75 long size; 76 int idx, byte; 77 78 /* Calculate offset of text after prompt */ 79 bol = edit_buffer_get_current_bol (&EDIT (ip)->buffer); 80 eol = edit_buffer_get_current_eol (&EDIT (ip)->buffer); 81 begin_instr = bol + ip->prompt_span; 82 83 /* Is there anything entered? */ 84 size = ((long) eol) - ((long) begin_instr); 85 if (size <= 0) 86 return NULL; 87 88 /* Allocate expected size string and fill it */ 89 instr = g_string_sized_new (size + 2); 90 for (idx = 0; idx < size; idx++) 91 { 92 byte = edit_buffer_get_byte (&EDIT (ip)->buffer, begin_instr + idx); 93 g_string_append_c (instr, byte); 94 } 95 96 /* Append new line if needed */ 97 if (instr->str[instr->len - 1] != '\n') 98 g_string_append_c (instr, '\n'); 99 100 /* Return char buffer */ 101 ret_str = instr->str; 102 g_string_free (instr, FALSE); 103 return ret_str; 104 } 105 106 /* --------------------------------------------------------------------------------------------- */ 107 108 static gboolean 109 instr_stn_release (WInstructionStation * ip, gboolean free_all) 110 { 111 /* Already relased? */ 112 if (ip == NULL) 113 { 114 if (free_all) 115 return TRUE; 116 else 117 return FALSE; 118 } 119 120 /* Already cleaned up (for a restart of program) ? */ 121 if (ip->finalized && !free_all) 122 return FALSE; 123 ip->finalized = TRUE; 124 125 /* Close process watcher first, suppressing *program_ended_cb() callback */ 126 if (ip->proc_src_id != 0) 127 { 128 GSource *src; 129 src = g_main_context_find_source_by_id (NULL, ip->proc_src_id); 130 if (src != NULL) 131 g_source_destroy (src); 132 ip->proc_src_id = 0; 133 } 134 135 /* Release the pipes, channels, etc. */ 136 for (int i = 0; i <= STDERR; i++) 137 { 138 /* Source */ 139 if (ip->io[i].src_id != 0) 140 { 141 GSource *src; 142 src = g_main_context_find_source_by_id (NULL, ip->io[i].src_id); 143 if (src != NULL) 144 g_source_destroy (src); 145 ip->io[i].src_id = 0; 146 } 147 /* Channel */ 148 if (ip->io[i].ch != NULL) 149 { 150 g_io_channel_unref (ip->io[i].ch); 151 ip->io[i].ch = NULL; 152 } 153 /* Pipe */ 154 if (ip->io[i].fd >= 0) 155 { 156 close (ip->io[i].fd); 157 ip->io[i].fd = -1; 158 } 159 } 160 161 /* Remove prompt guard recurring timeout callback function */ 162 if (ip->prompt_timeout_id != 0) 163 { 164 g_source_remove (ip->prompt_timeout_id); 165 ip->prompt_timeout_id = 0; 166 } 167 168 MC_PTR_FREE (ip->instruction); 169 /* Release prompt */ 170 MC_PTR_FREE (ip->prompt); 171 /* Release error prompt */ 172 MC_PTR_FREE (ip->eprompt); 173 174 /* Clear prompt information */ 175 ip->prompt_span = 0; 176 ip->eprompt_span = 0; 177 178 /* Set various indicator flags to some inactive state */ 179 ip->io_complete = TRUE; 180 ip->first_response = TRUE; 181 ip->before_first_prompt = TRUE; 182 ip->prompt_shown = FALSE; 183 ip->flags = INSTR_STN_NO_FLAGS; 184 185 /* Clear any GError */ 186 if (ip->error != NULL) 187 { 188 g_error_free (ip->error); 189 ip->error = NULL; 190 } 191 192 /* Release space occupied by WInstructionStation object? */ 193 if (free_all) 194 { 195 MC_PTR_FREE (ip->program); 196 /* Free main object */ 197 g_free (ip); 198 } 199 else 200 /* Value is still accessible in prev_program field */ 201 ip->program = NULL; 202 203 return TRUE; 204 } 205 206 /* --------------------------------------------------------------------------------------------- */ 207 208 static cb_ret_t 209 instr_stn_run_novel_state_id (WInstructionStation * ip, long novel_state_id, void *data) 210 { 211 WGroup *owner = WIDGET (ip)->owner; 212 cb_ret_t ret = MSG_NOT_HANDLED; 213 214 switch (novel_state_id) 215 { 216 case CK_BackSpace: 217 if (ip->cur_col <= ip->prompt_span) 218 ret = MSG_HANDLED; 219 else 220 { 221 EDIT (ip)->force |= REDRAW_PAGE; 222 edit_update_screen (EDIT (ip)); 223 } 224 break; 225 case CK_Enter: 226 case CK_Return: 227 if (EDIT (ip)->buffer.curs_line == ip->cur_line) 228 { 229 ip->instruction = instr_stn_get_instruction_text (ip); 230 ip->io_complete = FALSE; 231 /* Should dispatch to write callback which will send instruction */ 232 g_main_context_iteration (NULL, 0); 233 repaint_screen (); 234 } 235 ret = MSG_HANDLED; 236 break; 237 /* InstructionStation activity invoked when focus is at a station window behaves differently */ 238 case CK_InstructionStation: 239 { 240 /* Save needed information */ 241 char *program_save; 242 243 /* End previous program */ 244 if (kill (ip->process_id, 15) == -1) 245 mc_log ("Problem sending TERM signal to %d: %s.", ip->process_id, 246 g_strerror (errno)); 247 else 248 mc_log ("Ending process %d.", ip->process_id); 249 if (!ip->proc_support) 250 waitpid (ip->process_id, NULL, 0); 251 252 /* Allow process watcher callbacks to be called */ 253 g_usleep (150000); 254 g_main_context_iteration (NULL, FALSE); 255 /* Allow the process end message to flash noticeably long */ 256 g_usleep (200000); 257 258 /* Clean WInstructionStation object */ 259 instr_stn_release (ip, FALSE); 260 /* ...and reinitialize it */ 261 program_save = data != NULL ? g_strdup (data) : ip->prev_program; 262 if (instr_stn_init (ip, -1, -1, -1, -1, ip->prev_flags, program_save) == NULL) 263 { 264 /* Init failed -> close faulty station window */ 265 ret = 266 edit_dialog_callback (WIDGET (owner), WIDGET (ip), MSG_ACTION, CK_Close, NULL); 267 if (ret == MSG_HANDLED) 268 /* Update pointer in case of some future code like widget_draw(ip), etc. */ 269 ip = INSTR_STATION (owner->current->data); 270 } 271 else 272 { 273 repaint_screen (); 274 ret = MSG_HANDLED; 275 } 276 g_free (program_save); 277 } 278 break; 279 default: 280 break; 281 } 282 return ret; 283 } 284 285 /* --------------------------------------------------------------------------------------------- */ 286 287 static void 288 instr_stn_show_prompt (WInstructionStation * ip, gboolean is_ok) 289 { 290 char *sel_prompt = is_ok ? ip->prompt : ip->eprompt; 291 int sel_prompt_span = is_ok ? ip->prompt_span : ip->eprompt_span; 292 293 if (has_flag (ip->flags, INSTR_STN_NO_PROMPT)) 294 return; 295 296 /* Print prompt */ 297 if (!edit_newline_end_check_only (EDIT (ip)) && !ip->before_first_prompt) 298 { 299 edit_insert (EDIT (ip), '\n'); 300 ip->cur_line += 1; 301 } 302 else 303 ip->before_first_prompt = FALSE; 304 edit_insert_string (EDIT (ip), sel_prompt, sel_prompt_span); 305 306 /* Raise an indicator flag */ 307 ip->prompt_shown = TRUE; 308 309 /* Set cursor position to reflect state */ 310 ip->cur_col = sel_prompt_span; 311 } 312 313 /* --------------------------------------------------------------------------------------------- */ 314 /* Remove prompt from buffer (basically clear current line). */ 315 316 static void 317 instr_stn_clear_prompt (WInstructionStation * ip) 318 { 319 off_t bol, eol, idx; 320 321 if (has_flag (ip->flags, INSTR_STN_NO_PROMPT)) 322 return; 323 324 eol = edit_buffer_get_current_eol (&EDIT (ip)->buffer); 325 bol = edit_buffer_get_current_bol (&EDIT (ip)->buffer); 326 for (idx = 0; idx < eol - bol; idx++) 327 edit_backspace (EDIT (ip), TRUE); 328 ip->prompt_shown = FALSE; 329 } 330 331 /* --------------------------------------------------------------------------------------------- */ 332 333 static gboolean 334 prompt_drawing_timeout_callback (gpointer data) 335 { 336 WInstructionStation *ip = INSTR_STATION (data); 337 guint64 cur_time; 338 cur_time = g_get_real_time (); 339 /* Draw prompt after 0.5 seconds of no output from program */ 340 if (cur_time - ip->read_time > 500000 && !ip->prompt_shown) 341 { 342 instr_stn_show_prompt (ip, TRUE); 343 repaint_screen (); 344 } 345 return TRUE; 346 } 347 348 /* --------------------------------------------------------------------------------------------- */ 349 350 #ifdef GLIB_VERSION_2_40 351 352 static void 353 program_ended_callback (GPid pid, gint exit_code, gpointer user_data) 354 { 355 WInstructionStation *ip = INSTR_STATION (user_data); 356 char *msg; 357 gboolean st_ret; 358 359 /* Release object leaving it uninitialized (no freeing of main object pointer) */ 360 instr_stn_release (ip, FALSE); 361 362 g_spawn_close_pid (pid); 363 364 /* Examine exit code of closed program */ 365 #ifdef GLIB_VERSION_2_34 366 st_ret = g_spawn_check_exit_status (exit_code, NULL); 367 #else 368 st_ret = (exit_code == 0); 369 #endif 370 371 /* Choose message basing on exit code */ 372 if (st_ret) 373 msg = g_strdup (_("\nProgram closed.\n")); 374 else 375 msg = g_strdup_printf (_("\nProgram closed abnormally (exit code: %d).\n"), exit_code); 376 377 /* Insert/print message to buffer and to mc.log */ 378 edit_insert_string (EDIT (ip), msg, strlen (msg)); 379 mc_log ("%s", msg); 380 381 /* Release message upon using/printing it */ 382 g_free (msg); 383 repaint_screen (); 384 } 385 386 #endif 387 388 /* --------------------------------------------------------------------------------------------- */ 389 390 static gboolean 391 helper_configure_src_and_ch (GIOChannel ** ch, gint fd, guint * src_id, gboolean write, 392 GIOFunc cb_fun, gpointer data, const char *name) 393 { 394 /* Initialize the output variables */ 395 *ch = NULL; 396 *src_id = 0; 397 398 *ch = g_io_channel_unix_new (fd); 399 400 /* Channel created? */ 401 if (*ch == NULL) 402 goto cleanup_and_err; 403 404 /* Automatic shutdown of channel */ 405 g_io_channel_set_close_on_unref (*ch, TRUE); 406 407 /* Trim down buffering on this channel */ 408 g_io_channel_set_buffer_size (*ch, 5); 409 410 /* Attempt to set non-blocking flag on channel */ 411 if (g_io_channel_set_flags (*ch, G_IO_FLAG_NONBLOCK, NULL) != G_IO_STATUS_NORMAL) 412 mc_log ("Problem setting a channel to non-blocking state (channel flags: 0x%x)", 413 g_io_channel_get_flags (*ch)); 414 415 /* Create GSource */ 416 *src_id = 417 g_io_add_watch (*ch, (write ? G_IO_OUT : G_IO_IN) | G_IO_HUP | G_IO_ERR, cb_fun, data); 418 419 /* Source created OK? */ 420 if (*src_id == 0) 421 goto cleanup_and_err; 422 423 /* Configure the sources */ 424 g_source_set_name_by_id (*src_id, name); 425 426 /* Return true */ 427 return TRUE; 428 429 cleanup_and_err: 430 if (*src_id != 0) 431 { 432 GSource *src; 433 src = g_main_context_find_source_by_id (NULL, *src_id); 434 if (src != NULL) 435 /* Triggers also unref of wrapped channel */ 436 g_source_destroy (src); 437 } 438 if (*ch != NULL) 439 g_io_channel_unref (*ch); 440 *ch = NULL; 441 *src_id = 0; 442 443 return FALSE; 444 } 445 446 /* --------------------------------------------------------------------------------------------- */ 447 448 static gboolean 449 helper_read_all (GIOChannel * channel, char *buf, gsize * out_bytes_read_in_len) 450 { 451 gsize len = *out_bytes_read_in_len; 452 gsize count, retries = 10; 453 GIOStatus stat; 454 455 *out_bytes_read_in_len = 0; 456 457 while (*out_bytes_read_in_len < len) 458 { 459 count = 0; 460 stat = 461 g_io_channel_read_chars (channel, buf + *out_bytes_read_in_len, 462 len - *out_bytes_read_in_len, &count, NULL); 463 *out_bytes_read_in_len += count; 464 465 /* Should end the reading ? */ 466 if (stat == G_IO_STATUS_ERROR || (stat == G_IO_STATUS_NORMAL && count == 0) || 467 stat == G_IO_STATUS_EOF) 468 return (stat != G_IO_STATUS_ERROR); 469 else if (stat == G_IO_STATUS_AGAIN && retries-- == 0) 470 /* Exhausted retries - there must be no data to read - return OK */ 471 return TRUE; 472 } 473 474 return TRUE; 475 } 476 477 /* --------------------------------------------------------------------------------------------- */ 478 479 static gboolean 480 helper_write_all (GIOChannel * channel, char *buf, gsize * out_bytes_written_in_len) 481 { 482 gsize len = *out_bytes_written_in_len; 483 gsize count; 484 GIOError err; 485 486 *out_bytes_written_in_len = 0; 487 488 while (*out_bytes_written_in_len < len) 489 { 490 count = 0; 491 err = 492 g_io_channel_write (channel, buf + *out_bytes_written_in_len, 493 len - *out_bytes_written_in_len, &count); 494 *out_bytes_written_in_len += count; 495 496 if (err && err != G_IO_ERROR_AGAIN) 497 return FALSE; 498 } 499 500 return TRUE; 501 } 502 503 /* --------------------------------------------------------------------------------------------- */ 504 505 static gboolean 506 stdout_read_callback (GIOChannel * source, GIOCondition condition, gpointer data) 507 { 508 WInstructionStation *ip = INSTR_STATION (data); 509 char buf[2048]; 510 gsize count = 2047; 511 gboolean r_ret; 512 513 /* Active only when a recognized event of interest occurs */ 514 if ((condition & (G_IO_IN | G_IO_HUP | G_IO_ERR)) == 0) 515 return TRUE; 516 else 517 ip->io_complete = FALSE; 518 519 /* Repeat read of 2KiB-1 maximum bytes until 0 bytes are being read */ 520 do 521 { 522 r_ret = helper_read_all (source, buf, &count); 523 buf[count] = '\0'; 524 if (count == 0 && !r_ret) 525 { 526 mc_log ("Error while reading program's output: %s", g_strerror (errno)); 527 } 528 else 529 { 530 ip->read_time = g_get_real_time (); 531 buf[count] = '\0'; 532 if (count > 0) 533 { 534 gsize idx = 0, nl_count = 0; 535 536 /* Count number of read lines */ 537 char *p = buf; 538 while (idx++ < count) 539 if (*p++ == '\n') 540 nl_count++; 541 542 /* Move to next line after prompt */ 543 if (ip->first_response) 544 { 545 edit_insert (EDIT (ip), '\n'); 546 nl_count++; 547 ip->first_response = FALSE; 548 ip->prompt_shown = FALSE; 549 } 550 else if (ip->prompt_shown) 551 instr_stn_clear_prompt (ip); 552 553 /* Print whole buffer into file's window */ 554 edit_insert_string (EDIT (ip), buf, count); 555 556 /* Increase the row pointer */ 557 ip->cur_line += nl_count; 558 } 559 else if (!ip->prompt_shown) 560 instr_stn_show_prompt (ip, r_ret); 561 562 repaint_screen (); 563 } 564 } 565 while (count != 0); 566 567 ip->io_complete = r_ret; 568 return condition != G_IO_HUP; 569 } 570 571 /* --------------------------------------------------------------------------------------------- */ 572 573 static gboolean 574 stdin_write_callback (GIOChannel * source, GIOCondition condition, gpointer data) 575 { 576 WInstructionStation *ip = INSTR_STATION (data); 577 gsize count; 578 gboolean ret = TRUE; 579 580 /* Any instruction to send? */ 581 if (ip->instruction == NULL) 582 return ret; 583 else 584 ip->io_complete = FALSE; 585 586 if ((condition & G_IO_OUT) == 0) 587 return TRUE; 588 589 errno = 0; 590 count = strlen (ip->instruction); 591 ret = helper_write_all (source, ip->instruction, &count); 592 if (!ret) 593 { 594 mc_log ("Error during sending instruction to program: %s", g_strerror (errno)); 595 } 596 else 597 { 598 ip->first_response = TRUE; 599 MC_PTR_FREE (ip->instruction); 600 if (ip->prompt_timeout_id == 0) 601 ip->prompt_timeout_id = g_timeout_add (200, prompt_drawing_timeout_callback, ip); 602 } 603 604 g_io_channel_flush (ip->io[STDIN].ch, NULL); 605 ip->io_complete = TRUE; 606 607 return ret; 608 } 609 610 /* --------------------------------------------------------------------------------------------- */ 611 612 /* --------------------------------------------------------------------------------------------- */ 613 /*** public functions ****************************************************************************/ 614 /* --------------------------------------------------------------------------------------------- */ 615 616 WInstructionStation * 617 instr_stn_create (int y, int x, int lines, int cols, instr_stn_flags_t flags, const char *program) 618 { 619 WInstructionStation *ip, *iret; 620 621 ip = g_new0 (WInstructionStation, 1); 622 if (ip == NULL) 623 return NULL; 624 625 iret = instr_stn_init (ip, y, x, lines, cols, flags, program); 626 if (iret == NULL) 627 MC_PTR_FREE (ip); 628 629 return ip; 630 } 631 632 /* --------------------------------------------------------------------------------------------- */ 633 /* Initializes a preallocated object */ 634 635 WInstructionStation * 636 instr_stn_init (WInstructionStation * ip, int y, int x, int lines, int cols, 637 instr_stn_flags_t flags, const char *program) 638 { 639 WEdit *iret; 640 WGroup *owner_save = NULL; 641 gboolean tmp_ret = FALSE; 642 char **program_cline; 643 int rounds = 0; 644 645 if (ip == NULL) 646 goto cleanup_and_err; 647 648 /* Handle special -1 values indicating reuse of old values */ 649 if (ip->finalized) 650 { 651 y = (y == -1) ? WIDGET (ip)->y : y; 652 x = (x == -1) ? WIDGET (ip)->x : x; 653 lines = (lines == -1) ? WIDGET (ip)->lines : lines; 654 cols = (cols == -1) ? WIDGET (ip)->cols : cols; 655 /* Save owner */ 656 owner_save = WIDGET (ip)->owner; 657 ip->finalized = FALSE; 658 } 659 660 /* Initialize base object (WEdit) */ 661 iret = edit_init (EDIT (ip), y, x, lines, cols, NULL, 0, EDIT_DO_INIT_BASE_CLASS); 662 if (iret == NULL) 663 goto cleanup_and_err; 664 665 /* Restore owner field value */ 666 WIDGET (ip)->owner = owner_save; 667 WIDGET (ip)->callback = instr_stn_callback; 668 WIDGET (ip)->mouse_callback = edit_mouse_callback; 669 EDIT (ip)->fullscreen = 0; 670 671 ip->io[0].name = g_strdup ("Std-In (WInstructionStation)"); 672 ip->io[1].name = g_strdup ("Std-Out (WInstructionStation)"); 673 ip->io[2].name = g_strdup ("Std-Error (WInstructionStation)"); 674 ip->io[0].fd = ip->io[1].fd = ip->io[2].fd = -1; 675 676 ip->before_first_prompt = TRUE; 677 ip->prompt = g_strdup ("[guest@localhost]# "); 678 ip->prompt_span = strlen (ip->prompt); 679 ip->eprompt = g_strdup ("[guest@localhost]! "); 680 ip->eprompt_span = strlen (ip->eprompt); 681 ip->cur_col = 0; 682 ip->cur_line = 0; 683 ip->flags = flags; 684 ip->prev_flags = flags; 685 686 /* Set initial program (most probably a shell, like Bash) */ 687 if (program != NULL) 688 { 689 if (program[0] == 's' && program[1] == 'h') 690 ip->program = g_strdup (program); 691 else 692 ip->program = g_strdup_printf ("sh -c '%s'", program); 693 } 694 else 695 /* Fallback instruction if no program given */ 696 ip->program = g_strdup ("bash"); 697 698 while (++rounds <= 2 && !tmp_ret) 699 { 700 int argc = 0; 701 if (ip->error != NULL) 702 { 703 g_error_free (ip->error); 704 ip->error = NULL; 705 } 706 tmp_ret = g_shell_parse_argv (ip->program, &argc, &program_cline, &ip->error); 707 if (tmp_ret) 708 { 709 tmp_ret = g_spawn_async_with_pipes (NULL, program_cline, 710 NULL, G_SPAWN_SEARCH_PATH | 711 G_SPAWN_DO_NOT_REAP_CHILD | 712 G_SPAWN_LEAVE_DESCRIPTORS_OPEN, 713 NULL, NULL, &ip->process_id, 714 has_flag (flags, 715 INSTR_STN_NO_STDIN) ? NULL : 716 &ip->io[STDIN].fd, &ip->io[STDOUT].fd, 717 &ip->io[STDERR].fd, &ip->error); 718 g_strfreev (program_cline); 719 } 720 if (!tmp_ret) 721 { 722 char *new_program, *msg_text; 723 mc_log ("Creating CLI process [instruction:%s] failed: %s", 724 program, ip->error ? ip->error->message : "<no error message>"); 725 726 /* Create a transatable, parametrized message */ 727 msg_text = g_strdup_printf ("%s%s:", _("The specified program has failed to run.\n" 728 "Enter a new full path or a program name"), 729 (rounds >= 2 ? _(" (last try)") : "")); 730 731 /* Display message asking for a new program */ 732 new_program = input_expand_dialog (_("Provide an alternate program to run"), 733 msg_text, "instruction-station", 734 alt_prog_first_run ? ip->program : INPUT_LAST_TEXT, 735 INPUT_COMPLETE_COMMANDS | INPUT_COMPLETE_FILENAMES | 736 INPUT_COMPLETE_VARIABLES); 737 g_free (msg_text); 738 alt_prog_first_run = FALSE; 739 740 /* Obtained a new program? */ 741 if (new_program != NULL) 742 { 743 g_free (ip->program); 744 ip->program = new_program; 745 } 746 } 747 } 748 749 /* If no program to run has been found, then exit. */ 750 if (!tmp_ret) 751 { 752 message (D_ERROR, _("InstructionStation startup failed"), 753 _("Failed to initialize the CLI window\n(reason: %s)."), 754 ip->error ? ip->error->message : "<no error message>"); 755 goto cleanup_and_err; 756 } 757 758 ip->prev_program = ip->program; 759 760 for (int i = 0; i <= STDERR; i++) 761 { 762 if (has_flag (flags, INSTR_STN_NO_STDIN) && i == STDIN) 763 { 764 /* There is no standard input pipe for program */ 765 ip->io[i].fd = -1; 766 continue; 767 } 768 769 if (helper_configure_src_and_ch (&ip->io[i].ch, ip->io[i].fd, &ip->io[i].src_id, 770 (i == STDIN ? TRUE : FALSE), 771 (i == STDIN ? stdin_write_callback : stdout_read_callback), 772 ip, ip->io[i].name) == FALSE) 773 goto cleanup_and_err; 774 } 775 776 #ifdef GLIB_VERSION_2_40 777 /* Set a process watcher and restarter for the program */ 778 ip->proc_src_id = g_child_watch_add (ip->process_id, program_ended_callback, ip); 779 ip->proc_support = TRUE; 780 #endif 781 782 /* Display initial prompt */ 783 instr_stn_show_prompt (ip, TRUE); 784 ip->io_complete = TRUE; 785 786 return ip; 787 788 cleanup_and_err: 789 790 instr_stn_release (ip, TRUE); 791 return NULL; 792 } 793 794 /* --------------------------------------------------------------------------------------------- */ 795 796 WEdit * 797 find_cli (const WDialog * h) 798 { 799 const WGroup *g = CONST_GROUP (h); 800 801 if (edit_widget_is_cli (CONST_WIDGET (g->current->data))) 802 return (WEdit *) g->current->data; 803 return (WEdit *) widget_find_by_type (CONST_WIDGET (h), instr_stn_callback); 804 } 805 806 /* --------------------------------------------------------------------------------------------- */ 807 /* Check if widget is a WInstructionStation class type. */ 808 809 gboolean 810 edit_widget_is_cli (const Widget * w) 811 { 812 return (w != NULL && w->callback == instr_stn_callback); 813 } 814 815 /* --------------------------------------------------------------------------------------------- */ 816 817 cb_ret_t 818 instr_stn_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data) 819 { 820 cb_ret_t ret = MSG_NOT_HANDLED; 821 WInstructionStation *ip = INSTR_STATION (w); 822 WGroup *owner = w->owner; 823 824 switch (msg) 825 { 826 827 case MSG_KEY: 828 { 829 gboolean ext_mode; 830 long novel_state_id; 831 832 /* keep and then extmod flag */ 833 ext_mode = w->ext_mode; 834 novel_state_id = widget_lookup_key (w, parm); 835 w->ext_mode = ext_mode; 836 837 if (novel_state_id == CK_IgnoreKey) 838 w->ext_mode = FALSE; 839 else 840 { 841 /* Treat Station action specially when run from within a station window */ 842 if (novel_state_id != CK_InstructionStation) 843 ret = edit_dialog_command_execute (DIALOG (owner), novel_state_id, data); 844 if (ret == MSG_NOT_HANDLED) 845 ret = instr_stn_run_novel_state_id (ip, novel_state_id, data); 846 /* 847 * If activity was not handled, keep the extended mode 848 * for the further key processing, checking if the 849 * window is still open */ 850 if (novel_state_id != CK_Close) 851 { 852 if (ret == MSG_HANDLED) 853 w->ext_mode = FALSE; 854 } 855 else if (ret == MSG_HANDLED) 856 /* Window closed -> update `w` variable */ 857 w = WIDGET (owner->current->data); 858 } 859 860 /* 861 * Due to the "end of bracket" escape the editor sees input with is_idle() == false 862 * (expects more characters) and hence doesn't yet refresh the screen, but then 863 * no further characters arrive (there's only an "end of bracket" which is swallowed 864 * by tty_get_event()), so you end up with a screen that's not refreshed after pasting. 865 * So let's trigger an IDLE signal. 866 */ 867 if (!is_idle ()) 868 widget_idle (w, TRUE); 869 } 870 break; 871 case MSG_ACTION: 872 ret = instr_stn_run_novel_state_id (ip, parm, data); 873 break; 874 case MSG_DESTROY: 875 kill (ip->process_id, 15); 876 /* Have to wait directly (no GLib support for watchers) ? */ 877 if (!ip->proc_support) 878 waitpid (ip->process_id, NULL, 0); 879 880 /* 881 * Message will be passed on to WEdit callback which will g_free(), so passing FALSE (i.e.: 882 * requesting cleanup of WInstructionStation object without full release of its main 883 * pointer) */ 884 instr_stn_release (ip, FALSE); 885 /* Not restarting the station, so release program string backup field */ 886 g_free (ip->prev_program); 887 break; 888 default: 889 break; 890 } 891 892 /* Redirect message to base object (i.e.: editor window «» WEdit) if needed */ 893 if (ret == MSG_NOT_HANDLED) 894 { 895 ret = edit_callback (w, sender, msg, parm, data); 896 if (msg != MSG_DESTROY) 897 ip->cur_col = EDIT (w)->curs_col; 898 } 899 return ret; 900 } 901 902 /* --------------------------------------------------------------------------------------------- */ -
new file src/editor/instr_station.h
diff --git a/src/editor/instr_station.h b/src/editor/instr_station.h new file mode 100644 index 000000000..0f05900c1
- + 1 #ifndef MC__INSTR_STATION_H 2 #define MC__INSTR_STATION_H 3 4 /*** typedefs(not structures) and defined constants **********************************************/ 5 6 #define INSTR_STATION(x) ((WInstructionStation *)x) 7 #define CONST_INSTR_STATION(x) ((const WInstructionStation *)x) 8 9 /*** enums ***************************************************************************************/ 10 11 /*** structures declarations (and typedefs of structures)*****************************************/ 12 13 typedef struct 14 { 15 WEdit base; 16 17 /* Configuration flags */ 18 instr_stn_flags_t flags; 19 /* Save of flags for use upon finalization of this object */ 20 instr_stn_flags_t prev_flags; 21 22 int cur_line; /* Current line where prompt is */ 23 int cur_col; /* Current column where prompt ends */ 24 int prompt_span; /* Length of prompt in bytes */ 25 int eprompt_span; /* Length of error prompt */ 26 27 /* Complete command that's being run in this station */ 28 char *program; 29 /* Saved program string from before calling instr_stn_release(...,FALSE) (i.e.: finalization) */ 30 char *prev_program; 31 /* OK prompt */ 32 char *prompt; 33 /* Failure prompt */ 34 char *eprompt; 35 /* The current instruction to send (filled for the writer GSource's pseudo thread) */ 36 char *instruction; 37 38 /* An indicator of whether the prompt to show is the first one */ 39 gboolean before_first_prompt; 40 /* An indicator of waiting for an initial response from program */ 41 gboolean first_response; 42 /* An indicator of the prompt being printed or not */ 43 gboolean prompt_shown; 44 /* ID of prompt drawing GLib's timeout recurring function */ 45 guint prompt_timeout_id; 46 47 /* Process ID of the program */ 48 GPid process_id; 49 50 /* Pipes to and from the program – series of fd+channel+GSource collections */ 51 struct 52 { 53 gint fd; 54 GIOChannel *ch; 55 guint src_id; 56 char *name; 57 } io[3]; 58 59 /* Time of last non empty read of data from program */ 60 guint64 read_time; 61 62 /* GSource id of program process watcher */ 63 guint proc_src_id; 64 65 /* A flag indicating whether there is (can be) a process watcher running */ 66 gboolean proc_support; 67 68 /* A GError placeholder */ 69 GError *error; 70 71 /* Indicator of an idle state – set when there's no data to send and read */ 72 gboolean io_complete; 73 74 /* Indicator of instr_release being already called on WInstructionStation object */ 75 gboolean finalized; 76 } WInstructionStation; 77 78 /*** global variables defined in .c file *********************************************************/ 79 80 /*** declarations of public functions ************************************************************/ 81 82 WInstructionStation *instr_stn_create (int y, int x, int lines, int cols, instr_stn_flags_t flags, 83 const char *program); 84 WInstructionStation *instr_stn_init (WInstructionStation * ip, int y, int x, int lines, int cols, 85 instr_stn_flags_t flags, const char *program); 86 WEdit *find_cli (const WDialog * h); 87 gboolean edit_widget_is_cli (const Widget * w); 88 cb_ret_t instr_stn_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data); 89 90 /*** inline functions ****************************************************************************/ 91 92 #endif /* MC__INSTR_STATION_H */ -
src/keybind-defaults.c
diff --git a/src/keybind-defaults.c b/src/keybind-defaults.c index 7b87c2f5a..0f45f9c09 100644
a b static const global_keymap_ini_t default_editor_keymap[] = { 470 470 {"FileNext", "alt-plus"}, 471 471 {"Sort", "alt-t"}, 472 472 {"Mail", "alt-m"}, 473 {"InstructionStation", "alt-i"}, 473 474 {"ExternalCommand", "alt-u"}, 474 475 #ifdef HAVE_ASPELL 475 476 {"SpellCheckCurrentWord", "ctrl-p"},