commit 77456c4698f33511b0652c9dfd6f2904b4797584
Author: Alexander Rogachev <[email protected]>
Date:   Fri Jan 10 01:55:48 2025 +0400

    [st][patches][ligatures]
    
    Some code cleanup and refactoring.

diff --git 
a/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-20240427-0.9.2.diff 
b/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-20241226-0.9.2.diff
similarity index 71%
rename from 
st.suckless.org/patches/ligatures/0.9.2/st-ligatures-20240427-0.9.2.diff
rename to 
st.suckless.org/patches/ligatures/0.9.2/st-ligatures-20241226-0.9.2.diff
index b6832a67..698516fe 100644
--- a/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-20240427-0.9.2.diff
+++ b/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-20241226-0.9.2.diff
@@ -1,8 +1,9 @@
 diff --git a/Makefile b/Makefile
-index 470ac86..38240da 100644
+index 15db421..dfcea0f 100644
 --- a/Makefile
 +++ b/Makefile
-@@ -4,7 +4,7 @@
+@@ -3,9 +3,9 @@
+ .POSIX:
  
  include config.mk
  
@@ -11,7 +12,9 @@ index 470ac86..38240da 100644
  OBJ = $(SRC:.c=.o)
  
  all: st
-@@ -22,7 +22,8 @@ config.h:
+ 
+@@ -15,9 +15,10 @@ config.h:
+ .c.o:
        $(CC) $(STCFLAGS) -c $<
  
  st.o: config.h st.h win.h
@@ -21,11 +24,13 @@ index 470ac86..38240da 100644
  
  $(OBJ): config.h config.mk
  
+ st: $(OBJ)
 diff --git a/config.mk b/config.mk
-index 1e306f8..3e13e53 100644
+index fdc29a7..6833b3b 100644
 --- a/config.mk
 +++ b/config.mk
-@@ -15,10 +15,12 @@ PKG_CONFIG = pkg-config
+@@ -14,12 +14,14 @@ PKG_CONFIG = pkg-config
+ 
  # includes and libs
  INCS = -I$(X11INC) \
         `$(PKG_CONFIG) --cflags fontconfig` \
@@ -40,6 +45,19 @@ index 1e306f8..3e13e53 100644
  
  # flags
  STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600
+ STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS)
+@@ -28,9 +30,10 @@ STLDFLAGS = $(LIBS) $(LDFLAGS)
+ # OpenBSD:
+ #CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 -D_BSD_SOURCE
+ #LIBS = -L$(X11LIB) -lm -lX11 -lutil -lXft \
+ #       `$(PKG_CONFIG) --libs fontconfig` \
+-#       `$(PKG_CONFIG) --libs freetype2`
++#       `$(PKG_CONFIG) --libs freetype2` \
++#       `$(PKG_CONFIG) --libs harfbuzz`
+ #MANPREFIX = ${PREFIX}/man
+ 
+ # compiler and linker
+ # CC = c99
 diff --git a/hb.c b/hb.c
 new file mode 100644
 index 0000000..99412c8
@@ -192,10 +210,11 @@ index 0000000..3b0ef44
 +void hbtransform(HbTransformData *, XftFont *, const Glyph *, int, int);
 +void hbcleanup(HbTransformData *);
 diff --git a/st.c b/st.c
-index 62def59..041c6d8 100644
+index b9f66e7..da33a85 100644
 --- a/st.c
 +++ b/st.c
-@@ -2640,7 +2640,8 @@ draw(void)
+@@ -2658,9 +2658,10 @@ draw(void)
+               cx--;
  
        drawregion(0, 0, term.col, term.row);
        xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
@@ -205,11 +224,13 @@ index 62def59..041c6d8 100644
        term.ocx = cx;
        term.ocy = term.c.y;
        xfinishdraw();
+       if (ocx != term.ocx || ocy != term.ocy)
 diff --git a/st.h b/st.h
 index fd3b0d8..142fdfe 100644
 --- a/st.h
 +++ b/st.h
-@@ -11,7 +11,8 @@
+@@ -10,9 +10,10 @@
+ #define BETWEEN(x, a, b)      ((a) <= (x) && (x) <= (b))
  #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)
@@ -219,11 +240,13 @@ index fd3b0d8..142fdfe 100644
                                (a).bg != (b).bg)
  #define TIMEDIFF(t1, t2)      ((t1.tv_sec-t2.tv_sec)*1000 + \
                                (t1.tv_nsec-t2.tv_nsec)/1E6)
+ #define MODBIT(x, set, bit)   ((set) ? ((x) |= (bit)) : ((x) &= ~(bit)))
 diff --git a/win.h b/win.h
 index 6de960d..94679e4 100644
 --- a/win.h
 +++ b/win.h
-@@ -25,7 +25,7 @@ enum win_mode {
+@@ -24,9 +24,9 @@ enum win_mode {
+ };
  
  void xbell(void);
  void xclipcopy(void);
@@ -232,11 +255,13 @@ index 6de960d..94679e4 100644
  void xdrawline(Line, int, int, int);
  void xfinishdraw(void);
  void xloadcols(void);
+ int xsetcolorname(int, const char *);
 diff --git a/x.c b/x.c
-index 2a3bd38..66605ae 100644
+index bd23686..2bf3b72 100644
 --- a/x.c
 +++ b/x.c
-@@ -19,6 +19,7 @@ char *argv0;
+@@ -18,8 +18,9 @@
+ char *argv0;
  #include "arg.h"
  #include "st.h"
  #include "win.h"
@@ -244,7 +269,9 @@ index 2a3bd38..66605ae 100644
  
  /* types used in config.h */
  typedef struct {
-@@ -141,8 +142,9 @@ typedef struct {
+       uint mod;
+@@ -140,10 +141,11 @@ typedef struct {
+       GC gc;
  } DC;
  
  static inline ushort sixd_to_16bit(int);
@@ -255,7 +282,9 @@ index 2a3bd38..66605ae 100644
  static void xdrawglyph(Glyph, int, int);
  static void xclear(int, int, int, int);
  static int xgeommasktogravity(int);
-@@ -757,7 +759,7 @@ xresize(int col, int row)
+ static int ximopen(Display *);
+@@ -756,9 +758,9 @@ xresize(int col, int row)
+       XftDrawChange(xw.draw, xw.buf);
        xclear(0, 0, win.w, win.h);
  
        /* resize to new width */
@@ -264,7 +293,9 @@ index 2a3bd38..66605ae 100644
  }
  
  ushort
-@@ -1062,6 +1064,9 @@ xunloadfont(Font *f)
+ sixd_to_16bit(int x)
+@@ -1061,8 +1063,11 @@ xunloadfont(Font *f)
+ 
  void
  xunloadfonts(void)
  {
@@ -274,7 +305,9 @@ index 2a3bd38..66605ae 100644
        /* Free the loaded fonts in the font cache.  */
        while (frclen > 0)
                XftFontClose(xw.dpy, frc[--frclen].font);
-@@ -1185,7 +1190,7 @@ xinit(int cols, int rows)
+ 
+@@ -1184,9 +1189,9 @@ xinit(int cols, int rows)
+       XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel);
        XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h);
  
        /* font spec buffer */
@@ -283,7 +316,9 @@ index 2a3bd38..66605ae 100644
  
        /* Xft rendering context */
        xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
-@@ -1239,6 +1244,22 @@ xinit(int cols, int rows)
+ 
+@@ -1238,144 +1243,155 @@ xinit(int cols, int rows)
+       if (xsel.xtarget == None)
                xsel.xtarget = XA_STRING;
  }
  
@@ -306,28 +341,42 @@ index 2a3bd38..66605ae 100644
  int
  xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, 
int x, int y)
  {
-@@ -1253,128 +1274,156 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const 
Glyph *glyphs, int len, int x
+       float winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, xp, 
yp;
+-      ushort mode, prevmode = USHRT_MAX;
++      ushort mode = glyphs[0].mode & ~ATTR_WRAP;
+       Font *font = &dc.font;
+       int frcflags = FRC_NORMAL;
+-      float runewidth = win.cw;
++      float runewidth = win.cw * ((glyphs[0].mode & ATTR_WIDE) ? 2.0f : 1.0f);
+       Rune rune;
+       FT_UInt glyphidx;
+       FcResult fcres;
        FcPattern *fcpattern, *fontpattern;
        FcFontSet *fcsets[] = { NULL };
        FcCharSet *fccharset;
 -      int i, f, numspecs = 0;
-+      int i, f, length = 0, start = 0, numspecs = 0;
++      int f, code_idx, numspecs = 0;
 +      float cluster_xp = xp, cluster_yp = yp;
 +      HbTransformData shaped = { 0 };
-+
-+      /* Initial values. */
-+      mode = prevmode = glyphs[0].mode & ~ATTR_WRAP;
-+      xresetfontsettings(mode, &font, &frcflags);
  
-       for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) {
+-      for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) {
 -              /* Fetch rune and mode for current glyph. */
 -              rune = glyphs[i].u;
 -              mode = glyphs[i].mode;
-+              mode = glyphs[i].mode & ~ATTR_WRAP;
++      /* Initial values. */
++      xresetfontsettings(mode, &font, &frcflags);
  
-               /* Skip dummy wide-character spacing. */
+-              /* Skip dummy wide-character spacing. */
 -              if (mode == ATTR_WDUMMY)
-+              if (mode & ATTR_WDUMMY && i < (len - 1))
++      /* Shape the segment. */
++      hbtransform(&shaped, font->match, glyphs, 0, len);
++      xp = winx; yp = winy + font->ascent;
++      cluster_xp = xp; cluster_yp = yp;
++
++      for (code_idx = 0; code_idx < shaped.count; code_idx++) {
++              int idx = shaped.glyphs[code_idx].cluster;
++
++              if (glyphs[idx].mode & ATTR_WDUMMY)
                        continue;
  
 -              /* Determine font for glyph if different from previous glyph. */
@@ -345,31 +394,31 @@ index 2a3bd38..66605ae 100644
 -                      } else if (mode & ATTR_BOLD) {
 -                              font = &dc.bfont;
 -                              frcflags = FRC_BOLD;
-+              if (
-+                      prevmode != mode
-+                      || ATTRCMP(glyphs[start], glyphs[i])
-+                      || selected(x + i, y) != selected(x + start, y)
-+                      || i == (len - 1)
-+              ) {
-+                      /* Handle 1-character wide segments and end of line */
-+                      length = i - start;
-+                      if (i == start) {
-+                              length = 1;
-+                      } else if (i == (len - 1)) {
-+                              length = (i - start + 1);
-                       }
+-                      }
 -                      yp = winy + font->ascent;
--              }
++              /* Advance the drawing cursor if we've moved to a new cluster */
++              if (code_idx > 0 && idx != shaped.glyphs[code_idx - 1].cluster) 
{
++                      xp += runewidth;
++                      cluster_xp = xp;
++                      cluster_yp = yp;
+               }
  
 -              /* Lookup character index with default font. */
 -              glyphidx = XftCharIndex(xw.dpy, font->match, rune);
 -              if (glyphidx) {
--                      specs[numspecs].font = font->match;
++              if (shaped.glyphs[code_idx].codepoint != 0) {
++                      /* If symbol is found, put it into the specs. */
+                       specs[numspecs].font = font->match;
 -                      specs[numspecs].glyph = glyphidx;
 -                      specs[numspecs].x = (short)xp;
 -                      specs[numspecs].y = (short)yp;
 -                      xp += runewidth;
--                      numspecs++;
++                      specs[numspecs].glyph = 
shaped.glyphs[code_idx].codepoint;
++                      specs[numspecs].x = cluster_xp + 
(short)(shaped.positions[code_idx].x_offset / 64.);
++                      specs[numspecs].y = cluster_yp - 
(short)(shaped.positions[code_idx].y_offset / 64.);
++                      cluster_xp += shaped.positions[code_idx].x_advance / 
64.;
++                      cluster_yp += shaped.positions[code_idx].y_advance / 
64.;
+                       numspecs++;
 -                      continue;
 -              }
 -
@@ -383,105 +432,18 @@ index 2a3bd38..66605ae 100644
 -                      if (!glyphidx && frc[f].flags == frcflags
 -                                      && frc[f].unicodep == rune) {
 -                              break;
-+                      /* Shape the segment. */
-+                      hbtransform(&shaped, font->match, glyphs, start, 
length);
-+                      runewidth = win.cw * ((glyphs[start].mode & ATTR_WIDE) 
? 2.0f : 1.0f);
-+                      cluster_xp = xp; cluster_yp = yp;
-+                      for (int code_idx = 0; code_idx < shaped.count; 
code_idx++) {
-+                              int idx = shaped.glyphs[code_idx].cluster;
-+
-+                              if (glyphs[start + idx].mode & ATTR_WDUMMY)
-+                                      continue;
-+
-+                              /* Advance the drawing cursor if we've moved to 
a new cluster */
-+                              if (code_idx > 0 && idx != 
shaped.glyphs[code_idx - 1].cluster) {
-+                                      xp += runewidth;
-+                                      cluster_xp = xp;
-+                                      cluster_yp = yp;
-+                                      runewidth = win.cw * ((glyphs[start + 
idx].mode & ATTR_WIDE) ? 2.0f : 1.0f);
-+                              }
-+
-+                              if (shaped.glyphs[code_idx].codepoint != 0) {
-+                                      /* If symbol is found, put it into the 
specs. */
-+                                      specs[numspecs].font = font->match;
-+                                      specs[numspecs].glyph = 
shaped.glyphs[code_idx].codepoint;
-+                                      specs[numspecs].x = cluster_xp + 
(short)(shaped.positions[code_idx].x_offset / 64.);
-+                                      specs[numspecs].y = cluster_yp - 
(short)(shaped.positions[code_idx].y_offset / 64.);
-+                                      cluster_xp += 
shaped.positions[code_idx].x_advance / 64.;
-+                                      cluster_yp += 
shaped.positions[code_idx].y_advance / 64.;
-+                                      numspecs++;
-+                              } else {
-+                                      /* If it's not found, try to fetch it 
through the font cache. */
-+                                      rune = glyphs[start + idx].u;
-+                                      for (f = 0; f < frclen; f++) {
-+                                              glyphidx = XftCharIndex(xw.dpy, 
frc[f].font, rune);
-+                                              /* Everything correct. */
-+                                              if (glyphidx && frc[f].flags == 
frcflags)
-+                                                      break;
-+                                              /* We got a default font for a 
not found glyph. */
-+                                              if (!glyphidx && frc[f].flags 
== frcflags
-+                                                              && 
frc[f].unicodep == rune) {
-+                                                      break;
-+                                              }
-+                                      }
-+
-+                                      /* Nothing was found. Use fontconfig to 
find matching font. */
-+                                      if (f >= frclen) {
-+                                              if (!font->set)
-+                                                      font->set = 
FcFontSort(0, font->pattern,
-+                                                                              
                                                                 1, 0, &fcres);
-+                                              fcsets[0] = font->set;
-+
-+                                              /*
-+                                               * Nothing was found in the 
cache. Now use
-+                                               * some dozen of Fontconfig 
calls to get the
-+                                               * font for one single 
character.
-+                                               *
-+                                               * Xft and fontconfig are 
design failures.
-+                                               */
-+                                              fcpattern = 
FcPatternDuplicate(font->pattern);
-+                                              fccharset = FcCharSetCreate();
-+
-+                                              FcCharSetAddChar(fccharset, 
rune);
-+                                              FcPatternAddCharSet(fcpattern, 
FC_CHARSET,
-+                                                              fccharset);
-+                                              FcPatternAddBool(fcpattern, 
FC_SCALABLE, 1);
-+
-+                                              FcConfigSubstitute(0, fcpattern,
-+                                                              FcMatchPattern);
-+                                              FcDefaultSubstitute(fcpattern);
-+
-+                                              fontpattern = FcFontSetMatch(0, 
fcsets, 1,
-+                                                              fcpattern, 
&fcres);
-+
-+                                              /* Allocate memory for the new 
cache entry. */
-+                                              if (frclen >= frccap) {
-+                                                      frccap += 16;
-+                                                      frc = xrealloc(frc, 
frccap * sizeof(Fontcache));
-+                                              }
-+
-+                                              frc[frclen].font = 
XftFontOpenPattern(xw.dpy,
-+                                                              fontpattern);
-+                                              if (!frc[frclen].font)
-+                                                      die("XftFontOpenPattern 
failed seeking fallback font: %s
",
-+                                                              
strerror(errno));
-+                                              frc[frclen].flags = frcflags;
-+                                              frc[frclen].unicodep = rune;
-+
-+                                              glyphidx = XftCharIndex(xw.dpy, 
frc[frclen].font, rune);
-+
-+                                              f = frclen;
-+                                              frclen++;
-+
-+                                              FcPatternDestroy(fcpattern);
-+                                              FcCharSetDestroy(fccharset);
-+                                      }
-+
-+                                      specs[numspecs].font = frc[f].font;
-+                                      specs[numspecs].glyph = glyphidx;
-+                                      specs[numspecs].x = (short)xp;
-+                                      specs[numspecs].y = (short)yp;
-+                                      numspecs++;
++              } else {
++                      /* If it's not found, try to fetch it through the font 
cache. */
++                      rune = glyphs[idx].u;
++                      for (f = 0; f < frclen; f++) {
++                              glyphidx = XftCharIndex(xw.dpy, frc[f].font, 
rune);
++                              /* Everything correct. */
++                              if (glyphidx && frc[f].flags == frcflags)
++                                      break;
++                              /* We got a default font for a not found glyph. 
*/
++                              if (!glyphidx && frc[f].flags == frcflags
++                                              && frc[f].unicodep == rune) {
++                                      break;
 +                              }
                        }
 -              }
@@ -492,10 +454,7 @@ index 2a3bd38..66605ae 100644
 -                              font->set = FcFontSort(0, font->pattern,
 -                                                     1, 0, &fcres);
 -                      fcsets[0] = font->set;
-+                      /* Cleanup and get ready for next segment. */
-+                      hbcleanup(&shaped);
-+                      start = i;
- 
+-
 -                      /*
 -                       * Nothing was found in the cache. Now use
 -                       * some dozen of Fontconfig calls to get the
@@ -522,13 +481,58 @@ index 2a3bd38..66605ae 100644
 -                      if (frclen >= frccap) {
 -                              frccap += 16;
 -                              frc = xrealloc(frc, frccap * sizeof(Fontcache));
-+                      /* Determine font for glyph if different from previous 
glyph. */
-+                      if (prevmode != mode) {
-+                              prevmode = mode;
-+                              xresetfontsettings(mode, &font, &frcflags);
-+                              yp = winy + font->ascent;
++                      /* Nothing was found. Use fontconfig to find matching 
font. */
++                      if (f >= frclen) {
++                              if (!font->set)
++                                      font->set = FcFontSort(0, font->pattern,
++                                                             1, 0, &fcres);
++                              fcsets[0] = font->set;
++
++                              /*
++                               * Nothing was found in the cache. Now use
++                               * some dozen of Fontconfig calls to get the
++                               * font for one single character.
++                               *
++                               * Xft and fontconfig are design failures.
++                               */
++                              fcpattern = FcPatternDuplicate(font->pattern);
++                              fccharset = FcCharSetCreate();
++
++                              FcCharSetAddChar(fccharset, rune);
++                              FcPatternAddCharSet(fcpattern, FC_CHARSET,
++                                              fccharset);
++                              FcPatternAddBool(fcpattern, FC_SCALABLE, 1);
++
++                              FcConfigSubstitute(0, fcpattern,
++                                              FcMatchPattern);
++                              FcDefaultSubstitute(fcpattern);
++
++                              fontpattern = FcFontSetMatch(0, fcsets, 1,
++                                              fcpattern, &fcres);
++
++                              /* Allocate memory for the new cache entry. */
++                              if (frclen >= frccap) {
++                                      frccap += 16;
++                                      frc = xrealloc(frc, frccap * 
sizeof(Fontcache));
++                              }
++
++                              frc[frclen].font = XftFontOpenPattern(xw.dpy,
++                                              fontpattern);
++                              if (!frc[frclen].font)
++                                      die("XftFontOpenPattern failed seeking 
fallback font: %s
",
++                                              strerror(errno));
++                              frc[frclen].flags = frcflags;
++                              frc[frclen].unicodep = rune;
++
++                              glyphidx = XftCharIndex(xw.dpy, 
frc[frclen].font, rune);
++
++                              f = frclen;
++                              frclen++;
++
++                              FcPatternDestroy(fcpattern);
++                              FcCharSetDestroy(fccharset);
                        }
--
+ 
 -                      frc[frclen].font = XftFontOpenPattern(xw.dpy,
 -                                      fontpattern);
 -                      if (!frc[frclen].font)
@@ -544,6 +548,11 @@ index 2a3bd38..66605ae 100644
 -
 -                      FcPatternDestroy(fcpattern);
 -                      FcCharSetDestroy(fccharset);
++                      specs[numspecs].font = frc[f].font;
++                      specs[numspecs].glyph = glyphidx;
++                      specs[numspecs].x = (short)xp;
++                      specs[numspecs].y = (short)yp;
++                      numspecs++;
                }
 -
 -              specs[numspecs].font = frc[f].font;
@@ -554,6 +563,8 @@ index 2a3bd38..66605ae 100644
 -              numspecs++;
        }
  
++      /* Cleanup and get ready for next segment. */
++      hbcleanup(&shaped);
        return numspecs;
  }
  
@@ -565,7 +576,9 @@ index 2a3bd38..66605ae 100644
        int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch,
            width = charlen * win.cw;
        Color *fg, *bg, *temp, revfg, revbg, truefg, truebg;
-@@ -1510,21 +1559,24 @@ void
+       XRenderColor colfg, colbg;
+@@ -1509,23 +1525,26 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, 
Glyph base, int len, int x, i
+ void
  xdrawglyph(Glyph g, int x, int y)
  {
        int numspecs;
@@ -595,7 +608,9 @@ index 2a3bd38..66605ae 100644
  
        if (IS_SET(MODE_HIDE))
                return;
-@@ -1652,18 +1704,16 @@ xdrawline(Line line, int x1, int y1, int x2)
+ 
+@@ -1657,30 +1676,30 @@ xdrawline(Line line, int x1, int y1, int x2)
+       int i, x, ox, numspecs;
        Glyph base, new;
        XftGlyphFontSpec *specs = xw.specbuf;
  
@@ -618,7 +633,8 @@ index 2a3bd38..66605ae 100644
                        i = 0;
                }
                if (i == 0) {
-@@ -1672,8 +1722,10 @@ xdrawline(Line line, int x1, int y1, int x2)
+                       ox = x;
+                       base = new;
                }
                i++;
        }
@@ -631,3 +647,4 @@ index 2a3bd38..66605ae 100644
  }
  
  void
+ xfinishdraw(void)
diff --git 
a/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-alpha-20240427-0.9.2.diff
 
b/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-alpha-20241226-0.9.2.diff
similarity index 71%
rename from 
st.suckless.org/patches/ligatures/0.9.2/st-ligatures-alpha-20240427-0.9.2.diff
rename to 
st.suckless.org/patches/ligatures/0.9.2/st-ligatures-alpha-20241226-0.9.2.diff
index a4ac3f7d..7a8aa2ff 100644
--- 
a/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-alpha-20240427-0.9.2.diff
+++ 
b/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-alpha-20241226-0.9.2.diff
@@ -1,8 +1,9 @@
 diff --git a/Makefile b/Makefile
-index 470ac86..38240da 100644
+index 15db421..dfcea0f 100644
 --- a/Makefile
 +++ b/Makefile
-@@ -4,7 +4,7 @@
+@@ -3,9 +3,9 @@
+ .POSIX:
  
  include config.mk
  
@@ -11,7 +12,9 @@ index 470ac86..38240da 100644
  OBJ = $(SRC:.c=.o)
  
  all: st
-@@ -22,7 +22,8 @@ config.h:
+ 
+@@ -15,9 +15,10 @@ config.h:
+ .c.o:
        $(CC) $(STCFLAGS) -c $<
  
  st.o: config.h st.h win.h
@@ -21,19 +24,20 @@ index 470ac86..38240da 100644
  
  $(OBJ): config.h config.mk
  
+ st: $(OBJ)
 diff --git a/config.mk b/config.mk
-index 47c615e..d7439a3 100644
+index 069a6c2..977b7c7 100644
 --- a/config.mk
 +++ b/config.mk
-@@ -15,10 +15,12 @@ PKG_CONFIG = pkg-config
+@@ -14,12 +14,14 @@ PKG_CONFIG = pkg-config
+ 
  # includes and libs
  INCS = -I$(X11INC) \
         `$(PKG_CONFIG) --cflags fontconfig` \
 -       `$(PKG_CONFIG) --cflags freetype2`
--LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender\
 +       `$(PKG_CONFIG) --cflags freetype2` \
 +       `$(PKG_CONFIG) --cflags harfbuzz`
-+LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender \
+ LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender\
         `$(PKG_CONFIG) --libs fontconfig` \
 -       `$(PKG_CONFIG) --libs freetype2`
 +       `$(PKG_CONFIG) --libs freetype2` \
@@ -41,9 +45,22 @@ index 47c615e..d7439a3 100644
  
  # flags
  STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600
+ STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS)
+@@ -28,9 +30,10 @@ STLDFLAGS = $(LIBS) $(LDFLAGS)
+ # OpenBSD:
+ #CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 -D_BSD_SOURCE
+ #LIBS = -L$(X11LIB) -lm -lX11 -lutil -lXft \
+ #       `$(PKG_CONFIG) --libs fontconfig` \
+-#       `$(PKG_CONFIG) --libs freetype2`
++#       `$(PKG_CONFIG) --libs freetype2` \
++#       `$(PKG_CONFIG) --libs harfbuzz`
+ #MANPREFIX = ${PREFIX}/man
+ 
+ # compiler and linker
+ # CC = c99
 diff --git a/hb.c b/hb.c
 new file mode 100644
-index 0000000..58d534b
+index 0000000..99412c8
 --- /dev/null
 +++ b/hb.c
 @@ -0,0 +1,125 @@
@@ -193,10 +210,11 @@ index 0000000..3b0ef44
 +void hbtransform(HbTransformData *, XftFont *, const Glyph *, int, int);
 +void hbcleanup(HbTransformData *);
 diff --git a/st.c b/st.c
-index 62def59..041c6d8 100644
+index b9f66e7..da33a85 100644
 --- a/st.c
 +++ b/st.c
-@@ -2640,7 +2640,8 @@ draw(void)
+@@ -2658,9 +2658,10 @@ draw(void)
+               cx--;
  
        drawregion(0, 0, term.col, term.row);
        xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
@@ -206,11 +224,13 @@ index 62def59..041c6d8 100644
        term.ocx = cx;
        term.ocy = term.c.y;
        xfinishdraw();
+       if (ocx != term.ocx || ocy != term.ocy)
 diff --git a/st.h b/st.h
 index 9f91e2a..b1a6256 100644
 --- a/st.h
 +++ b/st.h
-@@ -11,7 +11,8 @@
+@@ -10,9 +10,10 @@
+ #define BETWEEN(x, a, b)      ((a) <= (x) && (x) <= (b))
  #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)
@@ -220,11 +240,13 @@ index 9f91e2a..b1a6256 100644
                                (a).bg != (b).bg)
  #define TIMEDIFF(t1, t2)      ((t1.tv_sec-t2.tv_sec)*1000 + \
                                (t1.tv_nsec-t2.tv_nsec)/1E6)
+ #define MODBIT(x, set, bit)   ((set) ? ((x) |= (bit)) : ((x) &= ~(bit)))
 diff --git a/win.h b/win.h
 index 6de960d..94679e4 100644
 --- a/win.h
 +++ b/win.h
-@@ -25,7 +25,7 @@ enum win_mode {
+@@ -24,9 +24,9 @@ enum win_mode {
+ };
  
  void xbell(void);
  void xclipcopy(void);
@@ -233,11 +255,13 @@ index 6de960d..94679e4 100644
  void xdrawline(Line, int, int, int);
  void xfinishdraw(void);
  void xloadcols(void);
+ int xsetcolorname(int, const char *);
 diff --git a/x.c b/x.c
-index 27e81d1..0632636 100644
+index 1e12ac8..b0819ac 100644
 --- a/x.c
 +++ b/x.c
-@@ -19,6 +19,7 @@ char *argv0;
+@@ -18,8 +18,9 @@
+ char *argv0;
  #include "arg.h"
  #include "st.h"
  #include "win.h"
@@ -245,7 +269,9 @@ index 27e81d1..0632636 100644
  
  /* types used in config.h */
  typedef struct {
-@@ -142,8 +143,9 @@ typedef struct {
+       uint mod;
+@@ -141,10 +142,11 @@ typedef struct {
+       GC gc;
  } DC;
  
  static inline ushort sixd_to_16bit(int);
@@ -256,7 +282,9 @@ index 27e81d1..0632636 100644
  static void xdrawglyph(Glyph, int, int);
  static void xclear(int, int, int, int);
  static int xgeommasktogravity(int);
-@@ -759,7 +761,7 @@ xresize(int col, int row)
+ static int ximopen(Display *);
+@@ -758,9 +760,9 @@ xresize(int col, int row)
+       XftDrawChange(xw.draw, xw.buf);
        xclear(0, 0, win.w, win.h);
  
        /* resize to new width */
@@ -265,7 +293,9 @@ index 27e81d1..0632636 100644
  }
  
  ushort
-@@ -1071,6 +1073,9 @@ xunloadfont(Font *f)
+ sixd_to_16bit(int x)
+@@ -1070,8 +1072,11 @@ xunloadfont(Font *f)
+ 
  void
  xunloadfonts(void)
  {
@@ -275,7 +305,9 @@ index 27e81d1..0632636 100644
        /* Free the loaded fonts in the font cache.  */
        while (frclen > 0)
                XftFontClose(xw.dpy, frc[--frclen].font);
-@@ -1202,7 +1207,7 @@ xinit(int cols, int rows)
+ 
+@@ -1201,9 +1206,9 @@ xinit(int cols, int rows)
+       XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel);
        XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h);
  
        /* font spec buffer */
@@ -284,7 +316,9 @@ index 27e81d1..0632636 100644
  
        /* Xft rendering context */
        xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
-@@ -1256,6 +1261,22 @@ xinit(int cols, int rows)
+ 
+@@ -1255,144 +1260,155 @@ xinit(int cols, int rows)
+       if (xsel.xtarget == None)
                xsel.xtarget = XA_STRING;
  }
  
@@ -307,28 +341,42 @@ index 27e81d1..0632636 100644
  int
  xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, 
int x, int y)
  {
-@@ -1270,128 +1291,157 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const 
Glyph *glyphs, int len, int x
+       float winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, xp, 
yp;
+-      ushort mode, prevmode = USHRT_MAX;
++      ushort mode = glyphs[0].mode & ~ATTR_WRAP;
+       Font *font = &dc.font;
+       int frcflags = FRC_NORMAL;
+-      float runewidth = win.cw;
++      float runewidth = win.cw * ((glyphs[0].mode & ATTR_WIDE) ? 2.0f : 1.0f);
+       Rune rune;
+       FT_UInt glyphidx;
+       FcResult fcres;
        FcPattern *fcpattern, *fontpattern;
        FcFontSet *fcsets[] = { NULL };
        FcCharSet *fccharset;
 -      int i, f, numspecs = 0;
-+      int i, f, length = 0, start = 0, numspecs = 0;
++      int f, code_idx, numspecs = 0;
 +      float cluster_xp = xp, cluster_yp = yp;
 +      HbTransformData shaped = { 0 };
-+
-+      /* Initial values. */
-+      mode = prevmode = glyphs[0].mode & ~ATTR_WRAP;
-+      xresetfontsettings(mode, &font, &frcflags);
  
-       for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) {
+-      for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) {
 -              /* Fetch rune and mode for current glyph. */
 -              rune = glyphs[i].u;
 -              mode = glyphs[i].mode;
-+              mode = glyphs[i].mode & ~ATTR_WRAP;
++      /* Initial values. */
++      xresetfontsettings(mode, &font, &frcflags);
  
-               /* Skip dummy wide-character spacing. */
+-              /* Skip dummy wide-character spacing. */
 -              if (mode == ATTR_WDUMMY)
-+              if (mode & ATTR_WDUMMY && i < (len - 1))
++      /* Shape the segment. */
++      hbtransform(&shaped, font->match, glyphs, 0, len);
++      xp = winx; yp = winy + font->ascent;
++      cluster_xp = xp; cluster_yp = yp;
++
++      for (code_idx = 0; code_idx < shaped.count; code_idx++) {
++              int idx = shaped.glyphs[code_idx].cluster;
++
++              if (glyphs[idx].mode & ATTR_WDUMMY)
                        continue;
  
 -              /* Determine font for glyph if different from previous glyph. */
@@ -346,31 +394,31 @@ index 27e81d1..0632636 100644
 -                      } else if (mode & ATTR_BOLD) {
 -                              font = &dc.bfont;
 -                              frcflags = FRC_BOLD;
-+              if (
-+                      prevmode != mode
-+                      || ATTRCMP(glyphs[start], glyphs[i])
-+                      || selected(x + i, y) != selected(x + start, y)
-+                      || i == (len - 1)
-+              ) {
-+                      /* Handle 1-character wide segments and end of line */
-+                      length = i - start;
-+                      if (i == start) {
-+                              length = 1;
-+                      } else if (i == (len - 1)) {
-+                              length = (i - start + 1);
-                       }
+-                      }
 -                      yp = winy + font->ascent;
--              }
++              /* Advance the drawing cursor if we've moved to a new cluster */
++              if (code_idx > 0 && idx != shaped.glyphs[code_idx - 1].cluster) 
{
++                      xp += runewidth;
++                      cluster_xp = xp;
++                      cluster_yp = yp;
+               }
  
 -              /* Lookup character index with default font. */
 -              glyphidx = XftCharIndex(xw.dpy, font->match, rune);
 -              if (glyphidx) {
--                      specs[numspecs].font = font->match;
++              if (shaped.glyphs[code_idx].codepoint != 0) {
++                      /* If symbol is found, put it into the specs. */
+                       specs[numspecs].font = font->match;
 -                      specs[numspecs].glyph = glyphidx;
 -                      specs[numspecs].x = (short)xp;
 -                      specs[numspecs].y = (short)yp;
 -                      xp += runewidth;
--                      numspecs++;
++                      specs[numspecs].glyph = 
shaped.glyphs[code_idx].codepoint;
++                      specs[numspecs].x = cluster_xp + 
(short)(shaped.positions[code_idx].x_offset / 64.);
++                      specs[numspecs].y = cluster_yp - 
(short)(shaped.positions[code_idx].y_offset / 64.);
++                      cluster_xp += shaped.positions[code_idx].x_advance / 
64.;
++                      cluster_yp += shaped.positions[code_idx].y_advance / 
64.;
+                       numspecs++;
 -                      continue;
 -              }
 -
@@ -384,105 +432,18 @@ index 27e81d1..0632636 100644
 -                      if (!glyphidx && frc[f].flags == frcflags
 -                                      && frc[f].unicodep == rune) {
 -                              break;
-+                      /* Shape the segment. */
-+                      hbtransform(&shaped, font->match, glyphs, start, 
length);
-+                      runewidth = win.cw * ((glyphs[start].mode & ATTR_WIDE) 
? 2.0f : 1.0f);
-+                      cluster_xp = xp; cluster_yp = yp;
-+                      for (int code_idx = 0; code_idx < shaped.count; 
code_idx++) {
-+                              int idx = shaped.glyphs[code_idx].cluster;
-+
-+                              if (glyphs[start + idx].mode & ATTR_WDUMMY)
-+                                      continue;
-+
-+                              /* Advance the drawing cursor if we've moved to 
a new cluster */
-+                              if (code_idx > 0 && idx != 
shaped.glyphs[code_idx - 1].cluster) {
-+                                      xp += runewidth;
-+                                      cluster_xp = xp;
-+                                      cluster_yp = yp;
-+                                      runewidth = win.cw * ((glyphs[start + 
idx].mode & ATTR_WIDE) ? 2.0f : 1.0f);
-+                              }
-+
-+                              if (shaped.glyphs[code_idx].codepoint != 0) {
-+                                      /* If symbol is found, put it into the 
specs. */
-+                                      specs[numspecs].font = font->match;
-+                                      specs[numspecs].glyph = 
shaped.glyphs[code_idx].codepoint;
-+                                      specs[numspecs].x = cluster_xp + 
(short)(shaped.positions[code_idx].x_offset / 64.);
-+                                      specs[numspecs].y = cluster_yp - 
(short)(shaped.positions[code_idx].y_offset / 64.);
-+                                      cluster_xp += 
shaped.positions[code_idx].x_advance / 64.;
-+                                      cluster_yp += 
shaped.positions[code_idx].y_advance / 64.;
-+                                      numspecs++;
-+                              } else {
-+                                      /* If it's not found, try to fetch it 
through the font cache. */
-+                                      rune = glyphs[start + idx].u;
-+                                      for (f = 0; f < frclen; f++) {
-+                                              glyphidx = XftCharIndex(xw.dpy, 
frc[f].font, rune);
-+                                              /* Everything correct. */
-+                                              if (glyphidx && frc[f].flags == 
frcflags)
-+                                                      break;
-+                                              /* We got a default font for a 
not found glyph. */
-+                                              if (!glyphidx && frc[f].flags 
== frcflags
-+                                                              && 
frc[f].unicodep == rune) {
-+                                                      break;
-+                                              }
-+                                      }
-+
-+                                      /* Nothing was found. Use fontconfig to 
find matching font. */
-+                                      if (f >= frclen) {
-+                                              if (!font->set)
-+                                                      font->set = 
FcFontSort(0, font->pattern,
-+                                                                              
                                                                 1, 0, &fcres);
-+                                              fcsets[0] = font->set;
-+
-+                                              /*
-+                                               * Nothing was found in the 
cache. Now use
-+                                               * some dozen of Fontconfig 
calls to get the
-+                                               * font for one single 
character.
-+                                               *
-+                                               * Xft and fontconfig are 
design failures.
-+                                               */
-+                                              fcpattern = 
FcPatternDuplicate(font->pattern);
-+                                              fccharset = FcCharSetCreate();
-+
-+                                              FcCharSetAddChar(fccharset, 
rune);
-+                                              FcPatternAddCharSet(fcpattern, 
FC_CHARSET,
-+                                                              fccharset);
-+                                              FcPatternAddBool(fcpattern, 
FC_SCALABLE, 1);
-+
-+                                              FcConfigSubstitute(0, fcpattern,
-+                                                              FcMatchPattern);
-+                                              FcDefaultSubstitute(fcpattern);
-+
-+                                              fontpattern = FcFontSetMatch(0, 
fcsets, 1,
-+                                                              fcpattern, 
&fcres);
-+
-+                                              /* Allocate memory for the new 
cache entry. */
-+                                              if (frclen >= frccap) {
-+                                                      frccap += 16;
-+                                                      frc = xrealloc(frc, 
frccap * sizeof(Fontcache));
-+                                              }
-+
-+                                              frc[frclen].font = 
XftFontOpenPattern(xw.dpy,
-+                                                              fontpattern);
-+                                              if (!frc[frclen].font)
-+                                                      die("XftFontOpenPattern 
failed seeking fallback font: %s
",
-+                                                              
strerror(errno));
-+                                              frc[frclen].flags = frcflags;
-+                                              frc[frclen].unicodep = rune;
-+
-+                                              glyphidx = XftCharIndex(xw.dpy, 
frc[frclen].font, rune);
-+
-+                                              f = frclen;
-+                                              frclen++;
-+
-+                                              FcPatternDestroy(fcpattern);
-+                                              FcCharSetDestroy(fccharset);
-+                                      }
-+
-+                                      specs[numspecs].font = frc[f].font;
-+                                      specs[numspecs].glyph = glyphidx;
-+                                      specs[numspecs].x = (short)xp;
-+                                      specs[numspecs].y = (short)yp;
-+                                      numspecs++;
++              } else {
++                      /* If it's not found, try to fetch it through the font 
cache. */
++                      rune = glyphs[idx].u;
++                      for (f = 0; f < frclen; f++) {
++                              glyphidx = XftCharIndex(xw.dpy, frc[f].font, 
rune);
++                              /* Everything correct. */
++                              if (glyphidx && frc[f].flags == frcflags)
++                                      break;
++                              /* We got a default font for a not found glyph. 
*/
++                              if (!glyphidx && frc[f].flags == frcflags
++                                              && frc[f].unicodep == rune) {
++                                      break;
 +                              }
                        }
 -              }
@@ -493,10 +454,7 @@ index 27e81d1..0632636 100644
 -                              font->set = FcFontSort(0, font->pattern,
 -                                                     1, 0, &fcres);
 -                      fcsets[0] = font->set;
-+                      /* Cleanup and get ready for next segment. */
-+                      hbcleanup(&shaped);
-+                      start = i;
- 
+-
 -                      /*
 -                       * Nothing was found in the cache. Now use
 -                       * some dozen of Fontconfig calls to get the
@@ -523,13 +481,58 @@ index 27e81d1..0632636 100644
 -                      if (frclen >= frccap) {
 -                              frccap += 16;
 -                              frc = xrealloc(frc, frccap * sizeof(Fontcache));
-+                      /* Determine font for glyph if different from previous 
glyph. */
-+                      if (prevmode != mode) {
-+                              prevmode = mode;
-+                              xresetfontsettings(mode, &font, &frcflags);
-+                              yp = winy + font->ascent;
++                      /* Nothing was found. Use fontconfig to find matching 
font. */
++                      if (f >= frclen) {
++                              if (!font->set)
++                                      font->set = FcFontSort(0, font->pattern,
++                                                             1, 0, &fcres);
++                              fcsets[0] = font->set;
++
++                              /*
++                               * Nothing was found in the cache. Now use
++                               * some dozen of Fontconfig calls to get the
++                               * font for one single character.
++                               *
++                               * Xft and fontconfig are design failures.
++                               */
++                              fcpattern = FcPatternDuplicate(font->pattern);
++                              fccharset = FcCharSetCreate();
++
++                              FcCharSetAddChar(fccharset, rune);
++                              FcPatternAddCharSet(fcpattern, FC_CHARSET,
++                                              fccharset);
++                              FcPatternAddBool(fcpattern, FC_SCALABLE, 1);
++
++                              FcConfigSubstitute(0, fcpattern,
++                                              FcMatchPattern);
++                              FcDefaultSubstitute(fcpattern);
++
++                              fontpattern = FcFontSetMatch(0, fcsets, 1,
++                                              fcpattern, &fcres);
++
++                              /* Allocate memory for the new cache entry. */
++                              if (frclen >= frccap) {
++                                      frccap += 16;
++                                      frc = xrealloc(frc, frccap * 
sizeof(Fontcache));
++                              }
++
++                              frc[frclen].font = XftFontOpenPattern(xw.dpy,
++                                              fontpattern);
++                              if (!frc[frclen].font)
++                                      die("XftFontOpenPattern failed seeking 
fallback font: %s
",
++                                              strerror(errno));
++                              frc[frclen].flags = frcflags;
++                              frc[frclen].unicodep = rune;
++
++                              glyphidx = XftCharIndex(xw.dpy, 
frc[frclen].font, rune);
++
++                              f = frclen;
++                              frclen++;
++
++                              FcPatternDestroy(fcpattern);
++                              FcCharSetDestroy(fccharset);
                        }
--
+ 
 -                      frc[frclen].font = XftFontOpenPattern(xw.dpy,
 -                                      fontpattern);
 -                      if (!frc[frclen].font)
@@ -545,6 +548,11 @@ index 27e81d1..0632636 100644
 -
 -                      FcPatternDestroy(fcpattern);
 -                      FcCharSetDestroy(fccharset);
++                      specs[numspecs].font = frc[f].font;
++                      specs[numspecs].glyph = glyphidx;
++                      specs[numspecs].x = (short)xp;
++                      specs[numspecs].y = (short)yp;
++                      numspecs++;
                }
 -
 -              specs[numspecs].font = frc[f].font;
@@ -555,6 +563,7 @@ index 27e81d1..0632636 100644
 -              numspecs++;
        }
  
++      /* Cleanup and get ready for next segment. */
 +      hbcleanup(&shaped);
        return numspecs;
  }
@@ -567,7 +576,9 @@ index 27e81d1..0632636 100644
        int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch,
            width = charlen * win.cw;
        Color *fg, *bg, *temp, revfg, revbg, truefg, truebg;
-@@ -1527,21 +1577,24 @@ void
+       XRenderColor colfg, colbg;
+@@ -1526,23 +1542,26 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, 
Glyph base, int len, int x, i
+ void
  xdrawglyph(Glyph g, int x, int y)
  {
        int numspecs;
@@ -597,7 +608,9 @@ index 27e81d1..0632636 100644
  
        if (IS_SET(MODE_HIDE))
                return;
-@@ -1669,18 +1722,16 @@ xdrawline(Line line, int x1, int y1, int x2)
+ 
+@@ -1674,30 +1693,30 @@ xdrawline(Line line, int x1, int y1, int x2)
+       int i, x, ox, numspecs;
        Glyph base, new;
        XftGlyphFontSpec *specs = xw.specbuf;
  
@@ -620,7 +633,8 @@ index 27e81d1..0632636 100644
                        i = 0;
                }
                if (i == 0) {
-@@ -1689,8 +1740,10 @@ xdrawline(Line line, int x1, int y1, int x2)
+                       ox = x;
+                       base = new;
                }
                i++;
        }
@@ -633,3 +647,4 @@ index 27e81d1..0632636 100644
  }
  
  void
+ xfinishdraw(void)
diff --git 
a/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-alpha-scrollback-20240427-0.9.2.diff
 
b/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-alpha-scrollback-20241226-0.9.2.diff
similarity index 71%
rename from 
st.suckless.org/patches/ligatures/0.9.2/st-ligatures-alpha-scrollback-20240427-0.9.2.diff
rename to 
st.suckless.org/patches/ligatures/0.9.2/st-ligatures-alpha-scrollback-20241226-0.9.2.diff
index 3e9d6751..00abd127 100644
--- 
a/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-alpha-scrollback-20240427-0.9.2.diff
+++ 
b/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-alpha-scrollback-20241226-0.9.2.diff
@@ -1,8 +1,9 @@
 diff --git a/Makefile b/Makefile
-index 470ac86..38240da 100644
+index 15db421..dfcea0f 100644
 --- a/Makefile
 +++ b/Makefile
-@@ -4,7 +4,7 @@
+@@ -3,9 +3,9 @@
+ .POSIX:
  
  include config.mk
  
@@ -11,7 +12,9 @@ index 470ac86..38240da 100644
  OBJ = $(SRC:.c=.o)
  
  all: st
-@@ -22,7 +22,8 @@ config.h:
+ 
+@@ -15,9 +15,10 @@ config.h:
+ .c.o:
        $(CC) $(STCFLAGS) -c $<
  
  st.o: config.h st.h win.h
@@ -21,19 +24,20 @@ index 470ac86..38240da 100644
  
  $(OBJ): config.h config.mk
  
+ st: $(OBJ)
 diff --git a/config.mk b/config.mk
-index 47c615e..d7439a3 100644
+index 069a6c2..977b7c7 100644
 --- a/config.mk
 +++ b/config.mk
-@@ -15,10 +15,12 @@ PKG_CONFIG = pkg-config
+@@ -14,12 +14,14 @@ PKG_CONFIG = pkg-config
+ 
  # includes and libs
  INCS = -I$(X11INC) \
         `$(PKG_CONFIG) --cflags fontconfig` \
 -       `$(PKG_CONFIG) --cflags freetype2`
--LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender\
 +       `$(PKG_CONFIG) --cflags freetype2` \
 +       `$(PKG_CONFIG) --cflags harfbuzz`
-+LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender \
+ LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender\
         `$(PKG_CONFIG) --libs fontconfig` \
 -       `$(PKG_CONFIG) --libs freetype2`
 +       `$(PKG_CONFIG) --libs freetype2` \
@@ -41,6 +45,19 @@ index 47c615e..d7439a3 100644
  
  # flags
  STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600
+ STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS)
+@@ -28,9 +30,10 @@ STLDFLAGS = $(LIBS) $(LDFLAGS)
+ # OpenBSD:
+ #CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 -D_BSD_SOURCE
+ #LIBS = -L$(X11LIB) -lm -lX11 -lutil -lXft \
+ #       `$(PKG_CONFIG) --libs fontconfig` \
+-#       `$(PKG_CONFIG) --libs freetype2`
++#       `$(PKG_CONFIG) --libs freetype2` \
++#       `$(PKG_CONFIG) --libs harfbuzz`
+ #MANPREFIX = ${PREFIX}/man
+ 
+ # compiler and linker
+ # CC = c99
 diff --git a/hb.c b/hb.c
 new file mode 100644
 index 0000000..99412c8
@@ -193,25 +210,27 @@ index 0000000..3b0ef44
 +void hbtransform(HbTransformData *, XftFont *, const Glyph *, int, int);
 +void hbcleanup(HbTransformData *);
 diff --git a/st.c b/st.c
-index 79ee9ba..454771d 100644
+index 2478942..bba90d3 100644
 --- a/st.c
 +++ b/st.c
-@@ -2711,7 +2711,9 @@ draw(void)
+@@ -2729,9 +2729,10 @@ draw(void)
+ 
        drawregion(0, 0, term.col, term.row);
        if (term.scr == 0)
                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();
+       if (ocx != term.ocx || ocy != term.ocy)
 diff --git a/st.h b/st.h
 index 78762a2..01eea49 100644
 --- a/st.h
 +++ b/st.h
-@@ -11,7 +11,8 @@
+@@ -10,9 +10,10 @@
+ #define BETWEEN(x, a, b)      ((a) <= (x) && (x) <= (b))
  #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)
@@ -221,11 +240,13 @@ index 78762a2..01eea49 100644
                                (a).bg != (b).bg)
  #define TIMEDIFF(t1, t2)      ((t1.tv_sec-t2.tv_sec)*1000 + \
                                (t1.tv_nsec-t2.tv_nsec)/1E6)
+ #define MODBIT(x, set, bit)   ((set) ? ((x) |= (bit)) : ((x) &= ~(bit)))
 diff --git a/win.h b/win.h
 index 6de960d..94679e4 100644
 --- a/win.h
 +++ b/win.h
-@@ -25,7 +25,7 @@ enum win_mode {
+@@ -24,9 +24,9 @@ enum win_mode {
+ };
  
  void xbell(void);
  void xclipcopy(void);
@@ -234,11 +255,13 @@ index 6de960d..94679e4 100644
  void xdrawline(Line, int, int, int);
  void xfinishdraw(void);
  void xloadcols(void);
+ int xsetcolorname(int, const char *);
 diff --git a/x.c b/x.c
-index 27e81d1..5e11c1f 100644
+index 1e12ac8..b0819ac 100644
 --- a/x.c
 +++ b/x.c
-@@ -19,6 +19,7 @@ char *argv0;
+@@ -18,8 +18,9 @@
+ char *argv0;
  #include "arg.h"
  #include "st.h"
  #include "win.h"
@@ -246,7 +269,9 @@ index 27e81d1..5e11c1f 100644
  
  /* types used in config.h */
  typedef struct {
-@@ -142,8 +143,9 @@ typedef struct {
+       uint mod;
+@@ -141,10 +142,11 @@ typedef struct {
+       GC gc;
  } DC;
  
  static inline ushort sixd_to_16bit(int);
@@ -257,7 +282,9 @@ index 27e81d1..5e11c1f 100644
  static void xdrawglyph(Glyph, int, int);
  static void xclear(int, int, int, int);
  static int xgeommasktogravity(int);
-@@ -759,7 +761,7 @@ xresize(int col, int row)
+ static int ximopen(Display *);
+@@ -758,9 +760,9 @@ xresize(int col, int row)
+       XftDrawChange(xw.draw, xw.buf);
        xclear(0, 0, win.w, win.h);
  
        /* resize to new width */
@@ -266,7 +293,9 @@ index 27e81d1..5e11c1f 100644
  }
  
  ushort
-@@ -1071,6 +1073,9 @@ xunloadfont(Font *f)
+ sixd_to_16bit(int x)
+@@ -1070,8 +1072,11 @@ xunloadfont(Font *f)
+ 
  void
  xunloadfonts(void)
  {
@@ -276,7 +305,9 @@ index 27e81d1..5e11c1f 100644
        /* Free the loaded fonts in the font cache.  */
        while (frclen > 0)
                XftFontClose(xw.dpy, frc[--frclen].font);
-@@ -1202,7 +1207,7 @@ xinit(int cols, int rows)
+ 
+@@ -1201,9 +1206,9 @@ xinit(int cols, int rows)
+       XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel);
        XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h);
  
        /* font spec buffer */
@@ -285,7 +316,9 @@ index 27e81d1..5e11c1f 100644
  
        /* Xft rendering context */
        xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
-@@ -1256,6 +1261,22 @@ xinit(int cols, int rows)
+ 
+@@ -1255,144 +1260,155 @@ xinit(int cols, int rows)
+       if (xsel.xtarget == None)
                xsel.xtarget = XA_STRING;
  }
  
@@ -308,28 +341,42 @@ index 27e81d1..5e11c1f 100644
  int
  xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, 
int x, int y)
  {
-@@ -1270,128 +1291,156 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const 
Glyph *glyphs, int len, int x
+       float winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, xp, 
yp;
+-      ushort mode, prevmode = USHRT_MAX;
++      ushort mode = glyphs[0].mode & ~ATTR_WRAP;
+       Font *font = &dc.font;
+       int frcflags = FRC_NORMAL;
+-      float runewidth = win.cw;
++      float runewidth = win.cw * ((glyphs[0].mode & ATTR_WIDE) ? 2.0f : 1.0f);
+       Rune rune;
+       FT_UInt glyphidx;
+       FcResult fcres;
        FcPattern *fcpattern, *fontpattern;
        FcFontSet *fcsets[] = { NULL };
        FcCharSet *fccharset;
 -      int i, f, numspecs = 0;
-+      int i, f, length = 0, start = 0, numspecs = 0;
++      int f, code_idx, numspecs = 0;
 +      float cluster_xp = xp, cluster_yp = yp;
 +      HbTransformData shaped = { 0 };
-+
-+      /* Initial values. */
-+      mode = prevmode = glyphs[0].mode & ~ATTR_WRAP;
-+      xresetfontsettings(mode, &font, &frcflags);
  
-       for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) {
+-      for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) {
 -              /* Fetch rune and mode for current glyph. */
 -              rune = glyphs[i].u;
 -              mode = glyphs[i].mode;
-+              mode = glyphs[i].mode & ~ATTR_WRAP;
++      /* Initial values. */
++      xresetfontsettings(mode, &font, &frcflags);
  
-               /* Skip dummy wide-character spacing. */
+-              /* Skip dummy wide-character spacing. */
 -              if (mode == ATTR_WDUMMY)
-+              if (mode & ATTR_WDUMMY && i < (len - 1))
++      /* Shape the segment. */
++      hbtransform(&shaped, font->match, glyphs, 0, len);
++      xp = winx; yp = winy + font->ascent;
++      cluster_xp = xp; cluster_yp = yp;
++
++      for (code_idx = 0; code_idx < shaped.count; code_idx++) {
++              int idx = shaped.glyphs[code_idx].cluster;
++
++              if (glyphs[idx].mode & ATTR_WDUMMY)
                        continue;
  
 -              /* Determine font for glyph if different from previous glyph. */
@@ -347,31 +394,31 @@ index 27e81d1..5e11c1f 100644
 -                      } else if (mode & ATTR_BOLD) {
 -                              font = &dc.bfont;
 -                              frcflags = FRC_BOLD;
-+              if (
-+                      prevmode != mode
-+                      || ATTRCMP(glyphs[start], glyphs[i])
-+                      || selected(x + i, y) != selected(x + start, y)
-+                      || i == (len - 1)
-+              ) {
-+                      /* Handle 1-character wide segments and end of line */
-+                      length = i - start;
-+                      if (i == start) {
-+                              length = 1;
-+                      } else if (i == (len - 1)) {
-+                              length = (i - start + 1);
-                       }
+-                      }
 -                      yp = winy + font->ascent;
--              }
++              /* Advance the drawing cursor if we've moved to a new cluster */
++              if (code_idx > 0 && idx != shaped.glyphs[code_idx - 1].cluster) 
{
++                      xp += runewidth;
++                      cluster_xp = xp;
++                      cluster_yp = yp;
+               }
  
 -              /* Lookup character index with default font. */
 -              glyphidx = XftCharIndex(xw.dpy, font->match, rune);
 -              if (glyphidx) {
--                      specs[numspecs].font = font->match;
++              if (shaped.glyphs[code_idx].codepoint != 0) {
++                      /* If symbol is found, put it into the specs. */
+                       specs[numspecs].font = font->match;
 -                      specs[numspecs].glyph = glyphidx;
 -                      specs[numspecs].x = (short)xp;
 -                      specs[numspecs].y = (short)yp;
 -                      xp += runewidth;
--                      numspecs++;
++                      specs[numspecs].glyph = 
shaped.glyphs[code_idx].codepoint;
++                      specs[numspecs].x = cluster_xp + 
(short)(shaped.positions[code_idx].x_offset / 64.);
++                      specs[numspecs].y = cluster_yp - 
(short)(shaped.positions[code_idx].y_offset / 64.);
++                      cluster_xp += shaped.positions[code_idx].x_advance / 
64.;
++                      cluster_yp += shaped.positions[code_idx].y_advance / 
64.;
+                       numspecs++;
 -                      continue;
 -              }
 -
@@ -385,105 +432,18 @@ index 27e81d1..5e11c1f 100644
 -                      if (!glyphidx && frc[f].flags == frcflags
 -                                      && frc[f].unicodep == rune) {
 -                              break;
-+                      /* Shape the segment. */
-+                      hbtransform(&shaped, font->match, glyphs, start, 
length);
-+                      runewidth = win.cw * ((glyphs[start].mode & ATTR_WIDE) 
? 2.0f : 1.0f);
-+                      cluster_xp = xp; cluster_yp = yp;
-+                      for (int code_idx = 0; code_idx < shaped.count; 
code_idx++) {
-+                              int idx = shaped.glyphs[code_idx].cluster;
-+
-+                              if (glyphs[start + idx].mode & ATTR_WDUMMY)
-+                                      continue;
-+
-+                              /* Advance the drawing cursor if we've moved to 
a new cluster */
-+                              if (code_idx > 0 && idx != 
shaped.glyphs[code_idx - 1].cluster) {
-+                                      xp += runewidth;
-+                                      cluster_xp = xp;
-+                                      cluster_yp = yp;
-+                                      runewidth = win.cw * ((glyphs[start + 
idx].mode & ATTR_WIDE) ? 2.0f : 1.0f);
-+                              }
-+
-+                              if (shaped.glyphs[code_idx].codepoint != 0) {
-+                                      /* If symbol is found, put it into the 
specs. */
-+                                      specs[numspecs].font = font->match;
-+                                      specs[numspecs].glyph = 
shaped.glyphs[code_idx].codepoint;
-+                                      specs[numspecs].x = cluster_xp + 
(short)(shaped.positions[code_idx].x_offset / 64.);
-+                                      specs[numspecs].y = cluster_yp - 
(short)(shaped.positions[code_idx].y_offset / 64.);
-+                                      cluster_xp += 
shaped.positions[code_idx].x_advance / 64.;
-+                                      cluster_yp += 
shaped.positions[code_idx].y_advance / 64.;
-+                                      numspecs++;
-+                              } else {
-+                                      /* If it's not found, try to fetch it 
through the font cache. */
-+                                      rune = glyphs[start + idx].u;
-+                                      for (f = 0; f < frclen; f++) {
-+                                              glyphidx = XftCharIndex(xw.dpy, 
frc[f].font, rune);
-+                                              /* Everything correct. */
-+                                              if (glyphidx && frc[f].flags == 
frcflags)
-+                                                      break;
-+                                              /* We got a default font for a 
not found glyph. */
-+                                              if (!glyphidx && frc[f].flags 
== frcflags
-+                                                              && 
frc[f].unicodep == rune) {
-+                                                      break;
-+                                              }
-+                                      }
-+
-+                                      /* Nothing was found. Use fontconfig to 
find matching font. */
-+                                      if (f >= frclen) {
-+                                              if (!font->set)
-+                                                      font->set = 
FcFontSort(0, font->pattern,
-+                                                                              
                                                                 1, 0, &fcres);
-+                                              fcsets[0] = font->set;
-+
-+                                              /*
-+                                               * Nothing was found in the 
cache. Now use
-+                                               * some dozen of Fontconfig 
calls to get the
-+                                               * font for one single 
character.
-+                                               *
-+                                               * Xft and fontconfig are 
design failures.
-+                                               */
-+                                              fcpattern = 
FcPatternDuplicate(font->pattern);
-+                                              fccharset = FcCharSetCreate();
-+
-+                                              FcCharSetAddChar(fccharset, 
rune);
-+                                              FcPatternAddCharSet(fcpattern, 
FC_CHARSET,
-+                                                              fccharset);
-+                                              FcPatternAddBool(fcpattern, 
FC_SCALABLE, 1);
-+
-+                                              FcConfigSubstitute(0, fcpattern,
-+                                                              FcMatchPattern);
-+                                              FcDefaultSubstitute(fcpattern);
-+
-+                                              fontpattern = FcFontSetMatch(0, 
fcsets, 1,
-+                                                              fcpattern, 
&fcres);
-+
-+                                              /* Allocate memory for the new 
cache entry. */
-+                                              if (frclen >= frccap) {
-+                                                      frccap += 16;
-+                                                      frc = xrealloc(frc, 
frccap * sizeof(Fontcache));
-+                                              }
-+
-+                                              frc[frclen].font = 
XftFontOpenPattern(xw.dpy,
-+                                                              fontpattern);
-+                                              if (!frc[frclen].font)
-+                                                      die("XftFontOpenPattern 
failed seeking fallback font: %s
",
-+                                                              
strerror(errno));
-+                                              frc[frclen].flags = frcflags;
-+                                              frc[frclen].unicodep = rune;
-+
-+                                              glyphidx = XftCharIndex(xw.dpy, 
frc[frclen].font, rune);
-+
-+                                              f = frclen;
-+                                              frclen++;
-+
-+                                              FcPatternDestroy(fcpattern);
-+                                              FcCharSetDestroy(fccharset);
-+                                      }
-+
-+                                      specs[numspecs].font = frc[f].font;
-+                                      specs[numspecs].glyph = glyphidx;
-+                                      specs[numspecs].x = (short)xp;
-+                                      specs[numspecs].y = (short)yp;
-+                                      numspecs++;
++              } else {
++                      /* If it's not found, try to fetch it through the font 
cache. */
++                      rune = glyphs[idx].u;
++                      for (f = 0; f < frclen; f++) {
++                              glyphidx = XftCharIndex(xw.dpy, frc[f].font, 
rune);
++                              /* Everything correct. */
++                              if (glyphidx && frc[f].flags == frcflags)
++                                      break;
++                              /* We got a default font for a not found glyph. 
*/
++                              if (!glyphidx && frc[f].flags == frcflags
++                                              && frc[f].unicodep == rune) {
++                                      break;
 +                              }
                        }
 -              }
@@ -494,10 +454,7 @@ index 27e81d1..5e11c1f 100644
 -                              font->set = FcFontSort(0, font->pattern,
 -                                                     1, 0, &fcres);
 -                      fcsets[0] = font->set;
-+                      /* Cleanup and get ready for next segment. */
-+                      hbcleanup(&shaped);
-+                      start = i;
- 
+-
 -                      /*
 -                       * Nothing was found in the cache. Now use
 -                       * some dozen of Fontconfig calls to get the
@@ -524,13 +481,58 @@ index 27e81d1..5e11c1f 100644
 -                      if (frclen >= frccap) {
 -                              frccap += 16;
 -                              frc = xrealloc(frc, frccap * sizeof(Fontcache));
-+                      /* Determine font for glyph if different from previous 
glyph. */
-+                      if (prevmode != mode) {
-+                              prevmode = mode;
-+                              xresetfontsettings(mode, &font, &frcflags);
-+                              yp = winy + font->ascent;
++                      /* Nothing was found. Use fontconfig to find matching 
font. */
++                      if (f >= frclen) {
++                              if (!font->set)
++                                      font->set = FcFontSort(0, font->pattern,
++                                                             1, 0, &fcres);
++                              fcsets[0] = font->set;
++
++                              /*
++                               * Nothing was found in the cache. Now use
++                               * some dozen of Fontconfig calls to get the
++                               * font for one single character.
++                               *
++                               * Xft and fontconfig are design failures.
++                               */
++                              fcpattern = FcPatternDuplicate(font->pattern);
++                              fccharset = FcCharSetCreate();
++
++                              FcCharSetAddChar(fccharset, rune);
++                              FcPatternAddCharSet(fcpattern, FC_CHARSET,
++                                              fccharset);
++                              FcPatternAddBool(fcpattern, FC_SCALABLE, 1);
++
++                              FcConfigSubstitute(0, fcpattern,
++                                              FcMatchPattern);
++                              FcDefaultSubstitute(fcpattern);
++
++                              fontpattern = FcFontSetMatch(0, fcsets, 1,
++                                              fcpattern, &fcres);
++
++                              /* Allocate memory for the new cache entry. */
++                              if (frclen >= frccap) {
++                                      frccap += 16;
++                                      frc = xrealloc(frc, frccap * 
sizeof(Fontcache));
++                              }
++
++                              frc[frclen].font = XftFontOpenPattern(xw.dpy,
++                                              fontpattern);
++                              if (!frc[frclen].font)
++                                      die("XftFontOpenPattern failed seeking 
fallback font: %s
",
++                                              strerror(errno));
++                              frc[frclen].flags = frcflags;
++                              frc[frclen].unicodep = rune;
++
++                              glyphidx = XftCharIndex(xw.dpy, 
frc[frclen].font, rune);
++
++                              f = frclen;
++                              frclen++;
++
++                              FcPatternDestroy(fcpattern);
++                              FcCharSetDestroy(fccharset);
                        }
--
+ 
 -                      frc[frclen].font = XftFontOpenPattern(xw.dpy,
 -                                      fontpattern);
 -                      if (!frc[frclen].font)
@@ -546,6 +548,11 @@ index 27e81d1..5e11c1f 100644
 -
 -                      FcPatternDestroy(fcpattern);
 -                      FcCharSetDestroy(fccharset);
++                      specs[numspecs].font = frc[f].font;
++                      specs[numspecs].glyph = glyphidx;
++                      specs[numspecs].x = (short)xp;
++                      specs[numspecs].y = (short)yp;
++                      numspecs++;
                }
 -
 -              specs[numspecs].font = frc[f].font;
@@ -556,6 +563,8 @@ index 27e81d1..5e11c1f 100644
 -              numspecs++;
        }
  
++      /* Cleanup and get ready for next segment. */
++      hbcleanup(&shaped);
        return numspecs;
  }
  
@@ -567,7 +576,9 @@ index 27e81d1..5e11c1f 100644
        int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch,
            width = charlen * win.cw;
        Color *fg, *bg, *temp, revfg, revbg, truefg, truebg;
-@@ -1527,21 +1576,24 @@ void
+       XRenderColor colfg, colbg;
+@@ -1526,23 +1542,26 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, 
Glyph base, int len, int x, i
+ void
  xdrawglyph(Glyph g, int x, int y)
  {
        int numspecs;
@@ -597,7 +608,9 @@ index 27e81d1..5e11c1f 100644
  
        if (IS_SET(MODE_HIDE))
                return;
-@@ -1669,18 +1721,16 @@ xdrawline(Line line, int x1, int y1, int x2)
+ 
+@@ -1674,30 +1693,30 @@ xdrawline(Line line, int x1, int y1, int x2)
+       int i, x, ox, numspecs;
        Glyph base, new;
        XftGlyphFontSpec *specs = xw.specbuf;
  
@@ -620,7 +633,8 @@ index 27e81d1..5e11c1f 100644
                        i = 0;
                }
                if (i == 0) {
-@@ -1689,8 +1739,10 @@ xdrawline(Line line, int x1, int y1, int x2)
+                       ox = x;
+                       base = new;
                }
                i++;
        }
@@ -633,3 +647,4 @@ index 27e81d1..5e11c1f 100644
  }
  
  void
+ xfinishdraw(void)
diff --git 
a/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-alpha-scrollback-ringbuffer-20240427-0.9.2.diff
 
b/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-alpha-scrollback-ringbuffer-20241226-0.9.2.diff
similarity index 71%
rename from 
st.suckless.org/patches/ligatures/0.9.2/st-ligatures-alpha-scrollback-ringbuffer-20240427-0.9.2.diff
rename to 
st.suckless.org/patches/ligatures/0.9.2/st-ligatures-alpha-scrollback-ringbuffer-20241226-0.9.2.diff
index 5d03b4df..49f33829 100644
--- 
a/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-alpha-scrollback-ringbuffer-20240427-0.9.2.diff
+++ 
b/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-alpha-scrollback-ringbuffer-20241226-0.9.2.diff
@@ -1,8 +1,9 @@
 diff --git a/Makefile b/Makefile
-index 470ac86..38240da 100644
+index 15db421..dfcea0f 100644
 --- a/Makefile
 +++ b/Makefile
-@@ -4,7 +4,7 @@
+@@ -3,9 +3,9 @@
+ .POSIX:
  
  include config.mk
  
@@ -11,7 +12,9 @@ index 470ac86..38240da 100644
  OBJ = $(SRC:.c=.o)
  
  all: st
-@@ -22,7 +22,8 @@ config.h:
+ 
+@@ -15,9 +15,10 @@ config.h:
+ .c.o:
        $(CC) $(STCFLAGS) -c $<
  
  st.o: config.h st.h win.h
@@ -21,19 +24,20 @@ index 470ac86..38240da 100644
  
  $(OBJ): config.h config.mk
  
+ st: $(OBJ)
 diff --git a/config.mk b/config.mk
-index 47c615e..d7439a3 100644
+index 069a6c2..977b7c7 100644
 --- a/config.mk
 +++ b/config.mk
-@@ -15,10 +15,12 @@ PKG_CONFIG = pkg-config
+@@ -14,12 +14,14 @@ PKG_CONFIG = pkg-config
+ 
  # includes and libs
  INCS = -I$(X11INC) \
         `$(PKG_CONFIG) --cflags fontconfig` \
 -       `$(PKG_CONFIG) --cflags freetype2`
--LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender\
 +       `$(PKG_CONFIG) --cflags freetype2` \
 +       `$(PKG_CONFIG) --cflags harfbuzz`
-+LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender \
+ LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender\
         `$(PKG_CONFIG) --libs fontconfig` \
 -       `$(PKG_CONFIG) --libs freetype2`
 +       `$(PKG_CONFIG) --libs freetype2` \
@@ -41,6 +45,19 @@ index 47c615e..d7439a3 100644
  
  # flags
  STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600
+ STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS)
+@@ -28,9 +30,10 @@ STLDFLAGS = $(LIBS) $(LDFLAGS)
+ # OpenBSD:
+ #CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 -D_BSD_SOURCE
+ #LIBS = -L$(X11LIB) -lm -lX11 -lutil -lXft \
+ #       `$(PKG_CONFIG) --libs fontconfig` \
+-#       `$(PKG_CONFIG) --libs freetype2`
++#       `$(PKG_CONFIG) --libs freetype2` \
++#       `$(PKG_CONFIG) --libs harfbuzz`
+ #MANPREFIX = ${PREFIX}/man
+ 
+ # compiler and linker
+ # CC = c99
 diff --git a/hb.c b/hb.c
 new file mode 100644
 index 0000000..99412c8
@@ -193,25 +210,27 @@ index 0000000..3b0ef44
 +void hbtransform(HbTransformData *, XftFont *, const Glyph *, int, int);
 +void hbcleanup(HbTransformData *);
 diff --git a/st.c b/st.c
-index c44797b..18aa1bf 100644
+index d9b163e..fbca4ba 100644
 --- a/st.c
 +++ b/st.c
-@@ -2759,7 +2759,9 @@ draw(void)
+@@ -2777,9 +2777,10 @@ draw(void)
+ 
        drawregion(0, 0, term.col, term.row);
        if (TSCREEN.off == 0)
                xdrawcursor(cx, term.c.y, TLINE(term.c.y)[cx],
 -                              term.ocx, term.ocy, TLINE(term.ocy)[term.ocx]);
 +                              term.ocx, term.ocy, TLINE(term.ocy)[term.ocx],
 +                              TLINE(term.ocy), term.col);
-+
        term.ocx = cx;
        term.ocy = term.c.y;
        xfinishdraw();
+       if (ocx != term.ocx || ocy != term.ocy)
 diff --git a/st.h b/st.h
 index 073851a..d0b071d 100644
 --- a/st.h
 +++ b/st.h
-@@ -11,7 +11,8 @@
+@@ -10,9 +10,10 @@
+ #define BETWEEN(x, a, b)      ((a) <= (x) && (x) <= (b))
  #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)
@@ -221,11 +240,13 @@ index 073851a..d0b071d 100644
                                (a).bg != (b).bg)
  #define TIMEDIFF(t1, t2)      ((t1.tv_sec-t2.tv_sec)*1000 + \
                                (t1.tv_nsec-t2.tv_nsec)/1E6)
+ #define MODBIT(x, set, bit)   ((set) ? ((x) |= (bit)) : ((x) &= ~(bit)))
 diff --git a/win.h b/win.h
 index 6de960d..94679e4 100644
 --- a/win.h
 +++ b/win.h
-@@ -25,7 +25,7 @@ enum win_mode {
+@@ -24,9 +24,9 @@ enum win_mode {
+ };
  
  void xbell(void);
  void xclipcopy(void);
@@ -234,11 +255,13 @@ index 6de960d..94679e4 100644
  void xdrawline(Line, int, int, int);
  void xfinishdraw(void);
  void xloadcols(void);
+ int xsetcolorname(int, const char *);
 diff --git a/x.c b/x.c
-index b81f5be..c1611bb 100644
+index c497e53..a213e52 100644
 --- a/x.c
 +++ b/x.c
-@@ -19,6 +19,7 @@ char *argv0;
+@@ -18,8 +18,9 @@
+ char *argv0;
  #include "arg.h"
  #include "st.h"
  #include "win.h"
@@ -246,7 +269,9 @@ index b81f5be..c1611bb 100644
  
  /* types used in config.h */
  typedef struct {
-@@ -144,8 +145,9 @@ typedef struct {
+       uint mod;
+@@ -143,10 +144,11 @@ typedef struct {
+       GC gc;
  } DC;
  
  static inline ushort sixd_to_16bit(int);
@@ -257,7 +282,9 @@ index b81f5be..c1611bb 100644
  static void xdrawglyph(Glyph, int, int);
  static void xclear(int, int, int, int);
  static int xgeommasktogravity(int);
-@@ -761,7 +763,7 @@ xresize(int col, int row)
+ static int ximopen(Display *);
+@@ -760,9 +762,9 @@ xresize(int col, int row)
+       XftDrawChange(xw.draw, xw.buf);
        xclear(0, 0, win.w, win.h);
  
        /* resize to new width */
@@ -266,7 +293,9 @@ index b81f5be..c1611bb 100644
  }
  
  ushort
-@@ -1073,6 +1075,9 @@ xunloadfont(Font *f)
+ sixd_to_16bit(int x)
+@@ -1072,8 +1074,11 @@ xunloadfont(Font *f)
+ 
  void
  xunloadfonts(void)
  {
@@ -276,7 +305,9 @@ index b81f5be..c1611bb 100644
        /* Free the loaded fonts in the font cache.  */
        while (frclen > 0)
                XftFontClose(xw.dpy, frc[--frclen].font);
-@@ -1204,7 +1209,7 @@ xinit(int cols, int rows)
+ 
+@@ -1203,9 +1208,9 @@ xinit(int cols, int rows)
+       XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel);
        XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h);
  
        /* font spec buffer */
@@ -285,7 +316,9 @@ index b81f5be..c1611bb 100644
  
        /* Xft rendering context */
        xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
-@@ -1258,6 +1263,22 @@ xinit(int cols, int rows)
+ 
+@@ -1257,144 +1262,155 @@ xinit(int cols, int rows)
+       if (xsel.xtarget == None)
                xsel.xtarget = XA_STRING;
  }
  
@@ -308,28 +341,42 @@ index b81f5be..c1611bb 100644
  int
  xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, 
int x, int y)
  {
-@@ -1272,128 +1293,156 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const 
Glyph *glyphs, int len, int x
+       float winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, xp, 
yp;
+-      ushort mode, prevmode = USHRT_MAX;
++      ushort mode = glyphs[0].mode & ~ATTR_WRAP;
+       Font *font = &dc.font;
+       int frcflags = FRC_NORMAL;
+-      float runewidth = win.cw;
++      float runewidth = win.cw * ((glyphs[0].mode & ATTR_WIDE) ? 2.0f : 1.0f);
+       Rune rune;
+       FT_UInt glyphidx;
+       FcResult fcres;
        FcPattern *fcpattern, *fontpattern;
        FcFontSet *fcsets[] = { NULL };
        FcCharSet *fccharset;
 -      int i, f, numspecs = 0;
-+      int i, f, length = 0, start = 0, numspecs = 0;
++      int f, code_idx, numspecs = 0;
 +      float cluster_xp = xp, cluster_yp = yp;
 +      HbTransformData shaped = { 0 };
-+
-+      /* Initial values. */
-+      mode = prevmode = glyphs[0].mode & ~ATTR_WRAP;
-+      xresetfontsettings(mode, &font, &frcflags);
  
-       for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) {
+-      for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) {
 -              /* Fetch rune and mode for current glyph. */
 -              rune = glyphs[i].u;
 -              mode = glyphs[i].mode;
-+              mode = glyphs[i].mode & ~ATTR_WRAP;
++      /* Initial values. */
++      xresetfontsettings(mode, &font, &frcflags);
  
-               /* Skip dummy wide-character spacing. */
+-              /* Skip dummy wide-character spacing. */
 -              if (mode == ATTR_WDUMMY)
-+              if (mode & ATTR_WDUMMY && i < (len - 1))
++      /* Shape the segment. */
++      hbtransform(&shaped, font->match, glyphs, 0, len);
++      xp = winx; yp = winy + font->ascent;
++      cluster_xp = xp; cluster_yp = yp;
++
++      for (code_idx = 0; code_idx < shaped.count; code_idx++) {
++              int idx = shaped.glyphs[code_idx].cluster;
++
++              if (glyphs[idx].mode & ATTR_WDUMMY)
                        continue;
  
 -              /* Determine font for glyph if different from previous glyph. */
@@ -347,31 +394,31 @@ index b81f5be..c1611bb 100644
 -                      } else if (mode & ATTR_BOLD) {
 -                              font = &dc.bfont;
 -                              frcflags = FRC_BOLD;
-+              if (
-+                      prevmode != mode
-+                      || ATTRCMP(glyphs[start], glyphs[i])
-+                      || selected(x + i, y) != selected(x + start, y)
-+                      || i == (len - 1)
-+              ) {
-+                      /* Handle 1-character wide segments and end of line */
-+                      length = i - start;
-+                      if (i == start) {
-+                              length = 1;
-+                      } else if (i == (len - 1)) {
-+                              length = (i - start + 1);
-                       }
+-                      }
 -                      yp = winy + font->ascent;
--              }
++              /* Advance the drawing cursor if we've moved to a new cluster */
++              if (code_idx > 0 && idx != shaped.glyphs[code_idx - 1].cluster) 
{
++                      xp += runewidth;
++                      cluster_xp = xp;
++                      cluster_yp = yp;
+               }
  
 -              /* Lookup character index with default font. */
 -              glyphidx = XftCharIndex(xw.dpy, font->match, rune);
 -              if (glyphidx) {
--                      specs[numspecs].font = font->match;
++              if (shaped.glyphs[code_idx].codepoint != 0) {
++                      /* If symbol is found, put it into the specs. */
+                       specs[numspecs].font = font->match;
 -                      specs[numspecs].glyph = glyphidx;
 -                      specs[numspecs].x = (short)xp;
 -                      specs[numspecs].y = (short)yp;
 -                      xp += runewidth;
--                      numspecs++;
++                      specs[numspecs].glyph = 
shaped.glyphs[code_idx].codepoint;
++                      specs[numspecs].x = cluster_xp + 
(short)(shaped.positions[code_idx].x_offset / 64.);
++                      specs[numspecs].y = cluster_yp - 
(short)(shaped.positions[code_idx].y_offset / 64.);
++                      cluster_xp += shaped.positions[code_idx].x_advance / 
64.;
++                      cluster_yp += shaped.positions[code_idx].y_advance / 
64.;
+                       numspecs++;
 -                      continue;
 -              }
 -
@@ -385,105 +432,18 @@ index b81f5be..c1611bb 100644
 -                      if (!glyphidx && frc[f].flags == frcflags
 -                                      && frc[f].unicodep == rune) {
 -                              break;
-+                      /* Shape the segment. */
-+                      hbtransform(&shaped, font->match, glyphs, start, 
length);
-+                      runewidth = win.cw * ((glyphs[start].mode & ATTR_WIDE) 
? 2.0f : 1.0f);
-+                      cluster_xp = xp; cluster_yp = yp;
-+                      for (int code_idx = 0; code_idx < shaped.count; 
code_idx++) {
-+                              int idx = shaped.glyphs[code_idx].cluster;
-+
-+                              if (glyphs[start + idx].mode & ATTR_WDUMMY)
-+                                      continue;
-+
-+                              /* Advance the drawing cursor if we've moved to 
a new cluster */
-+                              if (code_idx > 0 && idx != 
shaped.glyphs[code_idx - 1].cluster) {
-+                                      xp += runewidth;
-+                                      cluster_xp = xp;
-+                                      cluster_yp = yp;
-+                                      runewidth = win.cw * ((glyphs[start + 
idx].mode & ATTR_WIDE) ? 2.0f : 1.0f);
-+                              }
-+
-+                              if (shaped.glyphs[code_idx].codepoint != 0) {
-+                                      /* If symbol is found, put it into the 
specs. */
-+                                      specs[numspecs].font = font->match;
-+                                      specs[numspecs].glyph = 
shaped.glyphs[code_idx].codepoint;
-+                                      specs[numspecs].x = cluster_xp + 
(short)(shaped.positions[code_idx].x_offset / 64.);
-+                                      specs[numspecs].y = cluster_yp - 
(short)(shaped.positions[code_idx].y_offset / 64.);
-+                                      cluster_xp += 
shaped.positions[code_idx].x_advance / 64.;
-+                                      cluster_yp += 
shaped.positions[code_idx].y_advance / 64.;
-+                                      numspecs++;
-+                              } else {
-+                                      /* If it's not found, try to fetch it 
through the font cache. */
-+                                      rune = glyphs[start + idx].u;
-+                                      for (f = 0; f < frclen; f++) {
-+                                              glyphidx = XftCharIndex(xw.dpy, 
frc[f].font, rune);
-+                                              /* Everything correct. */
-+                                              if (glyphidx && frc[f].flags == 
frcflags)
-+                                                      break;
-+                                              /* We got a default font for a 
not found glyph. */
-+                                              if (!glyphidx && frc[f].flags 
== frcflags
-+                                                              && 
frc[f].unicodep == rune) {
-+                                                      break;
-+                                              }
-+                                      }
-+
-+                                      /* Nothing was found. Use fontconfig to 
find matching font. */
-+                                      if (f >= frclen) {
-+                                              if (!font->set)
-+                                                      font->set = 
FcFontSort(0, font->pattern,
-+                                                                              
                                                                 1, 0, &fcres);
-+                                              fcsets[0] = font->set;
-+
-+                                              /*
-+                                               * Nothing was found in the 
cache. Now use
-+                                               * some dozen of Fontconfig 
calls to get the
-+                                               * font for one single 
character.
-+                                               *
-+                                               * Xft and fontconfig are 
design failures.
-+                                               */
-+                                              fcpattern = 
FcPatternDuplicate(font->pattern);
-+                                              fccharset = FcCharSetCreate();
-+
-+                                              FcCharSetAddChar(fccharset, 
rune);
-+                                              FcPatternAddCharSet(fcpattern, 
FC_CHARSET,
-+                                                              fccharset);
-+                                              FcPatternAddBool(fcpattern, 
FC_SCALABLE, 1);
-+
-+                                              FcConfigSubstitute(0, fcpattern,
-+                                                              FcMatchPattern);
-+                                              FcDefaultSubstitute(fcpattern);
-+
-+                                              fontpattern = FcFontSetMatch(0, 
fcsets, 1,
-+                                                              fcpattern, 
&fcres);
-+
-+                                              /* Allocate memory for the new 
cache entry. */
-+                                              if (frclen >= frccap) {
-+                                                      frccap += 16;
-+                                                      frc = xrealloc(frc, 
frccap * sizeof(Fontcache));
-+                                              }
-+
-+                                              frc[frclen].font = 
XftFontOpenPattern(xw.dpy,
-+                                                              fontpattern);
-+                                              if (!frc[frclen].font)
-+                                                      die("XftFontOpenPattern 
failed seeking fallback font: %s
",
-+                                                              
strerror(errno));
-+                                              frc[frclen].flags = frcflags;
-+                                              frc[frclen].unicodep = rune;
-+
-+                                              glyphidx = XftCharIndex(xw.dpy, 
frc[frclen].font, rune);
-+
-+                                              f = frclen;
-+                                              frclen++;
-+
-+                                              FcPatternDestroy(fcpattern);
-+                                              FcCharSetDestroy(fccharset);
-+                                      }
-+
-+                                      specs[numspecs].font = frc[f].font;
-+                                      specs[numspecs].glyph = glyphidx;
-+                                      specs[numspecs].x = (short)xp;
-+                                      specs[numspecs].y = (short)yp;
-+                                      numspecs++;
++              } else {
++                      /* If it's not found, try to fetch it through the font 
cache. */
++                      rune = glyphs[idx].u;
++                      for (f = 0; f < frclen; f++) {
++                              glyphidx = XftCharIndex(xw.dpy, frc[f].font, 
rune);
++                              /* Everything correct. */
++                              if (glyphidx && frc[f].flags == frcflags)
++                                      break;
++                              /* We got a default font for a not found glyph. 
*/
++                              if (!glyphidx && frc[f].flags == frcflags
++                                              && frc[f].unicodep == rune) {
++                                      break;
 +                              }
                        }
 -              }
@@ -494,10 +454,7 @@ index b81f5be..c1611bb 100644
 -                              font->set = FcFontSort(0, font->pattern,
 -                                                     1, 0, &fcres);
 -                      fcsets[0] = font->set;
-+                      /* Cleanup and get ready for next segment. */
-+                      hbcleanup(&shaped);
-+                      start = i;
- 
+-
 -                      /*
 -                       * Nothing was found in the cache. Now use
 -                       * some dozen of Fontconfig calls to get the
@@ -524,13 +481,58 @@ index b81f5be..c1611bb 100644
 -                      if (frclen >= frccap) {
 -                              frccap += 16;
 -                              frc = xrealloc(frc, frccap * sizeof(Fontcache));
-+                      /* Determine font for glyph if different from previous 
glyph. */
-+                      if (prevmode != mode) {
-+                              prevmode = mode;
-+                              xresetfontsettings(mode, &font, &frcflags);
-+                              yp = winy + font->ascent;
++                      /* Nothing was found. Use fontconfig to find matching 
font. */
++                      if (f >= frclen) {
++                              if (!font->set)
++                                      font->set = FcFontSort(0, font->pattern,
++                                                             1, 0, &fcres);
++                              fcsets[0] = font->set;
++
++                              /*
++                               * Nothing was found in the cache. Now use
++                               * some dozen of Fontconfig calls to get the
++                               * font for one single character.
++                               *
++                               * Xft and fontconfig are design failures.
++                               */
++                              fcpattern = FcPatternDuplicate(font->pattern);
++                              fccharset = FcCharSetCreate();
++
++                              FcCharSetAddChar(fccharset, rune);
++                              FcPatternAddCharSet(fcpattern, FC_CHARSET,
++                                              fccharset);
++                              FcPatternAddBool(fcpattern, FC_SCALABLE, 1);
++
++                              FcConfigSubstitute(0, fcpattern,
++                                              FcMatchPattern);
++                              FcDefaultSubstitute(fcpattern);
++
++                              fontpattern = FcFontSetMatch(0, fcsets, 1,
++                                              fcpattern, &fcres);
++
++                              /* Allocate memory for the new cache entry. */
++                              if (frclen >= frccap) {
++                                      frccap += 16;
++                                      frc = xrealloc(frc, frccap * 
sizeof(Fontcache));
++                              }
++
++                              frc[frclen].font = XftFontOpenPattern(xw.dpy,
++                                              fontpattern);
++                              if (!frc[frclen].font)
++                                      die("XftFontOpenPattern failed seeking 
fallback font: %s
",
++                                              strerror(errno));
++                              frc[frclen].flags = frcflags;
++                              frc[frclen].unicodep = rune;
++
++                              glyphidx = XftCharIndex(xw.dpy, 
frc[frclen].font, rune);
++
++                              f = frclen;
++                              frclen++;
++
++                              FcPatternDestroy(fcpattern);
++                              FcCharSetDestroy(fccharset);
                        }
--
+ 
 -                      frc[frclen].font = XftFontOpenPattern(xw.dpy,
 -                                      fontpattern);
 -                      if (!frc[frclen].font)
@@ -546,6 +548,11 @@ index b81f5be..c1611bb 100644
 -
 -                      FcPatternDestroy(fcpattern);
 -                      FcCharSetDestroy(fccharset);
++                      specs[numspecs].font = frc[f].font;
++                      specs[numspecs].glyph = glyphidx;
++                      specs[numspecs].x = (short)xp;
++                      specs[numspecs].y = (short)yp;
++                      numspecs++;
                }
 -
 -              specs[numspecs].font = frc[f].font;
@@ -556,6 +563,8 @@ index b81f5be..c1611bb 100644
 -              numspecs++;
        }
  
++      /* Cleanup and get ready for next segment. */
++      hbcleanup(&shaped);
        return numspecs;
  }
  
@@ -567,7 +576,9 @@ index b81f5be..c1611bb 100644
        int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch,
            width = charlen * win.cw;
        Color *fg, *bg, *temp, revfg, revbg, truefg, truebg;
-@@ -1529,21 +1578,24 @@ void
+       XRenderColor colfg, colbg;
+@@ -1528,23 +1544,26 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, 
Glyph base, int len, int x, i
+ void
  xdrawglyph(Glyph g, int x, int y)
  {
        int numspecs;
@@ -597,7 +608,9 @@ index b81f5be..c1611bb 100644
  
        if (IS_SET(MODE_HIDE))
                return;
-@@ -1671,18 +1723,16 @@ xdrawline(Line line, int x1, int y1, int x2)
+ 
+@@ -1676,30 +1695,30 @@ xdrawline(Line line, int x1, int y1, int x2)
+       int i, x, ox, numspecs;
        Glyph base, new;
        XftGlyphFontSpec *specs = xw.specbuf;
  
@@ -620,7 +633,8 @@ index b81f5be..c1611bb 100644
                        i = 0;
                }
                if (i == 0) {
-@@ -1691,8 +1741,10 @@ xdrawline(Line line, int x1, int y1, int x2)
+                       ox = x;
+                       base = new;
                }
                i++;
        }
@@ -633,3 +647,4 @@ index b81f5be..c1611bb 100644
  }
  
  void
+ xfinishdraw(void)
diff --git 
a/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-boxdraw-20240427-0.9.2.diff
 
b/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-boxdraw-20241226-0.9.2.diff
similarity index 70%
rename from 
st.suckless.org/patches/ligatures/0.9.2/st-ligatures-boxdraw-20240427-0.9.2.diff
rename to 
st.suckless.org/patches/ligatures/0.9.2/st-ligatures-boxdraw-20241226-0.9.2.diff
index 2a92a30b..1f8799c9 100644
--- 
a/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-boxdraw-20240427-0.9.2.diff
+++ 
b/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-boxdraw-20241226-0.9.2.diff
@@ -1,8 +1,9 @@
 diff --git a/Makefile b/Makefile
-index 6dfa212..adfa07a 100644
+index a64b4c2..05124bf 100644
 --- a/Makefile
 +++ b/Makefile
-@@ -4,7 +4,7 @@
+@@ -3,9 +3,9 @@
+ .POSIX:
  
  include config.mk
  
@@ -11,7 +12,9 @@ index 6dfa212..adfa07a 100644
  OBJ = $(SRC:.c=.o)
  
  all: st
-@@ -22,8 +22,9 @@ config.h:
+ 
+@@ -15,10 +15,11 @@ config.h:
+ .c.o:
        $(CC) $(STCFLAGS) -c $<
  
  st.o: config.h st.h win.h
@@ -22,11 +25,13 @@ index 6dfa212..adfa07a 100644
  
  $(OBJ): config.h config.mk
  
+ st: $(OBJ)
 diff --git a/config.mk b/config.mk
-index 1e306f8..3e13e53 100644
+index fdc29a7..6833b3b 100644
 --- a/config.mk
 +++ b/config.mk
-@@ -15,10 +15,12 @@ PKG_CONFIG = pkg-config
+@@ -14,12 +14,14 @@ PKG_CONFIG = pkg-config
+ 
  # includes and libs
  INCS = -I$(X11INC) \
         `$(PKG_CONFIG) --cflags fontconfig` \
@@ -41,6 +46,19 @@ index 1e306f8..3e13e53 100644
  
  # flags
  STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600
+ STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS)
+@@ -28,9 +30,10 @@ STLDFLAGS = $(LIBS) $(LDFLAGS)
+ # OpenBSD:
+ #CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 -D_BSD_SOURCE
+ #LIBS = -L$(X11LIB) -lm -lX11 -lutil -lXft \
+ #       `$(PKG_CONFIG) --libs fontconfig` \
+-#       `$(PKG_CONFIG) --libs freetype2`
++#       `$(PKG_CONFIG) --libs freetype2` \
++#       `$(PKG_CONFIG) --libs harfbuzz`
+ #MANPREFIX = ${PREFIX}/man
+ 
+ # compiler and linker
+ # CC = c99
 diff --git a/hb.c b/hb.c
 new file mode 100644
 index 0000000..99412c8
@@ -193,10 +211,11 @@ index 0000000..3b0ef44
 +void hbtransform(HbTransformData *, XftFont *, const Glyph *, int, int);
 +void hbcleanup(HbTransformData *);
 diff --git a/st.c b/st.c
-index 41d5ace..1c2edd6 100644
+index ec6fbf3..1385f77 100644
 --- a/st.c
 +++ b/st.c
-@@ -2643,7 +2643,8 @@ draw(void)
+@@ -2661,9 +2661,10 @@ draw(void)
+               cx--;
  
        drawregion(0, 0, term.col, term.row);
        xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
@@ -206,11 +225,13 @@ index 41d5ace..1c2edd6 100644
        term.ocx = cx;
        term.ocy = term.c.y;
        xfinishdraw();
+       if (ocx != term.ocx || ocy != term.ocy)
 diff --git a/st.h b/st.h
 index 808f5f7..ae41368 100644
 --- a/st.h
 +++ b/st.h
-@@ -11,7 +11,8 @@
+@@ -10,9 +10,10 @@
+ #define BETWEEN(x, a, b)      ((a) <= (x) && (x) <= (b))
  #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)
@@ -220,11 +241,13 @@ index 808f5f7..ae41368 100644
                                (a).bg != (b).bg)
  #define TIMEDIFF(t1, t2)      ((t1.tv_sec-t2.tv_sec)*1000 + \
                                (t1.tv_nsec-t2.tv_nsec)/1E6)
+ #define MODBIT(x, set, bit)   ((set) ? ((x) |= (bit)) : ((x) &= ~(bit)))
 diff --git a/win.h b/win.h
 index 6de960d..94679e4 100644
 --- a/win.h
 +++ b/win.h
-@@ -25,7 +25,7 @@ enum win_mode {
+@@ -24,9 +24,9 @@ enum win_mode {
+ };
  
  void xbell(void);
  void xclipcopy(void);
@@ -233,11 +256,13 @@ index 6de960d..94679e4 100644
  void xdrawline(Line, int, int, int);
  void xfinishdraw(void);
  void xloadcols(void);
+ int xsetcolorname(int, const char *);
 diff --git a/x.c b/x.c
-index bf6bbf9..96b117f 100644
+index 978a8fc..c2d9993 100644
 --- a/x.c
 +++ b/x.c
-@@ -19,6 +19,7 @@ char *argv0;
+@@ -18,8 +18,9 @@
+ char *argv0;
  #include "arg.h"
  #include "st.h"
  #include "win.h"
@@ -245,7 +270,9 @@ index bf6bbf9..96b117f 100644
  
  /* types used in config.h */
  typedef struct {
-@@ -141,8 +142,9 @@ typedef struct {
+       uint mod;
+@@ -140,10 +141,11 @@ typedef struct {
+       GC gc;
  } DC;
  
  static inline ushort sixd_to_16bit(int);
@@ -256,7 +283,9 @@ index bf6bbf9..96b117f 100644
  static void xdrawglyph(Glyph, int, int);
  static void xclear(int, int, int, int);
  static int xgeommasktogravity(int);
-@@ -757,7 +759,7 @@ xresize(int col, int row)
+ static int ximopen(Display *);
+@@ -756,9 +758,9 @@ xresize(int col, int row)
+       XftDrawChange(xw.draw, xw.buf);
        xclear(0, 0, win.w, win.h);
  
        /* resize to new width */
@@ -265,7 +294,9 @@ index bf6bbf9..96b117f 100644
  }
  
  ushort
-@@ -1062,6 +1064,9 @@ xunloadfont(Font *f)
+ sixd_to_16bit(int x)
+@@ -1061,8 +1063,11 @@ xunloadfont(Font *f)
+ 
  void
  xunloadfonts(void)
  {
@@ -275,7 +306,9 @@ index bf6bbf9..96b117f 100644
        /* Free the loaded fonts in the font cache.  */
        while (frclen > 0)
                XftFontClose(xw.dpy, frc[--frclen].font);
-@@ -1185,7 +1190,7 @@ xinit(int cols, int rows)
+ 
+@@ -1184,9 +1189,9 @@ xinit(int cols, int rows)
+       XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel);
        XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h);
  
        /* font spec buffer */
@@ -284,7 +317,9 @@ index bf6bbf9..96b117f 100644
  
        /* Xft rendering context */
        xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
-@@ -1241,6 +1246,22 @@ xinit(int cols, int rows)
+ 
+@@ -1240,149 +1245,162 @@ xinit(int cols, int rows)
+ 
        boxdraw_xinit(xw.dpy, xw.cmap, xw.draw, xw.vis);
  }
  
@@ -307,28 +342,42 @@ index bf6bbf9..96b117f 100644
  int
  xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, 
int x, int y)
  {
-@@ -1255,133 +1276,164 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const 
Glyph *glyphs, int len, int x
+       float winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, xp, 
yp;
+-      ushort mode, prevmode = USHRT_MAX;
++      ushort mode = glyphs[0].mode & ~ATTR_WRAP;
+       Font *font = &dc.font;
+       int frcflags = FRC_NORMAL;
+-      float runewidth = win.cw;
++      float runewidth = win.cw * ((glyphs[0].mode & ATTR_WIDE) ? 2.0f : 1.0f);
+       Rune rune;
+       FT_UInt glyphidx;
+       FcResult fcres;
        FcPattern *fcpattern, *fontpattern;
        FcFontSet *fcsets[] = { NULL };
        FcCharSet *fccharset;
 -      int i, f, numspecs = 0;
-+      int i, f, length = 0, start = 0, numspecs = 0;
++      int f, code_idx, numspecs = 0;
 +      float cluster_xp = xp, cluster_yp = yp;
 +      HbTransformData shaped = { 0 };
-+
-+      /* Initial values. */
-+      mode = prevmode = glyphs[0].mode & ~ATTR_WRAP;
-+      xresetfontsettings(mode, &font, &frcflags);
  
-       for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) {
+-      for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) {
 -              /* Fetch rune and mode for current glyph. */
 -              rune = glyphs[i].u;
 -              mode = glyphs[i].mode;
-+              mode = glyphs[i].mode & ~ATTR_WRAP;
++      /* Initial values. */
++      xresetfontsettings(mode, &font, &frcflags);
  
-               /* Skip dummy wide-character spacing. */
+-              /* Skip dummy wide-character spacing. */
 -              if (mode == ATTR_WDUMMY)
-+              if (mode & ATTR_WDUMMY && i < (len - 1))
++      /* Shape the segment. */
++      hbtransform(&shaped, font->match, glyphs, 0, len);
++      xp = winx; yp = winy + font->ascent;
++      cluster_xp = xp; cluster_yp = yp;
++
++      for (code_idx = 0; code_idx < shaped.count; code_idx++) {
++              int idx = shaped.glyphs[code_idx].cluster;
++
++              if (glyphs[idx].mode & ATTR_WDUMMY)
                        continue;
  
 -              /* Determine font for glyph if different from previous glyph. */
@@ -346,36 +395,33 @@ index bf6bbf9..96b117f 100644
 -                      } else if (mode & ATTR_BOLD) {
 -                              font = &dc.bfont;
 -                              frcflags = FRC_BOLD;
-+              if (
-+                      prevmode != mode
-+                      || ATTRCMP(glyphs[start], glyphs[i])
-+                      || selected(x + i, y) != selected(x + start, y)
-+                      || i == (len - 1)
-+              ) {
-+                      /* Handle 1-character wide segments and end of line */
-+                      length = i - start;
-+                      if (i == start) {
-+                              length = 1;
-+                      } else if (i == (len - 1)) {
-+                              length = (i - start + 1);
-                       }
+-                      }
 -                      yp = winy + font->ascent;
--              }
++              /* Advance the drawing cursor if we've moved to a new cluster */
++              if (code_idx > 0 && idx != shaped.glyphs[code_idx - 1].cluster) 
{
++                      xp += runewidth;
++                      cluster_xp = xp;
++                      cluster_yp = yp;
+               }
  
 -              if (mode & ATTR_BOXDRAW) {
--                      /* minor shoehorning: boxdraw uses only this ushort */
++              if (glyphs[idx].mode & ATTR_BOXDRAW) {
+                       /* minor shoehorning: boxdraw uses only this ushort */
 -                      glyphidx = boxdrawindex(&glyphs[i]);
 -              } else {
 -                      /* Lookup character index with default font. */
 -                      glyphidx = XftCharIndex(xw.dpy, font->match, rune);
 -              }
 -              if (glyphidx) {
--                      specs[numspecs].font = font->match;
+                       specs[numspecs].font = font->match;
 -                      specs[numspecs].glyph = glyphidx;
 -                      specs[numspecs].x = (short)xp;
 -                      specs[numspecs].y = (short)yp;
 -                      xp += runewidth;
--                      numspecs++;
++                      specs[numspecs].glyph = boxdrawindex(&glyphs[idx]);
++                      specs[numspecs].x = xp;
++                      specs[numspecs].y = yp;
+                       numspecs++;
 -                      continue;
 -              }
 -
@@ -389,126 +435,38 @@ index bf6bbf9..96b117f 100644
 -                      if (!glyphidx && frc[f].flags == frcflags
 -                                      && frc[f].unicodep == rune) {
 -                              break;
-+                      /* Shape the segment. */
-+                      hbtransform(&shaped, font->match, glyphs, start, 
length);
-+                      runewidth = win.cw * ((glyphs[start].mode & ATTR_WIDE) 
? 2.0f : 1.0f);
-+                      cluster_xp = xp; cluster_yp = yp;
-+                      for (int code_idx = 0; code_idx < shaped.count; 
code_idx++) {
-+                              int idx = shaped.glyphs[code_idx].cluster;
-+
-+                              if (glyphs[start + idx].mode & ATTR_WDUMMY)
-+                                      continue;
-+
-+                              /* Advance the drawing cursor if we've moved to 
a new cluster */
-+                              if (code_idx > 0 && idx != 
shaped.glyphs[code_idx - 1].cluster) {
-+                                      xp += runewidth;
-+                                      cluster_xp = xp;
-+                                      cluster_yp = yp;
-+                                      runewidth = win.cw * ((glyphs[start + 
idx].mode & ATTR_WIDE) ? 2.0f : 1.0f);
-+                              }
-+
-+                              if (glyphs[start + idx].mode & ATTR_BOXDRAW) {
-+                                      /* minor shoehorning: boxdraw uses only 
this ushort */
-+                                      specs[numspecs].font = font->match;
-+                                      specs[numspecs].glyph = 
boxdrawindex(&glyphs[start + idx]);
-+                                      specs[numspecs].x = xp;
-+                                      specs[numspecs].y = yp;
-+                                      numspecs++;
-+                              } else if (shaped.glyphs[code_idx].codepoint != 
0) {
-+                                      /* If symbol is found, put it into the 
specs. */
-+                                      specs[numspecs].font = font->match;
-+                                      specs[numspecs].glyph = 
shaped.glyphs[code_idx].codepoint;
-+                                      specs[numspecs].x = cluster_xp + 
(short)(shaped.positions[code_idx].x_offset / 64.);
-+                                      specs[numspecs].y = cluster_yp - 
(short)(shaped.positions[code_idx].y_offset / 64.);
-+                                      cluster_xp += 
shaped.positions[code_idx].x_advance / 64.;
-+                                      cluster_yp += 
shaped.positions[code_idx].y_advance / 64.;
-+                                      numspecs++;
-+                              } else {
-+                                      /* If it's not found, try to fetch it 
through the font cache. */
-+                                      rune = glyphs[start + idx].u;
-+                                      for (f = 0; f < frclen; f++) {
-+                                              glyphidx = XftCharIndex(xw.dpy, 
frc[f].font, rune);
-+                                              /* Everything correct. */
-+                                              if (glyphidx && frc[f].flags == 
frcflags)
-+                                                      break;
-+                                              /* We got a default font for a 
not found glyph. */
-+                                              if (!glyphidx && frc[f].flags 
== frcflags
-+                                                              && 
frc[f].unicodep == rune) {
-+                                                      break;
-+                                              }
-+                                      }
-+
-+                                      /* Nothing was found. Use fontconfig to 
find matching font. */
-+                                      if (f >= frclen) {
-+                                              if (!font->set)
-+                                                      font->set = 
FcFontSort(0, font->pattern,
-+                                                                              
                                                                 1, 0, &fcres);
-+                                              fcsets[0] = font->set;
-+
-+                                              /*
-+                                               * Nothing was found in the 
cache. Now use
-+                                               * some dozen of Fontconfig 
calls to get the
-+                                               * font for one single 
character.
-+                                               *
-+                                               * Xft and fontconfig are 
design failures.
-+                                               */
-+                                              fcpattern = 
FcPatternDuplicate(font->pattern);
-+                                              fccharset = FcCharSetCreate();
-+
-+                                              FcCharSetAddChar(fccharset, 
rune);
-+                                              FcPatternAddCharSet(fcpattern, 
FC_CHARSET,
-+                                                              fccharset);
-+                                              FcPatternAddBool(fcpattern, 
FC_SCALABLE, 1);
-+
-+                                              FcConfigSubstitute(0, fcpattern,
-+                                                              FcMatchPattern);
-+                                              FcDefaultSubstitute(fcpattern);
-+
-+                                              fontpattern = FcFontSetMatch(0, 
fcsets, 1,
-+                                                              fcpattern, 
&fcres);
-+
-+                                              /* Allocate memory for the new 
cache entry. */
-+                                              if (frclen >= frccap) {
-+                                                      frccap += 16;
-+                                                      frc = xrealloc(frc, 
frccap * sizeof(Fontcache));
-+                                              }
-+
-+                                              frc[frclen].font = 
XftFontOpenPattern(xw.dpy,
-+                                                              fontpattern);
-+                                              if (!frc[frclen].font)
-+                                                      die("XftFontOpenPattern 
failed seeking fallback font: %s
",
-+                                                              
strerror(errno));
-+                                              frc[frclen].flags = frcflags;
-+                                              frc[frclen].unicodep = rune;
-+
-+                                              glyphidx = XftCharIndex(xw.dpy, 
frc[frclen].font, rune);
-+
-+                                              f = frclen;
-+                                              frclen++;
-+
-+                                              FcPatternDestroy(fcpattern);
-+                                              FcCharSetDestroy(fccharset);
-+                                      }
-+
-+                                      specs[numspecs].font = frc[f].font;
-+                                      specs[numspecs].glyph = glyphidx;
-+                                      specs[numspecs].x = (short)xp;
-+                                      specs[numspecs].y = (short)yp;
-+                                      numspecs++;
++              } else if (shaped.glyphs[code_idx].codepoint != 0) {
++                      /* If symbol is found, put it into the specs. */
++                      specs[numspecs].font = font->match;
++                      specs[numspecs].glyph = 
shaped.glyphs[code_idx].codepoint;
++                      specs[numspecs].x = cluster_xp + 
(short)(shaped.positions[code_idx].x_offset / 64.);
++                      specs[numspecs].y = cluster_yp - 
(short)(shaped.positions[code_idx].y_offset / 64.);
++                      cluster_xp += shaped.positions[code_idx].x_advance / 
64.;
++                      cluster_yp += shaped.positions[code_idx].y_advance / 
64.;
++                      numspecs++;
++              } else {
++                      /* If it's not found, try to fetch it through the font 
cache. */
++                      rune = glyphs[idx].u;
++                      for (f = 0; f < frclen; f++) {
++                              glyphidx = XftCharIndex(xw.dpy, frc[f].font, 
rune);
++                              /* Everything correct. */
++                              if (glyphidx && frc[f].flags == frcflags)
++                                      break;
++                              /* We got a default font for a not found glyph. 
*/
++                              if (!glyphidx && frc[f].flags == frcflags
++                                              && frc[f].unicodep == rune) {
++                                      break;
 +                              }
                        }
 -              }
- 
+-
 -              /* Nothing was found. Use fontconfig to find matching font. */
 -              if (f >= frclen) {
 -                      if (!font->set)
 -                              font->set = FcFontSort(0, font->pattern,
 -                                                     1, 0, &fcres);
 -                      fcsets[0] = font->set;
-+                      /* Cleanup and get ready for next segment. */
-+                      hbcleanup(&shaped);
-+                      start = i;
- 
+-
 -                      /*
 -                       * Nothing was found in the cache. Now use
 -                       * some dozen of Fontconfig calls to get the
@@ -527,7 +485,7 @@ index bf6bbf9..96b117f 100644
 -                      FcConfigSubstitute(0, fcpattern,
 -                                      FcMatchPattern);
 -                      FcDefaultSubstitute(fcpattern);
--
+ 
 -                      fontpattern = FcFontSetMatch(0, fcsets, 1,
 -                                      fcpattern, &fcres);
 -
@@ -535,13 +493,58 @@ index bf6bbf9..96b117f 100644
 -                      if (frclen >= frccap) {
 -                              frccap += 16;
 -                              frc = xrealloc(frc, frccap * sizeof(Fontcache));
-+                      /* Determine font for glyph if different from previous 
glyph. */
-+                      if (prevmode != mode) {
-+                              prevmode = mode;
-+                              xresetfontsettings(mode, &font, &frcflags);
-+                              yp = winy + font->ascent;
++                      /* Nothing was found. Use fontconfig to find matching 
font. */
++                      if (f >= frclen) {
++                              if (!font->set)
++                                      font->set = FcFontSort(0, font->pattern,
++                                                             1, 0, &fcres);
++                              fcsets[0] = font->set;
++
++                              /*
++                               * Nothing was found in the cache. Now use
++                               * some dozen of Fontconfig calls to get the
++                               * font for one single character.
++                               *
++                               * Xft and fontconfig are design failures.
++                               */
++                              fcpattern = FcPatternDuplicate(font->pattern);
++                              fccharset = FcCharSetCreate();
++
++                              FcCharSetAddChar(fccharset, rune);
++                              FcPatternAddCharSet(fcpattern, FC_CHARSET,
++                                              fccharset);
++                              FcPatternAddBool(fcpattern, FC_SCALABLE, 1);
++
++                              FcConfigSubstitute(0, fcpattern,
++                                              FcMatchPattern);
++                              FcDefaultSubstitute(fcpattern);
++
++                              fontpattern = FcFontSetMatch(0, fcsets, 1,
++                                              fcpattern, &fcres);
++
++                              /* Allocate memory for the new cache entry. */
++                              if (frclen >= frccap) {
++                                      frccap += 16;
++                                      frc = xrealloc(frc, frccap * 
sizeof(Fontcache));
++                              }
++
++                              frc[frclen].font = XftFontOpenPattern(xw.dpy,
++                                              fontpattern);
++                              if (!frc[frclen].font)
++                                      die("XftFontOpenPattern failed seeking 
fallback font: %s
",
++                                              strerror(errno));
++                              frc[frclen].flags = frcflags;
++                              frc[frclen].unicodep = rune;
++
++                              glyphidx = XftCharIndex(xw.dpy, 
frc[frclen].font, rune);
++
++                              f = frclen;
++                              frclen++;
++
++                              FcPatternDestroy(fcpattern);
++                              FcCharSetDestroy(fccharset);
                        }
--
+ 
 -                      frc[frclen].font = XftFontOpenPattern(xw.dpy,
 -                                      fontpattern);
 -                      if (!frc[frclen].font)
@@ -557,6 +560,11 @@ index bf6bbf9..96b117f 100644
 -
 -                      FcPatternDestroy(fcpattern);
 -                      FcCharSetDestroy(fccharset);
++                      specs[numspecs].font = frc[f].font;
++                      specs[numspecs].glyph = glyphidx;
++                      specs[numspecs].x = (short)xp;
++                      specs[numspecs].y = (short)yp;
++                      numspecs++;
                }
 -
 -              specs[numspecs].font = frc[f].font;
@@ -567,6 +575,7 @@ index bf6bbf9..96b117f 100644
 -              numspecs++;
        }
  
++      /* Cleanup and get ready for next segment. */
 +      hbcleanup(&shaped);
        return numspecs;
  }
@@ -579,7 +588,9 @@ index bf6bbf9..96b117f 100644
        int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch,
            width = charlen * win.cw;
        Color *fg, *bg, *temp, revfg, revbg, truefg, truebg;
-@@ -1521,21 +1573,24 @@ void
+       XRenderColor colfg, colbg;
+@@ -1520,23 +1538,26 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, 
Glyph base, int len, int x, i
+ void
  xdrawglyph(Glyph g, int x, int y)
  {
        int numspecs;
@@ -609,7 +620,9 @@ index bf6bbf9..96b117f 100644
  
        if (IS_SET(MODE_HIDE))
                return;
-@@ -1663,18 +1718,16 @@ xdrawline(Line line, int x1, int y1, int x2)
+ 
+@@ -1668,30 +1689,30 @@ xdrawline(Line line, int x1, int y1, int x2)
+       int i, x, ox, numspecs;
        Glyph base, new;
        XftGlyphFontSpec *specs = xw.specbuf;
  
@@ -632,7 +645,8 @@ index bf6bbf9..96b117f 100644
                        i = 0;
                }
                if (i == 0) {
-@@ -1683,8 +1736,10 @@ xdrawline(Line line, int x1, int y1, int x2)
+                       ox = x;
+                       base = new;
                }
                i++;
        }
@@ -645,3 +659,4 @@ index bf6bbf9..96b117f 100644
  }
  
  void
+ xfinishdraw(void)
diff --git 
a/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-scrollback-20240427-0.9.2.diff
 
b/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-scrollback-20241226-0.9.2.diff
similarity index 71%
rename from 
st.suckless.org/patches/ligatures/0.9.2/st-ligatures-scrollback-20240427-0.9.2.diff
rename to 
st.suckless.org/patches/ligatures/0.9.2/st-ligatures-scrollback-20241226-0.9.2.diff
index 92edf9a1..86d3939f 100644
--- 
a/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-scrollback-20240427-0.9.2.diff
+++ 
b/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-scrollback-20241226-0.9.2.diff
@@ -1,8 +1,9 @@
 diff --git a/Makefile b/Makefile
-index 470ac86..38240da 100644
+index 15db421..dfcea0f 100644
 --- a/Makefile
 +++ b/Makefile
-@@ -4,7 +4,7 @@
+@@ -3,9 +3,9 @@
+ .POSIX:
  
  include config.mk
  
@@ -11,7 +12,9 @@ index 470ac86..38240da 100644
  OBJ = $(SRC:.c=.o)
  
  all: st
-@@ -22,7 +22,8 @@ config.h:
+ 
+@@ -15,9 +15,10 @@ config.h:
+ .c.o:
        $(CC) $(STCFLAGS) -c $<
  
  st.o: config.h st.h win.h
@@ -21,11 +24,13 @@ index 470ac86..38240da 100644
  
  $(OBJ): config.h config.mk
  
+ st: $(OBJ)
 diff --git a/config.mk b/config.mk
-index 1e306f8..3e13e53 100644
+index fdc29a7..6833b3b 100644
 --- a/config.mk
 +++ b/config.mk
-@@ -15,10 +15,12 @@ PKG_CONFIG = pkg-config
+@@ -14,12 +14,14 @@ PKG_CONFIG = pkg-config
+ 
  # includes and libs
  INCS = -I$(X11INC) \
         `$(PKG_CONFIG) --cflags fontconfig` \
@@ -40,6 +45,19 @@ index 1e306f8..3e13e53 100644
  
  # flags
  STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600
+ STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS)
+@@ -28,9 +30,10 @@ STLDFLAGS = $(LIBS) $(LDFLAGS)
+ # OpenBSD:
+ #CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 -D_BSD_SOURCE
+ #LIBS = -L$(X11LIB) -lm -lX11 -lutil -lXft \
+ #       `$(PKG_CONFIG) --libs fontconfig` \
+-#       `$(PKG_CONFIG) --libs freetype2`
++#       `$(PKG_CONFIG) --libs freetype2` \
++#       `$(PKG_CONFIG) --libs harfbuzz`
+ #MANPREFIX = ${PREFIX}/man
+ 
+ # compiler and linker
+ # CC = c99
 diff --git a/hb.c b/hb.c
 new file mode 100644
 index 0000000..99412c8
@@ -192,10 +210,11 @@ index 0000000..3b0ef44
 +void hbtransform(HbTransformData *, XftFont *, const Glyph *, int, int);
 +void hbcleanup(HbTransformData *);
 diff --git a/st.c b/st.c
-index 79ee9ba..7675db6 100644
+index 2478942..bba90d3 100644
 --- a/st.c
 +++ b/st.c
-@@ -2711,7 +2711,8 @@ draw(void)
+@@ -2729,9 +2729,10 @@ draw(void)
+ 
        drawregion(0, 0, term.col, term.row);
        if (term.scr == 0)
                xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
@@ -205,11 +224,13 @@ index 79ee9ba..7675db6 100644
        term.ocx = cx;
        term.ocy = term.c.y;
        xfinishdraw();
+       if (ocx != term.ocx || ocy != term.ocy)
 diff --git a/st.h b/st.h
 index 818a6f8..4e584b6 100644
 --- a/st.h
 +++ b/st.h
-@@ -11,7 +11,8 @@
+@@ -10,9 +10,10 @@
+ #define BETWEEN(x, a, b)      ((a) <= (x) && (x) <= (b))
  #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)
@@ -219,11 +240,13 @@ index 818a6f8..4e584b6 100644
                                (a).bg != (b).bg)
  #define TIMEDIFF(t1, t2)      ((t1.tv_sec-t2.tv_sec)*1000 + \
                                (t1.tv_nsec-t2.tv_nsec)/1E6)
+ #define MODBIT(x, set, bit)   ((set) ? ((x) |= (bit)) : ((x) &= ~(bit)))
 diff --git a/win.h b/win.h
 index 6de960d..94679e4 100644
 --- a/win.h
 +++ b/win.h
-@@ -25,7 +25,7 @@ enum win_mode {
+@@ -24,9 +24,9 @@ enum win_mode {
+ };
  
  void xbell(void);
  void xclipcopy(void);
@@ -232,11 +255,13 @@ index 6de960d..94679e4 100644
  void xdrawline(Line, int, int, int);
  void xfinishdraw(void);
  void xloadcols(void);
+ int xsetcolorname(int, const char *);
 diff --git a/x.c b/x.c
-index 2a3bd38..0bb51ff 100644
+index bd23686..2bf3b72 100644
 --- a/x.c
 +++ b/x.c
-@@ -19,6 +19,7 @@ char *argv0;
+@@ -18,8 +18,9 @@
+ char *argv0;
  #include "arg.h"
  #include "st.h"
  #include "win.h"
@@ -244,7 +269,9 @@ index 2a3bd38..0bb51ff 100644
  
  /* types used in config.h */
  typedef struct {
-@@ -141,8 +142,9 @@ typedef struct {
+       uint mod;
+@@ -140,10 +141,11 @@ typedef struct {
+       GC gc;
  } DC;
  
  static inline ushort sixd_to_16bit(int);
@@ -255,7 +282,9 @@ index 2a3bd38..0bb51ff 100644
  static void xdrawglyph(Glyph, int, int);
  static void xclear(int, int, int, int);
  static int xgeommasktogravity(int);
-@@ -757,7 +759,7 @@ xresize(int col, int row)
+ static int ximopen(Display *);
+@@ -756,9 +758,9 @@ xresize(int col, int row)
+       XftDrawChange(xw.draw, xw.buf);
        xclear(0, 0, win.w, win.h);
  
        /* resize to new width */
@@ -264,7 +293,9 @@ index 2a3bd38..0bb51ff 100644
  }
  
  ushort
-@@ -1062,6 +1064,9 @@ xunloadfont(Font *f)
+ sixd_to_16bit(int x)
+@@ -1061,8 +1063,11 @@ xunloadfont(Font *f)
+ 
  void
  xunloadfonts(void)
  {
@@ -274,7 +305,9 @@ index 2a3bd38..0bb51ff 100644
        /* Free the loaded fonts in the font cache.  */
        while (frclen > 0)
                XftFontClose(xw.dpy, frc[--frclen].font);
-@@ -1185,7 +1190,7 @@ xinit(int cols, int rows)
+ 
+@@ -1184,9 +1189,9 @@ xinit(int cols, int rows)
+       XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel);
        XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h);
  
        /* font spec buffer */
@@ -283,7 +316,9 @@ index 2a3bd38..0bb51ff 100644
  
        /* Xft rendering context */
        xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
-@@ -1239,6 +1244,22 @@ xinit(int cols, int rows)
+ 
+@@ -1238,144 +1243,155 @@ xinit(int cols, int rows)
+       if (xsel.xtarget == None)
                xsel.xtarget = XA_STRING;
  }
  
@@ -306,28 +341,42 @@ index 2a3bd38..0bb51ff 100644
  int
  xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, 
int x, int y)
  {
-@@ -1253,128 +1274,157 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const 
Glyph *glyphs, int len, int x
+       float winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, xp, 
yp;
+-      ushort mode, prevmode = USHRT_MAX;
++      ushort mode = glyphs[0].mode & ~ATTR_WRAP;
+       Font *font = &dc.font;
+       int frcflags = FRC_NORMAL;
+-      float runewidth = win.cw;
++      float runewidth = win.cw * ((glyphs[0].mode & ATTR_WIDE) ? 2.0f : 1.0f);
+       Rune rune;
+       FT_UInt glyphidx;
+       FcResult fcres;
        FcPattern *fcpattern, *fontpattern;
        FcFontSet *fcsets[] = { NULL };
        FcCharSet *fccharset;
 -      int i, f, numspecs = 0;
-+      int i, f, length = 0, start = 0, numspecs = 0;
++      int f, code_idx, numspecs = 0;
 +      float cluster_xp = xp, cluster_yp = yp;
 +      HbTransformData shaped = { 0 };
-+
-+      /* Initial values. */
-+      mode = prevmode = glyphs[0].mode & ~ATTR_WRAP;
-+      xresetfontsettings(mode, &font, &frcflags);
  
-       for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) {
+-      for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) {
 -              /* Fetch rune and mode for current glyph. */
 -              rune = glyphs[i].u;
 -              mode = glyphs[i].mode;
-+              mode = glyphs[i].mode & ~ATTR_WRAP;
++      /* Initial values. */
++      xresetfontsettings(mode, &font, &frcflags);
  
-               /* Skip dummy wide-character spacing. */
+-              /* Skip dummy wide-character spacing. */
 -              if (mode == ATTR_WDUMMY)
-+              if (mode & ATTR_WDUMMY && i < (len - 1))
++      /* Shape the segment. */
++      hbtransform(&shaped, font->match, glyphs, 0, len);
++      xp = winx; yp = winy + font->ascent;
++      cluster_xp = xp; cluster_yp = yp;
++
++      for (code_idx = 0; code_idx < shaped.count; code_idx++) {
++              int idx = shaped.glyphs[code_idx].cluster;
++
++              if (glyphs[idx].mode & ATTR_WDUMMY)
                        continue;
  
 -              /* Determine font for glyph if different from previous glyph. */
@@ -345,31 +394,31 @@ index 2a3bd38..0bb51ff 100644
 -                      } else if (mode & ATTR_BOLD) {
 -                              font = &dc.bfont;
 -                              frcflags = FRC_BOLD;
-+              if (
-+                      prevmode != mode
-+                      || ATTRCMP(glyphs[start], glyphs[i])
-+                      || selected(x + i, y) != selected(x + start, y)
-+                      || i == (len - 1)
-+              ) {
-+                      /* Handle 1-character wide segments and end of line */
-+                      length = i - start;
-+                      if (i == start) {
-+                              length = 1;
-+                      } else if (i == (len - 1)) {
-+                              length = (i - start + 1);
-                       }
+-                      }
 -                      yp = winy + font->ascent;
--              }
++              /* Advance the drawing cursor if we've moved to a new cluster */
++              if (code_idx > 0 && idx != shaped.glyphs[code_idx - 1].cluster) 
{
++                      xp += runewidth;
++                      cluster_xp = xp;
++                      cluster_yp = yp;
+               }
  
 -              /* Lookup character index with default font. */
 -              glyphidx = XftCharIndex(xw.dpy, font->match, rune);
 -              if (glyphidx) {
--                      specs[numspecs].font = font->match;
++              if (shaped.glyphs[code_idx].codepoint != 0) {
++                      /* If symbol is found, put it into the specs. */
+                       specs[numspecs].font = font->match;
 -                      specs[numspecs].glyph = glyphidx;
 -                      specs[numspecs].x = (short)xp;
 -                      specs[numspecs].y = (short)yp;
 -                      xp += runewidth;
--                      numspecs++;
++                      specs[numspecs].glyph = 
shaped.glyphs[code_idx].codepoint;
++                      specs[numspecs].x = cluster_xp + 
(short)(shaped.positions[code_idx].x_offset / 64.);
++                      specs[numspecs].y = cluster_yp - 
(short)(shaped.positions[code_idx].y_offset / 64.);
++                      cluster_xp += shaped.positions[code_idx].x_advance / 
64.;
++                      cluster_yp += shaped.positions[code_idx].y_advance / 
64.;
+                       numspecs++;
 -                      continue;
 -              }
 -
@@ -383,105 +432,18 @@ index 2a3bd38..0bb51ff 100644
 -                      if (!glyphidx && frc[f].flags == frcflags
 -                                      && frc[f].unicodep == rune) {
 -                              break;
-+                      /* Shape the segment. */
-+                      hbtransform(&shaped, font->match, glyphs, start, 
length);
-+                      runewidth = win.cw * ((glyphs[start].mode & ATTR_WIDE) 
? 2.0f : 1.0f);
-+                      cluster_xp = xp; cluster_yp = yp;
-+                      for (int code_idx = 0; code_idx < shaped.count; 
code_idx++) {
-+                              int idx = shaped.glyphs[code_idx].cluster;
-+
-+                              if (glyphs[start + idx].mode & ATTR_WDUMMY)
-+                                      continue;
-+
-+                              /* Advance the drawing cursor if we've moved to 
a new cluster */
-+                              if (code_idx > 0 && idx != 
shaped.glyphs[code_idx - 1].cluster) {
-+                                      xp += runewidth;
-+                                      cluster_xp = xp;
-+                                      cluster_yp = yp;
-+                                      runewidth = win.cw * ((glyphs[start + 
idx].mode & ATTR_WIDE) ? 2.0f : 1.0f);
-+                              }
-+
-+                              if (shaped.glyphs[code_idx].codepoint != 0) {
-+                                      /* If symbol is found, put it into the 
specs. */
-+                                      specs[numspecs].font = font->match;
-+                                      specs[numspecs].glyph = 
shaped.glyphs[code_idx].codepoint;
-+                                      specs[numspecs].x = cluster_xp + 
(short)(shaped.positions[code_idx].x_offset / 64.);
-+                                      specs[numspecs].y = cluster_yp - 
(short)(shaped.positions[code_idx].y_offset / 64.);
-+                                      cluster_xp += 
shaped.positions[code_idx].x_advance / 64.;
-+                                      cluster_yp += 
shaped.positions[code_idx].y_advance / 64.;
-+                                      numspecs++;
-+                              } else {
-+                                      /* If it's not found, try to fetch it 
through the font cache. */
-+                                      rune = glyphs[start + idx].u;
-+                                      for (f = 0; f < frclen; f++) {
-+                                              glyphidx = XftCharIndex(xw.dpy, 
frc[f].font, rune);
-+                                              /* Everything correct. */
-+                                              if (glyphidx && frc[f].flags == 
frcflags)
-+                                                      break;
-+                                              /* We got a default font for a 
not found glyph. */
-+                                              if (!glyphidx && frc[f].flags 
== frcflags
-+                                                              && 
frc[f].unicodep == rune) {
-+                                                      break;
-+                                              }
-+                                      }
-+
-+                                      /* Nothing was found. Use fontconfig to 
find matching font. */
-+                                      if (f >= frclen) {
-+                                              if (!font->set)
-+                                                      font->set = 
FcFontSort(0, font->pattern,
-+                                                                              
                                                                 1, 0, &fcres);
-+                                              fcsets[0] = font->set;
-+
-+                                              /*
-+                                               * Nothing was found in the 
cache. Now use
-+                                               * some dozen of Fontconfig 
calls to get the
-+                                               * font for one single 
character.
-+                                               *
-+                                               * Xft and fontconfig are 
design failures.
-+                                               */
-+                                              fcpattern = 
FcPatternDuplicate(font->pattern);
-+                                              fccharset = FcCharSetCreate();
-+
-+                                              FcCharSetAddChar(fccharset, 
rune);
-+                                              FcPatternAddCharSet(fcpattern, 
FC_CHARSET,
-+                                                              fccharset);
-+                                              FcPatternAddBool(fcpattern, 
FC_SCALABLE, 1);
-+
-+                                              FcConfigSubstitute(0, fcpattern,
-+                                                              FcMatchPattern);
-+                                              FcDefaultSubstitute(fcpattern);
-+
-+                                              fontpattern = FcFontSetMatch(0, 
fcsets, 1,
-+                                                              fcpattern, 
&fcres);
-+
-+                                              /* Allocate memory for the new 
cache entry. */
-+                                              if (frclen >= frccap) {
-+                                                      frccap += 16;
-+                                                      frc = xrealloc(frc, 
frccap * sizeof(Fontcache));
-+                                              }
-+
-+                                              frc[frclen].font = 
XftFontOpenPattern(xw.dpy,
-+                                                              fontpattern);
-+                                              if (!frc[frclen].font)
-+                                                      die("XftFontOpenPattern 
failed seeking fallback font: %s
",
-+                                                              
strerror(errno));
-+                                              frc[frclen].flags = frcflags;
-+                                              frc[frclen].unicodep = rune;
-+
-+                                              glyphidx = XftCharIndex(xw.dpy, 
frc[frclen].font, rune);
-+
-+                                              f = frclen;
-+                                              frclen++;
-+
-+                                              FcPatternDestroy(fcpattern);
-+                                              FcCharSetDestroy(fccharset);
-+                                      }
-+
-+                                      specs[numspecs].font = frc[f].font;
-+                                      specs[numspecs].glyph = glyphidx;
-+                                      specs[numspecs].x = (short)xp;
-+                                      specs[numspecs].y = (short)yp;
-+                                      numspecs++;
++              } else {
++                      /* If it's not found, try to fetch it through the font 
cache. */
++                      rune = glyphs[idx].u;
++                      for (f = 0; f < frclen; f++) {
++                              glyphidx = XftCharIndex(xw.dpy, frc[f].font, 
rune);
++                              /* Everything correct. */
++                              if (glyphidx && frc[f].flags == frcflags)
++                                      break;
++                              /* We got a default font for a not found glyph. 
*/
++                              if (!glyphidx && frc[f].flags == frcflags
++                                              && frc[f].unicodep == rune) {
++                                      break;
 +                              }
                        }
 -              }
@@ -492,10 +454,7 @@ index 2a3bd38..0bb51ff 100644
 -                              font->set = FcFontSort(0, font->pattern,
 -                                                     1, 0, &fcres);
 -                      fcsets[0] = font->set;
-+                      /* Cleanup and get ready for next segment. */
-+                      hbcleanup(&shaped);
-+                      start = i;
- 
+-
 -                      /*
 -                       * Nothing was found in the cache. Now use
 -                       * some dozen of Fontconfig calls to get the
@@ -522,13 +481,58 @@ index 2a3bd38..0bb51ff 100644
 -                      if (frclen >= frccap) {
 -                              frccap += 16;
 -                              frc = xrealloc(frc, frccap * sizeof(Fontcache));
-+                      /* Determine font for glyph if different from previous 
glyph. */
-+                      if (prevmode != mode) {
-+                              prevmode = mode;
-+                              xresetfontsettings(mode, &font, &frcflags);
-+                              yp = winy + font->ascent;
++                      /* Nothing was found. Use fontconfig to find matching 
font. */
++                      if (f >= frclen) {
++                              if (!font->set)
++                                      font->set = FcFontSort(0, font->pattern,
++                                                             1, 0, &fcres);
++                              fcsets[0] = font->set;
++
++                              /*
++                               * Nothing was found in the cache. Now use
++                               * some dozen of Fontconfig calls to get the
++                               * font for one single character.
++                               *
++                               * Xft and fontconfig are design failures.
++                               */
++                              fcpattern = FcPatternDuplicate(font->pattern);
++                              fccharset = FcCharSetCreate();
++
++                              FcCharSetAddChar(fccharset, rune);
++                              FcPatternAddCharSet(fcpattern, FC_CHARSET,
++                                              fccharset);
++                              FcPatternAddBool(fcpattern, FC_SCALABLE, 1);
++
++                              FcConfigSubstitute(0, fcpattern,
++                                              FcMatchPattern);
++                              FcDefaultSubstitute(fcpattern);
++
++                              fontpattern = FcFontSetMatch(0, fcsets, 1,
++                                              fcpattern, &fcres);
++
++                              /* Allocate memory for the new cache entry. */
++                              if (frclen >= frccap) {
++                                      frccap += 16;
++                                      frc = xrealloc(frc, frccap * 
sizeof(Fontcache));
++                              }
++
++                              frc[frclen].font = XftFontOpenPattern(xw.dpy,
++                                              fontpattern);
++                              if (!frc[frclen].font)
++                                      die("XftFontOpenPattern failed seeking 
fallback font: %s
",
++                                              strerror(errno));
++                              frc[frclen].flags = frcflags;
++                              frc[frclen].unicodep = rune;
++
++                              glyphidx = XftCharIndex(xw.dpy, 
frc[frclen].font, rune);
++
++                              f = frclen;
++                              frclen++;
++
++                              FcPatternDestroy(fcpattern);
++                              FcCharSetDestroy(fccharset);
                        }
--
+ 
 -                      frc[frclen].font = XftFontOpenPattern(xw.dpy,
 -                                      fontpattern);
 -                      if (!frc[frclen].font)
@@ -544,6 +548,11 @@ index 2a3bd38..0bb51ff 100644
 -
 -                      FcPatternDestroy(fcpattern);
 -                      FcCharSetDestroy(fccharset);
++                      specs[numspecs].font = frc[f].font;
++                      specs[numspecs].glyph = glyphidx;
++                      specs[numspecs].x = (short)xp;
++                      specs[numspecs].y = (short)yp;
++                      numspecs++;
                }
 -
 -              specs[numspecs].font = frc[f].font;
@@ -554,6 +563,7 @@ index 2a3bd38..0bb51ff 100644
 -              numspecs++;
        }
  
++      /* Cleanup and get ready for next segment. */
 +      hbcleanup(&shaped);
        return numspecs;
  }
@@ -566,7 +576,9 @@ index 2a3bd38..0bb51ff 100644
        int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch,
            width = charlen * win.cw;
        Color *fg, *bg, *temp, revfg, revbg, truefg, truebg;
-@@ -1510,21 +1560,24 @@ void
+       XRenderColor colfg, colbg;
+@@ -1509,23 +1525,26 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, 
Glyph base, int len, int x, i
+ void
  xdrawglyph(Glyph g, int x, int y)
  {
        int numspecs;
@@ -596,7 +608,9 @@ index 2a3bd38..0bb51ff 100644
  
        if (IS_SET(MODE_HIDE))
                return;
-@@ -1652,18 +1705,16 @@ xdrawline(Line line, int x1, int y1, int x2)
+ 
+@@ -1657,30 +1676,30 @@ xdrawline(Line line, int x1, int y1, int x2)
+       int i, x, ox, numspecs;
        Glyph base, new;
        XftGlyphFontSpec *specs = xw.specbuf;
  
@@ -619,7 +633,8 @@ index 2a3bd38..0bb51ff 100644
                        i = 0;
                }
                if (i == 0) {
-@@ -1672,8 +1723,10 @@ xdrawline(Line line, int x1, int y1, int x2)
+                       ox = x;
+                       base = new;
                }
                i++;
        }
@@ -632,3 +647,4 @@ index 2a3bd38..0bb51ff 100644
  }
  
  void
+ xfinishdraw(void)
diff --git 
a/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-scrollback-ringbuffer-20240427-0.9.2.diff
 
b/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-scrollback-ringbuffer-20241226-0.9.2.diff
similarity index 71%
rename from 
st.suckless.org/patches/ligatures/0.9.2/st-ligatures-scrollback-ringbuffer-20240427-0.9.2.diff
rename to 
st.suckless.org/patches/ligatures/0.9.2/st-ligatures-scrollback-ringbuffer-20241226-0.9.2.diff
index 26105db4..6f3fd265 100644
--- 
a/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-scrollback-ringbuffer-20240427-0.9.2.diff
+++ 
b/st.suckless.org/patches/ligatures/0.9.2/st-ligatures-scrollback-ringbuffer-20241226-0.9.2.diff
@@ -1,8 +1,9 @@
 diff --git a/Makefile b/Makefile
-index 470ac86..38240da 100644
+index 15db421..dfcea0f 100644
 --- a/Makefile
 +++ b/Makefile
-@@ -4,7 +4,7 @@
+@@ -3,9 +3,9 @@
+ .POSIX:
  
  include config.mk
  
@@ -11,7 +12,9 @@ index 470ac86..38240da 100644
  OBJ = $(SRC:.c=.o)
  
  all: st
-@@ -22,7 +22,8 @@ config.h:
+ 
+@@ -15,9 +15,10 @@ config.h:
+ .c.o:
        $(CC) $(STCFLAGS) -c $<
  
  st.o: config.h st.h win.h
@@ -21,11 +24,13 @@ index 470ac86..38240da 100644
  
  $(OBJ): config.h config.mk
  
+ st: $(OBJ)
 diff --git a/config.mk b/config.mk
-index 1e306f8..3e13e53 100644
+index fdc29a7..6833b3b 100644
 --- a/config.mk
 +++ b/config.mk
-@@ -15,10 +15,12 @@ PKG_CONFIG = pkg-config
+@@ -14,12 +14,14 @@ PKG_CONFIG = pkg-config
+ 
  # includes and libs
  INCS = -I$(X11INC) \
         `$(PKG_CONFIG) --cflags fontconfig` \
@@ -40,6 +45,19 @@ index 1e306f8..3e13e53 100644
  
  # flags
  STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600
+ STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS)
+@@ -28,9 +30,10 @@ STLDFLAGS = $(LIBS) $(LDFLAGS)
+ # OpenBSD:
+ #CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 -D_BSD_SOURCE
+ #LIBS = -L$(X11LIB) -lm -lX11 -lutil -lXft \
+ #       `$(PKG_CONFIG) --libs fontconfig` \
+-#       `$(PKG_CONFIG) --libs freetype2`
++#       `$(PKG_CONFIG) --libs freetype2` \
++#       `$(PKG_CONFIG) --libs harfbuzz`
+ #MANPREFIX = ${PREFIX}/man
+ 
+ # compiler and linker
+ # CC = c99
 diff --git a/hb.c b/hb.c
 new file mode 100644
 index 0000000..99412c8
@@ -192,10 +210,11 @@ index 0000000..3b0ef44
 +void hbtransform(HbTransformData *, XftFont *, const Glyph *, int, int);
 +void hbcleanup(HbTransformData *);
 diff --git a/st.c b/st.c
-index c44797b..91f54dc 100644
+index d9b163e..fbca4ba 100644
 --- a/st.c
 +++ b/st.c
-@@ -2759,7 +2759,8 @@ draw(void)
+@@ -2777,9 +2777,10 @@ draw(void)
+ 
        drawregion(0, 0, term.col, term.row);
        if (TSCREEN.off == 0)
                xdrawcursor(cx, term.c.y, TLINE(term.c.y)[cx],
@@ -205,11 +224,13 @@ index c44797b..91f54dc 100644
        term.ocx = cx;
        term.ocy = term.c.y;
        xfinishdraw();
+       if (ocx != term.ocx || ocy != term.ocy)
 diff --git a/st.h b/st.h
 index 3cea73b..709a369 100644
 --- a/st.h
 +++ b/st.h
-@@ -11,7 +11,8 @@
+@@ -10,9 +10,10 @@
+ #define BETWEEN(x, a, b)      ((a) <= (x) && (x) <= (b))
  #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)
@@ -219,11 +240,13 @@ index 3cea73b..709a369 100644
                                (a).bg != (b).bg)
  #define TIMEDIFF(t1, t2)      ((t1.tv_sec-t2.tv_sec)*1000 + \
                                (t1.tv_nsec-t2.tv_nsec)/1E6)
+ #define MODBIT(x, set, bit)   ((set) ? ((x) |= (bit)) : ((x) &= ~(bit)))
 diff --git a/win.h b/win.h
 index 6de960d..94679e4 100644
 --- a/win.h
 +++ b/win.h
-@@ -25,7 +25,7 @@ enum win_mode {
+@@ -24,9 +24,9 @@ enum win_mode {
+ };
  
  void xbell(void);
  void xclipcopy(void);
@@ -232,11 +255,13 @@ index 6de960d..94679e4 100644
  void xdrawline(Line, int, int, int);
  void xfinishdraw(void);
  void xloadcols(void);
+ int xsetcolorname(int, const char *);
 diff --git a/x.c b/x.c
-index 9891e91..7d42790 100644
+index 25785a6..16d7a3a 100644
 --- a/x.c
 +++ b/x.c
-@@ -19,6 +19,7 @@ char *argv0;
+@@ -18,8 +18,9 @@
+ char *argv0;
  #include "arg.h"
  #include "st.h"
  #include "win.h"
@@ -244,7 +269,9 @@ index 9891e91..7d42790 100644
  
  /* types used in config.h */
  typedef struct {
-@@ -143,8 +144,9 @@ typedef struct {
+       uint mod;
+@@ -142,10 +143,11 @@ typedef struct {
+       GC gc;
  } DC;
  
  static inline ushort sixd_to_16bit(int);
@@ -255,7 +282,9 @@ index 9891e91..7d42790 100644
  static void xdrawglyph(Glyph, int, int);
  static void xclear(int, int, int, int);
  static int xgeommasktogravity(int);
-@@ -759,7 +761,7 @@ xresize(int col, int row)
+ static int ximopen(Display *);
+@@ -758,9 +760,9 @@ xresize(int col, int row)
+       XftDrawChange(xw.draw, xw.buf);
        xclear(0, 0, win.w, win.h);
  
        /* resize to new width */
@@ -264,7 +293,9 @@ index 9891e91..7d42790 100644
  }
  
  ushort
-@@ -1064,6 +1066,9 @@ xunloadfont(Font *f)
+ sixd_to_16bit(int x)
+@@ -1063,8 +1065,11 @@ xunloadfont(Font *f)
+ 
  void
  xunloadfonts(void)
  {
@@ -274,7 +305,9 @@ index 9891e91..7d42790 100644
        /* Free the loaded fonts in the font cache.  */
        while (frclen > 0)
                XftFontClose(xw.dpy, frc[--frclen].font);
-@@ -1187,7 +1192,7 @@ xinit(int cols, int rows)
+ 
+@@ -1186,9 +1191,9 @@ xinit(int cols, int rows)
+       XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel);
        XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h);
  
        /* font spec buffer */
@@ -283,7 +316,9 @@ index 9891e91..7d42790 100644
  
        /* Xft rendering context */
        xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
-@@ -1241,6 +1246,22 @@ xinit(int cols, int rows)
+ 
+@@ -1240,144 +1245,155 @@ xinit(int cols, int rows)
+       if (xsel.xtarget == None)
                xsel.xtarget = XA_STRING;
  }
  
@@ -306,28 +341,42 @@ index 9891e91..7d42790 100644
  int
  xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, 
int x, int y)
  {
-@@ -1255,128 +1276,156 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const 
Glyph *glyphs, int len, int x
+       float winx = borderpx + x * win.cw, winy = borderpx + y * win.ch, xp, 
yp;
+-      ushort mode, prevmode = USHRT_MAX;
++      ushort mode = glyphs[0].mode & ~ATTR_WRAP;
+       Font *font = &dc.font;
+       int frcflags = FRC_NORMAL;
+-      float runewidth = win.cw;
++      float runewidth = win.cw * ((glyphs[0].mode & ATTR_WIDE) ? 2.0f : 1.0f);
+       Rune rune;
+       FT_UInt glyphidx;
+       FcResult fcres;
        FcPattern *fcpattern, *fontpattern;
        FcFontSet *fcsets[] = { NULL };
        FcCharSet *fccharset;
 -      int i, f, numspecs = 0;
-+      int i, f, length = 0, start = 0, numspecs = 0;
++      int f, code_idx, numspecs = 0;
 +      float cluster_xp = xp, cluster_yp = yp;
 +      HbTransformData shaped = { 0 };
-+
-+      /* Initial values. */
-+      mode = prevmode = glyphs[0].mode & ~ATTR_WRAP;
-+      xresetfontsettings(mode, &font, &frcflags);
  
-       for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) {
+-      for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) {
 -              /* Fetch rune and mode for current glyph. */
 -              rune = glyphs[i].u;
 -              mode = glyphs[i].mode;
-+              mode = glyphs[i].mode & ~ATTR_WRAP;
++      /* Initial values. */
++      xresetfontsettings(mode, &font, &frcflags);
  
-               /* Skip dummy wide-character spacing. */
+-              /* Skip dummy wide-character spacing. */
 -              if (mode == ATTR_WDUMMY)
-+              if (mode & ATTR_WDUMMY && i < (len - 1))
++      /* Shape the segment. */
++      hbtransform(&shaped, font->match, glyphs, 0, len);
++      xp = winx; yp = winy + font->ascent;
++      cluster_xp = xp; cluster_yp = yp;
++
++      for (code_idx = 0; code_idx < shaped.count; code_idx++) {
++              int idx = shaped.glyphs[code_idx].cluster;
++
++              if (glyphs[idx].mode & ATTR_WDUMMY)
                        continue;
  
 -              /* Determine font for glyph if different from previous glyph. */
@@ -345,31 +394,31 @@ index 9891e91..7d42790 100644
 -                      } else if (mode & ATTR_BOLD) {
 -                              font = &dc.bfont;
 -                              frcflags = FRC_BOLD;
-+              if (
-+                      prevmode != mode
-+                      || ATTRCMP(glyphs[start], glyphs[i])
-+                      || selected(x + i, y) != selected(x + start, y)
-+                      || i == (len - 1)
-+              ) {
-+                      /* Handle 1-character wide segments and end of line */
-+                      length = i - start;
-+                      if (i == start) {
-+                              length = 1;
-+                      } else if (i == (len - 1)) {
-+                              length = (i - start + 1);
-                       }
+-                      }
 -                      yp = winy + font->ascent;
--              }
++              /* Advance the drawing cursor if we've moved to a new cluster */
++              if (code_idx > 0 && idx != shaped.glyphs[code_idx - 1].cluster) 
{
++                      xp += runewidth;
++                      cluster_xp = xp;
++                      cluster_yp = yp;
+               }
  
 -              /* Lookup character index with default font. */
 -              glyphidx = XftCharIndex(xw.dpy, font->match, rune);
 -              if (glyphidx) {
--                      specs[numspecs].font = font->match;
++              if (shaped.glyphs[code_idx].codepoint != 0) {
++                      /* If symbol is found, put it into the specs. */
+                       specs[numspecs].font = font->match;
 -                      specs[numspecs].glyph = glyphidx;
 -                      specs[numspecs].x = (short)xp;
 -                      specs[numspecs].y = (short)yp;
 -                      xp += runewidth;
--                      numspecs++;
++                      specs[numspecs].glyph = 
shaped.glyphs[code_idx].codepoint;
++                      specs[numspecs].x = cluster_xp + 
(short)(shaped.positions[code_idx].x_offset / 64.);
++                      specs[numspecs].y = cluster_yp - 
(short)(shaped.positions[code_idx].y_offset / 64.);
++                      cluster_xp += shaped.positions[code_idx].x_advance / 
64.;
++                      cluster_yp += shaped.positions[code_idx].y_advance / 
64.;
+                       numspecs++;
 -                      continue;
 -              }
 -
@@ -383,105 +432,18 @@ index 9891e91..7d42790 100644
 -                      if (!glyphidx && frc[f].flags == frcflags
 -                                      && frc[f].unicodep == rune) {
 -                              break;
-+                      /* Shape the segment. */
-+                      hbtransform(&shaped, font->match, glyphs, start, 
length);
-+                      runewidth = win.cw * ((glyphs[start].mode & ATTR_WIDE) 
? 2.0f : 1.0f);
-+                      cluster_xp = xp; cluster_yp = yp;
-+                      for (int code_idx = 0; code_idx < shaped.count; 
code_idx++) {
-+                              int idx = shaped.glyphs[code_idx].cluster;
-+
-+                              if (glyphs[start + idx].mode & ATTR_WDUMMY)
-+                                      continue;
-+
-+                              /* Advance the drawing cursor if we've moved to 
a new cluster */
-+                              if (code_idx > 0 && idx != 
shaped.glyphs[code_idx - 1].cluster) {
-+                                      xp += runewidth;
-+                                      cluster_xp = xp;
-+                                      cluster_yp = yp;
-+                                      runewidth = win.cw * ((glyphs[start + 
idx].mode & ATTR_WIDE) ? 2.0f : 1.0f);
-+                              }
-+
-+                              if (shaped.glyphs[code_idx].codepoint != 0) {
-+                                      /* If symbol is found, put it into the 
specs. */
-+                                      specs[numspecs].font = font->match;
-+                                      specs[numspecs].glyph = 
shaped.glyphs[code_idx].codepoint;
-+                                      specs[numspecs].x = cluster_xp + 
(short)(shaped.positions[code_idx].x_offset / 64.);
-+                                      specs[numspecs].y = cluster_yp - 
(short)(shaped.positions[code_idx].y_offset / 64.);
-+                                      cluster_xp += 
shaped.positions[code_idx].x_advance / 64.;
-+                                      cluster_yp += 
shaped.positions[code_idx].y_advance / 64.;
-+                                      numspecs++;
-+                              } else {
-+                                      /* If it's not found, try to fetch it 
through the font cache. */
-+                                      rune = glyphs[start + idx].u;
-+                                      for (f = 0; f < frclen; f++) {
-+                                              glyphidx = XftCharIndex(xw.dpy, 
frc[f].font, rune);
-+                                              /* Everything correct. */
-+                                              if (glyphidx && frc[f].flags == 
frcflags)
-+                                                      break;
-+                                              /* We got a default font for a 
not found glyph. */
-+                                              if (!glyphidx && frc[f].flags 
== frcflags
-+                                                              && 
frc[f].unicodep == rune) {
-+                                                      break;
-+                                              }
-+                                      }
-+
-+                                      /* Nothing was found. Use fontconfig to 
find matching font. */
-+                                      if (f >= frclen) {
-+                                              if (!font->set)
-+                                                      font->set = 
FcFontSort(0, font->pattern,
-+                                                                              
                                                                 1, 0, &fcres);
-+                                              fcsets[0] = font->set;
-+
-+                                              /*
-+                                               * Nothing was found in the 
cache. Now use
-+                                               * some dozen of Fontconfig 
calls to get the
-+                                               * font for one single 
character.
-+                                               *
-+                                               * Xft and fontconfig are 
design failures.
-+                                               */
-+                                              fcpattern = 
FcPatternDuplicate(font->pattern);
-+                                              fccharset = FcCharSetCreate();
-+
-+                                              FcCharSetAddChar(fccharset, 
rune);
-+                                              FcPatternAddCharSet(fcpattern, 
FC_CHARSET,
-+                                                              fccharset);
-+                                              FcPatternAddBool(fcpattern, 
FC_SCALABLE, 1);
-+
-+                                              FcConfigSubstitute(0, fcpattern,
-+                                                              FcMatchPattern);
-+                                              FcDefaultSubstitute(fcpattern);
-+
-+                                              fontpattern = FcFontSetMatch(0, 
fcsets, 1,
-+                                                              fcpattern, 
&fcres);
-+
-+                                              /* Allocate memory for the new 
cache entry. */
-+                                              if (frclen >= frccap) {
-+                                                      frccap += 16;
-+                                                      frc = xrealloc(frc, 
frccap * sizeof(Fontcache));
-+                                              }
-+
-+                                              frc[frclen].font = 
XftFontOpenPattern(xw.dpy,
-+                                                              fontpattern);
-+                                              if (!frc[frclen].font)
-+                                                      die("XftFontOpenPattern 
failed seeking fallback font: %s
",
-+                                                              
strerror(errno));
-+                                              frc[frclen].flags = frcflags;
-+                                              frc[frclen].unicodep = rune;
-+
-+                                              glyphidx = XftCharIndex(xw.dpy, 
frc[frclen].font, rune);
-+
-+                                              f = frclen;
-+                                              frclen++;
-+
-+                                              FcPatternDestroy(fcpattern);
-+                                              FcCharSetDestroy(fccharset);
-+                                      }
-+
-+                                      specs[numspecs].font = frc[f].font;
-+                                      specs[numspecs].glyph = glyphidx;
-+                                      specs[numspecs].x = (short)xp;
-+                                      specs[numspecs].y = (short)yp;
-+                                      numspecs++;
++              } else {
++                      /* If it's not found, try to fetch it through the font 
cache. */
++                      rune = glyphs[idx].u;
++                      for (f = 0; f < frclen; f++) {
++                              glyphidx = XftCharIndex(xw.dpy, frc[f].font, 
rune);
++                              /* Everything correct. */
++                              if (glyphidx && frc[f].flags == frcflags)
++                                      break;
++                              /* We got a default font for a not found glyph. 
*/
++                              if (!glyphidx && frc[f].flags == frcflags
++                                              && frc[f].unicodep == rune) {
++                                      break;
 +                              }
                        }
 -              }
@@ -492,10 +454,7 @@ index 9891e91..7d42790 100644
 -                              font->set = FcFontSort(0, font->pattern,
 -                                                     1, 0, &fcres);
 -                      fcsets[0] = font->set;
-+                      /* Cleanup and get ready for next segment. */
-+                      hbcleanup(&shaped);
-+                      start = i;
- 
+-
 -                      /*
 -                       * Nothing was found in the cache. Now use
 -                       * some dozen of Fontconfig calls to get the
@@ -522,13 +481,58 @@ index 9891e91..7d42790 100644
 -                      if (frclen >= frccap) {
 -                              frccap += 16;
 -                              frc = xrealloc(frc, frccap * sizeof(Fontcache));
-+                      /* Determine font for glyph if different from previous 
glyph. */
-+                      if (prevmode != mode) {
-+                              prevmode = mode;
-+                              xresetfontsettings(mode, &font, &frcflags);
-+                              yp = winy + font->ascent;
++                      /* Nothing was found. Use fontconfig to find matching 
font. */
++                      if (f >= frclen) {
++                              if (!font->set)
++                                      font->set = FcFontSort(0, font->pattern,
++                                                             1, 0, &fcres);
++                              fcsets[0] = font->set;
++
++                              /*
++                               * Nothing was found in the cache. Now use
++                               * some dozen of Fontconfig calls to get the
++                               * font for one single character.
++                               *
++                               * Xft and fontconfig are design failures.
++                               */
++                              fcpattern = FcPatternDuplicate(font->pattern);
++                              fccharset = FcCharSetCreate();
++
++                              FcCharSetAddChar(fccharset, rune);
++                              FcPatternAddCharSet(fcpattern, FC_CHARSET,
++                                              fccharset);
++                              FcPatternAddBool(fcpattern, FC_SCALABLE, 1);
++
++                              FcConfigSubstitute(0, fcpattern,
++                                              FcMatchPattern);
++                              FcDefaultSubstitute(fcpattern);
++
++                              fontpattern = FcFontSetMatch(0, fcsets, 1,
++                                              fcpattern, &fcres);
++
++                              /* Allocate memory for the new cache entry. */
++                              if (frclen >= frccap) {
++                                      frccap += 16;
++                                      frc = xrealloc(frc, frccap * 
sizeof(Fontcache));
++                              }
++
++                              frc[frclen].font = XftFontOpenPattern(xw.dpy,
++                                              fontpattern);
++                              if (!frc[frclen].font)
++                                      die("XftFontOpenPattern failed seeking 
fallback font: %s
",
++                                              strerror(errno));
++                              frc[frclen].flags = frcflags;
++                              frc[frclen].unicodep = rune;
++
++                              glyphidx = XftCharIndex(xw.dpy, 
frc[frclen].font, rune);
++
++                              f = frclen;
++                              frclen++;
++
++                              FcPatternDestroy(fcpattern);
++                              FcCharSetDestroy(fccharset);
                        }
--
+ 
 -                      frc[frclen].font = XftFontOpenPattern(xw.dpy,
 -                                      fontpattern);
 -                      if (!frc[frclen].font)
@@ -544,6 +548,11 @@ index 9891e91..7d42790 100644
 -
 -                      FcPatternDestroy(fcpattern);
 -                      FcCharSetDestroy(fccharset);
++                      specs[numspecs].font = frc[f].font;
++                      specs[numspecs].glyph = glyphidx;
++                      specs[numspecs].x = (short)xp;
++                      specs[numspecs].y = (short)yp;
++                      numspecs++;
                }
 -
 -              specs[numspecs].font = frc[f].font;
@@ -554,6 +563,8 @@ index 9891e91..7d42790 100644
 -              numspecs++;
        }
  
++      /* Cleanup and get ready for next segment. */
++      hbcleanup(&shaped);
        return numspecs;
  }
  
@@ -565,7 +576,9 @@ index 9891e91..7d42790 100644
        int winx = borderpx + x * win.cw, winy = borderpx + y * win.ch,
            width = charlen * win.cw;
        Color *fg, *bg, *temp, revfg, revbg, truefg, truebg;
-@@ -1512,21 +1561,24 @@ void
+       XRenderColor colfg, colbg;
+@@ -1511,23 +1527,26 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, 
Glyph base, int len, int x, i
+ void
  xdrawglyph(Glyph g, int x, int y)
  {
        int numspecs;
@@ -595,7 +608,9 @@ index 9891e91..7d42790 100644
  
        if (IS_SET(MODE_HIDE))
                return;
-@@ -1654,18 +1706,16 @@ xdrawline(Line line, int x1, int y1, int x2)
+ 
+@@ -1659,30 +1678,30 @@ xdrawline(Line line, int x1, int y1, int x2)
+       int i, x, ox, numspecs;
        Glyph base, new;
        XftGlyphFontSpec *specs = xw.specbuf;
  
@@ -618,7 +633,8 @@ index 9891e91..7d42790 100644
                        i = 0;
                }
                if (i == 0) {
-@@ -1674,8 +1724,10 @@ xdrawline(Line line, int x1, int y1, int x2)
+                       ox = x;
+                       base = new;
                }
                i++;
        }
@@ -631,3 +647,4 @@ index 9891e91..7d42790 100644
  }
  
  void
+ xfinishdraw(void)
diff --git a/st.suckless.org/patches/ligatures/index.md 
b/st.suckless.org/patches/ligatures/index.md
index 3734a433..14f506cb 100644
--- a/st.suckless.org/patches/ligatures/index.md
+++ b/st.suckless.org/patches/ligatures/index.md
@@ -28,13 +28,13 @@ Boxdraw
 Download
 --------
 **0.9.2**:
-* [st-ligatures-0.9.2](0.9.2/st-ligatures-20240427-0.9.2.diff)
-* 
[st-ligatures-scrollback-0.9.2](0.9.2/st-ligatures-scrollback-20240427-0.9.2.diff)
-* 
[st-ligatures-scrollback-ringbuffer-0.9.2](0.9.2/st-ligatures-scrollback-ringbuffer-20240427-0.9.2.diff)
-* [st-ligatures-alpha-0.9.2](0.9.2/st-ligatures-alpha-20240427-0.9.2.diff)
-* 
[st-ligatures-alpha-scrollback-0.9.2](0.9.2/st-ligatures-alpha-scrollback-20240427-0.9.2.diff)
-* 
[st-ligatures-alpha-scrollback-ringbuffer-0.9.2](0.9.2/st-ligatures-alpha-scrollback-ringbuffer-20240427-0.9.2.diff)
-* [st-ligatures-boxdraw-0.9.2](0.9.2/st-ligatures-boxdraw-20240427-0.9.2.diff)
+* [st-ligatures-0.9.2](0.9.2/st-ligatures-20241226-0.9.2.diff)
+* 
[st-ligatures-scrollback-0.9.2](0.9.2/st-ligatures-scrollback-20241226-0.9.2.diff)
+* 
[st-ligatures-scrollback-ringbuffer-0.9.2](0.9.2/st-ligatures-scrollback-ringbuffer-20241226-0.9.2.diff)
+* [st-ligatures-alpha-0.9.2](0.9.2/st-ligatures-alpha-20241226-0.9.2.diff)
+* 
[st-ligatures-alpha-scrollback-0.9.2](0.9.2/st-ligatures-alpha-scrollback-20241226-0.9.2.diff)
+* 
[st-ligatures-alpha-scrollback-ringbuffer-0.9.2](0.9.2/st-ligatures-alpha-scrollback-ringbuffer-20241226-0.9.2.diff)
+* [st-ligatures-boxdraw-0.9.2](0.9.2/st-ligatures-boxdraw-20241226-0.9.2.diff)
 
 **0.9**:
 * [st-ligatures-0.9](0.9/st-ligatures-20240105-0.9.diff)


Reply via email to