this repo has no description
13
fork

Configure Feed

Select the types of activity you want to include in your feed.

unicode: convert to stateless namespace module

Convert Unicode.zig from a struct-based API requiring initialization
to a stateless namespace module. This eliminates the need to allocate
and pass Unicode instances throughout the codebase.

Remove the unicode field from all structs including Vaxis, Window, and
various widget types. Change graphemeIterator from a method requiring
a Unicode instance to a namespace function that can be called directly.

Update all callsites to use unicode.graphemeIterator(str) instead of
self.unicode.graphemeIterator(str). Remove all Unicode.init() and
unicode.deinit() calls as they are no longer needed.

This simplifies the API and reduces coupling since grapheme iteration
no longer requires passing Unicode instances through the component
hierarchy.

Amp-Thread-ID: https://ampcode.com/threads/T-d83881e8-f6ea-45ee-889f-f480c0c6d4cb
Co-authored-by: Amp <amp@ampcode.com>

+63 -135
+1 -4
examples/fuzzy.zig
··· 8 8 list_view: vxfw.ListView, 9 9 text_field: vxfw.TextField, 10 10 result: []const u8, 11 - unicode_data: *const vaxis.Unicode, 12 11 13 12 /// Used for filtered RichText Spans 14 13 arena: std.heap.ArenaAllocator, ··· 119 118 120 119 var spans = std.ArrayList(vxfw.RichText.TextSpan){}; 121 120 var i: usize = 0; 122 - var iter = self.unicode_data.graphemeIterator(str); 121 + var iter = vaxis.unicode.graphemeIterator(str); 123 122 while (iter.next()) |g| { 124 123 if (std.mem.indexOfPos(u8, tgt, i, g.bytes(str))) |idx| { 125 124 const up_to_here: vxfw.RichText.TextSpan = .{ .text = item.text[i..idx] }; ··· 189 188 }, 190 189 .text_field = .{ 191 190 .buf = vxfw.TextField.Buffer.init(allocator), 192 - .unicode = &app.vx.unicode, 193 191 .userdata = model, 194 192 .onChange = Model.onChange, 195 193 .onSubmit = Model.onSubmit, 196 194 }, 197 195 .result = "", 198 196 .arena = std.heap.ArenaAllocator.init(allocator), 199 - .unicode_data = &app.vx.unicode, 200 197 }; 201 198 defer model.text_field.deinit(); 202 199 defer model.list.deinit(allocator);
+1 -2
src/Unicode.zig
··· 76 76 }; 77 77 78 78 /// creates a grapheme iterator based on str 79 - pub fn graphemeIterator(self: *const Unicode, str: []const u8) GraphemeIterator { 80 - _ = self; 79 + pub fn graphemeIterator(str: []const u8) GraphemeIterator { 81 80 return GraphemeIterator.init(str); 82 81 }
+1 -6
src/Vaxis.zig
··· 11 11 const Key = @import("Key.zig"); 12 12 const Mouse = @import("Mouse.zig"); 13 13 const Screen = @import("Screen.zig"); 14 - const Unicode = @import("Unicode.zig"); 14 + const unicode = @import("unicode.zig"); 15 15 const Window = @import("Window.zig"); 16 16 17 17 const Hyperlink = Cell.Hyperlink; ··· 73 73 74 74 // images 75 75 next_img_id: u32 = 1, 76 - 77 - unicode: Unicode, 78 76 79 77 sgr: enum { 80 78 standard, ··· 110 108 .opts = opts, 111 109 .screen = .{}, 112 110 .screen_last = try .init(alloc, 0, 0), 113 - .unicode = try Unicode.init(alloc), 114 111 }; 115 112 } 116 113 ··· 124 121 if (alloc) |a| { 125 122 self.screen.deinit(a); 126 123 self.screen_last.deinit(a); 127 - self.unicode.deinit(a); 128 124 } 129 125 } 130 126 ··· 227 223 .width = self.screen.width, 228 224 .height = self.screen.height, 229 225 .screen = &self.screen, 230 - .unicode = &self.unicode, 231 226 }; 232 227 } 233 228
+4 -19
src/Window.zig
··· 4 4 const Cell = @import("Cell.zig"); 5 5 const Mouse = @import("Mouse.zig"); 6 6 const Segment = @import("Cell.zig").Segment; 7 - const Unicode = @import("Unicode.zig"); 7 + const unicode = @import("unicode.zig"); 8 8 const gw = @import("gwidth.zig"); 9 9 10 10 const Window = @This(); ··· 25 25 height: u16, 26 26 27 27 screen: *Screen, 28 - unicode: *const Unicode, 29 28 30 29 /// Creates a new window with offset relative to parent and size clamped to the 31 30 /// parent's size. Windows do not retain a reference to their parent and are ··· 50 49 .width = @min(width, max_width), 51 50 .height = @min(height, max_height), 52 51 .screen = self.screen, 53 - .unicode = self.unicode, 54 52 }; 55 53 } 56 54 ··· 295 293 .grapheme => { 296 294 var col: u16 = opts.col_offset; 297 295 const overflow: bool = blk: for (segments) |segment| { 298 - var iter = self.unicode.graphemeIterator(segment.text); 296 + var iter = unicode.graphemeIterator(segment.text); 299 297 while (iter.next()) |grapheme| { 300 298 if (col >= self.width) { 301 299 row += 1; ··· 378 376 col = 0; 379 377 } 380 378 381 - var grapheme_iterator = self.unicode.graphemeIterator(word); 379 + var grapheme_iterator = unicode.graphemeIterator(word); 382 380 while (grapheme_iterator.next()) |grapheme| { 383 381 soft_wrapped = false; 384 382 if (row >= self.height) { ··· 417 415 .none => { 418 416 var col: u16 = opts.col_offset; 419 417 const overflow: bool = blk: for (segments) |segment| { 420 - var iter = self.unicode.graphemeIterator(segment.text); 418 + var iter = unicode.graphemeIterator(segment.text); 421 419 while (iter.next()) |grapheme| { 422 420 if (col >= self.width) break :blk true; 423 421 const s = grapheme.bytes(segment.text); ··· 489 487 .width = 20, 490 488 .height = 20, 491 489 .screen = undefined, 492 - .unicode = undefined, 493 490 }; 494 491 495 492 const ch = parent.initChild(1, 1, null, null); ··· 506 503 .width = 20, 507 504 .height = 20, 508 505 .screen = undefined, 509 - .unicode = undefined, 510 506 }; 511 507 512 508 const ch = parent.initChild(0, 0, 21, 21); ··· 523 519 .width = 20, 524 520 .height = 20, 525 521 .screen = undefined, 526 - .unicode = undefined, 527 522 }; 528 523 529 524 const ch = parent.initChild(10, 10, 21, 21); ··· 540 535 .width = 20, 541 536 .height = 20, 542 537 .screen = undefined, 543 - .unicode = undefined, 544 538 }; 545 539 546 540 const ch = parent.initChild(10, 10, 21, 21); ··· 557 551 .width = 20, 558 552 .height = 20, 559 553 .screen = undefined, 560 - .unicode = undefined, 561 554 }; 562 555 563 556 const ch = parent.initChild(10, 10, 21, 21); ··· 569 562 } 570 563 571 564 test "print: grapheme" { 572 - const alloc = std.testing.allocator_instance.allocator(); 573 - const unicode = try Unicode.init(alloc); 574 - defer unicode.deinit(alloc); 575 565 var screen: Screen = .{ .width_method = .unicode }; 576 566 const win: Window = .{ 577 567 .x_off = 0, ··· 581 571 .width = 4, 582 572 .height = 2, 583 573 .screen = &screen, 584 - .unicode = &unicode, 585 574 }; 586 575 const opts: PrintOptions = .{ 587 576 .commit = false, ··· 636 625 } 637 626 638 627 test "print: word" { 639 - const alloc = std.testing.allocator_instance.allocator(); 640 - const unicode = try Unicode.init(alloc); 641 - defer unicode.deinit(alloc); 642 628 var screen: Screen = .{ 643 629 .width_method = .unicode, 644 630 }; ··· 650 636 .width = 4, 651 637 .height = 2, 652 638 .screen = &screen, 653 - .unicode = &unicode, 654 639 }; 655 640 const opts: PrintOptions = .{ 656 641 .commit = false,
+1 -1
src/main.zig
··· 28 28 pub const ctlseqs = @import("ctlseqs.zig"); 29 29 pub const GraphemeCache = @import("GraphemeCache.zig"); 30 30 pub const Event = @import("event.zig").Event; 31 - pub const Unicode = @import("Unicode.zig"); 31 + pub const unicode = @import("unicode.zig"); 32 32 33 33 pub const vxfw = @import("vxfw/vxfw.zig"); 34 34
+1 -2
src/vxfw/Border.zig
··· 119 119 120 120 var arena = std.heap.ArenaAllocator.init(std.testing.allocator); 121 121 defer arena.deinit(); 122 - const ucd = try vaxis.Unicode.init(arena.allocator()); 123 - vxfw.DrawContext.init(&ucd, .unicode); 122 + vxfw.DrawContext.init(.unicode); 124 123 125 124 // Border will draw itself tightly around the child 126 125 const ctx: vxfw.DrawContext = .{
+1 -2
src/vxfw/Button.zig
··· 187 187 // Now we draw the button. Set up our context with some unicode data 188 188 var arena = std.heap.ArenaAllocator.init(std.testing.allocator); 189 189 defer arena.deinit(); 190 - const ucd = try vaxis.Unicode.init(arena.allocator()); 191 - vxfw.DrawContext.init(&ucd, .unicode); 190 + vxfw.DrawContext.init(.unicode); 192 191 193 192 const draw_ctx: vxfw.DrawContext = .{ 194 193 .arena = arena.allocator(),
+1 -2
src/vxfw/Center.zig
··· 54 54 55 55 var arena = std.heap.ArenaAllocator.init(std.testing.allocator); 56 56 defer arena.deinit(); 57 - const ucd = try vaxis.Unicode.init(arena.allocator()); 58 - vxfw.DrawContext.init(&ucd, .unicode); 57 + vxfw.DrawContext.init(.unicode); 59 58 60 59 { 61 60 // Center expands to the max size. It must therefore have non-null max width and max height.
+1 -2
src/vxfw/FlexColumn.zig
··· 115 115 // Boiler plate draw context 116 116 var arena = std.heap.ArenaAllocator.init(std.testing.allocator); 117 117 defer arena.deinit(); 118 - const ucd = try vaxis.Unicode.init(arena.allocator()); 119 - vxfw.DrawContext.init(&ucd, .unicode); 118 + vxfw.DrawContext.init(.unicode); 120 119 121 120 const flex_widget = flex_column.widget(); 122 121 const ctx: vxfw.DrawContext = .{
+1 -2
src/vxfw/FlexRow.zig
··· 114 114 // Boiler plate draw context 115 115 var arena = std.heap.ArenaAllocator.init(std.testing.allocator); 116 116 defer arena.deinit(); 117 - const ucd = try vaxis.Unicode.init(arena.allocator()); 118 - vxfw.DrawContext.init(&ucd, .unicode); 117 + vxfw.DrawContext.init(.unicode); 119 118 120 119 const flex_widget = flex_row.widget(); 121 120 const ctx: vxfw.DrawContext = .{
+2 -4
src/vxfw/ListView.zig
··· 536 536 // Boiler plate draw context 537 537 var arena = std.heap.ArenaAllocator.init(std.testing.allocator); 538 538 defer arena.deinit(); 539 - const ucd = try vaxis.Unicode.init(arena.allocator()); 540 - vxfw.DrawContext.init(&ucd, .unicode); 539 + vxfw.DrawContext.init(.unicode); 541 540 542 541 const list_widget = list_view.widget(); 543 542 const draw_ctx: vxfw.DrawContext = .{ ··· 709 708 // Boiler plate draw context 710 709 var arena = std.heap.ArenaAllocator.init(std.testing.allocator); 711 710 defer arena.deinit(); 712 - const ucd = try vaxis.Unicode.init(arena.allocator()); 713 - vxfw.DrawContext.init(&ucd, .unicode); 711 + vxfw.DrawContext.init(.unicode); 714 712 715 713 const list_widget = list_view.widget(); 716 714 const draw_ctx: vxfw.DrawContext = .{
+1 -2
src/vxfw/Padding.zig
··· 112 112 113 113 var arena = std.heap.ArenaAllocator.init(std.testing.allocator); 114 114 defer arena.deinit(); 115 - const ucd = try vaxis.Unicode.init(arena.allocator()); 116 - vxfw.DrawContext.init(&ucd, .unicode); 115 + vxfw.DrawContext.init(.unicode); 117 116 118 117 // Center expands to the max size. It must therefore have non-null max width and max height. 119 118 // These values are asserted in draw
+4 -4
src/vxfw/RichText.zig
··· 363 363 364 364 var arena = std.heap.ArenaAllocator.init(std.testing.allocator); 365 365 defer arena.deinit(); 366 - const ucd = try vaxis.Unicode.init(arena.allocator()); 367 - vxfw.DrawContext.init(&ucd, .unicode); 366 + 367 + vxfw.DrawContext.init(.unicode); 368 368 369 369 // Center expands to the max size. It must therefore have non-null max width and max height. 370 370 // These values are asserted in draw ··· 402 402 403 403 var arena = std.heap.ArenaAllocator.init(std.testing.allocator); 404 404 defer arena.deinit(); 405 - const ucd = try vaxis.Unicode.init(arena.allocator()); 406 - vxfw.DrawContext.init(&ucd, .unicode); 405 + 406 + vxfw.DrawContext.init(.unicode); 407 407 408 408 const len = rich_text.text[0].text.len; 409 409 const width: u16 = 8;
+1 -2
src/vxfw/ScrollBars.zig
··· 572 572 // Boiler plate draw context 573 573 var arena = std.heap.ArenaAllocator.init(std.testing.allocator); 574 574 defer arena.deinit(); 575 - const ucd = try vaxis.Unicode.init(arena.allocator()); 576 - vxfw.DrawContext.init(&ucd, .unicode); 575 + vxfw.DrawContext.init(.unicode); 577 576 578 577 const scroll_widget = scroll_bars.widget(); 579 578 const draw_ctx: vxfw.DrawContext = .{
+2 -4
src/vxfw/ScrollView.zig
··· 609 609 // Boiler plate draw context 610 610 var arena = std.heap.ArenaAllocator.init(std.testing.allocator); 611 611 defer arena.deinit(); 612 - const ucd = try vaxis.Unicode.init(arena.allocator()); 613 - vxfw.DrawContext.init(&ucd, .unicode); 612 + vxfw.DrawContext.init(.unicode); 614 613 615 614 const scroll_widget = scroll_view.widget(); 616 615 const draw_ctx: vxfw.DrawContext = .{ ··· 1022 1021 // Boiler plate draw context 1023 1022 var arena = std.heap.ArenaAllocator.init(std.testing.allocator); 1024 1023 defer arena.deinit(); 1025 - const ucd = try vaxis.Unicode.init(arena.allocator()); 1026 - vxfw.DrawContext.init(&ucd, .unicode); 1024 + vxfw.DrawContext.init(.unicode); 1027 1025 1028 1026 const scroll_widget = scroll_view.widget(); 1029 1027 const draw_ctx: vxfw.DrawContext = .{
+1 -2
src/vxfw/SizedBox.zig
··· 59 59 // Boiler plate draw context 60 60 var arena = std.heap.ArenaAllocator.init(std.testing.allocator); 61 61 defer arena.deinit(); 62 - const ucd = try vaxis.Unicode.init(arena.allocator()); 63 - vxfw.DrawContext.init(&ucd, .unicode); 62 + vxfw.DrawContext.init(.unicode); 64 63 65 64 var draw_ctx: vxfw.DrawContext = .{ 66 65 .arena = arena.allocator(),
+1 -2
src/vxfw/SplitView.zig
··· 185 185 // Boiler plate draw context 186 186 var arena = std.heap.ArenaAllocator.init(std.testing.allocator); 187 187 defer arena.deinit(); 188 - const ucd = try vaxis.Unicode.init(arena.allocator()); 189 - vxfw.DrawContext.init(&ucd, .unicode); 188 + vxfw.DrawContext.init(.unicode); 190 189 191 190 const draw_ctx: vxfw.DrawContext = .{ 192 191 .arena = arena.allocator(),
+5 -14
src/vxfw/Text.zig
··· 293 293 }; 294 294 295 295 test "SoftwrapIterator: LF breaks" { 296 - const unicode = try vaxis.Unicode.init(std.testing.allocator); 297 - defer unicode.deinit(std.testing.allocator); 298 - vxfw.DrawContext.init(&unicode, .unicode); 296 + vxfw.DrawContext.init(.unicode); 299 297 var arena = std.heap.ArenaAllocator.init(std.testing.allocator); 300 298 defer arena.deinit(); 301 299 ··· 321 319 } 322 320 323 321 test "SoftwrapIterator: soft breaks that fit" { 324 - const unicode = try vaxis.Unicode.init(std.testing.allocator); 325 - defer unicode.deinit(std.testing.allocator); 326 - vxfw.DrawContext.init(&unicode, .unicode); 322 + vxfw.DrawContext.init(.unicode); 327 323 var arena = std.heap.ArenaAllocator.init(std.testing.allocator); 328 324 defer arena.deinit(); 329 325 ··· 349 345 } 350 346 351 347 test "SoftwrapIterator: soft breaks that are longer than width" { 352 - const unicode = try vaxis.Unicode.init(std.testing.allocator); 353 - defer unicode.deinit(std.testing.allocator); 354 - vxfw.DrawContext.init(&unicode, .unicode); 348 + vxfw.DrawContext.init(.unicode); 355 349 var arena = std.heap.ArenaAllocator.init(std.testing.allocator); 356 350 defer arena.deinit(); 357 351 ··· 387 381 } 388 382 389 383 test "SoftwrapIterator: soft breaks with leading spaces" { 390 - const unicode = try vaxis.Unicode.init(std.testing.allocator); 391 - defer unicode.deinit(std.testing.allocator); 392 - vxfw.DrawContext.init(&unicode, .unicode); 384 + vxfw.DrawContext.init(.unicode); 393 385 var arena = std.heap.ArenaAllocator.init(std.testing.allocator); 394 386 defer arena.deinit(); 395 387 ··· 484 476 485 477 var arena = std.heap.ArenaAllocator.init(std.testing.allocator); 486 478 defer arena.deinit(); 487 - const ucd = try vaxis.Unicode.init(arena.allocator()); 488 - vxfw.DrawContext.init(&ucd, .unicode); 479 + vxfw.DrawContext.init(.unicode); 489 480 490 481 // Center expands to the max size. It must therefore have non-null max width and max height. 491 482 // These values are asserted in draw
+14 -21
src/vxfw/TextField.zig
··· 9 9 const Key = vaxis.Key; 10 10 const Cell = vaxis.Cell; 11 11 const Window = vaxis.Window; 12 - const Unicode = vaxis.Unicode; 12 + const unicode = vaxis.unicode; 13 13 14 14 const TextField = @This(); 15 15 ··· 32 32 /// Previous width we drew at 33 33 prev_width: u16 = 0, 34 34 35 - unicode: *const Unicode, 36 - 37 35 previous_val: []const u8 = "", 38 36 39 37 userdata: ?*anyopaque = null, 40 38 onChange: ?*const fn (?*anyopaque, *vxfw.EventContext, []const u8) anyerror!void = null, 41 39 onSubmit: ?*const fn (?*anyopaque, *vxfw.EventContext, []const u8) anyerror!void = null, 42 40 43 - pub fn init(alloc: std.mem.Allocator, unicode: *const Unicode) TextField { 41 + pub fn init(alloc: std.mem.Allocator) TextField { 44 42 return TextField{ 45 43 .buf = Buffer.init(alloc), 46 - .unicode = unicode, 47 44 }; 48 45 } 49 46 ··· 137 134 138 135 /// insert text at the cursor position 139 136 pub fn insertSliceAtCursor(self: *TextField, data: []const u8) std.mem.Allocator.Error!void { 140 - var iter = self.unicode.graphemeIterator(data); 137 + var iter = unicode.graphemeIterator(data); 141 138 while (iter.next()) |text| { 142 139 try self.buf.insertSliceAtCursor(text.bytes(data)); 143 140 } ··· 153 150 pub fn widthToCursor(self: *TextField, ctx: vxfw.DrawContext) u16 { 154 151 var width: u16 = 0; 155 152 const first_half = self.buf.firstHalf(); 156 - var first_iter = self.unicode.graphemeIterator(first_half); 153 + var first_iter = unicode.graphemeIterator(first_half); 157 154 var i: usize = 0; 158 155 while (first_iter.next()) |grapheme| { 159 156 defer i += 1; ··· 168 165 169 166 pub fn cursorLeft(self: *TextField) void { 170 167 // We need to find the size of the last grapheme in the first half 171 - var iter = self.unicode.graphemeIterator(self.buf.firstHalf()); 168 + var iter = unicode.graphemeIterator(self.buf.firstHalf()); 172 169 var len: usize = 0; 173 170 while (iter.next()) |grapheme| { 174 171 len = grapheme.len; ··· 177 174 } 178 175 179 176 pub fn cursorRight(self: *TextField) void { 180 - var iter = self.unicode.graphemeIterator(self.buf.secondHalf()); 177 + var iter = unicode.graphemeIterator(self.buf.secondHalf()); 181 178 const grapheme = iter.next() orelse return; 182 179 self.buf.moveGapRight(grapheme.len); 183 180 } 184 181 185 182 pub fn graphemesBeforeCursor(self: *const TextField) u16 { 186 183 const first_half = self.buf.firstHalf(); 187 - var first_iter = self.unicode.graphemeIterator(first_half); 184 + var first_iter = unicode.graphemeIterator(first_half); 188 185 var i: u16 = 0; 189 186 while (first_iter.next()) |_| { 190 187 i += 1; ··· 230 227 self.prev_cursor_col = 0; 231 228 232 229 const first_half = self.buf.firstHalf(); 233 - var first_iter = self.unicode.graphemeIterator(first_half); 230 + var first_iter = unicode.graphemeIterator(first_half); 234 231 var col: u16 = 0; 235 232 var i: u16 = 0; 236 233 while (first_iter.next()) |grapheme| { ··· 259 256 if (i == cursor_idx) self.prev_cursor_col = col; 260 257 } 261 258 const second_half = self.buf.secondHalf(); 262 - var second_iter = self.unicode.graphemeIterator(second_half); 259 + var second_iter = unicode.graphemeIterator(second_half); 263 260 while (second_iter.next()) |grapheme| { 264 261 if (i < self.draw_offset) { 265 262 i += 1; ··· 332 329 333 330 pub fn deleteBeforeCursor(self: *TextField) void { 334 331 // We need to find the size of the last grapheme in the first half 335 - var iter = self.unicode.graphemeIterator(self.buf.firstHalf()); 332 + var iter = unicode.graphemeIterator(self.buf.firstHalf()); 336 333 var len: usize = 0; 337 334 while (iter.next()) |grapheme| { 338 335 len = grapheme.len; ··· 341 338 } 342 339 343 340 pub fn deleteAfterCursor(self: *TextField) void { 344 - var iter = self.unicode.graphemeIterator(self.buf.secondHalf()); 341 + var iter = unicode.graphemeIterator(self.buf.secondHalf()); 345 342 const grapheme = iter.next() orelse return; 346 343 self.buf.growGapRight(grapheme.len); 347 344 } ··· 384 381 } 385 382 386 383 test "sliceToCursor" { 387 - const alloc = std.testing.allocator_instance.allocator(); 388 - const unicode = try Unicode.init(alloc); 389 - defer unicode.deinit(alloc); 390 - var input = init(alloc, &unicode); 384 + var input = init(std.testing.allocator); 391 385 defer input.deinit(); 392 386 try input.insertSliceAtCursor("hello, world"); 393 387 input.cursorLeft(); ··· 541 535 // Boiler plate draw context init 542 536 var arena = std.heap.ArenaAllocator.init(std.testing.allocator); 543 537 defer arena.deinit(); 544 - const ucd = try vaxis.Unicode.init(arena.allocator()); 545 - vxfw.DrawContext.init(&ucd, .unicode); 538 + vxfw.DrawContext.init(.unicode); 546 539 547 540 // Create some object which reacts to text field changes 548 541 const Foo = struct { ··· 572 565 }; 573 566 574 567 // Enough boiler plate...Create the text field 575 - var text_field = TextField.init(std.testing.allocator, &ucd); 568 + var text_field = TextField.init(std.testing.allocator); 576 569 defer text_field.deinit(); 577 570 text_field.onChange = Foo.onChange; 578 571 text_field.onSubmit = Foo.onChange;
+3 -6
src/vxfw/vxfw.zig
··· 191 191 cell_size: Size, 192 192 193 193 // Unicode stuff 194 - var unicode: ?*const vaxis.Unicode = null; 195 194 var width_method: vaxis.gwidth.Method = .unicode; 196 195 197 - pub fn init(ucd: *const vaxis.Unicode, method: vaxis.gwidth.Method) void { 198 - DrawContext.unicode = ucd; 196 + pub fn init(method: vaxis.gwidth.Method) void { 199 197 DrawContext.width_method = method; 200 198 } 201 199 ··· 206 204 ); 207 205 } 208 206 209 - pub fn graphemeIterator(_: DrawContext, str: []const u8) vaxis.Unicode.GraphemeIterator { 210 - assert(DrawContext.unicode != null); // DrawContext not initialized 211 - return DrawContext.unicode.?.graphemeIterator(str); 207 + pub fn graphemeIterator(_: DrawContext, str: []const u8) vaxis.unicode.GraphemeIterator { 208 + return vaxis.unicode.graphemeIterator(str); 212 209 } 213 210 214 211 pub fn withConstraints(self: DrawContext, min: Size, max: MaxSize) DrawContext {
+13 -22
src/widgets/TextInput.zig
··· 3 3 const Key = @import("../Key.zig"); 4 4 const Cell = @import("../Cell.zig"); 5 5 const Window = @import("../Window.zig"); 6 - const Unicode = @import("../Unicode.zig"); 6 + const unicode = @import("../unicode.zig"); 7 7 8 8 const TextInput = @This(); 9 9 ··· 26 26 /// approximate distance from an edge before we scroll 27 27 scroll_offset: u16 = 4, 28 28 29 - unicode: *const Unicode, 30 - 31 - pub fn init(alloc: std.mem.Allocator, unicode: *const Unicode) TextInput { 29 + pub fn init(alloc: std.mem.Allocator) TextInput { 32 30 return TextInput{ 33 31 .buf = Buffer.init(alloc), 34 - .unicode = unicode, 35 32 }; 36 33 } 37 34 ··· 75 72 76 73 /// insert text at the cursor position 77 74 pub fn insertSliceAtCursor(self: *TextInput, data: []const u8) std.mem.Allocator.Error!void { 78 - var iter = self.unicode.graphemeIterator(data); 75 + var iter = unicode.graphemeIterator(data); 79 76 while (iter.next()) |text| { 80 77 try self.buf.insertSliceAtCursor(text.bytes(data)); 81 78 } ··· 91 88 pub fn widthToCursor(self: *TextInput, win: Window) u16 { 92 89 var width: u16 = 0; 93 90 const first_half = self.buf.firstHalf(); 94 - var first_iter = self.unicode.graphemeIterator(first_half); 91 + var first_iter = unicode.graphemeIterator(first_half); 95 92 var i: usize = 0; 96 93 while (first_iter.next()) |grapheme| { 97 94 defer i += 1; ··· 106 103 107 104 pub fn cursorLeft(self: *TextInput) void { 108 105 // We need to find the size of the last grapheme in the first half 109 - var iter = self.unicode.graphemeIterator(self.buf.firstHalf()); 106 + var iter = unicode.graphemeIterator(self.buf.firstHalf()); 110 107 var len: usize = 0; 111 108 while (iter.next()) |grapheme| { 112 109 len = grapheme.len; ··· 115 112 } 116 113 117 114 pub fn cursorRight(self: *TextInput) void { 118 - var iter = self.unicode.graphemeIterator(self.buf.secondHalf()); 115 + var iter = unicode.graphemeIterator(self.buf.secondHalf()); 119 116 const grapheme = iter.next() orelse return; 120 117 self.buf.moveGapRight(grapheme.len); 121 118 } 122 119 123 120 pub fn graphemesBeforeCursor(self: *const TextInput) u16 { 124 121 const first_half = self.buf.firstHalf(); 125 - var first_iter = self.unicode.graphemeIterator(first_half); 122 + var first_iter = unicode.graphemeIterator(first_half); 126 123 var i: u16 = 0; 127 124 while (first_iter.next()) |_| { 128 125 i += 1; ··· 152 149 // assumption!! the gap is never within a grapheme 153 150 // one way to _ensure_ this is to move the gap... but that's a cost we probably don't want to pay. 154 151 const first_half = self.buf.firstHalf(); 155 - var first_iter = self.unicode.graphemeIterator(first_half); 152 + var first_iter = unicode.graphemeIterator(first_half); 156 153 var col: u16 = 0; 157 154 var i: u16 = 0; 158 155 while (first_iter.next()) |grapheme| { ··· 181 178 if (i == cursor_idx) self.prev_cursor_col = col; 182 179 } 183 180 const second_half = self.buf.secondHalf(); 184 - var second_iter = self.unicode.graphemeIterator(second_half); 181 + var second_iter = unicode.graphemeIterator(second_half); 185 182 while (second_iter.next()) |grapheme| { 186 183 if (i < self.draw_offset) { 187 184 i += 1; ··· 252 249 253 250 pub fn deleteBeforeCursor(self: *TextInput) void { 254 251 // We need to find the size of the last grapheme in the first half 255 - var iter = self.unicode.graphemeIterator(self.buf.firstHalf()); 252 + var iter = unicode.graphemeIterator(self.buf.firstHalf()); 256 253 var len: usize = 0; 257 254 while (iter.next()) |grapheme| { 258 255 len = grapheme.len; ··· 261 258 } 262 259 263 260 pub fn deleteAfterCursor(self: *TextInput) void { 264 - var iter = self.unicode.graphemeIterator(self.buf.secondHalf()); 261 + var iter = unicode.graphemeIterator(self.buf.secondHalf()); 265 262 const grapheme = iter.next() orelse return; 266 263 self.buf.growGapRight(grapheme.len); 267 264 } ··· 304 301 } 305 302 306 303 test "assertion" { 307 - const alloc = std.testing.allocator_instance.allocator(); 308 - const unicode = try Unicode.init(alloc); 309 - defer unicode.deinit(); 310 304 const astronaut = "👩‍🚀"; 311 305 const astronaut_emoji: Key = .{ 312 306 .text = astronaut, 313 307 .codepoint = try std.unicode.utf8Decode(astronaut[0..4]), 314 308 }; 315 - var input = TextInput.init(std.testing.allocator, &unicode); 309 + var input = TextInput.init(std.testing.allocator); 316 310 defer input.deinit(); 317 311 for (0..6) |_| { 318 312 try input.update(.{ .key_press = astronaut_emoji }); ··· 320 314 } 321 315 322 316 test "sliceToCursor" { 323 - const alloc = std.testing.allocator_instance.allocator(); 324 - const unicode = try Unicode.init(alloc); 325 - defer unicode.deinit(); 326 - var input = init(alloc, &unicode); 317 + var input = init(std.testing.allocator); 327 318 defer input.deinit(); 328 319 try input.insertSliceAtCursor("hello, world"); 329 320 input.cursorLeft();
+2 -6
src/widgets/View.zig
··· 9 9 10 10 const Screen = @import("../Screen.zig"); 11 11 const Window = @import("../Window.zig"); 12 - const Unicode = @import("../Unicode.zig"); 12 + const unicode = @import("../unicode.zig"); 13 13 const Cell = @import("../Cell.zig"); 14 14 15 15 /// View Allocator ··· 17 17 18 18 /// Underlying Screen 19 19 screen: Screen, 20 - 21 - unicode: *const Unicode, 22 20 23 21 /// View Initialization Config 24 22 pub const Config = struct { ··· 27 25 }; 28 26 29 27 /// Initialize a new View 30 - pub fn init(alloc: mem.Allocator, unicode: *const Unicode, config: Config) mem.Allocator.Error!View { 28 + pub fn init(alloc: mem.Allocator, config: Config) mem.Allocator.Error!View { 31 29 return .{ 32 30 .alloc = alloc, 33 31 .screen = try Screen.init(alloc, .{ ··· 36 34 .x_pixel = 0, 37 35 .y_pixel = 0, 38 36 }), 39 - .unicode = unicode, 40 37 }; 41 38 } 42 39 ··· 49 46 .width = self.screen.width, 50 47 .height = self.screen.height, 51 48 .screen = &self.screen, 52 - .unicode = self.unicode, 53 49 }; 54 50 } 55 51
+1 -4
src/widgets/terminal/Terminal.zig
··· 69 69 // dirty is protected by back_mutex. Only access this field when you hold that mutex 70 70 dirty: bool = false, 71 71 72 - unicode: *const vaxis.Unicode, 73 72 should_quit: bool = false, 74 73 75 74 mode: Mode = .{}, ··· 88 87 allocator: std.mem.Allocator, 89 88 argv: []const []const u8, 90 89 env: *const std.process.EnvMap, 91 - unicode: *const vaxis.Unicode, 92 90 opts: Options, 93 91 write_buf: []u8, 94 92 ) !Terminal { ··· 118 116 .front_screen = try Screen.init(allocator, opts.winsize.cols, opts.winsize.rows), 119 117 .back_screen_pri = try Screen.init(allocator, opts.winsize.cols, opts.winsize.rows + opts.scrollback_size), 120 118 .back_screen_alt = try Screen.init(allocator, opts.winsize.cols, opts.winsize.rows), 121 - .unicode = unicode, 122 119 .tab_stops = tabs, 123 120 }; 124 121 } ··· 276 273 277 274 switch (event) { 278 275 .print => |str| { 279 - var iter = self.unicode.graphemeIterator(str); 276 + var iter = vaxis.unicode.graphemeIterator(str); 280 277 while (iter.next()) |grapheme| { 281 278 const gr = grapheme.bytes(str); 282 279 // TODO: use actual instead of .unicode