summaryrefslogtreecommitdiff
path: root/pico/bind.c
diff options
context:
space:
mode:
authorEduardo Chappa <echappa@gmx.com>2013-02-03 00:59:38 -0700
committerEduardo Chappa <echappa@gmx.com>2013-02-03 00:59:38 -0700
commit094ca96844842928810f14844413109fc6cdd890 (patch)
treee60efbb980f38ba9308ccb4fb2b77b87bbc115f3 /pico/bind.c
downloadalpine-094ca96844842928810f14844413109fc6cdd890.tar.xz
Initial Alpine Version
Diffstat (limited to 'pico/bind.c')
-rw-r--r--pico/bind.c406
1 files changed, 406 insertions, 0 deletions
diff --git a/pico/bind.c b/pico/bind.c
new file mode 100644
index 00000000..83e93627
--- /dev/null
+++ b/pico/bind.c
@@ -0,0 +1,406 @@
+#if !defined(lint) && !defined(DOS)
+static char rcsid[] = "$Id: bind.c 857 2007-12-08 00:49:45Z hubert@u.washington.edu $";
+#endif
+
+/*
+ * ========================================================================
+ * Copyright 2006-2007 University of Washington
+ * Copyright 2013 Eduardo Chappa
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * ========================================================================
+ *
+ * Program: Key binding routines
+ */
+
+/* This file is for functions having to do with key bindings,
+ descriptions, help commands, and command line execution.
+
+ written 11-feb-86 by Daniel Lawrence
+ */
+
+#include "headers.h"
+
+int arraylen(char **);
+
+/*
+ * help - help function for pico (UW pared down version of uemacs).
+ * this function will intentionally garbage with helpful
+ * tips and then wait for a ' ' to be hit to then update the
+ * screen.
+ */
+
+
+static char *helptext[] = {
+ /* TRANSLATORS: The next several lines go together as help text.
+ Leave the ~ characters where they are, they cause the following
+ character to be printed in boldface as long as the first character
+ of the line is also a ~. */
+ N_(" Pico Help Text"),
+ " ",
+ N_(" Pico is designed to be a simple, easy-to-use text editor with a"),
+ N_(" layout very similar to the Alpine mailer. The status line at the"),
+ N_(" top of the display shows pico's version, the current file being"),
+ N_(" edited and whether or not there are outstanding modifications"),
+ N_(" that have not been saved. The third line from the bottom is used"),
+ N_(" to report informational messages and for additional command input."),
+ N_(" The bottom two lines list the available editing commands."),
+ " ",
+ N_(" Each character typed is automatically inserted into the buffer"),
+ N_(" at the current cursor position. Editing commands and cursor"),
+ N_(" movement (besides arrow keys) are given to pico by typing"),
+ N_(" special control-key sequences. A caret, '^', is used to denote"),
+ N_("~ the control key, sometimes marked \"CTRL\", so the ~C~T~R~L~-~q key"),
+ N_("~ combination is written as ~^~Q."),
+ " ",
+ N_(" The following functions are available in pico (where applicable,"),
+ N_(" corresponding function key commands are in parentheses)."),
+ " ",
+ N_("~ ~^~G (~F~1) Display this help text."),
+ " ",
+ N_("~ ~^~F move Forward a character."),
+ N_("~ ~^~B move Backward a character."),
+ N_("~ ~^~P move to the Previous line."),
+ N_("~ ~^~N move to the Next line."),
+ N_("~ ~^~A move to the beginning of the current line."),
+ N_("~ ~^~E move to the End of the current line."),
+ N_("~ ~^~V (~F~8) move forward a page of text."),
+ N_("~ ~^~Y (~F~7) move backward a page of text."),
+ " ",
+ N_("~ ~^~W (~F~6) Search for (where is) text, neglecting case."),
+ N_("~ ~^~L Refresh the display."),
+ " ",
+ N_("~ ~^~D Delete the character at the cursor position."),
+ N_("~ ~^~^ Mark cursor position as beginning of selected text."),
+ N_(" Note: Setting mark when already set unselects text."),
+ N_("~ ~^~K (~F~9) Cut selected text (displayed in inverse characters)."),
+ N_(" Note: The selected text's boundary on the cursor side"),
+ N_(" ends at the left edge of the cursor. So, with "),
+ N_(" selected text to the left of the cursor, the "),
+ N_(" character under the cursor is not selected."),
+ N_("~ ~^~U (~F~1~0) Uncut (paste) last cut text inserting it at the"),
+ N_(" current cursor position."),
+ N_("~ ~^~I Insert a tab at the current cursor position."),
+ " ",
+ N_("~ ~^~J (~F~4) Format (justify) the current paragraph."),
+ N_(" Note: paragraphs delimited by blank lines or indentation."),
+ N_("~ ~^~T (~F~1~2) To invoke the spelling checker"),
+ N_("~ ~^~C (~F~1~1) Report current cursor position"),
+ " ",
+ N_("~ ~^~R (~F~5) Insert an external file at the current cursor position."),
+ N_("~ ~^~O (~F~3) Output the current buffer to a file, saving it."),
+ N_("~ ~^~X (~F~2) Exit pico, saving buffer."),
+ " ",
+ N_(" End of Help."),
+ " ",
+ NULL
+};
+
+
+/*
+ * arraylen - return the number of bytes in an array of char
+ */
+int
+arraylen(char **array)
+{
+ register int i=0;
+
+ while(array[i++] != NULL) ;
+ return(i);
+}
+
+
+/*
+ * whelp - display help text for the composer and pico
+ */
+int
+whelp(int f, int n)
+{
+ if(term.t_mrow == 0){ /* blank keymenu in effect */
+ if(km_popped == 0){
+ /* cause keymenu display */
+ km_popped = 2;
+ if(!Pmaster)
+ sgarbf = TRUE;
+
+ return(TRUE);
+ }
+ }
+
+ if(Pmaster){
+ VARS_TO_SAVE *saved_state;
+
+ saved_state = save_pico_state();
+ (*Pmaster->helper)(Pmaster->composer_help,
+ Pmaster->headents
+ ? _("Help for the Alpine Composer")
+ : _("Help for Signature Editor"),
+ 1);
+ if(saved_state){
+ restore_pico_state(saved_state);
+ free_pico_state(saved_state);
+ }
+
+ ttresize();
+ picosigs(); /* restore any altered handlers */
+ curwp->w_flag |= WFMODE;
+ if(km_popped) /* this will unpop us */
+ curwp->w_flag |= WFHARD;
+ }
+ else{
+ int mrow_was_zero = 0;
+
+ /* always want keyhelp showing during help */
+ if(term.t_mrow == 0){
+ mrow_was_zero++;
+ term.t_mrow = 2;
+ }
+
+ /* TRANSLATORS: Pico is the name of a program */
+ pico_help(helptext, _("Help for Pico"), 1);
+ /* put it back the way it was */
+ if(mrow_was_zero)
+ term.t_mrow = 0;
+ }
+
+ sgarbf = TRUE;
+ return(FALSE);
+}
+
+static KEYMENU menu_scroll[] = {
+ {NULL, NULL, KS_NONE}, {NULL, NULL, KS_NONE},
+ {NULL, NULL, KS_NONE}, {NULL, NULL, KS_NONE},
+ {NULL, NULL, KS_NONE}, {NULL, NULL, KS_NONE},
+ {"^X", N_("Exit Help"), KS_NONE}, {NULL, NULL, KS_NONE},
+ {NULL, NULL, KS_NONE}, {NULL, NULL, KS_NONE},
+ {NULL, NULL, KS_NONE}, {NULL, NULL, KS_NONE}
+};
+#define PREV_KEY 3
+#define NEXT_KEY 9
+
+
+#define OVERLAP 2 /* displayed page overlap */
+
+/*
+ * scrollw - takes beginning row and ending row to diplay an array
+ * of text lines. returns either 0 if scrolling terminated
+ * normally or the value of a ctrl character typed to end it.
+ *
+ * updates -
+ * 01/11/89 - added stripe call if 1st char is tilde - '~'
+ *
+ */
+int
+wscrollw(int begrow, int endrow, char *utf8textp[], int textlen)
+{
+ register int loffset = 0;
+ register int prevoffset = -1;
+ register int dlines;
+ register int i;
+ register int cont;
+ register int done = 0;
+ register char *buf;
+ UCS c;
+
+ dlines = endrow - begrow - 1;
+ while(!done) {
+ /*
+ * diplay a page loop ...
+ */
+ if(prevoffset != loffset){
+ for(i = 0; i < dlines; i++){
+ movecursor(i + begrow, 0);
+ peeol();
+ if((loffset+i) < textlen){
+ buf = _(&(utf8textp[loffset+i][0]));
+ if(*buf == '~'){
+ buf++;
+ wstripe(begrow+i, 0, buf, '~');
+ }
+ else{
+ pputs_utf8(buf, 0);
+ }
+ }
+ }
+ /*
+ * put up the options prompt
+ */
+ movecursor(begrow + dlines, 0);
+ cont = (loffset+dlines < textlen);
+ if(cont){ /* continue ? */
+ menu_scroll[NEXT_KEY].name = "^V";
+ /* TRANSLATORS: Next Page, a command key label */
+ menu_scroll[NEXT_KEY].label = N_("Next Pg");
+ }
+ else
+ menu_scroll[NEXT_KEY].name = NULL;
+
+ if(loffset){
+ menu_scroll[PREV_KEY].name = "^Y";
+ /* TRANSLATORS: Previous Page */
+ menu_scroll[PREV_KEY].label = N_("Prev Pg");
+ }
+ else
+ menu_scroll[PREV_KEY].name = NULL;
+
+ wkeyhelp(menu_scroll);
+ }
+
+ (*term.t_flush)();
+
+ c = GetKey();
+
+ prevoffset = loffset;
+ switch(c){
+ case (CTRL|'X') : /* quit */
+ case F2 :
+ done = 1;
+ break;
+ case (CTRL|'Y') : /* prev page */
+ case F7 : /* prev page */
+ if((loffset-dlines-OVERLAP) > 0){
+ loffset -= (dlines-OVERLAP);
+ }
+ else{
+ if(loffset != 0){
+ prevoffset = -1;
+ }
+ else{
+ (*term.t_beep)();
+ }
+ loffset = 0;
+ }
+ break;
+ case (CTRL|'V') : /* next page */
+ case F8 :
+ if(cont){
+ loffset += (dlines-OVERLAP);
+ }
+ else{
+ (*term.t_beep)();
+ }
+ break;
+ case '\016' : /* prev-line */
+ case (CTRL|'N') :
+ if(cont)
+ loffset++;
+ else
+ (*term.t_beep)();
+ break;
+ case '\020' : /* prev-line */
+ case (CTRL|'P') :
+ if(loffset > 0)
+ loffset--;
+ else
+ (*term.t_beep)();
+ break;
+ case '\014' : /* refresh */
+ case (CTRL|'L') : /* refresh */
+ modeline(curwp);
+ update();
+ prevoffset = -1;
+ break;
+ case NODATA :
+ break;
+#ifdef notdef
+ /*
+ * We don't handle window resize events correctly when in pico help.
+ * resize_pico() redraws the edit window instead of the help window.
+ * A ^L will redraw the help text. What we'd like is something like
+ * a KEY_RESIZE return from GetKey. If we had that we could exit
+ * wscrollw with a FALSE return value and have that cause us to loop
+ * back into wscrollw with the adjusted size. That would still mean
+ * the edit text would be redrawn first...
+ */
+#endif /* notdef */
+ default :
+ unknown_command(c);
+ break;
+ }
+ }
+
+ return(TRUE);
+}
+
+
+/*
+ * normalize_cmd - given a char and list of function key to command key
+ * mappings, return, depending on gmode, the right command.
+ * The list is an array of (Fkey, command-key) pairs.
+ * sc is the index in the array that means to ignore fkey
+ * vs. command key mapping
+ *
+ * rules: 1. if c not in table (either fkey or command), let it thru
+ * 2. if c matches, but in other mode, punt it
+ */
+UCS
+normalize_cmd(UCS c, UCS list[][2], int sc)
+{
+ int i;
+
+ for(i=0; i < 12; i++){
+ if(c == list[i][(FUNC&c) ? 0 : 1]){ /* in table? */
+ if(i == sc) /* SPECIAL CASE! */
+ return(list[i][1]);
+
+ if(list[i][1] == NODATA) /* no mapping ! */
+ return(c);
+
+ if(((FUNC&c) == FUNC) && !((gmode&MDFKEY) == MDFKEY))
+ return(c); /* not allowed, let caller handle it */
+ else
+ return(list[i][1]); /* never return func keys */
+ }
+ }
+
+ return(c);
+}
+
+
+/*
+ * rebind - replace the first function with the second
+ */
+void
+rebindfunc(int (*a)(int, int), int (*b)(int, int))
+{
+ KEYTAB *kp;
+
+ kp = (Pmaster) ? &keytab[0] : &pkeytab[0];
+
+ while(kp->k_fp != NULL){ /* go thru whole list, and */
+ if(kp->k_fp == a)
+ kp->k_fp = b; /* replace all occurances */
+ kp++;
+ }
+}
+
+
+/*
+ * bindtokey - bind function f to command c
+ */
+int
+bindtokey(UCS c, int (*f)(int, int))
+{
+ KEYTAB *kp, *ktab = (Pmaster) ? &keytab[0] : &pkeytab[0];
+
+ for(kp = ktab; kp->k_fp; kp++)
+ if(kp->k_code == c){
+ kp->k_fp = f; /* set to new function */
+ break;
+ }
+
+ /* not found? create new binding */
+ if(!kp->k_fp && kp < &ktab[NBINDS]){
+ kp->k_code = c; /* assign new code and function */
+ kp->k_fp = f;
+ (++kp)->k_code = 0; /* and null out next slot */
+ kp->k_fp = NULL;
+ }
+
+ return(TRUE);
+}