2

In less's line editing mode, the left and right arrow keys move the cursor backwards and forwards. I was hoping to use these together with the control key to navigate by word, as promised by man less.

       ^LEFTARROW [ ESC-b or ESC-LEFTARROW ]
              (That is, CONTROL and LEFTARROW simultaneously.)  Move the cursor one word to the left.

       ^RIGHTARROW [ ESC-w or ESC-RIGHTARROW ]
              (That is, CONTROL and RIGHTARROW simultaneously.)  Move the cursor one word to the right.

Unfortunately, this seems not to work in my terminal. (Tilix 1.8.3, VTE 0.52, GTK 3.22.30 on Fedora 28). Instead, pressing Control-left prints something I don't recognise. In the example below, I typed alpha beta and then immediately pressed Control-Left. This added ESC[1;5D to the line.

[1]

Is there some misconfiguration going on here? In other applications (e.g. vim) Control-Left and Control-Right navigate by word as intended.

FWIW, Ctrl + left/right arrow keys issue, might be related as might Arrow keys in less

  • Looks like less doesn't support (at least not out of the box) the standard escape sequences that Ctrl+arrow keypresses generate nowadays in xterm and many other terminal emulators. It probably supports an older one instead. It would be lovely if you reported this to less's developer, thanks in advance! – egmont Mar 15 '19 at 12:32

4 Answers4

2

Try Alt+w and Alt+b

w will be used for forward search and b will be used for backward.

2

Because you are not using OS/2

I am not kidding.

The OS/2 input handling code in less has a "special key" mapping for the ⎈ Control+ and ⎈ Control+ chords to its internal SK_CTL_LEFT_ARROW and SK_CTL_RIGHT_ARROW events.

The Unix code simply has no equivalent mapping. It relies upon termcap, and termcap is notoriously deficient in this area.

What is in square brackets in the doco is right, and what is in parentheses is wrong. You'll have to use ⎋ Escape B, ⎋ Escape F, ⎋ Escape (sic!), and ⎋ Escape (sic!) sequences (not chords, note) until someone makes less better. Please file a report.

(In some terminal emulators, you can configure a modifier key to cause an ⎋ Escape to be prefixed. This is not true for all terminal emulators and terminals, in particular the ones whose input control sequences are being emulated here (which, rather, report modifiers in the CSI sequence), and the important part is that the first character received by less from the terminal is . less itself has no notion of such a modifier.)

Further reading

JdeBP
  • 68,745
1

less is a termcap application, using the termcap interface to obtain all of the information it "knows" about a given terminal. Unless its developer introduces some hard-coded behavior (as done in a very few programs which I won't mention), less will provide no support for those key combinations because they are not standard features (see for instance the termcap column of the capabilities listed in ncurses' terminfo(5)), and have no 2-character names assigned to them (see the terminal database for a summary of extensions).

By the way, referring to my answer and taking a quick look at less's source-code, I do not see anything that corresponds to left/right word movement (unless that is the intended meaning of the left/right shift A_LSHIFT and A_RSHIFT). git blame says those as well as the manual page comment about "word" date back to 2007 (version 394). These look more promising (from 2016):

    SK(SK_CTL_RIGHT_ARROW),0,       A_RRSHIFT,
    SK(SK_CTL_LEFT_ARROW),0,        A_LLSHIFT

but the checkin comment only says

commit e5c195113d1666ac506ea3f65545d436d96fe099
Author: Mark Nudelman <markn@greenwoodsoftware.com>
Date:   Sat Oct 22 15:25:44 2016 +0000

    New commands ESC-{ and ESC-} to shift to start/end of displayed lines.

Reading the code (in command.c) for shifting, I did not see anything that disagrees with the conclusion that less scrolls by columns (single characters) rather than words, but OP's comment pointed to these:

    ESC,SK(SK_LEFT_ARROW),0,        EC_W_LEFT,      /* ESC LEFTARROW */
    SK(SK_CTL_LEFT_ARROW),0,        EC_W_LEFT,      /* CTRL-LEFTARROW */
    ESC,'w',0,                      EC_W_RIGHT,     /* ESC w */
    ESC,SK(SK_RIGHT_ARROW),0,       EC_W_RIGHT,     /* ESC RIGHTARROW */
    SK(SK_CTL_RIGHT_ARROW),0,       EC_W_RIGHT,     /* CTRL-RIGHTARROW */

which use space as a delimiter for "words". Perhaps when the developer made those changes, he had in mind imitating vi, which can do both (though vi's words are delimited differently).

The suggested *Escapeleft-arrow, etc., are provided using these lines from the table:

    ESC,SK(SK_LEFT_ARROW),0,        EC_W_LEFT,      /* ESC LEFTARROW */

    ESC,SK(SK_RIGHT_ARROW),0,       EC_W_RIGHT,     /* ESC RIGHTARROW */

However—the current program does not contain any assignments using those SK_CTL_RIGHT_ARROW or SK_CTL_LEFT_ARROW symbols. That would be done in lesskey, e.g., in this case statement (or close by, at any rate):

            switch (*++p)
            {
            case 'u': ch = SK_UP_ARROW; break;
            case 'd': ch = SK_DOWN_ARROW; break;
            case 'r': ch = SK_RIGHT_ARROW; break;
            case 'l': ch = SK_LEFT_ARROW; break;
            case 'U': ch = SK_PAGE_UP; break;
            case 'D': ch = SK_PAGE_DOWN; break;
            case 'h': ch = SK_HOME; break;
            case 'e': ch = SK_END; break;
            case 'x': ch = SK_DELETE; break;
            default:
                error("illegal char after \\k", NULL_PARG);
                *pp = p+1;
                return ("");
            }

Without assignments in the code, those are hard-coded only, not configurable.

The MSDOS / OS/2 configurations differ from the Unix one by having a (hard-coded) table of key codes:

#if MSDOS_COMPILER || OS2
        static char k_right[]           = { '\340', PCK_RIGHT, 0 };
        static char k_left[]            = { '\340', PCK_LEFT, 0  };
        static char k_ctl_right[]       = { '\340', PCK_CTL_RIGHT, 0  };
        static char k_ctl_left[]        = { '\340', PCK_CTL_LEFT, 0  };

and provides for using those in a case statement:

#if MSDOS_COMPILER || OS2
        case SK_INSERT:
                s = k_insert;
                break;
        case SK_CTL_LEFT_ARROW:
                s = k_ctl_left;
                break;
        case SK_CTL_RIGHT_ARROW:
                s = k_ctl_right;
                break;

(note: still no assignments, hence the cases are unused), while in the termcap configuration, those symbols are not used at all. (termcap is "extensible", and if you took the trouble to invent 2-character mnemonics for your own use and modify less to implement those cases, it would do what you want).

Revisiting lesskey's manual page, it says this:

An action may be followed by an "extra" string. When such a command is entered while running less, the action is performed, and then the extra string is parsed, just as if it were typed in to less. This feature can be used in certain cases to extend the functionality of a command. For example, see the "{" and ":t" commands in the example below. The extra string has a special meaning for the "quit" action: when less quits, first character of the extra string is used as its exit status.

That implies that you could do something like this:

\e[1;5D     noaction \e\e[D
\e[1;5C     noaction \e\e[C

to map into an extra string which uses the predefined word-shift.

Thomas Dickey
  • 76,765
  • Esc ← and Esc → navigate by what looks like words to me (as in JdeBP's answer). Note that there are separate binds and commands for the "text buffer" you get at the bottom of less, and in particular EC_W_LEFT which seems promising.

    Perhaps I can use lesskey(1) to make less treat whatever input it is getting as if it was getting Ctrl-← and Ctrl-→; I will investigate.

    – David Robertson Mar 15 '19 at 22:26
  • I see - will update – Thomas Dickey Mar 15 '19 at 22:30
  • Thank you for your thoroughness. Do I understand you and the source code correctly?
    1. There is no way for lesskey to generate a SK_SPECIAL_KEY string whose second (i.e. index 1) character is SK_CTL_LEFT_ARROW. This is because there is no standard termcap 2-character mnemonic for the Ctrl-← chord.

    2. This means there is no way to "hit" the

    SK(SK_CTL_LEFT_ARROW),0, EC_W_LEFT, /* CTRL-LEFTARROW */ entry in the edittable which in order to trigger the EC_W_LEFT "action".

    – David Robertson Mar 15 '19 at 23:31
  • right less doesn't ask tgetstr for a capability, and none is defined (terminfo uses more than 2 characters) and lesskey doesn't have a way to set the value. As I read it, you can only get to those word-shifts using the escape+key stuff. – Thomas Dickey Mar 16 '19 at 00:32
  • The noaction approach looks promising. lesskey doesn't like using the noaction action within a #line-edit section, I assume because there is no entry in editnames. There is a code EC_NOACTION which is used here but not assigned anywhere. – David Robertson Mar 18 '19 at 12:57
0

I managed to get this working in the end. (I contacted less's author, whose response pointed out that I was making things a little more complicated than they needed to be.)

Here's the lesskey configuration file I ended up using.

#! /usr/bin/env lesskey
#line-edit
\e[1;5D word-left
\e[1;5C word-right
\e[3;5~ word-delete

Running lesskey on this file and starting a new instance made Ctrl-← and Ctrl-→ navigate by (space-delimited?) word, and Ctrl-Delete delete rightwards to the end of the current word. I guess the downside of this solution is that it's hard-coded to the particular escape sequences generated by my terminal emulator; the other answers explain why a generic "control+arrow key" mechanism wasn't possible.