diff options
Diffstat (limited to 'decode.c')
| -rw-r--r-- | decode.c | 315 |
1 files changed, 180 insertions, 135 deletions
@@ -1,5 +1,5 @@ /* - * Copyright (C) 1984-2024 Mark Nudelman + * Copyright (C) 1984-2025 Mark Nudelman * * You may distribute under the terms of either the GNU General Public * License or the Less License, as specified in the README file. @@ -37,6 +37,8 @@ extern int erase_char, erase2_char, kill_char; extern int mousecap; extern int sc_height; +static constant lbool allow_drag = TRUE; + #if USERFILE /* "content" is lesskey source, never binary. */ static void add_content_table(int (*call_lesskey)(constant char *, lbool), constant char *envname, lbool sysvar); @@ -86,6 +88,9 @@ static unsigned char cmdtable[] = 'z',0, A_F_WINDOW, 'w',0, A_B_WINDOW, ESC,' ',0, A_FF_SCREEN, + ESC,'b',0, A_BF_SCREEN, + ESC,'j',0, A_F_NEWLINE, + ESC,'k',0, A_B_NEWLINE, 'F',0, A_F_FOREVER, ESC,'F',0, A_F_UNTIL_HILITE, 'R',0, A_FREPAINT, @@ -178,6 +183,8 @@ static unsigned char cmdtable[] = '!',0, A_SHELL, '#',0, A_PSHELL, '+',0, A_FIRSTCMD, + ESC,'[','2','0','0','~',0, A_START_PASTE, + ESC,'[','2','0','1','~',0, A_END_PASTE, 'H',0, A_HELP, 'h',0, A_HELP, @@ -229,6 +236,8 @@ static unsigned char edittable[] = CONTROL('G'),0, EC_ABORT, /* CTRL-G */ ESC,'[','M',0, EC_X11MOUSE, /* X11 mouse report */ ESC,'[','<',0, EC_X116MOUSE, /* X11 1006 mouse report */ + ESC,'[','2','0','0','~',0, A_START_PASTE, /* open paste bracket */ + ESC,'[','2','0','1','~',0, A_END_PASTE, /* close paste bracket */ }; static unsigned char dflt_vartable[] = @@ -514,22 +523,42 @@ static int mouse_wheel_up(void) /* * Return action for the left mouse button trigger. */ -static int mouse_button_left(int x, int y) +static int mouse_button_left(int x, int y, lbool down, lbool drag) { - /* - * {{ It would be better to return an action and then do this - * in commands() but it's nontrivial to pass y to it. }} - */ + static int last_drag_y = -1; + static int last_click_y = -1; + + if (down && !drag) + { + last_drag_y = last_click_y = y; + } + if (allow_drag && drag && last_drag_y >= 0) + { + /* Drag text up/down */ + if (y > last_drag_y) + { + cmd_exec(); + backward(y - last_drag_y, FALSE, FALSE, FALSE); + last_drag_y = y; + } else if (y < last_drag_y) + { + cmd_exec(); + forward(last_drag_y - y, FALSE, FALSE, FALSE); + last_drag_y = y; + } + } else if (!down) + { #if OSC8_LINK - if (osc8_click(y, x)) - return (A_NOACTION); + if (osc8_click(y, x)) + return (A_NOACTION); #else - (void) x; + (void) x; #endif /* OSC8_LINK */ - if (y < sc_height-1) - { - setmark('#', y); - screen_trashed(); + if (y < sc_height-1 && y == last_click_y) + { + setmark('#', y); + screen_trashed(); + } } return (A_NOACTION); } @@ -537,14 +566,14 @@ static int mouse_button_left(int x, int y) /* * Return action for the right mouse button trigger. */ -static int mouse_button_right(int x, int y) +static int mouse_button_right(int x, int y, lbool down, lbool drag) { - (void) x; + (void) x; (void) drag; /* * {{ unlike mouse_button_left, we could return an action, * but keep it near mouse_button_left for readability. }} */ - if (y < sc_height-1) + if (!down && y < sc_height-1) { gomark('#'); screen_trashed(); @@ -575,49 +604,61 @@ static int getcc_int(char *pterm) } } +static int x11mouse_button(int btn, int x, int y, lbool down, lbool drag) +{ + switch (btn) { + case X11MOUSE_BUTTON1: + return mouse_button_left(x, y, down, drag); + /* is BUTTON2 the rightmost with 2-buttons mouse? */ + case X11MOUSE_BUTTON2: + case X11MOUSE_BUTTON3: + return mouse_button_right(x, y, down, drag); + } + return (A_NOACTION); +} + /* * Read suffix of mouse input and return the action to take. * The prefix ("\e[M") has already been read. */ -static int x11mouse_action(int skip) +static int x11mouse_action(lbool skip) { static int prev_b = X11MOUSE_BUTTON_REL; + int x, y; int b = getcc() - X11MOUSE_OFFSET; - int x = getcc() - X11MOUSE_OFFSET-1; - int y = getcc() - X11MOUSE_OFFSET-1; + lbool drag = ((b & X11MOUSE_DRAG) != 0); + b &= ~X11MOUSE_DRAG; + x = getcc() - X11MOUSE_OFFSET-1; + y = getcc() - X11MOUSE_OFFSET-1; if (skip) return (A_NOACTION); switch (b) { - default: - prev_b = b; - return (A_NOACTION); case X11MOUSE_WHEEL_DOWN: return mouse_wheel_down(); case X11MOUSE_WHEEL_UP: return mouse_wheel_up(); - case X11MOUSE_BUTTON_REL: - /* to trigger on button-up, we check the last button-down */ - switch (prev_b) { - case X11MOUSE_BUTTON1: - return mouse_button_left(x, y); - /* is BUTTON2 the rightmost with 2-buttons mouse? */ - case X11MOUSE_BUTTON2: - case X11MOUSE_BUTTON3: - return mouse_button_right(x, y); - } - return (A_NOACTION); + case X11MOUSE_BUTTON1: + case X11MOUSE_BUTTON2: + case X11MOUSE_BUTTON3: + prev_b = b; + return x11mouse_button(b, x, y, TRUE, drag); + case X11MOUSE_BUTTON_REL: /* button up */ + return x11mouse_button(prev_b, x, y, FALSE, drag); } + return (A_NOACTION); } /* * Read suffix of mouse input and return the action to take. * The prefix ("\e[<") has already been read. */ -static int x116mouse_action(int skip) +static int x116mouse_action(lbool skip) { char ch; int x, y; int b = getcc_int(&ch); + lbool drag = ((b & X11MOUSE_DRAG) != 0); + b &= ~X11MOUSE_DRAG; if (b < 0 || ch != ';') return (A_NOACTION); x = getcc_int(&ch) - 1; if (x < 0 || ch != ';') return (A_NOACTION); @@ -631,106 +672,94 @@ static int x116mouse_action(int skip) case X11MOUSE_WHEEL_UP: return mouse_wheel_up(); case X11MOUSE_BUTTON1: - if (ch != 'm') return (A_NOACTION); - return mouse_button_left(x, y); - default: - if (ch != 'm') return (A_NOACTION); - /* any other button release */ - return mouse_button_right(x, y); + case X11MOUSE_BUTTON2: + case X11MOUSE_BUTTON3: { + lbool down = (ch == 'M'); + lbool up = (ch == 'm'); + if (up || down) + return x11mouse_button(b, x, y, down, drag); + break; } } + return (A_NOACTION); } /* - * Search a single command table for the command string in cmd. + * Return the largest N such that the first N chars of goal + * are equal to the last N chars of str. */ -static int cmd_search(constant char *cmd, constant char *table, constant char *endtable, constant char **sp) +static size_t cmd_match(constant char *goal, constant char *str) { - constant char *p; - constant char *q; - int a = A_INVALID; + size_t slen = strlen(str); + size_t len; + for (len = slen; len > 0; len--) + if (strncmp(str + slen - len, goal, len) == 0) + break; + return len; +} - *sp = NULL; - for (p = table, q = cmd; p < endtable; p++, q++) +/* + * Return pointer to next command table entry. + * Also return the action and the extra string from the entry. + */ +static constant unsigned char * cmd_next_entry(constant unsigned char *entry, mutable int *action, mutable constant unsigned char **extra, mutable size_t *cmdlen) +{ + int a; + constant unsigned char *oentry = entry; + while (*entry != '\0') /* skip cmd */ + ++entry; + if (cmdlen != NULL) + *cmdlen = ptr_diff(entry, oentry); + do + a = *++entry; /* get action */ + while (a == A_SKIP); + ++entry; /* skip action */ + if (extra != NULL) + *extra = (a & A_EXTRA) ? entry : NULL; + if (a & A_EXTRA) { - if (*p == *q) + while (*entry++ != '\0') /* skip extra string */ + continue; + a &= ~A_EXTRA; + } + if (action != NULL) + *action = a; + return entry; +} + +/* + * Search a single command table for the command string in cmd. + */ +static int cmd_search(constant char *cmd, constant unsigned char *table, constant unsigned char *endtable, constant unsigned char **extra, size_t *mlen) +{ + int action = A_INVALID; + size_t match_len = 0; + if (extra != NULL) + *extra = NULL; + while (table < endtable) + { + int taction; + const unsigned char *textra; + size_t cmdlen; + size_t match = cmd_match((constant char *) table, cmd); + table = cmd_next_entry(table, &taction, &textra, &cmdlen); + if (taction == A_END_LIST) + return (-action); + if (match >= match_len) { - /* - * Current characters match. - * If we're at the end of the string, we've found it. - * Return the action code, which is the character - * after the null at the end of the string - * in the command table. - */ - if (*p == '\0') + if (match == cmdlen) /* (last chars of) cmd matches this table entry */ { - a = *++p & 0377; - while (a == A_SKIP) - a = *++p & 0377; - if (a == A_END_LIST) - { - /* - * We get here only if the original - * cmd string passed in was empty (""). - * I don't think that can happen, - * but just in case ... - */ - return (A_UINVALID); - } - /* - * Check for an "extra" string. - */ - if (a & A_EXTRA) - { - *sp = ++p; - while (*p != '\0') - ++p; - a &= ~A_EXTRA; - } - if (a == A_X11MOUSE_IN) - a = x11mouse_action(0); - else if (a == A_X116MOUSE_IN) - a = x116mouse_action(0); - q = cmd-1; - } - } else if (*q == '\0') - { - /* - * Hit the end of the user's command, - * but not the end of the string in the command table. - * The user's command is incomplete. - */ - if (a == A_INVALID) - a = A_PREFIX; - q = cmd-1; - } else - { - /* - * Not a match. - * Skip ahead to the next command in the - * command table, and reset the pointer - * to the beginning of the user's command. - */ - if (*p == '\0' && p[1] == A_END_LIST) + action = taction; + *extra = textra; + } else if (match > 0) /* cmd is a prefix of this table entry */ { - /* - * A_END_LIST is a special marker that tells - * us to abort the cmd search. - * Negative action means accept this action - * without searching any more cmd tables. - */ - return -a; + action = A_PREFIX; } - while (*p++ != '\0') - continue; - while (*p == A_SKIP) - p++; - if (*p & A_EXTRA) - while (*++p != '\0') - continue; - q = cmd-1; + match_len = match; } } - return (a); + if (mlen != NULL) + *mlen = match_len; + return (action); } /* @@ -741,6 +770,7 @@ static int cmd_decode(struct tablelist *tlist, constant char *cmd, constant char { struct tablelist *t; int action = A_INVALID; + size_t match_len = 0; /* * Search for the cmd thru all the command tables. @@ -749,18 +779,30 @@ static int cmd_decode(struct tablelist *tlist, constant char *cmd, constant char *sp = NULL; for (t = tlist; t != NULL; t = t->t_next) { - constant char *tsp; - int taction = cmd_search(cmd, (char *) t->t_start, (char *) t->t_end, &tsp); - if (taction == A_UINVALID) - taction = A_INVALID; - if (taction != A_INVALID) + constant unsigned char *tsp; + size_t mlen; + int taction = cmd_search(cmd, t->t_start, t->t_end, &tsp, &mlen); + if (mlen >= match_len) { - *sp = tsp; - if (taction < 0) - return (-taction); - action = taction; + match_len = mlen; + if (taction == A_UINVALID) + taction = A_INVALID; + if (taction != A_INVALID) + { + *sp = (constant char *) tsp; + if (taction < 0) + { + action = -taction; + break; + } + action = taction; + } } } + if (action == A_X11MOUSE_IN) + action = x11mouse_action(FALSE); + else if (action == A_X116MOUSE_IN) + action = x116mouse_action(FALSE); return (action); } @@ -780,6 +822,7 @@ public int ecmd_decode(constant char *cmd, constant char **sp) return (cmd_decode(list_ecmd_tables, cmd, sp)); } + /* * Get the value of an environment variable. * Looks first in the lesskey file, then in the real environment. @@ -1003,10 +1046,12 @@ public int lesskey(constant char *filename, lbool sysvar) #if HAVE_LESSKEYSRC static int lesskey_text(constant char *filename, lbool sysvar, lbool content) { + int r; static struct lesskey_tables tables; + if (!secure_allow(SF_LESSKEY)) return (1); - int r = content ? parse_lesskey_content(filename, &tables) : parse_lesskey(filename, &tables); + r = content ? parse_lesskey_content(filename, &tables) : parse_lesskey(filename, &tables); if (r != 0) return (r); add_fcmd_table(tables.cmdtable.buf.data, tables.cmdtable.buf.end); @@ -1080,8 +1125,10 @@ static int add_hometable(int (*call_lesskey)(constant char *, lbool), constant c */ static void add_content_table(int (*call_lesskey)(constant char *, lbool), constant char *envname, lbool sysvar) { + constant char *content; + (void) call_lesskey; /* not used */ - constant char *content = lgetenv(envname); + content = lgetenv(envname); if (isnullenv(content)) return; lesskey_content(content, sysvar); @@ -1130,9 +1177,9 @@ public int editchar(char c, int flags) } while (action == A_PREFIX && nch < MAX_CMDLEN); if (action == EC_X11MOUSE) - return (x11mouse_action(1)); + return (x11mouse_action(TRUE)); if (action == EC_X116MOUSE) - return (x116mouse_action(1)); + return (x116mouse_action(TRUE)); if (flags & ECF_NORIGHTLEFT) { @@ -1160,7 +1207,6 @@ public int editchar(char c, int flags) } } #endif -#if TAB_COMPLETE_FILENAME if (flags & ECF_NOCOMPLETE) { /* @@ -1176,7 +1222,6 @@ public int editchar(char c, int flags) break; } } -#endif if ((flags & ECF_PEEK) || action == A_INVALID) { /* |
