fix: Window.printSegments correctly prints all non-trailing whitespace

I'm told it's not unusual in the web world for multiple whitespace
characters to be consumed as a single space. If that is the intention
for `.word` wrap, that's fine with me! If not, this PR correctly
prints all non-trailing whitespace.

I also chose to consume a `\r\n` sequence as intending a single newline,
while all other sequences of `\r` and `\n` should produce multiple newlines.
This commit is contained in:
Rylee Lyman 2024-06-21 15:49:11 -04:00 committed by Tim Culverhouse
parent fcb705adaa
commit 74fb130797

View file

@ -328,92 +328,72 @@ pub fn print(self: Window, segments: []const Segment, opts: PrintOptions) !Print
.word => { .word => {
var col: usize = opts.col_offset; var col: usize = opts.col_offset;
var overflow: bool = false; var overflow: bool = false;
var soft_wrapped: bool = false;
for (segments) |segment| { for (segments) |segment| {
var start: usize = 0; var start: usize = 0;
var i: usize = 0; var tokenizer = std.mem.tokenizeAny(u8, segment.text, "\r\n");
while (i < segment.text.len) : (i += 1) { while (tokenizer.peek() != null) {
// for (segment.text, 0..) |b, i| { const returns = segment.text[start..tokenizer.index];
const b = segment.text[i]; const line = tokenizer.next().?;
const end = switch (b) { start = tokenizer.index;
' ', var i: usize = 0;
'\r', while (i < returns.len) : (i += 1) {
'\n', const b = returns[i];
=> i, if (b == '\r' and i + 1 < returns.len and returns[i + 1] == '\n') {
else => if (i != segment.text.len - 1) continue else i + 1, i += 1;
};
const word = segment.text[start..end];
// find the start of the next word
start = while (i + 1 < segment.text.len) : (i += 1) {
if (segment.text[i + 1] == ' ') continue;
break i + 1;
} else i;
const width = self.gwidth(word);
const non_wsp_width: usize = for (word, 0..) |wb, wi| {
if (wb == '\r' or wb == '\n') {
row += 1;
col = 0;
break width -| wi -| 1;
} }
if (wb != ' ') break width - wi;
} else 0;
if (width + col > self.width and non_wsp_width < self.width) {
// wrap
row += 1; row += 1;
col = 0; col = 0;
soft_wrapped = true;
} }
if (row >= self.height) { var iter = std.mem.tokenizeScalar(u8, line, ' ');
overflow = true; var ws_start: usize = 0;
break; while (iter.peek() != null) {
} const whitespace = line[ws_start..iter.index];
// if we are soft wrapped, (col == 0 and row > 0), then trim const word = iter.next().?;
// leading spaces ws_start = iter.index;
const printed_word = if (soft_wrapped) var j: usize = 0;
std.mem.trimLeft(u8, word, " ") while (j < whitespace.len) : (j += 1) {
else if (opts.commit) self.writeCell(col, row, .{
word; .char = .{
defer soft_wrapped = false; .grapheme = " ",
var iter = self.screen.unicode.graphemeIterator(printed_word); .width = 1,
while (iter.next()) |grapheme| { },
const s = grapheme.bytes(printed_word); .style = segment.style,
const w = self.gwidth(s); .link = segment.link,
if (opts.commit) self.writeCell(col, row, .{ });
.char = .{ col += 1;
.grapheme = s, }
.width = w,
},
.style = segment.style,
.link = segment.link,
});
col += w;
if (col >= self.width) { if (col >= self.width) {
col = 0;
row += 1;
}
const width = self.gwidth(word);
if (width + col > self.width and width < self.width) {
row += 1; row += 1;
col = 0; col = 0;
} }
} if (row >= self.height) {
switch (b) { overflow = true;
' ' => { break;
if (col > 0) { }
if (opts.commit) self.writeCell(col, row, .{
.char = .{ var grapheme_iterator = self.screen.unicode.graphemeIterator(word);
.grapheme = " ", while (grapheme_iterator.next()) |grapheme| {
.width = 1, const s = grapheme.bytes(word);
}, const w = self.gwidth(s);
.style = segment.style, if (opts.commit) self.writeCell(col, row, .{
.link = segment.link, .char = .{
}); .grapheme = s,
col += 1; .width = w,
},
.style = segment.style,
.link = segment.link,
});
col += w;
if (col >= self.width) {
row += 1;
col = 0;
} }
}, }
'\r',
'\n',
=> {
col = 0;
row += 1;
},
else => {},
} }
} }
} }