Add new indentation features to support Python
This commit is contained in:
parent
095f18d661
commit
929615964d
10 changed files with 365 additions and 63 deletions
|
@ -256,3 +256,41 @@ impl super::LspAdapter for CLspAdapter {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use gpui::MutableAppContext;
|
||||
use language::{Buffer, IndentSize};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[gpui::test]
|
||||
fn test_c_autoindent(cx: &mut MutableAppContext) {
|
||||
cx.foreground().set_block_on_ticks(usize::MAX..=usize::MAX);
|
||||
let language = crate::languages::language("c", tree_sitter_c::language(), None);
|
||||
|
||||
cx.add_model(|cx| {
|
||||
let mut buffer = Buffer::new(0, "", cx).with_language(Arc::new(language), cx);
|
||||
let size = IndentSize::spaces(2);
|
||||
|
||||
// empty function
|
||||
buffer.edit_with_autoindent([(0..0, "int main() {}")], size, cx);
|
||||
|
||||
// indent inside braces
|
||||
let ix = buffer.len() - 1;
|
||||
buffer.edit_with_autoindent([(ix..ix, "\n\n")], size, cx);
|
||||
assert_eq!(buffer.text(), "int main() {\n \n}");
|
||||
|
||||
// indent body of single-statement if statement
|
||||
let ix = buffer.len() - 2;
|
||||
buffer.edit_with_autoindent([(ix..ix, "if (a)\nb;")], size, cx);
|
||||
assert_eq!(buffer.text(), "int main() {\n if (a)\n b;\n}");
|
||||
|
||||
// indent inside field expression
|
||||
let ix = buffer.len() - 3;
|
||||
buffer.edit_with_autoindent([(ix..ix, "\n.c")], size, cx);
|
||||
assert_eq!(buffer.text(), "int main() {\n if (a)\n b\n .c;\n}");
|
||||
|
||||
buffer
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
[
|
||||
(field_expression)
|
||||
(assignment_expression)
|
||||
(field_expression)
|
||||
(assignment_expression)
|
||||
(if_statement)
|
||||
(for_statement)
|
||||
] @indent
|
||||
|
||||
(_ "{" "}" @end) @indent
|
||||
|
|
|
@ -151,3 +151,103 @@ impl LspAdapter for PythonLspAdapter {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use gpui::{ModelContext, MutableAppContext};
|
||||
use language::{Buffer, IndentSize};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[gpui::test]
|
||||
fn test_python_autoindent(cx: &mut MutableAppContext) {
|
||||
cx.foreground().set_block_on_ticks(usize::MAX..=usize::MAX);
|
||||
let language = crate::languages::language("python", tree_sitter_python::language(), None);
|
||||
|
||||
cx.add_model(|cx| {
|
||||
let mut buffer = Buffer::new(0, "", cx).with_language(Arc::new(language), cx);
|
||||
let size = IndentSize::spaces(2);
|
||||
let append = |buffer: &mut Buffer, text: &str, cx: &mut ModelContext<Buffer>| {
|
||||
let ix = buffer.len();
|
||||
buffer.edit_with_autoindent([(ix..ix, text)], size, cx);
|
||||
};
|
||||
|
||||
// indent after "def():"
|
||||
append(&mut buffer, "def a():\n", cx);
|
||||
assert_eq!(buffer.text(), "def a():\n ");
|
||||
|
||||
// preserve indent after blank line
|
||||
append(&mut buffer, "\n ", cx);
|
||||
assert_eq!(buffer.text(), "def a():\n \n ");
|
||||
|
||||
// indent after "if"
|
||||
append(&mut buffer, "if a:\n ", cx);
|
||||
assert_eq!(buffer.text(), "def a():\n \n if a:\n ");
|
||||
|
||||
// preserve indent after statement
|
||||
append(&mut buffer, "b()\n", cx);
|
||||
assert_eq!(buffer.text(), "def a():\n \n if a:\n b()\n ");
|
||||
|
||||
// preserve indent after statement
|
||||
append(&mut buffer, "else", cx);
|
||||
assert_eq!(buffer.text(), "def a():\n \n if a:\n b()\n else");
|
||||
|
||||
// dedent "else""
|
||||
append(&mut buffer, ":", cx);
|
||||
assert_eq!(buffer.text(), "def a():\n \n if a:\n b()\n else:");
|
||||
|
||||
// indent lines after else
|
||||
append(&mut buffer, "\n", cx);
|
||||
assert_eq!(
|
||||
buffer.text(),
|
||||
"def a():\n \n if a:\n b()\n else:\n "
|
||||
);
|
||||
|
||||
// indent after an open paren. the closing paren is not indented
|
||||
// because there is another token before it on the same line.
|
||||
append(&mut buffer, "foo(\n1)", cx);
|
||||
assert_eq!(
|
||||
buffer.text(),
|
||||
"def a():\n \n if a:\n b()\n else:\n foo(\n 1)"
|
||||
);
|
||||
|
||||
// dedent the closing paren if it is shifted to the beginning of the line
|
||||
let argument_ix = buffer.text().find("1").unwrap();
|
||||
buffer.edit_with_autoindent([(argument_ix..argument_ix + 1, "")], size, cx);
|
||||
assert_eq!(
|
||||
buffer.text(),
|
||||
"def a():\n \n if a:\n b()\n else:\n foo(\n )"
|
||||
);
|
||||
|
||||
// preserve indent after the close paren
|
||||
append(&mut buffer, "\n", cx);
|
||||
assert_eq!(
|
||||
buffer.text(),
|
||||
"def a():\n \n if a:\n b()\n else:\n foo(\n )\n "
|
||||
);
|
||||
|
||||
// manually outdent the last line
|
||||
let end_whitespace_ix = buffer.len() - 4;
|
||||
buffer.edit_with_autoindent([(end_whitespace_ix..buffer.len(), "")], size, cx);
|
||||
assert_eq!(
|
||||
buffer.text(),
|
||||
"def a():\n \n if a:\n b()\n else:\n foo(\n )\n"
|
||||
);
|
||||
|
||||
// preserve the newly reduced indentation on the next newline
|
||||
append(&mut buffer, "\n", cx);
|
||||
assert_eq!(
|
||||
buffer.text(),
|
||||
"def a():\n \n if a:\n b()\n else:\n foo(\n )\n\n"
|
||||
);
|
||||
|
||||
// reset to a simple if statement
|
||||
buffer.edit([(0..buffer.len(), "if a:\n b(\n )")], cx);
|
||||
|
||||
// dedent "else" on the line after a closing paren
|
||||
append(&mut buffer, "\n else:\n", cx);
|
||||
assert_eq!(buffer.text(), "if a:\n b(\n )\nelse:\n ");
|
||||
|
||||
buffer
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,3 +9,7 @@ brackets = [
|
|||
{ start = "\"", end = "\"", close = true, newline = false },
|
||||
{ start = "'", end = "'", close = false, newline = false },
|
||||
]
|
||||
|
||||
auto_indent_using_last_non_empty_line = false
|
||||
increase_indent_pattern = ":$"
|
||||
decrease_indent_pattern = "^\\s*(else|elif|except|finally)\\b.*:"
|
|
@ -1,4 +1,3 @@
|
|||
(_ (block)) @indent
|
||||
(_ "[" "]" @end) @indent
|
||||
(_ "{" "}" @end) @indent
|
||||
(_ "(" ")" @end) @indent
|
||||
|
|
|
@ -270,7 +270,7 @@ impl LspAdapter for RustLspAdapter {
|
|||
mod tests {
|
||||
use super::*;
|
||||
use crate::languages::{language, LspAdapter};
|
||||
use gpui::color::Color;
|
||||
use gpui::{color::Color, MutableAppContext};
|
||||
use theme::SyntaxTheme;
|
||||
|
||||
#[test]
|
||||
|
@ -432,4 +432,42 @@ mod tests {
|
|||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn test_rust_autoindent(cx: &mut MutableAppContext) {
|
||||
cx.foreground().set_block_on_ticks(usize::MAX..=usize::MAX);
|
||||
let language = crate::languages::language("rust", tree_sitter_rust::language(), None);
|
||||
|
||||
cx.add_model(|cx| {
|
||||
let mut buffer = Buffer::new(0, "", cx).with_language(Arc::new(language), cx);
|
||||
let size = IndentSize::spaces(2);
|
||||
|
||||
// start with empty function
|
||||
buffer.edit_with_autoindent([(0..0, "fn a() {}")], size, cx);
|
||||
|
||||
// indent between braces
|
||||
let ix = buffer.len() - 1;
|
||||
buffer.edit_with_autoindent([(ix..ix, "\n\n")], size, cx);
|
||||
assert_eq!(buffer.text(), "fn a() {\n \n}");
|
||||
|
||||
// indent field expression
|
||||
let ix = buffer.len() - 2;
|
||||
buffer.edit_with_autoindent([(ix..ix, "b\n.c")], size, cx);
|
||||
assert_eq!(buffer.text(), "fn a() {\n b\n .c\n}");
|
||||
|
||||
// indent chained field expression preceded by blank line
|
||||
let ix = buffer.len() - 2;
|
||||
buffer.edit_with_autoindent([(ix..ix, "\n\n.d")], size, cx);
|
||||
assert_eq!(buffer.text(), "fn a() {\n b\n .c\n \n .d\n}");
|
||||
|
||||
// dedent line after the field expression
|
||||
let ix = buffer.len() - 2;
|
||||
buffer.edit_with_autoindent([(ix..ix, ";\ne")], size, cx);
|
||||
assert_eq!(
|
||||
buffer.text(),
|
||||
"fn a() {\n b\n .c\n \n .d;\n e\n}"
|
||||
);
|
||||
buffer
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue