Commit: 8de9e21b0bb2d2af9962987b5b9b89a31eb040ed
Parent: 61b3e6313ac97ea8ad93f3cede5d058f5bc1c233
Author: Randy Palamar
Date: Fri, 7 Aug 2026 20:48:03 -0700
ui: add word navigation for text input
Diffstat:
| M | ui.c | | | 7 | +++---- |
| M | util.c | | | 34 | ++++++++++++++++++++++++++++++++++ |
| M | util.h | | | 11 | +++++++---- |
3 files changed, 44 insertions(+), 8 deletions(-)
diff --git a/ui.c b/ui.c
@@ -2,9 +2,6 @@
/* TODO(rnp):
* [ ]: track active panel
* - when beamformer gets command to open tab it goes to this location by default
- * [ ]: word scan for text input
- * [ ]: when dragging only tab from group close old group on release
- * - only keep layout when closing tabs
* [ ]: animation state
* [ ]: tooltips
* [ ]: extra copy view settings
@@ -1681,7 +1678,9 @@ ui_text_input_update(BeamformerInput *input)
if ((flags & Delete) && tis->mark != tis->cursor)
delta = 0;
- // TODO(rnp): word selection
+ if (flags & WordScan)
+ delta = str8_word_boundary(ui_text_input_string(), tis->mark, delta) - tis->mark;
+
tis->mark += delta;
tis->mark = Clamp(tis->mark, 0, tis->count);
diff --git a/util.c b/util.c
@@ -813,6 +813,40 @@ str8_cut_head(str8 s, i64 cut)
return result;
}
+function i64
+str8_word_boundary_before(str8 s, i64 p)
+{
+ p = Max(p - 1, 0);
+ b32 negate = IsWordBoundary(s.data[p]);
+ while (p >= 0 && (negate ^ !IsWordBoundary(s.data[p])))
+ p -= 1;
+ p++;
+ return p;
+}
+
+function i64
+str8_word_boundary_after(str8 s, i64 p)
+{
+ b32 negate = IsWordBoundary(s.data[p]);
+ while (p != s.length && (negate ^ !IsWordBoundary(s.data[p])))
+ p += 1;
+ return p;
+}
+
+function i64
+str8_word_boundary(str8 s, i64 p, i64 count)
+{
+ i64 sign = Sign(count);
+ i64 end_p = sign > 0 ? s.length : 0;
+ count = Abs(count);
+ p = Clamp(p, 0, s.length);
+
+ for (i64 word_count = 0; word_count < count && p != end_p; word_count++)
+ p = sign > 0 ? str8_word_boundary_after(s, p) : str8_word_boundary_before(s, p);
+
+ return p;
+}
+
function b32
str8_match(str8 a, str8 b, StringMatchFlags flags)
{
diff --git a/util.h b/util.h
@@ -75,10 +75,13 @@
#define IsPowerOfTwo(a) (((a) & ((a) - 1)) == 0)
#define AlignUpPowerOfTwo(v, a) (((v) + (a) - 1) & (~((a) - 1)))
-#define IsDigit(c) (Between((c), '0', '9'))
-#define IsUpper(c) (((c) & 0x20u) == 0)
-#define ToLower(c) (((c) | 0x20u))
-#define ToUpper(c) (((c) & ~(0x20u)))
+#define IsDigit(c) (Between((c), '0', '9'))
+#define IsUpper(c) (((c) & 0x20u) == 0)
+#define ToLower(c) (((c) | 0x20u))
+#define ToUpper(c) (((c) & ~(0x20u)))
+
+#define IsPunctuation(c) (Between(c, '!', '/') || Between(c, ':', '@') || Between(c, '[', '`') || Between(c, '{', '~'))
+#define IsWordBoundary(c) (((c) == ' ') || IsPunctuation(c))
#define f32_equal(x, y) (Abs((x) - (y)) <= F32_EPSILON * Max(1.0f, Max(Abs(x), Abs(y))))