Skip to content

Commit

Permalink
Add AutoIndent action and '=' vim operator (#21427)
Browse files Browse the repository at this point in the history
Release Notes:

- vim: Added the `=` operator, for auto-indent

Co-authored-by: Conrad <[email protected]>
  • Loading branch information
maxbrunsfeld and ConradIrwin authored Dec 2, 2024
1 parent f3140f5 commit 7c994cd
Show file tree
Hide file tree
Showing 13 changed files with 481 additions and 186 deletions.
10 changes: 6 additions & 4 deletions assets/keymaps/vim.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,10 @@
"n": "vim::MoveToNextMatch",
"shift-n": "vim::MoveToPrevMatch",
"%": "vim::Matching",
"] }": ["vim::UnmatchedForward", { "char": "}" } ],
"[ {": ["vim::UnmatchedBackward", { "char": "{" } ],
"] )": ["vim::UnmatchedForward", { "char": ")" } ],
"[ (": ["vim::UnmatchedBackward", { "char": "(" } ],
"] }": ["vim::UnmatchedForward", { "char": "}" }],
"[ {": ["vim::UnmatchedBackward", { "char": "{" }],
"] )": ["vim::UnmatchedForward", { "char": ")" }],
"[ (": ["vim::UnmatchedBackward", { "char": "(" }],
"f": ["vim::PushOperator", { "FindForward": { "before": false } }],
"t": ["vim::PushOperator", { "FindForward": { "before": true } }],
"shift-f": ["vim::PushOperator", { "FindBackward": { "after": false } }],
Expand Down Expand Up @@ -209,6 +209,7 @@
"shift-s": "vim::SubstituteLine",
">": ["vim::PushOperator", "Indent"],
"<": ["vim::PushOperator", "Outdent"],
"=": ["vim::PushOperator", "AutoIndent"],
"g u": ["vim::PushOperator", "Lowercase"],
"g shift-u": ["vim::PushOperator", "Uppercase"],
"g ~": ["vim::PushOperator", "OppositeCase"],
Expand Down Expand Up @@ -275,6 +276,7 @@
"ctrl-[": ["vim::SwitchMode", "Normal"],
">": "vim::Indent",
"<": "vim::Outdent",
"=": "vim::AutoIndent",
"i": ["vim::PushOperator", { "Object": { "around": false } }],
"a": ["vim::PushOperator", { "Object": { "around": true } }],
"g c": "vim::ToggleComments",
Expand Down
1 change: 1 addition & 0 deletions crates/editor/src/actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ gpui::actions!(
OpenPermalinkToLine,
OpenUrl,
Outdent,
AutoIndent,
PageDown,
PageUp,
Paste,
Expand Down
19 changes: 19 additions & 0 deletions crates/editor/src/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6297,6 +6297,25 @@ impl Editor {
});
}

pub fn autoindent(&mut self, _: &AutoIndent, cx: &mut ViewContext<Self>) {
if self.read_only(cx) {
return;
}
let selections = self
.selections
.all::<usize>(cx)
.into_iter()
.map(|s| s.range());

self.transact(cx, |this, cx| {
this.buffer.update(cx, |buffer, cx| {
buffer.autoindent_ranges(selections, cx);
});
let selections = this.selections.all::<usize>(cx);
this.change_selections(Some(Autoscroll::fit()), cx, |s| s.select(selections));
});
}

pub fn delete_line(&mut self, _: &DeleteLine, cx: &mut ViewContext<Self>) {
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
let selections = self.selections.all::<Point>(cx);
Expand Down
100 changes: 85 additions & 15 deletions crates/editor/src/editor_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ use serde_json::{self, json};
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::{self, AtomicBool};
use std::{cell::RefCell, future::Future, rc::Rc, time::Instant};
use test::editor_lsp_test_context::rust_lang;
use unindent::Unindent;
use util::{
assert_set_eq,
Expand Down Expand Up @@ -5458,7 +5459,7 @@ async fn test_select_larger_smaller_syntax_node(cx: &mut gpui::TestAppContext) {
}

#[gpui::test]
async fn test_autoindent_selections(cx: &mut gpui::TestAppContext) {
async fn test_autoindent(cx: &mut gpui::TestAppContext) {
init_test(cx, |_| {});

let language = Arc::new(
Expand Down Expand Up @@ -5520,6 +5521,89 @@ async fn test_autoindent_selections(cx: &mut gpui::TestAppContext) {
});
}

#[gpui::test]
async fn test_autoindent_selections(cx: &mut gpui::TestAppContext) {
init_test(cx, |_| {});

{
let mut cx = EditorLspTestContext::new_rust(Default::default(), cx).await;
cx.set_state(indoc! {"
impl A {
fn b() {}
«fn c() {
}ˇ»
}
"});

cx.update_editor(|editor, cx| {
editor.autoindent(&Default::default(), cx);
});

cx.assert_editor_state(indoc! {"
impl A {
fn b() {}
«fn c() {
}ˇ»
}
"});
}

{
let mut cx = EditorTestContext::new_multibuffer(
cx,
[indoc! { "
impl A {
«
// a
fn b(){}
»
«
}
fn c(){}
»
"}],
);

let buffer = cx.update_editor(|editor, cx| {
let buffer = editor.buffer().update(cx, |buffer, _| {
buffer.all_buffers().iter().next().unwrap().clone()
});
buffer.update(cx, |buffer, cx| buffer.set_language(Some(rust_lang()), cx));
buffer
});

cx.run_until_parked();
cx.update_editor(|editor, cx| {
editor.select_all(&Default::default(), cx);
editor.autoindent(&Default::default(), cx)
});
cx.run_until_parked();

cx.update(|cx| {
pretty_assertions::assert_eq!(
buffer.read(cx).text(),
indoc! { "
impl A {
// a
fn b(){}
}
fn c(){}
" }
)
});
}
}

#[gpui::test]
async fn test_autoclose_and_auto_surround_pairs(cx: &mut gpui::TestAppContext) {
init_test(cx, |_| {});
Expand Down Expand Up @@ -13933,20 +14017,6 @@ pub(crate) fn init_test(cx: &mut TestAppContext, f: fn(&mut AllLanguageSettingsC
update_test_language_settings(cx, f);
}

pub(crate) fn rust_lang() -> Arc<Language> {
Arc::new(Language::new(
LanguageConfig {
name: "Rust".into(),
matcher: LanguageMatcher {
path_suffixes: vec!["rs".to_string()],
..Default::default()
},
..Default::default()
},
Some(tree_sitter_rust::LANGUAGE.into()),
))
}

#[track_caller]
fn assert_hunk_revert(
not_reverted_text_with_selections: &str,
Expand Down
1 change: 1 addition & 0 deletions crates/editor/src/element.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ impl EditorElement {
register_action(view, cx, Editor::tab_prev);
register_action(view, cx, Editor::indent);
register_action(view, cx, Editor::outdent);
register_action(view, cx, Editor::autoindent);
register_action(view, cx, Editor::delete_line);
register_action(view, cx, Editor::join_lines);
register_action(view, cx, Editor::sort_lines_case_sensitive);
Expand Down
11 changes: 6 additions & 5 deletions crates/editor/src/inlay_hint_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1258,6 +1258,7 @@ pub mod tests {

use crate::{
scroll::{scroll_amount::ScrollAmount, Autoscroll},
test::editor_lsp_test_context::rust_lang,
ExcerptRange,
};
use futures::StreamExt;
Expand Down Expand Up @@ -2274,7 +2275,7 @@ pub mod tests {
let project = Project::test(fs, ["/a".as_ref()], cx).await;

let language_registry = project.read_with(cx, |project, _| project.languages().clone());
language_registry.add(crate::editor_tests::rust_lang());
language_registry.add(rust_lang());
let mut fake_servers = language_registry.register_fake_lsp(
"Rust",
FakeLspAdapter {
Expand Down Expand Up @@ -2570,7 +2571,7 @@ pub mod tests {
let project = Project::test(fs, ["/a".as_ref()], cx).await;

let language_registry = project.read_with(cx, |project, _| project.languages().clone());
let language = crate::editor_tests::rust_lang();
let language = rust_lang();
language_registry.add(language);
let mut fake_servers = language_registry.register_fake_lsp(
"Rust",
Expand Down Expand Up @@ -2922,7 +2923,7 @@ pub mod tests {
let project = Project::test(fs, ["/a".as_ref()], cx).await;

let language_registry = project.read_with(cx, |project, _| project.languages().clone());
language_registry.add(crate::editor_tests::rust_lang());
language_registry.add(rust_lang());
let mut fake_servers = language_registry.register_fake_lsp(
"Rust",
FakeLspAdapter {
Expand Down Expand Up @@ -3153,7 +3154,7 @@ pub mod tests {
let project = Project::test(fs, ["/a".as_ref()], cx).await;

let language_registry = project.read_with(cx, |project, _| project.languages().clone());
language_registry.add(crate::editor_tests::rust_lang());
language_registry.add(rust_lang());
let mut fake_servers = language_registry.register_fake_lsp(
"Rust",
FakeLspAdapter {
Expand Down Expand Up @@ -3396,7 +3397,7 @@ pub mod tests {
let project = Project::test(fs, ["/a".as_ref()], cx).await;

let language_registry = project.read_with(cx, |project, _| project.languages().clone());
language_registry.add(crate::editor_tests::rust_lang());
language_registry.add(rust_lang());
let mut fake_servers = language_registry.register_fake_lsp(
"Rust",
FakeLspAdapter {
Expand Down
82 changes: 42 additions & 40 deletions crates/editor/src/test/editor_lsp_test_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,47 @@ pub struct EditorLspTestContext {
pub buffer_lsp_url: lsp::Url,
}

pub(crate) fn rust_lang() -> Arc<Language> {
let language = Language::new(
LanguageConfig {
name: "Rust".into(),
matcher: LanguageMatcher {
path_suffixes: vec!["rs".to_string()],
..Default::default()
},
line_comments: vec!["// ".into(), "/// ".into(), "//! ".into()],
..Default::default()
},
Some(tree_sitter_rust::LANGUAGE.into()),
)
.with_queries(LanguageQueries {
indents: Some(Cow::from(indoc! {r#"
[
((where_clause) _ @end)
(field_expression)
(call_expression)
(assignment_expression)
(let_declaration)
(let_chain)
(await_expression)
] @indent
(_ "[" "]" @end) @indent
(_ "<" ">" @end) @indent
(_ "{" "}" @end) @indent
(_ "(" ")" @end) @indent"#})),
brackets: Some(Cow::from(indoc! {r#"
("(" @open ")" @close)
("[" @open "]" @close)
("{" @open "}" @close)
("<" @open ">" @close)
("\"" @open "\"" @close)
(closure_parameters "|" @open "|" @close)"#})),
..Default::default()
})
.expect("Could not parse queries");
Arc::new(language)
}
impl EditorLspTestContext {
pub async fn new(
language: Language,
Expand Down Expand Up @@ -119,46 +160,7 @@ impl EditorLspTestContext {
capabilities: lsp::ServerCapabilities,
cx: &mut gpui::TestAppContext,
) -> EditorLspTestContext {
let language = Language::new(
LanguageConfig {
name: "Rust".into(),
matcher: LanguageMatcher {
path_suffixes: vec!["rs".to_string()],
..Default::default()
},
line_comments: vec!["// ".into(), "/// ".into(), "//! ".into()],
..Default::default()
},
Some(tree_sitter_rust::LANGUAGE.into()),
)
.with_queries(LanguageQueries {
indents: Some(Cow::from(indoc! {r#"
[
((where_clause) _ @end)
(field_expression)
(call_expression)
(assignment_expression)
(let_declaration)
(let_chain)
(await_expression)
] @indent
(_ "[" "]" @end) @indent
(_ "<" ">" @end) @indent
(_ "{" "}" @end) @indent
(_ "(" ")" @end) @indent"#})),
brackets: Some(Cow::from(indoc! {r#"
("(" @open ")" @close)
("[" @open "]" @close)
("{" @open "}" @close)
("<" @open ">" @close)
("\"" @open "\"" @close)
(closure_parameters "|" @open "|" @close)"#})),
..Default::default()
})
.expect("Could not parse queries");

Self::new(language, capabilities, cx).await
Self::new(Arc::into_inner(rust_lang()).unwrap(), capabilities, cx).await
}

pub async fn new_typescript(
Expand Down
Loading

0 comments on commit 7c994cd

Please sign in to comment.