summaryrefslogtreecommitdiff
path: root/src/modal.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/modal.zig')
-rw-r--r--src/modal.zig21
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