Skip to content

Commit 35f5eb1

Browse files
vim: Add gt and gT bindings for Markdown preview mode (#39854)
### What does this PR do? - Adds default keybindings `gt` for navigating to the next tab and `gT` for navigating to the previous tab in markdown viewer mode ### Why do we need this change? - While previewing markdown files, the default vim bindings (`gt` and `gT`) do not work for navigating between tabs. These bindings work everywhere else, which provides a non-consistent experience for the user. ### How do we do this change? - Update the vim mode bindings to explicitly add handling for this mode --------- Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
1 parent 5939cae commit 35f5eb1

File tree

3 files changed

+50
-56
lines changed

3 files changed

+50
-56
lines changed

assets/keymaps/vim.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,6 @@
9595
"g g": "vim::StartOfDocument",
9696
"g h": "editor::Hover",
9797
"g B": "editor::BlameHover",
98-
"g t": "vim::GoToTab",
99-
"g shift-t": "vim::GoToPreviousTab",
10098
"g d": "editor::GoToDefinition",
10199
"g shift-d": "editor::GoToDeclaration",
102100
"g y": "editor::GoToTypeDefinition",
@@ -811,7 +809,7 @@
811809
}
812810
},
813811
{
814-
"context": "VimControl || !Editor && !Terminal",
812+
"context": "VimControl && !menu || !Editor && !Terminal",
815813
"bindings": {
816814
// window related commands (ctrl-w X)
817815
"ctrl-w": null,
@@ -865,7 +863,9 @@
865863
"ctrl-w ctrl-o": "workspace::CloseInactiveTabsAndPanes",
866864
"ctrl-w o": "workspace::CloseInactiveTabsAndPanes",
867865
"ctrl-w ctrl-n": "workspace::NewFileSplitHorizontal",
868-
"ctrl-w n": "workspace::NewFileSplitHorizontal"
866+
"ctrl-w n": "workspace::NewFileSplitHorizontal",
867+
"g t": "vim::GoToTab",
868+
"g shift-t": "vim::GoToPreviousTab"
869869
}
870870
},
871871
{

crates/vim/src/normal.rs

Lines changed: 2 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use editor::Editor;
2828
use editor::{Anchor, SelectionEffects};
2929
use editor::{Bias, ToPoint};
3030
use editor::{display_map::ToDisplayPoint, movement};
31-
use gpui::{Action, Context, Window, actions};
31+
use gpui::{Context, Window, actions};
3232
use language::{Point, SelectionGoal};
3333
use log::error;
3434
use multi_buffer::MultiBufferRow;
@@ -123,8 +123,6 @@ pub(crate) fn register(editor: &mut Editor, cx: &mut Context<Vim>) {
123123
Vim::action(editor, cx, Vim::toggle_comments);
124124
Vim::action(editor, cx, Vim::paste);
125125
Vim::action(editor, cx, Vim::show_location);
126-
Vim::action(editor, cx, Vim::go_to_tab);
127-
Vim::action(editor, cx, Vim::go_to_previous_tab);
128126

129127
Vim::action(editor, cx, |vim, _: &DeleteLeft, window, cx| {
130128
vim.record_current_action(cx);
@@ -1014,55 +1012,8 @@ impl Vim {
10141012
self.switch_mode(Mode::Insert, true, window, cx);
10151013
}
10161014
}
1017-
1018-
fn go_to_tab(&mut self, _: &GoToTab, window: &mut Window, cx: &mut Context<Self>) {
1019-
let count = Vim::take_count(cx);
1020-
Vim::take_forced_motion(cx);
1021-
1022-
if let Some(tab_index) = count {
1023-
// <count>gt goes to tab <count> (1-based).
1024-
let zero_based_index = tab_index.saturating_sub(1);
1025-
window.dispatch_action(
1026-
workspace::pane::ActivateItem(zero_based_index).boxed_clone(),
1027-
cx,
1028-
);
1029-
} else {
1030-
// If no count is provided, go to the next tab.
1031-
window.dispatch_action(workspace::pane::ActivateNextItem.boxed_clone(), cx);
1032-
}
1033-
}
1034-
1035-
fn go_to_previous_tab(
1036-
&mut self,
1037-
_: &GoToPreviousTab,
1038-
window: &mut Window,
1039-
cx: &mut Context<Self>,
1040-
) {
1041-
let count = Vim::take_count(cx);
1042-
Vim::take_forced_motion(cx);
1043-
1044-
if let Some(count) = count {
1045-
// gT with count goes back that many tabs with wraparound (not the same as gt!).
1046-
if let Some(workspace) = self.workspace(window) {
1047-
let pane = workspace.read(cx).active_pane().read(cx);
1048-
let item_count = pane.items().count();
1049-
if item_count > 0 {
1050-
let current_index = pane.active_item_index();
1051-
let target_index = (current_index as isize - count as isize)
1052-
.rem_euclid(item_count as isize)
1053-
as usize;
1054-
window.dispatch_action(
1055-
workspace::pane::ActivateItem(target_index).boxed_clone(),
1056-
cx,
1057-
);
1058-
}
1059-
}
1060-
} else {
1061-
// No count provided, go to the previous tab.
1062-
window.dispatch_action(workspace::pane::ActivatePreviousItem.boxed_clone(), cx);
1063-
}
1064-
}
10651015
}
1016+
10661017
#[cfg(test)]
10671018
mod test {
10681019
use gpui::{KeyBinding, TestAppContext, UpdateGlobal};

crates/vim/src/vim.rs

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,10 @@ use vim_mode_setting::HelixModeSetting;
5151
use vim_mode_setting::VimModeSetting;
5252
use workspace::{self, Pane, Workspace};
5353

54-
use crate::state::ReplayableAction;
54+
use crate::{
55+
normal::{GoToPreviousTab, GoToTab},
56+
state::ReplayableAction,
57+
};
5558

5659
/// Number is used to manage vim's count. Pushing a digit
5760
/// multiplies the current value by 10 and adds the digit.
@@ -409,6 +412,46 @@ pub fn init(cx: &mut App) {
409412
cx.defer_in(window, |vim, window, cx| vim.search_submit(window, cx))
410413
})
411414
});
415+
workspace.register_action(|_, _: &GoToTab, window, cx| {
416+
let count = Vim::take_count(cx);
417+
Vim::take_forced_motion(cx);
418+
419+
if let Some(tab_index) = count {
420+
// <count>gt goes to tab <count> (1-based).
421+
let zero_based_index = tab_index.saturating_sub(1);
422+
window.dispatch_action(
423+
workspace::pane::ActivateItem(zero_based_index).boxed_clone(),
424+
cx,
425+
);
426+
} else {
427+
// If no count is provided, go to the next tab.
428+
window.dispatch_action(workspace::pane::ActivateNextItem.boxed_clone(), cx);
429+
}
430+
});
431+
432+
workspace.register_action(|workspace, _: &GoToPreviousTab, window, cx| {
433+
let count = Vim::take_count(cx);
434+
Vim::take_forced_motion(cx);
435+
436+
if let Some(count) = count {
437+
// gT with count goes back that many tabs with wraparound (not the same as gt!).
438+
let pane = workspace.active_pane().read(cx);
439+
let item_count = pane.items().count();
440+
if item_count > 0 {
441+
let current_index = pane.active_item_index();
442+
let target_index = (current_index as isize - count as isize)
443+
.rem_euclid(item_count as isize)
444+
as usize;
445+
window.dispatch_action(
446+
workspace::pane::ActivateItem(target_index).boxed_clone(),
447+
cx,
448+
);
449+
}
450+
} else {
451+
// No count provided, go to the previous tab.
452+
window.dispatch_action(workspace::pane::ActivatePreviousItem.boxed_clone(), cx);
453+
}
454+
});
412455
})
413456
.detach();
414457
}

0 commit comments

Comments
 (0)