Make the indent heuristic configurable

pull/9828/head
Daniel Ebert 1 year ago committed by Blaž Hrastnik
parent 559bfc1f5e
commit 938a710904

@ -6,7 +6,7 @@ use crate::{
chars::{char_is_line_ending, char_is_whitespace}, chars::{char_is_line_ending, char_is_whitespace},
find_first_non_whitespace_char, find_first_non_whitespace_char,
graphemes::{grapheme_width, tab_width_at}, graphemes::{grapheme_width, tab_width_at},
syntax::{LanguageConfiguration, RopeProvider, Syntax}, syntax::{IndentationHeuristic, LanguageConfiguration, RopeProvider, Syntax},
tree_sitter::Node, tree_sitter::Node,
Rope, RopeGraphemes, RopeSlice, Rope, RopeGraphemes, RopeSlice,
}; };
@ -931,6 +931,7 @@ pub fn treesitter_indent_for_pos<'a>(
pub fn indent_for_newline( pub fn indent_for_newline(
language_config: Option<&LanguageConfiguration>, language_config: Option<&LanguageConfiguration>,
syntax: Option<&Syntax>, syntax: Option<&Syntax>,
indent_heuristic: &IndentationHeuristic,
indent_style: &IndentStyle, indent_style: &IndentStyle,
tab_width: usize, tab_width: usize,
text: RopeSlice, text: RopeSlice,
@ -939,7 +940,12 @@ pub fn indent_for_newline(
current_line: usize, current_line: usize,
) -> String { ) -> String {
let indent_width = indent_style.indent_width(tab_width); let indent_width = indent_style.indent_width(tab_width);
if let (Some(query), Some(syntax)) = ( if let (
IndentationHeuristic::TreeSitter | IndentationHeuristic::Hybrid,
Some(query),
Some(syntax),
) = (
indent_heuristic,
language_config.and_then(|config| config.indent_query()), language_config.and_then(|config| config.indent_query()),
syntax, syntax,
) { ) {
@ -953,6 +959,7 @@ pub fn indent_for_newline(
line_before_end_pos, line_before_end_pos,
true, true,
) { ) {
if let IndentationHeuristic::Hybrid = indent_heuristic {
// We want to compute the indentation not only based on the // We want to compute the indentation not only based on the
// syntax tree but also on the actual indentation of a previous // syntax tree but also on the actual indentation of a previous
// line. This makes indentation computation more resilient to // line. This makes indentation computation more resilient to
@ -998,6 +1005,7 @@ pub fn indent_for_newline(
break; break;
} }
} }
}
return indent.to_string(indent_style, tab_width); return indent.to_string(indent_style, tab_width);
}; };
} }

@ -442,6 +442,22 @@ pub struct IndentationConfiguration {
pub unit: String, pub unit: String,
} }
/// How the indentation for a newly inserted line should be determined.
/// If the selected heuristic is not available (e.g. because the current
/// language has no tree-sitter indent queries), a simpler one will be used.
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum IndentationHeuristic {
/// Just copy the indentation of the line that the cursor is currently on.
Simple,
/// Use tree-sitter indent queries to compute the expected absolute indentation level of the new line.
TreeSitter,
/// Use tree-sitter indent queries to compute the expected difference in indentation between the new line
/// and the line before. Add this to the actual indentation level of the line before.
#[default]
Hybrid,
}
/// Configuration for auto pairs /// Configuration for auto pairs
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case", deny_unknown_fields, untagged)] #[serde(rename_all = "kebab-case", deny_unknown_fields, untagged)]

@ -3053,6 +3053,7 @@ fn insert_with_indent(cx: &mut Context, cursor_fallback: IndentFallbackPos) {
let indent = indent::indent_for_newline( let indent = indent::indent_for_newline(
language_config, language_config,
syntax, syntax,
&doc.config.load().indent_heuristic,
&doc.indent_style, &doc.indent_style,
tab_width, tab_width,
text, text,
@ -3181,6 +3182,7 @@ fn open(cx: &mut Context, open: Open) {
let indent = indent::indent_for_newline( let indent = indent::indent_for_newline(
doc.language_config(), doc.language_config(),
doc.syntax(), doc.syntax(),
&doc.config.load().indent_heuristic,
&doc.indent_style, &doc.indent_style,
doc.tab_width(), doc.tab_width(),
text, text,
@ -3720,6 +3722,7 @@ pub mod insert {
let indent = indent::indent_for_newline( let indent = indent::indent_for_newline(
doc.language_config(), doc.language_config(),
doc.syntax(), doc.syntax(),
&doc.config.load().indent_heuristic,
&doc.indent_style, &doc.indent_style,
doc.tab_width(), doc.tab_width(),
text, text,

@ -42,7 +42,7 @@ use anyhow::{anyhow, bail, Error};
pub use helix_core::diagnostic::Severity; pub use helix_core::diagnostic::Severity;
use helix_core::{ use helix_core::{
auto_pairs::AutoPairs, auto_pairs::AutoPairs,
syntax::{self, AutoPairConfig, SoftWrap}, syntax::{self, AutoPairConfig, IndentationHeuristic, SoftWrap},
Change, LineEnding, NATIVE_LINE_ENDING, Change, LineEnding, NATIVE_LINE_ENDING,
}; };
use helix_core::{Position, Selection}; use helix_core::{Position, Selection};
@ -291,6 +291,9 @@ pub struct Config {
pub insert_final_newline: bool, pub insert_final_newline: bool,
/// Enables smart tab /// Enables smart tab
pub smart_tab: Option<SmartTabConfig>, pub smart_tab: Option<SmartTabConfig>,
/// Which indent heuristic to use when a new line is inserted
#[serde(default)]
pub indent_heuristic: IndentationHeuristic,
} }
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq, PartialOrd, Ord)]
@ -841,6 +844,7 @@ impl Default for Config {
default_line_ending: LineEndingConfig::default(), default_line_ending: LineEndingConfig::default(),
insert_final_newline: true, insert_final_newline: true,
smart_tab: Some(SmartTabConfig::default()), smart_tab: Some(SmartTabConfig::default()),
indent_heuristic: IndentationHeuristic::default(),
} }
} }
} }

Loading…
Cancel
Save