cog1to / st-ligatures

Patches for ST (suckless terminal) that add support for ligatures drawing
52 stars 5 forks source link

(neo)mutt messed up sidebar when scrolling text area #15

Closed Infrasonics closed 4 years ago

Infrasonics commented 4 years ago

In mutt or neomutt with enabled sidebar, when scrolling the message text in the pager view, it happens that the number of messages per mailbox in the sidebar starts wandering, depending on the scrolling direction, which also leaves artifacts. E.g. depicted below, when scrolling the text area, the "123" would start moving and leaving "1" or "12" as artifacts. It seems that the full line gets scrolled instead of only the text area.

Approximated described Layout:

Mailbox1    1| Index pane
Mailbox1    1|
Mailbox2   44|---------[ Pager ] ----
Mailbox1    1|  Message header + text
Mailbox1    1|  more text
Mbox3     123|  more text
Mailbox1   20|  more text

This does not happen in vanilla st.

Tested version: st 0.8.3 with ligatures patch mutt 1.13.5 or neomutt 20200313

P.S.: Thank you for the ligatures, they are a very nice addition!

cog1to commented 4 years ago

Never saw that in neomutt so far. I'm using st 0.8.3 and neomutt 20200320. Can you provide more details?

Infrasonics commented 4 years ago

I'll try to find a MWE mutt layout.

Infrasonics commented 4 years ago

Okay, I was unable to find an MWE for the scrolling issue so far, but on the way I found one for a distorted sidebar that happens in the patched but not in the vanilla version. MWE: Create a dummy mail folder, I used:

DIR=/tmp/stligatures-mwe
mkdir $DIR

for m in {00..20}; do
    mkdir -p $DIR/Mailbox${m}/{cur,new,tmp}
done

for m in $DIR/*; do
    NUM=$((1 + RANDOM % 130))
    for f in $(seq 000 $NUM); do
        touch $m/cur/$f
    done
done

And for the config:

set mbox_type=Maildir
set folder    ="/tmp/stligatures-mwe"
set mbox      ="/tmp/stligatures-mwe"
set sidebar_visible = yes
set sidebar_width   = 24
set sidebar_format = '%B%?F?[%F]?%* %?N?%N/?%S'
set mail_check_stats = yes

mailboxes =Mailbox00
mailboxes =Mailbox01
mailboxes =Mailbox02
mailboxes =Mailbox03
mailboxes =Mailbox04
mailboxes =Mailbox05
mailboxes =Mailbox06
mailboxes =Mailbox07
mailboxes =Mailbox08
mailboxes =Mailbox09
mailboxes =Mailbox10
mailboxes =Mailbox11
mailboxes =Mailbox12
mailboxes =Mailbox13
mailboxes =Mailbox14
mailboxes =Mailbox15
mailboxes =Mailbox16
mailboxes =Mailbox17
mailboxes =Mailbox18
mailboxes =Mailbox19
mailboxes =Mailbox20

neomutt -F /path/to/config then gives me: messy-sidebar

cog1to commented 4 years ago

Interestingly, I still can't get this. neomutt-with-st-ligatures

I'm not sure what is going on on your side. Can you maybe get a git diff from the current state of st repo you're building? maybe we don't see some patch conflict or something.

Infrasonics commented 4 years ago

Hmmmm, interesting problem... I've applied the patch to commit 43a395ae91f7d67ce694e65edeaa7bbc720dd027 which is tagged with 0.8.3.

git diff gives (yes, the Makefile paths are a personal change):

diff --git i/Makefile w/Makefile
index 470ac86..38240da 100644
--- i/Makefile
+++ w/Makefile
@@ -4,7 +4,7 @@

 include config.mk

-SRC = st.c x.c
+SRC = st.c x.c hb.c
 OBJ = $(SRC:.c=.o)

 all: options st
@@ -22,7 +22,8 @@ config.h:
    $(CC) $(STCFLAGS) -c $<

 st.o: config.h st.h win.h
-x.o: arg.h config.h st.h win.h
+x.o: arg.h config.h st.h win.h hb.h
+hb.o: st.h

 $(OBJ): config.h config.mk

diff --git i/config.mk w/config.mk
index beafc35..8881254 100644
--- i/config.mk
+++ w/config.mk
@@ -4,8 +4,8 @@ VERSION = 0.8.3
 # Customize below to fit your system

 # paths
-PREFIX = /usr/local
-MANPREFIX = $(PREFIX)/share/man
+PREFIX = ${HOME}/usr
+MANPREFIX = $(PREFIX)/man

 X11INC = /usr/X11R6/include
 X11LIB = /usr/X11R6/lib
@@ -15,10 +15,12 @@ PKG_CONFIG = pkg-config
 # includes and libs
 INCS = -I$(X11INC) \
        `$(PKG_CONFIG) --cflags fontconfig` \
-       `$(PKG_CONFIG) --cflags freetype2`
+       `$(PKG_CONFIG) --cflags freetype2` \
+       `$(PKG_CONFIG) --cflags harfbuzz`
 LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft \
        `$(PKG_CONFIG) --libs fontconfig` \
-       `$(PKG_CONFIG) --libs freetype2`
+       `$(PKG_CONFIG) --libs freetype2` \
+       `$(PKG_CONFIG) --libs harfbuzz`

 # flags
 STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600
diff --git i/st.c w/st.c
index 0ce6ac2..3201490 100644
--- i/st.c
+++ w/st.c
@@ -2599,7 +2599,8 @@ draw(void)

    drawregion(0, 0, term.col, term.row);
    xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
-           term.ocx, term.ocy, term.line[term.ocy][term.ocx]);
+           term.ocx, term.ocy, term.line[term.ocy][term.ocx],
+           term.line[term.ocy], term.col);
    term.ocx = cx;
    term.ocy = term.c.y;
    xfinishdraw();
diff --git i/st.h w/st.h
index d978458..c9b279b 100644
--- i/st.h
+++ w/st.h
@@ -11,7 +11,8 @@
 #define DIVCEIL(n, d)      (((n) + ((d) - 1)) / (d))
 #define DEFAULT(a, b)      (a) = (a) ? (a) : (b)
 #define LIMIT(x, a, b)     (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x)
-#define ATTRCMP(a, b)      ((a).mode != (b).mode || (a).fg != (b).fg || \
+#define ATTRCMP(a, b)      (((a).mode & (~ATTR_WRAP) & (~ATTR_LIGA)) != ((b).mode & (~ATTR_WRAP) & (~ATTR_LIGA)) || \
+               (a).fg != (b).fg || \
                (a).bg != (b).bg)
 #define TIMEDIFF(t1, t2)   ((t1.tv_sec-t2.tv_sec)*1000 + \
                (t1.tv_nsec-t2.tv_nsec)/1E6)
@@ -33,6 +34,7 @@ enum glyph_attribute {
    ATTR_WRAP       = 1 << 8,
    ATTR_WIDE       = 1 << 9,
    ATTR_WDUMMY     = 1 << 10,
+   ATTR_LIGA       = 1 << 11,
    ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
 };

diff --git i/win.h w/win.h
index a6ef1b9..bc0d180 100644
--- i/win.h
+++ w/win.h
@@ -25,7 +25,7 @@ enum win_mode {

 void xbell(void);
 void xclipcopy(void);
-void xdrawcursor(int, int, Glyph, int, int, Glyph);
+void xdrawcursor(int, int, Glyph, int, int, Glyph, Line, int);
 void xdrawline(Line, int, int, int);
 void xfinishdraw(void);
 void xloadcols(void);
diff --git i/x.c w/x.c
index e5f1737..3334a83 100644
--- i/x.c
+++ w/x.c
@@ -19,6 +19,7 @@ char *argv0;
 #include "arg.h"
 #include "st.h"
 #include "win.h"
+#include "hb.h"

 /* types used in config.h */
 typedef struct {
@@ -1031,6 +1032,9 @@ xunloadfont(Font *f)
 void
 xunloadfonts(void)
 {
+   /* Clear Harfbuzz font cache. */
+   hbunloadfonts();
+
    /* Free the loaded fonts in the font cache.  */
    while (frclen > 0)
        XftFontClose(xw.dpy, frc[--frclen].font);
@@ -1229,7 +1233,7 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
        mode = glyphs[i].mode;

        /* Skip dummy wide-character spacing. */
-       if (mode == ATTR_WDUMMY)
+       if (mode & ATTR_WDUMMY)
            continue;

        /* Determine font for glyph if different from previous glyph. */
@@ -1336,6 +1340,9 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
        numspecs++;
    }

+   /* Harfbuzz transformation for ligatures. */
+   hbtransform(specs, glyphs, len, x, y);
+
    return numspecs;
 }

@@ -1485,14 +1492,17 @@ xdrawglyph(Glyph g, int x, int y)
 }

 void
-xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
+xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og, Line line, int len)
 {
    Color drawcol;

    /* remove the old cursor */
    if (selected(ox, oy))
        og.mode ^= ATTR_REVERSE;
-   xdrawglyph(og, ox, oy);
+
+   /* Redraw the line where cursor was previously.
+    * It will restore the ligatures broken by the cursor. */
+   xdrawline(line, 0, oy, len);

    if (IS_SET(MODE_HIDE))
        return;
Infrasonics commented 4 years ago

And just now I wanted to make sure that it's not some distribution specific patch of neomutt interfering, so I built a fresh neomutt from the repository. For me both 20200313 and 20200320 show the problem.

If you have any idea what else could cause this, let me know. For now I'm using a vanilla st for the mail terminal.

cog1to commented 4 years ago

maybe this is somehow related to the tabs/spaces conversion...

and while we're here, can you actually attach your config.h as well? maybe there's some specific setting I'm missing.

Infrasonics commented 4 years ago

Indeed! I had changed the spaces from 8 to 4 on a whim without thinking about it too much. With this setting reset the problem goes away. Thank you very much!

EDIT: I'm not sure whether this is intended behavior, so let me know if you still need the config and output.

cog1to commented 4 years ago

Yeah, please attach those. It is still a bug, if it's caused by the patch. :)

Infrasonics commented 4 years ago

Here you go.

stty -a:

speed 38400 baud; rows 66; columns 119; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>;
eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R;
werase = ^W; lnext = ^V; discard = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff
-iuclc -ixany -imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt
echoctl echoke -flusho -extproc

To save you some time looking, the config should only differ from the default in font, blink and tabwidth settings.

/* See LICENSE file for copyright and license details. */

/*
 * appearance
 *
 * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
 */
//static char *font = "Liberation Mono:pixelsize=12:antialias=true:autohint=true";
static char *font = "Fira Code:size=10";
static int borderpx = 2;

/*
 * What program is execed by st depends of these precedence rules:
 * 1: program passed with -e
 * 2: scroll and/or utmp
 * 3: SHELL environment variable
 * 4: value of shell in /etc/passwd
 * 5: value of shell in config.h
 */
static char *shell = "/bin/sh";
char *utmp = NULL;
/* scroll program: to enable use a string like "scroll" */
char *scroll = NULL;
char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400";

/* identification sequence returned in DA and DECID */
char *vtiden = "\033[?6c";

/* Kerning / character bounding-box multipliers */
static float cwscale = 1.0;
static float chscale = 1.0;

/*
 * word delimiter string
 *
 * More advanced example: L" `'\"()[]{}"
 */
wchar_t *worddelimiters = L" ";

/* selection timeouts (in milliseconds) */
static unsigned int doubleclicktimeout = 300;
static unsigned int tripleclicktimeout = 600;

/* alt screens */
int allowaltscreen = 1;

/* frames per second st should at maximum draw to the screen */
static unsigned int xfps = 120;
static unsigned int actionfps = 30;

/*
 * blinking timeout (set to 0 to disable blinking) for the terminal blinking
 * attribute.
 */
static unsigned int blinktimeout = 000;

/*
 * thickness of underline and bar cursors
 */
static unsigned int cursorthickness = 2;

/*
 * bell volume. It must be a value between -100 and 100. Use 0 for disabling
 * it
 */
static int bellvolume = 0;

/* default TERM value */
char *termname = "st-256color";

/*
 * spaces per tab
 *
 * When you are changing this value, don't forget to adapt the »it« value in
 * the st.info and appropriately install the st.info in the environment where
 * you use this st version.
 *
 *  it#$tabspaces,
 *
 * Secondly make sure your kernel is not expanding tabs. When running `stty
 * -a` »tab0« should appear. You can tell the terminal to not expand tabs by
 *  running following command:
 *
 *  stty tabs
 */
unsigned int tabspaces = 4;

/* Terminal colors (16 first used in escape sequence) */
static const char *colorname[] = {
    /* 8 normal colors */
    "#000000",
    "#a30052",
    "#0fa721",
    "#e2a800",
    "#175dbd",
    "#845ca1",
    "#00a9ae",
    "#cbcbcb",

    /* 8 bright colors */
    "#d1d1d1",
    "#fb763c",
    "#28b672",
    "#fdf65a",
    "#468ff1",
    "#b566e5",
    "#0fc5d4",
    "#ffffff",

    [255] = 0,

    /* more colors can be added after 255 to use with DefaultXX */
    "#cccccc",
    "#555555",
};

/*
 * Default colors (colorname index)
 * foreground, background, cursor, reverse cursor
 */
unsigned int defaultfg = 7;
unsigned int defaultbg = 0;
static unsigned int defaultcs = 256;
static unsigned int defaultrcs = 257;

/*
 * Default shape of cursor
 * 2: Block ("█")
 * 4: Underline ("_")
 * 6: Bar ("|")
 * 7: Snowman ("☃")
 */
static unsigned int cursorshape = 2;

/*
 * Default columns and rows numbers
 */

static unsigned int cols = 80;
static unsigned int rows = 24;

/*
 * Default colour and shape of the mouse cursor
 */
static unsigned int mouseshape = XC_xterm;
static unsigned int mousefg = 7;
static unsigned int mousebg = 0;

/*
 * Color used to display font attributes when fontconfig selected a font which
 * doesn't match the ones requested.
 */
static unsigned int defaultattr = 11;

/*
 * Force mouse select/shortcuts while mask is active (when MODE_MOUSE is set).
 * Note that if you want to use ShiftMask with selmasks, set this to an other
 * modifier, set to 0 to not use it.
 */
static uint forcemousemod = ShiftMask;

/*
 * Internal mouse shortcuts.
 * Beware that overloading Button1 will disable the selection.
 */
static MouseShortcut mshortcuts[] = {
    /* mask                 button   function        argument       release */
    { XK_ANY_MOD,           Button2, selpaste,       {.i = 0},      1 },
    { XK_ANY_MOD,           Button4, ttysend,        {.s = "\031"} },
    { XK_ANY_MOD,           Button5, ttysend,        {.s = "\005"} },
};

/* Internal keyboard shortcuts. */
#define MODKEY Mod1Mask
#define TERMMOD (ControlMask|ShiftMask)

static Shortcut shortcuts[] = {
    /* mask                 keysym          function        argument */
    { XK_ANY_MOD,           XK_Break,       sendbreak,      {.i =  0} },
    { ControlMask,          XK_Print,       toggleprinter,  {.i =  0} },
    { ShiftMask,            XK_Print,       printscreen,    {.i =  0} },
    { XK_ANY_MOD,           XK_Print,       printsel,       {.i =  0} },
    { TERMMOD,              XK_Prior,       zoom,           {.f = +1} },
    { TERMMOD,              XK_Next,        zoom,           {.f = -1} },
    { TERMMOD,              XK_Home,        zoomreset,      {.f =  0} },
    { TERMMOD,              XK_C,           clipcopy,       {.i =  0} },
    { TERMMOD,              XK_V,           clippaste,      {.i =  0} },
    { TERMMOD,              XK_Y,           selpaste,       {.i =  0} },
    { ShiftMask,            XK_Insert,      selpaste,       {.i =  0} },
    { TERMMOD,              XK_Num_Lock,    numlock,        {.i =  0} },
};

/*
 * Special keys (change & recompile st.info accordingly)
 *
 * Mask value:
 * * Use XK_ANY_MOD to match the key no matter modifiers state
 * * Use XK_NO_MOD to match the key alone (no modifiers)
 * appkey value:
 * * 0: no value
 * * > 0: keypad application mode enabled
 * *   = 2: term.numlock = 1
 * * < 0: keypad application mode disabled
 * appcursor value:
 * * 0: no value
 * * > 0: cursor application mode enabled
 * * < 0: cursor application mode disabled
 *
 * Be careful with the order of the definitions because st searches in
 * this table sequentially, so any XK_ANY_MOD must be in the last
 * position for a key.
 */

/*
 * If you want keys other than the X11 function keys (0xFD00 - 0xFFFF)
 * to be mapped below, add them to this array.
 */
static KeySym mappedkeys[] = { -1 };

/*
 * State bits to ignore when matching key or button events.  By default,
 * numlock (Mod2Mask) and keyboard layout (XK_SWITCH_MOD) are ignored.
 */
static uint ignoremod = Mod2Mask|XK_SWITCH_MOD;

/*
 * This is the huge key array which defines all compatibility to the Linux
 * world. Please decide about changes wisely.
 */
static Key key[] = {
    /* keysym           mask            string      appkey appcursor */
    { XK_KP_Home,       ShiftMask,      "\033[2J",       0,   -1},
    { XK_KP_Home,       ShiftMask,      "\033[1;2H",     0,   +1},
    { XK_KP_Home,       XK_ANY_MOD,     "\033[H",        0,   -1},
    { XK_KP_Home,       XK_ANY_MOD,     "\033[1~",       0,   +1},
    { XK_KP_Up,         XK_ANY_MOD,     "\033Ox",       +1,    0},
    { XK_KP_Up,         XK_ANY_MOD,     "\033[A",        0,   -1},
    { XK_KP_Up,         XK_ANY_MOD,     "\033OA",        0,   +1},
    { XK_KP_Down,       XK_ANY_MOD,     "\033Or",       +1,    0},
    { XK_KP_Down,       XK_ANY_MOD,     "\033[B",        0,   -1},
    { XK_KP_Down,       XK_ANY_MOD,     "\033OB",        0,   +1},
    { XK_KP_Left,       XK_ANY_MOD,     "\033Ot",       +1,    0},
    { XK_KP_Left,       XK_ANY_MOD,     "\033[D",        0,   -1},
    { XK_KP_Left,       XK_ANY_MOD,     "\033OD",        0,   +1},
    { XK_KP_Right,      XK_ANY_MOD,     "\033Ov",       +1,    0},
    { XK_KP_Right,      XK_ANY_MOD,     "\033[C",        0,   -1},
    { XK_KP_Right,      XK_ANY_MOD,     "\033OC",        0,   +1},
    { XK_KP_Prior,      ShiftMask,      "\033[5;2~",     0,    0},
    { XK_KP_Prior,      XK_ANY_MOD,     "\033[5~",       0,    0},
    { XK_KP_Begin,      XK_ANY_MOD,     "\033[E",        0,    0},
    { XK_KP_End,        ControlMask,    "\033[J",       -1,    0},
    { XK_KP_End,        ControlMask,    "\033[1;5F",    +1,    0},
    { XK_KP_End,        ShiftMask,      "\033[K",       -1,    0},
    { XK_KP_End,        ShiftMask,      "\033[1;2F",    +1,    0},
    { XK_KP_End,        XK_ANY_MOD,     "\033[4~",       0,    0},
    { XK_KP_Next,       ShiftMask,      "\033[6;2~",     0,    0},
    { XK_KP_Next,       XK_ANY_MOD,     "\033[6~",       0,    0},
    { XK_KP_Insert,     ShiftMask,      "\033[2;2~",    +1,    0},
    { XK_KP_Insert,     ShiftMask,      "\033[4l",      -1,    0},
    { XK_KP_Insert,     ControlMask,    "\033[L",       -1,    0},
    { XK_KP_Insert,     ControlMask,    "\033[2;5~",    +1,    0},
    { XK_KP_Insert,     XK_ANY_MOD,     "\033[4h",      -1,    0},
    { XK_KP_Insert,     XK_ANY_MOD,     "\033[2~",      +1,    0},
    { XK_KP_Delete,     ControlMask,    "\033[M",       -1,    0},
    { XK_KP_Delete,     ControlMask,    "\033[3;5~",    +1,    0},
    { XK_KP_Delete,     ShiftMask,      "\033[2K",      -1,    0},
    { XK_KP_Delete,     ShiftMask,      "\033[3;2~",    +1,    0},
    { XK_KP_Delete,     XK_ANY_MOD,     "\033[P",       -1,    0},
    { XK_KP_Delete,     XK_ANY_MOD,     "\033[3~",      +1,    0},
    { XK_KP_Multiply,   XK_ANY_MOD,     "\033Oj",       +2,    0},
    { XK_KP_Add,        XK_ANY_MOD,     "\033Ok",       +2,    0},
    { XK_KP_Enter,      XK_ANY_MOD,     "\033OM",       +2,    0},
    { XK_KP_Enter,      XK_ANY_MOD,     "\r",           -1,    0},
    { XK_KP_Subtract,   XK_ANY_MOD,     "\033Om",       +2,    0},
    { XK_KP_Decimal,    XK_ANY_MOD,     "\033On",       +2,    0},
    { XK_KP_Divide,     XK_ANY_MOD,     "\033Oo",       +2,    0},
    { XK_KP_0,          XK_ANY_MOD,     "\033Op",       +2,    0},
    { XK_KP_1,          XK_ANY_MOD,     "\033Oq",       +2,    0},
    { XK_KP_2,          XK_ANY_MOD,     "\033Or",       +2,    0},
    { XK_KP_3,          XK_ANY_MOD,     "\033Os",       +2,    0},
    { XK_KP_4,          XK_ANY_MOD,     "\033Ot",       +2,    0},
    { XK_KP_5,          XK_ANY_MOD,     "\033Ou",       +2,    0},
    { XK_KP_6,          XK_ANY_MOD,     "\033Ov",       +2,    0},
    { XK_KP_7,          XK_ANY_MOD,     "\033Ow",       +2,    0},
    { XK_KP_8,          XK_ANY_MOD,     "\033Ox",       +2,    0},
    { XK_KP_9,          XK_ANY_MOD,     "\033Oy",       +2,    0},
    { XK_Up,            ShiftMask,      "\033[1;2A",     0,    0},
    { XK_Up,            Mod1Mask,       "\033[1;3A",     0,    0},
    { XK_Up,         ShiftMask|Mod1Mask,"\033[1;4A",     0,    0},
    { XK_Up,            ControlMask,    "\033[1;5A",     0,    0},
    { XK_Up,      ShiftMask|ControlMask,"\033[1;6A",     0,    0},
    { XK_Up,       ControlMask|Mod1Mask,"\033[1;7A",     0,    0},
    { XK_Up,ShiftMask|ControlMask|Mod1Mask,"\033[1;8A",  0,    0},
    { XK_Up,            XK_ANY_MOD,     "\033[A",        0,   -1},
    { XK_Up,            XK_ANY_MOD,     "\033OA",        0,   +1},
    { XK_Down,          ShiftMask,      "\033[1;2B",     0,    0},
    { XK_Down,          Mod1Mask,       "\033[1;3B",     0,    0},
    { XK_Down,       ShiftMask|Mod1Mask,"\033[1;4B",     0,    0},
    { XK_Down,          ControlMask,    "\033[1;5B",     0,    0},
    { XK_Down,    ShiftMask|ControlMask,"\033[1;6B",     0,    0},
    { XK_Down,     ControlMask|Mod1Mask,"\033[1;7B",     0,    0},
    { XK_Down,ShiftMask|ControlMask|Mod1Mask,"\033[1;8B",0,    0},
    { XK_Down,          XK_ANY_MOD,     "\033[B",        0,   -1},
    { XK_Down,          XK_ANY_MOD,     "\033OB",        0,   +1},
    { XK_Left,          ShiftMask,      "\033[1;2D",     0,    0},
    { XK_Left,          Mod1Mask,       "\033[1;3D",     0,    0},
    { XK_Left,       ShiftMask|Mod1Mask,"\033[1;4D",     0,    0},
    { XK_Left,          ControlMask,    "\033[1;5D",     0,    0},
    { XK_Left,    ShiftMask|ControlMask,"\033[1;6D",     0,    0},
    { XK_Left,     ControlMask|Mod1Mask,"\033[1;7D",     0,    0},
    { XK_Left,ShiftMask|ControlMask|Mod1Mask,"\033[1;8D",0,    0},
    { XK_Left,          XK_ANY_MOD,     "\033[D",        0,   -1},
    { XK_Left,          XK_ANY_MOD,     "\033OD",        0,   +1},
    { XK_Right,         ShiftMask,      "\033[1;2C",     0,    0},
    { XK_Right,         Mod1Mask,       "\033[1;3C",     0,    0},
    { XK_Right,      ShiftMask|Mod1Mask,"\033[1;4C",     0,    0},
    { XK_Right,         ControlMask,    "\033[1;5C",     0,    0},
    { XK_Right,   ShiftMask|ControlMask,"\033[1;6C",     0,    0},
    { XK_Right,    ControlMask|Mod1Mask,"\033[1;7C",     0,    0},
    { XK_Right,ShiftMask|ControlMask|Mod1Mask,"\033[1;8C",0,   0},
    { XK_Right,         XK_ANY_MOD,     "\033[C",        0,   -1},
    { XK_Right,         XK_ANY_MOD,     "\033OC",        0,   +1},
    { XK_ISO_Left_Tab,  ShiftMask,      "\033[Z",        0,    0},
    { XK_Return,        Mod1Mask,       "\033\r",        0,    0},
    { XK_Return,        XK_ANY_MOD,     "\r",            0,    0},
    { XK_Insert,        ShiftMask,      "\033[4l",      -1,    0},
    { XK_Insert,        ShiftMask,      "\033[2;2~",    +1,    0},
    { XK_Insert,        ControlMask,    "\033[L",       -1,    0},
    { XK_Insert,        ControlMask,    "\033[2;5~",    +1,    0},
    { XK_Insert,        XK_ANY_MOD,     "\033[4h",      -1,    0},
    { XK_Insert,        XK_ANY_MOD,     "\033[2~",      +1,    0},
    { XK_Delete,        ControlMask,    "\033[M",       -1,    0},
    { XK_Delete,        ControlMask,    "\033[3;5~",    +1,    0},
    { XK_Delete,        ShiftMask,      "\033[2K",      -1,    0},
    { XK_Delete,        ShiftMask,      "\033[3;2~",    +1,    0},
    { XK_Delete,        XK_ANY_MOD,     "\033[P",       -1,    0},
    { XK_Delete,        XK_ANY_MOD,     "\033[3~",      +1,    0},
    { XK_BackSpace,     XK_NO_MOD,      "\177",          0,    0},
    { XK_BackSpace,     Mod1Mask,       "\033\177",      0,    0},
    { XK_Home,          ShiftMask,      "\033[2J",       0,   -1},
    { XK_Home,          ShiftMask,      "\033[1;2H",     0,   +1},
    { XK_Home,          XK_ANY_MOD,     "\033[H",        0,   -1},
    { XK_Home,          XK_ANY_MOD,     "\033[1~",       0,   +1},
    { XK_End,           ControlMask,    "\033[J",       -1,    0},
    { XK_End,           ControlMask,    "\033[1;5F",    +1,    0},
    { XK_End,           ShiftMask,      "\033[K",       -1,    0},
    { XK_End,           ShiftMask,      "\033[1;2F",    +1,    0},
    { XK_End,           XK_ANY_MOD,     "\033[4~",       0,    0},
    { XK_Prior,         ControlMask,    "\033[5;5~",     0,    0},
    { XK_Prior,         ShiftMask,      "\033[5;2~",     0,    0},
    { XK_Prior,         XK_ANY_MOD,     "\033[5~",       0,    0},
    { XK_Next,          ControlMask,    "\033[6;5~",     0,    0},
    { XK_Next,          ShiftMask,      "\033[6;2~",     0,    0},
    { XK_Next,          XK_ANY_MOD,     "\033[6~",       0,    0},
    { XK_F1,            XK_NO_MOD,      "\033OP" ,       0,    0},
    { XK_F1, /* F13 */  ShiftMask,      "\033[1;2P",     0,    0},
    { XK_F1, /* F25 */  ControlMask,    "\033[1;5P",     0,    0},
    { XK_F1, /* F37 */  Mod4Mask,       "\033[1;6P",     0,    0},
    { XK_F1, /* F49 */  Mod1Mask,       "\033[1;3P",     0,    0},
    { XK_F1, /* F61 */  Mod3Mask,       "\033[1;4P",     0,    0},
    { XK_F2,            XK_NO_MOD,      "\033OQ" ,       0,    0},
    { XK_F2, /* F14 */  ShiftMask,      "\033[1;2Q",     0,    0},
    { XK_F2, /* F26 */  ControlMask,    "\033[1;5Q",     0,    0},
    { XK_F2, /* F38 */  Mod4Mask,       "\033[1;6Q",     0,    0},
    { XK_F2, /* F50 */  Mod1Mask,       "\033[1;3Q",     0,    0},
    { XK_F2, /* F62 */  Mod3Mask,       "\033[1;4Q",     0,    0},
    { XK_F3,            XK_NO_MOD,      "\033OR" ,       0,    0},
    { XK_F3, /* F15 */  ShiftMask,      "\033[1;2R",     0,    0},
    { XK_F3, /* F27 */  ControlMask,    "\033[1;5R",     0,    0},
    { XK_F3, /* F39 */  Mod4Mask,       "\033[1;6R",     0,    0},
    { XK_F3, /* F51 */  Mod1Mask,       "\033[1;3R",     0,    0},
    { XK_F3, /* F63 */  Mod3Mask,       "\033[1;4R",     0,    0},
    { XK_F4,            XK_NO_MOD,      "\033OS" ,       0,    0},
    { XK_F4, /* F16 */  ShiftMask,      "\033[1;2S",     0,    0},
    { XK_F4, /* F28 */  ControlMask,    "\033[1;5S",     0,    0},
    { XK_F4, /* F40 */  Mod4Mask,       "\033[1;6S",     0,    0},
    { XK_F4, /* F52 */  Mod1Mask,       "\033[1;3S",     0,    0},
    { XK_F5,            XK_NO_MOD,      "\033[15~",      0,    0},
    { XK_F5, /* F17 */  ShiftMask,      "\033[15;2~",    0,    0},
    { XK_F5, /* F29 */  ControlMask,    "\033[15;5~",    0,    0},
    { XK_F5, /* F41 */  Mod4Mask,       "\033[15;6~",    0,    0},
    { XK_F5, /* F53 */  Mod1Mask,       "\033[15;3~",    0,    0},
    { XK_F6,            XK_NO_MOD,      "\033[17~",      0,    0},
    { XK_F6, /* F18 */  ShiftMask,      "\033[17;2~",    0,    0},
    { XK_F6, /* F30 */  ControlMask,    "\033[17;5~",    0,    0},
    { XK_F6, /* F42 */  Mod4Mask,       "\033[17;6~",    0,    0},
    { XK_F6, /* F54 */  Mod1Mask,       "\033[17;3~",    0,    0},
    { XK_F7,            XK_NO_MOD,      "\033[18~",      0,    0},
    { XK_F7, /* F19 */  ShiftMask,      "\033[18;2~",    0,    0},
    { XK_F7, /* F31 */  ControlMask,    "\033[18;5~",    0,    0},
    { XK_F7, /* F43 */  Mod4Mask,       "\033[18;6~",    0,    0},
    { XK_F7, /* F55 */  Mod1Mask,       "\033[18;3~",    0,    0},
    { XK_F8,            XK_NO_MOD,      "\033[19~",      0,    0},
    { XK_F8, /* F20 */  ShiftMask,      "\033[19;2~",    0,    0},
    { XK_F8, /* F32 */  ControlMask,    "\033[19;5~",    0,    0},
    { XK_F8, /* F44 */  Mod4Mask,       "\033[19;6~",    0,    0},
    { XK_F8, /* F56 */  Mod1Mask,       "\033[19;3~",    0,    0},
    { XK_F9,            XK_NO_MOD,      "\033[20~",      0,    0},
    { XK_F9, /* F21 */  ShiftMask,      "\033[20;2~",    0,    0},
    { XK_F9, /* F33 */  ControlMask,    "\033[20;5~",    0,    0},
    { XK_F9, /* F45 */  Mod4Mask,       "\033[20;6~",    0,    0},
    { XK_F9, /* F57 */  Mod1Mask,       "\033[20;3~",    0,    0},
    { XK_F10,           XK_NO_MOD,      "\033[21~",      0,    0},
    { XK_F10, /* F22 */ ShiftMask,      "\033[21;2~",    0,    0},
    { XK_F10, /* F34 */ ControlMask,    "\033[21;5~",    0,    0},
    { XK_F10, /* F46 */ Mod4Mask,       "\033[21;6~",    0,    0},
    { XK_F10, /* F58 */ Mod1Mask,       "\033[21;3~",    0,    0},
    { XK_F11,           XK_NO_MOD,      "\033[23~",      0,    0},
    { XK_F11, /* F23 */ ShiftMask,      "\033[23;2~",    0,    0},
    { XK_F11, /* F35 */ ControlMask,    "\033[23;5~",    0,    0},
    { XK_F11, /* F47 */ Mod4Mask,       "\033[23;6~",    0,    0},
    { XK_F11, /* F59 */ Mod1Mask,       "\033[23;3~",    0,    0},
    { XK_F12,           XK_NO_MOD,      "\033[24~",      0,    0},
    { XK_F12, /* F24 */ ShiftMask,      "\033[24;2~",    0,    0},
    { XK_F12, /* F36 */ ControlMask,    "\033[24;5~",    0,    0},
    { XK_F12, /* F48 */ Mod4Mask,       "\033[24;6~",    0,    0},
    { XK_F12, /* F60 */ Mod1Mask,       "\033[24;3~",    0,    0},
    { XK_F13,           XK_NO_MOD,      "\033[1;2P",     0,    0},
    { XK_F14,           XK_NO_MOD,      "\033[1;2Q",     0,    0},
    { XK_F15,           XK_NO_MOD,      "\033[1;2R",     0,    0},
    { XK_F16,           XK_NO_MOD,      "\033[1;2S",     0,    0},
    { XK_F17,           XK_NO_MOD,      "\033[15;2~",    0,    0},
    { XK_F18,           XK_NO_MOD,      "\033[17;2~",    0,    0},
    { XK_F19,           XK_NO_MOD,      "\033[18;2~",    0,    0},
    { XK_F20,           XK_NO_MOD,      "\033[19;2~",    0,    0},
    { XK_F21,           XK_NO_MOD,      "\033[20;2~",    0,    0},
    { XK_F22,           XK_NO_MOD,      "\033[21;2~",    0,    0},
    { XK_F23,           XK_NO_MOD,      "\033[23;2~",    0,    0},
    { XK_F24,           XK_NO_MOD,      "\033[24;2~",    0,    0},
    { XK_F25,           XK_NO_MOD,      "\033[1;5P",     0,    0},
    { XK_F26,           XK_NO_MOD,      "\033[1;5Q",     0,    0},
    { XK_F27,           XK_NO_MOD,      "\033[1;5R",     0,    0},
    { XK_F28,           XK_NO_MOD,      "\033[1;5S",     0,    0},
    { XK_F29,           XK_NO_MOD,      "\033[15;5~",    0,    0},
    { XK_F30,           XK_NO_MOD,      "\033[17;5~",    0,    0},
    { XK_F31,           XK_NO_MOD,      "\033[18;5~",    0,    0},
    { XK_F32,           XK_NO_MOD,      "\033[19;5~",    0,    0},
    { XK_F33,           XK_NO_MOD,      "\033[20;5~",    0,    0},
    { XK_F34,           XK_NO_MOD,      "\033[21;5~",    0,    0},
    { XK_F35,           XK_NO_MOD,      "\033[23;5~",    0,    0},
};

/*
 * Selection types' masks.
 * Use the same masks as usual.
 * Button1Mask is always unset, to make masks match between ButtonPress.
 * ButtonRelease and MotionNotify.
 * If no match is found, regular selection is used.
 */
static uint selmasks[] = {
    [SEL_RECTANGULAR] = Mod1Mask,
};

/*
 * Printable characters in ASCII, used to estimate the advance width
 * of single wide characters.
 */
static char ascii_printable[] =
    " !\"#$%&'()*+,-./0123456789:;<=>?"
    "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
    "`abcdefghijklmnopqrstuvwxyz{|}~";
Infrasonics commented 4 years ago

I belive this is not a problem with the patch... I'm sorry to have caused unnecessary work. Just checked the config in my "vanilla" st version and it has the same problem when changing the tabwidth. As I was intending to use it only for mail, I hadn't adapted it.

cog1to commented 4 years ago

Huh. Funny enough, I still can't reproduce it :) Maybe it's some kind of discrepancy between terminfo data installed in the environment and the actual tab length in the config...

Infrasonics commented 4 years ago

Sounds reasonable. If you changed the terminfo db manually, what command did you use? I'll see whether I can get it working with the different tabwidth that way.

cog1to commented 4 years ago

I didn't change it. I just did basic make install and that's all. what TERM value do you have when running st?

Infrasonics commented 4 years ago

$TERM says st-256-color. My shell initialization had xterm-256color before, but between these two it doesn't make a difference.

Infrasonics commented 4 years ago

Okay, I simply manually changed the it value in the terminfo file and did tic -sx st.info, that fixed it. ~I don't know why make install was not enough.~ Probably makeing two different versions of st messed up my terminfo. Luckily the st config file does say to do that in a comment...

Thanks for your help.

cog1to commented 4 years ago

No problem, glad to help :)