window: implement wrap and introduce Segment type
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
This commit is contained in:
parent
f3cf7bcfcd
commit
3798a8ede3
4 changed files with 75 additions and 0 deletions
|
@ -22,6 +22,7 @@ cursor_row: usize = 0,
|
||||||
cursor_col: usize = 0,
|
cursor_col: usize = 0,
|
||||||
cursor_vis: bool = false,
|
cursor_vis: bool = false,
|
||||||
|
|
||||||
|
/// true when we measure cells with unicode
|
||||||
unicode: bool = false,
|
unicode: bool = false,
|
||||||
|
|
||||||
mouse_shape: Shape = .default,
|
mouse_shape: Shape = .default,
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
const ziglyph = @import("ziglyph");
|
||||||
|
const WordIterator = ziglyph.WordIterator;
|
||||||
|
const GraphemeIterator = ziglyph.GraphemeIterator;
|
||||||
|
|
||||||
const Screen = @import("Screen.zig");
|
const Screen = @import("Screen.zig");
|
||||||
const Cell = @import("cell.zig").Cell;
|
const Cell = @import("cell.zig").Cell;
|
||||||
|
const Segment = @import("cell.zig").Segment;
|
||||||
const gw = @import("gwidth.zig");
|
const gw = @import("gwidth.zig");
|
||||||
|
|
||||||
const log = std.log.scoped(.window);
|
const log = std.log.scoped(.window);
|
||||||
|
@ -104,6 +108,68 @@ pub fn showCursor(self: Window, col: usize, row: usize) void {
|
||||||
self.screen.cursor_col = col + self.x_off;
|
self.screen.cursor_col = col + self.x_off;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// prints text in the window with simple word wrapping.
|
||||||
|
pub fn wrap(self: Window, segments: []Segment) !void {
|
||||||
|
// pub fn wrap(self: Window, str: []const u8) !void {
|
||||||
|
var row: usize = 0;
|
||||||
|
var col: usize = 0;
|
||||||
|
var wrapped: bool = false;
|
||||||
|
for (segments) |segment| {
|
||||||
|
var word_iter = try WordIterator.init(segment.text);
|
||||||
|
while (word_iter.next()) |word| {
|
||||||
|
// break lines when we need
|
||||||
|
if (isLineBreak(word.bytes)) {
|
||||||
|
row += 1;
|
||||||
|
col = 0;
|
||||||
|
wrapped = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// break lines when we can't fit this word, and the word isn't longer
|
||||||
|
// than our width
|
||||||
|
const word_width = self.gwidth(word.bytes);
|
||||||
|
if (word_width + col >= self.width and word_width < self.width) {
|
||||||
|
row += 1;
|
||||||
|
col = 0;
|
||||||
|
wrapped = true;
|
||||||
|
}
|
||||||
|
// don't print whitespace in the first column, unless we had a hard
|
||||||
|
// break
|
||||||
|
if (col == 0 and std.mem.eql(u8, word.bytes, " ") and wrapped) continue;
|
||||||
|
var iter = GraphemeIterator.init(word.bytes);
|
||||||
|
while (iter.next()) |grapheme| {
|
||||||
|
if (col >= self.width) {
|
||||||
|
row += 1;
|
||||||
|
col = 0;
|
||||||
|
wrapped = true;
|
||||||
|
}
|
||||||
|
const s = grapheme.slice(word.bytes);
|
||||||
|
const w = self.gwidth(s);
|
||||||
|
self.writeCell(col, row, .{
|
||||||
|
.char = .{
|
||||||
|
.grapheme = s,
|
||||||
|
.width = w,
|
||||||
|
},
|
||||||
|
.style = segment.style,
|
||||||
|
.link = segment.link,
|
||||||
|
});
|
||||||
|
col += w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn isLineBreak(str: []const u8) bool {
|
||||||
|
if (std.mem.eql(u8, str, "\r\n")) {
|
||||||
|
return true;
|
||||||
|
} else if (std.mem.eql(u8, str, "\r")) {
|
||||||
|
return true;
|
||||||
|
} else if (std.mem.eql(u8, str, "\n")) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
test "Window size set" {
|
test "Window size set" {
|
||||||
var parent = Window{
|
var parent = Window{
|
||||||
.x_off = 0,
|
.x_off = 0,
|
||||||
|
|
|
@ -7,6 +7,13 @@ pub const Cell = struct {
|
||||||
image: ?Image.Placement = null,
|
image: ?Image.Placement = null,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Segment is a contiguous run of text that has a constant style
|
||||||
|
pub const Segment = struct {
|
||||||
|
text: []const u8,
|
||||||
|
style: Style = .{},
|
||||||
|
link: Hyperlink = .{},
|
||||||
|
};
|
||||||
|
|
||||||
pub const Character = struct {
|
pub const Character = struct {
|
||||||
grapheme: []const u8 = " ",
|
grapheme: []const u8 = " ",
|
||||||
/// width should only be provided when the application is sure the terminal
|
/// width should only be provided when the application is sure the terminal
|
||||||
|
|
|
@ -4,6 +4,7 @@ pub const Options = @import("Options.zig");
|
||||||
const cell = @import("cell.zig");
|
const cell = @import("cell.zig");
|
||||||
pub const Cell = cell.Cell;
|
pub const Cell = cell.Cell;
|
||||||
pub const Style = cell.Style;
|
pub const Style = cell.Style;
|
||||||
|
pub const Segment = cell.Segment;
|
||||||
|
|
||||||
pub const Key = @import("Key.zig");
|
pub const Key = @import("Key.zig");
|
||||||
pub const Mouse = @import("Mouse.zig");
|
pub const Mouse = @import("Mouse.zig");
|
||||||
|
|
Loading…
Reference in a new issue