Merge branch 'ical'
[alpine.git] / pico / bind.c
blob7678797d2d70ceb9bee35a4b7f9092c8f84de5d4
1 #if !defined(lint) && !defined(DOS)
2 static char rcsid[] = "$Id: bind.c 857 2007-12-08 00:49:45Z hubert@u.washington.edu $";
3 #endif
5 /*
6 * ========================================================================
7 * Copyright 2006-2007 University of Washington
8 * Copyright 2013-2017 Eduardo Chappa
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * ========================================================================
18 * Program: Key binding routines
21 /* This file is for functions having to do with key bindings,
22 descriptions, help commands, and command line execution.
24 written 11-feb-86 by Daniel Lawrence
27 #include "headers.h"
29 int arraylen(char **);
31 /*
32 * help - help function for pico (UW pared down version of uemacs).
33 * this function will intentionally garbage with helpful
34 * tips and then wait for a ' ' to be hit to then update the
35 * screen.
39 static char *helptext[] = {
40 /* TRANSLATORS: The next several lines go together as help text.
41 Leave the ~ characters where they are, they cause the following
42 character to be printed in boldface as long as the first character
43 of the line is also a ~. */
44 N_(" Pico Help Text"),
45 " ",
46 N_(" Pico is designed to be a simple, easy-to-use text editor with a"),
47 N_(" layout very similar to the Alpine mailer. The status line at the"),
48 N_(" top of the display shows pico's version, the current file being"),
49 N_(" edited and whether or not there are outstanding modifications"),
50 N_(" that have not been saved. The third line from the bottom is used"),
51 N_(" to report informational messages and for additional command input."),
52 N_(" The bottom two lines list the available editing commands."),
53 " ",
54 N_(" Each character typed is automatically inserted into the buffer"),
55 N_(" at the current cursor position. Editing commands and cursor"),
56 N_(" movement (besides arrow keys) are given to pico by typing"),
57 N_(" special control-key sequences. A caret, '^', is used to denote"),
58 N_("~ the control key, sometimes marked \"CTRL\", so the ~C~T~R~L~-~q key"),
59 N_("~ combination is written as ~^~Q."),
60 " ",
61 N_(" The following functions are available in pico (where applicable,"),
62 N_(" corresponding function key commands are in parentheses)."),
63 " ",
64 N_("~ ~^~G (~F~1) Display this help text."),
65 " ",
66 N_("~ ~^~F move Forward a character."),
67 N_("~ ~^~B move Backward a character."),
68 N_("~ ~^~P move to the Previous line."),
69 N_("~ ~^~N move to the Next line."),
70 N_("~ ~^~A move to the beginning of the current line."),
71 N_("~ ~^~E move to the End of the current line."),
72 N_("~ ~^~V (~F~8) move forward a page of text."),
73 N_("~ ~^~Y (~F~7) move backward a page of text."),
74 " ",
75 N_("~ ~^~W (~F~6) Search for (where is) text, neglecting case."),
76 N_("~ ~^~L Refresh the display."),
77 " ",
78 N_("~ ~^~D Delete the character at the cursor position."),
79 N_("~ ~^~^ Mark cursor position as beginning of selected text."),
80 N_(" Note: Setting mark when already set unselects text."),
81 N_("~ ~^~K (~F~9) Cut selected text (displayed in inverse characters)."),
82 N_(" Note: The selected text's boundary on the cursor side"),
83 N_(" ends at the left edge of the cursor. So, with "),
84 N_(" selected text to the left of the cursor, the "),
85 N_(" character under the cursor is not selected."),
86 N_("~ ~^~U (~F~1~0) Uncut (paste) last cut text inserting it at the"),
87 N_(" current cursor position."),
88 N_("~ ~^~I Insert a tab at the current cursor position."),
89 " ",
90 N_("~ ~^~J (~F~4) Format (justify) the current paragraph."),
91 N_(" Note: paragraphs delimited by blank lines or indentation."),
92 N_("~ ~^~T (~F~1~2) To invoke the spelling checker"),
93 N_("~ ~^~C (~F~1~1) Report current cursor position"),
94 " ",
95 N_("~ ~^~R (~F~5) Insert an external file at the current cursor position."),
96 N_("~ ~^~O (~F~3) Output the current buffer to a file, saving it."),
97 N_("~ ~^~X (~F~2) Exit pico, saving buffer."),
98 " ",
99 N_(" End of Help."),
100 " ",
101 NULL
106 * arraylen - return the number of bytes in an array of char
109 arraylen(char **array)
111 register int i=0;
113 while(array[i++] != NULL) ;
114 return(i);
119 * whelp - display help text for the composer and pico
122 whelp(int f, int n)
124 if(term.t_mrow == 0){ /* blank keymenu in effect */
125 if(km_popped == 0){
126 /* cause keymenu display */
127 km_popped = 2;
128 if(!Pmaster)
129 sgarbf = TRUE;
131 return(TRUE);
135 if(Pmaster){
136 VARS_TO_SAVE *saved_state;
138 saved_state = save_pico_state();
139 (*Pmaster->helper)(Pmaster->composer_help,
140 Pmaster->headents
141 ? _("Help for the Alpine Composer")
142 : _("Help for Signature Editor"),
144 if(saved_state){
145 restore_pico_state(saved_state);
146 free_pico_state(saved_state);
149 ttresize();
150 picosigs(); /* restore any altered handlers */
151 curwp->w_flag |= WFMODE;
152 if(km_popped) /* this will unpop us */
153 curwp->w_flag |= WFHARD;
155 else{
156 int mrow_was_zero = 0;
158 /* always want keyhelp showing during help */
159 if(term.t_mrow == 0){
160 mrow_was_zero++;
161 term.t_mrow = 2;
164 /* TRANSLATORS: Pico is the name of a program */
165 pico_help(helptext, _("Help for Pico"), 1);
166 /* put it back the way it was */
167 if(mrow_was_zero)
168 term.t_mrow = 0;
171 sgarbf = TRUE;
172 return(FALSE);
175 static KEYMENU menu_scroll[] = {
176 {NULL, NULL, KS_NONE}, {NULL, NULL, KS_NONE},
177 {NULL, NULL, KS_NONE}, {NULL, NULL, KS_NONE},
178 {NULL, NULL, KS_NONE}, {NULL, NULL, KS_NONE},
179 {"^X", N_("Exit Help"), KS_NONE}, {NULL, NULL, KS_NONE},
180 {NULL, NULL, KS_NONE}, {NULL, NULL, KS_NONE},
181 {NULL, NULL, KS_NONE}, {NULL, NULL, KS_NONE}
183 #define PREV_KEY 3
184 #define NEXT_KEY 9
187 #define OVERLAP 2 /* displayed page overlap */
190 * scrollw - takes beginning row and ending row to diplay an array
191 * of text lines. returns either 0 if scrolling terminated
192 * normally or the value of a ctrl character typed to end it.
194 * updates -
195 * 01/11/89 - added stripe call if 1st char is tilde - '~'
199 wscrollw(int begrow, int endrow, char *utf8textp[], int textlen)
201 register int loffset = 0;
202 register int prevoffset = -1;
203 register int dlines;
204 register int i;
205 register int cont;
206 register int done = 0;
207 register char *buf;
208 UCS c;
210 dlines = endrow - begrow - 1;
211 while(!done) {
213 * diplay a page loop ...
215 if(prevoffset != loffset){
216 for(i = 0; i < dlines; i++){
217 movecursor(i + begrow, 0);
218 peeol();
219 if((loffset+i) < textlen){
220 buf = _(&(utf8textp[loffset+i][0]));
221 if(*buf == '~'){
222 buf++;
223 wstripe(begrow+i, 0, buf, '~');
225 else{
226 pputs_utf8(buf, 0);
231 * put up the options prompt
233 movecursor(begrow + dlines, 0);
234 cont = (loffset+dlines < textlen);
235 if(cont){ /* continue ? */
236 menu_scroll[NEXT_KEY].name = "^V";
237 /* TRANSLATORS: Next Page, a command key label */
238 menu_scroll[NEXT_KEY].label = N_("Next Pg");
240 else
241 menu_scroll[NEXT_KEY].name = NULL;
243 if(loffset){
244 menu_scroll[PREV_KEY].name = "^Y";
245 /* TRANSLATORS: Previous Page */
246 menu_scroll[PREV_KEY].label = N_("Prev Pg");
248 else
249 menu_scroll[PREV_KEY].name = NULL;
251 wkeyhelp(menu_scroll);
254 (*term.t_flush)();
256 c = GetKey();
258 prevoffset = loffset;
259 switch(c){
260 case (CTRL|'X') : /* quit */
261 case F2 :
262 done = 1;
263 break;
264 case (CTRL|'Y') : /* prev page */
265 case F7 : /* prev page */
266 if((loffset-dlines-OVERLAP) > 0){
267 loffset -= (dlines-OVERLAP);
269 else{
270 if(loffset != 0){
271 prevoffset = -1;
273 else{
274 (*term.t_beep)();
276 loffset = 0;
278 break;
279 case (CTRL|'V') : /* next page */
280 case F8 :
281 if(cont){
282 loffset += (dlines-OVERLAP);
284 else{
285 (*term.t_beep)();
287 break;
288 case '\016' : /* prev-line */
289 case (CTRL|'N') :
290 if(cont)
291 loffset++;
292 else
293 (*term.t_beep)();
294 break;
295 case '\020' : /* prev-line */
296 case (CTRL|'P') :
297 if(loffset > 0)
298 loffset--;
299 else
300 (*term.t_beep)();
301 break;
302 case '\014' : /* refresh */
303 case (CTRL|'L') : /* refresh */
304 modeline(curwp);
305 update();
306 prevoffset = -1;
307 break;
308 case NODATA :
309 break;
310 #ifdef notdef
312 * We don't handle window resize events correctly when in pico help.
313 * resize_pico() redraws the edit window instead of the help window.
314 * A ^L will redraw the help text. What we'd like is something like
315 * a KEY_RESIZE return from GetKey. If we had that we could exit
316 * wscrollw with a FALSE return value and have that cause us to loop
317 * back into wscrollw with the adjusted size. That would still mean
318 * the edit text would be redrawn first...
320 #endif /* notdef */
321 default :
322 unknown_command(c);
323 break;
327 return(TRUE);
332 * normalize_cmd - given a char and list of function key to command key
333 * mappings, return, depending on gmode, the right command.
334 * The list is an array of (Fkey, command-key) pairs.
335 * sc is the index in the array that means to ignore fkey
336 * vs. command key mapping
338 * rules: 1. if c not in table (either fkey or command), let it thru
339 * 2. if c matches, but in other mode, punt it
342 normalize_cmd(UCS c, UCS list[][2], int sc)
344 int i;
346 for(i=0; i < 12; i++){
347 if(c == list[i][(FUNC&c) ? 0 : 1]){ /* in table? */
348 if(i == sc) /* SPECIAL CASE! */
349 return(list[i][1]);
351 if(list[i][1] == NODATA) /* no mapping ! */
352 return(c);
354 if(((FUNC&c) == FUNC) && !((gmode&MDFKEY) == MDFKEY))
355 return(c); /* not allowed, let caller handle it */
356 else
357 return(list[i][1]); /* never return func keys */
361 return(c);
366 * rebind - replace the first function with the second
368 void
369 rebindfunc(int (*a)(int, int), int (*b)(int, int))
371 KEYTAB *kp;
373 kp = (Pmaster) ? &keytab[0] : &pkeytab[0];
375 while(kp->k_fp != NULL){ /* go thru whole list, and */
376 if(kp->k_fp == a)
377 kp->k_fp = b; /* replace all occurances */
378 kp++;
384 * bindtokey - bind function f to command c
387 bindtokey(UCS c, int (*f)(int, int))
389 KEYTAB *kp, *ktab = (Pmaster) ? &keytab[0] : &pkeytab[0];
391 for(kp = ktab; kp->k_fp; kp++)
392 if(kp->k_code == c){
393 kp->k_fp = f; /* set to new function */
394 break;
397 /* not found? create new binding */
398 if(!kp->k_fp && kp < &ktab[NBINDS]){
399 kp->k_code = c; /* assign new code and function */
400 kp->k_fp = f;
401 (++kp)->k_code = 0; /* and null out next slot */
402 kp->k_fp = NULL;
405 return(TRUE);