This patch adds bidirectional text (BiDi) support to st
using the GNU FriBidi library.
RTL languages such as Arabic, Hebrew, and Farsi are now
displayed correctly. Mixed LTR/RTL text is also handled.
Please add it to st.suckless.org/patches/bidi/
Bidirectional Text (BiDi)
=========================
Description
-----------
This patch adds proper support for Right-To-Left languages such as
Arabic, Hebrew, and Farsi. Texts combining both RTL and LTR languages
are displayed correctly.
This is achieved using the GNU FriBiDi library, which is an additional
dependency for this patch.
The reordering is applied in xdrawline() via fribidi_log2vis() before
glyphs are rendered.
without st-bidi:

with st-bidi:

Download
--------
* [st-bidi-20260507-688f70a.diff](st-bidi-20260507-688f70a.diff)
Authors
-------
* Mohamed Abdelrazeq - <[email protected]>
EOF
diff --git a/config.mk b/config.mk
index 2fc854e..f2a80f7 100644
--- a/config.mk
+++ b/config.mk
@@ -15,10 +15,12 @@ PKG_CONFIG = pkg-config
# includes and libs
INCS = -I$(X11INC) \
`$(PKG_CONFIG) --cflags fontconfig` \
- `$(PKG_CONFIG) --cflags freetype2`
+ `$(PKG_CONFIG) --cflags freetype2` \
+ `$(PKG_CONFIG) --cflags fribidi`
LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft \
`$(PKG_CONFIG) --libs fontconfig` \
- `$(PKG_CONFIG) --libs freetype2`
+ `$(PKG_CONFIG) --libs freetype2` \
+ `$(PKG_CONFIG) --libs fribidi`
# flags
STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600
diff --git a/st.c b/st.c
index 6f40e35..3e826c7 100644
--- a/st.c
+++ b/st.c
@@ -2703,3 +2703,4 @@ redraw(void)
tfulldirt();
draw();
}
+
diff --git a/st.h b/st.h
index fd3b0d8..a7d5a37 100644
--- a/st.h
+++ b/st.h
@@ -2,7 +2,7 @@
#include <stdint.h>
#include <sys/types.h>
-
+#include <fribidi.h>
/* macros */
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) < (b) ? (b) : (a))
diff --git a/x.c b/x.c
index d73152b..ae5bfc5 100644
--- a/x.c
+++ b/x.c
@@ -19,7 +19,7 @@ char *argv0;
#include "arg.h"
#include "st.h"
#include "win.h"
-
+#include <fribidi.h>
/* types used in config.h */
typedef struct {
uint mod;
@@ -1657,14 +1657,33 @@ xstartdraw(void)
void
xdrawline(Line line, int x1, int y1, int x2)
{
- int i, x, ox, numspecs;
+ int i, x, ox, numspecs, len;
Glyph base, new;
XftGlyphFontSpec *specs = xw.specbuf;
- numspecs = xmakeglyphfontspecs(specs, &line[x1], x2 - x1, x1, y1);
+ /* BiDi reordering */
+ len = x2 - x1;
+ FriBidiChar fribidi_src[len], fribidi_dst[len];
+ FriBidiParType base_dir = FRIBIDI_PAR_ON;
+ FriBidiLevel *embedding_levels = NULL;
+
+ for (i = 0; i < len; i++)
+ fribidi_src[i] = (FriBidiChar)line[x1 + i].u;
+
+ fribidi_log2vis(fribidi_src, len, &base_dir,
+ fribidi_dst, NULL, NULL, NULL);
+
+ /* Copy reordered codepoints back into a temporary line */
+ Glyph bidi_line[len];
+ for (i = 0; i < len; i++) {
+ bidi_line[i] = line[x1 + i];
+ bidi_line[i].u = (Rune)fribidi_dst[i];
+ }
+
+ numspecs = xmakeglyphfontspecs(specs, bidi_line, len, x1, y1);
i = ox = 0;
for (x = x1; x < x2 && i < numspecs; x++) {
- new = line[x];
+ new = bidi_line[x - x1];
if (new.mode == ATTR_WDUMMY)
continue;
if (selected(x, y1))