a modern tui library written in zig

widgets(text_input): expose api

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>

Changed files
+27 -27
src
widgets
+27 -27
src/widgets/TextInput.zig
··· 88 88 } 89 89 90 90 /// calculates the display width from the draw_offset to the cursor 91 - fn widthToCursor(self: *TextInput, win: Window) usize { 91 + pub fn widthToCursor(self: *TextInput, win: Window) usize { 92 92 var width: usize = 0; 93 93 const first_half = self.buf.firstHalf(); 94 94 var first_iter = self.unicode.graphemeIterator(first_half); ··· 104 104 return width; 105 105 } 106 106 107 - fn cursorLeft(self: *TextInput) void { 107 + pub fn cursorLeft(self: *TextInput) void { 108 108 // We need to find the size of the last grapheme in the first half 109 109 var iter = self.unicode.graphemeIterator(self.buf.firstHalf()); 110 110 var len: usize = 0; ··· 114 114 self.buf.moveGapLeft(len); 115 115 } 116 116 117 - fn cursorRight(self: *TextInput) void { 117 + pub fn cursorRight(self: *TextInput) void { 118 118 var iter = self.unicode.graphemeIterator(self.buf.secondHalf()); 119 119 const grapheme = iter.next() orelse return; 120 120 self.buf.moveGapRight(grapheme.len); 121 121 } 122 122 123 - fn graphemesBeforeCursor(self: *const TextInput) usize { 123 + pub fn graphemesBeforeCursor(self: *const TextInput) usize { 124 124 const first_half = self.buf.firstHalf(); 125 125 var first_iter = self.unicode.graphemeIterator(first_half); 126 126 var i: usize = 0; ··· 216 216 return self.buf.toOwnedSlice(); 217 217 } 218 218 219 - fn reset(self: *TextInput) void { 219 + pub fn reset(self: *TextInput) void { 220 220 self.draw_offset = 0; 221 221 self.prev_cursor_col = 0; 222 222 self.prev_cursor_idx = 0; ··· 227 227 return self.buf.cursor; 228 228 } 229 229 230 - fn deleteToEnd(self: *TextInput) void { 230 + pub fn deleteToEnd(self: *TextInput) void { 231 231 self.buf.growGapRight(self.buf.secondHalf().len); 232 232 } 233 233 234 - fn deleteToStart(self: *TextInput) void { 234 + pub fn deleteToStart(self: *TextInput) void { 235 235 self.buf.growGapLeft(self.buf.cursor); 236 236 } 237 237 238 - fn deleteBeforeCursor(self: *TextInput) void { 238 + pub fn deleteBeforeCursor(self: *TextInput) void { 239 239 // We need to find the size of the last grapheme in the first half 240 240 var iter = self.unicode.graphemeIterator(self.buf.firstHalf()); 241 241 var len: usize = 0; ··· 245 245 self.buf.growGapLeft(len); 246 246 } 247 247 248 - fn deleteAfterCursor(self: *TextInput) void { 248 + pub fn deleteAfterCursor(self: *TextInput) void { 249 249 var iter = self.unicode.graphemeIterator(self.buf.secondHalf()); 250 250 const grapheme = iter.next() orelse return; 251 251 self.buf.growGapRight(grapheme.len); ··· 253 253 254 254 /// Moves the cursor backward by words. If the character before the cursor is a space, the cursor is 255 255 /// positioned just after the next previous space 256 - fn moveBackwardWordwise(self: *TextInput) void { 256 + pub fn moveBackwardWordwise(self: *TextInput) void { 257 257 const trimmed = std.mem.trimRight(u8, self.buf.firstHalf(), " "); 258 258 const idx = if (std.mem.lastIndexOfScalar(u8, trimmed, ' ')) |last| 259 259 last + 1 ··· 262 262 self.buf.moveGapLeft(self.buf.cursor - idx); 263 263 } 264 264 265 - fn moveForwardWordwise(self: *TextInput) void { 265 + pub fn moveForwardWordwise(self: *TextInput) void { 266 266 const second_half = self.buf.secondHalf(); 267 267 var i: usize = 0; 268 268 while (i < second_half.len and second_half[i] == ' ') : (i += 1) {} ··· 270 270 self.buf.moveGapRight(idx); 271 271 } 272 272 273 - fn deleteWordBefore(self: *TextInput) void { 273 + pub fn deleteWordBefore(self: *TextInput) void { 274 274 // Store current cursor position. Move one word backward. Delete after the cursor the bytes we 275 275 // moved 276 276 const pre = self.buf.cursor; ··· 278 278 self.buf.growGapRight(pre - self.buf.cursor); 279 279 } 280 280 281 - fn deleteWordAfter(self: *TextInput) void { 281 + pub fn deleteWordAfter(self: *TextInput) void { 282 282 // Store current cursor position. Move one word backward. Delete after the cursor the bytes we 283 283 // moved 284 284 const second_half = self.buf.secondHalf(); ··· 320 320 try std.testing.expectEqualStrings("hello, wor", input.sliceToCursor(&buf)); 321 321 } 322 322 323 - const Buffer = struct { 323 + pub const Buffer = struct { 324 324 allocator: std.mem.Allocator, 325 325 buffer: []u8, 326 326 cursor: usize, 327 327 gap_size: usize, 328 328 329 - fn init(allocator: std.mem.Allocator) Buffer { 329 + pub fn init(allocator: std.mem.Allocator) Buffer { 330 330 return .{ 331 331 .allocator = allocator, 332 332 .buffer = &.{}, ··· 335 335 }; 336 336 } 337 337 338 - fn deinit(self: *Buffer) void { 338 + pub fn deinit(self: *Buffer) void { 339 339 self.allocator.free(self.buffer); 340 340 } 341 341 342 - fn firstHalf(self: Buffer) []const u8 { 342 + pub fn firstHalf(self: Buffer) []const u8 { 343 343 return self.buffer[0..self.cursor]; 344 344 } 345 345 346 - fn secondHalf(self: Buffer) []const u8 { 346 + pub fn secondHalf(self: Buffer) []const u8 { 347 347 return self.buffer[self.cursor + self.gap_size ..]; 348 348 } 349 349 350 - fn grow(self: *Buffer, n: usize) std.mem.Allocator.Error!void { 350 + pub fn grow(self: *Buffer, n: usize) std.mem.Allocator.Error!void { 351 351 // Always grow by 512 bytes 352 352 const new_size = self.buffer.len + n + 512; 353 353 // Allocate the new memory ··· 362 362 self.gap_size = new_size - second_half.len - self.cursor; 363 363 } 364 364 365 - fn insertSliceAtCursor(self: *Buffer, slice: []const u8) std.mem.Allocator.Error!void { 365 + pub fn insertSliceAtCursor(self: *Buffer, slice: []const u8) std.mem.Allocator.Error!void { 366 366 if (slice.len == 0) return; 367 367 if (self.gap_size <= slice.len) try self.grow(slice.len); 368 368 @memcpy(self.buffer[self.cursor .. self.cursor + slice.len], slice); ··· 371 371 } 372 372 373 373 /// Move the gap n bytes to the left 374 - fn moveGapLeft(self: *Buffer, n: usize) void { 374 + pub fn moveGapLeft(self: *Buffer, n: usize) void { 375 375 const new_idx = self.cursor -| n; 376 376 const dst = self.buffer[new_idx + self.gap_size ..]; 377 377 const src = self.buffer[new_idx..self.cursor]; ··· 379 379 self.cursor = new_idx; 380 380 } 381 381 382 - fn moveGapRight(self: *Buffer, n: usize) void { 382 + pub fn moveGapRight(self: *Buffer, n: usize) void { 383 383 const new_idx = self.cursor + n; 384 384 const dst = self.buffer[self.cursor..]; 385 385 const src = self.buffer[self.cursor + self.gap_size .. new_idx + self.gap_size]; ··· 388 388 } 389 389 390 390 /// grow the gap by moving the cursor n bytes to the left 391 - fn growGapLeft(self: *Buffer, n: usize) void { 391 + pub fn growGapLeft(self: *Buffer, n: usize) void { 392 392 // gap grows by the delta 393 393 self.gap_size += n; 394 394 self.cursor -|= n; 395 395 } 396 396 397 397 /// grow the gap by removing n bytes after the cursor 398 - fn growGapRight(self: *Buffer, n: usize) void { 398 + pub fn growGapRight(self: *Buffer, n: usize) void { 399 399 self.gap_size = @min(self.gap_size + n, self.buffer.len - self.cursor); 400 400 } 401 401 402 - fn clearAndFree(self: *Buffer) void { 402 + pub fn clearAndFree(self: *Buffer) void { 403 403 self.cursor = 0; 404 404 self.allocator.free(self.buffer); 405 405 self.buffer = &.{}; 406 406 self.gap_size = 0; 407 407 } 408 408 409 - fn clearRetainingCapacity(self: *Buffer) void { 409 + pub fn clearRetainingCapacity(self: *Buffer) void { 410 410 self.cursor = 0; 411 411 self.gap_size = self.buffer.len; 412 412 } 413 413 414 - fn toOwnedSlice(self: *Buffer) std.mem.Allocator.Error![]const u8 { 414 + pub fn toOwnedSlice(self: *Buffer) std.mem.Allocator.Error![]const u8 { 415 415 const first_half = self.firstHalf(); 416 416 const second_half = self.secondHalf(); 417 417 const buf = try self.allocator.alloc(u8, first_half.len + second_half.len);