code clean up
[midnight-commander.git] / src / viewer / actions_cmd.c
blobe8d5fefb1be63aa7329fd64a0ae82eb8286d6206
1 /*
2 Internal file viewer for the Midnight Commander
3 Callback function for some actions (hotkeys, menu)
5 Copyright (C) 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003,
6 2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc.
8 Written by: 1994, 1995, 1998 Miguel de Icaza
9 1994, 1995 Janne Kukonlehto
10 1995 Jakub Jelinek
11 1996 Joseph M. Hinkle
12 1997 Norbert Warmuth
13 1998 Pavel Machek
14 2004 Roland Illig <roland.illig@gmx.de>
15 2005 Roland Illig <roland.illig@gmx.de>
16 2009 Slava Zanko <slavazanko@google.com>
17 2009 Andrew Borodin <aborodin@vmail.ru>
18 2009 Ilia Maslakov <il.smind@gmail.com>
20 This file is part of the Midnight Commander.
22 The Midnight Commander is free software; you can redistribute it
23 and/or modify it under the terms of the GNU General Public License as
24 published by the Free Software Foundation; either version 2 of the
25 License, or (at your option) any later version.
27 The Midnight Commander is distributed in the hope that it will be
28 useful, but WITHOUT ANY WARRANTY; without even the implied warranty
29 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
30 General Public License for more details.
32 You should have received a copy of the GNU General Public License
33 along with this program; if not, write to the Free Software
34 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
35 MA 02110-1301, USA.
39 The functions in this section can be bound to hotkeys. They are all
40 of the same type (taking a pointer to mcview_t as parameter and
41 returning void). TODO: In the not-too-distant future, these commands
42 will become fully configurable, like they already are in the
43 internal editor. By convention, all the function names end in
44 "_cmd".
47 #include <config.h>
49 #include <errno.h>
50 #include <stdlib.h>
52 #include "../src/global.h"
53 #include "../src/panel.h"
54 #include "../src/layout.h"
55 #include "../src/wtools.h"
56 #include "../src/history.h"
57 #include "../src/charsets.h"
58 #include "../src/tty/tty.h"
59 #include "../src/tty/key.h"
60 #include "../src/cmd.h"
61 #include "../src/execute.h"
62 #include "../src/help.h"
63 #include "internal.h"
64 #include "mcviewer.h"
66 /*** global variables ****************************************************************************/
68 /*** file scope macro definitions ****************************************************************/
70 /*** file scope type declarations ****************************************************************/
72 /*** file scope variables ************************************************************************/
74 /*** file scope functions ************************************************************************/
76 /* --------------------------------------------------------------------------------------------- */
78 static void
79 mcview_continue_search_cmd (mcview_t * view)
81 if (view->last_search_string != NULL) {
82 mcview_do_search (view);
83 } else {
84 /* if not... then ask for an expression */
85 mcview_search_cmd (view);
89 /* --------------------------------------------------------------------------------------------- */
90 static cb_ret_t
91 mcview_handle_editkey (mcview_t * view, int key)
93 struct hexedit_change_node *node;
94 int byte_val;
96 /* Has there been a change at this position? */
97 node = view->change_list;
98 while (node && (node->offset != view->hex_cursor))
99 node = node->next;
101 if (!view->hexview_in_text) {
102 /* Hex editing */
103 unsigned int hexvalue = 0;
105 if (key >= '0' && key <= '9')
106 hexvalue = 0 + (key - '0');
107 else if (key >= 'A' && key <= 'F')
108 hexvalue = 10 + (key - 'A');
109 else if (key >= 'a' && key <= 'f')
110 hexvalue = 10 + (key - 'a');
111 else
112 return MSG_NOT_HANDLED;
114 if (node)
115 byte_val = node->value;
116 else
117 mcview_get_byte (view, view->hex_cursor, &byte_val);
119 if (view->hexedit_lownibble) {
120 byte_val = (byte_val & 0xf0) | (hexvalue);
121 } else {
122 byte_val = (byte_val & 0x0f) | (hexvalue << 4);
124 } else {
125 /* Text editing */
126 if (key < 256 && ((key == '\n') || is_printable (key)))
127 byte_val = key;
128 else
129 return MSG_NOT_HANDLED;
131 if (!node) {
132 node = g_new (struct hexedit_change_node, 1);
133 node->offset = view->hex_cursor;
134 node->value = byte_val;
135 mcview_enqueue_change (&view->change_list, node);
136 } else {
137 node->value = byte_val;
139 view->dirty++;
140 mcview_update (view);
141 mcview_move_right (view, 1);
142 return MSG_HANDLED;
145 /* --------------------------------------------------------------------------------------------- */
147 /* Check for left and right arrows, possibly with modifiers */
148 static cb_ret_t
149 mcview_check_left_right_keys (mcview_t * view, int c)
151 if (c == KEY_LEFT) {
152 mcview_move_left (view, 1);
153 return MSG_HANDLED;
156 if (c == KEY_RIGHT) {
157 mcview_move_right (view, 1);
158 return MSG_HANDLED;
161 /* Ctrl with arrows moves by 10 postions in the unwrap mode */
162 if (view->hex_mode || view->text_wrap_mode)
163 return MSG_NOT_HANDLED;
165 if (c == (KEY_M_CTRL | KEY_LEFT)) {
166 if (view->dpy_text_column >= 10)
167 view->dpy_text_column -= 10;
168 else
169 view->dpy_text_column = 0;
170 view->dirty++;
171 return MSG_HANDLED;
174 if (c == (KEY_M_CTRL | KEY_RIGHT)) {
175 if (view->dpy_text_column <= OFFSETTYPE_MAX - 10)
176 view->dpy_text_column += 10;
177 else
178 view->dpy_text_column = OFFSETTYPE_MAX;
179 view->dirty++;
180 return MSG_HANDLED;
183 return MSG_NOT_HANDLED;
186 /* --------------------------------------------------------------------------------------------- */
188 static void
189 mcview_cmk_move_up (void *w, int n)
191 mcview_move_up ((mcview_t *) w, n);
194 /* --------------------------------------------------------------------------------------------- */
196 static void
197 mcview_cmk_move_down (void *w, int n)
199 mcview_move_down ((mcview_t *) w, n);
202 /* --------------------------------------------------------------------------------------------- */
204 static void
205 mcview_cmk_moveto_top (void *w, int n)
207 (void) &n;
208 mcview_moveto_top ((mcview_t *) w);
211 /* --------------------------------------------------------------------------------------------- */
213 static void
214 mcview_cmk_moveto_bottom (void *w, int n)
216 (void) &n;
217 mcview_moveto_bottom ((mcview_t *) w);
220 /* --------------------------------------------------------------------------------------------- */
222 static void
223 mcview_hook (void *v)
225 mcview_t *view = (mcview_t *) v;
226 WPanel *panel;
228 /* If the user is busy typing, wait until he finishes to update the
229 screen */
230 if (!is_idle ()) {
231 if (!hook_present (idle_hook, mcview_hook))
232 add_hook (&idle_hook, mcview_hook, v);
233 return;
236 delete_hook (&idle_hook, mcview_hook);
238 if (get_current_type () == view_listing)
239 panel = current_panel;
240 else if (get_other_type () == view_listing)
241 panel = other_panel;
242 else
243 return;
245 mcview_load (view, 0, panel->dir.list[panel->selected].fname, 0);
246 mcview_display (view);
249 /* --------------------------------------------------------------------------------------------- */
251 /* Both views */
252 static cb_ret_t
253 mcview_handle_key (mcview_t * view, int c)
255 c = convert_from_input_c (c);
257 if (view->hex_mode) {
258 switch (c) {
259 case '\t':
260 view->hexview_in_text = !view->hexview_in_text;
261 view->dirty++;
262 return MSG_HANDLED;
264 case XCTRL ('a'):
265 mcview_moveto_bol (view);
266 view->dirty++;
267 return MSG_HANDLED;
269 case XCTRL ('b'):
270 mcview_move_left (view, 1);
271 return MSG_HANDLED;
273 case XCTRL ('e'):
274 mcview_moveto_eol (view);
275 return MSG_HANDLED;
277 case XCTRL ('f'):
278 mcview_move_right (view, 1);
279 return MSG_HANDLED;
282 if (view->hexedit_mode && mcview_handle_editkey (view, c) == MSG_HANDLED)
283 return MSG_HANDLED;
286 if (mcview_check_left_right_keys (view, c))
287 return MSG_HANDLED;
289 if (check_movement_keys (c, view->data_area.height + 1, view,
290 mcview_cmk_move_up, mcview_cmk_move_down,
291 mcview_cmk_moveto_top, mcview_cmk_moveto_bottom))
292 return MSG_HANDLED;
294 switch (c) {
296 case '?':
297 case '/':
298 view->search_type = MC_SEARCH_T_REGEX;
299 mcview_search_cmd (view);
300 return MSG_HANDLED;
301 break;
302 /* Continue search */
303 case XCTRL ('r'):
304 case XCTRL ('s'):
305 case 'n':
306 case KEY_F (17):
307 mcview_continue_search_cmd (view);
308 return MSG_HANDLED;
310 /* toggle ruler */
311 case ALT ('r'):
312 mcview_toggle_ruler_cmd (view);
313 return MSG_HANDLED;
315 case 'h':
316 mcview_move_left (view, 1);
317 return MSG_HANDLED;
319 case 'j':
320 case '\n':
321 case 'e':
322 mcview_move_down (view, 1);
323 return MSG_HANDLED;
325 case 'd':
326 mcview_move_down (view, (view->data_area.height + 1) / 2);
327 return MSG_HANDLED;
329 case 'u':
330 mcview_move_up (view, (view->data_area.height + 1) / 2);
331 return MSG_HANDLED;
333 case 'k':
334 case 'y':
335 mcview_move_up (view, 1);
336 return MSG_HANDLED;
338 case 'l':
339 mcview_move_right (view, 1);
340 return MSG_HANDLED;
342 case ' ':
343 case 'f':
344 mcview_move_down (view, view->data_area.height);
345 return MSG_HANDLED;
347 case XCTRL ('o'):
348 view_other_cmd ();
349 return MSG_HANDLED;
351 /* Unlike Ctrl-O, run a new shell if the subshell is not running. */
352 case '!':
353 exec_shell ();
354 return MSG_HANDLED;
356 case 'b':
357 mcview_move_up (view, view->data_area.height);
358 return MSG_HANDLED;
360 case KEY_IC:
361 mcview_move_up (view, 2);
362 return MSG_HANDLED;
364 case KEY_DC:
365 mcview_move_down (view, 2);
366 return MSG_HANDLED;
368 case 'm':
369 view->marks[view->marker] = view->dpy_start;
370 return MSG_HANDLED;
372 case 'r':
373 view->dpy_start = view->marks[view->marker];
374 view->dirty++;
375 return MSG_HANDLED;
377 /* Use to indicate parent that we want to see the next/previous file */
378 /* Does not work in panel mode */
379 case XCTRL ('f'):
380 case XCTRL ('b'):
381 if (!mcview_is_in_panel (view))
382 view->move_dir = c == XCTRL ('f') ? 1 : -1;
383 /* FALLTHROUGH */
384 case 'q':
385 case XCTRL ('g'):
386 case ESC_CHAR:
387 if (mcview_ok_to_quit (view))
388 view->want_to_quit = TRUE;
389 return MSG_HANDLED;
391 case XCTRL ('t'):
392 mcview_select_encoding (view);
393 view->dirty++;
394 mcview_update (view);
395 return MSG_HANDLED;
397 #ifdef MC_ENABLE_DEBUGGING_CODE
398 case 't': /* mnemonic: "test" */
399 mcview_ccache_dump (view);
400 return MSG_HANDLED;
401 #endif
403 if (c >= '0' && c <= '9')
404 view->marker = c - '0';
406 /* Key not used */
407 return MSG_NOT_HANDLED;
410 /* --------------------------------------------------------------------------------------------- */
412 /*** public functions ****************************************************************************/
414 /* --------------------------------------------------------------------------------------------- */
416 cb_ret_t
417 mcview_callback (Widget * w, widget_msg_t msg, int parm)
419 mcview_t *view = (mcview_t *) w;
420 cb_ret_t i;
421 Dlg_head *h = view->widget.parent;
423 mcview_compute_areas (view);
424 mcview_update_bytes_per_line (view);
426 switch (msg) {
427 case WIDGET_INIT:
428 if (mcview_is_in_panel (view))
429 add_hook (&select_file_hook, mcview_hook, view);
430 else
431 view->dpy_bbar_dirty = TRUE;
432 return MSG_HANDLED;
434 case WIDGET_DRAW:
435 mcview_display (view);
436 return MSG_HANDLED;
438 case WIDGET_CURSOR:
439 if (view->hex_mode)
440 mcview_place_cursor (view);
441 return MSG_HANDLED;
443 case WIDGET_KEY:
444 i = mcview_handle_key ((mcview_t *) view, parm);
445 if (view->want_to_quit && !mcview_is_in_panel (view))
446 dlg_stop (h);
447 else {
448 mcview_update (view);
450 return i;
452 case WIDGET_FOCUS:
453 view->dpy_bbar_dirty = TRUE;
454 mcview_update (view);
455 return MSG_HANDLED;
457 case WIDGET_DESTROY:
458 mcview_done (view);
459 if (mcview_is_in_panel (view))
460 delete_hook (&select_file_hook, mcview_hook);
461 return MSG_HANDLED;
463 default:
464 return default_proc (msg, parm);
468 /* --------------------------------------------------------------------------------------------- */
470 cb_ret_t
471 mcview_dialog_callback (Dlg_head * h, dlg_msg_t msg, int parm)
473 switch (msg) {
474 case DLG_RESIZE:
475 mcview_adjust_size (h);
476 return MSG_HANDLED;
478 default:
479 return default_dlg_callback (h, msg, parm);
483 /* --------------------------------------------------------------------------------------------- */
485 void
486 mcview_help_cmd (void)
488 interactive_display (NULL, "[Internal File Viewer]");
491 /* --------------------------------------------------------------------------------------------- */
493 void
494 mcview_quit_cmd (mcview_t * view)
496 if (mcview_ok_to_quit (view))
497 dlg_stop (view->widget.parent);
500 /* --------------------------------------------------------------------------------------------- */
502 /* Toggle between hex view and text view */
503 void
504 mcview_toggle_hex_mode_cmd (mcview_t * view)
506 mcview_toggle_hex_mode (view);
507 mcview_update (view);
510 /* --------------------------------------------------------------------------------------------- */
512 void
513 mcview_moveto_line_cmd (mcview_t * view)
515 char *answer, *answer_end, prompt[BUF_SMALL];
516 off_t line, col;
518 mcview_offset_to_coord (view, &line, &col, view->dpy_start);
520 g_snprintf (prompt, sizeof (prompt),
521 _(" The current line number is %lld.\n"
522 " Enter the new line number:"), (line + 1));
523 answer = input_dialog (_(" Goto line "), prompt, MC_HISTORY_VIEW_GOTO_LINE, "");
524 if (answer != NULL && answer[0] != '\0') {
525 errno = 0;
526 line = strtoul (answer, &answer_end, 10);
527 if (*answer_end == '\0' && errno == 0 && line >= 1)
528 mcview_moveto (view, line - 1, 0);
530 g_free (answer);
531 view->dirty++;
532 mcview_update (view);
535 /* --------------------------------------------------------------------------------------------- */
537 void
538 mcview_moveto_addr_cmd (mcview_t * view)
540 char *line, *error, prompt[BUF_SMALL], prompt_format[BUF_SMALL];
541 off_t addr;
543 g_snprintf (prompt_format, sizeof (prompt_format),
544 _(" The current address is %s.\n"
545 " Enter the new address:"), "0x%08" OFFSETTYPE_PRIX "");
546 g_snprintf (prompt, sizeof (prompt), prompt_format, view->hex_cursor);
547 line = input_dialog (_(" Goto Address "), prompt, MC_HISTORY_VIEW_GOTO_ADDR, "");
548 if (line != NULL) {
549 if (*line != '\0') {
550 addr = strtoul (line, &error, 0);
551 if ((*error == '\0') && mcview_get_byte (view, addr, NULL) == TRUE) {
552 mcview_moveto_offset (view, addr);
553 } else {
554 message (D_ERROR, _("Warning"), _(" Invalid address "));
557 g_free (line);
559 view->dirty++;
560 mcview_update (view);
563 /* --------------------------------------------------------------------------------------------- */
565 /* Toggle between hexview and hexedit mode */
566 void
567 mcview_toggle_hexedit_mode_cmd (mcview_t * view)
569 mcview_toggle_hexedit_mode (view);
570 mcview_update (view);
573 /* --------------------------------------------------------------------------------------------- */
575 void
576 mcview_hexedit_save_changes_cmd (mcview_t * view)
578 (void) mcview_hexedit_save_changes (view);
581 /* --------------------------------------------------------------------------------------------- */
583 /* Toggle between wrapped and unwrapped view */
584 void
585 mcview_toggle_wrap_mode_cmd (mcview_t * view)
587 mcview_toggle_wrap_mode (view);
588 mcview_update (view);
591 /* --------------------------------------------------------------------------------------------- */
593 /* Both views */
594 void
595 mcview_search_cmd (mcview_t * view)
597 if (mcview_dialog_search (view))
598 mcview_do_search (view);
601 /* --------------------------------------------------------------------------------------------- */
603 void
604 mcview_toggle_magic_mode_cmd (mcview_t * view)
606 mcview_toggle_magic_mode (view);
607 mcview_update (view);
610 /* --------------------------------------------------------------------------------------------- */
612 void
613 mcview_toggle_nroff_mode_cmd (mcview_t * view)
615 mcview_toggle_nroff_mode (view);
616 mcview_update (view);
619 /* --------------------------------------------------------------------------------------------- */
621 void
622 mcview_toggle_ruler_cmd (mcview_t * view)
624 mcview_display_toggle_ruler (view);
627 /* --------------------------------------------------------------------------------------------- */