Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Indentation rework #1562

Merged
merged 22 commits into from
Mar 30, 2022
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
420 changes: 336 additions & 84 deletions helix-core/src/indent.rs

Large diffs are not rendered by default.

85 changes: 81 additions & 4 deletions helix-core/src/syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,15 +106,92 @@ pub struct IndentationConfiguration {
pub unit: String,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum IndentQueryNode {
// A node given just by its kind
SimpleNode(String),
// A node given by a list of characteristics which must all be fulfilled in order to match
ComplexNode {
kind: Option<String>,
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
Triton171 marked this conversation as resolved.
Show resolved Hide resolved
kind_not_in: Vec<String>,
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
parent_kind_in: Vec<String>,
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
field_name_in: Vec<String>,
},
}
impl IndentQueryNode {
pub fn kind(&self) -> Option<&str> {
match self {
IndentQueryNode::SimpleNode(n) => Some(n),
IndentQueryNode::ComplexNode { kind, .. } => kind.as_ref().map(|k| k.as_str()),
}
}
}
impl PartialEq for IndentQueryNode {
fn eq(&self, other: &Self) -> bool {
self.kind().eq(&other.kind())
}
}
impl Eq for IndentQueryNode {}
impl PartialOrd for IndentQueryNode {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for IndentQueryNode {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.kind().cmp(&other.kind())
}
}

#[derive(Default, Debug, Serialize)]
pub struct IndentQueryScopes {
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub all: Vec<IndentQueryNode>,
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub tail: Vec<IndentQueryNode>,
}

impl<'de> Deserialize<'de> for IndentQueryScopes {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
#[derive(Deserialize)]
struct Derived {
#[serde(default)]
pub all: Vec<IndentQueryNode>,
#[serde(default)]
pub tail: Vec<IndentQueryNode>,
}
let derived = Derived::deserialize(deserializer)?;
let mut result = IndentQueryScopes {
all: derived.all,
tail: derived.tail,
};
result.all.sort_unstable();
result.tail.sort_unstable();
Ok(result)
}
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct IndentQuery {
/// Every node specified here increases the indent level by one (in total at most one per line)
#[serde(default)]
#[serde(skip_serializing_if = "HashSet::is_empty")]
pub indent: HashSet<String>,
pub indent: IndentQueryScopes,
/// Every node specified here decreases the indent level by one (in total at most one per line)
#[serde(default)]
#[serde(skip_serializing_if = "HashSet::is_empty")]
pub outdent: HashSet<String>,
pub outdent: IndentQueryScopes,
}

#[derive(Debug)]
Expand Down
28 changes: 12 additions & 16 deletions helix-term/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3805,17 +3805,16 @@ fn open(cx: &mut Context, open: Open) {
)
};

// TODO: share logic with insert_newline for indentation
let indent_level = indent::suggested_indent_for_pos(
let indent = indent::indent_for_newline(
doc.language_config(),
doc.syntax(),
&doc.indent_style,
doc.tab_width(),
text,
line_end_index,
new_line.saturating_sub(1),
true,
)
.unwrap_or_else(|| indent::indent_level_for_line(text.line(cursor_line), doc.tab_width()));
let indent = doc.indent_unit().repeat(indent_level);
line_end_index,
cursor_line,
);
let indent_len = indent.len();
let mut text = String::with_capacity(1 + indent_len);
text.push_str(doc.line_ending.as_str());
Expand Down Expand Up @@ -4550,23 +4549,20 @@ pub mod insert {
let curr = contents.get_char(pos).unwrap_or(' ');

let current_line = text.char_to_line(pos);
let indent_level = indent::suggested_indent_for_pos(
let indent = indent::indent_for_newline(
doc.language_config(),
doc.syntax(),
&doc.indent_style,
doc.tab_width(),
text,
current_line,
pos,
current_line,
true,
)
.unwrap_or_else(|| {
indent::indent_level_for_line(text.line(current_line), doc.tab_width())
});

let indent = doc.indent_unit().repeat(indent_level);
);
let mut text = String::new();
// If we are between pairs (such as brackets), we want to insert an additional line which is indented one level more and place the cursor there
let new_head_pos = if helix_core::auto_pairs::PAIRS.contains(&(prev, curr)) {
let inner_indent = doc.indent_unit().repeat(indent_level + 1);
let inner_indent = indent.clone() + doc.indent_style.as_str();
text.reserve_exact(2 + indent.len() + inner_indent.len());
text.push_str(doc.line_ending.as_str());
text.push_str(&inner_indent);
Expand Down
11 changes: 9 additions & 2 deletions runtime/queries/c/indents.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
indent = [
[indent]
all = [
# Indent non-grouped bodies of if-, while- and do-while-statements.
# TODO Add indent for the for-statement (ideally the body of a for-statement should have a field name in the tree-sitter grammar)
{ kind_not_in = ["compound_statement"], parent_kind_in = ["if_statement", "while_statement", "do_statement"], field_name_in = ["consequence", "body"] }
]
tail = [
"compound_statement",
"field_declaration_list",
"enumerator_list",
Expand All @@ -9,7 +15,8 @@ indent = [
"expression_statement",
]

outdent = [
[outdent]
all = [
"case",
"}",
"]",
Expand Down
4 changes: 2 additions & 2 deletions runtime/queries/cmake/indents.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
indent = [
indent.tail = [
"if_condition",
"foreach_loop",
"while_loop",
Expand All @@ -7,6 +7,6 @@ indent = [
"normal_command",
]

outdent = [
outdent.all = [
")"
]
11 changes: 9 additions & 2 deletions runtime/queries/cpp/indents.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
indent = [
[indent]
all = [
# Indent non-grouped bodies of if-, while- and do-while-statements.
# TODO Add indent for the for-statement (ideally the body of a for-statement should have a field name in the tree-sitter grammar)
{ kind_not_in = ["compound_statement"], parent_kind_in = ["if_statement", "while_statement", "do_statement"], field_name_in = ["consequence", "body"] }
]
tail = [
"compound_statement",
"field_declaration_list",
"enumerator_list",
Expand All @@ -9,7 +15,8 @@ indent = [
"expression_statement",
]

outdent = [
[outdent]
all = [
"case",
"access_specifier",
"}",
Expand Down
4 changes: 2 additions & 2 deletions runtime/queries/dart/indents.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
indent = [
indent.tail = [
"class_body",
"function_body",
"function_expression_body",
Expand All @@ -13,7 +13,7 @@ indent = [
"arguments"
]

outdent = [
outdent.all = [
"}",
"]",
")"
Expand Down
4 changes: 2 additions & 2 deletions runtime/queries/fish/indents.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
indent = [
indent.tail = [
"function_definition",
"while_statement",
"for_statement",
Expand All @@ -7,6 +7,6 @@ indent = [
"switch_statement",
]

outdent = [
outdent.all = [
"end"
]
4 changes: 2 additions & 2 deletions runtime/queries/glsl/indents.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
indent = [
indent.tail = [
"init_declarator",
"compound_statement",
"preproc_arg",
Expand All @@ -10,7 +10,7 @@ indent = [
"compound_literal_expression"
]

outdent = [
outdent.all = [
"#define",
"#ifdef",
"#endif",
Expand Down
6 changes: 4 additions & 2 deletions runtime/queries/go/indents.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
indent = [
indent.tail = [
"import_declaration",
"const_declaration",
#"var_declaration",
Expand All @@ -20,9 +20,11 @@ indent = [
"argument_list",
"field_declaration_list",
"block",
"type_switch_statement",
"expression_switch_statement"
]

outdent = [
outdent.all = [
"case",
"}",
"]",
Expand Down
4 changes: 2 additions & 2 deletions runtime/queries/javascript/indents.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
indent = [
indent.tail = [
"array",
"object",
"arguments",
Expand All @@ -21,7 +21,7 @@ indent = [
"object_type",
]

outdent = [
outdent.all = [
"}",
"]",
")"
Expand Down
4 changes: 2 additions & 2 deletions runtime/queries/json/indents.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
indent = [
indent.tail = [
"object",
"array"
]

outdent = [
outdent.all = [
"]",
"}"
]
2 changes: 1 addition & 1 deletion runtime/queries/llvm-mir-yaml/indents.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
indent = [
indent.tail = [
"block_mapping_pair",
]
4 changes: 2 additions & 2 deletions runtime/queries/llvm-mir/indents.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
indent = [
indent.tail = [
"basic_block",
]

outdent = [
outdent.all = [
"label",
]
4 changes: 2 additions & 2 deletions runtime/queries/llvm/indents.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
indent = [
indent.tail = [
"function_body",
"instruction",
]

outdent = [
outdent.all = [
"}",
]
2 changes: 1 addition & 1 deletion runtime/queries/lua/indents.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
indent = [
indent.tail = [
"function_definition",
"variable_declaration",
"local_variable_declaration",
Expand Down
4 changes: 2 additions & 2 deletions runtime/queries/nix/indents.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
indent = [
indent.tail = [
# "function",
"bind",
"assert",
Expand All @@ -12,7 +12,7 @@ indent = [
"parenthesized",
]

outdent = [
outdent.all = [
"}",
"]",
]
4 changes: 2 additions & 2 deletions runtime/queries/ocaml/indents.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
indent = [
indent.tail = [
"let_binding",
"type_binding",
"structure",
Expand All @@ -8,6 +8,6 @@ indent = [
"match_case",
]

outdent = [
outdent.all = [
"}",
]
4 changes: 2 additions & 2 deletions runtime/queries/perl/indents.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
indent = [
indent.tail = [
"function",
"identifier",
"method_invocation",
Expand All @@ -12,6 +12,6 @@ indent = [
"word_list_qw"
]

outdent = [
outdent.all = [
"}"
]
2 changes: 1 addition & 1 deletion runtime/queries/php/indents.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
indent = [
indent.tail = [
"array_creation_expression",
"arguments",
"formal_parameters",
Expand Down
4 changes: 2 additions & 2 deletions runtime/queries/protobuf/indents.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
indent = [
indent.tail = [
"messageBody",
"enumBody",
"oneofBody",
Expand All @@ -7,6 +7,6 @@ indent = [
"msgLit",
]

outdent = [
outdent.all = [
"}",
]
Loading