(get_paragraph): fix of pointer difference.
[midnight-commander.git] / src / viewer / actions_cmd.c
blobf10021a92d8dbb42c579bcfc94832a522f59523f
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"
60 #include "lib/event.h" /* mc_event_raise() */
62 #include "src/filemanager/layout.h"
63 #include "src/filemanager/cmd.h"
64 #include "src/filemanager/midnight.h" /* current_panel */
66 #include "src/history.h"
67 #include "src/execute.h"
68 #include "src/keybind-defaults.h"
70 #include "internal.h"
71 #include "mcviewer.h"
73 /*** global variables ****************************************************************************/
75 /*** file scope macro definitions ****************************************************************/
77 /*** file scope type declarations ****************************************************************/
79 /*** file scope variables ************************************************************************/
81 /*** file scope functions ************************************************************************/
82 /* --------------------------------------------------------------------------------------------- */
84 /* Both views */
85 static void
86 mcview_search (mcview_t * view)
88 if (mcview_dialog_search (view))
89 mcview_do_search (view);
92 /* --------------------------------------------------------------------------------------------- */
94 static void
95 mcview_continue_search_cmd (mcview_t * view)
97 if (view->last_search_string != NULL)
99 mcview_do_search (view);
101 else
103 /* find last search string in history */
104 GList *history;
105 history = history_get (MC_HISTORY_SHARED_SEARCH);
106 if (history != NULL && history->data != NULL)
108 view->last_search_string = (gchar *) g_strdup (history->data);
109 history = g_list_first (history);
110 g_list_foreach (history, (GFunc) g_free, NULL);
111 g_list_free (history);
113 view->search = mc_search_new (view->last_search_string, -1);
114 view->search_nroff_seq = mcview_nroff_seq_new (view);
116 if (!view->search)
118 /* if not... then ask for an expression */
119 g_free (view->last_search_string);
120 view->last_search_string = NULL;
121 mcview_search (view);
123 else
125 view->search->search_type = mcview_search_options.type;
126 view->search->is_all_charsets = mcview_search_options.all_codepages;
127 view->search->is_case_sensitive = mcview_search_options.case_sens;
128 view->search->whole_words = mcview_search_options.whole_words;
129 view->search->search_fn = mcview_search_cmd_callback;
130 view->search->update_fn = mcview_search_update_cmd_callback;
132 mcview_do_search (view);
135 else
137 /* if not... then ask for an expression */
138 g_free (view->last_search_string);
139 view->last_search_string = NULL;
140 mcview_search (view);
145 /* --------------------------------------------------------------------------------------------- */
147 static void
148 mcview_hook (void *v)
150 mcview_t *view = (mcview_t *) v;
151 WPanel *panel;
153 /* If the user is busy typing, wait until he finishes to update the
154 screen */
155 if (!is_idle ())
157 if (!hook_present (idle_hook, mcview_hook))
158 add_hook (&idle_hook, mcview_hook, v);
159 return;
162 delete_hook (&idle_hook, mcview_hook);
164 if (get_current_type () == view_listing)
165 panel = current_panel;
166 else if (get_other_type () == view_listing)
167 panel = other_panel;
168 else
169 return;
171 mcview_done (view);
172 mcview_init (view);
173 mcview_load (view, 0, panel->dir.list[panel->selected].fname, 0);
174 mcview_display (view);
177 /* --------------------------------------------------------------------------------------------- */
179 static cb_ret_t
180 mcview_handle_editkey (mcview_t * view, int key)
182 struct hexedit_change_node *node;
183 int byte_val;
185 /* Has there been a change at this position? */
186 node = view->change_list;
187 while ((node != NULL) && (node->offset != view->hex_cursor))
188 node = node->next;
190 if (!view->hexview_in_text)
192 /* Hex editing */
193 unsigned int hexvalue = 0;
195 if (key >= '0' && key <= '9')
196 hexvalue = 0 + (key - '0');
197 else if (key >= 'A' && key <= 'F')
198 hexvalue = 10 + (key - 'A');
199 else if (key >= 'a' && key <= 'f')
200 hexvalue = 10 + (key - 'a');
201 else
202 return MSG_NOT_HANDLED;
204 if (node != NULL)
205 byte_val = node->value;
206 else
207 mcview_get_byte (view, view->hex_cursor, &byte_val);
209 if (view->hexedit_lownibble)
210 byte_val = (byte_val & 0xf0) | (hexvalue);
211 else
212 byte_val = (byte_val & 0x0f) | (hexvalue << 4);
214 else
216 /* Text editing */
217 if (key < 256 && ((key == '\n') || is_printable (key)))
218 byte_val = key;
219 else
220 return MSG_NOT_HANDLED;
223 if ((view->filename != NULL) && (view->filename[0] != '\0') && (view->change_list == NULL))
224 view->locked = mcview_lock_file (view);
226 if (node == NULL)
228 node = g_new (struct hexedit_change_node, 1);
229 node->offset = view->hex_cursor;
230 node->value = byte_val;
231 mcview_enqueue_change (&view->change_list, node);
233 else
234 node->value = byte_val;
236 view->dirty++;
237 mcview_move_right (view, 1);
239 return MSG_HANDLED;
242 /* --------------------------------------------------------------------------------------------- */
244 static cb_ret_t
245 mcview_execute_cmd (mcview_t * view, unsigned long command)
247 int res = MSG_HANDLED;
249 switch (command)
251 case CK_Help:
253 ev_help_t event_data = { NULL, "[Internal File Viewer]" };
254 mc_event_raise (MCEVENT_GROUP_CORE, "help", &event_data);
256 break;
257 case CK_WrapMode:
258 /* Toggle between wrapped and unwrapped view */
259 mcview_toggle_wrap_mode (view);
260 break;
261 case CK_HexEditMode:
262 /* Toggle between hexview and hexedit mode */
263 mcview_toggle_hexedit_mode (view);
264 break;
265 case CK_HexMode:
266 /* Toggle between hex view and text view */
267 mcview_toggle_hex_mode (view);
268 break;
269 case CK_Goto:
271 off_t addr;
273 if (mcview_dialog_goto (view, &addr))
275 if (addr >= 0)
276 mcview_moveto_offset (view, addr);
277 else
279 message (D_ERROR, _("Warning"), _("Invalid value"));
280 view->dirty++;
283 break;
285 case CK_Save:
286 mcview_hexedit_save_changes (view);
287 break;
288 case CK_Search:
289 mcview_search (view);
290 break;
291 case CK_MagicMode:
292 mcview_toggle_magic_mode (view);
293 break;
294 case CK_NroffMode:
295 mcview_toggle_nroff_mode (view);
296 break;
297 case CK_ToggleNavigation:
298 view->hexview_in_text = !view->hexview_in_text;
299 view->dirty++;
300 break;
301 case CK_Home:
302 mcview_moveto_bol (view);
303 break;
304 case CK_End:
305 mcview_moveto_eol (view);
306 break;
307 case CK_Left:
308 mcview_move_left (view, 1);
309 break;
310 case CK_Right:
311 mcview_move_right (view, 1);
312 break;
313 case CK_LeftQuick:
314 if (!view->hex_mode)
315 mcview_move_left (view, 10);
316 break;
317 case CK_RightQuick:
318 if (!view->hex_mode)
319 mcview_move_right (view, 10);
320 break;
321 case CK_SearchContinue:
322 mcview_continue_search_cmd (view);
323 break;
324 case CK_Ruler:
325 mcview_display_toggle_ruler (view);
326 break;
327 case CK_Up:
328 mcview_move_up (view, 1);
329 break;
330 case CK_Down:
331 mcview_move_down (view, 1);
332 break;
333 case CK_HalfPageUp:
334 mcview_move_up (view, (view->data_area.height + 1) / 2);
335 break;
336 case CK_HalfPageDown:
337 mcview_move_down (view, (view->data_area.height + 1) / 2);
338 break;
339 case CK_PageUp:
340 mcview_move_up (view, view->data_area.height);
341 break;
342 case CK_PageDown:
343 mcview_move_down (view, view->data_area.height);
344 break;
345 case CK_Top:
346 mcview_moveto_top (view);
347 break;
348 case CK_Bottom:
349 mcview_moveto_bottom (view);
350 break;
351 case CK_Shell:
352 view_other_cmd ();
353 break;
354 case CK_BookmarkGoto:
355 view->marks[view->marker] = view->dpy_start;
356 break;
357 case CK_Bookmark:
358 view->dpy_start = view->marks[view->marker];
359 view->dirty++;
360 break;
361 #ifdef HAVE_CHARSET
362 case CK_SelectCodepage:
363 mcview_select_encoding (view);
364 view->dirty++;
365 break;
366 #endif
367 case CK_FileNext:
368 case CK_FilePrev:
369 /* Use to indicate parent that we want to see the next/previous file */
370 /* Does not work in panel mode */
371 if (!mcview_is_in_panel (view))
372 view->move_dir = (command == CK_FileNext) ? 1 : -1;
373 /* fallthrough */
374 case CK_Quit:
375 if (!mcview_is_in_panel (view))
376 dlg_stop (view->widget.owner);
377 break;
378 case CK_Cancel:
379 /* don't close viewer due to SIGINT */
380 break;
381 default:
382 res = MSG_NOT_HANDLED;
384 return res;
387 /* --------------------------------------------------------------------------------------------- */
388 /** Both views */
389 static cb_ret_t
390 mcview_handle_key (mcview_t * view, int key)
392 unsigned long command;
394 key = convert_from_input_c (key);
396 if (view->hex_mode)
398 if (view->hexedit_mode && (mcview_handle_editkey (view, key) == MSG_HANDLED))
399 return MSG_HANDLED;
401 command = keybind_lookup_keymap_command (viewer_hex_map, key);
402 if ((command != CK_IgnoreKey) && (mcview_execute_cmd (view, command) == MSG_HANDLED))
403 return MSG_HANDLED;
406 command = keybind_lookup_keymap_command (viewer_map, key);
407 if ((command != CK_IgnoreKey) && (mcview_execute_cmd (view, command) == MSG_HANDLED))
408 return MSG_HANDLED;
410 #ifdef MC_ENABLE_DEBUGGING_CODE
411 if (c == 't')
412 { /* mnemonic: "test" */
413 mcview_ccache_dump (view);
414 return MSG_HANDLED;
416 #endif
417 if (key >= '0' && key <= '9')
418 view->marker = key - '0';
420 /* Key not used */
421 return MSG_NOT_HANDLED;
425 /* --------------------------------------------------------------------------------------------- */
427 static inline void
428 mcview_adjust_size (Dlg_head * h)
430 mcview_t *view;
431 WButtonBar *b;
433 /* Look up the viewer and the buttonbar, we assume only two widgets here */
434 view = (mcview_t *) find_widget_type (h, mcview_callback);
435 b = find_buttonbar (h);
437 widget_set_size (&view->widget, 0, 0, LINES - 1, COLS);
438 widget_set_size (&b->widget, LINES - 1, 0, 1, COLS);
440 mcview_compute_areas (view);
441 mcview_update_bytes_per_line (view);
445 /* --------------------------------------------------------------------------------------------- */
446 /*** public functions ****************************************************************************/
447 /* --------------------------------------------------------------------------------------------- */
449 cb_ret_t
450 mcview_callback (Widget * w, widget_msg_t msg, int parm)
452 mcview_t *view = (mcview_t *) w;
453 cb_ret_t i;
455 mcview_compute_areas (view);
456 mcview_update_bytes_per_line (view);
458 switch (msg)
460 case WIDGET_INIT:
461 if (mcview_is_in_panel (view))
462 add_hook (&select_file_hook, mcview_hook, view);
463 else
464 view->dpy_bbar_dirty = TRUE;
465 return MSG_HANDLED;
467 case WIDGET_DRAW:
468 mcview_display (view);
469 return MSG_HANDLED;
471 case WIDGET_CURSOR:
472 if (view->hex_mode)
473 mcview_place_cursor (view);
474 return MSG_HANDLED;
476 case WIDGET_KEY:
477 i = mcview_handle_key (view, parm);
478 mcview_update (view);
479 return i;
481 case WIDGET_COMMAND:
482 i = mcview_execute_cmd (view, parm);
483 mcview_update (view);
484 return i;
486 case WIDGET_FOCUS:
487 view->dpy_bbar_dirty = TRUE;
488 mcview_update (view);
489 return MSG_HANDLED;
491 case WIDGET_DESTROY:
492 if (mcview_is_in_panel (view))
494 delete_hook (&select_file_hook, mcview_hook);
496 if (mc_global.widget.midnight_shutdown)
497 mcview_ok_to_quit (view);
499 mcview_done (view);
500 return MSG_HANDLED;
502 default:
503 return default_proc (msg, parm);
507 /* --------------------------------------------------------------------------------------------- */
509 cb_ret_t
510 mcview_dialog_callback (Dlg_head * h, Widget * sender, dlg_msg_t msg, int parm, void *data)
512 mcview_t *view;
514 switch (msg)
516 case DLG_RESIZE:
517 mcview_adjust_size (h);
518 return MSG_HANDLED;
520 case DLG_ACTION:
521 /* shortcut */
522 if (sender == NULL)
523 return mcview_execute_cmd (NULL, parm);
524 /* message from buttonbar */
525 if (sender == (Widget *) find_buttonbar (h))
527 if (data != NULL)
528 return send_message ((Widget *) data, WIDGET_COMMAND, parm);
530 view = (mcview_t *) find_widget_type (h, mcview_callback);
531 return mcview_execute_cmd (view, parm);
533 return MSG_NOT_HANDLED;
535 case DLG_VALIDATE:
536 view = (mcview_t *) find_widget_type (h, mcview_callback);
537 h->state = DLG_ACTIVE; /* don't stop the dialog before final decision */
538 if (mcview_ok_to_quit (view))
539 h->state = DLG_CLOSED;
540 else
541 mcview_update (view);
542 return MSG_HANDLED;
544 default:
545 return default_dlg_callback (h, sender, msg, parm, data);
549 /* --------------------------------------------------------------------------------------------- */