Add config for default line ending (#5621)

pull/7357/head
Alex 1 year ago committed by GitHub
parent df094909d1
commit 3fb9fafb2a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -63,6 +63,7 @@ Its settings will be merged with the configuration directory `config.toml` and t
| `color-modes` | Whether to color the mode indicator with different colors depending on the mode itself | `false` | | `color-modes` | Whether to color the mode indicator with different colors depending on the mode itself | `false` |
| `text-width` | Maximum line length. Used for the `:reflow` command and soft-wrapping if `soft-wrap.wrap-at-text-width` is set | `80` | | `text-width` | Maximum line length. Used for the `:reflow` command and soft-wrapping if `soft-wrap.wrap-at-text-width` is set | `80` |
| `workspace-lsp-roots` | Directories relative to the workspace root that are treated as LSP roots. Should only be set in `.helix/config.toml` | `[]` | | `workspace-lsp-roots` | Directories relative to the workspace root that are treated as LSP roots. Should only be set in `.helix/config.toml` | `[]` |
| `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` |
### `[editor.statusline]` Section ### `[editor.statusline]` Section

@ -66,5 +66,5 @@ pub use syntax::Syntax;
pub use diagnostic::Diagnostic; pub use diagnostic::Diagnostic;
pub use line_ending::{LineEnding, DEFAULT_LINE_ENDING}; pub use line_ending::{LineEnding, NATIVE_LINE_ENDING};
pub use transaction::{Assoc, Change, ChangeSet, Deletion, Operation, Transaction}; pub use transaction::{Assoc, Change, ChangeSet, Deletion, Operation, Transaction};

@ -1,9 +1,9 @@
use crate::{Rope, RopeSlice}; use crate::{Rope, RopeSlice};
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
pub const DEFAULT_LINE_ENDING: LineEnding = LineEnding::Crlf; pub const NATIVE_LINE_ENDING: LineEnding = LineEnding::Crlf;
#[cfg(not(target_os = "windows"))] #[cfg(not(target_os = "windows"))]
pub const DEFAULT_LINE_ENDING: LineEnding = LineEnding::LF; pub const NATIVE_LINE_ENDING: LineEnding = LineEnding::LF;
/// Represents one of the valid Unicode line endings. /// Represents one of the valid Unicode line endings.
#[derive(PartialEq, Eq, Copy, Clone, Debug)] #[derive(PartialEq, Eq, Copy, Clone, Debug)]

@ -2,7 +2,7 @@ use helix_core::{auto_pairs::DEFAULT_PAIRS, hashmap};
use super::*; use super::*;
const LINE_END: &str = helix_core::DEFAULT_LINE_ENDING.as_str(); const LINE_END: &str = helix_core::NATIVE_LINE_ENDING.as_str();
fn differing_pairs() -> impl Iterator<Item = &'static (char, char)> { fn differing_pairs() -> impl Iterator<Item = &'static (char, char)> {
DEFAULT_PAIRS.iter().filter(|(open, close)| open != close) DEFAULT_PAIRS.iter().filter(|(open, close)| open != close)

@ -244,7 +244,7 @@ pub fn test_editor_config() -> helix_view::editor::Config {
/// character, and if one doesn't exist already, appends the system's /// character, and if one doesn't exist already, appends the system's
/// appropriate line ending to the end of a string. /// appropriate line ending to the end of a string.
pub fn platform_line(input: &str) -> String { pub fn platform_line(input: &str) -> String {
let line_end = helix_core::DEFAULT_LINE_ENDING.as_str(); let line_end = helix_core::NATIVE_LINE_ENDING.as_str();
// we can assume that the source files in this code base will always // we can assume that the source files in this code base will always
// be LF, so indoc strings will always insert LF // be LF, so indoc strings will always insert LF

@ -8,7 +8,6 @@ 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};
use helix_core::text_annotations::{InlineAnnotation, TextAnnotations}; use helix_core::text_annotations::{InlineAnnotation, TextAnnotations};
use helix_core::Range;
use helix_vcs::{DiffHandle, DiffProviderRegistry}; use helix_vcs::{DiffHandle, DiffProviderRegistry};
use ::parking_lot::Mutex; use ::parking_lot::Mutex;
@ -31,8 +30,8 @@ use helix_core::{
indent::{auto_detect_indent_style, IndentStyle}, indent::{auto_detect_indent_style, IndentStyle},
line_ending::auto_detect_line_ending, line_ending::auto_detect_line_ending,
syntax::{self, LanguageConfiguration}, syntax::{self, LanguageConfiguration},
ChangeSet, Diagnostic, LineEnding, Rope, RopeBuilder, Selection, Syntax, Transaction, ChangeSet, Diagnostic, LineEnding, Range, Rope, RopeBuilder, Selection, Syntax, Transaction,
DEFAULT_LINE_ENDING, NATIVE_LINE_ENDING,
}; };
use crate::editor::{Config, RedrawHandle}; use crate::editor::{Config, RedrawHandle};
@ -590,6 +589,7 @@ impl Document {
config: Arc<dyn DynAccess<Config>>, config: Arc<dyn DynAccess<Config>>,
) -> Self { ) -> Self {
let (encoding, has_bom) = encoding_with_bom_info.unwrap_or((encoding::UTF_8, false)); let (encoding, has_bom) = encoding_with_bom_info.unwrap_or((encoding::UTF_8, false));
let line_ending = config.load().default_line_ending.into();
let changes = ChangeSet::new(&text); let changes = ChangeSet::new(&text);
let old_state = None; let old_state = None;
@ -603,7 +603,7 @@ impl Document {
inlay_hints: HashMap::default(), inlay_hints: HashMap::default(),
inlay_hints_oudated: false, inlay_hints_oudated: false,
indent_style: DEFAULT_INDENT, indent_style: DEFAULT_INDENT,
line_ending: DEFAULT_LINE_ENDING, line_ending,
restore_cursor: false, restore_cursor: false,
syntax: None, syntax: None,
language: None, language: None,
@ -623,10 +623,12 @@ impl Document {
focused_at: std::time::Instant::now(), focused_at: std::time::Instant::now(),
} }
} }
pub fn default(config: Arc<dyn DynAccess<Config>>) -> Self { pub fn default(config: Arc<dyn DynAccess<Config>>) -> Self {
let text = Rope::from(DEFAULT_LINE_ENDING.as_str()); let text = Rope::from(NATIVE_LINE_ENDING.as_str());
Self::from(text, None, config) Self::from(text, None, config)
} }
// TODO: async fn? // TODO: async fn?
/// Create a new document from `path`. Encoding is auto-detected, but it can be manually /// Create a new document from `path`. Encoding is auto-detected, but it can be manually
/// overwritten with the `encoding` parameter. /// overwritten with the `encoding` parameter.
@ -643,7 +645,7 @@ impl Document {
from_reader(&mut file, encoding)? from_reader(&mut file, encoding)?
} else { } else {
let encoding = encoding.unwrap_or(encoding::UTF_8); let encoding = encoding.unwrap_or(encoding::UTF_8);
(Rope::from(DEFAULT_LINE_ENDING.as_str()), encoding, false) (Rope::from(NATIVE_LINE_ENDING.as_str()), encoding, false)
}; };
let mut doc = Self::from(rope, Some((encoding, has_bom)), config); let mut doc = Self::from(rope, Some((encoding, has_bom)), config);
@ -887,14 +889,16 @@ impl Document {
/// 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 language indentation
/// configured in `languages.toml`, with a fallback to tabs if it isn't specified. Line ending /// configured in `languages.toml`, with a fallback to tabs if it isn't specified. Line ending
/// is likewise auto-detected, and will fallback to the default OS line ending. /// 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.language_config()
.and_then(|config| config.indent.as_ref()) .and_then(|config| config.indent.as_ref())
.map_or(DEFAULT_INDENT, |config| IndentStyle::from_str(&config.unit)) .map_or(DEFAULT_INDENT, |config| IndentStyle::from_str(&config.unit))
}); });
self.line_ending = auto_detect_line_ending(&self.text).unwrap_or(DEFAULT_LINE_ENDING); if let Some(line_ending) = auto_detect_line_ending(&self.text) {
self.line_ending = line_ending;
}
} }
/// Reload the document from its path. /// Reload the document from its path.
@ -1921,7 +1925,7 @@ mod test {
Document::default(Arc::new(ArcSwap::new(Arc::new(Config::default())))) Document::default(Arc::new(ArcSwap::new(Arc::new(Config::default()))))
.text() .text()
.to_string(), .to_string(),
DEFAULT_LINE_ENDING.as_str() NATIVE_LINE_ENDING.as_str()
); );
} }

@ -44,7 +44,7 @@ pub use helix_core::register::Registers;
use helix_core::{ use helix_core::{
auto_pairs::AutoPairs, auto_pairs::AutoPairs,
syntax::{self, AutoPairConfig, SoftWrap}, syntax::{self, AutoPairConfig, SoftWrap},
Change, Change, LineEnding, NATIVE_LINE_ENDING,
}; };
use helix_core::{Position, Selection}; use helix_core::{Position, Selection};
use helix_dap as dap; use helix_dap as dap;
@ -273,7 +273,7 @@ pub struct Config {
pub search: SearchConfig, pub search: SearchConfig,
pub lsp: LspConfig, pub lsp: LspConfig,
pub terminal: Option<TerminalConfig>, pub terminal: Option<TerminalConfig>,
/// Column numbers at which to draw the rulers. Default to `[]`, meaning no rulers. /// Column numbers at which to draw the rulers. Defaults to `[]`, meaning no rulers.
pub rulers: Vec<u16>, pub rulers: Vec<u16>,
#[serde(default)] #[serde(default)]
pub whitespace: WhitespaceConfig, pub whitespace: WhitespaceConfig,
@ -286,6 +286,8 @@ pub struct Config {
pub soft_wrap: SoftWrap, pub soft_wrap: SoftWrap,
/// Workspace specific lsp ceiling dirs /// Workspace specific lsp ceiling dirs
pub workspace_lsp_roots: Vec<PathBuf>, pub workspace_lsp_roots: Vec<PathBuf>,
/// Which line ending to choose for new documents. Defaults to `native`. i.e. `crlf` on Windows, otherwise `lf`.
pub default_line_ending: LineEndingConfig,
} }
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
@ -727,6 +729,51 @@ impl Default for IndentGuidesConfig {
} }
} }
/// Line ending configuration.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum LineEndingConfig {
/// The platform's native line ending.
///
/// `crlf` on Windows, otherwise `lf`.
Native,
/// Line feed.
LF,
/// Carriage return followed by line feed.
Crlf,
/// Form feed.
#[cfg(feature = "unicode-lines")]
FF,
/// Carriage return.
#[cfg(feature = "unicode-lines")]
CR,
/// Next line.
#[cfg(feature = "unicode-lines")]
Nel,
}
impl Default for LineEndingConfig {
fn default() -> Self {
LineEndingConfig::Native
}
}
impl From<LineEndingConfig> for LineEnding {
fn from(line_ending: LineEndingConfig) -> Self {
match line_ending {
LineEndingConfig::Native => NATIVE_LINE_ENDING,
LineEndingConfig::LF => LineEnding::LF,
LineEndingConfig::Crlf => LineEnding::Crlf,
#[cfg(feature = "unicode-lines")]
LineEndingConfig::FF => LineEnding::FF,
#[cfg(feature = "unicode-lines")]
LineEndingConfig::CR => LineEnding::CR,
#[cfg(feature = "unicode-lines")]
LineEndingConfig::Nel => LineEnding::Nel,
}
}
}
impl Default for Config { impl Default for Config {
fn default() -> Self { fn default() -> Self {
Self { Self {
@ -771,6 +818,7 @@ impl Default for Config {
text_width: 80, text_width: 80,
completion_replace: false, completion_replace: false,
workspace_lsp_roots: Vec::new(), workspace_lsp_roots: Vec::new(),
default_line_ending: LineEndingConfig::default(),
} }
} }
} }

Loading…
Cancel
Save