vim: Command (#2951)
Release Notes: - vim: Add v1 of command mode ([#279](https://github.com/zed-industries/community/issues/279)). The goal was to cover 90% of what most people actually do, but it is very incomplete. Known omissions are that ranges cannot be specified (except that `:%s//` must always specify the % range), commands cannot take arguments (you can `:w` but not `:w [file]`), and there is no history. Please file feature requests on https://github.com/zed-industries/community as you notice things that could be better. - `:` triggers zed's command palette. If you type a known vim command it will run it, otherwise you get zed's normal fuzzy search. For this release supported commands are limited to: - - `:w[rite][!]`, `:wq[!]`, `:q[uit][!]`, `:wa[ll][!]`, `:wqa[ll][!]`, `:qa[ll][!]`, `:[e]x[it][!]`, `:up[date]` to save/close tab(s) and pane(s). - - `:cq` to quit completely. - - `:vs[plit]`, `:sp[lit]` to split vertically/horizontally - - `:new`, `:vne[w]` to create a new file in a new pane above or to the left - - `:tabedit`, `:tabnew` to create a new file in a new tab. - - `:tabn[ext]`, `:tabp[rev]` to go to previous/next tabs - - `:tabc[lose]` to close tabs - - `:cn[ext]`, `:cp[rev]`, `:ln[ext]`, `:lp[rev]` to go to the next/prev diagnostics. - - `:cc`, `:ll` to open the errors page - - `:<number>` to jump to a line number. - - `:$` to jump to end of file - - `:%s/foo/bar/` (note that /g is always implied, the range must always be %, and zed uses different regex syntax to vim) - - `:/foo` and `:?foo` to jump to next/prev line matching foo - - `:j[oin]`, to join the current line (no range is yet supported) - - `:d[elete][l][p]`, to delete the current line (no range is yet supported) - - `:s[ort] [i]` to sort the current selection (case-insensitively) - vim: Add `ctrl-w o` (closes everything except the current item) and `ctrl-w n` (creates a new file in the pane above). ([#1884](https://github.com/zed-industries/community/issues/1884)) - all: Add a "Discard" option to prompt when saving a file with conflicts (previously this only appeared on close, not on save). Internal changes: - The Picker will now wait for pending queries before confirming (to handle people typing `: w enter` rapidly. - workspace::save_item and Pane::save_item are now merged together, and the behavior controlled by `workspace::SaveIntent`. - Many actions related to closing/saving items now take an optional `SaveIntent`. -
This commit is contained in:
commit
d17d38fe70
28 changed files with 1155 additions and 300 deletions
|
@ -744,7 +744,7 @@ mod tests {
|
|||
use theme::{ThemeRegistry, ThemeSettings};
|
||||
use workspace::{
|
||||
item::{Item, ItemHandle},
|
||||
open_new, open_paths, pane, NewFile, SaveBehavior, SplitDirection, WorkspaceHandle,
|
||||
open_new, open_paths, pane, NewFile, SaveIntent, SplitDirection, WorkspaceHandle,
|
||||
};
|
||||
|
||||
#[gpui::test]
|
||||
|
@ -945,10 +945,14 @@ mod tests {
|
|||
|
||||
editor.update(cx, |editor, cx| {
|
||||
assert!(editor.text(cx).is_empty());
|
||||
assert!(!editor.is_dirty(cx));
|
||||
});
|
||||
|
||||
let save_task = workspace.update(cx, |workspace, cx| workspace.save_active_item(false, cx));
|
||||
let save_task = workspace.update(cx, |workspace, cx| {
|
||||
workspace.save_active_item(SaveIntent::Save, cx)
|
||||
});
|
||||
app_state.fs.create_dir(Path::new("/root")).await.unwrap();
|
||||
cx.foreground().run_until_parked();
|
||||
cx.simulate_new_path_selection(|_| Some(PathBuf::from("/root/the-new-name")));
|
||||
save_task.await.unwrap();
|
||||
editor.read_with(cx, |editor, cx| {
|
||||
|
@ -1311,7 +1315,10 @@ mod tests {
|
|||
.await;
|
||||
cx.read(|cx| assert!(editor.is_dirty(cx)));
|
||||
|
||||
let save_task = workspace.update(cx, |workspace, cx| workspace.save_active_item(false, cx));
|
||||
let save_task = workspace.update(cx, |workspace, cx| {
|
||||
workspace.save_active_item(SaveIntent::Save, cx)
|
||||
});
|
||||
cx.foreground().run_until_parked();
|
||||
window.simulate_prompt_answer(0, cx);
|
||||
save_task.await.unwrap();
|
||||
editor.read_with(cx, |editor, cx| {
|
||||
|
@ -1353,7 +1360,10 @@ mod tests {
|
|||
});
|
||||
|
||||
// Save the buffer. This prompts for a filename.
|
||||
let save_task = workspace.update(cx, |workspace, cx| workspace.save_active_item(false, cx));
|
||||
let save_task = workspace.update(cx, |workspace, cx| {
|
||||
workspace.save_active_item(SaveIntent::Save, cx)
|
||||
});
|
||||
cx.foreground().run_until_parked();
|
||||
cx.simulate_new_path_selection(|parent_dir| {
|
||||
assert_eq!(parent_dir, Path::new("/root"));
|
||||
Some(parent_dir.join("the-new-name.rs"))
|
||||
|
@ -1377,7 +1387,9 @@ mod tests {
|
|||
editor.handle_input(" there", cx);
|
||||
assert!(editor.is_dirty(cx));
|
||||
});
|
||||
let save_task = workspace.update(cx, |workspace, cx| workspace.save_active_item(false, cx));
|
||||
let save_task = workspace.update(cx, |workspace, cx| {
|
||||
workspace.save_active_item(SaveIntent::Save, cx)
|
||||
});
|
||||
save_task.await.unwrap();
|
||||
assert!(!cx.did_prompt_for_new_path());
|
||||
editor.read_with(cx, |editor, cx| {
|
||||
|
@ -1444,7 +1456,10 @@ mod tests {
|
|||
});
|
||||
|
||||
// Save the buffer. This prompts for a filename.
|
||||
let save_task = workspace.update(cx, |workspace, cx| workspace.save_active_item(false, cx));
|
||||
let save_task = workspace.update(cx, |workspace, cx| {
|
||||
workspace.save_active_item(SaveIntent::Save, cx)
|
||||
});
|
||||
cx.foreground().run_until_parked();
|
||||
cx.simulate_new_path_selection(|_| Some(PathBuf::from("/root/the-new-name.rs")));
|
||||
save_task.await.unwrap();
|
||||
// The buffer is not dirty anymore and the language is assigned based on the path.
|
||||
|
@ -1508,9 +1523,7 @@ mod tests {
|
|||
});
|
||||
cx.dispatch_action(
|
||||
window.into(),
|
||||
workspace::CloseActiveItem {
|
||||
save_behavior: None,
|
||||
},
|
||||
workspace::CloseActiveItem { save_intent: None },
|
||||
);
|
||||
|
||||
cx.foreground().run_until_parked();
|
||||
|
@ -1521,9 +1534,7 @@ mod tests {
|
|||
|
||||
cx.dispatch_action(
|
||||
window.into(),
|
||||
workspace::CloseActiveItem {
|
||||
save_behavior: None,
|
||||
},
|
||||
workspace::CloseActiveItem { save_intent: None },
|
||||
);
|
||||
cx.foreground().run_until_parked();
|
||||
window.simulate_prompt_answer(1, cx);
|
||||
|
@ -1682,7 +1693,7 @@ mod tests {
|
|||
pane.update(cx, |pane, cx| {
|
||||
let editor3_id = editor3.id();
|
||||
drop(editor3);
|
||||
pane.close_item_by_id(editor3_id, SaveBehavior::PromptOnWrite, cx)
|
||||
pane.close_item_by_id(editor3_id, SaveIntent::Close, cx)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
@ -1717,7 +1728,7 @@ mod tests {
|
|||
pane.update(cx, |pane, cx| {
|
||||
let editor2_id = editor2.id();
|
||||
drop(editor2);
|
||||
pane.close_item_by_id(editor2_id, SaveBehavior::PromptOnWrite, cx)
|
||||
pane.close_item_by_id(editor2_id, SaveIntent::Close, cx)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
@ -1874,28 +1885,28 @@ mod tests {
|
|||
|
||||
// Close all the pane items in some arbitrary order.
|
||||
pane.update(cx, |pane, cx| {
|
||||
pane.close_item_by_id(file1_item_id, SaveBehavior::PromptOnWrite, cx)
|
||||
pane.close_item_by_id(file1_item_id, SaveIntent::Close, cx)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(active_path(&workspace, cx), Some(file4.clone()));
|
||||
|
||||
pane.update(cx, |pane, cx| {
|
||||
pane.close_item_by_id(file4_item_id, SaveBehavior::PromptOnWrite, cx)
|
||||
pane.close_item_by_id(file4_item_id, SaveIntent::Close, cx)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(active_path(&workspace, cx), Some(file3.clone()));
|
||||
|
||||
pane.update(cx, |pane, cx| {
|
||||
pane.close_item_by_id(file2_item_id, SaveBehavior::PromptOnWrite, cx)
|
||||
pane.close_item_by_id(file2_item_id, SaveIntent::Close, cx)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(active_path(&workspace, cx), Some(file3.clone()));
|
||||
|
||||
pane.update(cx, |pane, cx| {
|
||||
pane.close_item_by_id(file3_item_id, SaveBehavior::PromptOnWrite, cx)
|
||||
pane.close_item_by_id(file3_item_id, SaveIntent::Close, cx)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue