Add options `editor.indent.{tab-width,unit}`.

Also add `language.indent.required`.
pull/6652/head
Muhammad 8 months ago
parent a1453350df
commit c301792ff7
No known key found for this signature in database
GPG Key ID: 6667F8D7694B5CCF

@ -146,7 +146,7 @@ pub struct LanguageConfiguration {
)] )]
pub language_servers: Vec<LanguageServerFeatures>, pub language_servers: Vec<LanguageServerFeatures>,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub indent: Option<IndentationConfiguration>, pub indent: Option<LanguageIndentationConfiguration>,
#[serde(skip)] #[serde(skip)]
pub(crate) indent_query: OnceCell<Option<Query>>, pub(crate) indent_query: OnceCell<Option<Query>>,
@ -537,7 +537,7 @@ pub struct DebuggerQuirks {
pub absolute_paths: bool, pub absolute_paths: bool,
} }
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")] #[serde(rename_all = "kebab-case")]
pub struct IndentationConfiguration { pub struct IndentationConfiguration {
#[serde(deserialize_with = "deserialize_tab_width")] #[serde(deserialize_with = "deserialize_tab_width")]
@ -545,6 +545,14 @@ pub struct IndentationConfiguration {
pub unit: String, pub unit: String,
} }
#[derive(Debug, Serialize, Deserialize)]
pub struct LanguageIndentationConfiguration {
#[serde(flatten)]
pub indent: IndentationConfiguration,
#[serde(default)]
pub required: bool,
}
/// How the indentation for a newly inserted line should be determined. /// How the indentation for a newly inserted line should be determined.
/// If the selected heuristic is not available (e.g. because the current /// 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. /// language has no tree-sitter indent queries), a simpler one will be used.

@ -7,7 +7,7 @@ use helix_core::auto_pairs::AutoPairs;
use helix_core::chars::char_is_word; use helix_core::chars::char_is_word;
use helix_core::doc_formatter::TextFormat; use helix_core::doc_formatter::TextFormat;
use helix_core::encoding::Encoding; use helix_core::encoding::Encoding;
use helix_core::syntax::{Highlight, LanguageServerFeature}; use helix_core::syntax::{Highlight, LanguageServerFeature, IndentationConfiguration};
use helix_core::text_annotations::{InlineAnnotation, Overlay}; use helix_core::text_annotations::{InlineAnnotation, Overlay};
use helix_lsp::util::lsp_pos_to_pos; use helix_lsp::util::lsp_pos_to_pos;
use helix_stdx::faccess::{copy_metadata, readonly}; use helix_stdx::faccess::{copy_metadata, readonly};
@ -653,7 +653,7 @@ impl Document {
let changes = ChangeSet::new(text.slice(..)); let changes = ChangeSet::new(text.slice(..));
let old_state = None; let old_state = None;
Self { let mut doc = Self {
id: DocumentId::default(), id: DocumentId::default(),
path: None, path: None,
encoding, encoding,
@ -684,7 +684,9 @@ impl Document {
focused_at: std::time::Instant::now(), focused_at: std::time::Instant::now(),
readonly: false, readonly: false,
jump_labels: HashMap::new(), jump_labels: HashMap::new(),
} };
doc.detect_indent_and_line_ending();
doc
} }
pub fn default(config: Arc<dyn DynAccess<Config>>) -> Self { pub fn default(config: Arc<dyn DynAccess<Config>>) -> Self {
@ -1065,14 +1067,13 @@ impl Document {
.or_else(|| config_loader.language_config_for_shebang(self.text().slice(..))) .or_else(|| config_loader.language_config_for_shebang(self.text().slice(..)))
} }
/// Detect the indentation used in the file, or otherwise defaults to the language indentation /// Detect the indentation used in the file, or otherwise defaults to the global indentation
/// configured in `languages.toml`, with a fallback to tabs if it isn't specified. Line ending /// configured in `config.toml` and then the language indentation configured in
/// `languages.toml`, with a fallback to tabs if it isn't specified. Line ending
/// is likewise auto-detected, and will remain unchanged if no line endings were detected. /// is likewise auto-detected, and will remain unchanged if no line endings were detected.
pub fn detect_indent_and_line_ending(&mut self) { pub fn detect_indent_and_line_ending(&mut self) {
self.indent_style = auto_detect_indent_style(&self.text).unwrap_or_else(|| { self.indent_style = auto_detect_indent_style(&self.text).unwrap_or_else(|| {
self.language_config() self.indent_config(DEFAULT_INDENT, |config| IndentStyle::from_str(&config.unit))
.and_then(|config| config.indent.as_ref())
.map_or(DEFAULT_INDENT, |config| IndentStyle::from_str(&config.unit))
}); });
if let Some(line_ending) = auto_detect_line_ending(&self.text) { if let Some(line_ending) = auto_detect_line_ending(&self.text) {
self.line_ending = line_ending; self.line_ending = line_ending;
@ -1107,6 +1108,20 @@ impl Document {
}; };
} }
fn indent_config<T, F: Fn(&IndentationConfiguration) -> T>(&self, default: T, mapper: F) -> T {
self.language_config()
.and_then(|config| config.indent.as_ref())
.filter(|config| config.required)
.map(|config| mapper(&config.indent))
.or_else(|| self.config.load().indent.as_ref().map(&mapper))
.or_else(|| {
self.language_config()
.and_then(|config| config.indent.as_ref())
.map(|config| mapper(&config.indent))
})
.unwrap_or(default)
}
/// Reload the document from its path. /// Reload the document from its path.
pub fn reload( pub fn reload(
&mut self, &mut self,
@ -1790,9 +1805,7 @@ impl Document {
/// The width that the tab character is rendered at /// The width that the tab character is rendered at
pub fn tab_width(&self) -> usize { pub fn tab_width(&self) -> usize {
self.language_config() self.indent_config(4, |config| config.tab_width) // fallback to 4 columns
.and_then(|config| config.indent.as_ref())
.map_or(4, |config| config.tab_width) // fallback to 4 columns
} }
// The width (in spaces) of a level of indentation. // The width (in spaces) of a level of indentation.

@ -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, IndentationHeuristic, LanguageServerFeature, SoftWrap}, syntax::{self, AutoPairConfig, IndentationConfiguration, IndentationHeuristic, LanguageServerFeature, SoftWrap},
Change, LineEnding, Position, Range, Selection, Uri, NATIVE_LINE_ENDING, Change, LineEnding, Position, Range, Selection, Uri, NATIVE_LINE_ENDING,
}; };
use helix_dap as dap; use helix_dap as dap;
@ -316,6 +316,8 @@ pub struct Config {
pub rulers: Vec<u16>, pub rulers: Vec<u16>,
#[serde(default)] #[serde(default)]
pub whitespace: WhitespaceConfig, pub whitespace: WhitespaceConfig,
#[serde(skip_serializing_if = "Option::is_none")]
pub indent: Option<IndentationConfiguration>,
/// Persistently display open buffers along the top /// Persistently display open buffers along the top
pub bufferline: BufferLine, pub bufferline: BufferLine,
/// Vertical indent width guides. /// Vertical indent width guides.
@ -964,6 +966,7 @@ impl Default for Config {
terminal: get_terminal_provider(), terminal: get_terminal_provider(),
rulers: Vec::new(), rulers: Vec::new(),
whitespace: WhitespaceConfig::default(), whitespace: WhitespaceConfig::default(),
indent: None,
bufferline: BufferLine::default(), bufferline: BufferLine::default(),
indent_guides: IndentGuidesConfig::default(), indent_guides: IndentGuidesConfig::default(),
color_modes: false, color_modes: false,

@ -863,7 +863,7 @@ roots = ["pyproject.toml", "setup.py", "poetry.lock", "pyrightconfig.json"]
comment-token = "#" comment-token = "#"
language-servers = ["ruff", "jedi", "pylsp"] language-servers = ["ruff", "jedi", "pylsp"]
# TODO: pyls needs utf-8 offsets # TODO: pyls needs utf-8 offsets
indent = { tab-width = 4, unit = " " } indent = { tab-width = 4, unit = " ", required = true }
[[grammar]] [[grammar]]
name = "python" name = "python"
@ -1308,7 +1308,7 @@ name = "yaml"
scope = "source.yaml" scope = "source.yaml"
file-types = ["yml", "yaml"] file-types = ["yml", "yaml"]
comment-token = "#" comment-token = "#"
indent = { tab-width = 2, unit = " " } indent = { tab-width = 2, unit = " ", required = true }
language-servers = [ "yaml-language-server", "ansible-language-server" ] language-servers = [ "yaml-language-server", "ansible-language-server" ]
injection-regex = "yml|yaml" injection-regex = "yml|yaml"

Loading…
Cancel
Save