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:
parent
fcb705adaa
commit
74fb130797
1 changed files with 55 additions and 75 deletions
130
src/Window.zig
130
src/Window.zig
|
@ -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 => {},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue