window: add print method
Add a print method with multiple print options Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
This commit is contained in:
parent
2fab89f2cb
commit
e281a67a43
1 changed files with 123 additions and 46 deletions
169
src/Window.zig
169
src/Window.zig
|
@ -108,54 +108,131 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Options to use when printing Segments to a window
|
||||||
|
pub const PrintOptions = struct {
|
||||||
|
/// vertical offset to start printing at
|
||||||
|
row_offset: usize = 0,
|
||||||
|
|
||||||
|
/// wrap behavior for printing
|
||||||
|
wrap: enum {
|
||||||
|
/// wrap at grapheme boundaries
|
||||||
|
grapheme,
|
||||||
|
/// wrap at word boundaries
|
||||||
|
word,
|
||||||
|
/// stop printing after one line
|
||||||
|
none,
|
||||||
|
} = .grapheme,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// prints segments to the window. returns true if the text overflowed with the
|
||||||
|
/// given wrap strategy and size.
|
||||||
|
pub fn print(self: Window, segments: []Segment, opts: PrintOptions) !bool {
|
||||||
|
var row = opts.row_offset;
|
||||||
|
switch (opts.wrap) {
|
||||||
|
.grapheme => {
|
||||||
|
var col: usize = 0;
|
||||||
|
for (segments) |segment| {
|
||||||
|
var iter = GraphemeIterator.init(segment.text);
|
||||||
|
while (iter.next()) |grapheme| {
|
||||||
|
if (col >= self.width) {
|
||||||
|
row += 1;
|
||||||
|
col = 0;
|
||||||
|
}
|
||||||
|
if (row >= self.height) return true;
|
||||||
|
const s = grapheme.slice(segment.text);
|
||||||
|
if (std.mem.eql(u8, s, "\n")) {
|
||||||
|
row += 1;
|
||||||
|
col = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const w = self.gwidth(s);
|
||||||
|
self.writeCell(col, row, .{
|
||||||
|
.char = .{
|
||||||
|
.grapheme = s,
|
||||||
|
.width = w,
|
||||||
|
},
|
||||||
|
.style = segment.style,
|
||||||
|
.link = segment.link,
|
||||||
|
});
|
||||||
|
col += w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.word => {
|
||||||
|
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 (word.bytes[0] == '\r' or word.bytes[0] == '\n') {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
if (row >= self.height) return 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.none => {
|
||||||
|
var col: usize = 0;
|
||||||
|
for (segments) |segment| {
|
||||||
|
var iter = GraphemeIterator.init(segment.text);
|
||||||
|
while (iter.next()) |grapheme| {
|
||||||
|
if (col >= self.width) return true;
|
||||||
|
const s = grapheme.slice(segment.text);
|
||||||
|
if (std.mem.eql(u8, s, "\n")) return true;
|
||||||
|
const w = self.gwidth(s);
|
||||||
|
self.writeCell(col, row, .{
|
||||||
|
.char = .{
|
||||||
|
.grapheme = s,
|
||||||
|
.width = w,
|
||||||
|
},
|
||||||
|
.style = segment.style,
|
||||||
|
.link = segment.link,
|
||||||
|
});
|
||||||
|
col += w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// prints text in the window with simple word wrapping.
|
/// prints text in the window with simple word wrapping.
|
||||||
pub fn wrap(self: Window, segments: []Segment) !void {
|
pub fn wrap(self: Window, segments: []Segment) !void {
|
||||||
// pub fn wrap(self: Window, str: []const u8) !void {
|
return self.print(segments, .{ .wrap = .word });
|
||||||
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 (word.bytes[0] == '\r' or word.bytes[0] == '\n') {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
test "Window size set" {
|
test "Window size set" {
|
||||||
|
|
Loading…
Reference in a new issue