Ticket #4196: InstructionStation_v3.patch
File InstructionStation_v3.patch, 55.3 KB (added by psprint, 4 years ago) |
---|
-
lib/global.h
From 05e4cf188f825479b7b4149061821241134abb52 Mon Sep 17 00:00:00 2001 From: Sebastian Gniazdowski <sgniazdowski@gmail.com> Date: Wed, 10 Feb 2021 13:41:35 -0600 Subject: =?UTF-8?q?Instructions=20Station=20=E2=80=93=20a=20CLI=20window?= =?UTF-8?q?=20for=20MCEdit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/global.h | 3 + lib/keybind.c | 1 + lib/keybind.h | 1 + lib/tty/key.c | 10 +- lib/widget/Makefile.am | 1 + lib/widget/instr_station.c | 664 +++++++++++++++++++++++++++++++++++++ lib/widget/instr_station.h | 82 +++++ misc/mc.default.keymap | 1 + misc/mc.emacs.keymap | 1 + src/editor/edit-impl.h | 15 +- src/editor/edit.c | 27 +- src/editor/editcmd.c | 9 + src/editor/editdraw.c | 1 - src/editor/editmenu.c | 3 + src/editor/editwidget.c | 581 ++++++++++++++++---------------- src/editor/editwidget.h | 3 + src/history.h | 1 + src/keybind-defaults.c | 1 + 18 files changed, 1113 insertions(+), 292 deletions(-) create mode 100644 lib/widget/instr_station.c create mode 100644 lib/widget/instr_station.h diff --git a/lib/global.h b/lib/global.h index f1a3e702c..1f76061c6 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 65ac5f15c..2f9d3cf29 100644
a b static name_keymap_t command_names_start[] = { 300 300 ADD_KEYMAP_NAME (EditMail), 301 301 ADD_KEYMAP_NAME (ParagraphFormat), 302 302 ADD_KEYMAP_NAME (MatchBracket), 303 ADD_KEYMAP_NAME (InstructionStation), 303 304 ADD_KEYMAP_NAME (ExternalCommand), 304 305 ADD_KEYMAP_NAME (MacroStartRecord), 305 306 ADD_KEYMAP_NAME (MacroStopRecord), -
lib/keybind.h
diff --git a/lib/keybind.h b/lib/keybind.h index 4e954ade2..18c7d95e4 100644
a b enum 324 324 CK_SyntaxOnOff, 325 325 CK_SyntaxChoose, 326 326 CK_InsertLiteral, 327 CK_InstructionStation, 327 328 CK_ExternalCommand, 328 329 CK_Date, 329 330 CK_EditMail, -
lib/tty/key.c
diff --git a/lib/tty/key.c b/lib/tty/key.c index 58a2f018b..cec17801a 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, 0); 2046 2054 if (redo_event) 2047 2055 return EV_MOUSE; 2048 2056 if (!block || tty_got_winch ()) -
lib/widget/Makefile.am
diff --git a/lib/widget/Makefile.am b/lib/widget/Makefile.am index 2d8434391..2500af671 100644
a b libmcwidget_la_SOURCES = \ 8 8 check.c check.h \ 9 9 dialog.c dialog.h \ 10 10 dialog-switch.c dialog-switch.h \ 11 instr_station.c instr_station.h \ 11 12 frame.c frame.h \ 12 13 gauge.c gauge.h \ 13 14 group.c group.h \ -
new file lib/widget/instr_station.c
diff --git a/lib/widget/instr_station.c b/lib/widget/instr_station.c new file mode 100644 index 000000000..53f17cec8
- + 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 "lib/util.h" 40 #include "lib/tty/key.h" 41 #include "lib/widget.h" 42 #include "lib/widget/instr_station.h" 43 44 /*** global variables ****************************************************************************/ 45 46 /*** file scope macro definitions ****************************************************************/ 47 48 /*** file scope type declarations ****************************************************************/ 49 50 /*** file scope variables ************************************************************************/ 51 52 static gboolean alt_prog_first_run = TRUE; 53 54 /*** file scope functions ************************************************************************/ 55 /* --------------------------------------------------------------------------------------------- */ 56 57 static char * 58 instr_stat_get_instruction_text (WInstructionStation * ip) 59 { 60 char *ret_str; 61 GString *instr; 62 off_t bol, eol, begin_instr; 63 long size; 64 int idx, byte; 65 66 /* Calculate offset of text after prompt */ 67 bol = edit_buffer_get_current_bol (&EDIT (ip)->buffer); 68 eol = edit_buffer_get_current_eol (&EDIT (ip)->buffer); 69 begin_instr = bol + ip->prompt_span; 70 71 /* Is there anything entered? */ 72 size = ((long) eol) - ((long) begin_instr); 73 if (size <= 0) 74 return NULL; 75 76 /* Allocate expected size string and fill it */ 77 instr = g_string_sized_new (size + 2); 78 for (idx = 0; idx < size; idx++) 79 { 80 byte = edit_buffer_get_byte (&EDIT (ip)->buffer, begin_instr + idx); 81 g_string_append_c (instr, byte); 82 } 83 84 /* Append new line if needed */ 85 if (instr->str[instr->len - 1] != '\n') 86 g_string_append_c (instr, '\n'); 87 88 /* Return char buffer */ 89 ret_str = instr->str; 90 g_string_free (instr, FALSE); 91 return ret_str; 92 } 93 94 /* --------------------------------------------------------------------------------------------- */ 95 96 static cb_ret_t 97 instr_stat_run_activity (WInstructionStation * ip, long activity) 98 { 99 cb_ret_t ret = MSG_NOT_HANDLED; 100 switch (activity) 101 { 102 case CK_BackSpace: 103 if (ip->cur_col <= ip->prompt_span) 104 { 105 ret = MSG_HANDLED; 106 } 107 else 108 { 109 EDIT (ip)->force |= REDRAW_PAGE; 110 edit_update_screen (EDIT (ip)); 111 } 112 break; 113 case CK_Enter: 114 case CK_Return: 115 if (EDIT (ip)->buffer.curs_line == ip->cur_line) 116 { 117 ip->instruction = instr_stat_get_instruction_text (ip); 118 /* Should dispatch to write callback which will send instruction */ 119 g_main_context_iteration (NULL, 0); 120 EDIT (ip)->force |= REDRAW_PAGE; 121 edit_update_screen (EDIT (ip)); 122 } 123 ret = MSG_HANDLED; 124 break; 125 default: 126 break; 127 } 128 return ret; 129 } 130 131 /* --------------------------------------------------------------------------------------------- */ 132 133 static gboolean 134 instr_release (WInstructionStation * ip, gboolean free_all) 135 { 136 if (ip->finalizing) 137 return FALSE; 138 ip->finalizing = TRUE; 139 140 /* Close process watcher first, suppressing *program_ended_cb() callback */ 141 if (ip->proc_src_id != 0) 142 { 143 GSource *src; 144 src = g_main_context_find_source_by_id (NULL, ip->proc_src_id); 145 if (src != NULL) 146 g_source_destroy (src); 147 ip->proc_src_id = 0; 148 } 149 150 /* Release the pipes, channels, etc. */ 151 for (int i = 0; i <= STDERR; i++) 152 { 153 if (ip->io[i].src_id != 0) 154 { 155 GSource *src; 156 src = g_main_context_find_source_by_id (NULL, ip->io[i].src_id); 157 if (src != NULL) 158 g_source_destroy (src); 159 ip->io[i].src_id = 0; 160 } 161 if (ip->io[i].ch != NULL) 162 { 163 g_io_channel_unref (ip->io[i].ch); 164 ip->io[i].ch = NULL; 165 } 166 if (ip->io[i].fd >= 0) 167 { 168 close (ip->io[i].fd); 169 ip->io[i].fd = -1; 170 } 171 } 172 173 if (free_all) 174 { 175 MC_PTR_FREE (ip->program); 176 /* Release prompt */ 177 MC_PTR_FREE (ip->prompt); 178 /* Release error prompt */ 179 MC_PTR_FREE (ip->eprompt); 180 181 /* Free main object */ 182 g_free (ip); 183 } 184 return TRUE; 185 } 186 187 /* --------------------------------------------------------------------------------------------- */ 188 189 static void 190 helper_program_ended_cb (GPid pid, gint status, gpointer user_data) 191 { 192 WInstructionStation *ip = INSTR_STATION (user_data); 193 char *msg; 194 mc_log ("Program %d ended with status: %d (%s)", pid, status, 195 g_spawn_check_exit_status (status, NULL) ? "normally" : "abnormally"); 196 197 instr_release (ip, FALSE); 198 g_spawn_close_pid (pid); 199 msg = _("\nProgram closed."); 200 edit_insert_string (EDIT (ip), msg, strlen (msg)); 201 } 202 203 /* --------------------------------------------------------------------------------------------- */ 204 205 static gboolean 206 instr_stat_update_cursor (WInstructionStation * ip, int y, int x) 207 { 208 WEdit *edit = EDIT (ip); 209 210 x += option_line_state_width; 211 212 edit->prev_col = x - edit->start_col - option_line_state_width; 213 214 if (y > edit->curs_row) 215 edit_move_down (edit, y - edit->curs_row, FALSE); 216 else if (y < edit->curs_row) 217 edit_move_up (edit, edit->curs_row - y, FALSE); 218 else 219 edit_move_to_prev_col (edit, edit_buffer_get_current_bol (&edit->buffer)); 220 221 return TRUE; 222 } 223 224 /* --------------------------------------------------------------------------------------------- */ 225 226 static void 227 instr_stat_show_prompt (WInstructionStation * ip, gboolean is_ok) 228 { 229 char *sel_prompt = is_ok ? ip->prompt : ip->eprompt; 230 int sel_prompt_span = is_ok ? ip->prompt_span : ip->eprompt_span; 231 232 /* Print prompt */ 233 if (!edit_newline_end_check_only (EDIT (ip))) 234 { 235 edit_insert (EDIT (ip), '\n'); 236 ip->cur_line += 1; 237 } 238 edit_insert_string (EDIT (ip), sel_prompt, sel_prompt_span); 239 240 /* Raise an indicator flag */ 241 ip->prompt_shown = TRUE; 242 243 /* Set cursor position to reflect state */ 244 ip->cur_col = sel_prompt_span; 245 } 246 247 /* --------------------------------------------------------------------------------------------- */ 248 249 static gboolean 250 helper_timeout_cb (gpointer data) 251 { 252 WInstructionStation *ip = INSTR_STATION (data); 253 guint64 cur_time; 254 cur_time = g_get_real_time (); 255 if (cur_time - ip->read_time > 500000) 256 { 257 instr_stat_show_prompt (ip, TRUE); 258 repaint_screen (); 259 return FALSE; 260 } 261 return TRUE; 262 } 263 264 /* --------------------------------------------------------------------------------------------- */ 265 266 static gboolean 267 helper_configure_src_and_ch (GIOChannel ** ch, gint fd, guint * src_id, gboolean write, 268 GIOFunc cb_fun, gpointer data, const char *name) 269 { 270 /* Initialize the output variables */ 271 *ch = NULL; 272 *src_id = 0; 273 274 *ch = g_io_channel_unix_new (fd); 275 276 /* Channel created? */ 277 if (*ch == NULL) 278 goto cleanup_and_err; 279 280 /* Automatic shutdown of channel */ 281 g_io_channel_set_close_on_unref (*ch, TRUE); 282 283 /* Trim down buffering on this channel */ 284 g_io_channel_set_buffer_size (*ch, 5); 285 286 /* Attempt to set non-blocking flag on channel */ 287 if (g_io_channel_set_flags (*ch, G_IO_FLAG_NONBLOCK, NULL) != G_IO_STATUS_NORMAL) 288 mc_log ("Problem setting a channel to non-blocking state (channel flags: 0x%x)", 289 g_io_channel_get_flags (*ch)); 290 291 /* Create GSource */ 292 *src_id = g_io_add_watch (*ch, (write ? G_IO_OUT : G_IO_IN) | G_IO_HUP, cb_fun, data); 293 294 /* Source created OK? */ 295 if (*src_id == 0) 296 goto cleanup_and_err; 297 298 /* Configure the sources */ 299 g_source_set_name_by_id (*src_id, name); 300 301 /* Return true */ 302 return TRUE; 303 304 cleanup_and_err: 305 if (*src_id != 0) 306 { 307 GSource *src; 308 src = g_main_context_find_source_by_id (NULL, *src_id); 309 if (src != NULL) 310 /* Triggers also unref of wrapped channel */ 311 g_source_destroy (src); 312 } 313 if (*ch != NULL) 314 g_io_channel_unref (*ch); 315 *ch = NULL; 316 *src_id = 0; 317 318 return FALSE; 319 } 320 321 /* --------------------------------------------------------------------------------------------- */ 322 323 static gboolean 324 helper_read_all (GIOChannel * channel, char *buf, gsize * out_bytes_read_in_len) 325 { 326 gsize len = *out_bytes_read_in_len; 327 gsize count, retries = 10; 328 GIOStatus stat; 329 330 *out_bytes_read_in_len = 0; 331 332 while (*out_bytes_read_in_len < len) 333 { 334 count = 0; 335 stat = 336 g_io_channel_read_chars (channel, buf + *out_bytes_read_in_len, 337 len - *out_bytes_read_in_len, &count, NULL); 338 *out_bytes_read_in_len += count; 339 340 /* Should end the reading ? */ 341 if (stat == G_IO_STATUS_ERROR || (stat == G_IO_STATUS_NORMAL && count == 0) || 342 stat == G_IO_STATUS_EOF) 343 return (stat != G_IO_STATUS_ERROR); 344 else if (stat == G_IO_STATUS_AGAIN && retries-- == 0) 345 /* Exhausted retries - there must be no data to read - return OK */ 346 return TRUE; 347 } 348 349 return TRUE; 350 } 351 352 /* --------------------------------------------------------------------------------------------- */ 353 354 static gboolean 355 helper_write_all (GIOChannel * channel, char *buf, gsize * out_bytes_written_in_len) 356 { 357 gsize len = *out_bytes_written_in_len; 358 gsize count; 359 GIOError err; 360 361 *out_bytes_written_in_len = 0; 362 363 while (*out_bytes_written_in_len < len) 364 { 365 count = 0; 366 err = 367 g_io_channel_write (channel, buf + *out_bytes_written_in_len, 368 len - *out_bytes_written_in_len, &count); 369 *out_bytes_written_in_len += count; 370 371 if (err && err != G_IO_ERROR_AGAIN) 372 return FALSE; 373 } 374 375 return TRUE; 376 } 377 378 /* --------------------------------------------------------------------------------------------- */ 379 380 static gboolean 381 stdout_read_callback (GIOChannel * source, GIOCondition condition, gpointer data) 382 { 383 WInstructionStation *ip = INSTR_STATION (data); 384 char buf[2048]; 385 gsize count = 2047; 386 gboolean r_ret, first_response = ip->prompt_shown; 387 388 if ((condition & G_IO_IN) == 0) 389 return TRUE; 390 391 r_ret = helper_read_all (source, buf, &count); 392 buf[count] = '\0'; 393 if (count == 0) 394 { 395 mc_log ("Error while reading program's output: %s", g_strerror (errno)); 396 } 397 else 398 { 399 ip->read_time = g_get_real_time (); 400 buf[count] = '\0'; 401 if (count > 0) 402 { 403 gsize idx = 0, nl_count = 0; 404 char *p = buf; 405 while (idx++ < count) 406 if (*p++ == '\n') 407 nl_count++; 408 409 /* Move to next line after prompt */ 410 if (first_response) 411 { 412 edit_insert (EDIT (ip), '\n'); 413 nl_count++; 414 } 415 416 /* Print whole buffer into file's window */ 417 edit_insert_string (EDIT (ip), buf, count); 418 419 /* Increase the row pointer */ 420 ip->cur_line += nl_count; 421 422 /* Mark a lack of prompt display */ 423 ip->prompt_shown = FALSE; 424 } 425 else if (!ip->prompt_shown) 426 instr_stat_show_prompt (ip, r_ret); 427 428 repaint_screen (); 429 } 430 431 return TRUE; 432 } 433 434 /* --------------------------------------------------------------------------------------------- */ 435 436 static gboolean 437 stdin_write_callback (GIOChannel * source, GIOCondition condition, gpointer data) 438 { 439 WInstructionStation *ip = INSTR_STATION (data); 440 gsize count; 441 gboolean ret = TRUE; 442 443 /* Any instruction to send? */ 444 if (ip->instruction == NULL) 445 return ret; 446 447 if ((condition & G_IO_OUT) == 0) 448 return TRUE; 449 450 errno = 0; 451 count = strlen (ip->instruction); 452 ret = helper_write_all (ip->io[STDIN].ch, ip->instruction, &count); 453 if (!ret) 454 { 455 mc_log ("Error during sending instruction to program: %s", g_strerror (errno)); 456 } 457 else 458 { 459 MC_PTR_FREE (ip->instruction); 460 g_timeout_add (200, helper_timeout_cb, ip); 461 } 462 463 g_io_channel_flush (ip->io[STDIN].ch, NULL); 464 465 return ret; 466 } 467 468 /* --------------------------------------------------------------------------------------------- */ 469 470 /* --------------------------------------------------------------------------------------------- */ 471 /*** public functions ****************************************************************************/ 472 /* --------------------------------------------------------------------------------------------- */ 473 474 WInstructionStation * 475 instr_stat_create (int y, int x, int lines, int cols, const char *program) 476 { 477 WInstructionStation *ip; 478 WEdit *iret; 479 gboolean proc_ret = FALSE; 480 char *program_cline[2]; 481 int rounds = 0; 482 483 ip = g_new0 (WInstructionStation, 1); 484 if (ip == NULL) 485 return NULL; 486 487 iret = edit_init (EDIT (ip), y, x, lines, cols, NULL, 0, EDIT_DO_INIT_BASE_CLASS); 488 if (iret == NULL) 489 goto cleanup_and_err; 490 491 WIDGET (ip)->callback = instr_stat_callback; 492 WIDGET (ip)->mouse_callback = edit_mouse_callback; 493 EDIT (ip)->fullscreen = 0; 494 495 ip->io[0].name = g_strdup ("Std-In (WInstructionStation)"); 496 ip->io[1].name = g_strdup ("Std-Out (WInstructionStation)"); 497 ip->io[2].name = g_strdup ("Std-Error (WInstructionStation)"); 498 ip->io[0].fd = ip->io[1].fd = ip->io[2].fd = -1; 499 500 ip->prompt = g_strdup ("[guest@localhost]# "); 501 ip->prompt_span = strlen (ip->prompt); 502 ip->eprompt = g_strdup ("[guest@localhost]! "); 503 ip->eprompt_span = strlen (ip->eprompt); 504 505 /* Set initial program (most probably a shell, like Bash) */ 506 if (program != NULL) 507 ip->program = g_strdup (program); 508 else 509 /* Fallback instruction if no program given */ 510 ip->program = g_strdup ("bash"); 511 512 while (++rounds <= 2 && !proc_ret) 513 { 514 if (ip->error != NULL) 515 { 516 g_error_free (ip->error); 517 ip->error = NULL; 518 } 519 program_cline[0] = ip->program; 520 program_cline[1] = NULL; 521 proc_ret = g_spawn_async_with_pipes (NULL, program_cline, 522 NULL, G_SPAWN_SEARCH_PATH | 523 G_SPAWN_DO_NOT_REAP_CHILD | 524 G_SPAWN_LEAVE_DESCRIPTORS_OPEN, 525 NULL, NULL, &ip->proc_id, &ip->io[STDIN].fd, 526 &ip->io[STDOUT].fd, &ip->io[STDERR].fd, &ip->error); 527 528 if (!proc_ret) 529 { 530 char *new_program, *msg_text; 531 mc_log ("Creating the background process [program:%s] failed: %s", 532 program, ip->error ? ip->error->message : "<no error message>"); 533 534 /* Create a transatable, parametrized message */ 535 msg_text = g_strdup_printf ("%s%s:", _("The specified program has failed to run.\n" 536 "Enter a new full path or a program name"), 537 (rounds >= 2 ? _(" (last try)") : "")); 538 539 /* Display message asking for a new program */ 540 new_program = input_expand_dialog (_("Provide an alternate program to run"), 541 msg_text, "instruction-station", 542 alt_prog_first_run ? ip->program : INPUT_LAST_TEXT, 543 INPUT_COMPLETE_COMMANDS | INPUT_COMPLETE_FILENAMES | 544 INPUT_COMPLETE_VARIABLES); 545 g_free(msg_text); 546 alt_prog_first_run = FALSE; 547 548 /* Obtained a new program? */ 549 if (new_program != NULL) 550 { 551 g_free (ip->program); 552 ip->program = new_program; 553 } 554 } 555 } 556 557 /* If no program to run has been found, then exit. */ 558 if (!proc_ret) 559 { 560 message (D_ERROR, _("InstructionStation startup failed"), 561 _("Failed to initialize the CLI window.")); 562 goto cleanup_and_err; 563 } 564 565 /* Display initial prompt */ 566 instr_stat_show_prompt (ip, TRUE); 567 568 for (int i = 0; i <= STDERR; i++) 569 { 570 if (helper_configure_src_and_ch (&ip->io[i].ch, ip->io[i].fd, &ip->io[i].src_id, 571 (i == STDIN ? TRUE : FALSE), 572 (i == STDIN ? stdin_write_callback : stdout_read_callback), 573 ip, ip->io[i].name) == FALSE) 574 goto cleanup_and_err; 575 } 576 /* Set a process watcher and restarter for the program */ 577 ip->proc_src_id = g_child_watch_add (ip->proc_id, helper_program_ended_cb, ip); 578 579 return ip; 580 581 cleanup_and_err: 582 583 instr_release (ip, TRUE); 584 return NULL; 585 } 586 587 /* --------------------------------------------------------------------------------------------- */ 588 /* Check if widget is an WInstructionStation class. */ 589 590 gboolean 591 edit_widget_is_cli (const Widget * w) 592 { 593 return (w != NULL && w->callback == instr_stat_callback); 594 } 595 596 /* --------------------------------------------------------------------------------------------- */ 597 598 cb_ret_t 599 instr_stat_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data) 600 { 601 cb_ret_t ret = MSG_NOT_HANDLED; 602 WInstructionStation *ip = INSTR_STATION (w); 603 WEdit *e = EDIT (w); 604 605 switch (msg) 606 { 607 608 case MSG_KEY: 609 { 610 gboolean ext_mode; 611 long activity; 612 613 /* keep and then extmod flag */ 614 ext_mode = w->ext_mode; 615 activity = widget_lookup_key (w, parm); 616 w->ext_mode = ext_mode; 617 618 if (activity == CK_IgnoreKey) 619 w->ext_mode = FALSE; 620 else 621 { 622 ret = edit_dialog_command_execute (DIALOG(w->owner), activity); 623 if (ret == MSG_NOT_HANDLED) 624 ret = instr_stat_run_activity (ip, activity); 625 /* if activity was not handled, keep the extended mode 626 for the further key processing */ 627 if (ret == MSG_HANDLED) 628 w->ext_mode = FALSE; 629 } 630 631 /* 632 * Due to the "end of bracket" escape the editor sees input with is_idle() == false 633 * (expects more characters) and hence doesn't yet refresh the screen, but then 634 * no further characters arrive (there's only an "end of bracket" which is swallowed 635 * by tty_get_event()), so you end up with a screen that's not refreshed after pasting. 636 * So let's trigger an IDLE signal. 637 */ 638 if (!is_idle ()) 639 widget_idle (w, TRUE); 640 } 641 break; 642 case MSG_ACTION: 643 ret = instr_stat_run_activity (ip, parm); 644 break; 645 case MSG_IDLE: 646 edit_update_screen (e); 647 break; 648 case MSG_DESTROY: 649 instr_release(ip, FALSE); 650 break; 651 default: 652 break; 653 } 654 655 /* Route to editor window */ 656 if (ret == MSG_NOT_HANDLED) 657 { 658 ret = edit_callback (w, sender, msg, parm, data); 659 ip->cur_col = EDIT (w)->curs_col; 660 } 661 return ret; 662 } 663 664 /* --------------------------------------------------------------------------------------------- */ -
new file lib/widget/instr_station.h
diff --git a/lib/widget/instr_station.h b/lib/widget/instr_station.h new file mode 100644 index 000000000..d744d7b6e
- + 1 #ifndef MC__INSTR_STATION_H 2 #define MC__INSTR_STATION_H 3 4 #include <gio/gio.h> 5 6 #include "src/editor/editwidget.h" 7 8 /*** typedefs(not structures) and defined constants **********************************************/ 9 10 #define INSTR_STATION(x) ((WInstructionStation *)x) 11 #define CONST_INSTR_STATION(x) ((const WInstructionStation *)x) 12 13 /*** enums ***************************************************************************************/ 14 15 typedef enum instr_stat_io_type 16 { 17 STDIN = 0, 18 STDOUT, 19 STDERR 20 } instr_stat_io_type_t; 21 22 /*** structures declarations (and typedefs of structures)*****************************************/ 23 24 typedef struct 25 { 26 WEdit base; 27 28 int cur_line; 29 int cur_col; 30 int prompt_span; 31 int eprompt_span; 32 33 /* Shell (or other program) that is being run in station */ 34 char *program; 35 /* The prompt (a simulation) */ 36 char *prompt; 37 char *eprompt; 38 /* The current instruction to send */ 39 char *instruction; 40 41 /* An indicator of the prompt being printed after running an instruction */ 42 gboolean prompt_shown; 43 44 /* Process ID of the program */ 45 GPid proc_id; 46 47 /* A mark whether process ID is ready to be released */ 48 gboolean program_working; 49 50 /* Pipes to and from the program */ 51 struct 52 { 53 gint fd; 54 GIOChannel *ch; 55 guint src_id; 56 char *name; 57 } io[3]; 58 59 /* Time of last read of data from program */ 60 guint64 read_time; 61 62 /* GSource id (tag) of program process watcher */ 63 guint proc_src_id; 64 65 /* A GError placeholder */ 66 GError *error; 67 68 gboolean io_complete; 69 gboolean finalizing; 70 } WInstructionStation; 71 72 /*** global variables defined in .c file *********************************************************/ 73 74 /*** declarations of public functions ************************************************************/ 75 76 WInstructionStation *instr_stat_create (int y, int x, int lines, int cols, const char *program); 77 gboolean edit_widget_is_cli (const Widget * w); 78 cb_ret_t instr_stat_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data); 79 80 /*** inline functions ****************************************************************************/ 81 82 #endif /* MC__INSTR_STATION_H */ -
misc/mc.default.keymap
diff --git a/misc/mc.default.keymap b/misc/mc.default.keymap index 73b4c0eab..a7269d07f 100644
a b Sort = alt-t 352 352 Mail = alt-m 353 353 ParagraphFormat = alt-p 354 354 MatchBracket = alt-b 355 InstructionStation = alt-i 355 356 ExternalCommand = alt-u 356 357 UserMenu = f11 357 358 Menu = f9 -
misc/mc.emacs.keymap
diff --git a/misc/mc.emacs.keymap b/misc/mc.emacs.keymap index 955929444..98412b75f 100644
a b Sort = alt-t 351 351 # Mail = 352 352 ParagraphFormat = alt-p 353 353 # MatchBracket = 354 InstructionStation = alt-i 354 355 ExternalCommand = alt-u 355 356 UserMenu = f11 356 357 Menu = f9 -
src/editor/edit-impl.h
diff --git a/src/editor/edit-impl.h b/src/editor/edit-impl.h index 881ef549b..eedd98952 100644
a b typedef enum 88 88 LB_MAC 89 89 } LineBreaks; 90 90 91 typedef enum 92 { 93 EDIT_DO_INIT_BASE_CLASS = 1 << 0, 94 95 } edit_init_flags_t; 96 91 97 typedef enum 92 98 { 93 99 EDIT_QUICK_SAVE = 0, … … extern char *edit_window_state_char; 146 152 extern char *edit_window_close_char; 147 153 148 154 /*** declarations of public functions ************************************************************/ 155 cb_ret_t edit_dialog_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data); 156 cb_ret_t edit_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data); 157 cb_ret_t edit_dialog_command_execute (WDialog * h, long command); 158 159 void edit_mouse_callback (Widget * w, mouse_msg_t msg, mouse_event_t * event); 149 160 150 161 gboolean edit_add_window (WDialog * h, int y, int x, int lines, int cols, 151 162 const vfs_path_t * f, long fline); … … void edit_move_to_prev_col (WEdit * edit, off_t p); 169 180 long edit_get_col (const WEdit * edit); 170 181 void edit_update_curs_row (WEdit * edit); 171 182 void edit_update_curs_col (WEdit * edit); 183 gboolean edit_newline_end_check_only (const WEdit * edit); 172 184 void edit_find_bracket (WEdit * edit); 173 185 gboolean edit_reload_line (WEdit * edit, const vfs_path_t * filename_vpath, long line); 174 186 void edit_set_codeset (WEdit * edit); … … void edit_delete_line (WEdit * edit); 180 192 181 193 int edit_delete (WEdit * edit, gboolean byte_delete); 182 194 int edit_backspace (WEdit * edit, gboolean byte_delete); 195 void edit_insert_string (WEdit * edit, char *str_text, gsize len); 183 196 void edit_insert (WEdit * edit, int c); 184 197 void edit_insert_over (WEdit * edit); 185 198 void edit_cursor_move (WEdit * edit, off_t increment); … … char *edit_get_write_filter (const vfs_path_t * write_name_vpath, 193 206 gboolean edit_save_confirm_cmd (WEdit * edit); 194 207 gboolean edit_save_as_cmd (WEdit * edit); 195 208 WEdit *edit_init (WEdit * edit, int y, int x, int lines, int cols, 196 const vfs_path_t * filename_vpath, long line );209 const vfs_path_t * filename_vpath, long line, edit_init_flags_t flags); 197 210 gboolean edit_clean (WEdit * edit); 198 211 gboolean edit_ok_to_exit (WEdit * edit); 199 212 file_suitable_rank_t edit_check_file_suitable (const vfs_path_t * fs_path); -
src/editor/edit.c
diff --git a/src/editor/edit.c b/src/editor/edit.c index 8477939aa..ea193a8de 100644
a b edit_modification (WEdit * edit) 652 652 { 653 653 edit->caches_valid = FALSE; 654 654 655 /* raise lock when file modified */656 if ( !edit->modified && !edit->delete_file)655 /* raise lock when file is about to be modified */ 656 if (edit->filename_vpath && !edit->modified && !edit->delete_file) 657 657 edit->locked = lock_file (edit->filename_vpath); 658 658 edit->modified = 1; 659 659 } … … edit_insert_file (WEdit * edit, const vfs_path_t * filename_vpath) 2106 2106 2107 2107 WEdit * 2108 2108 edit_init (WEdit * edit, int y, int x, int lines, int cols, const vfs_path_t * filename_vpath, 2109 long line )2109 long line, edit_init_flags_t flags) 2110 2110 { 2111 2111 gboolean to_free = FALSE; 2112 2112 … … edit_init (WEdit * edit, int y, int x, int lines, int cols, const vfs_path_t * f 2128 2128 edit->fullscreen = fullscreen; 2129 2129 edit->loc_prev = loc_prev; 2130 2130 } 2131 else2131 if (has_flag (flags, EDIT_DO_INIT_BASE_CLASS) || edit == NULL) 2132 2132 { 2133 2133 Widget *w; 2134 edit = g_malloc0 (sizeof (WEdit)); 2135 to_free = TRUE; 2134 if (edit == NULL) 2135 { 2136 edit = g_malloc0 (sizeof (WEdit)); 2137 to_free = TRUE; 2138 } 2136 2139 2137 2140 w = WIDGET (edit); 2138 2141 widget_init (w, y, x, lines, cols, NULL, NULL); … … edit_reload_line (WEdit * edit, const vfs_path_t * filename_vpath, long line) 2271 2274 e->fullscreen = edit->fullscreen; 2272 2275 e->loc_prev = edit->loc_prev; 2273 2276 2274 if (edit_init (e, w->y, w->x, w->lines, w->cols, filename_vpath, line ) == NULL)2277 if (edit_init (e, w->y, w->x, w->lines, w->cols, filename_vpath, line, 0) == NULL) 2275 2278 { 2276 2279 g_free (e); 2277 2280 return FALSE; … … edit_push_redo_action (WEdit * edit, long c) 2528 2531 edit->redo_stack_bottom = edit->redo_stack_pointer = 0; 2529 2532 } 2530 2533 2534 /* --------------------------------------------------------------------------------------------- */ 2535 2536 void 2537 edit_insert_string (WEdit * edit, char *str_text, gsize len) 2538 { 2539 size_t i; 2540 for (i = 0; i < len; i++) 2541 edit_insert (edit, str_text[i]); 2542 } 2543 2531 2544 /* --------------------------------------------------------------------------------------------- */ 2532 2545 /** 2533 2546 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 be58f3db7..7318aebd5 100644
a b edit_complete_word_insert_recoded_completion (WEdit * edit, char *completion, gs 1573 1573 /*** public functions ****************************************************************************/ 1574 1574 /* --------------------------------------------------------------------------------------------- */ 1575 1575 1576 gboolean 1577 edit_newline_end_check_only (const WEdit * e) 1578 { 1579 const edit_buffer_t *buf = &e->buffer; 1580 return (buf->size > 0 && edit_buffer_get_byte (buf, buf->size - 1) == '\n'); 1581 } 1582 1583 /* --------------------------------------------------------------------------------------------- */ 1584 1576 1585 void 1577 1586 edit_refresh_cmd (void) 1578 1587 { -
src/editor/editdraw.c
diff --git a/src/editor/editdraw.c b/src/editor/editdraw.c index 61bbdcbee..80495dcd0 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 c20e9fb7e..0c8e60801 100644
a b create_window_menu (void) 238 238 entries = g_list_prepend (entries, menu_entry_create (_("&Next"), CK_WindowNext)); 239 239 entries = g_list_prepend (entries, menu_entry_create (_("&Previous"), CK_WindowPrev)); 240 240 entries = g_list_prepend (entries, menu_entry_create (_("&List..."), CK_WindowList)); 241 entries = 242 g_list_prepend (entries, 243 menu_entry_create (_("Instr&uction Station"), CK_InstructionStation)); 241 244 242 245 return g_list_reverse (entries); 243 246 } -
src/editor/editwidget.c
diff --git a/src/editor/editwidget.c b/src/editor/editwidget.c index e32541cd9..41ac2917a 100644
a b 68 68 #ifdef HAVE_ASPELL 69 69 #include "spell.h" 70 70 #endif 71 #include "lib/widget/instr_station.h" 71 72 72 73 /*** global variables ****************************************************************************/ 73 74 … … static unsigned int edit_dlg_init_refcounter = 0; 86 87 87 88 /*** file scope functions ************************************************************************/ 88 89 89 static cb_ret_t edit_dialog_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, 90 void *data); 90 /* --------------------------------------------------------------------------------------------- */ 91 /* Creates a CLI special window, windowed (not fullscreen) */ 92 93 static gboolean 94 edit_add_instr_stat_window (WDialog * h) 95 { 96 WInstructionStation *ip; 97 ip = instr_stat_create (3, 10, 17, 80, "/bin/bash"); 98 if (ip == NULL) 99 return FALSE; 100 group_add_widget_autopos (GROUP (h), ip, WPOS_KEEP_ALL, NULL); 101 widget_draw (WIDGET (h)); 102 return TRUE; 103 } 91 104 92 105 /* --------------------------------------------------------------------------------------------- */ 93 106 … … edit_get_title (const WDialog * h, size_t len) 634 647 return g_strconcat (_("Edit: "), modified, file_label, (char *) NULL); 635 648 } 636 649 637 /* --------------------------------------------------------------------------------------------- */638 639 static cb_ret_t640 edit_dialog_command_execute (WDialog * h, long command)641 {642 WGroup *g = GROUP (h);643 Widget *wh = WIDGET (h);644 cb_ret_t ret = MSG_HANDLED;645 646 switch (command)647 {648 case CK_EditNew:649 edit_add_window (h, wh->y + 1, wh->x, wh->lines - 2, wh->cols, NULL, 0);650 break;651 case CK_EditFile:652 edit_load_cmd (h, NULL);653 break;654 case CK_OtherFile:655 {656 WEdit *e = (WEdit *) g->current->data;657 gboolean retflag = FALSE;658 659 if (e != NULL && edit_widget_is_editor (CONST_WIDGET (e)))660 {661 retflag = edit_compute_other_file_vfs_path (e);662 if (retflag)663 retflag = edit_switch_to_file (h, e->otherfile_vpath);664 }665 if (!retflag)666 ret = MSG_NOT_HANDLED;667 }668 break;669 case CK_History:670 edit_load_file_from_history (h);671 break;672 case CK_EditSyntaxFile:673 edit_load_syntax_file (h);674 break;675 case CK_EditUserMenu:676 edit_load_menu_file (h);677 break;678 case CK_Close:679 /* if there are no opened files anymore, close MC editor */680 if (edit_widget_is_editor (CONST_WIDGET (g->current->data)) &&681 edit_close_cmd ((WEdit *) g->current->data) && find_editor (h) == NULL)682 dlg_stop (h);683 break;684 case CK_Help:685 edit_help ();686 /* edit->force |= REDRAW_COMPLETELY; */687 break;688 case CK_Menu:689 edit_menu_cmd (h);690 break;691 case CK_Quit:692 case CK_Cancel:693 /* don't close editor due to SIGINT, but stop move/resize window */694 {695 Widget *w = WIDGET (g->current->data);696 697 if (edit_widget_is_editor (w) && ((WEdit *) w)->drag_state != MCEDIT_DRAG_NONE)698 edit_restore_size ((WEdit *) w);699 else if (command == CK_Quit)700 dlg_stop (h);701 }702 break;703 case CK_About:704 edit_about ();705 break;706 case CK_SyntaxOnOff:707 edit_syntax_onoff_cmd (h);708 break;709 case CK_ShowTabTws:710 edit_show_tabs_tws_cmd (h);711 break;712 case CK_ShowMargin:713 edit_show_margin_cmd (h);714 break;715 case CK_ShowNumbers:716 edit_show_numbers_cmd (h);717 break;718 case CK_Refresh:719 edit_refresh_cmd ();720 break;721 case CK_Shell:722 toggle_subshell ();723 break;724 case CK_LearnKeys:725 learn_keys ();726 break;727 case CK_WindowMove:728 case CK_WindowResize:729 if (edit_widget_is_editor (CONST_WIDGET (g->current->data)))730 edit_handle_move_resize ((WEdit *) g->current->data, command);731 break;732 case CK_WindowList:733 edit_window_list (h);734 break;735 case CK_WindowCascade:736 edit_window_cascade (h);737 break;738 case CK_WindowTile:739 edit_window_tile (h);740 break;741 case CK_WindowNext:742 group_select_next_widget (g);743 break;744 case CK_WindowPrev:745 group_select_prev_widget (g);746 break;747 case CK_Options:748 edit_options_dialog (h);749 break;750 case CK_OptionsSaveMode:751 edit_save_mode_cmd ();752 break;753 case CK_SaveSetup:754 save_setup_cmd ();755 break;756 default:757 ret = MSG_NOT_HANDLED;758 break;759 }760 761 return ret;762 }763 764 650 /* --------------------------------------------------------------------------------------------- */ 765 651 /* 766 652 * Translate the keycode into either 'command' or 'char_for_insertion'. … … edit_update_cursor (WEdit * edit, const mouse_event_t * event) 1019 905 } 1020 906 1021 907 /* --------------------------------------------------------------------------------------------- */ 1022 /** Callback for the edit dialog */ 908 909 /** 910 * Handle mouse events of editor screen. 911 * 912 * @param w Widget object (the editor) 913 * @param msg mouse event message 914 * @param event mouse event data 915 */ 916 static void 917 edit_dialog_mouse_callback (Widget * w, mouse_msg_t msg, mouse_event_t * event) 918 { 919 gboolean unhandled = TRUE; 920 921 if (msg == MSG_MOUSE_DOWN && event->y == 0) 922 { 923 WGroup *g = GROUP (w); 924 WDialog *h = DIALOG (w); 925 WMenuBar *b; 926 927 b = find_menubar (h); 928 929 if (!widget_get_state (WIDGET (b), WST_FOCUSED)) 930 { 931 /* menubar */ 932 933 GList *l; 934 GList *top = NULL; 935 int x; 936 937 /* Try find top fullscreen window */ 938 for (l = g->widgets; l != NULL; l = g_list_next (l)) 939 if (edit_widget_is_editor (CONST_WIDGET (l->data)) 940 && ((WEdit *) l->data)->fullscreen) 941 top = l; 942 943 /* Handle fullscreen/close buttons in the top line */ 944 x = w->cols - 6; 945 946 if (top != NULL && event->x >= x) 947 { 948 WEdit *e = (WEdit *) top->data; 949 950 if (top != g->current) 951 { 952 /* Window is not active. Activate it */ 953 widget_select (WIDGET (e)); 954 } 955 956 /* Handle buttons */ 957 if (event->x - x <= 2) 958 edit_toggle_fullscreen (e); 959 else 960 send_message (h, NULL, MSG_ACTION, CK_Close, NULL); 961 962 unhandled = FALSE; 963 } 964 965 if (unhandled) 966 menubar_activate (b, drop_menus, -1); 967 } 968 } 969 970 /* Continue handling of unhandled event in window or menu */ 971 event->result.abort = unhandled; 972 } 973 974 /* --------------------------------------------------------------------------------------------- */ 1023 975 1024 976 static cb_ret_t 977 edit_dialog_bg_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data) 978 { 979 switch (msg) 980 { 981 case MSG_INIT: 982 { 983 Widget *wo = WIDGET (w->owner); 984 985 w->y = wo->y + 1; 986 w->x = wo->x; 987 w->lines = wo->lines - 2; 988 w->cols = wo->cols; 989 w->pos_flags |= WPOS_KEEP_ALL; 990 991 return MSG_HANDLED; 992 } 993 994 default: 995 return background_callback (w, sender, msg, parm, data); 996 } 997 } 998 999 /* --------------------------------------------------------------------------------------------- */ 1000 1001 /** 1002 * Handle move/resize mouse events. 1003 */ 1004 static void 1005 edit_mouse_handle_move_resize (Widget * w, mouse_msg_t msg, mouse_event_t * event) 1006 { 1007 WEdit *edit = (WEdit *) (w); 1008 Widget *h = WIDGET (w->owner); 1009 int global_x, global_y; 1010 1011 if (msg == MSG_MOUSE_UP) 1012 { 1013 /* Exit move/resize mode. */ 1014 edit_execute_cmd (edit, CK_Enter, -1); 1015 edit_update_screen (edit); /* Paint the buttonbar over our possibly overlapping frame. */ 1016 return; 1017 } 1018 1019 if (msg != MSG_MOUSE_DRAG) 1020 /** 1021 * We ignore any other events. Specifically, MSG_MOUSE_DOWN. 1022 * 1023 * When the move/resize is initiated by the menu, we let the user 1024 * stop it by clicking with the mouse. Which is why we don't want 1025 * a mouse down to affect the window. 1026 */ 1027 return; 1028 1029 /* Convert point to global coordinates for easier calculations. */ 1030 global_x = event->x + w->x; 1031 global_y = event->y + w->y; 1032 1033 /* Clamp the point to the dialog's client area. */ 1034 global_y = CLAMP (global_y, h->y + 1, h->y + h->lines - 2); /* Status line, buttonbar */ 1035 global_x = CLAMP (global_x, h->x, h->x + h->cols - 1); /* Currently a no-op, as the dialog has no left/right margins. */ 1036 1037 if (edit->drag_state == MCEDIT_DRAG_MOVE) 1038 { 1039 w->y = global_y; 1040 w->x = global_x - edit->drag_state_start; 1041 } 1042 else if (edit->drag_state == MCEDIT_DRAG_RESIZE) 1043 { 1044 w->lines = MAX (WINDOW_MIN_LINES, global_y - w->y + 1); 1045 w->cols = MAX (WINDOW_MIN_COLS, global_x - w->x + 1); 1046 } 1047 1048 edit->force |= REDRAW_COMPLETELY; /* Not really needed as WEdit's MSG_DRAW already does this. */ 1049 1050 /* We draw the whole dialog because dragging/resizing exposes area beneath. */ 1051 widget_draw (WIDGET (w->owner)); 1052 } 1053 1054 /* --------------------------------------------------------------------------------------------- */ 1055 /*** public functions ****************************************************************************/ 1056 /* --------------------------------------------------------------------------------------------- */ 1057 1058 cb_ret_t 1059 edit_dialog_command_execute (WDialog * h, long command) 1060 { 1061 WGroup *g = GROUP (h); 1062 Widget *wh = WIDGET (h); 1063 cb_ret_t ret = MSG_HANDLED; 1064 1065 switch (command) 1066 { 1067 case CK_EditNew: 1068 edit_add_window (h, wh->y + 1, wh->x, wh->lines - 2, wh->cols, NULL, 0); 1069 break; 1070 case CK_EditFile: 1071 edit_load_cmd (h, NULL); 1072 break; 1073 case CK_OtherFile: 1074 { 1075 WEdit *e = (WEdit *) g->current->data; 1076 gboolean retflag = FALSE; 1077 1078 if (e != NULL && edit_widget_is_editor (CONST_WIDGET (e))) 1079 { 1080 retflag = edit_compute_other_file_vfs_path (e); 1081 if (retflag) 1082 retflag = edit_switch_to_file (h, e->otherfile_vpath); 1083 } 1084 if (!retflag) 1085 ret = MSG_NOT_HANDLED; 1086 } 1087 break; 1088 case CK_History: 1089 edit_load_file_from_history (h); 1090 break; 1091 case CK_EditSyntaxFile: 1092 edit_load_syntax_file (h); 1093 break; 1094 case CK_EditUserMenu: 1095 edit_load_menu_file (h); 1096 break; 1097 case CK_Close: 1098 /* if there are no opened files anymore, close MC editor */ 1099 if ((edit_widget_is_editor (CONST_WIDGET (g->current->data)) || 1100 edit_widget_is_cli(CONST_WIDGET(g->current->data))) && 1101 edit_close_cmd ((WEdit *) g->current->data) && find_editor (h) == NULL) 1102 dlg_stop (h); 1103 break; 1104 case CK_Help: 1105 edit_help (); 1106 /* edit->force |= REDRAW_COMPLETELY; */ 1107 break; 1108 case CK_Menu: 1109 edit_menu_cmd (h); 1110 break; 1111 case CK_Quit: 1112 case CK_Cancel: 1113 /* don't close editor due to SIGINT, but stop move/resize window */ 1114 { 1115 Widget *w = WIDGET (g->current->data); 1116 1117 if (edit_widget_is_editor (w) && ((WEdit *) w)->drag_state != MCEDIT_DRAG_NONE) 1118 edit_restore_size ((WEdit *) w); 1119 else if (command == CK_Quit) 1120 dlg_stop (h); 1121 } 1122 break; 1123 case CK_About: 1124 edit_about (); 1125 break; 1126 case CK_SyntaxOnOff: 1127 edit_syntax_onoff_cmd (h); 1128 break; 1129 case CK_ShowTabTws: 1130 edit_show_tabs_tws_cmd (h); 1131 break; 1132 case CK_ShowMargin: 1133 edit_show_margin_cmd (h); 1134 break; 1135 case CK_ShowNumbers: 1136 edit_show_numbers_cmd (h); 1137 break; 1138 case CK_Refresh: 1139 edit_refresh_cmd (); 1140 break; 1141 case CK_InstructionStation: 1142 edit_add_instr_stat_window (h); 1143 break; 1144 case CK_Shell: 1145 toggle_subshell (); 1146 break; 1147 case CK_LearnKeys: 1148 learn_keys (); 1149 break; 1150 case CK_WindowMove: 1151 case CK_WindowResize: 1152 if (edit_widget_is_editor (CONST_WIDGET (g->current->data))) 1153 edit_handle_move_resize ((WEdit *) g->current->data, command); 1154 break; 1155 case CK_WindowList: 1156 edit_window_list (h); 1157 break; 1158 case CK_WindowCascade: 1159 edit_window_cascade (h); 1160 break; 1161 case CK_WindowTile: 1162 edit_window_tile (h); 1163 break; 1164 case CK_WindowNext: 1165 group_select_next_widget (g); 1166 break; 1167 case CK_WindowPrev: 1168 group_select_prev_widget (g); 1169 break; 1170 case CK_Options: 1171 edit_options_dialog (h); 1172 break; 1173 case CK_OptionsSaveMode: 1174 edit_save_mode_cmd (); 1175 break; 1176 case CK_SaveSetup: 1177 save_setup_cmd (); 1178 break; 1179 default: 1180 ret = MSG_NOT_HANDLED; 1181 break; 1182 } 1183 1184 return ret; 1185 } 1186 1187 /* --------------------------------------------------------------------------------------------- */ 1188 /** Callback for the edit dialog */ 1189 1190 cb_ret_t 1025 1191 edit_dialog_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data) 1026 1192 { 1027 1193 WGroup *g = GROUP (w); … … edit_dialog_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, v 1116 1282 1117 1283 /* --------------------------------------------------------------------------------------------- */ 1118 1284 1119 /** 1120 * Handle mouse events of editor screen. 1121 * 1122 * @param w Widget object (the editor) 1123 * @param msg mouse event message 1124 * @param event mouse event data 1125 */ 1126 static void 1127 edit_dialog_mouse_callback (Widget * w, mouse_msg_t msg, mouse_event_t * event) 1128 { 1129 gboolean unhandled = TRUE; 1130 1131 if (msg == MSG_MOUSE_DOWN && event->y == 0) 1132 { 1133 WGroup *g = GROUP (w); 1134 WDialog *h = DIALOG (w); 1135 WMenuBar *b; 1136 1137 b = find_menubar (h); 1138 1139 if (!widget_get_state (WIDGET (b), WST_FOCUSED)) 1140 { 1141 /* menubar */ 1142 1143 GList *l; 1144 GList *top = NULL; 1145 int x; 1146 1147 /* Try find top fullscreen window */ 1148 for (l = g->widgets; l != NULL; l = g_list_next (l)) 1149 if (edit_widget_is_editor (CONST_WIDGET (l->data)) 1150 && ((WEdit *) l->data)->fullscreen) 1151 top = l; 1152 1153 /* Handle fullscreen/close buttons in the top line */ 1154 x = w->cols - 6; 1155 1156 if (top != NULL && event->x >= x) 1157 { 1158 WEdit *e = (WEdit *) top->data; 1159 1160 if (top != g->current) 1161 { 1162 /* Window is not active. Activate it */ 1163 widget_select (WIDGET (e)); 1164 } 1165 1166 /* Handle buttons */ 1167 if (event->x - x <= 2) 1168 edit_toggle_fullscreen (e); 1169 else 1170 send_message (h, NULL, MSG_ACTION, CK_Close, NULL); 1171 1172 unhandled = FALSE; 1173 } 1174 1175 if (unhandled) 1176 menubar_activate (b, drop_menus, -1); 1177 } 1178 } 1179 1180 /* Continue handling of unhandled event in window or menu */ 1181 event->result.abort = unhandled; 1182 } 1183 1184 /* --------------------------------------------------------------------------------------------- */ 1185 1186 static cb_ret_t 1187 edit_dialog_bg_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data) 1188 { 1189 switch (msg) 1190 { 1191 case MSG_INIT: 1192 { 1193 Widget *wo = WIDGET (w->owner); 1194 1195 w->y = wo->y + 1; 1196 w->x = wo->x; 1197 w->lines = wo->lines - 2; 1198 w->cols = wo->cols; 1199 w->pos_flags |= WPOS_KEEP_ALL; 1200 1201 return MSG_HANDLED; 1202 } 1203 1204 default: 1205 return background_callback (w, sender, msg, parm, data); 1206 } 1207 } 1208 1209 /* --------------------------------------------------------------------------------------------- */ 1210 1211 static cb_ret_t 1285 cb_ret_t 1212 1286 edit_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data) 1213 1287 { 1214 1288 WEdit *e = (WEdit *) w; … … edit_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *da 1278 1352 1279 1353 /* --------------------------------------------------------------------------------------------- */ 1280 1354 1281 /**1282 * Handle move/resize mouse events.1283 */1284 static void1285 edit_mouse_handle_move_resize (Widget * w, mouse_msg_t msg, mouse_event_t * event)1286 {1287 WEdit *edit = (WEdit *) (w);1288 Widget *h = WIDGET (w->owner);1289 int global_x, global_y;1290 1291 if (msg == MSG_MOUSE_UP)1292 {1293 /* Exit move/resize mode. */1294 edit_execute_cmd (edit, CK_Enter, -1);1295 edit_update_screen (edit); /* Paint the buttonbar over our possibly overlapping frame. */1296 return;1297 }1298 1299 if (msg != MSG_MOUSE_DRAG)1300 /**1301 * We ignore any other events. Specifically, MSG_MOUSE_DOWN.1302 *1303 * When the move/resize is initiated by the menu, we let the user1304 * stop it by clicking with the mouse. Which is why we don't want1305 * a mouse down to affect the window.1306 */1307 return;1308 1309 /* Convert point to global coordinates for easier calculations. */1310 global_x = event->x + w->x;1311 global_y = event->y + w->y;1312 1313 /* Clamp the point to the dialog's client area. */1314 global_y = CLAMP (global_y, h->y + 1, h->y + h->lines - 2); /* Status line, buttonbar */1315 global_x = CLAMP (global_x, h->x, h->x + h->cols - 1); /* Currently a no-op, as the dialog has no left/right margins. */1316 1317 if (edit->drag_state == MCEDIT_DRAG_MOVE)1318 {1319 w->y = global_y;1320 w->x = global_x - edit->drag_state_start;1321 }1322 else if (edit->drag_state == MCEDIT_DRAG_RESIZE)1323 {1324 w->lines = MAX (WINDOW_MIN_LINES, global_y - w->y + 1);1325 w->cols = MAX (WINDOW_MIN_COLS, global_x - w->x + 1);1326 }1327 1328 edit->force |= REDRAW_COMPLETELY; /* Not really needed as WEdit's MSG_DRAW already does this. */1329 1330 /* We draw the whole dialog because dragging/resizing exposes area beneath. */1331 widget_draw (WIDGET (w->owner));1332 }1333 1334 /* --------------------------------------------------------------------------------------------- */1335 1336 1355 /** 1337 1356 * Handle mouse events of editor window 1338 1357 * … … edit_mouse_handle_move_resize (Widget * w, mouse_msg_t msg, mouse_event_t * even 1340 1359 * @param msg mouse event message 1341 1360 * @param event mouse event data 1342 1361 */ 1343 staticvoid1362 void 1344 1363 edit_mouse_callback (Widget * w, mouse_msg_t msg, mouse_event_t * event) 1345 1364 { 1346 1365 WEdit *edit = (WEdit *) w; … … edit_mouse_callback (Widget * w, mouse_msg_t msg, mouse_event_t * event) 1454 1473 } 1455 1474 } 1456 1475 1457 /* --------------------------------------------------------------------------------------------- */1458 /*** public functions ****************************************************************************/1459 1476 /* --------------------------------------------------------------------------------------------- */ 1460 1477 1461 1478 gboolean … … edit_add_window (WDialog * h, int y, int x, int lines, int cols, const vfs_path_ 1686 1703 WEdit *edit; 1687 1704 Widget *w; 1688 1705 1689 edit = edit_init (NULL, y, x, lines, cols, f, fline );1706 edit = edit_init (NULL, y, x, lines, cols, f, fline, 0); 1690 1707 if (edit == NULL) 1691 1708 return FALSE; 1692 1709 -
src/editor/editwidget.h
diff --git a/src/editor/editwidget.h b/src/editor/editwidget.h index b4b10692e..a80057393 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 ***************************************************************************************/ -
src/history.h
diff --git a/src/history.h b/src/history.h index 7a8d73fa2..738d75c66 100644
a b 17 17 #define MC_HISTORY_EDIT_SORT "mc.edit.sort" 18 18 #define MC_HISTORY_EDIT_PASTE_EXTCMD "mc.edit.paste-extcmd" 19 19 #define MC_HISTORY_EDIT_REPEAT "mc.edit.repeat-action" 20 #define MC_HISTORY_EDIT_INSTR_STATION_PATH "mc.edit.instr-panel-path" 20 21 21 22 #define MC_HISTORY_FM_VIEW_FILE "mc.fm.view-file" 22 23 #define MC_HISTORY_FM_MKDIR "mc.fm.mkdir" -
src/keybind-defaults.c
diff --git a/src/keybind-defaults.c b/src/keybind-defaults.c index db483382a..c0cede558 100644
a b static const global_keymap_ini_t default_editor_keymap[] = { 478 478 {"FileNext", "alt-plus"}, 479 479 {"Sort", "alt-t"}, 480 480 {"Mail", "alt-m"}, 481 {"InstructionStation", "alt-i"}, 481 482 {"ExternalCommand", "alt-u"}, 482 483 {"WindowMove", "ctrl-alt-e"}, 483 484 {"WindowResize", "ctrl-alt-s"},