Ticket #1791: a nice dark skin created by Lee Bigelow.
[kaloumi3.git] / src / viewer / actions_cmd.c
blob016c0ef4bcc2a037b42c34b28e6651e9eb7505cb
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 view->dirty++;
333 break;
334 case CK_ViewToggleHexEditMode:
335 /* Toggle between hexview and hexedit mode */
336 mcview_toggle_hexedit_mode (view);
337 view->dirty++;
338 break;
339 case CK_ViewToggleHexMode:
340 /* Toggle between hex view and text view */
341 mcview_toggle_hex_mode (view);
342 view->dirty++;
343 break;
344 case CK_ViewGoto:
346 off_t addr;
348 if (mcview_dialog_goto (view, &addr))
350 if (addr >= 0)
351 mcview_moveto_offset (view, addr);
352 else
354 message (D_ERROR, _("Warning"), _("Invalid value"));
355 view->dirty++;
358 break;
360 case CK_ViewHexEditSave:
361 mcview_hexedit_save_changes (view);
362 break;
363 case CK_ViewSearch:
364 mcview_search (view);
365 break;
366 case CK_ViewToggleMagicMode:
367 mcview_toggle_magic_mode (view);
368 view->dirty++;
369 break;
370 case CK_ViewToggleNroffMode:
371 mcview_toggle_nroff_mode (view);
372 view->dirty++;
373 break;
374 case CK_ViewToggleHexNavMode:
375 view->hexview_in_text = !view->hexview_in_text;
376 view->dirty++;
377 break;
378 case CK_ViewMoveToBol:
379 mcview_moveto_bol (view);
380 break;
381 case CK_ViewMoveToEol:
382 mcview_moveto_eol (view);
383 break;
384 case CK_ViewMoveLeft:
385 mcview_move_left (view, 1);
386 break;
387 case CK_ViewMoveRight:
388 mcview_move_right (view, 1);
389 break;
390 /* Continue search */
391 case CK_ViewContinueSearch:
392 mcview_continue_search_cmd (view);
393 break;
394 case CK_ViewToggleRuler:
395 mcview_display_toggle_ruler (view);
396 break;
397 case CK_ViewMoveUp:
398 mcview_move_up (view, 1);
399 break;
400 case CK_ViewMoveDown:
401 mcview_move_down (view, 1);
402 break;
403 case CK_ViewMoveHalfPgUp:
404 mcview_move_up (view, (view->data_area.height + 1) / 2);
405 break;
406 case CK_ViewMoveHalfPgDn:
407 mcview_move_down (view, (view->data_area.height + 1) / 2);
408 break;
409 case CK_ViewMovePgUp:
410 mcview_move_up (view, view->data_area.height);
411 break;
412 case CK_ViewMovePgDn:
413 mcview_move_down (view, view->data_area.height);
414 break;
415 case CK_ShowCommandLine:
416 view_other_cmd ();
417 break;
419 // Unlike Ctrl-O, run a new shell if the subshell is not running
420 case '!':
421 exec_shell ();
422 return MSG_HANDLED;
424 case CK_ViewGotoBookmark:
425 view->marks[view->marker] = view->dpy_start;
426 break;
427 case CK_ViewNewBookmark:
428 view->dpy_start = view->marks[view->marker];
429 view->dirty++;
430 break;
431 case CK_SelectCodepage:
432 mcview_select_encoding (view);
433 view->dirty++;
434 break;
435 case CK_ViewNextFile:
436 case CK_ViewPrevFile:
437 /* Use to indicate parent that we want to see the next/previous file */
438 /* Does not work in panel mode */
439 if (!mcview_is_in_panel (view))
440 view->move_dir = (command == CK_ViewNextFile) ? 1 : -1;
441 /* fallthrough */
442 case CK_ViewQuit:
443 if (mcview_ok_to_quit (view))
444 view->want_to_quit = TRUE;
445 break;
446 default:
447 res = MSG_NOT_HANDLED;
449 return res;
452 /* Both views */
453 static cb_ret_t
454 mcview_handle_key (mcview_t * view, int key)
456 unsigned long command;
458 key = convert_from_input_c (key);
460 if (view->hex_mode)
462 if (view->hexedit_mode && (mcview_handle_editkey (view, key) == MSG_HANDLED))
463 return MSG_HANDLED;
465 command = lookup_keymap_command (view->hex_map, key);
466 if ((command != CK_Ignore_Key) && (mcview_execute_cmd (view, command) == MSG_HANDLED))
467 return MSG_HANDLED;
470 command = lookup_keymap_command (view->plain_map, key);
471 if ((command != CK_Ignore_Key) && (mcview_execute_cmd (view, command) == MSG_HANDLED))
472 return MSG_HANDLED;
474 if (mcview_check_left_right_keys (view, key))
475 return MSG_HANDLED;
477 if (check_movement_keys (key, view->data_area.height + 1, view,
478 mcview_cmk_move_up, mcview_cmk_move_down,
479 mcview_cmk_moveto_top, mcview_cmk_moveto_bottom))
480 return MSG_HANDLED;
482 #ifdef MC_ENABLE_DEBUGGING_CODE
483 if (c == 't')
484 { /* mnemonic: "test" */
485 mcview_ccache_dump (view);
486 return MSG_HANDLED;
488 #endif
489 if (key >= '0' && key <= '9')
490 view->marker = key - '0';
492 /* Key not used */
493 return MSG_NOT_HANDLED;
497 /* --------------------------------------------------------------------------------------------- */
499 static inline void
500 mcview_adjust_size (Dlg_head * h)
502 mcview_t *view;
503 WButtonBar *b;
505 /* Look up the viewer and the buttonbar, we assume only two widgets here */
506 view = (mcview_t *) find_widget_type (h, mcview_callback);
507 b = find_buttonbar (h);
509 widget_set_size (&view->widget, 0, 0, LINES - 1, COLS);
510 widget_set_size (&b->widget, LINES - 1, 0, 1, COLS);
512 mcview_compute_areas (view);
513 mcview_update_bytes_per_line (view);
517 /* --------------------------------------------------------------------------------------------- */
519 /*** public functions ****************************************************************************/
521 /* --------------------------------------------------------------------------------------------- */
523 cb_ret_t
524 mcview_callback (Widget * w, widget_msg_t msg, int parm)
526 mcview_t *view = (mcview_t *) w;
527 cb_ret_t i;
528 Dlg_head *h = view->widget.parent;
530 mcview_compute_areas (view);
531 mcview_update_bytes_per_line (view);
533 switch (msg)
535 case WIDGET_INIT:
536 if (mcview_is_in_panel (view))
537 add_hook (&select_file_hook, mcview_hook, view);
538 else
539 view->dpy_bbar_dirty = TRUE;
540 return MSG_HANDLED;
542 case WIDGET_DRAW:
543 mcview_display (view);
544 return MSG_HANDLED;
546 case WIDGET_CURSOR:
547 if (view->hex_mode)
548 mcview_place_cursor (view);
549 return MSG_HANDLED;
551 case WIDGET_KEY:
552 i = mcview_handle_key (view, parm);
553 if (view->want_to_quit && !mcview_is_in_panel (view))
554 dlg_stop (h);
555 else
556 mcview_update (view);
557 return i;
559 case WIDGET_COMMAND:
560 i = mcview_execute_cmd (view, parm);
561 if (view->want_to_quit && !mcview_is_in_panel (view))
562 dlg_stop (h);
563 else
564 mcview_update (view);
565 return i;
567 case WIDGET_FOCUS:
568 view->dpy_bbar_dirty = TRUE;
569 mcview_update (view);
570 return MSG_HANDLED;
572 case WIDGET_DESTROY:
573 mcview_done (view);
574 if (mcview_is_in_panel (view))
575 delete_hook (&select_file_hook, mcview_hook);
576 return MSG_HANDLED;
578 default:
579 return default_proc (msg, parm);
583 /* --------------------------------------------------------------------------------------------- */
585 cb_ret_t
586 mcview_dialog_callback (Dlg_head * h, Widget * sender, dlg_msg_t msg, int parm, void *data)
588 mcview_t *view = data;
590 switch (msg)
592 case DLG_RESIZE:
593 mcview_adjust_size (h);
594 return MSG_HANDLED;
596 case DLG_ACTION:
597 /* command from buttonbar */
598 return send_message ((Widget *) view, WIDGET_COMMAND, parm);
600 default:
601 return default_dlg_callback (h, sender, msg, parm, data);
605 /* --------------------------------------------------------------------------------------------- */