Compare commits

...
Sign in to create a new pull request.

25 commits

Author SHA1 Message Date
b5e1cce4b3
fix: rebase left overs 2025-12-02 16:30:45 +01:00
a779c590bd
refactor: clean-up duplicate commands overlay_toggle_panel/_inputivew 2025-12-02 16:28:43 +01:00
f964296051
fix: extend the correct end of the selection in move_cursor_prev_word_start_extend 2025-12-02 16:24:21 +01:00
c65a4af30a
fix: helix g g command keybind 2025-12-02 16:24:20 +01:00
0ca1d372f6
fix: use correct direction for selection in move_cursor_prev_word_start 2025-12-02 16:24:20 +01:00
d410fabf1b
fix: don't stomp on existing selection when entering helix SEL mode 2025-12-02 16:24:20 +01:00
eba444c6fc
refactor: eliminate redundent healper function 2025-12-02 16:24:20 +01:00
faa54afb8b
refactor: re-write all helix commands to use bound self parameter
This makes implementing commands in helix mode almost identical to
implementing them inside the editor directly.
2025-12-02 16:24:20 +01:00
839f1b8e38
fix: init all cursors in init_helix_select_mode 2025-12-02 16:24:20 +01:00
2b27ef3332
refactor: use orelse in CurSel.to_selection 2025-12-02 16:24:20 +01:00
0cba416ec4
refactor: move goto_line_vim into mode specific commands files 2025-12-02 16:24:20 +01:00
5f242d6cf2
refactor: mark helix mode keybindings that are not implemented 2025-12-02 16:24:20 +01:00
66f8819a19
refactor: move more mode specific commands to helix & vim 2025-12-02 16:24:20 +01:00
8d8f4b82cb
refactor: completely remove inclusive selection mode
Having inclusive mode change a few critical functions behind the sceans
is not a good way to share functionality. Basically every function is
broken in one or the other mode. So we remove it entirely and instead
will rely on different functions for different behaviors.
2025-12-02 16:24:16 +01:00
dd88be893e
refactor: add explicit command for initializing helix select mode 2025-12-02 16:22:38 +01:00
c65583b1ae
fix: remove typo 2025-12-02 16:22:38 +01:00
0ab260a165
refactor: reduce duplication of context getting code in helix mode 2025-12-02 16:22:38 +01:00
7bf532bdfd
fix: make helix move_prev_word_start an exact match to real helix 2025-12-02 16:22:38 +01:00
1755ecb3dd
refactor: simplify disable_selection to never move the cursor 2025-12-02 16:22:38 +01:00
a15ceeb4a7
refactor: split is_not_word_char into char_class and CharClass 2025-12-02 16:22:38 +01:00
1615cd37e8
refactor: add Selection.from_cursor_inclusive 2025-12-02 16:22:38 +01:00
bb53ba0fc1
refactor: add Cursor char_at, char_left/_right, test_left/_right functions 2025-12-02 16:22:37 +01:00
3db11a43c9
Reapply "fix: build fix after rebase/merge"
This reverts commit fd9fa4ee8f.
2025-12-02 16:22:06 +01:00
77b2afdd0c
Reapply "Fixed selection extensions with new helper functions"
This reverts commit 989557fb6d.
2025-12-02 16:21:58 +01:00
7410435c4f
Reapply "Initial attempt to fix prev and next word movement"
This reverts commit 6f1806cd95.
2025-12-02 16:21:46 +01:00
13 changed files with 773 additions and 697 deletions

View file

@ -193,10 +193,39 @@ pub fn egc_at(self: *const Self, root: Buffer.Root, metrics: Metrics) error{NotF
return root.egc_at(self.row, self.col, metrics); return root.egc_at(self.row, self.col, metrics);
} }
pub fn char_at(self: *const Self, root: Buffer.Root, metrics: Metrics) []const u8 {
const char, _, _ = root.egc_at(self.row, self.col, metrics) catch return &.{};
return char;
}
pub fn char_left(self: *const Self, root: Buffer.Root, metrics: Metrics) []const u8 {
var tmp = self.*;
tmp.move_left(root, metrics) catch return &.{};
return tmp.char_at(root, metrics);
}
pub fn char_right(self: *const Self, root: Buffer.Root, metrics: Metrics) []const u8 {
var tmp = self.*;
tmp.move_right(root, metrics) catch return &.{};
return tmp.char_at(root, metrics);
}
pub fn test_at(self: *const Self, root: Buffer.Root, pred: *const fn (c: []const u8) bool, metrics: Metrics) bool { pub fn test_at(self: *const Self, root: Buffer.Root, pred: *const fn (c: []const u8) bool, metrics: Metrics) bool {
return root.test_at(pred, self.row, self.col, metrics); return root.test_at(pred, self.row, self.col, metrics);
} }
pub fn test_left(self: *const Self, root: Buffer.Root, pred: *const fn (c: []const u8) bool, metrics: Metrics) bool {
var tmp = self.*;
tmp.move_left(root, metrics) catch return false;
return root.test_at(pred, tmp.row, tmp.col, metrics);
}
pub fn test_right(self: *const Self, root: Buffer.Root, pred: *const fn (c: []const u8) bool, metrics: Metrics) bool {
var tmp = self.*;
tmp.move_right(root, metrics) catch return false;
return root.test_at(pred, tmp.row, tmp.col, metrics);
}
pub fn write(self: *const Self, writer: *std.Io.Writer) !void { pub fn write(self: *const Self, writer: *std.Io.Writer) !void {
try cbor.writeValue(writer, .{ try cbor.writeValue(writer, .{
self.row, self.row,

View file

@ -9,8 +9,6 @@ end: Cursor = Cursor{},
const Self = @This(); const Self = @This();
pub const Style = enum { normal, inclusive };
pub inline fn eql(self: Self, other: Self) bool { pub inline fn eql(self: Self, other: Self) bool {
return self.begin.eql(other.begin) and self.end.eql(other.end); return self.begin.eql(other.begin) and self.end.eql(other.end);
} }
@ -19,6 +17,12 @@ pub fn from_cursor(cursor: *const Cursor) Self {
return .{ .begin = cursor.*, .end = cursor.* }; return .{ .begin = cursor.*, .end = cursor.* };
} }
pub fn from_cursor_inclusive(cursor: *const Cursor, root: Buffer.Root, metrics: Buffer.Metrics) Self {
var sel: Self = .{ .begin = cursor.*, .end = cursor.* };
sel.end.move_right(root, metrics) catch {};
return sel;
}
pub fn from_pos(sel: Self, root: Buffer.Root, metrics: Buffer.Metrics) Self { pub fn from_pos(sel: Self, root: Buffer.Root, metrics: Buffer.Metrics) Self {
return .{ return .{
.begin = .{ .begin = .{

View file

@ -27,7 +27,6 @@
["ctrl+shift+p", "open_command_palette"], ["ctrl+shift+p", "open_command_palette"],
["ctrl+shift+q", "quit_without_saving"], ["ctrl+shift+q", "quit_without_saving"],
["ctrl+shift+f", "find_in_files"], ["ctrl+shift+f", "find_in_files"],
["ctrl+shift+l", "toggle_panel"],
["alt+shift+p", "open_command_palette"], ["alt+shift+p", "open_command_palette"],
["alt+n", "goto_next_file_or_diagnostic"], ["alt+n", "goto_next_file_or_diagnostic"],
["alt+p", "goto_prev_file_or_diagnostic"], ["alt+p", "goto_prev_file_or_diagnostic"],
@ -410,8 +409,6 @@
["ctrl+shift+p", "palette_menu_down"], ["ctrl+shift+p", "palette_menu_down"],
["ctrl+shift+q", "quit_without_saving"], ["ctrl+shift+q", "quit_without_saving"],
["ctrl+shift+w", "close_file_without_saving"], ["ctrl+shift+w", "close_file_without_saving"],
["ctrl+shift+l", "overlay_toggle_panel"],
["ctrl+shift+i", "overlay_toggle_inputview"],
["alt+shift+p", "palette_menu_down"], ["alt+shift+p", "palette_menu_down"],
["alt+p", "palette_menu_up"], ["alt+p", "palette_menu_up"],
["alt+l", "toggle_panel"], ["alt+l", "toggle_panel"],

View file

@ -8,7 +8,6 @@
"name": "NOR", "name": "NOR",
"line_numbers": "relative", "line_numbers": "relative",
"cursor": "block", "cursor": "block",
"selection": "inclusive",
"press": [ "press": [
["ctrl+b", "move_scroll_page_up"], ["ctrl+b", "move_scroll_page_up"],
["ctrl+f", "move_scroll_page_down"], ["ctrl+f", "move_scroll_page_down"],
@ -22,29 +21,29 @@
["ctrl+i", "jump_forward"], ["ctrl+i", "jump_forward"],
["ctrl+o", "jump_back"], ["ctrl+o", "jump_back"],
["ctrl+s", "save_selection"], ["ctrl+s", "save_selection"],
["ctrl+a", "increment"], ["ctrl+a", "increment-NOIMPL"],
["ctrl+x", "decrement"], ["ctrl+x", "decrement-NOIMPL"],
["ctrl+^", "open_previous_file"], ["ctrl+^", "open_previous_file"],
["ctrl+w v", "add_split"], ["ctrl+w v", "add_split"],
["ctrl+w c", "toggle_centered_view"], ["ctrl+w c", "toggle_centered_view"],
["ctrl+w h", "goto_left_split"], ["ctrl+w h", "goto_left_split-NOIMPL"],
["ctrl+w l", "goto_right_split"], ["ctrl+w l", "goto_right_split-NOIMPL"],
["ctrl+w H", "swap_left_split"], ["ctrl+w H", "swap_left_split-NOIMPL"],
["ctrl+w L", "swap_right_split"], ["ctrl+w L", "swap_right_split-NOIMPL"],
["ctrl+w F", "goto_file_split"], ["ctrl+w F", "goto_file_split-NOIMPL"],
["ctrl+w q", "close_split"], ["ctrl+w q", "close_split"],
["ctrl+w o", "close_other_splits"], ["ctrl+w o", "close_other_splits-NOIMPL"],
["alt+.", "repeat_last_motion"], ["alt+.", "repeat_last_motion-NOIMPL"],
["alt+d", "delete_backward"], ["alt+d", "delete_backward"],
["alt+c", "change_backward_helix"], ["alt+c", "change_backward_helix-NOIMPL"],
["alt+s", "split_selection_on_newline"], ["alt+s", "split_selection_on_newline"],
["alt+-", "merge_selections"], ["alt+-", "merge_selections-NOIMPL"],
["alt+_", "merge_consecutive_selections"], ["alt+_", "merge_consecutive_selections-NOIMPL"],
["alt+;", "flip_selections"], ["alt+;", "flip_selections-NOIMPL"],
["alt+o", "expand_selection"], ["alt+o", "expand_selection"],
["alt+up", "expand_selection"], ["alt+up", "expand_selection"],
["alt+kp_up", "expand_selection"], ["alt+kp_up", "expand_selection"],
@ -58,22 +57,23 @@
["alt+right", "select_next_sibling"], ["alt+right", "select_next_sibling"],
["alt+kp_right", "select_next_sibling"], ["alt+kp_right", "select_next_sibling"],
["alt+e", "move_parent_node_end"], ["alt+e", "move_parent_node_end-NOIMPL"],
["alt+b", "move_parent_node_start"], ["alt+b", "move_parent_node_start-NOIMPL"],
["alt+a", "select_all_siblings"], ["alt+a", "select_all_siblings-NOIMPL"],
["alt+x", "shrink_to_line_bounds"], ["alt+x", "shrink_to_line_bounds-NOIMPL"],
["alt+u", "undo"], ["alt+u", "undo"],
["alt+,", "remove_primary_selection"], ["alt+,", "remove_primary_selection-NOIMPL"],
["alt+C", "copy_selection_on_next_line"], ["alt+C", "copy_selection_on_next_line-NOIMPL"],
["alt+I", "select_all_children"], ["alt+I", "select_all_children-NOIMPL"],
["alt+shift+down", "select_all_children"], ["alt+shift+down", "select_all_children-NOIMPL"],
["alt+U", "redo"], ["alt+U", "redo"],
["alt+J", "join_selections_space"], ["alt+J", "join_selections_space-NOIMPL"],
["alt+(", "rotate_selection_contents_backward"], ["alt+)", "rotate_selection_contents_forward"], ["alt+(", "rotate_selection_contents_backward-NOIMPL"],
["alt+|", "shell_pipe_to"], ["alt+)", "rotate_selection_contents_forward-NOIMPL"],
["alt+!", "shell_append_output"], ["alt+|", "shell_pipe_to-NOIMPL"],
["alt+!", "shell_append_output-NOIMPL"],
["F", "move_to_char", "select_to_char_left_helix"], ["F", "move_to_char", "select_to_char_left_helix"],
["T", "move_to_char", "select_till_char_left_helix"], ["T", "move_to_char", "select_till_char_left_helix"],
@ -93,10 +93,10 @@
["C", "add_cursor_down"], ["C", "add_cursor_down"],
["S", "split_selection"], ["S", "split_selection"],
["X", "extend_to_line_bounds"], ["X", "extend_to_line_bounds-NOIMPL"],
["?", "rfind"], ["?", "rfind-NOIMPL"],
["N", "goto_prev_match"], ["N", "goto_prev_match"],
["*", "search_selection"], ["*", "search_selection-NOIMPL"],
["~", "switch_case"], ["~", "switch_case"],
["`", "to_lower"], ["`", "to_lower"],
@ -110,20 +110,20 @@
[">", "indent"], [">", "indent"],
["<", "unindent"], ["<", "unindent"],
["J", "join_selections"], ["J", "join_selections-NOIMPL"],
[":", "open_command_palette"], [":", "open_command_palette"],
["&", "align_selections"], ["&", "align_selections-NOIMPL"],
["_", "trim_selections"], ["_", "trim_selections-NOIMPL"],
["(", "rotate_selections_backward"], ["(", "rotate_selections_backward-NOIMPL"],
[")", "rotate_selections_forward"], [")", "rotate_selections_forward-NOIMPL"],
["\"", "select_register"], ["\"", "select_register-NOIMPL"],
["|", "shell_pipe"], ["|", "shell_pipe-NOIMPL"],
["!", "shell_insert_output"], ["!", "shell_insert_output-NOIMPL"],
["$", "shell_keep_pipe"], ["$", "shell_keep_pipe-NOIMPL"],
["h", "move_left"], ["h", "move_left"],
["j", "move_down"], ["j", "move_down"],
@ -138,7 +138,7 @@
["v", "enter_mode", "select"], ["v", "enter_mode", "select"],
["G", "goto_line"], ["G", "goto_line"],
["g g", "goto_line_vim"], ["g g", "goto_line_helix"],
["g e", "move_buffer_end"], ["g e", "move_buffer_end"],
["g f", "goto_file"], ["g f", "goto_file"],
["g h", "move_begin"], ["g h", "move_begin"],
@ -281,8 +281,7 @@
"name": "SEL", "name": "SEL",
"line_numbers": "relative", "line_numbers": "relative",
"cursor": "block", "cursor": "block",
"selection": "inclusive", "init_command": ["init_helix_select_mode"],
"init_command": ["enable_selection"],
"press": [ "press": [
["ctrl+b", "select_page_up"], ["ctrl+b", "select_page_up"],
@ -431,9 +430,9 @@
["kp_end", "extend_to_line_end"], ["kp_end", "extend_to_line_end"],
["v", "enter_mode", "normal"], ["v", "enter_mode", "normal"],
["g g", "goto_line_vim"], ["g g", "goto_line_helix"],
["g e", "move_buffer_end"], ["g e", "move_buffer_end"],
["g f", "goto_file"], ["g f", "goto_file-NOIMPL"],
["g h", "move_begin"], ["g h", "move_begin"],
["g l", "select_end"], ["g l", "select_end"],
["g s", "smart_move_begin"], ["g s", "smart_move_begin"],
@ -441,16 +440,16 @@
["g y", "goto_type_definition"], ["g y", "goto_type_definition"],
["g r", "references"], ["g r", "references"],
["g i", "goto_implementation"], ["g i", "goto_implementation"],
["g t", "goto_window_top"], ["g t", "goto_window_top-NOIMPL"],
["g c", "goto_window_center"], ["g c", "goto_window_center-NOIMPL"],
["g b", "goto_window_bottom"], ["g b", "goto_window_bottom-NOIMPL"],
["g a", "open_previous_file"], ["g a", "open_previous_file"],
["g m", "open_most_recent_file"], ["g m", "open_most_recent_file"],
["g n", "goto_next_buffer"], ["g n", "goto_next_buffer-NOIMPL"],
["g p", "goto_previous_buffer"], ["g p", "goto_previous_buffer-NOIMPL"],
["g k", "goto_previous_buffer"], ["g k", "goto_previous_buffer-NOIMPL"],
["g .", "goto_last_modification"], ["g .", "goto_last_modification-NOIMPL"],
["g w", "goto_word"], ["g w", "goto_word-NOIMPL"],
["g D", "goto_declaration"], ["g D", "goto_declaration"],
["i", "enter_mode", "insert"], ["i", "enter_mode", "insert"],
@ -460,8 +459,8 @@
["d", ["cut"], ["enter_mode", "normal"]], ["d", ["cut"], ["enter_mode", "normal"]],
["c", ["enter_mode", "insert"], ["cut"]], ["c", ["enter_mode", "insert"], ["cut"]],
["s", "select_regex"], ["s", "select_regex-NOIMPL"],
[";", "collapse_selections"], [";", "collapse_selections-NOIMPL"],
["x", "extend_line_below"], ["x", "extend_line_below"],
@ -472,32 +471,32 @@
["m r", "match", "surround_replace"], ["m r", "match", "surround_replace"],
["m s", "match", "surround_add"], ["m s", "match", "surround_add"],
["[ D", "goto_first_diag"], ["[ D", "goto_first_diag-NOIMPL"],
["[ G", "goto_first_change"], ["[ G", "goto_first_change-NOIMPL"],
["[ T", "goto_prev_test"], ["[ T", "goto_prev_test-NOIMPL"],
["[ d", "goto_prev_diagnostic"], ["[ d", "goto_prev_diagnostic"],
["[ g", "goto_prev_change"], ["[ g", "goto_prev_change-NOIMPL"],
["[ f", "goto_prev_function"], ["[ f", "goto_prev_function-NOIMPL"],
["[ t", "goto_prev_class"], ["[ t", "goto_prev_class-NOIMPL"],
["[ a", "goto_prev_parameter"], ["[ a", "goto_prev_parameter-NOIMPL"],
["[ c", "goto_prev_comment"], ["[ c", "goto_prev_comment-NOIMPL"],
["[ e", "goto_prev_entry"], ["[ e", "goto_prev_entry-NOIMPL"],
["[ p", "goto_prev_paragraph"], ["[ p", "goto_prev_paragraph-NOIMPL"],
["[ space", "add_newline_above"], ["[ space", "add_newline_above-NOIMPL"],
["] d", "goto_last_diag"], ["] d", "goto_last_diag-NOIMPL"],
["] g", "goto_last_change"], ["] g", "goto_last_change-NOIMPL"],
["] t", "goto_next_test"], ["] t", "goto_next_test-NOIMPL"],
["] d", "goto_next_diagnostic"], ["] d", "goto_next_diagnostic"],
["] g", "goto_next_change"], ["] g", "goto_next_change-NOIMPL"],
["] f", "goto_next_function"], ["] f", "goto_next_function-NOIMPL"],
["] t", "goto_next_class"], ["] t", "goto_next_class-NOIMPL"],
["] a", "goto_next_parameter"], ["] a", "goto_next_parameter-NOIMPL"],
["] c", "goto_next_comment"], ["] c", "goto_next_comment-NOIMPL"],
["] e", "goto_next_entry"], ["] e", "goto_next_entry-NOIMPL"],
["] p", "goto_next_paragraph"], ["] p", "goto_next_paragraph-NOIMPL"],
["] space", "add_newline_below"], ["] space", "add_newline_below-NOIMPL"],
["/", "find"], ["/", "find"],
["n", "goto_next_match"], ["n", "goto_next_match"],
@ -507,35 +506,35 @@
["y", ["copy_helix"], ["enter_mode", "normal"]], ["y", ["copy_helix"], ["enter_mode", "normal"]],
["q", "record_macro"], ["q", "record_macro-NOIMPL"],
["Q", "replay_macro"], ["Q", "replay_macro-NOIMPL"],
["=", "format_selections"], ["=", "format_selections-NOIMPL"],
[",", "keep_primary_selection"], [",", "keep_primary_selection-NOIMPL"],
["escape", "enter_mode", "normal"], ["escape", "enter_mode", "normal"],
["space F", "file_picker_in_current_directory"], ["space F", "file_picker_in_current_directory-NOIMPL"],
["space S", "workspace_symbol_picker"], ["space S", "workspace_symbol_picker-NOIMPL"],
["space D", "workspace_diagnostics_picker"], ["space D", "workspace_diagnostics_picker-NOIMPL"],
["space P", "system_paste"], ["space P", "system_paste"],
["space R", "replace_selections_with_clipboard"], ["space R", "replace_selections_with_clipboard"],
["space ?", "open_command_palette"], ["space ?", "open_command_palette"],
["space f", "find_file"], ["space f", "find_file"],
["space b", "switch_buffers"], ["space b", "switch_buffers"],
["space j", "jumplist_picker"], ["space j", "jumplist_picker-NOIMPL"],
["space s", "symbol_picker"], ["space s", "symbol_picker-NOIMPL"],
["space d", "show_diagnostics"], ["space d", "show_diagnostics"],
["space a", "code_action"], ["space a", "code_action-NOIMPL"],
["space '", "last_picker"], ["space '", "last_picker-NOIMPL"],
["space y", "copy"], ["space y", "copy"],
["space p", "system_paste_after"], ["space p", "system_paste_after-NOIMPL"],
["space /", "find_in_files"], ["space /", "find_in_files"],
["space k", "hover"], ["space k", "hover"],
["space r", "rename_symbol"], ["space r", "rename_symbol"],
["space h", "select_references_to_symbol_under_cursor"], ["space h", "select_references_to_symbol_under_cursor-NOIMPL"],
["space c", "toggle_comment"], ["space c", "toggle_comment"],
["0", "add_integer_argument_digit", 0], ["0", "add_integer_argument_digit", 0],

View file

@ -9,7 +9,6 @@
"name": "NORMAL", "name": "NORMAL",
"line_numbers": "relative", "line_numbers": "relative",
"cursor": "block", "cursor": "block",
"selection": "normal",
"press": [ "press": [
["b", "move_word_left_vim"], ["b", "move_word_left_vim"],
["w", "move_word_right_vim"], ["w", "move_word_right_vim"],
@ -76,8 +75,8 @@
["yy", ["copy_line_internal_vim"], ["cancel"]], ["yy", ["copy_line_internal_vim"], ["cancel"]],
["<C-u>", "move_scroll_half_page_up_vim"], ["<C-u>", "move_scroll_half_page_up"],
["<C-d>", "move_scroll_half_page_down_vim"], ["<C-d>", "move_scroll_half_page_down"],
["zz", "scroll_view_center"], ["zz", "scroll_view_center"],
@ -121,7 +120,6 @@
"name": "VISUAL", "name": "VISUAL",
"line_numbers": "relative", "line_numbers": "relative",
"cursor": "block", "cursor": "block",
"selection": "normal",
"init_command": ["enable_selection"], "init_command": ["enable_selection"],
"press": [ "press": [
["<Esc>", ["cancel"], ["enter_mode", "normal"]], ["<Esc>", ["cancel"], ["enter_mode", "normal"]],
@ -151,8 +149,8 @@
["p", ["paste_internal_vim"], ["enter_mode", "normal"]], ["p", ["paste_internal_vim"], ["enter_mode", "normal"]],
["P", ["paste_internal_vim"], ["enter_mode", "normal"]], ["P", ["paste_internal_vim"], ["enter_mode", "normal"]],
["<C-u>", "move_scroll_half_page_up_vim"], ["<C-u>", "move_scroll_half_page_up"],
["<C-d>", "move_scroll_half_page_down_vim"], ["<C-d>", "move_scroll_half_page_down"],
["zz", "scroll_view_center"], ["zz", "scroll_view_center"],
["<S-.>", "indent"], ["<S-.>", "indent"],
@ -186,7 +184,6 @@
"name": "VISUAL LINE", "name": "VISUAL LINE",
"line_numbers": "relative", "line_numbers": "relative",
"cursor": "block", "cursor": "block",
"selection": "normal",
"press": [ "press": [
["<Esc>", ["cancel"], ["enter_mode", "normal"]], ["<Esc>", ["cancel"], ["enter_mode", "normal"]],
["k", "select_up"], ["k", "select_up"],
@ -199,8 +196,8 @@
["p", ["paste_internal_vim"], ["enter_mode", "normal"]], ["p", ["paste_internal_vim"], ["enter_mode", "normal"]],
["P", ["paste_internal_vim"], ["enter_mode", "normal"]], ["P", ["paste_internal_vim"], ["enter_mode", "normal"]],
["<C-u>", "move_scroll_half_page_up_vim"], ["<C-u>", "move_scroll_half_page_up"],
["<C-d>", "move_scroll_half_page_down_vim"], ["<C-d>", "move_scroll_half_page_down"],
["<S-.>", "indent"], ["<S-.>", "indent"],
["<S-,>", "unindent"], ["<S-,>", "unindent"],
@ -234,7 +231,6 @@
"inherit": "visual", "inherit": "visual",
"line_numbers": "relative", "line_numbers": "relative",
"cursor": "block", "cursor": "block",
"selection": "normal",
"init_command": ["enable_selection"], "init_command": ["enable_selection"],
"press": [ "press": [
["k", "add_cursor_up"], ["k", "add_cursor_up"],

View file

@ -12,7 +12,6 @@ const input = @import("input");
const command = @import("command"); const command = @import("command");
const EventHandler = @import("EventHandler"); const EventHandler = @import("EventHandler");
const KeyEvent = input.KeyEvent; const KeyEvent = input.KeyEvent;
const SelectionStyle = @import("Buffer").Selection.Style;
pub const CursorShape = @import("config").CursorShape; pub const CursorShape = @import("config").CursorShape;
const log = std.log.scoped(.keybind); const log = std.log.scoped(.keybind);
@ -87,7 +86,6 @@ const Handler = struct {
.name = self.bindings.name, .name = self.bindings.name,
.line_numbers = self.bindings.line_numbers, .line_numbers = self.bindings.line_numbers,
.cursor_shape = self.bindings.cursor_shape, .cursor_shape = self.bindings.cursor_shape,
.selection_style = self.bindings.selection_style,
.init_command = self.bindings.init_command, .init_command = self.bindings.init_command,
.deinit_command = self.bindings.deinit_command, .deinit_command = self.bindings.deinit_command,
.insert_command = try allocator.dupe(u8, insert_command), .insert_command = try allocator.dupe(u8, insert_command),
@ -112,7 +110,6 @@ const Handler = struct {
mode_.name = self.bindings.name; mode_.name = self.bindings.name;
mode_.line_numbers = self.bindings.line_numbers; mode_.line_numbers = self.bindings.line_numbers;
mode_.cursor_shape = self.bindings.cursor_shape; mode_.cursor_shape = self.bindings.cursor_shape;
mode_.selection_style = self.bindings.selection_style;
mode_.init_command = self.bindings.init_command; mode_.init_command = self.bindings.init_command;
mode_.deinit_command = self.bindings.deinit_command; mode_.deinit_command = self.bindings.deinit_command;
if (mode_.init_command) |init_command| init_command.execute_const(); if (mode_.init_command) |init_command| init_command.execute_const();
@ -136,7 +133,6 @@ pub const Mode = struct {
bindings: *const BindingSet, bindings: *const BindingSet,
keybind_hints: *const KeybindHints, keybind_hints: *const KeybindHints,
cursor_shape: ?CursorShape = null, cursor_shape: ?CursorShape = null,
selection_style: SelectionStyle,
init_command: ?Command = null, init_command: ?Command = null,
deinit_command: ?Command = null, deinit_command: ?Command = null,
initialized: bool = false, initialized: bool = false,
@ -172,7 +168,6 @@ pub const Mode = struct {
self.line_numbers = .inherit; self.line_numbers = .inherit;
self.keybind_hints = &.{}; self.keybind_hints = &.{};
self.cursor_shape = null; self.cursor_shape = null;
self.selection_style = .normal;
self.init_command = null; self.init_command = null;
self.deinit_command = null; self.deinit_command = null;
self.initialized = false; self.initialized = false;
@ -468,7 +463,6 @@ const BindingSet = struct {
config_section: []const u8, config_section: []const u8,
line_numbers: LineNumbers = .inherit, line_numbers: LineNumbers = .inherit,
cursor_shape: ?CursorShape = null, cursor_shape: ?CursorShape = null,
selection_style: SelectionStyle,
insert_command: []const u8 = "", insert_command: []const u8 = "",
hints_map: KeybindHints = .{}, hints_map: KeybindHints = .{},
init_command: ?Command = null, init_command: ?Command = null,
@ -478,7 +472,7 @@ const BindingSet = struct {
const OnMatchFailure = enum { insert, ignore }; const OnMatchFailure = enum { insert, ignore };
fn load(allocator: std.mem.Allocator, namespace_name: []const u8, config_section: []const u8, mode_bindings: std.json.Value, fallback: ?*const BindingSet, namespace: *Namespace) (error{ OutOfMemory, WriteFailed } || parse_flow.ParseError || parse_vim.ParseError || std.json.ParseFromValueError)!@This() { fn load(allocator: std.mem.Allocator, namespace_name: []const u8, config_section: []const u8, mode_bindings: std.json.Value, fallback: ?*const BindingSet, namespace: *Namespace) (error{ OutOfMemory, WriteFailed } || parse_flow.ParseError || parse_vim.ParseError || std.json.ParseFromValueError)!@This() {
var self: @This() = .{ .name = undefined, .config_section = config_section, .selection_style = undefined }; var self: @This() = .{ .name = undefined, .config_section = config_section };
const JsonConfig = struct { const JsonConfig = struct {
press: []const []const std.json.Value = &[_][]std.json.Value{}, press: []const []const std.json.Value = &[_][]std.json.Value{},
@ -490,7 +484,6 @@ const BindingSet = struct {
cursor: ?CursorShape = null, cursor: ?CursorShape = null,
inherit: ?[]const u8 = null, inherit: ?[]const u8 = null,
inherits: ?[][]const u8 = null, inherits: ?[][]const u8 = null,
selection: ?SelectionStyle = null,
init_command: ?[]const std.json.Value = null, init_command: ?[]const std.json.Value = null,
deinit_command: ?[]const std.json.Value = null, deinit_command: ?[]const std.json.Value = null,
}; };
@ -503,7 +496,6 @@ const BindingSet = struct {
self.name = try allocator.dupe(u8, parsed.value.name orelse namespace_name); self.name = try allocator.dupe(u8, parsed.value.name orelse namespace_name);
self.line_numbers = parsed.value.line_numbers; self.line_numbers = parsed.value.line_numbers;
self.cursor_shape = parsed.value.cursor; self.cursor_shape = parsed.value.cursor;
self.selection_style = parsed.value.selection orelse .normal;
if (parsed.value.init_command) |cmd| self.init_command = try Command.load(allocator, cmd); if (parsed.value.init_command) |cmd| self.init_command = try Command.load(allocator, cmd);
if (parsed.value.deinit_command) |cmd| self.deinit_command = try Command.load(allocator, cmd); if (parsed.value.deinit_command) |cmd| self.deinit_command = try Command.load(allocator, cmd);
try self.load_event(allocator, &self.press, input.event.press, parsed.value.press); try self.load_event(allocator, &self.press, input.event.press, parsed.value.press);
@ -575,7 +567,7 @@ const BindingSet = struct {
} }
fn copy(allocator: std.mem.Allocator, config_section: []const u8, fallback: *const BindingSet) error{OutOfMemory}!@This() { fn copy(allocator: std.mem.Allocator, config_section: []const u8, fallback: *const BindingSet) error{OutOfMemory}!@This() {
var self: @This() = .{ .name = fallback.name, .config_section = config_section, .selection_style = fallback.selection_style }; var self: @This() = .{ .name = fallback.name, .config_section = config_section };
self.on_match_failure = fallback.on_match_failure; self.on_match_failure = fallback.on_match_failure;
for (fallback.press.items) |binding| try self.press.append(allocator, binding); for (fallback.press.items) |binding| try self.press.append(allocator, binding);
for (fallback.release.items) |binding| try self.release.append(allocator, binding); for (fallback.release.items) |binding| try self.release.append(allocator, binding);
@ -971,7 +963,7 @@ test "match" {
} }
test "json" { test "json" {
var bindings: BindingSet = .{ .name = "test", .config_section = "test_section", .selection_style = .normal }; var bindings: BindingSet = .{ .name = "test", .config_section = "test_section" };
_ = try bindings.process_key_event(input.KeyEvent.from_key('j')); _ = try bindings.process_key_event(input.KeyEvent.from_key('j'));
_ = try bindings.process_key_event(input.KeyEvent.from_key('k')); _ = try bindings.process_key_event(input.KeyEvent.from_key('k'));
_ = try bindings.process_key_event(input.KeyEvent.from_key('g')); _ = try bindings.process_key_event(input.KeyEvent.from_key('g'));

View file

@ -115,63 +115,38 @@ pub const CurSel = struct {
self.* = .{}; self.* = .{};
} }
pub fn enable_selection(self: *Self, root: Buffer.Root, metrics: Buffer.Metrics) *Selection { pub fn enable_selection(self: *Self) *Selection {
self.selection = self.to_selection(root, metrics); self.selection = self.to_selection();
return if (self.selection) |*sel| sel else unreachable; return if (self.selection) |*sel| sel else unreachable;
} }
pub fn enable_selection_normal(self: *Self) *Selection { pub fn enable_selection_inclusive(self: *Self, root: Buffer.Root, metrics: Buffer.Metrics) *Selection {
self.selection = self.to_selection_normal(); self.selection = self.to_selection_inclusive(root, metrics);
return if (self.selection) |*sel| sel else unreachable; return if (self.selection) |*sel| sel else unreachable;
} }
fn to_selection(self: *const Self, root: Buffer.Root, metrics: Buffer.Metrics) Selection { pub fn to_selection(self: *const Self) Selection {
return switch (tui.get_selection_style()) { return self.selection orelse Selection.from_cursor(&self.cursor);
.normal => self.to_selection_normal(),
.inclusive => self.to_selection_inclusive(root, metrics),
};
} }
fn to_selection_normal(self: *const Self) Selection { pub fn to_selection_inclusive(self: *const Self, root: Buffer.Root, metrics: Buffer.Metrics) Selection {
return if (self.selection) |sel| sel else Selection.from_cursor(&self.cursor); return self.selection orelse Selection.from_cursor_inclusive(&self.cursor, root, metrics);
} }
fn to_selection_inclusive(self: *const Self, root: Buffer.Root, metrics: Buffer.Metrics) Selection { pub fn disable_selection(self: *Self) void {
return if (self.selection) |sel| self.selection = null;
sel
else cod: {
var sel = Selection.from_cursor(&self.cursor);
sel.end.move_right(root, metrics) catch {};
break :cod sel;
};
}
pub fn disable_selection(self: *Self, root: Buffer.Root, metrics: Buffer.Metrics) void {
switch (tui.get_selection_style()) {
.normal => self.disable_selection_normal(),
.inclusive => self.disable_selection_inclusive(root, metrics),
}
} }
pub fn disable_selection_normal(self: *Self) void { pub fn disable_selection_normal(self: *Self) void {
self.selection = null; self.selection = null;
} }
fn disable_selection_inclusive(self: *Self, root: Buffer.Root, metrics: Buffer.Metrics) void { pub fn check_selection(self: *Self) void {
if (self.selection) |sel| { self.selection = if (self.selection) |sel| if (sel.empty()) null else sel else null;
if (!sel.is_reversed()) self.cursor.move_left(root, metrics) catch {};
self.selection = null;
}
}
pub fn check_selection(self: *Self, root: Buffer.Root, metrics: Buffer.Metrics) void {
if (self.selection) |sel| if (sel.empty()) {
self.disable_selection(root, metrics);
};
} }
fn expand_selection_to_line(self: *Self, root: Buffer.Root, metrics: Buffer.Metrics) *Selection { fn expand_selection_to_line(self: *Self, root: Buffer.Root, metrics: Buffer.Metrics) *Selection {
const sel = self.enable_selection(root, metrics); const sel = self.enable_selection();
sel.normalize(); sel.normalize();
sel.begin.move_begin(); sel.begin.move_begin();
if (!(sel.end.row > sel.begin.row and sel.end.col == 0)) { if (!(sel.end.row > sel.begin.row and sel.end.col == 0)) {
@ -1658,7 +1633,7 @@ pub const Editor = struct {
return row < sel.begin.row or (row == sel.begin.row and col < sel.begin.col); return row < sel.begin.row or (row == sel.begin.row and col < sel.begin.col);
} }
inline fn screen_cursor(self: *const Self, cursor: *const Cursor) ?Cursor { pub inline fn screen_cursor(self: *const Self, cursor: *const Cursor) ?Cursor {
return if (self.view.is_visible(cursor)) .{ return if (self.view.is_visible(cursor)) .{
.row = cursor.row - self.view.row, .row = cursor.row - self.view.row,
.col = cursor.col - self.view.col, .col = cursor.col - self.view.col,
@ -1771,7 +1746,7 @@ pub const Editor = struct {
try self.send_editor_cursel_msg("jump_source", self.get_primary()); try self.send_editor_cursel_msg("jump_source", self.get_primary());
} }
fn send_editor_jump_destination(self: *Self) !void { pub fn send_editor_jump_destination(self: *Self) !void {
try self.send_editor_cursel_msg("jump_destination", self.get_primary()); try self.send_editor_cursel_msg("jump_destination", self.get_primary());
} }
@ -1901,7 +1876,7 @@ pub const Editor = struct {
fn cancel_all_selections(self: *Self) void { fn cancel_all_selections(self: *Self) void {
var primary = self.get_primary().*; var primary = self.get_primary().*;
primary.disable_selection(self.buf_root() catch return, self.metrics); primary.disable_selection();
self.cursels.clearRetainingCapacity(); self.cursels.clearRetainingCapacity();
self.cursels.addOneAssumeCapacity().* = primary; self.cursels.addOneAssumeCapacity().* = primary;
for (self.matches.items) |*match_| if (match_.*) |*match| { for (self.matches.items) |*match_| if (match_.*) |*match| {
@ -1955,7 +1930,7 @@ pub const Editor = struct {
fn with_cursors_const_once(self: *Self, root: Buffer.Root, move: cursor_operator_const) error{Stop}!void { fn with_cursors_const_once(self: *Self, root: Buffer.Root, move: cursor_operator_const) error{Stop}!void {
for (self.cursels.items) |*cursel_| if (cursel_.*) |*cursel| { for (self.cursels.items) |*cursel_| if (cursel_.*) |*cursel| {
cursel.disable_selection(root, self.metrics); cursel.disable_selection();
try with_cursor_const(root, move, cursel, self.metrics); try with_cursor_const(root, move, cursel, self.metrics);
}; };
self.collapse_cursors(); self.collapse_cursors();
@ -1966,7 +1941,7 @@ pub const Editor = struct {
_ = ctx.args.match(.{tp.extract(&repeat)}) catch false; _ = ctx.args.match(.{tp.extract(&repeat)}) catch false;
while (repeat > 0) : (repeat -= 1) { while (repeat > 0) : (repeat -= 1) {
for (self.cursels.items) |*cursel_| if (cursel_.*) |*cursel| { for (self.cursels.items) |*cursel_| if (cursel_.*) |*cursel| {
cursel.disable_selection(root, self.metrics); cursel.disable_selection();
try with_cursor_const(root, move, cursel, self.metrics); try with_cursor_const(root, move, cursel, self.metrics);
}; };
self.collapse_cursors(); self.collapse_cursors();
@ -1979,7 +1954,7 @@ pub const Editor = struct {
fn with_cursors_const_arg(self: *Self, root: Buffer.Root, move: cursor_operator_const_arg, ctx: Context) error{Stop}!void { fn with_cursors_const_arg(self: *Self, root: Buffer.Root, move: cursor_operator_const_arg, ctx: Context) error{Stop}!void {
for (self.cursels.items) |*cursel_| if (cursel_.*) |*cursel| { for (self.cursels.items) |*cursel_| if (cursel_.*) |*cursel| {
cursel.disable_selection(root, self.metrics); cursel.disable_selection();
try with_cursor_const_arg(root, move, cursel, ctx, self.metrics); try with_cursor_const_arg(root, move, cursel, ctx, self.metrics);
}; };
self.collapse_cursors(); self.collapse_cursors();
@ -1989,7 +1964,7 @@ pub const Editor = struct {
try move(root, &cursel.cursor, view, metrics); try move(root, &cursel.cursor, view, metrics);
} }
fn with_cursors_and_view_const(self: *Self, root: Buffer.Root, move: cursor_view_operator_const, view: *const View) error{Stop}!void { pub fn with_cursors_and_view_const(self: *Self, root: Buffer.Root, move: cursor_view_operator_const, view: *const View) error{Stop}!void {
var someone_stopped = false; var someone_stopped = false;
for (self.cursels.items) |*cursel_| if (cursel_.*) |*cursel| for (self.cursels.items) |*cursel_| if (cursel_.*) |*cursel|
with_cursor_and_view_const(root, move, cursel, view, self.metrics) catch { with_cursor_and_view_const(root, move, cursel, view, self.metrics) catch {
@ -2004,10 +1979,10 @@ pub const Editor = struct {
} }
pub fn with_selection_const(root: Buffer.Root, move: cursor_operator_const, cursel: *CurSel, metrics: Buffer.Metrics) error{Stop}!void { pub fn with_selection_const(root: Buffer.Root, move: cursor_operator_const, cursel: *CurSel, metrics: Buffer.Metrics) error{Stop}!void {
const sel = cursel.enable_selection(root, metrics); const sel = cursel.enable_selection();
try move(root, &sel.end, metrics); try move(root, &sel.end, metrics);
cursel.cursor = sel.end; cursel.cursor = sel.end;
cursel.check_selection(root, metrics); cursel.check_selection();
} }
pub fn with_selections_const_once(self: *Self, root: Buffer.Root, move: cursor_operator_const) error{Stop}!void { pub fn with_selections_const_once(self: *Self, root: Buffer.Root, move: cursor_operator_const) error{Stop}!void {
@ -2036,10 +2011,10 @@ pub const Editor = struct {
} }
fn with_selection_const_arg(root: Buffer.Root, move: cursor_operator_const_arg, cursel: *CurSel, ctx: Context, metrics: Buffer.Metrics) error{Stop}!void { fn with_selection_const_arg(root: Buffer.Root, move: cursor_operator_const_arg, cursel: *CurSel, ctx: Context, metrics: Buffer.Metrics) error{Stop}!void {
const sel = cursel.enable_selection(root, metrics); const sel = cursel.enable_selection();
try move(root, &sel.end, ctx, metrics); try move(root, &sel.end, ctx, metrics);
cursel.cursor = sel.end; cursel.cursor = sel.end;
cursel.check_selection(root, metrics); cursel.check_selection();
} }
fn with_selections_const_arg(self: *Self, root: Buffer.Root, move: cursor_operator_const_arg, ctx: Context) error{Stop}!void { fn with_selections_const_arg(self: *Self, root: Buffer.Root, move: cursor_operator_const_arg, ctx: Context) error{Stop}!void {
@ -2053,12 +2028,12 @@ pub const Editor = struct {
} }
fn with_selection_and_view_const(root: Buffer.Root, move: cursor_view_operator_const, cursel: *CurSel, view: *const View, metrics: Buffer.Metrics) error{Stop}!void { fn with_selection_and_view_const(root: Buffer.Root, move: cursor_view_operator_const, cursel: *CurSel, view: *const View, metrics: Buffer.Metrics) error{Stop}!void {
const sel = cursel.enable_selection(root, metrics); const sel = cursel.enable_selection();
try move(root, &sel.end, view, metrics); try move(root, &sel.end, view, metrics);
cursel.cursor = sel.end; cursel.cursor = sel.end;
} }
fn with_selections_and_view_const(self: *Self, root: Buffer.Root, move: cursor_view_operator_const, view: *const View) error{Stop}!void { pub fn with_selections_and_view_const(self: *Self, root: Buffer.Root, move: cursor_view_operator_const, view: *const View) error{Stop}!void {
var someone_stopped = false; var someone_stopped = false;
for (self.cursels.items) |*cursel_| if (cursel_.*) |*cursel| for (self.cursels.items) |*cursel_| if (cursel_.*) |*cursel|
with_selection_and_view_const(root, move, cursel, view, self.metrics) catch { with_selection_and_view_const(root, move, cursel, view, self.metrics) catch {
@ -2214,48 +2189,60 @@ pub const Editor = struct {
const cursor_operator_const_arg = *const fn (root: Buffer.Root, cursor: *Cursor, ctx: Context, metrics: Buffer.Metrics) error{Stop}!void; const cursor_operator_const_arg = *const fn (root: Buffer.Root, cursor: *Cursor, ctx: Context, metrics: Buffer.Metrics) error{Stop}!void;
pub const cursel_operator_mut_once_arg = *const fn (root: Buffer.Root, cursel: *CurSel, ctx: Context, metrics: Buffer.Metrics) error{Stop}!void; pub const cursel_operator_mut_once_arg = *const fn (root: Buffer.Root, cursel: *CurSel, ctx: Context, metrics: Buffer.Metrics) error{Stop}!void;
const cursor_view_operator_const = *const fn (root: Buffer.Root, cursor: *Cursor, view: *const View, metrics: Buffer.Metrics) error{Stop}!void; const cursor_view_operator_const = *const fn (root: Buffer.Root, cursor: *Cursor, view: *const View, metrics: Buffer.Metrics) error{Stop}!void;
const cursel_operator_const = *const fn (root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics) error{Stop}!void; pub const cursel_operator_const = *const fn (root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics) error{Stop}!void;
const cursor_operator = *const fn (root: Buffer.Root, cursor: *Cursor, allocator: Allocator) error{Stop}!Buffer.Root; const cursor_operator = *const fn (root: Buffer.Root, cursor: *Cursor, allocator: Allocator) error{Stop}!Buffer.Root;
const cursel_operator = *const fn (root: Buffer.Root, cursel: *CurSel, allocator: Allocator) error{Stop}!Buffer.Root; const cursel_operator = *const fn (root: Buffer.Root, cursel: *CurSel, allocator: Allocator) error{Stop}!Buffer.Root;
const cursel_operator_mut = *const fn (self: *Self, root: Buffer.Root, cursel: *CurSel, allocator: Allocator) error{Stop}!Buffer.Root; const cursel_operator_mut = *const fn (self: *Self, root: Buffer.Root, cursel: *CurSel, allocator: Allocator) error{Stop}!Buffer.Root;
const cursel_operator_mut_arg = *const fn (self: *Self, root: Buffer.Root, cursel: *CurSel, allocator: Allocator, ctx: Context) error{Stop}!Buffer.Root; const cursel_operator_mut_arg = *const fn (self: *Self, root: Buffer.Root, cursel: *CurSel, allocator: Allocator, ctx: Context) error{Stop}!Buffer.Root;
pub fn is_not_word_char(c: []const u8) bool { pub const CharClass = enum {
if (c.len == 0) return true; whitespace,
word,
non_word,
eol,
end,
};
pub fn char_class(c: []const u8) CharClass {
if (c.len == 0) return .end;
return switch (c[0]) { return switch (c[0]) {
' ' => true, '=' => .non_word,
'=' => true, '"' => .non_word,
'"' => true, '\'' => .non_word,
'\'' => true, '/' => .non_word,
'\t' => true, '\\' => .non_word,
'\n' => true, '*' => .non_word,
'/' => true, ':' => .non_word,
'\\' => true, '.' => .non_word,
'*' => true, ',' => .non_word,
':' => true, '(' => .non_word,
'.' => true, ')' => .non_word,
',' => true, '{' => .non_word,
'(' => true, '}' => .non_word,
')' => true, '[' => .non_word,
'{' => true, ']' => .non_word,
'}' => true, ';' => .non_word,
'[' => true, '|' => .non_word,
']' => true, '!' => .non_word,
';' => true, '?' => .non_word,
'|' => true, '&' => .non_word,
'!' => true, '@' => .non_word,
'?' => true, '-' => .non_word,
'&' => true, '<' => .non_word,
'@' => true, '>' => .non_word,
'-' => true, ' ' => .whitespace,
'<' => true, '\t' => .whitespace,
'>' => true, '\n' => .eol,
else => false, else => .word,
}; };
} }
pub fn is_not_word_char(c: []const u8) bool {
return char_class(c) != .word;
}
pub fn is_word_char(c: []const u8) bool { pub fn is_word_char(c: []const u8) bool {
return !is_not_word_char(c); return char_class(c) == .word;
} }
fn is_word_char_at_cursor(root: Buffer.Root, cursor: *const Cursor, metrics: Buffer.Metrics) bool { fn is_word_char_at_cursor(root: Buffer.Root, cursor: *const Cursor, metrics: Buffer.Metrics) bool {
@ -2279,11 +2266,17 @@ pub const Editor = struct {
} }
pub fn is_whitespace(c: []const u8) bool { pub fn is_whitespace(c: []const u8) bool {
return (c.len == 0) or (c[0] == ' ') or (c[0] == '\t'); return switch (char_class(c)) {
.whitespace, .end => true,
else => false,
};
} }
pub fn is_whitespace_or_eol(c: []const u8) bool { pub fn is_whitespace_or_eol(c: []const u8) bool {
return is_whitespace(c) or c[0] == '\n'; return switch (char_class(c)) {
.whitespace, .end, .eol => true,
else => false,
};
} }
pub fn is_whitespace_at_cursor(root: Buffer.Root, cursor: *const Cursor, metrics: Buffer.Metrics) bool { pub fn is_whitespace_at_cursor(root: Buffer.Root, cursor: *const Cursor, metrics: Buffer.Metrics) bool {
@ -2358,7 +2351,7 @@ pub const Editor = struct {
return false; return false;
} }
fn is_eol_left(_: Buffer.Root, cursor: *const Cursor, _: Buffer.Metrics) bool { pub fn is_eol_left(_: Buffer.Root, cursor: *const Cursor, _: Buffer.Metrics) bool {
if (cursor.col == 0) if (cursor.col == 0)
return true; return true;
return false; return false;
@ -2371,22 +2364,6 @@ pub const Editor = struct {
return false; return false;
} }
fn is_eol_right_vim(root: Buffer.Root, cursor: *const Cursor, metrics: Buffer.Metrics) bool {
const line_width = root.line_width(cursor.row, metrics) catch return true;
if (line_width == 0) return true;
if (cursor.col >= line_width - 1)
return true;
return false;
}
fn is_eol_vim(root: Buffer.Root, cursor: *const Cursor, metrics: Buffer.Metrics) bool {
const line_width = root.line_width(cursor.row, metrics) catch return true;
if (line_width == 0) return true;
if (cursor.col >= line_width)
return true;
return false;
}
pub fn move_cursor_left(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) error{Stop}!void { pub fn move_cursor_left(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) error{Stop}!void {
try cursor.move_left(root, metrics); try cursor.move_left(root, metrics);
} }
@ -2396,7 +2373,7 @@ pub const Editor = struct {
move_cursor_left(root, cursor, metrics) catch return; move_cursor_left(root, cursor, metrics) catch return;
} }
fn move_cursor_left_unless(root: Buffer.Root, cursor: *Cursor, pred: cursor_predicate, metrics: Buffer.Metrics) void { pub fn move_cursor_left_unless(root: Buffer.Root, cursor: *Cursor, pred: cursor_predicate, metrics: Buffer.Metrics) void {
if (!pred(root, cursor, metrics)) if (!pred(root, cursor, metrics))
move_cursor_left(root, cursor, metrics) catch return; move_cursor_left(root, cursor, metrics) catch return;
} }
@ -2419,7 +2396,7 @@ pub const Editor = struct {
move_cursor_right(root, cursor, metrics) catch return; move_cursor_right(root, cursor, metrics) catch return;
} }
fn move_cursor_right_unless(root: Buffer.Root, cursor: *Cursor, pred: cursor_predicate, metrics: Buffer.Metrics) void { pub fn move_cursor_right_unless(root: Buffer.Root, cursor: *Cursor, pred: cursor_predicate, metrics: Buffer.Metrics) void {
if (!pred(root, cursor, metrics)) if (!pred(root, cursor, metrics))
move_cursor_right(root, cursor, metrics) catch return; move_cursor_right(root, cursor, metrics) catch return;
} }
@ -2428,32 +2405,18 @@ pub const Editor = struct {
cursor.move_end(root, metrics); cursor.move_end(root, metrics);
} }
fn move_cursor_end_vim(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) !void {
move_cursor_right_until(root, cursor, is_eol_vim, metrics);
}
fn move_cursor_up(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) !void { fn move_cursor_up(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) !void {
cursor.move_up(root, metrics) catch |e| switch (e) { cursor.move_up(root, metrics) catch |e| switch (e) {
error.Stop => cursor.move_begin(), error.Stop => cursor.move_begin(),
}; };
} }
fn move_cursor_up_vim(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) !void {
try cursor.move_up(root, metrics);
if (is_eol_vim(root, cursor, metrics)) try move_cursor_left_vim(root, cursor, metrics);
}
pub fn move_cursor_down(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) !void { pub fn move_cursor_down(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) !void {
cursor.move_down(root, metrics) catch |e| switch (e) { cursor.move_down(root, metrics) catch |e| switch (e) {
error.Stop => cursor.move_end(root, metrics), error.Stop => cursor.move_end(root, metrics),
}; };
} }
fn move_cursor_down_vim(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) !void {
try cursor.move_down(root, metrics);
if (is_eol_vim(root, cursor, metrics)) try move_cursor_left_vim(root, cursor, metrics);
}
fn move_cursor_buffer_begin(_: Buffer.Root, cursor: *Cursor, _: Buffer.Metrics) !void { fn move_cursor_buffer_begin(_: Buffer.Root, cursor: *Cursor, _: Buffer.Metrics) !void {
cursor.move_buffer_begin(); cursor.move_buffer_begin();
} }
@ -2470,24 +2433,6 @@ pub const Editor = struct {
cursor.move_page_down(root, view, metrics); cursor.move_page_down(root, view, metrics);
} }
fn move_cursor_half_page_up(root: Buffer.Root, cursor: *Cursor, view: *const View, metrics: Buffer.Metrics) !void {
cursor.move_half_page_up(root, view, metrics);
}
fn move_cursor_half_page_up_vim(root: Buffer.Root, cursor: *Cursor, view: *const View, metrics: Buffer.Metrics) !void {
cursor.move_half_page_up(root, view, metrics);
if (is_eol_vim(root, cursor, metrics)) try move_cursor_left_vim(root, cursor, metrics);
}
fn move_cursor_half_page_down(root: Buffer.Root, cursor: *Cursor, view: *const View, metrics: Buffer.Metrics) !void {
cursor.move_half_page_down(root, view, metrics);
}
fn move_cursor_half_page_down_vim(root: Buffer.Root, cursor: *Cursor, view: *const View, metrics: Buffer.Metrics) !void {
cursor.move_half_page_down(root, view, metrics);
if (is_eol_vim(root, cursor, metrics)) try move_cursor_left_vim(root, cursor, metrics);
}
pub fn primary_click(self: *Self, y: c_int, x: c_int) !void { pub fn primary_click(self: *Self, y: c_int, x: c_int) !void {
const root = self.buf_root() catch return; const root = self.buf_root() catch return;
if (self.fast_scroll) { if (self.fast_scroll) {
@ -2500,7 +2445,7 @@ pub const Editor = struct {
self.cancel_all_selections(); self.cancel_all_selections();
} }
const primary = self.get_primary(); const primary = self.get_primary();
primary.disable_selection(root, self.metrics); primary.disable_selection();
self.selection_mode = .char; self.selection_mode = .char;
try self.send_editor_jump_source(); try self.send_editor_jump_source();
primary.cursor.move_abs(root, &self.view, @intCast(y), @intCast(x), self.metrics) catch return; primary.cursor.move_abs(root, &self.view, @intCast(y), @intCast(x), self.metrics) catch return;
@ -2514,7 +2459,7 @@ pub const Editor = struct {
pub fn primary_double_click(self: *Self, y: c_int, x: c_int) !void { pub fn primary_double_click(self: *Self, y: c_int, x: c_int) !void {
const primary = self.get_primary(); const primary = self.get_primary();
const root = self.buf_root() catch return; const root = self.buf_root() catch return;
primary.disable_selection(root, self.metrics); primary.disable_selection();
self.selection_mode = .word; self.selection_mode = .word;
primary.cursor.move_abs(root, &self.view, @intCast(y), @intCast(x), self.metrics) catch return; primary.cursor.move_abs(root, &self.view, @intCast(y), @intCast(x), self.metrics) catch return;
_ = try self.select_word_at_cursor(primary); _ = try self.select_word_at_cursor(primary);
@ -2526,7 +2471,7 @@ pub const Editor = struct {
pub fn primary_triple_click(self: *Self, y: c_int, x: c_int) !void { pub fn primary_triple_click(self: *Self, y: c_int, x: c_int) !void {
const primary = self.get_primary(); const primary = self.get_primary();
const root = self.buf_root() catch return; const root = self.buf_root() catch return;
primary.disable_selection(root, self.metrics); primary.disable_selection();
self.selection_mode = .line; self.selection_mode = .line;
primary.cursor.move_abs(root, &self.view, @intCast(y), @intCast(x), self.metrics) catch return; primary.cursor.move_abs(root, &self.view, @intCast(y), @intCast(x), self.metrics) catch return;
try self.select_line_at_cursor(root, primary, .exclude_eol); try self.select_line_at_cursor(root, primary, .exclude_eol);
@ -2540,7 +2485,7 @@ pub const Editor = struct {
const x_ = if (x < 0) 0 else x; const x_ = if (x < 0) 0 else x;
const primary = self.get_primary(); const primary = self.get_primary();
const root = self.buf_root() catch return; const root = self.buf_root() catch return;
const sel = primary.enable_selection(root, self.metrics); const sel = primary.enable_selection();
sel.end.move_abs(root, &self.view, @intCast(y_), @intCast(x_), self.metrics) catch return; sel.end.move_abs(root, &self.view, @intCast(y_), @intCast(x_), self.metrics) catch return;
const initial = self.selection_drag_initial orelse sel.*; const initial = self.selection_drag_initial orelse sel.*;
switch (self.selection_mode) { switch (self.selection_mode) {
@ -2568,7 +2513,7 @@ pub const Editor = struct {
}, },
} }
primary.cursor = sel.end; primary.cursor = sel.end;
primary.check_selection(root, self.metrics); primary.check_selection();
self.collapse_cursors(); self.collapse_cursors();
self.clamp_mouse(); self.clamp_mouse();
} }
@ -2758,7 +2703,7 @@ pub const Editor = struct {
} }
pub fn insert(self: *Self, root: Buffer.Root, cursel: *CurSel, s: []const u8, allocator: Allocator) !Buffer.Root { pub fn insert(self: *Self, root: Buffer.Root, cursel: *CurSel, s: []const u8, allocator: Allocator) !Buffer.Root {
cursel.check_selection(root, self.metrics); cursel.check_selection();
var root_ = if (cursel.selection) |_| try self.delete_selection(root, cursel, allocator) else root; var root_ = if (cursel.selection) |_| try self.delete_selection(root, cursel, allocator) else root;
const cursor = &cursel.cursor; const cursor = &cursel.cursor;
const begin = cursel.cursor; const begin = cursel.cursor;
@ -2911,7 +2856,7 @@ pub const Editor = struct {
const primary = self.get_primary(); const primary = self.get_primary();
const root = self.buf_root() catch return; const root = self.buf_root() catch return;
if (primary.selection) |_| {} else { if (primary.selection) |_| {} else {
const sel = primary.enable_selection(root, self.metrics); const sel = primary.enable_selection();
try move_cursor_begin(root, &sel.begin, self.metrics); try move_cursor_begin(root, &sel.begin, self.metrics);
try move_cursor_end(root, &sel.end, self.metrics); try move_cursor_end(root, &sel.end, self.metrics);
try move_cursor_right(root, &sel.end, self.metrics); try move_cursor_right(root, &sel.end, self.metrics);
@ -3202,14 +3147,6 @@ pub const Editor = struct {
} }
pub const delete_line_meta: Meta = .{ .description = "Delete current line", .arguments = &.{.integer} }; pub const delete_line_meta: Meta = .{ .description = "Delete current line", .arguments = &.{.integer} };
pub fn cut_to_end_vim(self: *Self, _: Context) Result {
const b = try self.buf_for_update();
const root = try self.cut_to(move_cursor_end_vim, b.root);
try self.update_buf(root);
self.clamp();
}
pub const cut_to_end_vim_meta: Meta = .{ .description = "Cut to end of line (vim)" };
pub fn join_next_line(self: *Self, ctx: Context) Result { pub fn join_next_line(self: *Self, ctx: Context) Result {
const b = try self.buf_for_update(); const b = try self.buf_for_update();
try self.with_cursors_const_repeat(b.root, move_cursor_end, ctx); try self.with_cursors_const_repeat(b.root, move_cursor_end, ctx);
@ -3237,7 +3174,7 @@ pub const Editor = struct {
.left => if (sel.is_reversed()) sel.end else sel.begin, .left => if (sel.is_reversed()) sel.end else sel.begin,
.right => if (sel.is_reversed()) sel.begin else sel.end, .right => if (sel.is_reversed()) sel.begin else sel.end,
}; };
cursel.disable_selection(root, self.metrics); cursel.disable_selection();
} else { } else {
try with_cursor_const(root, switch (direction) { try with_cursor_const(root, switch (direction) {
.left => move_cursor_left, .left => move_cursor_left,
@ -3260,28 +3197,6 @@ pub const Editor = struct {
} }
pub const move_right_meta: Meta = .{ .description = "Move cursor right", .arguments = &.{.integer} }; pub const move_right_meta: Meta = .{ .description = "Move cursor right", .arguments = &.{.integer} };
fn move_cursor_left_vim(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) error{Stop}!void {
move_cursor_left_unless(root, cursor, is_eol_left, metrics);
}
fn move_cursor_right_vim(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) error{Stop}!void {
move_cursor_right_unless(root, cursor, is_eol_right_vim, metrics);
}
pub fn move_left_vim(self: *Self, ctx: Context) Result {
const root = try self.buf_root();
self.with_cursors_const_repeat(root, move_cursor_left_vim, ctx) catch {};
self.clamp();
}
pub const move_left_vim_meta: Meta = .{ .description = "Move cursor left (vim)", .arguments = &.{.integer} };
pub fn move_right_vim(self: *Self, ctx: Context) Result {
const root = try self.buf_root();
self.with_cursors_const_repeat(root, move_cursor_right_vim, ctx) catch {};
self.clamp();
}
pub const move_right_vim_meta: Meta = .{ .description = "Move cursor right (vim)", .arguments = &.{.integer} };
fn move_cursor_word_begin(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) error{Stop}!void { fn move_cursor_word_begin(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) error{Stop}!void {
if (is_non_word_char_at_cursor(root, cursor, metrics)) { if (is_non_word_char_at_cursor(root, cursor, metrics)) {
move_cursor_left_until(root, cursor, is_word_boundary_right, metrics); move_cursor_left_until(root, cursor, is_word_boundary_right, metrics);
@ -3568,13 +3483,6 @@ pub const Editor = struct {
} }
pub const move_up_meta: Meta = .{ .description = "Move cursor up", .arguments = &.{.integer} }; pub const move_up_meta: Meta = .{ .description = "Move cursor up", .arguments = &.{.integer} };
pub fn move_up_vim(self: *Self, ctx: Context) Result {
const root = try self.buf_root();
self.with_cursors_const_repeat(root, move_cursor_up_vim, ctx) catch {};
self.clamp();
}
pub const move_up_vim_meta: Meta = .{ .description = "Move cursor up (vim)", .arguments = &.{.integer} };
pub fn add_cursor_up(self: *Self, ctx: Context) Result { pub fn add_cursor_up(self: *Self, ctx: Context) Result {
const root = try self.buf_root(); const root = try self.buf_root();
var repeat: usize = 1; var repeat: usize = 1;
@ -3595,13 +3503,6 @@ pub const Editor = struct {
} }
pub const move_down_meta: Meta = .{ .description = "Move cursor down", .arguments = &.{.integer} }; pub const move_down_meta: Meta = .{ .description = "Move cursor down", .arguments = &.{.integer} };
pub fn move_down_vim(self: *Self, ctx: Context) Result {
const root = try self.buf_root();
self.with_cursors_const_repeat(root, move_cursor_down_vim, ctx) catch {};
self.clamp();
}
pub const move_down_vim_meta: Meta = .{ .description = "Move cursor down (vim)", .arguments = &.{.integer} };
pub fn add_cursor_down(self: *Self, ctx: Context) Result { pub fn add_cursor_down(self: *Self, ctx: Context) Result {
var repeat: usize = 1; var repeat: usize = 1;
_ = ctx.args.match(.{tp.extract(&repeat)}) catch false; _ = ctx.args.match(.{tp.extract(&repeat)}) catch false;
@ -3657,7 +3558,7 @@ pub const Editor = struct {
pub const add_cursor_all_matches_meta: Meta = .{ .description = "Add cursors to all highlighted matches" }; pub const add_cursor_all_matches_meta: Meta = .{ .description = "Add cursors to all highlighted matches" };
fn add_cursors_to_cursel_line_ends(self: *Self, root: Buffer.Root, cursel: *CurSel) !void { fn add_cursors_to_cursel_line_ends(self: *Self, root: Buffer.Root, cursel: *CurSel) !void {
const sel = cursel.enable_selection(root, self.metrics); const sel = cursel.enable_selection();
sel.normalize(); sel.normalize();
var row = sel.begin.row; var row = sel.begin.row;
while (row <= sel.end.row) : (row += 1) { while (row <= sel.end.row) : (row += 1) {
@ -3751,7 +3652,7 @@ pub const Editor = struct {
cursel.cursor = sel.begin; cursel.cursor = sel.begin;
var add_eol = false; var add_eol = false;
if (cursel.selection) |_| { if (cursel.selection) |_| {
cursel.disable_selection(root, self.metrics); cursel.disable_selection();
} else { } else {
var test_eof = sel.end; var test_eof = sel.end;
test_eof.move_right(root, self.metrics) catch { // test for EOF test_eof.move_right(root, self.metrics) catch { // test for EOF
@ -3786,7 +3687,7 @@ pub const Editor = struct {
cursel.cursor = sel.end; cursel.cursor = sel.end;
if (cursel.selection) |_| { if (cursel.selection) |_| {
cursel.disable_selection(root, self.metrics); cursel.disable_selection();
} else { } else {
var test_eof = sel.end; var test_eof = sel.end;
test_eof.move_right(root, self.metrics) catch { // test for EOF test_eof.move_right(root, self.metrics) catch { // test for EOF
@ -3840,7 +3741,7 @@ pub const Editor = struct {
cursel.cursor = sel.end; cursel.cursor = sel.end;
if (cursel.selection) |_| { if (cursel.selection) |_| {
cursel.disable_selection(root, self.metrics); cursel.disable_selection();
} else { } else {
var test_eof = sel.end; var test_eof = sel.end;
test_eof.move_right(root, self.metrics) catch { // test for EOF test_eof.move_right(root, self.metrics) catch { // test for EOF
@ -3944,7 +3845,7 @@ pub const Editor = struct {
if (first == 0) return root; if (first == 0) return root;
const off = first % self.indent_size; const off = first % self.indent_size;
const cols = if (off == 0) self.indent_size else off; const cols = if (off == 0) self.indent_size else off;
const sel = cursel.enable_selection(root, self.metrics); const sel = cursel.enable_selection();
try sel.begin.move_to(root, sel.begin.row, first, self.metrics); try sel.begin.move_to(root, sel.begin.row, first, self.metrics);
try sel.end.move_to(root, sel.end.row, first - cols, self.metrics); try sel.end.move_to(root, sel.end.row, first - cols, self.metrics);
var saved = false; var saved = false;
@ -4039,54 +3940,6 @@ pub const Editor = struct {
} }
pub const move_scroll_page_down_meta: Meta = .{ .description = "Move and scroll page down" }; pub const move_scroll_page_down_meta: Meta = .{ .description = "Move and scroll page down" };
pub fn move_scroll_half_page_up(self: *Self, _: Context) Result {
if (self.screen_cursor(&self.get_primary().cursor)) |cursor| {
const root = try self.buf_root();
self.with_cursors_and_view_const(root, move_cursor_half_page_up, &self.view) catch {};
const new_cursor_row = self.get_primary().cursor.row;
self.update_scroll_dest_abs(if (cursor.row > new_cursor_row) 0 else new_cursor_row - cursor.row);
} else {
return self.move_half_page_up(.{});
}
}
pub const move_scroll_half_page_up_meta: Meta = .{ .description = "Move and scroll half a page up" };
pub fn move_scroll_half_page_up_vim(self: *Self, _: Context) Result {
if (self.screen_cursor(&self.get_primary().cursor)) |cursor| {
const root = try self.buf_root();
self.with_cursors_and_view_const(root, move_cursor_half_page_up_vim, &self.view) catch {};
const new_cursor_row = self.get_primary().cursor.row;
self.update_scroll_dest_abs(if (cursor.row > new_cursor_row) 0 else new_cursor_row - cursor.row);
} else {
return self.move_half_page_up(.{});
}
}
pub const move_scroll_half_page_up_vim_meta: Meta = .{ .description = "Move and scroll half a page up (vim)" };
pub fn move_scroll_half_page_down(self: *Self, _: Context) Result {
if (self.screen_cursor(&self.get_primary().cursor)) |cursor| {
const root = try self.buf_root();
self.with_cursors_and_view_const(root, move_cursor_half_page_down, &self.view) catch {};
const new_cursor_row = self.get_primary().cursor.row;
self.update_scroll_dest_abs(if (cursor.row > new_cursor_row) 0 else new_cursor_row - cursor.row);
} else {
return self.move_half_page_down(.{});
}
}
pub const move_scroll_half_page_down_meta: Meta = .{ .description = "Move and scroll half a page down" };
pub fn move_scroll_half_page_down_vim(self: *Self, _: Context) Result {
if (self.screen_cursor(&self.get_primary().cursor)) |cursor| {
const root = try self.buf_root();
self.with_cursors_and_view_const(root, move_cursor_half_page_down_vim, &self.view) catch {};
const new_cursor_row = self.get_primary().cursor.row;
self.update_scroll_dest_abs(if (cursor.row > new_cursor_row) 0 else new_cursor_row - cursor.row);
} else {
return self.move_half_page_down(.{});
}
}
pub const move_scroll_half_page_down_vim_meta: Meta = .{ .description = "Move and scroll half a page down (vim)" };
pub fn smart_move_begin(self: *Self, _: Context) Result { pub fn smart_move_begin(self: *Self, _: Context) Result {
const root = try self.buf_root(); const root = try self.buf_root();
try self.with_cursors_const_once(root, smart_move_cursor_begin); try self.with_cursors_const_once(root, smart_move_cursor_begin);
@ -4169,8 +4022,7 @@ pub const Editor = struct {
pub const cancel_meta: Meta = .{ .description = "Cancel current action" }; pub const cancel_meta: Meta = .{ .description = "Cancel current action" };
pub fn enable_selection(self: *Self, _: Context) Result { pub fn enable_selection(self: *Self, _: Context) Result {
const root = try self.buf_root(); _ = self.get_primary().enable_selection();
_ = self.get_primary().enable_selection(root, self.metrics);
} }
pub const enable_selection_meta: Meta = .{ .description = "Enable selection" }; pub const enable_selection_meta: Meta = .{ .description = "Enable selection" };
@ -4376,30 +4228,12 @@ pub const Editor = struct {
} }
pub const select_page_down_meta: Meta = .{ .description = "Select page down" }; pub const select_page_down_meta: Meta = .{ .description = "Select page down" };
pub fn select_half_page_up(self: *Self, _: Context) Result {
try self.send_editor_jump_source();
const root = try self.buf_root();
try self.with_selections_and_view_const(root, move_cursor_half_page_up, &self.view);
self.clamp();
try self.send_editor_jump_destination();
}
pub const select_half_page_up_meta: Meta = .{ .description = "Select half a page up" };
pub fn select_half_page_down(self: *Self, _: Context) Result {
try self.send_editor_jump_source();
const root = try self.buf_root();
try self.with_selections_and_view_const(root, move_cursor_half_page_down, &self.view);
self.clamp();
try self.send_editor_jump_destination();
}
pub const select_half_page_down_meta: Meta = .{ .description = "Select half a page down" };
pub fn select_all(self: *Self, _: Context) Result { pub fn select_all(self: *Self, _: Context) Result {
try self.send_editor_jump_source(); try self.send_editor_jump_source();
self.cancel_all_selections(); self.cancel_all_selections();
const primary = self.get_primary(); const primary = self.get_primary();
const root = try self.buf_root(); const root = try self.buf_root();
const sel = primary.enable_selection(root, self.metrics); const sel = primary.enable_selection();
try expand_selection_to_all(root, sel, self.metrics); try expand_selection_to_all(root, sel, self.metrics);
primary.cursor = sel.end; primary.cursor = sel.end;
self.clamp(); self.clamp();
@ -4409,8 +4243,8 @@ pub const Editor = struct {
fn select_word_at_cursor(self: *Self, cursel: *CurSel) !*Selection { fn select_word_at_cursor(self: *Self, cursel: *CurSel) !*Selection {
const root = try self.buf_root(); const root = try self.buf_root();
const sel = cursel.enable_selection(root, self.metrics); const sel = cursel.enable_selection();
defer cursel.check_selection(root, self.metrics); defer cursel.check_selection();
sel.normalize(); sel.normalize();
try move_cursor_word_begin(root, &sel.begin, self.metrics); try move_cursor_word_begin(root, &sel.begin, self.metrics);
move_cursor_word_end(root, &sel.end, self.metrics) catch {}; move_cursor_word_end(root, &sel.end, self.metrics) catch {};
@ -4419,7 +4253,7 @@ pub const Editor = struct {
} }
pub fn select_line_at_cursor(self: *Self, root: Buffer.Root, cursel: *CurSel, mode: enum { include_eol, exclude_eol, hold_cursor }) !void { pub fn select_line_at_cursor(self: *Self, root: Buffer.Root, cursel: *CurSel, mode: enum { include_eol, exclude_eol, hold_cursor }) !void {
const sel = cursel.enable_selection(root, self.metrics); const sel = cursel.enable_selection();
sel.normalize(); sel.normalize();
try move_cursor_begin(root, &sel.begin, self.metrics); try move_cursor_begin(root, &sel.begin, self.metrics);
move_cursor_end(root, &sel.end, self.metrics) catch {}; move_cursor_end(root, &sel.end, self.metrics) catch {};
@ -4483,12 +4317,12 @@ pub const Editor = struct {
} }
fn top_node_at_cursel(self: *const Self, cursel: *const CurSel, root: Buffer.Root, metrics: Buffer.Metrics) error{Stop}!syntax.Node { fn top_node_at_cursel(self: *const Self, cursel: *const CurSel, root: Buffer.Root, metrics: Buffer.Metrics) error{Stop}!syntax.Node {
const sel = cursel.to_selection(root, metrics); const sel = cursel.to_selection();
return try self.top_node_at_selection(sel, root, metrics); return try self.top_node_at_selection(sel, root, metrics);
} }
fn expand_selection_to_parent_node(self: *Self, root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics) !void { fn expand_selection_to_parent_node(self: *Self, root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics) !void {
const sel = cursel.enable_selection(root, metrics).*; const sel = cursel.enable_selection().*;
var node = try self.top_node_at_selection(sel, root, metrics); var node = try self.top_node_at_selection(sel, root, metrics);
if (node.isNull()) return error.Stop; if (node.isNull()) return error.Stop;
var node_sel = CurSel.selection_from_node(node, root, metrics); var node_sel = CurSel.selection_from_node(node, root, metrics);
@ -4502,7 +4336,7 @@ pub const Editor = struct {
try self.send_editor_jump_source(); try self.send_editor_jump_source();
const root = try self.buf_root(); const root = try self.buf_root();
const cursel = self.get_primary(); const cursel = self.get_primary();
cursel.check_selection(root, self.metrics); cursel.check_selection();
try if (cursel.selection) |_| try if (cursel.selection) |_|
self.expand_selection_to_parent_node(root, cursel, self.metrics) self.expand_selection_to_parent_node(root, cursel, self.metrics)
else else
@ -4513,7 +4347,7 @@ pub const Editor = struct {
pub const expand_selection_meta: Meta = .{ .description = "Expand selection to AST parent node" }; pub const expand_selection_meta: Meta = .{ .description = "Expand selection to AST parent node" };
fn shrink_selection_to_child_node(self: *Self, root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics) !void { fn shrink_selection_to_child_node(self: *Self, root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics) !void {
const sel = cursel.enable_selection(root, metrics).*; const sel = cursel.enable_selection().*;
const node = try self.node_at_selection(sel, root, metrics); const node = try self.node_at_selection(sel, root, metrics);
if (node.isNull() or node.getChildCount() == 0) return error.Stop; if (node.isNull() or node.getChildCount() == 0) return error.Stop;
const child = node.getChild(0); const child = node.getChild(0);
@ -4522,7 +4356,7 @@ pub const Editor = struct {
} }
fn shrink_selection_to_named_child_node(self: *Self, root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics) !void { fn shrink_selection_to_named_child_node(self: *Self, root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics) !void {
const sel = cursel.enable_selection(root, metrics).*; const sel = cursel.enable_selection().*;
const node = try self.node_at_selection(sel, root, metrics); const node = try self.node_at_selection(sel, root, metrics);
if (node.isNull() or node.getNamedChildCount() == 0) return error.Stop; if (node.isNull() or node.getNamedChildCount() == 0) return error.Stop;
const child = node.getNamedChild(0); const child = node.getNamedChild(0);
@ -4536,7 +4370,7 @@ pub const Editor = struct {
try self.send_editor_jump_source(); try self.send_editor_jump_source();
const root = try self.buf_root(); const root = try self.buf_root();
const cursel = self.get_primary(); const cursel = self.get_primary();
cursel.check_selection(root, self.metrics); cursel.check_selection();
if (cursel.selection) |_| { if (cursel.selection) |_| {
try if (unnamed) try if (unnamed)
self.shrink_selection_to_child_node(root, cursel, self.metrics) self.shrink_selection_to_child_node(root, cursel, self.metrics)
@ -4570,7 +4404,7 @@ pub const Editor = struct {
try self.send_editor_jump_source(); try self.send_editor_jump_source();
const root = try self.buf_root(); const root = try self.buf_root();
const cursel = self.get_primary(); const cursel = self.get_primary();
cursel.check_selection(root, self.metrics); cursel.check_selection();
if (cursel.selection) |_| { if (cursel.selection) |_| {
try if (unnamed) try if (unnamed)
self.select_next_sibling_node(root, cursel, self.metrics) self.select_next_sibling_node(root, cursel, self.metrics)
@ -4604,7 +4438,7 @@ pub const Editor = struct {
try self.send_editor_jump_source(); try self.send_editor_jump_source();
const root = try self.buf_root(); const root = try self.buf_root();
const cursel = self.get_primary(); const cursel = self.get_primary();
cursel.check_selection(root, self.metrics); cursel.check_selection();
try if (unnamed) try if (unnamed)
self.select_prev_sibling_node(root, cursel, self.metrics) self.select_prev_sibling_node(root, cursel, self.metrics)
else else
@ -4680,7 +4514,7 @@ pub const Editor = struct {
root_ = self.collapse_trailing_ws_line(root_, row, b_allocator); root_ = self.collapse_trailing_ws_line(root_, row, b_allocator);
const leading_ws_ = find_first_non_ws(root_, cursel.cursor.row, self.metrics); const leading_ws_ = find_first_non_ws(root_, cursel.cursor.row, self.metrics);
if (leading_ws_ > leading_ws and leading_ws_ > cursel.cursor.col) { if (leading_ws_ > leading_ws and leading_ws_ > cursel.cursor.col) {
const sel = cursel.enable_selection(root_, self.metrics); const sel = cursel.enable_selection();
sel.* = .{ sel.* = .{
.begin = .{ .row = cursel.cursor.row, .col = cursel.cursor.col }, .begin = .{ .row = cursel.cursor.row, .col = cursel.cursor.col },
.end = .{ .row = cursel.cursor.row, .col = leading_ws_ }, .end = .{ .row = cursel.cursor.row, .col = leading_ws_ },
@ -4866,7 +4700,7 @@ pub const Editor = struct {
root = try self.insert(root, &begin, chars_begin, b.allocator); root = try self.insert(root, &begin, chars_begin, b.allocator);
var end: CurSel = .{ .cursor = sel.end }; var end: CurSel = .{ .cursor = sel.end };
root = try self.insert(root, &end, chars_end, b.allocator); root = try self.insert(root, &end, chars_end, b.allocator);
cursel.disable_selection(root, self.metrics); cursel.disable_selection();
} else blk: { } else blk: {
const egc, _, _ = cursel.cursor.egc_at(root, self.metrics) catch { const egc, _, _ = cursel.cursor.egc_at(root, self.metrics) catch {
root = try self.insert(root, cursel, chars_right, b.allocator); root = try self.insert(root, cursel, chars_right, b.allocator);
@ -5469,10 +5303,7 @@ pub const Editor = struct {
const col = cursor.col; const col = cursor.col;
for (self.matches.items) |*match_| if (match_.*) |*match| { for (self.matches.items) |*match_| if (match_.*) |*match| {
if (match.has_selection) continue; if (match.has_selection) continue;
switch (tui.get_selection_style()) { if (cursor.within(match.to_selection())) return match;
.normal => if (cursor.within(match.to_selection())) return match,
.inclusive => {},
}
if (row < match.begin.row or (row == match.begin.row and col < match.begin.col)) return match; if (row < match.begin.row or (row == match.begin.row and col < match.begin.col)) return match;
}; };
return null; return null;
@ -5634,18 +5465,6 @@ pub const Editor = struct {
} }
pub const goto_line_meta: Meta = .{ .arguments = &.{.integer} }; pub const goto_line_meta: Meta = .{ .arguments = &.{.integer} };
pub fn goto_line_vim(self: *Self, ctx: Context) Result {
try self.send_editor_jump_source();
var line: usize = 0;
_ = ctx.args.match(.{tp.extract(&line)}) catch false;
const root = self.buf_root() catch return;
const primary = self.get_primary();
try primary.cursor.move_to(root, @intCast(if (line < 1) 0 else line - 1), primary.cursor.col, self.metrics);
self.clamp();
try self.send_editor_jump_destination();
}
pub const goto_line_vim_meta: Meta = .{ .arguments = &.{.integer} };
pub fn goto_column(self: *Self, ctx: Context) Result { pub fn goto_column(self: *Self, ctx: Context) Result {
const root = self.buf_root() catch return; const root = self.buf_root() catch return;
const primary = self.get_primary(); const primary = self.get_primary();
@ -6161,7 +5980,7 @@ pub const Editor = struct {
state.chunks = 1; state.chunks = 1;
primary.cursor = state.old_primary.cursor; primary.cursor = state.old_primary.cursor;
} else { } else {
const sel = primary.enable_selection(root, self.metrics); const sel = primary.enable_selection();
sel.begin = state.begin; sel.begin = state.begin;
sel.end = state.pos.cursor; sel.end = state.pos.cursor;
if (state.old_primary_reversed) sel.reverse(); if (state.old_primary_reversed) sel.reverse();
@ -6190,7 +6009,7 @@ pub const Editor = struct {
var root = root_; var root = root_;
const saved = cursel.*; const saved = cursel.*;
const sel = if (cursel.selection) |*sel| sel else ret: { const sel = if (cursel.selection) |*sel| sel else ret: {
var sel = cursel.enable_selection(root, self.metrics); var sel = cursel.enable_selection();
move_cursor_word_begin(root, &sel.begin, self.metrics) catch return error.Stop; move_cursor_word_begin(root, &sel.begin, self.metrics) catch return error.Stop;
move_cursor_word_end(root, &sel.end, self.metrics) catch return error.Stop; move_cursor_word_end(root, &sel.end, self.metrics) catch return error.Stop;
break :ret sel; break :ret sel;
@ -6219,7 +6038,7 @@ pub const Editor = struct {
var root = root_; var root = root_;
const saved = cursel.*; const saved = cursel.*;
const sel = if (cursel.selection) |*sel| sel else ret: { const sel = if (cursel.selection) |*sel| sel else ret: {
var sel = cursel.enable_selection(root, self.metrics); var sel = cursel.enable_selection();
move_cursor_word_begin(root, &sel.begin, self.metrics) catch return error.Stop; move_cursor_word_begin(root, &sel.begin, self.metrics) catch return error.Stop;
move_cursor_word_end(root, &sel.end, self.metrics) catch return error.Stop; move_cursor_word_end(root, &sel.end, self.metrics) catch return error.Stop;
break :ret sel; break :ret sel;
@ -6248,7 +6067,7 @@ pub const Editor = struct {
var root = root_; var root = root_;
var saved = cursel.*; var saved = cursel.*;
const sel = if (cursel.selection) |*sel| sel else ret: { const sel = if (cursel.selection) |*sel| sel else ret: {
var sel = cursel.enable_selection(root, self.metrics); var sel = cursel.enable_selection();
move_cursor_right(root, &sel.end, self.metrics) catch return error.Stop; move_cursor_right(root, &sel.end, self.metrics) catch return error.Stop;
saved.cursor = sel.end; saved.cursor = sel.end;
break :ret sel; break :ret sel;

File diff suppressed because it is too large Load diff

View file

@ -405,16 +405,6 @@ const cmds = struct {
} }
pub const overlay_insert_bytes_meta: Meta = .{ .arguments = &.{.string} }; pub const overlay_insert_bytes_meta: Meta = .{ .arguments = &.{.string} };
pub fn overlay_toggle_panel(self: *Self, _: Ctx) Result {
return self.cmd_async("toggle_panel");
}
pub const overlay_toggle_panel_meta: Meta = .{};
pub fn overlay_toggle_inputview(self: *Self, _: Ctx) Result {
return self.cmd_async("toggle_inputview");
}
pub const overlay_toggle_inputview_meta: Meta = .{};
pub fn overlay_next_widget_style(self: *Self, _: Ctx) Result { pub fn overlay_next_widget_style(self: *Self, _: Ctx) Result {
tui.set_next_style(widget_type); tui.set_next_style(widget_type);
self.do_resize(); self.do_resize();

View file

@ -598,16 +598,6 @@ pub fn Create(options: type) type {
} }
pub const overlay_insert_bytes_meta: Meta = .{ .arguments = &.{.string} }; pub const overlay_insert_bytes_meta: Meta = .{ .arguments = &.{.string} };
pub fn overlay_toggle_panel(self: *Self, _: Ctx) Result {
return self.cmd_async("toggle_panel");
}
pub const overlay_toggle_panel_meta: Meta = .{};
pub fn overlay_toggle_inputview(self: *Self, _: Ctx) Result {
return self.cmd_async("toggle_inputview");
}
pub const overlay_toggle_inputview_meta: Meta = .{};
pub fn overlay_next_widget_style(self: *Self, _: Ctx) Result { pub fn overlay_next_widget_style(self: *Self, _: Ctx) Result {
tui.set_next_style(widget_type); tui.set_next_style(widget_type);
const padding = tui.get_widget_style(widget_type).padding; const padding = tui.get_widget_style(widget_type).padding;

View file

@ -366,16 +366,6 @@ const cmds = struct {
} }
pub const overlay_insert_bytes_meta: Meta = .{ .arguments = &.{.string} }; pub const overlay_insert_bytes_meta: Meta = .{ .arguments = &.{.string} };
pub fn overlay_toggle_panel(self: *Self, _: Ctx) Result {
return self.cmd_async("toggle_panel");
}
pub const overlay_toggle_panel_meta: Meta = .{};
pub fn overlay_toggle_inputview(self: *Self, _: Ctx) Result {
return self.cmd_async("toggle_inputview");
}
pub const overlay_toggle_inputview_meta: Meta = .{};
pub fn overlay_next_widget_style(self: *Self, _: Ctx) Result { pub fn overlay_next_widget_style(self: *Self, _: Ctx) Result {
tui.set_next_style(widget_type); tui.set_next_style(widget_type);
self.do_resize(); self.do_resize();

View file

@ -1,12 +1,21 @@
const std = @import("std"); const std = @import("std");
const command = @import("command"); const command = @import("command");
const tp = @import("thespian");
const cmd = command.executeName; const cmd = command.executeName;
const tui = @import("../tui.zig");
const Editor = @import("../editor.zig").Editor;
const Buffer = @import("Buffer");
const Cursor = Buffer.Cursor;
const View = Buffer.View;
var commands: Commands = undefined; var commands: Commands = undefined;
const Self = Editor;
pub fn init() !void { pub fn init() !void {
var v: void = {}; const mv = tui.mainview() orelse return;
try commands.init(&v); const ed = mv.get_active_editor() orelse return;
try commands.init(ed);
} }
pub fn deinit() void { pub fn deinit() void {
@ -14,74 +23,75 @@ pub fn deinit() void {
} }
const Commands = command.Collection(cmds_); const Commands = command.Collection(cmds_);
const cmds_ = struct { const Context = command.Context;
pub const Target = void; const Meta = command.Metadata;
const Ctx = command.Context; const Result = command.Result;
const Meta = command.Metadata;
const Result = command.Result;
pub fn w(_: *void, _: Ctx) Result { const cmds_ = struct {
pub const Target = Self;
pub fn w(_: *Self, _: Context) Result {
try cmd("save_file", .{}); try cmd("save_file", .{});
} }
pub const w_meta: Meta = .{ .description = "w (write file)" }; pub const w_meta: Meta = .{ .description = "w (write file)" };
pub fn q(_: *void, _: Ctx) Result { pub fn q(_: *Self, _: Context) Result {
try cmd("quit", .{}); try cmd("quit", .{});
} }
pub const q_meta: Meta = .{ .description = "q (quit)" }; pub const q_meta: Meta = .{ .description = "q (quit)" };
pub fn @"q!"(_: *void, _: Ctx) Result { pub fn @"q!"(_: *Self, _: Context) Result {
try cmd("quit_without_saving", .{}); try cmd("quit_without_saving", .{});
} }
pub const @"q!_meta": Meta = .{ .description = "q! (quit without saving)" }; pub const @"q!_meta": Meta = .{ .description = "q! (quit without saving)" };
pub fn @"qa!"(_: *void, _: Ctx) Result { pub fn @"qa!"(_: *Self, _: Context) Result {
try cmd("quit_without_saving", .{}); try cmd("quit_without_saving", .{});
} }
pub const @"qa!_meta": Meta = .{ .description = "qa! (quit without saving anything)" }; pub const @"qa!_meta": Meta = .{ .description = "qa! (quit without saving anything)" };
pub fn wq(_: *void, _: Ctx) Result { pub fn wq(_: *Self, _: Context) Result {
try cmd("save_file", command.fmt(.{ "then", .{ "quit", .{} } })); try cmd("save_file", command.fmt(.{ "then", .{ "quit", .{} } }));
} }
pub const wq_meta: Meta = .{ .description = "wq (write file and quit)" }; pub const wq_meta: Meta = .{ .description = "wq (write file and quit)" };
pub fn @"wq!"(_: *void, _: Ctx) Result { pub fn @"wq!"(_: *Self, _: Context) Result {
cmd("save_file", .{}) catch {}; cmd("save_file", .{}) catch {};
try cmd("quit_without_saving", .{}); try cmd("quit_without_saving", .{});
} }
pub const @"wq!_meta": Meta = .{ .description = "wq! (write file and quit without saving)" }; pub const @"wq!_meta": Meta = .{ .description = "wq! (write file and quit without saving)" };
pub fn @"e!"(_: *void, _: Ctx) Result { pub fn @"e!"(_: *Self, _: Context) Result {
try cmd("reload_file", .{}); try cmd("reload_file", .{});
} }
pub const @"e!_meta": Meta = .{ .description = "e! (force reload current file)" }; pub const @"e!_meta": Meta = .{ .description = "e! (force reload current file)" };
pub fn bd(_: *void, _: Ctx) Result { pub fn bd(_: *Self, _: Context) Result {
try cmd("close_file", .{}); try cmd("close_file", .{});
} }
pub const bd_meta: Meta = .{ .description = "bd (Close file)" }; pub const bd_meta: Meta = .{ .description = "bd (Close file)" };
pub fn bw(_: *void, _: Ctx) Result { pub fn bw(_: *Self, _: Context) Result {
try cmd("delete_buffer", .{}); try cmd("delete_buffer", .{});
} }
pub const bw_meta: Meta = .{ .description = "bw (Delete buffer)" }; pub const bw_meta: Meta = .{ .description = "bw (Delete buffer)" };
pub fn bnext(_: *void, _: Ctx) Result { pub fn bnext(_: *Self, _: Context) Result {
try cmd("next_tab", .{}); try cmd("next_tab", .{});
} }
pub const bnext_meta: Meta = .{ .description = "bnext (Next buffer/tab)" }; pub const bnext_meta: Meta = .{ .description = "bnext (Next buffer/tab)" };
pub fn bprevious(_: *void, _: Ctx) Result { pub fn bprevious(_: *Self, _: Context) Result {
try cmd("next_tab", .{}); try cmd("next_tab", .{});
} }
pub const bprevious_meta: Meta = .{ .description = "bprevious (Previous buffer/tab)" }; pub const bprevious_meta: Meta = .{ .description = "bprevious (Previous buffer/tab)" };
pub fn ls(_: *void, _: Ctx) Result { pub fn ls(_: *Self, _: Context) Result {
try cmd("switch_buffers", .{}); try cmd("switch_buffers", .{});
} }
pub const ls_meta: Meta = .{ .description = "ls (List/switch buffers)" }; pub const ls_meta: Meta = .{ .description = "ls (List/switch buffers)" };
pub fn move_begin_or_add_integer_argument_zero(_: *void, _: Ctx) Result { pub fn move_begin_or_add_integer_argument_zero(_: *Self, _: Context) Result {
return if (@import("keybind").current_integer_argument()) |_| return if (@import("keybind").current_integer_argument()) |_|
command.executeName("add_integer_argument_digit", command.fmt(.{0})) command.executeName("add_integer_argument_digit", command.fmt(.{0}))
else else
@ -89,7 +99,7 @@ const cmds_ = struct {
} }
pub const move_begin_or_add_integer_argument_zero_meta: Meta = .{ .description = "Move cursor to beginning of line (vim)" }; pub const move_begin_or_add_integer_argument_zero_meta: Meta = .{ .description = "Move cursor to beginning of line (vim)" };
pub fn enter_mode_at_next_char(self: *void, ctx: Ctx) Result { pub fn enter_mode_at_next_char(self: *Self, ctx: Context) Result {
_ = self; // autofix _ = self; // autofix
_ = ctx; // autofix _ = ctx; // autofix
//TODO //TODO
@ -98,7 +108,7 @@ const cmds_ = struct {
pub const enter_mode_at_next_char_meta: Meta = .{ .description = "Move forward one char and change mode" }; pub const enter_mode_at_next_char_meta: Meta = .{ .description = "Move forward one char and change mode" };
pub fn enter_mode_on_newline_down(self: *void, ctx: Ctx) Result { pub fn enter_mode_on_newline_down(self: *Self, ctx: Context) Result {
_ = self; // autofix _ = self; // autofix
_ = ctx; // autofix _ = ctx; // autofix
//TODO //TODO
@ -107,7 +117,7 @@ const cmds_ = struct {
pub const enter_mode_on_newline_down_meta: Meta = .{ .description = "Insert a newline and change mode" }; pub const enter_mode_on_newline_down_meta: Meta = .{ .description = "Insert a newline and change mode" };
pub fn enter_mode_on_newline_up(self: *void, ctx: Ctx) Result { pub fn enter_mode_on_newline_up(self: *Self, ctx: Context) Result {
_ = self; // autofix _ = self; // autofix
_ = ctx; // autofix _ = ctx; // autofix
//TODO //TODO
@ -115,7 +125,7 @@ const cmds_ = struct {
} }
pub const enter_mode_on_newline_up_meta: Meta = .{ .description = "Insert a newline above the current line and change mode" }; pub const enter_mode_on_newline_up_meta: Meta = .{ .description = "Insert a newline above the current line and change mode" };
pub fn enter_mode_at_line_begin(self: *void, ctx: Ctx) Result { pub fn enter_mode_at_line_begin(self: *Self, ctx: Context) Result {
_ = self; // autofix _ = self; // autofix
_ = ctx; // autofix _ = ctx; // autofix
//TODO //TODO
@ -124,7 +134,7 @@ const cmds_ = struct {
pub const enter_mode_at_line_begin_meta: Meta = .{ .description = "Goto line begin and change mode" }; pub const enter_mode_at_line_begin_meta: Meta = .{ .description = "Goto line begin and change mode" };
pub fn enter_mode_at_line_end(self: *void, ctx: Ctx) Result { pub fn enter_mode_at_line_end(self: *Self, ctx: Context) Result {
_ = self; // autofix _ = self; // autofix
_ = ctx; // autofix _ = ctx; // autofix
//TODO //TODO
@ -132,7 +142,7 @@ const cmds_ = struct {
} }
pub const enter_mode_at_line_end_meta: Meta = .{ .description = "Goto line end and change mode" }; pub const enter_mode_at_line_end_meta: Meta = .{ .description = "Goto line end and change mode" };
pub fn copy_line(self: *void, ctx: Ctx) Result { pub fn copy_line(self: *Self, ctx: Context) Result {
_ = self; // autofix _ = self; // autofix
_ = ctx; // autofix _ = ctx; // autofix
//TODO //TODO
@ -140,4 +150,124 @@ const cmds_ = struct {
} }
pub const copy_line_meta: Meta = .{ .description = "Copies the current line" }; pub const copy_line_meta: Meta = .{ .description = "Copies the current line" };
pub fn move_scroll_half_page_up(self: *Self, _: Context) Result {
if (self.screen_cursor(&self.get_primary().cursor)) |cursor| {
const root = try self.buf_root();
self.with_cursors_and_view_const(root, move_cursor_half_page_up, &self.view) catch {};
const new_cursor_row = self.get_primary().cursor.row;
self.update_scroll_dest_abs(if (cursor.row > new_cursor_row) 0 else new_cursor_row - cursor.row);
} else {
return self.move_half_page_up(.{});
}
}
pub const move_scroll_half_page_up_meta: Meta = .{ .description = "Move and scroll half a page up" };
pub fn move_scroll_half_page_down(self: *Self, _: Context) Result {
if (self.screen_cursor(&self.get_primary().cursor)) |cursor| {
const root = try self.buf_root();
self.with_cursors_and_view_const(root, move_cursor_half_page_down, &self.view) catch {};
const new_cursor_row = self.get_primary().cursor.row;
self.update_scroll_dest_abs(if (cursor.row > new_cursor_row) 0 else new_cursor_row - cursor.row);
} else {
return self.move_half_page_down(.{});
}
}
pub const move_scroll_half_page_down_meta: Meta = .{ .description = "Move and scroll half a page down" };
pub fn move_left_vim(self: *Self, ctx: Context) Result {
const root = try self.buf_root();
self.with_cursors_const_repeat(root, move_cursor_left_vim, ctx) catch {};
self.clamp();
}
pub const move_left_vim_meta: Meta = .{ .description = "Move cursor left (vim)", .arguments = &.{.integer} };
pub fn move_right_vim(self: *Self, ctx: Context) Result {
const root = try self.buf_root();
self.with_cursors_const_repeat(root, move_cursor_right_vim, ctx) catch {};
self.clamp();
}
pub const move_right_vim_meta: Meta = .{ .description = "Move cursor right (vim)", .arguments = &.{.integer} };
pub fn cut_to_end_vim(self: *Self, _: Context) Result {
const b = try self.buf_for_update();
const root = try self.cut_to(move_cursor_end_vim, b.root);
try self.update_buf(root);
self.clamp();
}
pub const cut_to_end_vim_meta: Meta = .{ .description = "Cut to end of line (vim)" };
pub fn move_up_vim(self: *Self, ctx: Context) Result {
const root = try self.buf_root();
self.with_cursors_const_repeat(root, move_cursor_up_vim, ctx) catch {};
self.clamp();
}
pub const move_up_vim_meta: Meta = .{ .description = "Move cursor up (vim)", .arguments = &.{.integer} };
pub fn move_down_vim(self: *Self, ctx: Context) Result {
const root = try self.buf_root();
self.with_cursors_const_repeat(root, move_cursor_down_vim, ctx) catch {};
self.clamp();
}
pub const move_down_vim_meta: Meta = .{ .description = "Move cursor down (vim)", .arguments = &.{.integer} };
pub fn goto_line_vim(self: *Self, ctx: Context) Result {
try self.send_editor_jump_source();
var line: usize = 0;
_ = ctx.args.match(.{tp.extract(&line)}) catch false;
const root = self.buf_root() catch return;
const primary = self.get_primary();
try primary.cursor.move_to(root, @intCast(if (line < 1) 0 else line - 1), primary.cursor.col, self.metrics);
self.clamp();
try self.send_editor_jump_destination();
}
pub const goto_line_vim_meta: Meta = .{ .arguments = &.{.integer} };
}; };
fn is_eol_right_vim(root: Buffer.Root, cursor: *const Cursor, metrics: Buffer.Metrics) bool {
const line_width = root.line_width(cursor.row, metrics) catch return true;
if (line_width == 0) return true;
if (cursor.col >= line_width - 1)
return true;
return false;
}
fn is_eol_vim(root: Buffer.Root, cursor: *const Cursor, metrics: Buffer.Metrics) bool {
const line_width = root.line_width(cursor.row, metrics) catch return true;
if (line_width == 0) return true;
if (cursor.col >= line_width)
return true;
return false;
}
fn move_cursor_half_page_up(root: Buffer.Root, cursor: *Cursor, view: *const View, metrics: Buffer.Metrics) !void {
cursor.move_half_page_up(root, view, metrics);
if (is_eol_vim(root, cursor, metrics)) try move_cursor_left_vim(root, cursor, metrics);
}
fn move_cursor_half_page_down(root: Buffer.Root, cursor: *Cursor, view: *const View, metrics: Buffer.Metrics) !void {
cursor.move_half_page_down(root, view, metrics);
if (is_eol_vim(root, cursor, metrics)) try move_cursor_left_vim(root, cursor, metrics);
}
fn move_cursor_up_vim(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) !void {
try cursor.move_up(root, metrics);
if (is_eol_vim(root, cursor, metrics)) try move_cursor_left_vim(root, cursor, metrics);
}
fn move_cursor_down_vim(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) !void {
try cursor.move_down(root, metrics);
if (is_eol_vim(root, cursor, metrics)) try move_cursor_left_vim(root, cursor, metrics);
}
fn move_cursor_end_vim(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) !void {
Editor.move_cursor_right_until(root, cursor, is_eol_vim, metrics);
}
fn move_cursor_left_vim(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) error{Stop}!void {
Editor.move_cursor_left_unless(root, cursor, Editor.is_eol_left, metrics);
}
fn move_cursor_right_vim(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) error{Stop}!void {
Editor.move_cursor_right_unless(root, cursor, is_eol_right_vim, metrics);
}

View file

@ -18,7 +18,7 @@ const syntax = @import("syntax");
const Widget = @import("Widget.zig"); const Widget = @import("Widget.zig");
const MessageFilter = @import("MessageFilter.zig"); const MessageFilter = @import("MessageFilter.zig");
const MainView = @import("mainview.zig"); pub const MainView = @import("mainview.zig");
// exports for unittesting // exports for unittesting
pub const exports = struct { pub const exports = struct {
@ -1850,10 +1850,6 @@ pub fn is_cursor_beam() bool {
}; };
} }
pub fn get_selection_style() @import("Buffer").Selection.Style {
return if (current().input_mode_) |mode| mode.selection_style else .normal;
}
pub fn message(comptime fmt: anytype, args: anytype) void { pub fn message(comptime fmt: anytype, args: anytype) void {
var buf: [256]u8 = undefined; var buf: [256]u8 = undefined;
tp.self_pid().send(.{ "message", std.fmt.bufPrint(&buf, fmt, args) catch @panic("too large") }) catch {}; tp.self_pid().send(.{ "message", std.fmt.bufPrint(&buf, fmt, args) catch @panic("too large") }) catch {};