Fix select motions and mobile line aliases
This commit is contained in:
+67
-26
@@ -1055,6 +1055,8 @@ pub const Client = struct {
|
||||
return;
|
||||
}
|
||||
if (std.mem.eql(u8, text, "s")) {
|
||||
const snap = try self.session.snapshot();
|
||||
try self.session.selectRange(snap.cursor_byte, snap.cursor_byte);
|
||||
self.mode = .select;
|
||||
self.message = "select";
|
||||
self.pending_count = 0;
|
||||
@@ -1070,8 +1072,8 @@ pub const Client = struct {
|
||||
if (std.mem.eql(u8, text, "p")) return self.pasteRegister();
|
||||
if (std.mem.eql(u8, text, "u")) return self.undoEdit();
|
||||
if (std.mem.eql(u8, text, "U")) return self.redoEdit();
|
||||
if (std.mem.eql(u8, text, "0")) return self.applyProtocol("command move_line_start");
|
||||
if (std.mem.eql(u8, text, "$")) return self.applyProtocol("command move_line_end");
|
||||
if (std.mem.eql(u8, text, "H") or std.mem.eql(u8, text, "0") or std.mem.eql(u8, text, "^")) return self.applyProtocol("command move_line_start");
|
||||
if (std.mem.eql(u8, text, "L") or std.mem.eql(u8, text, "$")) return self.applyProtocol("command move_line_end");
|
||||
if (std.mem.eql(u8, text, "%")) return self.jumpToMatch(null);
|
||||
if (std.mem.eql(u8, text, "m")) return self.openPrefix(.match);
|
||||
if (std.mem.eql(u8, text, "g")) return self.openPrefix(.go);
|
||||
@@ -1110,7 +1112,7 @@ pub const Client = struct {
|
||||
.key => |key| switch (key) {
|
||||
.space => try self.insertText(" "),
|
||||
.enter => try self.insertNewlineWithIndent(),
|
||||
.tab => try self.insertText(try self.smartTabText()),
|
||||
.tab => try self.insertText(" "),
|
||||
.escape => {
|
||||
self.mode = .normal;
|
||||
self.message = "normal";
|
||||
@@ -1136,7 +1138,16 @@ pub const Client = struct {
|
||||
self.message = "normal";
|
||||
return;
|
||||
}
|
||||
if (std.mem.eql(u8, text, "%")) return self.jumpToMatch(null);
|
||||
if (std.mem.eql(u8, text, "%")) return self.extendSelectionWithJump(null);
|
||||
if (std.mem.eql(u8, text, "H") or std.mem.eql(u8, text, "0") or std.mem.eql(u8, text, "^")) return self.extendSelectionWithProtocol("command move_line_start");
|
||||
if (std.mem.eql(u8, text, "L") or std.mem.eql(u8, text, "$")) return self.extendSelectionWithProtocol("command move_line_end");
|
||||
if (std.mem.eql(u8, text, "j")) return self.repeatSelectionProtocol("command move_down", self.takeRepeat());
|
||||
if (std.mem.eql(u8, text, "k")) return self.repeatSelectionProtocol("command move_up", self.takeRepeat());
|
||||
if (std.mem.eql(u8, text, "h")) return self.repeatSelectionProtocol("command move_left", self.takeRepeat());
|
||||
if (std.mem.eql(u8, text, "l")) return self.repeatSelectionProtocol("command move_right", self.takeRepeat());
|
||||
if (std.mem.eql(u8, text, "w")) return self.repeatSelectionProtocol("command move_word_forward", self.takeRepeat());
|
||||
if (std.mem.eql(u8, text, "b")) return self.repeatSelectionProtocol("command move_word_back", self.takeRepeat());
|
||||
if (std.mem.eql(u8, text, "e")) return self.repeatSelectionProtocol("command move_word_end", self.takeRepeat());
|
||||
if (std.mem.eql(u8, text, "m")) return self.openPrefix(.match);
|
||||
if (std.mem.eql(u8, text, "g")) return self.openPrefix(.go);
|
||||
if (text.len == 1) {
|
||||
@@ -1153,12 +1164,12 @@ pub const Client = struct {
|
||||
self.mode = .normal;
|
||||
self.message = "normal";
|
||||
},
|
||||
.arrow_left => try self.applyProtocol("command move_left"),
|
||||
.arrow_right => try self.applyProtocol("command move_right"),
|
||||
.arrow_up => try self.applyProtocol("command move_up"),
|
||||
.arrow_down => try self.applyProtocol("command move_down"),
|
||||
.home => try self.applyProtocol("command move_line_start"),
|
||||
.end => try self.applyProtocol("command move_line_end"),
|
||||
.arrow_left => try self.extendSelectionWithProtocol("command move_left"),
|
||||
.arrow_right => try self.extendSelectionWithProtocol("command move_right"),
|
||||
.arrow_up => try self.extendSelectionWithProtocol("command move_up"),
|
||||
.arrow_down => try self.extendSelectionWithProtocol("command move_down"),
|
||||
.home => try self.extendSelectionWithProtocol("command move_line_start"),
|
||||
.end => try self.extendSelectionWithProtocol("command move_line_end"),
|
||||
else => {},
|
||||
},
|
||||
.unknown => self.unknownPrefixOrInput("select"),
|
||||
@@ -1868,6 +1879,13 @@ pub const Client = struct {
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (self.effectiveMode() == .select and text.len == 1) {
|
||||
if (self.objectRangeForKey(text[0])) |range| {
|
||||
try self.session.selectRange(range.start, range.end);
|
||||
self.message = "select";
|
||||
return;
|
||||
} else |_| {}
|
||||
}
|
||||
self.unknownPrefixOrInput("normal");
|
||||
}
|
||||
|
||||
@@ -2157,20 +2175,6 @@ pub const Client = struct {
|
||||
try self.insertText(text.items);
|
||||
}
|
||||
|
||||
fn smartTabText(self: *Client) ![]const u8 {
|
||||
const snap = try self.session.snapshot();
|
||||
const line_start = currentLineStart(snap.bytes, snap.cursor_byte);
|
||||
if (line_start < snap.bytes.len and snap.bytes[line_start] == '\t') return "\t";
|
||||
var i: usize = 0;
|
||||
while (i < snap.bytes.len) {
|
||||
if (snap.bytes[i] == '\t') return "\t";
|
||||
while (i < snap.bytes.len and snap.bytes[i] != '\n') : (i += 1) {}
|
||||
if (i < snap.bytes.len) i += 1;
|
||||
while (i < snap.bytes.len and snap.bytes[i] == ' ') : (i += 1) {}
|
||||
}
|
||||
return " ";
|
||||
}
|
||||
|
||||
fn currentLineStart(bytes: []const u8, cursor_byte: usize) usize {
|
||||
var start = @min(cursor_byte, bytes.len);
|
||||
while (start > 0 and bytes[start - 1] != '\n') start -= 1;
|
||||
@@ -2202,6 +2206,29 @@ pub const Client = struct {
|
||||
while (i < repeat) : (i += 1) try self.applyProtocol(line);
|
||||
}
|
||||
|
||||
fn extendSelectionWithProtocol(self: *Client, line: []const u8) !void {
|
||||
const before = try self.session.snapshot();
|
||||
const anchor = if (before.selection) |selection| selection.anchor else before.cursor_byte;
|
||||
try self.applyProtocol(line);
|
||||
const after = try self.session.snapshot();
|
||||
try self.session.selectRange(@min(anchor, after.cursor_byte), @max(anchor, after.cursor_byte));
|
||||
self.message = "select";
|
||||
}
|
||||
|
||||
fn repeatSelectionProtocol(self: *Client, line: []const u8, repeat: usize) !void {
|
||||
var i: usize = 0;
|
||||
while (i < repeat) : (i += 1) try self.extendSelectionWithProtocol(line);
|
||||
}
|
||||
|
||||
fn extendSelectionWithJump(self: *Client, delimiter: ?u8) !void {
|
||||
const before = try self.session.snapshot();
|
||||
const anchor = if (before.selection) |selection| selection.anchor else before.cursor_byte;
|
||||
try self.jumpToMatch(delimiter);
|
||||
const after = try self.session.snapshot();
|
||||
try self.session.selectRange(@min(anchor, after.cursor_byte), @max(anchor, after.cursor_byte));
|
||||
self.message = "select";
|
||||
}
|
||||
|
||||
fn repeatMutatingProtocol(self: *Client, line: []const u8, repeat: usize) !void {
|
||||
var i: usize = 0;
|
||||
while (i < repeat) : (i += 1) try self.applyMutatingProtocol(line);
|
||||
@@ -2417,9 +2444,13 @@ fn appendEditorLine(
|
||||
try out.append(allocator, '\n');
|
||||
return;
|
||||
}
|
||||
const horizontal_scroll = if (is_cursor_line and cursor_col >= content_width)
|
||||
cursor_col - content_width + 1
|
||||
else
|
||||
0;
|
||||
if (is_cursor_line) try out.appendSlice(allocator, ansi_current_line);
|
||||
try out.appendSlice(allocator, ansi_text);
|
||||
try appendEditorCells(allocator, out, line, line_start_byte, content_width, is_cursor_line, cursor_col, cursor_byte, selection);
|
||||
try appendEditorCells(allocator, out, line, line_start_byte, content_width, is_cursor_line, cursor_col, cursor_byte, selection, horizontal_scroll);
|
||||
try out.appendSlice(allocator, ansi_reset);
|
||||
try out.append(allocator, '\n');
|
||||
}
|
||||
@@ -2458,11 +2489,19 @@ fn appendEditorCells(
|
||||
cursor_col: usize,
|
||||
cursor_byte: usize,
|
||||
selection: ?session_mod.Selection,
|
||||
horizontal_scroll: usize,
|
||||
) !void {
|
||||
var i: usize = 0;
|
||||
var source_col: usize = 0;
|
||||
var visual_col: usize = 0;
|
||||
var drew_cursor = false;
|
||||
while (i < bytes.len and source_col < horizontal_scroll) {
|
||||
const len = std.unicode.utf8ByteSequenceLength(bytes[i]) catch 1;
|
||||
const end = @min(bytes.len, i + len);
|
||||
const width = @max(@as(usize, 1), session_mod.cellWidth(bytes[i..end]));
|
||||
source_col += width;
|
||||
i = end;
|
||||
}
|
||||
while (i < bytes.len and visual_col < max_cells) {
|
||||
const len = std.unicode.utf8ByteSequenceLength(bytes[i]) catch 1;
|
||||
const end = @min(bytes.len, i + len);
|
||||
@@ -4178,12 +4217,14 @@ test "regular: select mode object grammar selects word line indent parameter and
|
||||
try client.handleInput("j");
|
||||
try client.handleInput("w");
|
||||
try client.handleInput("s");
|
||||
try client.handleInput("m");
|
||||
try client.handleInput("w");
|
||||
var snap = try client.session.snapshot();
|
||||
try std.testing.expectEqualStrings("alpha", snap.bytes[snap.selection.?.anchor..snap.selection.?.cursor]);
|
||||
|
||||
try client.handleInput("n");
|
||||
try client.handleInput("s");
|
||||
try client.handleInput("m");
|
||||
try client.handleInput("l");
|
||||
snap = try client.session.snapshot();
|
||||
try std.testing.expectEqualStrings(" alpha(beta, gamma);\n", snap.bytes[snap.selection.?.anchor..snap.selection.?.cursor]);
|
||||
@@ -5100,5 +5141,5 @@ test "regular: insert Enter copies current line indent and Tab follows tab-inden
|
||||
try tabs.handleTraceLine("key tab");
|
||||
try tabs.handleInput("x");
|
||||
snap = try tabs.session.snapshot();
|
||||
try std.testing.expectEqualStrings("\titem\tx", snap.bytes);
|
||||
try std.testing.expectEqualStrings("\titem x", snap.bytes);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user