diff options
Diffstat (limited to 'src/modal.zig')
| -rw-r--r-- | src/modal.zig | 21 |
1 files changed, 16 insertions, 5 deletions
diff --git a/src/modal.zig b/src/modal.zig index 742dbc6f..cdc49142 100644 --- a/src/modal.zig +++ b/src/modal.zig @@ -438,7 +438,7 @@ pub fn lineStartOffset(content: []const u8, row: usize) usize { var off: usize = 0; var r: usize = 0; while (r < row) : (r += 1) { - const nl = std.mem.indexOfPos(u8, content, off, "\n") orelse return content.len; + const nl = std.mem.indexOfScalarPos(u8, content, off, '\n') orelse return content.len; off = nl + 1; } return off; @@ -775,15 +775,24 @@ pub fn hxLineEndIdx(text: []const u8, line: usize) usize { /// gap offset -> (row, col) cell pub fn hxPos(text: []const u8, off: usize) Cursor { - const row = hxLineOf(text, off); - return .{ .row = row, .col = @min(off, text.len) - lineStartOffset(text, row) }; + const o = @min(off, text.len); + // The line start is the byte after the last '\n' BEFORE off, which is the + // same number lineStartOffset(text, row) walks the whole prefix to reach — + // one backward scan of a single line instead of a second pass over + // everything above the cursor. On a multi-MB buffer that second pass was + // most of what a keystroke cost. + const s = if (std.mem.lastIndexOfScalar(u8, text[0..o], '\n')) |nl| nl + 1 else 0; + return .{ .row = hxLineOf(text, off), .col = o - s }; } /// (row, col) -> clamped gap offset; col == line length lands ON the '\n' pub fn hxOff(text: []const u8, c: Cursor) usize { const row = @min(c.row, hxLineCount(text) - 1); const s = lineStartOffset(text, row); - return @min(s + c.col, hxLineEndIdx(text, row)); + // hxLineEndIdx(text, row) inlined: it starts by walking to `row` again, + // and we are already standing there + const e = std.mem.indexOfScalarPos(u8, text, s, '\n') orelse text.len; + return @min(s + c.col, e); } pub const WordTarget = enum { @@ -979,7 +988,9 @@ pub fn hxVertTarget(text: []const u8, pos: usize, down: bool, count: usize, goal const line = hxLineOf(text, pos); const nline = if (down) @min(line + @max(1, count), nlines - 1) else line -| @max(1, count); const s = lineStartOffset(text, nline); - return @min(s + goal_col, hxLineEndIdx(text, nline)); + // hxLineEndIdx(text, nline) without its second walk to nline (see hxOff) + const e = std.mem.indexOfScalarPos(u8, text, s, '\n') orelse text.len; + return @min(s + goal_col, e); } /// f/F/t/T target cell. helix find_char: the exclusive (till) search starts |
