--
+
- frc[frclen].font = XftFontOpenPattern(xw.dpy,
- fontpattern);
- if (!frc[frclen].font)
_AT_@ -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;
_AT_@ -554,6 +563,8 @@ index 2a3bd38..66605ae 100644
- numspecs++;
}
++ /* Cleanup and get ready for next segment. */
++ hbcleanup(&shaped);
return numspecs;
}
_AT_@ -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;
-_AT_@ -1510,21 +1559,24 @@ void
+ XRenderColor colfg, colbg;
+_AT_@ -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;
_AT_@ -595,7 +608,9 @@ index 2a3bd38..66605ae 100644
if (IS_SET(MODE_HIDE))
return;
-_AT_@ -1652,18 +1704,16 @@ xdrawline(Line line, int x1, int y1, int x2)
+
+_AT_@ -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;
_AT_@ -618,7 +633,8 @@ index 2a3bd38..66605ae 100644
i = 0;
}
if (i == 0) {
-_AT_@ -1672,8 +1722,10 @@ xdrawline(Line line, int x1, int y1, int x2)
+ ox = x;
+ base = new;
}
i++;
}
_AT_@ -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
_AT_@ -1,8 +1,9 @@
diff --git a/Makefile b/Makefile
-index 470ac86..38240da 100644
+index 15db421..dfcea0f 100644
--- a/Makefile
+++ b/Makefile
-_AT_@ -4,7 +4,7 @@
+_AT_@ -3,9 +3,9 @@
+ .POSIX:
include config.mk
_AT_@ -11,7 +12,9 @@ index 470ac86..38240da 100644
OBJ = $(SRC:.c=.o)
all: st
-_AT_@ -22,7 +22,8 @@ config.h:
+
+_AT_@ -15,9 +15,10 @@ config.h:
+ .c.o:
$(CC) $(STCFLAGS) -c $<
st.o: config.h st.h win.h
_AT_@ -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
-_AT_@ -15,10 +15,12 @@ PKG_CONFIG = pkg-config
+_AT_@ -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` \
_AT_@ -41,9 +45,22 @@ index 47c615e..d7439a3 100644
# flags
STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600
+ STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS)
+_AT_@ -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
_AT_@ -0,0 +1,125 @@
_AT_@ -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
-_AT_@ -2640,7 +2640,8 @@ draw(void)
+_AT_@ -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],
_AT_@ -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
-_AT_@ -11,7 +11,8 @@
+_AT_@ -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)
_AT_@ -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
-_AT_@ -25,7 +25,7 @@ enum win_mode {
+_AT_@ -24,9 +24,9 @@ enum win_mode {
+ };
void xbell(void);
void xclipcopy(void);
_AT_@ -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
-_AT_@ -19,6 +19,7 @@ char *argv0;
+_AT_@ -18,8 +18,9 @@
+ char *argv0;
#include "arg.h"
#include "st.h"
#include "win.h"
_AT_@ -245,7 +269,9 @@ index 27e81d1..0632636 100644
/* types used in config.h */
typedef struct {
-_AT_@ -142,8 +143,9 @@ typedef struct {
+ uint mod;
+_AT_@ -141,10 +142,11 @@ typedef struct {
+ GC gc;
} DC;
static inline ushort sixd_to_16bit(int);
_AT_@ -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);
-_AT_@ -759,7 +761,7 @@ xresize(int col, int row)
+ static int ximopen(Display *);
+_AT_@ -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 */
_AT_@ -265,7 +293,9 @@ index 27e81d1..0632636 100644
}
ushort
-_AT_@ -1071,6 +1073,9 @@ xunloadfont(Font *f)
+ sixd_to_16bit(int x)
+_AT_@ -1070,8 +1072,11 @@ xunloadfont(Font *f)
+
void
xunloadfonts(void)
{
_AT_@ -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);
-_AT_@ -1202,7 +1207,7 @@ xinit(int cols, int rows)
+
+_AT_@ -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 */
_AT_@ -284,7 +316,9 @@ index 27e81d1..0632636 100644
/* Xft rendering context */
xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
-_AT_@ -1256,6 +1261,22 @@ xinit(int cols, int rows)
+
+_AT_@ -1255,144 +1260,155 @@ xinit(int cols, int rows)
+ if (xsel.xtarget == None)
xsel.xtarget = XA_STRING;
}
_AT_@ -307,28 +341,42 @@ index 27e81d1..0632636 100644
int
xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y)
{
-_AT_@ -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. */
_AT_@ -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;
- }
-
_AT_@ -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;
+ }
}
- }
_AT_@ -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
_AT_@ -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)
_AT_@ -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;
_AT_@ -555,6 +563,7 @@ index 27e81d1..0632636 100644
- numspecs++;
}
++ /* Cleanup and get ready for next segment. */
+ hbcleanup(&shaped);
return numspecs;
}
_AT_@ -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;
-_AT_@ -1527,21 +1577,24 @@ void
+ XRenderColor colfg, colbg;
+_AT_@ -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;
_AT_@ -597,7 +608,9 @@ index 27e81d1..0632636 100644
if (IS_SET(MODE_HIDE))
return;
-_AT_@ -1669,18 +1722,16 @@ xdrawline(Line line, int x1, int y1, int x2)
+
+_AT_@ -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;
_AT_@ -620,7 +633,8 @@ index 27e81d1..0632636 100644
i = 0;
}
if (i == 0) {
-_AT_@ -1689,8 +1740,10 @@ xdrawline(Line line, int x1, int y1, int x2)
+ ox = x;
+ base = new;
}
i++;
}
_AT_@ -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
_AT_@ -1,8 +1,9 @@
diff --git a/Makefile b/Makefile
-index 470ac86..38240da 100644
+index 15db421..dfcea0f 100644
--- a/Makefile
+++ b/Makefile
-_AT_@ -4,7 +4,7 @@
+_AT_@ -3,9 +3,9 @@
+ .POSIX:
include config.mk
_AT_@ -11,7 +12,9 @@ index 470ac86..38240da 100644
OBJ = $(SRC:.c=.o)
all: st
-_AT_@ -22,7 +22,8 @@ config.h:
+
+_AT_@ -15,9 +15,10 @@ config.h:
+ .c.o:
$(CC) $(STCFLAGS) -c $<
st.o: config.h st.h win.h
_AT_@ -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
-_AT_@ -15,10 +15,12 @@ PKG_CONFIG = pkg-config
+_AT_@ -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` \
_AT_@ -41,6 +45,19 @@ index 47c615e..d7439a3 100644
# flags
STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600
+ STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS)
+_AT_@ -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
_AT_@ -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
-_AT_@ -2711,7 +2711,9 @@ draw(void)
+_AT_@ -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
-_AT_@ -11,7 +11,8 @@
+_AT_@ -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)
_AT_@ -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
-_AT_@ -25,7 +25,7 @@ enum win_mode {
+_AT_@ -24,9 +24,9 @@ enum win_mode {
+ };
void xbell(void);
void xclipcopy(void);
_AT_@ -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
-_AT_@ -19,6 +19,7 @@ char *argv0;
+_AT_@ -18,8 +18,9 @@
+ char *argv0;
#include "arg.h"
#include "st.h"
#include "win.h"
_AT_@ -246,7 +269,9 @@ index 27e81d1..5e11c1f 100644
/* types used in config.h */
typedef struct {
-_AT_@ -142,8 +143,9 @@ typedef struct {
+ uint mod;
+_AT_@ -141,10 +142,11 @@ typedef struct {
+ GC gc;
} DC;
static inline ushort sixd_to_16bit(int);
_AT_@ -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);
-_AT_@ -759,7 +761,7 @@ xresize(int col, int row)
+ static int ximopen(Display *);
+_AT_@ -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 */
_AT_@ -266,7 +293,9 @@ index 27e81d1..5e11c1f 100644
}
ushort
-_AT_@ -1071,6 +1073,9 @@ xunloadfont(Font *f)
+ sixd_to_16bit(int x)
+_AT_@ -1070,8 +1072,11 @@ xunloadfont(Font *f)
+
void
xunloadfonts(void)
{
_AT_@ -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);
-_AT_@ -1202,7 +1207,7 @@ xinit(int cols, int rows)
+
+_AT_@ -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 */
_AT_@ -285,7 +316,9 @@ index 27e81d1..5e11c1f 100644
/* Xft rendering context */
xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
-_AT_@ -1256,6 +1261,22 @@ xinit(int cols, int rows)
+
+_AT_@ -1255,144 +1260,155 @@ xinit(int cols, int rows)
+ if (xsel.xtarget == None)
xsel.xtarget = XA_STRING;
}
_AT_@ -308,28 +341,42 @@ index 27e81d1..5e11c1f 100644
int
xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y)
{
-_AT_@ -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. */
_AT_@ -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;
- }
-
_AT_@ -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;
+ }
}
- }
_AT_@ -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
_AT_@ -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)
_AT_@ -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;
_AT_@ -556,6 +563,8 @@ index 27e81d1..5e11c1f 100644
- numspecs++;
}
++ /* Cleanup and get ready for next segment. */
++ hbcleanup(&shaped);
return numspecs;
}
_AT_@ -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;
-_AT_@ -1527,21 +1576,24 @@ void
+ XRenderColor colfg, colbg;
+_AT_@ -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;
_AT_@ -597,7 +608,9 @@ index 27e81d1..5e11c1f 100644
if (IS_SET(MODE_HIDE))
return;
-_AT_@ -1669,18 +1721,16 @@ xdrawline(Line line, int x1, int y1, int x2)
+
+_AT_@ -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;
_AT_@ -620,7 +633,8 @@ index 27e81d1..5e11c1f 100644
i = 0;
}
if (i == 0) {
-_AT_@ -1689,8 +1739,10 @@ xdrawline(Line line, int x1, int y1, int x2)
+ ox = x;
+ base = new;
}
i++;
}
_AT_@ -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
_AT_@ -1,8 +1,9 @@
diff --git a/Makefile b/Makefile
-index 470ac86..38240da 100644
+index 15db421..dfcea0f 100644
--- a/Makefile
+++ b/Makefile
-_AT_@ -4,7 +4,7 @@
+_AT_@ -3,9 +3,9 @@
+ .POSIX:
include config.mk
_AT_@ -11,7 +12,9 @@ index 470ac86..38240da 100644
OBJ = $(SRC:.c=.o)
all: st
-_AT_@ -22,7 +22,8 @@ config.h:
+
+_AT_@ -15,9 +15,10 @@ config.h:
+ .c.o:
$(CC) $(STCFLAGS) -c $<
st.o: config.h st.h win.h
_AT_@ -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
-_AT_@ -15,10 +15,12 @@ PKG_CONFIG = pkg-config
+_AT_@ -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` \
_AT_@ -41,6 +45,19 @@ index 47c615e..d7439a3 100644
# flags
STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600
+ STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS)
+_AT_@ -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
_AT_@ -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
-_AT_@ -2759,7 +2759,9 @@ draw(void)
+_AT_@ -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
-_AT_@ -11,7 +11,8 @@
+_AT_@ -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)
_AT_@ -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
-_AT_@ -25,7 +25,7 @@ enum win_mode {
+_AT_@ -24,9 +24,9 @@ enum win_mode {
+ };
void xbell(void);
void xclipcopy(void);
_AT_@ -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
-_AT_@ -19,6 +19,7 @@ char *argv0;
+_AT_@ -18,8 +18,9 @@
+ char *argv0;
#include "arg.h"
#include "st.h"
#include "win.h"
_AT_@ -246,7 +269,9 @@ index b81f5be..c1611bb 100644
/* types used in config.h */
typedef struct {
-_AT_@ -144,8 +145,9 @@ typedef struct {
+ uint mod;
+_AT_@ -143,10 +144,11 @@ typedef struct {
+ GC gc;
} DC;
static inline ushort sixd_to_16bit(int);
_AT_@ -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);
-_AT_@ -761,7 +763,7 @@ xresize(int col, int row)
+ static int ximopen(Display *);
+_AT_@ -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 */
_AT_@ -266,7 +293,9 @@ index b81f5be..c1611bb 100644
}
ushort
-_AT_@ -1073,6 +1075,9 @@ xunloadfont(Font *f)
+ sixd_to_16bit(int x)
+_AT_@ -1072,8 +1074,11 @@ xunloadfont(Font *f)
+
void
xunloadfonts(void)
{
_AT_@ -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);
-_AT_@ -1204,7 +1209,7 @@ xinit(int cols, int rows)
+
+_AT_@ -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 */
_AT_@ -285,7 +316,9 @@ index b81f5be..c1611bb 100644
/* Xft rendering context */
xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
-_AT_@ -1258,6 +1263,22 @@ xinit(int cols, int rows)
+
+_AT_@ -1257,144 +1262,155 @@ xinit(int cols, int rows)
+ if (xsel.xtarget == None)
xsel.xtarget = XA_STRING;
}
_AT_@ -308,28 +341,42 @@ index b81f5be..c1611bb 100644
int
xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y)
{
-_AT_@ -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. */
_AT_@ -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;
- }
-
_AT_@ -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;
+ }
}
- }
_AT_@ -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
_AT_@ -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)
_AT_@ -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;
_AT_@ -556,6 +563,8 @@ index b81f5be..c1611bb 100644
- numspecs++;
}
++ /* Cleanup and get ready for next segment. */
++ hbcleanup(&shaped);
return numspecs;
}
_AT_@ -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;
-_AT_@ -1529,21 +1578,24 @@ void
+ XRenderColor colfg, colbg;
+_AT_@ -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;
_AT_@ -597,7 +608,9 @@ index b81f5be..c1611bb 100644
if (IS_SET(MODE_HIDE))
return;
-_AT_@ -1671,18 +1723,16 @@ xdrawline(Line line, int x1, int y1, int x2)
+
+_AT_@ -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;
_AT_@ -620,7 +633,8 @@ index b81f5be..c1611bb 100644
i = 0;
}
if (i == 0) {
-_AT_@ -1691,8 +1741,10 @@ xdrawline(Line line, int x1, int y1, int x2)
+ ox = x;
+ base = new;
}
i++;
}
_AT_@ -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
_AT_@ -1,8 +1,9 @@
diff --git a/Makefile b/Makefile
-index 6dfa212..adfa07a 100644
+index a64b4c2..05124bf 100644
--- a/Makefile
+++ b/Makefile
-_AT_@ -4,7 +4,7 @@
+_AT_@ -3,9 +3,9 @@
+ .POSIX:
include config.mk
_AT_@ -11,7 +12,9 @@ index 6dfa212..adfa07a 100644
OBJ = $(SRC:.c=.o)
all: st
-_AT_@ -22,8 +22,9 @@ config.h:
+
+_AT_@ -15,10 +15,11 @@ config.h:
+ .c.o:
$(CC) $(STCFLAGS) -c $<
st.o: config.h st.h win.h
_AT_@ -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
-_AT_@ -15,10 +15,12 @@ PKG_CONFIG = pkg-config
+_AT_@ -14,12 +14,14 @@ PKG_CONFIG = pkg-config
+
# includes and libs
INCS = -I$(X11INC) \
`$(PKG_CONFIG) --cflags fontconfig` \
_AT_@ -41,6 +46,19 @@ index 1e306f8..3e13e53 100644
# flags
STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600
+ STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS)
+_AT_@ -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
_AT_@ -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
-_AT_@ -2643,7 +2643,8 @@ draw(void)
+_AT_@ -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],
_AT_@ -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
-_AT_@ -11,7 +11,8 @@
+_AT_@ -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)
_AT_@ -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
-_AT_@ -25,7 +25,7 @@ enum win_mode {
+_AT_@ -24,9 +24,9 @@ enum win_mode {
+ };
void xbell(void);
void xclipcopy(void);
_AT_@ -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
-_AT_@ -19,6 +19,7 @@ char *argv0;
+_AT_@ -18,8 +18,9 @@
+ char *argv0;
#include "arg.h"
#include "st.h"
#include "win.h"
_AT_@ -245,7 +270,9 @@ index bf6bbf9..96b117f 100644
/* types used in config.h */
typedef struct {
-_AT_@ -141,8 +142,9 @@ typedef struct {
+ uint mod;
+_AT_@ -140,10 +141,11 @@ typedef struct {
+ GC gc;
} DC;
static inline ushort sixd_to_16bit(int);
_AT_@ -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);
-_AT_@ -757,7 +759,7 @@ xresize(int col, int row)
+ static int ximopen(Display *);
+_AT_@ -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 */
_AT_@ -265,7 +294,9 @@ index bf6bbf9..96b117f 100644
}
ushort
-_AT_@ -1062,6 +1064,9 @@ xunloadfont(Font *f)
+ sixd_to_16bit(int x)
+_AT_@ -1061,8 +1063,11 @@ xunloadfont(Font *f)
+
void
xunloadfonts(void)
{
_AT_@ -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);
-_AT_@ -1185,7 +1190,7 @@ xinit(int cols, int rows)
+
+_AT_@ -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 */
_AT_@ -284,7 +317,9 @@ index bf6bbf9..96b117f 100644
/* Xft rendering context */
xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
-_AT_@ -1241,6 +1246,22 @@ xinit(int cols, int rows)
+
+_AT_@ -1240,149 +1245,162 @@ xinit(int cols, int rows)
+
boxdraw_xinit(xw.dpy, xw.cmap, xw.draw, xw.vis);
}
_AT_@ -307,28 +342,42 @@ index bf6bbf9..96b117f 100644
int
xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y)
{
-_AT_@ -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. */
_AT_@ -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;
- }
-
_AT_@ -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
_AT_@ -527,7 +485,7 @@ index bf6bbf9..96b117f 100644
- FcConfigSubstitute(0, fcpattern,
- FcMatchPattern);
- FcDefaultSubstitute(fcpattern);
--
+
- fontpattern = FcFontSetMatch(0, fcsets, 1,
- fcpattern, &fcres);
-
_AT_@ -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)
_AT_@ -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;
_AT_@ -567,6 +575,7 @@ index bf6bbf9..96b117f 100644
- numspecs++;
}
++ /* Cleanup and get ready for next segment. */
+ hbcleanup(&shaped);
return numspecs;
}
_AT_@ -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;
-_AT_@ -1521,21 +1573,24 @@ void
+ XRenderColor colfg, colbg;
+_AT_@ -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;
_AT_@ -609,7 +620,9 @@ index bf6bbf9..96b117f 100644
if (IS_SET(MODE_HIDE))
return;
-_AT_@ -1663,18 +1718,16 @@ xdrawline(Line line, int x1, int y1, int x2)
+
+_AT_@ -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;
_AT_@ -632,7 +645,8 @@ index bf6bbf9..96b117f 100644
i = 0;
}
if (i == 0) {
-_AT_@ -1683,8 +1736,10 @@ xdrawline(Line line, int x1, int y1, int x2)
+ ox = x;
+ base = new;
}
i++;
}
_AT_@ -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
_AT_@ -1,8 +1,9 @@
diff --git a/Makefile b/Makefile
-index 470ac86..38240da 100644
+index 15db421..dfcea0f 100644
--- a/Makefile
+++ b/Makefile
-_AT_@ -4,7 +4,7 @@
+_AT_@ -3,9 +3,9 @@
+ .POSIX:
include config.mk
_AT_@ -11,7 +12,9 @@ index 470ac86..38240da 100644
OBJ = $(SRC:.c=.o)
all: st
-_AT_@ -22,7 +22,8 @@ config.h:
+
+_AT_@ -15,9 +15,10 @@ config.h:
+ .c.o:
$(CC) $(STCFLAGS) -c $<
st.o: config.h st.h win.h
_AT_@ -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
-_AT_@ -15,10 +15,12 @@ PKG_CONFIG = pkg-config
+_AT_@ -14,12 +14,14 @@ PKG_CONFIG = pkg-config
+
# includes and libs
INCS = -I$(X11INC) \
`$(PKG_CONFIG) --cflags fontconfig` \
_AT_@ -40,6 +45,19 @@ index 1e306f8..3e13e53 100644
# flags
STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600
+ STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS)
+_AT_@ -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
_AT_@ -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
-_AT_@ -2711,7 +2711,8 @@ draw(void)
+_AT_@ -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],
_AT_@ -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
-_AT_@ -11,7 +11,8 @@
+_AT_@ -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)
_AT_@ -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
-_AT_@ -25,7 +25,7 @@ enum win_mode {
+_AT_@ -24,9 +24,9 @@ enum win_mode {
+ };
void xbell(void);
void xclipcopy(void);
_AT_@ -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
-_AT_@ -19,6 +19,7 @@ char *argv0;
+_AT_@ -18,8 +18,9 @@
+ char *argv0;
#include "arg.h"
#include "st.h"
#include "win.h"
_AT_@ -244,7 +269,9 @@ index 2a3bd38..0bb51ff 100644
/* types used in config.h */
typedef struct {
-_AT_@ -141,8 +142,9 @@ typedef struct {
+ uint mod;
+_AT_@ -140,10 +141,11 @@ typedef struct {
+ GC gc;
} DC;
static inline ushort sixd_to_16bit(int);
_AT_@ -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);
-_AT_@ -757,7 +759,7 @@ xresize(int col, int row)
+ static int ximopen(Display *);
+_AT_@ -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 */
_AT_@ -264,7 +293,9 @@ index 2a3bd38..0bb51ff 100644
}
ushort
-_AT_@ -1062,6 +1064,9 @@ xunloadfont(Font *f)
+ sixd_to_16bit(int x)
+_AT_@ -1061,8 +1063,11 @@ xunloadfont(Font *f)
+
void
xunloadfonts(void)
{
_AT_@ -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);
-_AT_@ -1185,7 +1190,7 @@ xinit(int cols, int rows)
+
+_AT_@ -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 */
_AT_@ -283,7 +316,9 @@ index 2a3bd38..0bb51ff 100644
/* Xft rendering context */
xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
-_AT_@ -1239,6 +1244,22 @@ xinit(int cols, int rows)
+
+_AT_@ -1238,144 +1243,155 @@ xinit(int cols, int rows)
+ if (xsel.xtarget == None)
xsel.xtarget = XA_STRING;
}
_AT_@ -306,28 +341,42 @@ index 2a3bd38..0bb51ff 100644
int
xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y)
{
-_AT_@ -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. */
_AT_@ -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;
- }
-
_AT_@ -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;
+ }
}
- }
_AT_@ -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
_AT_@ -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)
_AT_@ -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;
_AT_@ -554,6 +563,7 @@ index 2a3bd38..0bb51ff 100644
- numspecs++;
}
++ /* Cleanup and get ready for next segment. */
+ hbcleanup(&shaped);
return numspecs;
}
_AT_@ -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;
-_AT_@ -1510,21 +1560,24 @@ void
+ XRenderColor colfg, colbg;
+_AT_@ -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;
_AT_@ -596,7 +608,9 @@ index 2a3bd38..0bb51ff 100644
if (IS_SET(MODE_HIDE))
return;
-_AT_@ -1652,18 +1705,16 @@ xdrawline(Line line, int x1, int y1, int x2)
+
+_AT_@ -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;
_AT_@ -619,7 +633,8 @@ index 2a3bd38..0bb51ff 100644
i = 0;
}
if (i == 0) {
-_AT_@ -1672,8 +1723,10 @@ xdrawline(Line line, int x1, int y1, int x2)
+ ox = x;
+ base = new;
}
i++;
}
_AT_@ -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
_AT_@ -1,8 +1,9 @@
diff --git a/Makefile b/Makefile
-index 470ac86..38240da 100644
+index 15db421..dfcea0f 100644
--- a/Makefile
+++ b/Makefile
-_AT_@ -4,7 +4,7 @@
+_AT_@ -3,9 +3,9 @@
+ .POSIX:
include config.mk
_AT_@ -11,7 +12,9 @@ index 470ac86..38240da 100644
OBJ = $(SRC:.c=.o)
all: st
-_AT_@ -22,7 +22,8 @@ config.h:
+
+_AT_@ -15,9 +15,10 @@ config.h:
+ .c.o:
$(CC) $(STCFLAGS) -c $<
st.o: config.h st.h win.h
_AT_@ -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
-_AT_@ -15,10 +15,12 @@ PKG_CONFIG = pkg-config
+_AT_@ -14,12 +14,14 @@ PKG_CONFIG = pkg-config
+
# includes and libs
INCS = -I$(X11INC) \
`$(PKG_CONFIG) --cflags fontconfig` \
_AT_@ -40,6 +45,19 @@ index 1e306f8..3e13e53 100644
# flags
STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600
+ STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS)
+_AT_@ -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
_AT_@ -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
-_AT_@ -2759,7 +2759,8 @@ draw(void)
+_AT_@ -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],
_AT_@ -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
-_AT_@ -11,7 +11,8 @@
+_AT_@ -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)
_AT_@ -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
-_AT_@ -25,7 +25,7 @@ enum win_mode {
+_AT_@ -24,9 +24,9 @@ enum win_mode {
+ };
void xbell(void);
void xclipcopy(void);
_AT_@ -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
-_AT_@ -19,6 +19,7 @@ char *argv0;
+_AT_@ -18,8 +18,9 @@
+ char *argv0;
#include "arg.h"
#include "st.h"
#include "win.h"
_AT_@ -244,7 +269,9 @@ index 9891e91..7d42790 100644
/* types used in config.h */
typedef struct {
-_AT_@ -143,8 +144,9 @@ typedef struct {
+ uint mod;
+_AT_@ -142,10 +143,11 @@ typedef struct {
+ GC gc;
} DC;
static inline ushort sixd_to_16bit(int);
_AT_@ -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);
-_AT_@ -759,7 +761,7 @@ xresize(int col, int row)
+ static int ximopen(Display *);
+_AT_@ -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 */
_AT_@ -264,7 +293,9 @@ index 9891e91..7d42790 100644
}
ushort
-_AT_@ -1064,6 +1066,9 @@ xunloadfont(Font *f)
+ sixd_to_16bit(int x)
+_AT_@ -1063,8 +1065,11 @@ xunloadfont(Font *f)
+
void
xunloadfonts(void)
{
_AT_@ -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);
-_AT_@ -1187,7 +1192,7 @@ xinit(int cols, int rows)
+
+_AT_@ -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 */
_AT_@ -283,7 +316,9 @@ index 9891e91..7d42790 100644
/* Xft rendering context */
xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
-_AT_@ -1241,6 +1246,22 @@ xinit(int cols, int rows)
+
+_AT_@ -1240,144 +1245,155 @@ xinit(int cols, int rows)
+ if (xsel.xtarget == None)
xsel.xtarget = XA_STRING;
}
_AT_@ -306,28 +341,42 @@ index 9891e91..7d42790 100644
int
xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y)
{
-_AT_@ -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. */
_AT_@ -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;
- }
-
_AT_@ -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;
+ }
}
- }
_AT_@ -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
_AT_@ -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)
_AT_@ -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;
_AT_@ -554,6 +563,8 @@ index 9891e91..7d42790 100644
- numspecs++;
}
++ /* Cleanup and get ready for next segment. */
++ hbcleanup(&shaped);
return numspecs;
}
_AT_@ -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;
-_AT_@ -1512,21 +1561,24 @@ void
+ XRenderColor colfg, colbg;
+_AT_@ -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;
_AT_@ -595,7 +608,9 @@ index 9891e91..7d42790 100644
if (IS_SET(MODE_HIDE))
return;
-_AT_@ -1654,18 +1706,16 @@ xdrawline(Line line, int x1, int y1, int x2)
+
+_AT_@ -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;
_AT_@ -618,7 +633,8 @@ index 9891e91..7d42790 100644
i = 0;
}
if (i == 0) {
-_AT_@ -1674,8 +1724,10 @@ xdrawline(Line line, int x1, int y1, int x2)
+ ox = x;
+ base = new;
}
i++;
}
_AT_@ -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
_AT_@ -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)
Received on Thu Jan 09 2025 - 22:55:03 CET
This archive was generated by hypermail 2.3.0 : Thu Jan 09 2025 - 23:00:56 CET