mirror of
https://github.com/helix-editor/helix.git
synced 2024-11-22 17:36:19 +04:00
add a separate "helix:" modeline for setting helix-specific config
for example, if the language name differs between vim and helix
This commit is contained in:
parent
01554579e9
commit
cdc53f42e8
@ -4,14 +4,16 @@
|
|||||||
|
|
||||||
use crate::indent::IndentStyle;
|
use crate::indent::IndentStyle;
|
||||||
use crate::regex::Regex;
|
use crate::regex::Regex;
|
||||||
|
use crate::syntax::ModelineConfig;
|
||||||
use crate::{LineEnding, RopeSlice};
|
use crate::{LineEnding, RopeSlice};
|
||||||
|
|
||||||
// 5 is the vim default
|
// 5 is the vim default
|
||||||
const LINES_TO_CHECK: usize = 5;
|
const LINES_TO_CHECK: usize = 5;
|
||||||
const LENGTH_TO_CHECK: usize = 256;
|
const LENGTH_TO_CHECK: usize = 256;
|
||||||
|
|
||||||
static MODELINE_REGEX: Lazy<Regex> =
|
static VIM_MODELINE_REGEX: Lazy<Regex> =
|
||||||
Lazy::new(|| Regex::new(r"^(\S*\s+)?(vi|[vV]im[<=>]?\d*|ex):\s*(set?\s+)?").unwrap());
|
Lazy::new(|| Regex::new(r"^(\S*\s+)?(vi|[vV]im[<=>]?\d*|ex):\s*(set?\s+)?").unwrap());
|
||||||
|
static HELIX_MODELINE_REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"^(\S*\s+)?helix:").unwrap());
|
||||||
|
|
||||||
#[derive(Default, Debug, Eq, PartialEq)]
|
#[derive(Default, Debug, Eq, PartialEq)]
|
||||||
pub struct Modeline {
|
pub struct Modeline {
|
||||||
@ -65,7 +67,8 @@ fn parse_from_line(&mut self, line: &str) {
|
|||||||
};
|
};
|
||||||
c == ' ' || c == '\t'
|
c == ' ' || c == '\t'
|
||||||
};
|
};
|
||||||
if let Some(pos) = MODELINE_REGEX.find(line) {
|
|
||||||
|
if let Some(pos) = VIM_MODELINE_REGEX.find(line) {
|
||||||
for option in line[pos.end()..].split(split_modeline) {
|
for option in line[pos.end()..].split(split_modeline) {
|
||||||
let parts: Vec<_> = option.split('=').collect();
|
let parts: Vec<_> = option.split('=').collect();
|
||||||
match parts[0] {
|
match parts[0] {
|
||||||
@ -93,6 +96,27 @@ fn parse_from_line(&mut self, line: &str) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(pos) = HELIX_MODELINE_REGEX.find(line) {
|
||||||
|
let config = &line[pos.end()..];
|
||||||
|
match toml::from_str::<ModelineConfig>(config) {
|
||||||
|
Ok(modeline) => {
|
||||||
|
if let Some(language) = modeline.language {
|
||||||
|
self.language = Some(language);
|
||||||
|
}
|
||||||
|
if let Some(indent) = modeline.indent {
|
||||||
|
self.indent_style = Some(IndentStyle::from_str(&indent.unit));
|
||||||
|
}
|
||||||
|
if let Some(line_ending) = modeline.line_ending {
|
||||||
|
self.line_ending = LineEnding::from_str(&line_ending);
|
||||||
|
if self.line_ending.is_none() {
|
||||||
|
log::warn!("could not interpret line ending {line_ending:?}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => log::warn!("{e}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,6 +247,41 @@ fn test_modeline_parsing() {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
"# helix: language = 'perl'",
|
||||||
|
Modeline {
|
||||||
|
language: Some("perl".to_string()),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"# helix: indent = { unit = ' ' }",
|
||||||
|
Modeline {
|
||||||
|
indent_style: Some(IndentStyle::Spaces(3)),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"# helix: indent = { unit = \"\t\" }",
|
||||||
|
Modeline {
|
||||||
|
indent_style: Some(IndentStyle::Tabs),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"# helix: indent = { unit = \"\\t\" }",
|
||||||
|
Modeline {
|
||||||
|
indent_style: Some(IndentStyle::Tabs),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"# helix: line-ending = \"\\r\\n\"",
|
||||||
|
Modeline {
|
||||||
|
line_ending: Some(LineEnding::Crlf),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
),
|
||||||
];
|
];
|
||||||
for (line, expected) in tests {
|
for (line, expected) in tests {
|
||||||
let mut got = Modeline::default();
|
let mut got = Modeline::default();
|
||||||
|
@ -171,6 +171,18 @@ pub struct LanguageConfiguration {
|
|||||||
pub persistent_diagnostic_sources: Vec<String>,
|
pub persistent_diagnostic_sources: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The subset of LanguageConfig which can be read from a modeline.
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "kebab-case", deny_unknown_fields)]
|
||||||
|
pub struct ModelineConfig {
|
||||||
|
/// the language name (corresponds to language_id in LanguageConfig)
|
||||||
|
pub language: Option<String>,
|
||||||
|
/// the indent settings (only unit is supported in modelines)
|
||||||
|
pub indent: Option<ModelineIndentationConfiguration>,
|
||||||
|
/// the line ending to use (as a literal string)
|
||||||
|
pub line_ending: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum FileType {
|
pub enum FileType {
|
||||||
/// The extension of the file, either the `Path::extension` or the full
|
/// The extension of the file, either the `Path::extension` or the full
|
||||||
@ -536,6 +548,12 @@ pub struct DebuggerQuirks {
|
|||||||
pub absolute_paths: bool,
|
pub absolute_paths: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "kebab-case")]
|
||||||
|
pub struct ModelineIndentationConfiguration {
|
||||||
|
pub unit: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
pub struct IndentationConfiguration {
|
pub struct IndentationConfiguration {
|
||||||
|
Loading…
Reference in New Issue
Block a user