Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement EditorConfig support #1777

Open
wants to merge 24 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
aa65111
Add initial editorconfig parsing on document open
TheDaemoness Mar 8, 2022
0d433fd
Add document::Config and parse editorconfig into it
TheDaemoness Mar 10, 2022
a9ee261
Add a flag to enable EditorConfig support
TheDaemoness Mar 10, 2022
6950865
Fix Config-related clippy lints
TheDaemoness Mar 10, 2022
c120e35
Merge branch 'master' of https://github.com/helix-editor/helix into h…
TheDaemoness Jun 11, 2022
86c0923
Merge upstream changes
TheDaemoness Jun 11, 2022
278d9f4
Bump ec4rs to 1.0.0 and apply fixes
TheDaemoness Jun 11, 2022
73a8f25
Merge branch 'helix-editor:master' into master
TheDaemoness Jun 25, 2022
2bff8f2
Update ec4rs
TheDaemoness Jun 25, 2022
0ec192a
Add support for EditorConfig tab_width
TheDaemoness Jun 25, 2022
ff3d631
Make Document::tab_width_override private
TheDaemoness Jun 25, 2022
d07440d
Update ec4rs version requirement
TheDaemoness Jun 25, 2022
e177b85
Merge branch 'helix-editor:master' into master
TheDaemoness Jul 14, 2022
c878e20
Remove unused method in helix_view::document::Config
TheDaemoness Jul 14, 2022
2d8fefa
Rename document::Config to DocumentOptions
TheDaemoness Aug 7, 2022
7f57658
Change document tab width field
TheDaemoness Aug 7, 2022
77dffd7
Merge branch 'master' of https://github.com/helix-editor/helix
TheDaemoness Aug 7, 2022
7de1bbe
Fix incomplete documentation of DocumentOptions
TheDaemoness Aug 7, 2022
5d53965
Merge from upstream, discard EditorConfig-related changes
TheDaemoness Mar 18, 2023
ff215a8
Re-implement EditorConfig integration
TheDaemoness Mar 18, 2023
91af0f1
Make ConfigureDocument and DocumentConfig private
TheDaemoness Mar 18, 2023
a4f9325
Merge branch 'master' into master
TheDaemoness Mar 31, 2023
6fbc8af
Fixup documentation and indent size handling
TheDaemoness Mar 31, 2023
a359bec
Remove DocumentConfig
TheDaemoness Apr 1, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions helix-view/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ log = "~0.4"

which = "4.2"

ec4rs = "1.0.0-rc.1"
TheDaemoness marked this conversation as resolved.
Show resolved Hide resolved

[target.'cfg(windows)'.dependencies]
clipboard-win = { version = "4.4", features = ["std"] }

Expand Down
79 changes: 74 additions & 5 deletions helix-view/src/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -371,14 +371,54 @@ impl Document {
encoding: Option<&'static encoding::Encoding>,
config_loader: Option<Arc<syntax::Loader>>,
) -> Result<Self, Error> {
Self::open_with_editorconfig(path, encoding, config_loader, false)
}

// TODO: async fn?
/// Create a new document from `path`,
/// optionally using settings from EditorConfig.
///
/// If the `encoding` parameter is specified,
/// it overrides the encoding obtained from EditorConfig
/// and auto-detection.
pub fn open_with_editorconfig(
path: &Path,
encoding: Option<&'static encoding::Encoding>,
config_loader: Option<Arc<syntax::Loader>>,
use_editorconfig: bool,
) -> Result<Self, Error> {
// Closure to read the editorconfig files that apply to `path`.
// Ideally this should be done after an existing file is already opened.
let get_editorconfig = || {
if use_editorconfig {
let mut ecfg = ec4rs::config_for(path).unwrap_or_default();
ecfg.use_fallbacks();
ecfg
} else {
Default::default()
}
};
// Adds editorconfig values to encoding as a fallback.
let encoding_with_ecfg = move |ecfg: &ec4rs::Properties| {
encoding.or_else(|| {
ecfg.get_raw::<ec4rs::property::Charset>()
.filter_unset()
.into_result()
.ok()
.map(|string| string.as_bytes())
.and_then(encoding::Encoding::for_label)
})
};
// Open the file if it exists, otherwise assume it is a new file (and thus empty).
let (rope, encoding) = if path.exists() {
let ((rope, encoding), ecfg) = if path.exists() {
let mut file =
std::fs::File::open(path).context(format!("unable to open {:?}", path))?;
from_reader(&mut file, encoding)?
let ecfg = get_editorconfig();
(from_reader(&mut file, encoding_with_ecfg(&ecfg))?, ecfg)
} else {
let encoding = encoding.unwrap_or(encoding::UTF_8);
(Rope::from(DEFAULT_LINE_ENDING.as_str()), encoding)
let ecfg = get_editorconfig();
let encoding = encoding_with_ecfg(&ecfg).unwrap_or(encoding::UTF_8);
((Rope::from(DEFAULT_LINE_ENDING.as_str()), encoding), get_editorconfig())
};

let mut doc = Self::from(rope, Some(encoding));
Expand All @@ -389,7 +429,28 @@ impl Document {
doc.detect_language(loader);
}

doc.detect_indent_and_line_ending();
// Set the indent style.
use ec4rs::property::{IndentSize, IndentStyle as EcIndentStyle};
match (ecfg.get::<EcIndentStyle>(), ecfg.get::<IndentSize>()) {
(Ok(EcIndentStyle::Tabs), _) => {
doc.indent_style = IndentStyle::Tabs;
}
(Ok(EcIndentStyle::Spaces), Ok(IndentSize::Value(n))) => {
doc.indent_style = IndentStyle::Spaces(
n.try_into().unwrap_or(u8::MAX)
);
}
_ => doc.detect_indent_impl()
}

// Set the line ending.
use ec4rs::property::EndOfLine;
match ecfg.get::<EndOfLine>() {
Ok(EndOfLine::Cr) => {doc.line_ending = LineEnding::CR},
Ok(EndOfLine::Lf) => {doc.line_ending = LineEnding::LF},
Ok(EndOfLine::CrLf) => {doc.line_ending = LineEnding::Crlf},
Err(_) => doc.detect_line_ending_impl()
}

Ok(doc)
}
Expand Down Expand Up @@ -517,11 +578,19 @@ impl Document {
/// specified. Line ending is likewise auto-detected, and will fallback to the default OS
/// line ending.
pub fn detect_indent_and_line_ending(&mut self) {
self.detect_indent_impl();
self.detect_line_ending_impl();
}

fn detect_indent_impl(&mut self) {
self.indent_style = auto_detect_indent_style(&self.text).unwrap_or_else(|| {
self.language_config()
.and_then(|config| config.indent.as_ref())
.map_or(DEFAULT_INDENT, |config| IndentStyle::from_str(&config.unit))
});
}

fn detect_line_ending_impl(&mut self) {
self.line_ending = auto_detect_line_ending(&self.text).unwrap_or(DEFAULT_LINE_ENDING);
}

Expand Down
8 changes: 7 additions & 1 deletion helix-view/src/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -587,7 +587,13 @@ impl Editor {
let id = if let Some(id) = id {
id
} else {
let mut doc = Document::open(&path, None, Some(self.syn_loader.clone()))?;
// TODO: Config variable instead of `false`.
let mut doc = Document::open_with_editorconfig(
&path,
None,
Some(self.syn_loader.clone()),
false
)?;

let _ = Self::launch_language_server(&mut self.language_servers, &mut doc);

Expand Down