on master help sign in
Simplify implementation of `add_indent_level`.
723a132Daniel Ebert
book/src/configuration.md+1−1
@@ -65,7 +65,7 @@ Its settings will be merged with the configuration directory `config.toml` and t
65| `workspace-lsp-roots` | Directories relative to the workspace root that are treated as LSP roots. Should only be set in `.helix/config.toml` | `[]` |
65| `workspace-lsp-roots` | Directories relative to the workspace root that are treated as LSP roots. Should only be set in `.helix/config.toml` | `[]` |
66| `default-line-ending` | The line ending to use for new documents. Can be `native`, `lf`, `crlf`, `ff`, `cr` or `nel`. `native` uses the platform's native line ending (`crlf` on Windows, otherwise `lf`). | `native` |
66| `default-line-ending` | The line ending to use for new documents. Can be `native`, `lf`, `crlf`, `ff`, `cr` or `nel`. `native` uses the platform's native line ending (`crlf` on Windows, otherwise `lf`). | `native` |
67| `insert-final-newline` | Whether to automatically insert a trailing line-ending on write if missing | `true` |
67| `insert-final-newline` | Whether to automatically insert a trailing line-ending on write if missing | `true` |
68−| `indent-heuristic` | How the indentation for a newly inserted line is computed: `simple` just copies the indentation level from the previous line, `tree-sitter` computes the indentation based on the syntax tree and `hybrid` combines both approaches | `hybrid`
68+| `indent-heuristic` | How the indentation for a newly inserted line is computed: `simple` just copies the indentation level from the previous line, `tree-sitter` computes the indentation based on the syntax tree and `hybrid` combines both approaches. If the chosen heuristic is not available, a different one will be used as a fallback (the fallback order being `hybrid` -> `tree-sitter` -> `simple`). | `hybrid`
69
69
70### `[editor.statusline]` Section
70### `[editor.statusline]` Section
71
71
helix-core/src/indent.rs+19−22
@@ -8,7 +8,7 @@ use crate::{
8 graphemes::{grapheme_width, tab_width_at},
8 graphemes::{grapheme_width, tab_width_at},
9 syntax::{IndentationHeuristic, LanguageConfiguration, RopeProvider, Syntax},
9 syntax::{IndentationHeuristic, LanguageConfiguration, RopeProvider, Syntax},
10 tree_sitter::Node,
10 tree_sitter::Node,
11− Rope, RopeGraphemes, RopeSlice,
11+ Position, Rope, RopeGraphemes, RopeSlice,
12};
12};
13
13
14/// Enum representing indentation style.
14/// Enum representing indentation style.
@@ -225,27 +225,24 @@ fn add_indent_level(
225 // Since the width of a tab depends on its offset, we cannot simply iterate over
225 // Since the width of a tab depends on its offset, we cannot simply iterate over
226 // the chars of `base_indent` in reverse until we have the desired indent reduction,
226 // the chars of `base_indent` in reverse until we have the desired indent reduction,
227 // instead we iterate over them twice in forward direction.
227 // instead we iterate over them twice in forward direction.
228− let mut base_indent_width: usize = 0;
228+ let base_indent_rope = RopeSlice::from(base_indent.as_str());
229− for c in base_indent.chars() {
229+ #[allow(deprecated)]
230− base_indent_width += match c {
230+ let base_indent_width =
231− '\t' => tab_width_at(base_indent_width, tab_width as u16),
231+ crate::visual_coords_at_pos(base_indent_rope, base_indent_rope.len_chars(), tab_width)
232− // This is only true since `base_indent` consists only of tabs and spaces
232+ .col;
233− _ => 1,
234− };
235− }
236 let target_indent_width = base_indent_width
233 let target_indent_width = base_indent_width
237 .saturating_sub((-added_indent_level) as usize * indent_style.indent_width(tab_width));
234 .saturating_sub((-added_indent_level) as usize * indent_style.indent_width(tab_width));
238− let mut reduced_indent_width = 0;
235+ #[allow(deprecated)]
239− for (i, c) in base_indent.char_indices() {
236+ let char_end_idx = crate::pos_at_visual_coords(
237+ base_indent_rope,
238+ Position {
239+ row: 0,
240− if reduced_indent_width >= target_indent_width {
240+ col: target_indent_width,
241+ },
242+ tab_width,
243+ );
244+ let byte_end_idx = base_indent_rope.char_to_byte(char_end_idx);
241− base_indent.truncate(i);
245+ base_indent.truncate(byte_end_idx);
242− return base_indent;
243− }
244− reduced_indent_width += match c {
245− '\t' => tab_width_at(base_indent_width, tab_width as u16),
246− _ => 1,
247− };
248− }
249 base_indent
246 base_indent
250 }
247 }
251}
248}
@@ -959,7 +956,7 @@ pub fn indent_for_newline(
959 line_before_end_pos,
956 line_before_end_pos,
960 true,
957 true,
961 ) {
958 ) {
962− if let IndentationHeuristic::Hybrid = indent_heuristic {
959+ if *indent_heuristic == IndentationHeuristic::Hybrid {
963 // We want to compute the indentation not only based on the
960 // We want to compute the indentation not only based on the
964 // syntax tree but also on the actual indentation of a previous
961 // syntax tree but also on the actual indentation of a previous
965 // line. This makes indentation computation more resilient to
962 // line. This makes indentation computation more resilient to
@@ -969,7 +966,7 @@ pub fn indent_for_newline(
969 // make sense, e.g. if it has a different alignment than the new line.
966 // make sense, e.g. if it has a different alignment than the new line.
970 // In order to prevent edge cases with long running times, we only try
967 // In order to prevent edge cases with long running times, we only try
971 // a constant number of (non-empty) lines.
968 // a constant number of (non-empty) lines.
972− const MAX_ATTEMPTS: usize = 2;
969+ const MAX_ATTEMPTS: usize = 4;
973 let mut num_attempts = 0;
970 let mut num_attempts = 0;
974 for line_idx in (0..=line_before).rev() {
971 for line_idx in (0..=line_before).rev() {
975 let line = text.line(line_idx);
972 let line = text.line(line_idx);