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
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,
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
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 "../src/keybind.h" /* global_key_map_t */
64 #include "../src/cmddef.h" /* CK_ cmd name const */
70 /*** global variables ****************************************************************************/
72 const global_key_map_t default_keymap
[] = {
74 { '?', CK_ViewSearch
},
75 { '/', CK_ViewSearch
},
76 { XCTRL('r'), CK_ViewContinueSearch
},
77 { XCTRL('s'), CK_ViewContinueSearch
},
78 { KEY_F (17), CK_ViewContinueSearch
},
79 { ALT('r'), CK_ViewToggleRuler
},
81 { KEY_HOME
, CK_ViewMoveToBol
},
82 { KEY_END
, CK_ViewMoveToEol
},
84 { 'h', CK_ViewMoveLeft
},
85 { KEY_LEFT
, CK_ViewMoveLeft
},
87 { 'l', CK_ViewMoveRight
},
88 { KEY_RIGHT
, CK_ViewMoveRight
},
90 { 'k', CK_ViewMoveUp
},
91 { 'y', CK_ViewMoveUp
},
92 { KEY_IC
, CK_ViewMoveUp
},
93 { KEY_UP
, CK_ViewMoveUp
},
95 { 'j', CK_ViewMoveDown
},
96 { 'e', CK_ViewMoveDown
},
97 { KEY_DOWN
, CK_ViewMoveDown
},
98 { KEY_DC
, CK_ViewMoveDown
},
101 { ' ', CK_ViewMovePgDn
},
102 { 'f', CK_ViewMovePgDn
},
103 { KEY_NPAGE
, CK_ViewMovePgDn
},
105 { 'b', CK_ViewMovePgUp
},
106 { KEY_PPAGE
, CK_ViewMovePgUp
},
108 { 'd', CK_ViewMoveHalfPgDn
},
110 { 'u', CK_ViewMoveHalfPgUp
},
112 { XCTRL('o'), CK_ViewOtherCmd
},
114 { 'm', CK_ViewGotoBookmark
},
115 { 'r', CK_ViewNewBookmark
},
117 { XCTRL ('f'), CK_ViewNextFile
},
118 { XCTRL ('b'), CK_ViewPrevFile
},
120 { 'q', CK_ViewQuit
},
121 { XCTRL ('g'), CK_ViewQuit
},
122 { ESC_CHAR
, CK_ViewQuit
},
124 { XCTRL ('t'), CK_Select_Codepage
},
128 const global_key_map_t default_hex_keymap
[] = {
130 { '\t', CK_HexViewToggleNavigationMode
},
131 { XCTRL ('a'), CK_ViewMoveToBol
},
132 { XCTRL ('e'), CK_ViewMoveToEol
},
134 { 'b', CK_ViewMoveLeft
},
135 { KEY_LEFT
, CK_ViewMoveLeft
},
137 { 'f', CK_ViewMoveRight
},
138 { KEY_RIGHT
, CK_ViewMoveRight
},
140 { 'k', CK_ViewMoveUp
},
141 { 'y', CK_ViewMoveUp
},
142 { KEY_UP
, CK_ViewMoveUp
},
144 { 'j', CK_ViewMoveDown
},
145 { KEY_DOWN
, CK_ViewMoveDown
},
146 { KEY_DC
, CK_ViewMoveDown
},
151 /*** file scope macro definitions ****************************************************************/
153 /*** file scope type declarations ****************************************************************/
155 /*** file scope variables ************************************************************************/
157 /*** file scope functions ************************************************************************/
159 /* --------------------------------------------------------------------------------------------- */
162 mcview_continue_search_cmd (mcview_t
* view
)
165 if (view
->last_search_string
!= NULL
) {
166 mcview_do_search (view
);
168 /* find last search string in history */
170 history
= history_get (MC_HISTORY_SHARED_SEARCH
);
171 if (history
!= NULL
&& history
->data
!= NULL
) {
172 view
->last_search_string
= (gchar
*) g_strdup(history
->data
);
173 history
= g_list_first (history
);
174 g_list_foreach (history
, (GFunc
) g_free
, NULL
);
175 g_list_free (history
);
177 view
->search
= mc_search_new (view
->last_search_string
, -1);
178 view
->search_nroff_seq
= mcview_nroff_seq_new (view
);
181 /* if not... then ask for an expression */
182 g_free(view
->last_search_string
);
183 mcview_search_cmd (view
);
185 view
->search
->search_type
= view
->search_type
;
186 view
->search
->is_all_charsets
= view
->search_all_codepages
;
187 view
->search
->is_case_sentitive
= view
->search_case
;
188 view
->search
->search_fn
= mcview_search_cmd_callback
;
189 view
->search
->update_fn
= mcview_search_update_cmd_callback
;
190 view
->search
->whole_words
= view
->whole_words
;
192 mcview_do_search (view
);
195 /* if not... then ask for an expression */
196 g_free(view
->last_search_string
);
197 mcview_search_cmd (view
);
202 /* --------------------------------------------------------------------------------------------- */
204 mcview_handle_editkey (mcview_t
* view
, int key
)
206 struct hexedit_change_node
*node
;
209 /* Has there been a change at this position? */
210 node
= view
->change_list
;
211 while (node
&& (node
->offset
!= view
->hex_cursor
))
214 if (!view
->hexview_in_text
) {
216 unsigned int hexvalue
= 0;
218 if (key
>= '0' && key
<= '9')
219 hexvalue
= 0 + (key
- '0');
220 else if (key
>= 'A' && key
<= 'F')
221 hexvalue
= 10 + (key
- 'A');
222 else if (key
>= 'a' && key
<= 'f')
223 hexvalue
= 10 + (key
- 'a');
225 return MSG_NOT_HANDLED
;
228 byte_val
= node
->value
;
230 mcview_get_byte (view
, view
->hex_cursor
, &byte_val
);
232 if (view
->hexedit_lownibble
) {
233 byte_val
= (byte_val
& 0xf0) | (hexvalue
);
235 byte_val
= (byte_val
& 0x0f) | (hexvalue
<< 4);
239 if (key
< 256 && ((key
== '\n') || is_printable (key
)))
242 return MSG_NOT_HANDLED
;
245 node
= g_new (struct hexedit_change_node
, 1);
246 node
->offset
= view
->hex_cursor
;
247 node
->value
= byte_val
;
248 mcview_enqueue_change (&view
->change_list
, node
);
250 node
->value
= byte_val
;
253 mcview_update (view
);
254 mcview_move_right (view
, 1);
258 /* --------------------------------------------------------------------------------------------- */
260 /* Check for left and right arrows, possibly with modifiers */
262 mcview_check_left_right_keys (mcview_t
* view
, int c
)
265 mcview_move_left (view
, 1);
269 if (c
== KEY_RIGHT
) {
270 mcview_move_right (view
, 1);
274 /* Ctrl with arrows moves by 10 postions in the unwrap mode */
275 if (view
->hex_mode
|| view
->text_wrap_mode
)
276 return MSG_NOT_HANDLED
;
278 if (c
== (KEY_M_CTRL
| KEY_LEFT
)) {
279 if (view
->dpy_text_column
>= 10)
280 view
->dpy_text_column
-= 10;
282 view
->dpy_text_column
= 0;
287 if (c
== (KEY_M_CTRL
| KEY_RIGHT
)) {
288 if (view
->dpy_text_column
<= OFFSETTYPE_MAX
- 10)
289 view
->dpy_text_column
+= 10;
291 view
->dpy_text_column
= OFFSETTYPE_MAX
;
296 return MSG_NOT_HANDLED
;
299 /* --------------------------------------------------------------------------------------------- */
302 mcview_cmk_move_up (void *w
, int n
)
304 mcview_move_up ((mcview_t
*) w
, n
);
307 /* --------------------------------------------------------------------------------------------- */
310 mcview_cmk_move_down (void *w
, int n
)
312 mcview_move_down ((mcview_t
*) w
, n
);
315 /* --------------------------------------------------------------------------------------------- */
318 mcview_cmk_moveto_top (void *w
, int n
)
321 mcview_moveto_top ((mcview_t
*) w
);
324 /* --------------------------------------------------------------------------------------------- */
327 mcview_cmk_moveto_bottom (void *w
, int n
)
330 mcview_moveto_bottom ((mcview_t
*) w
);
333 /* --------------------------------------------------------------------------------------------- */
336 mcview_hook (void *v
)
338 mcview_t
*view
= (mcview_t
*) v
;
341 /* If the user is busy typing, wait until he finishes to update the
344 if (!hook_present (idle_hook
, mcview_hook
))
345 add_hook (&idle_hook
, mcview_hook
, v
);
349 delete_hook (&idle_hook
, mcview_hook
);
351 if (get_current_type () == view_listing
)
352 panel
= current_panel
;
353 else if (get_other_type () == view_listing
)
358 mcview_load (view
, 0, panel
->dir
.list
[panel
->selected
].fname
, 0);
359 mcview_display (view
);
362 /* --------------------------------------------------------------------------------------------- */
365 mcview_execute_cmd (mcview_t
* view
, int command
, int key
)
367 int res
= MSG_HANDLED
;
369 if (view
->hex_mode
) {
371 case CK_HexViewToggleNavigationMode
:
372 view
->hexview_in_text
= !view
->hexview_in_text
;
375 case CK_ViewMoveToBol
:
376 mcview_moveto_bol (view
);
379 case CK_ViewMoveToEol
:
380 mcview_moveto_eol (view
);
382 case CK_ViewMoveLeft
:
383 mcview_move_left (view
, 1);
385 case CK_ViewMoveRight
:
386 mcview_move_right (view
, 1);
389 res
= MSG_NOT_HANDLED
;
395 view
->search_type
= MC_SEARCH_T_REGEX
;
396 mcview_search_cmd (view
);
398 /* Continue search */
399 case CK_ViewContinueSearch
:
400 mcview_continue_search_cmd (view
);
403 case CK_ViewToggleRuler
:
404 mcview_toggle_ruler_cmd (view
);
406 case CK_ViewMoveLeft
:
407 mcview_move_left (view
, 1);
409 case CK_ViewMoveRight
:
410 mcview_move_right (view
, 1);
413 mcview_move_up (view
, 1);
415 case CK_ViewMoveDown
:
416 mcview_move_down (view
, 1);
418 case CK_ViewMoveHalfPgUp
:
419 mcview_move_up (view
, (view
->data_area
.height
+ 1) / 2);
421 case CK_ViewMoveHalfPgDn
:
422 mcview_move_down (view
, (view
->data_area
.height
+ 1) / 2);
424 case CK_ViewMovePgUp
:
425 mcview_move_up (view
, view
->data_area
.height
);
427 case CK_ViewMovePgDn
:
428 mcview_move_down (view
, view
->data_area
.height
);
430 case CK_ViewOtherCmd
:
434 // Unlike Ctrl-O, run a new shell if the subshell is not running
439 case CK_ViewGotoBookmark
:
440 view
->marks
[view
->marker
] = view
->dpy_start
;
442 case CK_ViewNewBookmark
:
443 view
->dpy_start
= view
->marks
[view
->marker
];
446 case CK_ViewNextFile
:
447 /* Use to indicate parent that we want to see the next/previous file */
448 /* Does not work in panel mode */
449 if (!mcview_is_in_panel (view
))
452 case CK_ViewPrevFile
:
453 /* Use to indicate parent that we want to see the next/previous file */
454 /* Does not work in panel mode */
455 if (!mcview_is_in_panel (view
))
459 if (mcview_ok_to_quit (view
))
460 view
->want_to_quit
= TRUE
;
462 case CK_Select_Codepage
:
463 mcview_select_encoding (view
);
465 mcview_update (view
);
468 res
= MSG_NOT_HANDLED
;
477 mcview_handle_key (mcview_t
* view
, int key
)
479 key
= convert_from_input_c (key
);
484 if (view
->hex_mode
) {
485 for (i
= 0; view
->hex_map
[i
].key
; i
++) {
486 if (key
== view
->hex_map
[i
].key
) {
487 res
= mcview_execute_cmd (view
, view
->hex_map
[i
].command
, key
);
488 if (res
== MSG_HANDLED
) {
494 for (i
= 0; view
->plain_map
[i
].key
; i
++) {
495 if (key
== view
->plain_map
[i
].key
) {
496 res
= mcview_execute_cmd (view
, view
->plain_map
[i
].command
, key
);
497 mc_log ("key: %i, command: %i, res: %i\n", key
, view
->plain_map
[i
].command
, res
);
498 if (res
== MSG_HANDLED
) {
504 if (mcview_check_left_right_keys (view
, key
))
507 if (check_movement_keys (key
, view
->data_area
.height
+ 1, view
,
508 mcview_cmk_move_up
, mcview_cmk_move_down
,
509 mcview_cmk_moveto_top
, mcview_cmk_moveto_bottom
))
512 #ifdef MC_ENABLE_DEBUGGING_CODE
513 if (c
== 't') { /* mnemonic: "test" */
514 mcview_ccache_dump (view
);
518 if (key
>= '0' && key
<= '9')
519 view
->marker
= key
- '0';
522 return MSG_NOT_HANDLED
;
525 /* --------------------------------------------------------------------------------------------- */
527 /*** public functions ****************************************************************************/
529 /* --------------------------------------------------------------------------------------------- */
532 mcview_callback (Widget
* w
, widget_msg_t msg
, int parm
)
534 mcview_t
*view
= (mcview_t
*) w
;
536 Dlg_head
*h
= view
->widget
.parent
;
538 mcview_compute_areas (view
);
539 mcview_update_bytes_per_line (view
);
543 if (mcview_is_in_panel (view
))
544 add_hook (&select_file_hook
, mcview_hook
, view
);
546 view
->dpy_bbar_dirty
= TRUE
;
550 mcview_display (view
);
555 mcview_place_cursor (view
);
559 i
= mcview_handle_key ((mcview_t
*) view
, parm
);
560 if (view
->want_to_quit
&& !mcview_is_in_panel (view
))
563 mcview_update (view
);
568 view
->dpy_bbar_dirty
= TRUE
;
569 mcview_update (view
);
574 if (mcview_is_in_panel (view
))
575 delete_hook (&select_file_hook
, mcview_hook
);
579 return default_proc (msg
, parm
);
583 /* --------------------------------------------------------------------------------------------- */
586 mcview_dialog_callback (Dlg_head
* h
, dlg_msg_t msg
, int parm
)
590 mcview_adjust_size (h
);
594 return default_dlg_callback (h
, msg
, parm
);
598 /* --------------------------------------------------------------------------------------------- */
601 mcview_help_cmd (void)
603 interactive_display (NULL
, "[Internal File Viewer]");
606 /* --------------------------------------------------------------------------------------------- */
609 mcview_quit_cmd (mcview_t
* view
)
611 if (mcview_ok_to_quit (view
))
612 dlg_stop (view
->widget
.parent
);
615 /* --------------------------------------------------------------------------------------------- */
617 /* Toggle between hex view and text view */
619 mcview_toggle_hex_mode_cmd (mcview_t
* view
)
621 mcview_toggle_hex_mode (view
);
622 mcview_update (view
);
625 /* --------------------------------------------------------------------------------------------- */
628 mcview_moveto_line_cmd (mcview_t
* view
)
630 char *answer
, *answer_end
, prompt
[BUF_SMALL
];
633 mcview_offset_to_coord (view
, &line
, &col
, view
->dpy_start
);
635 g_snprintf (prompt
, sizeof (prompt
),
636 _(" The current line number is %lld.\n"
637 " Enter the new line number:"), (line
+ 1));
638 answer
= input_dialog (_(" Goto line "), prompt
, MC_HISTORY_VIEW_GOTO_LINE
, "");
639 if (answer
!= NULL
&& answer
[0] != '\0') {
641 line
= strtoul (answer
, &answer_end
, 10);
642 if (*answer_end
== '\0' && errno
== 0 && line
>= 1)
643 mcview_moveto (view
, line
- 1, 0);
647 mcview_update (view
);
650 /* --------------------------------------------------------------------------------------------- */
653 mcview_moveto_addr_cmd (mcview_t
* view
)
655 char *line
, *error
, prompt
[BUF_SMALL
], prompt_format
[BUF_SMALL
];
658 g_snprintf (prompt_format
, sizeof (prompt_format
),
659 _(" The current address is %s.\n"
660 " Enter the new address:"), "0x%08" OFFSETTYPE_PRIX
"");
661 g_snprintf (prompt
, sizeof (prompt
), prompt_format
, view
->hex_cursor
);
662 line
= input_dialog (_(" Goto Address "), prompt
, MC_HISTORY_VIEW_GOTO_ADDR
, "");
665 addr
= strtoul (line
, &error
, 0);
666 if ((*error
== '\0') && mcview_get_byte (view
, addr
, NULL
) == TRUE
) {
667 mcview_moveto_offset (view
, addr
);
669 message (D_ERROR
, _("Warning"), _(" Invalid address "));
675 mcview_update (view
);
678 /* --------------------------------------------------------------------------------------------- */
680 /* Toggle between hexview and hexedit mode */
682 mcview_toggle_hexedit_mode_cmd (mcview_t
* view
)
684 mcview_toggle_hexedit_mode (view
);
685 mcview_update (view
);
688 /* --------------------------------------------------------------------------------------------- */
691 mcview_hexedit_save_changes_cmd (mcview_t
* view
)
693 (void) mcview_hexedit_save_changes (view
);
696 /* --------------------------------------------------------------------------------------------- */
698 /* Toggle between wrapped and unwrapped view */
700 mcview_toggle_wrap_mode_cmd (mcview_t
* view
)
702 mcview_toggle_wrap_mode (view
);
703 mcview_update (view
);
706 /* --------------------------------------------------------------------------------------------- */
710 mcview_search_cmd (mcview_t
* view
)
712 if (mcview_dialog_search (view
))
713 mcview_do_search (view
);
716 /* --------------------------------------------------------------------------------------------- */
719 mcview_toggle_magic_mode_cmd (mcview_t
* view
)
721 mcview_toggle_magic_mode (view
);
722 mcview_update (view
);
725 /* --------------------------------------------------------------------------------------------- */
728 mcview_toggle_nroff_mode_cmd (mcview_t
* view
)
730 mcview_toggle_nroff_mode (view
);
731 mcview_update (view
);
734 /* --------------------------------------------------------------------------------------------- */
737 mcview_toggle_ruler_cmd (mcview_t
* view
)
739 mcview_display_toggle_ruler (view
);
742 /* --------------------------------------------------------------------------------------------- */