Skip to content

Commit

Permalink
Implement the next/previous editor commands and keybindings (#1447)
Browse files Browse the repository at this point in the history
* Implement the next/previous editor commands and keybindings

This wraps around like VSCode.

Fixes #778 and part of #1423.

* Remove unneeded new actions

* Adjust how the next/previous editor code works in EditorGroup

Resolve the TODO for _getIndexOfElement by making it return option(int).
List.find_opt is not actually the right choice to get an index.

Also ran `esy format`.
  • Loading branch information
leavengood authored Mar 10, 2020
1 parent b058845 commit 39477a2
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 5 deletions.
59 changes: 54 additions & 5 deletions src/Model/EditorGroup.re
Original file line number Diff line number Diff line change
Expand Up @@ -61,16 +61,23 @@ let getOrCreateEditorForBuffer = (state, bufferId) => {
};
};

// TODO: Just use List.find_opt?
let rec _getIndexOfElement = elem =>
fun
| [] => (-1)
| [hd, ...tl] => hd === elem ? 0 : _getIndexOfElement(elem, tl) + 1;
| [] => None
| [hd, ...tl] =>
hd === elem
? Some(0)
: (
switch (_getIndexOfElement(elem, tl)) {
| None => None
| Some(i) => Some(i + 1)
}
);

let _getAdjacentEditor = (editor: int, reverseTabOrder: list(int)) => {
switch (_getIndexOfElement(editor, reverseTabOrder)) {
| (-1) => None
| idx =>
| None => None
| Some(idx) =>
switch (
List.nth_opt(reverseTabOrder, idx + 1),
List.nth_opt(reverseTabOrder, max(idx - 1, 0)),
Expand All @@ -82,6 +89,48 @@ let _getAdjacentEditor = (editor: int, reverseTabOrder: list(int)) => {
};
};

let setActiveEditorTo = (kind, model) =>
switch (model.reverseTabOrder) {
| []
| [_] => model
| _ =>
switch (model.activeEditorId) {
| Some(activeEditorId) =>
switch (_getIndexOfElement(activeEditorId, model.reverseTabOrder)) {
| None => model
| Some(idx) =>
// The diff amounts are inverted because the list is in reverse order
let newIndex =
switch (kind) {
| `Next => idx - 1
| `Previous => idx + 1
};

let count = List.length(model.reverseTabOrder);

let newIndex =
if (newIndex < 0) {
// Wrapping negative, go to end
count - 1;
} else if (newIndex >= count) {
0;
// If this is past the end, go to zero
} else {
newIndex;
};

{
...model,
activeEditorId: List.nth_opt(model.reverseTabOrder, newIndex),
};
}
| None => model
}
};

let nextEditor = setActiveEditorTo(`Next);
let previousEditor = setActiveEditorTo(`Previous);

let isEmpty = model => IntMap.is_empty(model.editors);

let removeEditorById = (state, editorId) => {
Expand Down
2 changes: 2 additions & 0 deletions src/Model/EditorGroup.rei
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ let getActiveEditor: t => option(Feature_Editor.Editor.t);
let setActiveEditor: (t, int) => t;
let getEditorById: (int, t) => option(Feature_Editor.Editor.t);
let getOrCreateEditorForBuffer: (t, int) => (t, Feature_Editor.EditorId.t);
let nextEditor: t => t;
let previousEditor: t => t;
let removeEditorById: (t, int) => t;

let isEmpty: t => bool;
3 changes: 3 additions & 0 deletions src/Model/EditorGroupReducer.re
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ let reduce = (v: EditorGroup.t, action: Actions.t) => {
let (newState, activeEditorId) =
EditorGroup.getOrCreateEditorForBuffer(v, id);
{...newState, activeEditorId: Some(activeEditorId)};
| Command("workbench.action.nextEditor") => EditorGroup.nextEditor(v)
| Command("workbench.action.previousEditor") =>
EditorGroup.previousEditor(v)
| ViewCloseEditor(id) => EditorGroup.removeEditorById(v, id)
| ViewSetActiveEditor(id) =>
switch (IntMap.find_opt(id, v.editors)) {
Expand Down
12 changes: 12 additions & 0 deletions src/Store/CommandStoreConnector.re
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,18 @@ let createDefaultCommands = getState => {
~action=Command("view.closeEditor"),
(),
),
Command.create(
~category=Some("View"),
~name="Open Next Editor",
~action=Command("workbench.action.nextEditor"),
(),
),
Command.create(
~category=Some("View"),
~name="Open Previous Editor",
~action=Command("workbench.action.previousEditor"),
(),
),
Command.create(
~category=Some("View"),
~name="Toggle Problems (Errors, Warnings)",
Expand Down
20 changes: 20 additions & 0 deletions src/Store/KeyBindingsStoreConnector.re
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,26 @@ let start = () => {
command: "view.closeEditor",
condition: WhenExpr.Value(True),
},
{
key: "<C-PAGEDOWN>",
command: "workbench.action.nextEditor",
condition: WhenExpr.Value(True),
},
{
key: "<D-S-]>",
command: "workbench.action.nextEditor",
condition: WhenExpr.Value(True),
},
{
key: "<C-PAGEUP>",
command: "workbench.action.previousEditor",
condition: WhenExpr.Value(True),
},
{
key: "<D-S-[>",
command: "workbench.action.previousEditor",
condition: WhenExpr.Value(True),
},
];

let reloadConfigOnWritePost = (~configPath, dispatch) => {
Expand Down
8 changes: 8 additions & 0 deletions src/Store/VimStoreConnector.re
Original file line number Diff line number Diff line change
Expand Up @@ -904,6 +904,14 @@ let start =
)
| ViewSetActiveEditor(_) => (state, synchronizeEditorEffect(state))
| ViewCloseEditor(_) => (state, synchronizeEditorEffect(state))
| Command("workbench.action.nextEditor") => (
state,
synchronizeEditorEffect(state),
)
| Command("workbench.action.previousEditor") => (
state,
synchronizeEditorEffect(state),
)
| KeyboardInput(s) => (state, inputEffect(s))
| CopyActiveFilepathToClipboard => (
state,
Expand Down

0 comments on commit 39477a2

Please sign in to comment.