Minor grammar/spelling issues.
[kaloumi3.git] / src / viewer / actions_cmd.c
blob091d356962f370746724cc38e68cadabc1f6b9ae
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 "lib/global.h"
54 #include "lib/tty/tty.h"
55 #include "lib/tty/key.h"
57 #include "src/dialog.h" /* cb_ret_t */
58 #include "src/panel.h"
59 #include "src/layout.h"
60 #include "src/wtools.h"
61 #include "src/history.h"
62 #include "src/charsets.h"
63 #include "src/cmd.h"
64 #include "src/execute.h"
65 #include "src/help.h"
66 #include "src/keybind.h"
67 #include "src/cmddef.h" /* CK_ cmd name const */
69 #include "internal.h"
70 #include "mcviewer.h"
72 /*** global variables ****************************************************************************/
74 /*** file scope macro definitions ****************************************************************/
76 /*** file scope type declarations ****************************************************************/
78 /*** file scope variables ************************************************************************/
80 /*** file scope functions ************************************************************************/
82 /* Both views */
83 static void
84 mcview_search (mcview_t * view)
86 if (mcview_dialog_search (view))
87 mcview_do_search (view);
90 /* --------------------------------------------------------------------------------------------- */
92 static void
93 mcview_continue_search_cmd (mcview_t * view)
95 if (view->last_search_string != NULL)
97 mcview_do_search (view);
99 else
101 /* find last search string in history */
102 GList *history;
103 history = history_get (MC_HISTORY_SHARED_SEARCH);
104 if (history != NULL && history->data != NULL)
106 view->last_search_string = (gchar *) g_strdup (history->data);
107 history = g_list_first (history);
108 g_list_foreach (history, (GFunc) g_free, NULL);
109 g_list_free (history);
111 view->search = mc_search_new (view->last_search_string, -1);
112 view->search_nroff_seq = mcview_nroff_seq_new (view);
114 if (!view->search)
116 /* if not... then ask for an expression */
117 g_free (view->last_search_string);
118 view->last_search_string = NULL;
119 mcview_search (view);
121 else
123 view->search->search_type = mcview_search_options.type;
124 view->search->is_all_charsets = mcview_search_options.all_codepages;
125 view->search->is_case_sentitive = mcview_search_options.case_sens;
126 view->search->whole_words = mcview_search_options.whole_words;
127 view->search->search_fn = mcview_search_cmd_callback;
128 view->search->update_fn = mcview_search_update_cmd_callback;
130 mcview_do_search (view);
133 else
135 /* if not... then ask for an expression */
136 g_free (view->last_search_string);
137 view->last_search_string = NULL;
138 mcview_search (view);
143 /* --------------------------------------------------------------------------------------------- */
145 /* Check for left and right arrows, possibly with modifiers */
146 static cb_ret_t
147 mcview_check_left_right_keys (mcview_t * view, int c)
149 if (c == KEY_LEFT)
151 mcview_move_left (view, 1);
152 return MSG_HANDLED;
155 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))
167 if (view->dpy_text_column >= 10)
168 view->dpy_text_column -= 10;
169 else
170 view->dpy_text_column = 0;
171 view->dirty++;
172 return MSG_HANDLED;
175 if (c == (KEY_M_CTRL | KEY_RIGHT))
177 if (view->dpy_text_column <= OFFSETTYPE_MAX - 10)
178 view->dpy_text_column += 10;
179 else
180 view->dpy_text_column = OFFSETTYPE_MAX;
181 view->dirty++;
182 return MSG_HANDLED;
185 return MSG_NOT_HANDLED;
188 /* --------------------------------------------------------------------------------------------- */
190 static void
191 mcview_cmk_move_up (void *w, int n)
193 mcview_move_up ((mcview_t *) w, n);
196 /* --------------------------------------------------------------------------------------------- */
198 static void
199 mcview_cmk_move_down (void *w, int n)
201 mcview_move_down ((mcview_t *) w, n);
204 /* --------------------------------------------------------------------------------------------- */
206 static void
207 mcview_cmk_moveto_top (void *w, int n)
209 (void) &n;
210 mcview_moveto_top ((mcview_t *) w);
213 /* --------------------------------------------------------------------------------------------- */
215 static void
216 mcview_cmk_moveto_bottom (void *w, int n)
218 (void) &n;
219 mcview_moveto_bottom ((mcview_t *) w);
222 /* --------------------------------------------------------------------------------------------- */
224 static void
225 mcview_hook (void *v)
227 mcview_t *view = (mcview_t *) v;
228 WPanel *panel;
230 /* If the user is busy typing, wait until he finishes to update the
231 screen */
232 if (!is_idle ())
234 if (!hook_present (idle_hook, mcview_hook))
235 add_hook (&idle_hook, mcview_hook, v);
236 return;
239 delete_hook (&idle_hook, mcview_hook);
241 if (get_current_type () == view_listing)
242 panel = current_panel;
243 else if (get_other_type () == view_listing)
244 panel = other_panel;
245 else
246 return;
248 mcview_load (view, 0, panel->dir.list[panel->selected].fname, 0);
249 mcview_display (view);
252 /* --------------------------------------------------------------------------------------------- */
254 static cb_ret_t
255 mcview_handle_editkey (mcview_t * view, int key)
257 struct hexedit_change_node *node;
258 int byte_val;
259 /* Has there been a change at this position? */
260 node = view->change_list;
261 while (node && (node->offset != view->hex_cursor))
262 node = node->next;
264 if (!view->hexview_in_text)
266 /* Hex editing */
267 unsigned int hexvalue = 0;
268 if (key >= '0' && key <= '9')
270 hexvalue = 0 + (key - '0');
272 else if (key >= 'A' && key <= 'F')
273 hexvalue = 10 + (key - 'A');
274 else if (key >= 'a' && key <= 'f')
275 hexvalue = 10 + (key - 'a');
276 else
277 return MSG_NOT_HANDLED;
279 if (node)
280 byte_val = node->value;
281 else
282 mcview_get_byte (view, view->hex_cursor, &byte_val);
284 if (view->hexedit_lownibble)
286 byte_val = (byte_val & 0xf0) | (hexvalue);
288 else
290 byte_val = (byte_val & 0x0f) | (hexvalue << 4);
293 else
295 /* Text editing */
296 if (key < 256 && ((key == '\n') || is_printable (key)))
297 byte_val = key;
298 else
299 return MSG_NOT_HANDLED;
301 if (!node)
303 node = g_new (struct hexedit_change_node, 1);
304 node->offset = view->hex_cursor;
305 node->value = byte_val;
306 mcview_enqueue_change (&view->change_list, node);
308 else
310 node->value = byte_val;
312 view->dirty++;
313 mcview_move_right (view, 1);
314 return MSG_HANDLED;
317 /* --------------------------------------------------------------------------------------------- */
319 static cb_ret_t
320 mcview_execute_cmd (mcview_t * view, unsigned long command)
322 int res = MSG_HANDLED;
324 switch (command)
326 case CK_ViewHelp:
327 interactive_display (NULL, "[Internal File Viewer]");
328 break;
329 case CK_ViewToggleWrapMode:
330 /* Toggle between wrapped and unwrapped view */
331 mcview_toggle_wrap_mode (view);
332 break;
333 case CK_ViewToggleHexEditMode:
334 /* Toggle between hexview and hexedit mode */
335 mcview_toggle_hexedit_mode (view);
336 break;
337 case CK_ViewToggleHexMode:
338 /* Toggle between hex view and text view */
339 mcview_toggle_hex_mode (view);
340 break;
341 case CK_ViewGoto:
343 off_t addr;
345 if (mcview_dialog_goto (view, &addr))
347 if (addr >= 0)
348 mcview_moveto_offset (view, addr);
349 else
351 message (D_ERROR, _("Warning"), _("Invalid value"));
352 view->dirty++;
355 break;
357 case CK_ViewHexEditSave:
358 mcview_hexedit_save_changes (view);
359 break;
360 case CK_ViewSearch:
361 mcview_search (view);
362 break;
363 case CK_ViewToggleMagicMode:
364 mcview_toggle_magic_mode (view);
365 break;
366 case CK_ViewToggleNroffMode:
367 mcview_toggle_nroff_mode (view);
368 view->dirty++;
369 break;
370 case CK_ViewToggleHexNavMode:
371 view->hexview_in_text = !view->hexview_in_text;
372 view->dirty++;
373 break;
374 case CK_ViewMoveToBol:
375 mcview_moveto_bol (view);
376 break;
377 case CK_ViewMoveToEol:
378 mcview_moveto_eol (view);
379 break;
380 case CK_ViewMoveLeft:
381 mcview_move_left (view, 1);
382 break;
383 case CK_ViewMoveRight:
384 mcview_move_right (view, 1);
385 break;
386 /* Continue search */
387 case CK_ViewContinueSearch:
388 mcview_continue_search_cmd (view);
389 break;
390 case CK_ViewToggleRuler:
391 mcview_display_toggle_ruler (view);
392 break;
393 case CK_ViewMoveUp:
394 mcview_move_up (view, 1);
395 break;
396 case CK_ViewMoveDown:
397 mcview_move_down (view, 1);
398 break;
399 case CK_ViewMoveHalfPgUp:
400 mcview_move_up (view, (view->data_area.height + 1) / 2);
401 break;
402 case CK_ViewMoveHalfPgDn:
403 mcview_move_down (view, (view->data_area.height + 1) / 2);
404 break;
405 case CK_ViewMovePgUp:
406 mcview_move_up (view, view->data_area.height);
407 break;
408 case CK_ViewMovePgDn:
409 mcview_move_down (view, view->data_area.height);
410 break;
411 case CK_ShowCommandLine:
412 view_other_cmd ();
413 break;
415 // Unlike Ctrl-O, run a new shell if the subshell is not running
416 case '!':
417 exec_shell ();
418 return MSG_HANDLED;
420 case CK_ViewGotoBookmark:
421 view->marks[view->marker] = view->dpy_start;
422 break;
423 case CK_ViewNewBookmark:
424 view->dpy_start = view->marks[view->marker];
425 view->dirty++;
426 break;
427 case CK_SelectCodepage:
428 mcview_select_encoding (view);
429 view->dirty++;
430 break;
431 case CK_ViewNextFile:
432 case CK_ViewPrevFile:
433 /* Use to indicate parent that we want to see the next/previous file */
434 /* Does not work in panel mode */
435 if (!mcview_is_in_panel (view))
436 view->move_dir = (command == CK_ViewNextFile) ? 1 : -1;
437 /* fallthrough */
438 case CK_ViewQuit:
439 if (mcview_ok_to_quit (view))
440 view->want_to_quit = TRUE;
441 break;
442 default:
443 res = MSG_NOT_HANDLED;
445 return res;
448 /* Both views */
449 static cb_ret_t
450 mcview_handle_key (mcview_t * view, int key)
452 unsigned long command;
454 key = convert_from_input_c (key);
456 if (view->hex_mode)
458 if (view->hexedit_mode && (mcview_handle_editkey (view, key) == MSG_HANDLED))
459 return MSG_HANDLED;
461 command = lookup_keymap_command (view->hex_map, key);
462 if ((command != CK_Ignore_Key) && (mcview_execute_cmd (view, command) == MSG_HANDLED))
463 return MSG_HANDLED;
466 command = lookup_keymap_command (view->plain_map, key);
467 if ((command != CK_Ignore_Key) && (mcview_execute_cmd (view, command) == MSG_HANDLED))
468 return MSG_HANDLED;
470 if (mcview_check_left_right_keys (view, key) == MSG_HANDLED)
471 return MSG_HANDLED;
473 if (check_movement_keys (key, view->data_area.height + 1, view,
474 mcview_cmk_move_up, mcview_cmk_move_down,
475 mcview_cmk_moveto_top, mcview_cmk_moveto_bottom) == MSG_HANDLED)
476 return MSG_HANDLED;
478 #ifdef MC_ENABLE_DEBUGGING_CODE
479 if (c == 't')
480 { /* mnemonic: "test" */
481 mcview_ccache_dump (view);
482 return MSG_HANDLED;
484 #endif
485 if (key >= '0' && key <= '9')
486 view->marker = key - '0';
488 /* Key not used */
489 return MSG_NOT_HANDLED;
493 /* --------------------------------------------------------------------------------------------- */
495 static inline void
496 mcview_adjust_size (Dlg_head * h)
498 mcview_t *view;
499 WButtonBar *b;
501 /* Look up the viewer and the buttonbar, we assume only two widgets here */
502 view = (mcview_t *) find_widget_type (h, mcview_callback);
503 b = find_buttonbar (h);
505 widget_set_size (&view->widget, 0, 0, LINES - 1, COLS);
506 widget_set_size (&b->widget, LINES - 1, 0, 1, COLS);
508 mcview_compute_areas (view);
509 mcview_update_bytes_per_line (view);
513 /* --------------------------------------------------------------------------------------------- */
515 /*** public functions ****************************************************************************/
517 /* --------------------------------------------------------------------------------------------- */
519 cb_ret_t
520 mcview_callback (Widget * w, widget_msg_t msg, int parm)
522 mcview_t *view = (mcview_t *) w;
523 cb_ret_t i;
524 Dlg_head *h = view->widget.parent;
526 mcview_compute_areas (view);
527 mcview_update_bytes_per_line (view);
529 switch (msg)
531 case WIDGET_INIT:
532 if (mcview_is_in_panel (view))
533 add_hook (&select_file_hook, mcview_hook, view);
534 else
535 view->dpy_bbar_dirty = TRUE;
536 return MSG_HANDLED;
538 case WIDGET_DRAW:
539 mcview_display (view);
540 return MSG_HANDLED;
542 case WIDGET_CURSOR:
543 if (view->hex_mode)
544 mcview_place_cursor (view);
545 return MSG_HANDLED;
547 case WIDGET_KEY:
548 i = mcview_handle_key (view, parm);
549 if (view->want_to_quit && !mcview_is_in_panel (view))
550 dlg_stop (h);
551 else
552 mcview_update (view);
553 return i;
555 case WIDGET_COMMAND:
556 i = mcview_execute_cmd (view, parm);
557 if (view->want_to_quit && !mcview_is_in_panel (view))
558 dlg_stop (h);
559 else
560 mcview_update (view);
561 return i;
563 case WIDGET_FOCUS:
564 view->dpy_bbar_dirty = TRUE;
565 mcview_update (view);
566 return MSG_HANDLED;
568 case WIDGET_DESTROY:
569 mcview_done (view);
570 if (mcview_is_in_panel (view))
571 delete_hook (&select_file_hook, mcview_hook);
572 return MSG_HANDLED;
574 default:
575 return default_proc (msg, parm);
579 /* --------------------------------------------------------------------------------------------- */
581 cb_ret_t
582 mcview_dialog_callback (Dlg_head * h, Widget * sender, dlg_msg_t msg, int parm, void *data)
584 mcview_t *view = data;
586 switch (msg)
588 case DLG_RESIZE:
589 mcview_adjust_size (h);
590 return MSG_HANDLED;
592 case DLG_ACTION:
593 /* command from buttonbar */
594 return send_message ((Widget *) view, WIDGET_COMMAND, parm);
596 default:
597 return default_dlg_callback (h, sender, msg, parm, data);
601 /* --------------------------------------------------------------------------------------------- */