diff options
Diffstat (limited to 'src/draw.zig')
| -rw-r--r-- | src/draw.zig | 73 |
1 files changed, 39 insertions, 34 deletions
diff --git a/src/draw.zig b/src/draw.zig index 2d757635..280b5e90 100644 --- a/src/draw.zig +++ b/src/draw.zig @@ -712,9 +712,9 @@ fn joinPaneTag(p: *Pardes, s: *Surface, arena: std.mem.Allocator, pane: *Pane, r if (r.w <= TAG_TEXT_INSET) return paintPaneTag(p, s, arena, pane, r, id, active, capacity); const chrome = p.chromeTheme(); const region = s.region(.tag, id).?; - const tag = try tagline.tagText(p, arena, pane); + const tag = (try tagline.shownTag(p, arena, pane)).text; const rows = pane.tag_rows; - // As wide as the widest line it shows, and never narrower than its + // As wide as the widest row it shows, and never narrower than its // viewport. var widest: usize = 0; var split = std.mem.splitScalar(u8, tag, '\n'); @@ -858,8 +858,10 @@ pub fn paintPaneTag(p: *Pardes, s: *Surface, arena: std.mem.Allocator, pane: *Pa // A row per line shown, from `tag_top`: the tag's first line carries // the prefix, the rest are the tag's own text alone. const top = pane.tag_top; + // Its lines wrapped at its width (tagline.shownTag): a row per row shown. + const shown = try tagline.shownTag(p, arena, pane); var lines: [MAX_TAG_ROWS][]const u8 = @splat(""); - var split = std.mem.splitScalar(u8, whole, '\n'); + var split = std.mem.splitScalar(u8, shown.text, '\n'); for (0..top) |_| _ = split.next(); for (lines[0..rows]) |*line| line.* = split.next() orelse ""; // The keyboard's caret, as a row and a byte offset in that row's @@ -868,42 +870,45 @@ pub fn paintPaneTag(p: *Pardes, s: *Surface, arena: std.mem.Allocator, pane: *Pa const Caret = struct { row: usize, at: usize }; const caret: ?Caret = if (!active) null - else if (pane.prompt == .name) - .{ .row = 0, .at = @min(lines[0].len, @as(usize, @intCast(@max(0, pane.input.cur_col)))) } - else if (pane.focus == .tag and pane.prompt == .none and pane.tag.cur_row >= top and pane.tag.cur_row < top + rows) caret: { - const row: usize = @intCast(pane.tag.cur_row - top); - break :caret .{ .row = row, .at = @min(lines[row].len, @as(usize, @intCast(@max(0, pane.tag.cur_col)))) }; + else if (pane.prompt == .name) caret: { + // A drafted name is the prefix: its caret is on row 0 of the tag, + // the rows it wrapped onto included. + const at = modal.positionAt(shown.text, shown.fromReal(@intCast(@max(0, pane.input.cur_col)))); + if (at.row < top or at.row >= top + rows) break :caret null; + break :caret .{ .row = at.row - top, .at = @min(lines[at.row - top].len, at.col) }; + } + else if (pane.focus == .tag and pane.prompt == .none) caret: { + const real = modal.offsetAt(whole, .{ .row = @intCast(@max(0, pane.tag.cur_row)), .col = @intCast(@max(0, pane.tag.cur_col)) }); + const at = modal.positionAt(shown.text, shown.fromReal(real)); + if (at.row < top or at.row >= top + rows) break :caret null; + const row: usize = at.row - top; + break :caret .{ .row = row, .at = @min(lines[row].len, at.col) }; } else null; - if (caret) |at| { - const line = lines[at.row]; - const col = panes.File.rawDisplayCol(line, at.at); - var scroll: usize = pane.tag_scroll; - if (col < scroll) scroll = col; - if (col >= scroll + capacity) scroll = col - capacity + 1; - var raw = panes.File.rawAtDisplay(line, scroll); - scroll = panes.File.rawDisplayCol(line, raw); - if (col >= scroll + capacity) { - raw = modal.nextGrapheme(line, raw); - scroll = panes.File.rawDisplayCol(line, raw); - } - // A line past a u16 of columns keeps its caret off the band. - pane.tag_scroll = @intCast(@min(scroll, std.math.maxInt(u16))); - } else if (pane.focus != .tag) pane.tag_scroll = 0; + // Its rows are wrapped to fit: a pane tag never scrolls sideways. + _ = capacity; + pane.tag_scroll = 0; for (lines[0..rows], 0..) |line, row| { // The scroll is the caret's line's: a shorter row shows nothing. const start = @min(line.len, panes.File.rawAtDisplay(line, pane.tag_scroll)); _ = s.print(tx, tag_y + @as(u16, @intCast(row)), tw, line[start..], tag_style); } - const tag = lines[0]; - if (top == 0) if (tagTintRange(pane, tag, prefix_len)) |name| { - const lo = @max(name.lo, panes.File.rawAtDisplay(tag, pane.tag_scroll)); - const hi = @min(name.hi, tag.len); - if (lo < hi) { - var col = panes.File.rawDisplayCol(tag, lo) -| pane.tag_scroll; - const end = panes.File.rawDisplayCol(tag, hi) -| pane.tag_scroll; - const name_fg = if (active and p.settings.focus_tint) chrome.tag_active_name_fg else chrome.tag_name_fg; + // The name's tint, in the tag's first line, over whichever rows it + // wrapped onto. + const first_line = whole[0 .. std.mem.indexOfScalar(u8, whole, '\n') orelse whole.len]; + if (tagTintRange(pane, first_line, prefix_len)) |name| if (name.lo < name.hi) { + const name_fg = if (active and p.settings.focus_tint) chrome.tag_active_name_fg else chrome.tag_name_fg; + const a = modal.positionAt(shown.text, shown.fromReal(name.lo)); + const b = modal.positionAt(shown.text, shown.fromReal(@min(name.hi, first_line.len))); + var row = @max(a.row, top); + while (row <= b.row and row < top + rows) : (row += 1) { + const line = lines[row - top]; + const from = if (row == a.row) a.col else 0; + const to = if (row == b.row) b.col else line.len; + var col = panes.File.rawDisplayCol(line, @min(from, line.len)); + const end = panes.File.rawDisplayCol(line, @min(to, line.len)); + const y = tag_y + @as(u16, @intCast(row - top)); while (col < end and col < tw) : (col += 1) - s.at(tx + @as(u16, @intCast(col)), tag_y).style.fg = .{ .rgb = name_fg }; + s.at(tx + @as(u16, @intCast(col)), y).style.fg = .{ .rgb = name_fg }; } }; if (p.look_hover_preview) |preview| { @@ -921,8 +926,8 @@ pub fn paintPaneTag(p: *Pardes, s: *Surface, arena: std.mem.Allocator, pane: *Pa const lo = @min(range.anchor, range.head); const hi = @max(range.anchor, range.head); if (modal.nextGrapheme(whole, lo) >= hi) continue; - const first = modal.positionAt(whole, lo); - const last = modal.positionAt(whole, hi); + const first = modal.positionAt(shown.text, shown.fromReal(lo)); + const last = modal.positionAt(shown.text, shown.fromReal(hi)); var row = @max(first.row, top); while (row <= last.row and row < top + rows) : (row += 1) { const line = lines[row - top]; |
