Merge remote branch 'osp/only-directories' into homework
[pantumic.git] / src / viewer / actions_cmd.c
blob68bba803d261dbdc0524069be949d743f373310c
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" /* is_idle() */
56 #include "lib/lock.h" /* lock_file() */
57 #include "lib/util.h"
58 #include "lib/widget.h"
59 #include "lib/charsets.h"
61 #include "src/filemanager/layout.h"
62 #include "src/filemanager/cmd.h"
63 #include "src/filemanager/midnight.h" /* current_panel */
65 #include "src/history.h"
66 #include "src/execute.h"
67 #include "src/help.h"
68 #include "src/keybind-defaults.h"
69 #include "src/main.h" /* midnight_shutdown */
71 #include "internal.h"
72 #include "mcviewer.h"
74 /*** global variables ****************************************************************************/
76 /*** file scope macro definitions ****************************************************************/
78 /*** file scope type declarations ****************************************************************/
80 /*** file scope variables ************************************************************************/
82 /*** file scope functions ************************************************************************/
83 /* --------------------------------------------------------------------------------------------- */
85 /* Both views */
86 static void
87 mcview_search (mcview_t * view)
89 if (mcview_dialog_search (view))
90 mcview_do_search (view);
93 /* --------------------------------------------------------------------------------------------- */
95 static void
96 mcview_continue_search_cmd (mcview_t * view)
98 if (view->last_search_string != NULL)
100 mcview_do_search (view);
102 else
104 /* find last search string in history */
105 GList *history;
106 history = history_get (MC_HISTORY_SHARED_SEARCH);
107 if (history != NULL && history->data != NULL)
109 view->last_search_string = (gchar *) g_strdup (history->data);
110 history = g_list_first (history);
111 g_list_foreach (history, (GFunc) g_free, NULL);
112 g_list_free (history);
114 view->search = mc_search_new (view->last_search_string, -1);
115 view->search_nroff_seq = mcview_nroff_seq_new (view);
117 if (!view->search)
119 /* if not... then ask for an expression */
120 g_free (view->last_search_string);
121 view->last_search_string = NULL;
122 mcview_search (view);
124 else
126 view->search->search_type = mcview_search_options.type;
127 view->search->is_all_charsets = mcview_search_options.all_codepages;
128 view->search->is_case_sensitive = mcview_search_options.case_sens;
129 view->search->whole_words = mcview_search_options.whole_words;
130 view->search->search_fn = mcview_search_cmd_callback;
131 view->search->update_fn = mcview_search_update_cmd_callback;
133 mcview_do_search (view);
136 else
138 /* if not... then ask for an expression */
139 g_free (view->last_search_string);
140 view->last_search_string = NULL;
141 mcview_search (view);
146 /* --------------------------------------------------------------------------------------------- */
148 static void
149 mcview_hook (void *v)
151 mcview_t *view = (mcview_t *) v;
152 WPanel *panel;
154 /* If the user is busy typing, wait until he finishes to update the
155 screen */
156 if (!is_idle ())
158 if (!hook_present (idle_hook, mcview_hook))
159 add_hook (&idle_hook, mcview_hook, v);
160 return;
163 delete_hook (&idle_hook, mcview_hook);
165 if (get_current_type () == view_listing)
166 panel = current_panel;
167 else if (get_other_type () == view_listing)
168 panel = other_panel;
169 else
170 return;
172 mcview_done (view);
173 mcview_init (view);
174 mcview_load (view, 0, panel->dir.list[panel->selected].fname, 0);
175 mcview_display (view);
178 /* --------------------------------------------------------------------------------------------- */
180 static cb_ret_t
181 mcview_handle_editkey (mcview_t * view, int key)
183 struct hexedit_change_node *node;
184 int byte_val;
186 /* Has there been a change at this position? */
187 node = view->change_list;
188 while ((node != NULL) && (node->offset != view->hex_cursor))
189 node = node->next;
191 if (!view->hexview_in_text)
193 /* Hex editing */
194 unsigned int hexvalue = 0;
196 if (key >= '0' && key <= '9')
197 hexvalue = 0 + (key - '0');
198 else if (key >= 'A' && key <= 'F')
199 hexvalue = 10 + (key - 'A');
200 else if (key >= 'a' && key <= 'f')
201 hexvalue = 10 + (key - 'a');
202 else
203 return MSG_NOT_HANDLED;
205 if (node != NULL)
206 byte_val = node->value;
207 else
208 mcview_get_byte (view, view->hex_cursor, &byte_val);
210 if (view->hexedit_lownibble)
211 byte_val = (byte_val & 0xf0) | (hexvalue);
212 else
213 byte_val = (byte_val & 0x0f) | (hexvalue << 4);
215 else
217 /* Text editing */
218 if (key < 256 && ((key == '\n') || is_printable (key)))
219 byte_val = key;
220 else
221 return MSG_NOT_HANDLED;
224 if ((view->filename != NULL) && (view->filename[0] != '\0') && (view->change_list == NULL))
225 view->locked = mcview_lock_file (view);
227 if (node == NULL)
229 node = g_new (struct hexedit_change_node, 1);
230 node->offset = view->hex_cursor;
231 node->value = byte_val;
232 mcview_enqueue_change (&view->change_list, node);
234 else
235 node->value = byte_val;
237 view->dirty++;
238 mcview_move_right (view, 1);
240 return MSG_HANDLED;
243 /* --------------------------------------------------------------------------------------------- */
245 static cb_ret_t
246 mcview_execute_cmd (mcview_t * view, unsigned long command)
248 int res = MSG_HANDLED;
250 switch (command)
252 case CK_ViewHelp:
253 interactive_display (NULL, "[Internal File Viewer]");
254 break;
255 case CK_ViewToggleWrapMode:
256 /* Toggle between wrapped and unwrapped view */
257 mcview_toggle_wrap_mode (view);
258 break;
259 case CK_ViewToggleHexEditMode:
260 /* Toggle between hexview and hexedit mode */
261 mcview_toggle_hexedit_mode (view);
262 break;
263 case CK_ViewToggleHexMode:
264 /* Toggle between hex view and text view */
265 mcview_toggle_hex_mode (view);
266 break;
267 case CK_ViewGoto:
269 off_t addr;
271 if (mcview_dialog_goto (view, &addr))
273 if (addr >= 0)
274 mcview_moveto_offset (view, addr);
275 else
277 message (D_ERROR, _("Warning"), _("Invalid value"));
278 view->dirty++;
281 break;
283 case CK_ViewHexEditSave:
284 mcview_hexedit_save_changes (view);
285 break;
286 case CK_ViewSearch:
287 mcview_search (view);
288 break;
289 case CK_ViewToggleMagicMode:
290 mcview_toggle_magic_mode (view);
291 break;
292 case CK_ViewToggleNroffMode:
293 mcview_toggle_nroff_mode (view);
294 break;
295 case CK_ViewToggleHexNavMode:
296 view->hexview_in_text = !view->hexview_in_text;
297 view->dirty++;
298 break;
299 case CK_ViewMoveToBol:
300 mcview_moveto_bol (view);
301 break;
302 case CK_ViewMoveToEol:
303 mcview_moveto_eol (view);
304 break;
305 case CK_ViewMoveLeft:
306 mcview_move_left (view, 1);
307 break;
308 case CK_ViewMoveRight:
309 mcview_move_right (view, 1);
310 break;
311 case CK_ViewMoveLeft10:
312 if (!view->hex_mode)
313 mcview_move_left (view, 10);
314 break;
315 case CK_ViewMoveRight10:
316 if (!view->hex_mode)
317 mcview_move_right (view, 10);
318 break;
319 case CK_ViewContinueSearch:
320 mcview_continue_search_cmd (view);
321 break;
322 case CK_ViewToggleRuler:
323 mcview_display_toggle_ruler (view);
324 break;
325 case CK_ViewMoveUp:
326 mcview_move_up (view, 1);
327 break;
328 case CK_ViewMoveDown:
329 mcview_move_down (view, 1);
330 break;
331 case CK_ViewMoveHalfPgUp:
332 mcview_move_up (view, (view->data_area.height + 1) / 2);
333 break;
334 case CK_ViewMoveHalfPgDn:
335 mcview_move_down (view, (view->data_area.height + 1) / 2);
336 break;
337 case CK_ViewMovePgUp:
338 mcview_move_up (view, view->data_area.height);
339 break;
340 case CK_ViewMovePgDn:
341 mcview_move_down (view, view->data_area.height);
342 break;
343 case CK_ViewMoveTop:
344 mcview_moveto_top (view);
345 break;
346 case CK_ViewMoveBottom:
347 mcview_moveto_bottom (view);
348 break;
349 case CK_ShowCommandLine:
350 view_other_cmd ();
351 break;
353 // Unlike Ctrl-O, run a new shell if the subshell is not running
354 case '!':
355 exec_shell ();
356 return MSG_HANDLED;
358 case CK_ViewGotoBookmark:
359 view->marks[view->marker] = view->dpy_start;
360 break;
361 case CK_ViewNewBookmark:
362 view->dpy_start = view->marks[view->marker];
363 view->dirty++;
364 break;
365 case CK_SelectCodepage:
366 mcview_select_encoding (view);
367 view->dirty++;
368 break;
369 case CK_ViewNextFile:
370 case CK_ViewPrevFile:
371 /* Use to indicate parent that we want to see the next/previous file */
372 /* Does not work in panel mode */
373 if (!mcview_is_in_panel (view))
374 view->move_dir = (command == CK_ViewNextFile) ? 1 : -1;
375 /* fallthrough */
376 case CK_ViewQuit:
377 if (!mcview_is_in_panel (view))
378 dlg_stop (view->widget.owner);
379 break;
380 default:
381 res = MSG_NOT_HANDLED;
383 return res;
386 /* --------------------------------------------------------------------------------------------- */
387 /** Both views */
388 static cb_ret_t
389 mcview_handle_key (mcview_t * view, int key)
391 unsigned long command;
393 key = convert_from_input_c (key);
395 if (view->hex_mode)
397 if (view->hexedit_mode && (mcview_handle_editkey (view, key) == MSG_HANDLED))
398 return MSG_HANDLED;
400 command = keybind_lookup_keymap_command (view->hex_map, key);
401 if ((command != CK_Ignore_Key) && (mcview_execute_cmd (view, command) == MSG_HANDLED))
402 return MSG_HANDLED;
405 command = keybind_lookup_keymap_command (view->plain_map, key);
406 if ((command != CK_Ignore_Key) && (mcview_execute_cmd (view, command) == MSG_HANDLED))
407 return MSG_HANDLED;
409 #ifdef MC_ENABLE_DEBUGGING_CODE
410 if (c == 't')
411 { /* mnemonic: "test" */
412 mcview_ccache_dump (view);
413 return MSG_HANDLED;
415 #endif
416 if (key >= '0' && key <= '9')
417 view->marker = key - '0';
419 /* Key not used */
420 return MSG_NOT_HANDLED;
424 /* --------------------------------------------------------------------------------------------- */
426 static inline void
427 mcview_adjust_size (Dlg_head * h)
429 mcview_t *view;
430 WButtonBar *b;
432 /* Look up the viewer and the buttonbar, we assume only two widgets here */
433 view = (mcview_t *) find_widget_type (h, mcview_callback);
434 b = find_buttonbar (h);
436 widget_set_size (&view->widget, 0, 0, LINES - 1, COLS);
437 widget_set_size (&b->widget, LINES - 1, 0, 1, COLS);
439 mcview_compute_areas (view);
440 mcview_update_bytes_per_line (view);
444 /* --------------------------------------------------------------------------------------------- */
445 /*** public functions ****************************************************************************/
446 /* --------------------------------------------------------------------------------------------- */
448 cb_ret_t
449 mcview_callback (Widget * w, widget_msg_t msg, int parm)
451 mcview_t *view = (mcview_t *) w;
452 cb_ret_t i;
454 mcview_compute_areas (view);
455 mcview_update_bytes_per_line (view);
457 switch (msg)
459 case WIDGET_INIT:
460 if (mcview_is_in_panel (view))
461 add_hook (&select_file_hook, mcview_hook, view);
462 else
463 view->dpy_bbar_dirty = TRUE;
464 return MSG_HANDLED;
466 case WIDGET_DRAW:
467 mcview_display (view);
468 return MSG_HANDLED;
470 case WIDGET_CURSOR:
471 if (view->hex_mode)
472 mcview_place_cursor (view);
473 return MSG_HANDLED;
475 case WIDGET_KEY:
476 i = mcview_handle_key (view, parm);
477 mcview_update (view);
478 return i;
480 case WIDGET_COMMAND:
481 i = mcview_execute_cmd (view, parm);
482 mcview_update (view);
483 return i;
485 case WIDGET_FOCUS:
486 view->dpy_bbar_dirty = TRUE;
487 mcview_update (view);
488 return MSG_HANDLED;
490 case WIDGET_DESTROY:
491 if (mcview_is_in_panel (view))
493 delete_hook (&select_file_hook, mcview_hook);
495 if (midnight_shutdown)
496 mcview_ok_to_quit (view);
498 mcview_done (view);
499 return MSG_HANDLED;
501 default:
502 return default_proc (msg, parm);
506 /* --------------------------------------------------------------------------------------------- */
508 cb_ret_t
509 mcview_dialog_callback (Dlg_head * h, Widget * sender, dlg_msg_t msg, int parm, void *data)
511 mcview_t *view;
513 switch (msg)
515 case DLG_RESIZE:
516 mcview_adjust_size (h);
517 return MSG_HANDLED;
519 case DLG_ACTION:
520 /* command from buttonbar */
521 view = (mcview_t *) data;
522 return send_message ((Widget *) view, WIDGET_COMMAND, parm);
524 case DLG_VALIDATE:
525 view = (mcview_t *) find_widget_type (h, mcview_callback);
526 h->state = DLG_ACTIVE; /* don't stop the dialog before final decision */
527 if (mcview_ok_to_quit (view))
528 h->state = DLG_CLOSED;
529 else
530 mcview_update (view);
531 return MSG_HANDLED;
533 default:
534 return default_dlg_callback (h, sender, msg, parm, data);
538 /* --------------------------------------------------------------------------------------------- */