: nply/wmenu

commit baae6b1c0e2820a3e39f0dc2c1bfad4b9381dfa1
parent bfeedacdd9985196deb970d4b1405c37737ed5d2
Author: Bharatvaj Hemanth <bharatvaj@yahoo.com>
Date: Tue, 13 Oct 2026 23:05:14 +0530

Use byte-safe subsequence matching without fzy dependency
5 files changed, 31 insertions(+), 35 deletions(-)
M
HACKING
|
20
++++----------------
M
Makefile
|
18
++++++------------
D
requirements.ini
|
5
-----
M
test_stream.c
|
8
++++++++
M
wmenu.c
|
15
+++++++++++++--
diff --git a/HACKING b/HACKING
@@ -12,21 +12,9 @@ Build
 
 Dependencies
 ------------
-External source is pulled with mor from requirements.ini:
-
-    bash /path/to/mor.sh .
-
-This fetches fzy v1.1 into deps/fzy (requirements.ini pins the tag).
-For an existing checkout, remove deps/fzy before rerunning mor: mor does not
-update directories already present. The build uses only fzy's matcher:
-
-    deps/fzy/src/match.c
-    deps/fzy/src/match.h
-
-Makefile generates two tiny compatibility files inside deps/ when needed:
-
-    deps/fzy/config.h
-    deps/fzy/src/strings.h
+No external source dependencies. The byte-safe subsequence matcher lives in
+wmenu.c; ASCII matching retains fzy's old behavior, while non-ASCII UTF-8
+bytes are compared literally.
 
 Program shape
 -------------

@@ -113,7 +101,7 @@ Known simplifications
   It never yields while holding items_lock. The reader remains a separate
   thread. It publishes item_count with InterlockedIncrement after inserting a
   row; UI count reads use loaded_count(), and item pointers are read under
-  items_lock. Matching rows are indexed in source order (fzy subsequence matching,
+  items_lock. Matching rows are indexed in source order (subsequence matching,
   not score-ranked). No silent row cap. LB_SETCOUNT is wrapped with redraw
   suppression: unchanged visible rows are not invalidated as the row count
   grows; only newly visible rows are, and those are painted immediately so
diff --git a/Makefile b/Makefile
@@ -6,21 +6,15 @@ DEBUG=/D_WIN32 /D_DEBUG /D_CONSOLE /D_CRT_SECURE_NO_WARNINGS
 
 CFLAGS = $(DEBUG)
 
-wmenu.exe: wmenu.c arg.h deps/fzy/src/match.c deps/fzy/config.h deps/fzy/src/strings.h
-	cl wmenu.c deps/fzy/src/match.c /I deps/fzy/src $(CFLAGS) user32.lib comctl32.lib gdi32.lib
+wmenu.exe: wmenu.c arg.h
+	cl wmenu.c $(CFLAGS) user32.lib comctl32.lib gdi32.lib
 
-test: test_stream.c wmenu.c arg.h deps/fzy/src/match.c deps/fzy/config.h deps/fzy/src/strings.h
-	cl test_stream.c deps/fzy/src/match.c /I deps/fzy/src $(CFLAGS) user32.lib comctl32.lib gdi32.lib /Fe:test_stream.exe
+test: test_stream.c wmenu.c arg.h
+	cl test_stream.c $(CFLAGS) user32.lib comctl32.lib gdi32.lib /Fe:test_stream.exe
 	./test_stream.exe
 
 stress: test
 	./test_stream.exe stress
 
-deps/fzy/config.h: deps/fzy/src/config.def.h
-	printf '#include "src/config.def.h"\n' > deps/fzy/config.h
-
-deps/fzy/src/strings.h:
-	printf '/* generated for MSVC: fzy match.c does not need strings.h here */\n' > deps/fzy/src/strings.h
-
-wmenu-mingw.exe: wmenu.c arg.h deps/fzy/src/match.c deps/fzy/config.h deps/fzy/src/strings.h
-	/usr/bin/x86_64-w64-mingw32-gcc -municode -I deps/fzy/src -o wmenu-mingw.exe wmenu.c deps/fzy/src/match.c -luser32 -lcomctl32 -lgdi32
+wmenu-mingw.exe: wmenu.c arg.h
+	/usr/bin/x86_64-w64-mingw32-gcc -municode -o wmenu-mingw.exe wmenu.c -luser32 -lcomctl32 -lgdi32
diff --git a/requirements.ini b/requirements.ini
@@ -1,5 +0,0 @@
-[$]
-/=deps
-
-[.]
-fzy=https://github.com/jhawthorn/fzy.git@v1.1
diff --git a/test_stream.c b/test_stream.c
@@ -17,6 +17,10 @@ static LRESULT CALLBACK TestWndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
 
 int main(int argc, char **argv)
 {
+    assert(has_match("aC", "ABC"));
+    assert(!has_match("Ab", "abc")); /* Preserve fzy's ASCII query casing. */
+    assert(has_match("\xc3\xa9", "caf\xc3\xa9"));
+    assert(!has_match("\xc3\xa9", "caf\xc3\x89"));
     FILE *input = tmpfile();
     assert(input);
     char long_row[8193];

@@ -229,6 +233,10 @@ int main(int argc, char **argv)
     input_done = true;
     update_progress();
     assert(SendMessageW(list_hwnd, LB_GETCOUNT, 0, 0) == 1);
+    assert(add_item("caf\xc3\xa9"));
+    SetWindowTextW(input_hwnd, L"\x00e9"); /* UTF-8 edit text goes through the search path. */
+    while (search_pos < loaded_count()) search_step();
+    assert(match_count == 1 && matches[0] == 60003);
     DeleteFiber(search_fiber);
     ConvertFiberToThread();
     DestroyWindow(main_hwnd);
diff --git a/wmenu.c b/wmenu.c
@@ -12,8 +12,6 @@
 #include <wctype.h>
 
 #include "arg.h"
-#include "deps/fzy/src/match.h"
-
 #ifdef _MSC_VER
 #pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
 #endif

@@ -185,6 +183,19 @@ static DWORD WINAPI read_stdin_thread(void *unused)
     return 0;
 }
 
+/* fzy-style subsequence matching, with non-ASCII UTF-8 bytes compared literally. */
+static bool has_match(const char *query, const char *line)
+{
+    while (*query) {
+        unsigned char ch = (unsigned char)*query++;
+        unsigned char upper = ch >= 'a' && ch <= 'z' ? ch - 'a' + 'A' : ch;
+        while (*line && (unsigned char)*line != ch && (unsigned char)*line != upper) ++line;
+        if (!*line) return false;
+        ++line;
+    }
+    return true;
+}
+
 /* The ListBox stores only a count. Its row IDs map into items or matches. */
 static int row_item(int row)
 {