summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/config.zig2
-rw-r--r--src/modal.zig21
-rw-r--r--src/normal.zig10
3 files changed, 29 insertions, 4 deletions
diff --git a/src/config.zig b/src/config.zig
index ecaa3357..daa40028 100644
--- a/src/config.zig
+++ b/src/config.zig
@@ -440,6 +440,7 @@ pub const errors_buffer = "+Errors";
// Modal bindings below are checked against Helix by hxdiff and hxparity.
pub const goto_prefix = 'g';
pub const view_prefix = 'z';
+pub const view_prefix_sticky = 'Z';
pub const match_prefix = 'm';
pub const replace_prefix = 'r';
pub const next_prefix = ']';
@@ -473,6 +474,7 @@ pub const page_up: []const Chord = &.{ .{ .cp = 'b', .ctrl = true }, .{ .cp = Ke
pub const view_top: []const Chord = &.{.{ .cp = 't' }};
pub const view_center: []const Chord = &.{ .{ .cp = 'z' }, .{ .cp = 'c' } };
pub const view_bottom: []const Chord = &.{.{ .cp = 'b' }};
+pub const view_middle: []const Chord = &.{.{ .cp = 'm' }};
pub const view_scroll_down: []const Chord = &.{ .{ .cp = 'j' }, .{ .cp = Key.down } };
pub const view_scroll_up: []const Chord = &.{ .{ .cp = 'k' }, .{ .cp = Key.up } };
diff --git a/src/modal.zig b/src/modal.zig
index 0171da93..16196b4f 100644
--- a/src/modal.zig
+++ b/src/modal.zig
@@ -16,6 +16,7 @@ pub const Normal = struct {
prefix_next,
prefix_prev,
prefix_register,
+ prefix_view_sticky,
goto_file_start,
goto_last_line,
@@ -38,6 +39,7 @@ pub const Normal = struct {
view_top,
view_center,
view_bottom,
+ view_middle,
view_scroll_down,
view_scroll_up,
@@ -196,9 +198,12 @@ pub const Normal = struct {
held_char: u21 = 0,
/// `"<reg>`: the register the next command names, 0 for none
register: u21 = 0,
+ /// `Z`: the view keys stay armed until Esc (helix's sticky view)
+ sticky: bool = false,
+ /// Drop what is pending; sticky view mode stays armed through it.
pub fn clear(state: *State) void {
- state.* = .{};
+ state.* = if (state.sticky) .{ .sticky = true, .prefix = .view } else .{};
}
};
@@ -254,7 +259,7 @@ pub const Normal = struct {
view_bottom,
last_modification,
};
- pub const View = enum { top, center, bottom, scroll_down, scroll_up };
+ pub const View = enum { top, center, bottom, middle, scroll_down, scroll_up };
pub const Find = enum { forward, backward, till_forward, till_backward };
pub const Line = enum { start, end, first_nonws };
pub const Page = enum { half_down, half_up, down, up };
@@ -407,7 +412,10 @@ pub const Normal = struct {
pub fn parse(state: *State, key: Input) Result {
if (key.has(.escape)) {
- state.clear();
+ // Esc out of sticky view mode leaves that mode and nothing else
+ const sticky = state.sticky;
+ state.* = .{};
+ if (sticky) return .ignored;
return resultAction(.escape);
}
@@ -448,8 +456,9 @@ pub const Normal = struct {
return .ignored;
},
.view => {
- state.prefix = .none;
+ if (!state.sticky) state.prefix = .none;
if (key.has(.view_top)) return resultAction(.{ .view = .top });
+ if (key.has(.view_middle)) return resultAction(.{ .view = .middle });
if (key.has(.view_center)) return resultAction(.{ .view = .center });
if (key.has(.view_bottom)) return resultAction(.{ .view = .bottom });
if (key.has(.view_scroll_down)) return resultAction(.{ .view = .scroll_down });
@@ -543,6 +552,10 @@ pub const Normal = struct {
// Prefix setters retain the count for their continuation.
if (key.has(.prefix_goto)) return armPrefix(state, .goto, if (counted.explicit) count else 0);
if (key.has(.prefix_view)) return armPrefix(state, .view, if (counted.explicit) count else 0);
+ if (key.has(.prefix_view_sticky)) {
+ state.sticky = true;
+ return armPrefix(state, .view, 0);
+ }
if (key.has(.prefix_find_fwd)) return armPrefix(state, .find_fwd, if (counted.explicit) count else 0);
if (key.has(.prefix_find_back)) return armPrefix(state, .find_back, if (counted.explicit) count else 0);
if (key.has(.prefix_till_fwd)) return armPrefix(state, .till_fwd, if (counted.explicit) count else 0);
diff --git a/src/normal.zig b/src/normal.zig
index f9d7cf25..f7ba3810 100644
--- a/src/normal.zig
+++ b/src/normal.zig
@@ -29,6 +29,7 @@ fn roleBindingName(comptime role: modal.Normal.Role) []const u8 {
return switch (role) {
.prefix_goto => "goto_prefix",
.prefix_view => "view_prefix",
+ .prefix_view_sticky => "view_prefix_sticky",
.prefix_match => "match_prefix",
.prefix_find_fwd => "find_char_fwd",
.prefix_find_back => "find_char_back",
@@ -478,6 +479,15 @@ fn executeNormalAction(p: *Pardes, t: *Text, semantic: modal.Normal.Action) void
pane.scrollBy(t.cur_row - (pane.scroll() + @as(i32, pane.rows) - 1));
pane.ensureCursorVisible();
},
+ .middle => {
+ // helix align_view_middle: the cursor's column to the middle
+ // of an unwrapped view
+ if (pane.body_wrapped) return;
+ const line = text[modal.lineStartOffset(text, modal.lineAtOffset(text, cur))..modal.lineEndOffset(text, modal.lineAtOffset(text, cur))];
+ const w: usize = @intCast(@max(1, @as(i32, pane.cols) - @as(i32, panes.File.gutterWidth(pane))));
+ const col = panes.File.rawDisplayCol(line, @intCast(@max(0, t.cur_col)));
+ pane.hscroll = @intCast(panes.File.rawAtDisplay(line, col -| w / 2));
+ },
.scroll_down => return t.scrollViewMove(text, range, 1),
.scroll_up => return t.scrollViewMove(text, range, -1),
},