@@ -1,4 +1,4 @@
1−use anyhow::{anyhow, Context, Error};
1+use anyhow::{anyhow, bail, Context, Error};
2use serde::de::{self, Deserialize, Deserializer};
2use serde::de::{self, Deserialize, Deserializer};
3use serde::Serialize;
3use serde::Serialize;
4use std::cell::Cell;
4use std::cell::Cell;
@@ -11,7 +11,7 @@ use std::sync::Arc;
12use helix_core::{
12use helix_core::{
14− history::History,
14+ history::{History, UndoKind},
15 indent::{auto_detect_indent_style, IndentStyle},
15 indent::{auto_detect_indent_style, IndentStyle},
16 line_ending::auto_detect_line_ending,
16 line_ending::auto_detect_line_ending,
17 syntax::{self, LanguageConfiguration},
17 syntax::{self, LanguageConfiguration},
@@ -54,7 +54,7 @@ impl FromStr for Mode {
54 "normal" => Ok(Mode::Normal),
54 "normal" => Ok(Mode::Normal),
55 "select" => Ok(Mode::Select),
55 "select" => Ok(Mode::Select),
56 "insert" => Ok(Mode::Insert),
56 "insert" => Ok(Mode::Insert),
57− _ => Err(anyhow!("Invalid mode '{}'", s)),
57+ _ => bail!("Invalid mode '{}'", s),
@@ -396,7 +396,7 @@ impl Document {
396 /// The same as [`format`], but only returns formatting changes if auto-formatting
396 /// The same as [`format`], but only returns formatting changes if auto-formatting
397 /// is configured.
397 /// is configured.
398 pub fn auto_format(&self) -> Option<impl Future<Output = LspFormatting> + 'static> {
398 pub fn auto_format(&self) -> Option<impl Future<Output = LspFormatting> + 'static> {
399− if self.language_config().map(|c| c.auto_format) == Some(true) {
399+ if self.language_config()?.auto_format {
400 self.format()
400 self.format()
@@ -406,30 +406,27 @@ impl Document {
406 /// If supported, returns the changes that should be applied to this document in order
406 /// If supported, returns the changes that should be applied to this document in order
407 /// to format it nicely.
407 /// to format it nicely.
408 pub fn format(&self) -> Option<impl Future<Output = LspFormatting> + 'static> {
408 pub fn format(&self) -> Option<impl Future<Output = LspFormatting> + 'static> {
409− if let Some(language_server) = self.language_server() {
409+ let language_server = self.language_server()?;
410− let text = self.text.clone();
410+ let text = self.text.clone();
411− let offset_encoding = language_server.offset_encoding();
411+ let offset_encoding = language_server.offset_encoding();
412− let request = language_server.text_document_formatting(
412+ let request = language_server.text_document_formatting(
413− self.identifier(),
413+ self.identifier(),
414− lsp::FormattingOptions::default(),
414+ lsp::FormattingOptions::default(),
418− let fut = async move {
418+ let fut = async move {
419− let edits = request.await.unwrap_or_else(|e| {
419+ let edits = request.await.unwrap_or_else(|e| {
420− log::warn!("LSP formatting failed: {}", e);
420+ log::warn!("LSP formatting failed: {}", e);
421− Default::default()
421+ Default::default()
423− LspFormatting {
423+ LspFormatting {
424− doc: text,
424+ doc: text,
426− offset_encoding,
426+ offset_encoding,
429− Some(fut)
429+ Some(fut)
435 pub fn save(&mut self) -> impl Future<Output = Result<(), anyhow::Error>> {
432 pub fn save(&mut self) -> impl Future<Output = Result<(), anyhow::Error>> {
@@ -473,9 +470,7 @@ impl Document {
473 if let Some(parent) = path.parent() {
470 if let Some(parent) = path.parent() {
474 // TODO: display a prompt asking the user if the directories should be created
471 // TODO: display a prompt asking the user if the directories should be created
475 if !parent.exists() {
472 if !parent.exists() {
476− return Err(Error::msg(
477− "can't save file, parent directory does not exist",
473+ bail!("can't save file, parent directory does not exist");
@@ -522,8 +517,7 @@ impl Document {
522 /// line ending.
517 /// line ending.
523 pub fn detect_indent_and_line_ending(&mut self) {
518 pub fn detect_indent_and_line_ending(&mut self) {
524 self.indent_style = auto_detect_indent_style(&self.text).unwrap_or_else(|| {
519 self.indent_style = auto_detect_indent_style(&self.text).unwrap_or_else(|| {
525− self.language
520+ self.language_config()
527 .and_then(|config| config.indent.as_ref())
521 .and_then(|config| config.indent.as_ref())
528 .map_or(DEFAULT_INDENT, |config| IndentStyle::from_str(&config.unit))
522 .map_or(DEFAULT_INDENT, |config| IndentStyle::from_str(&config.unit))
@@ -537,7 +531,7 @@ impl Document {
538 // If there is no path or the path no longer exists.
532 // If there is no path or the path no longer exists.
539 if path.is_none() {
533 if path.is_none() {
540− return Err(anyhow!("can't find file to reload from"));
534+ bail!("can't find file to reload from");
543 let mut file = std::fs::File::open(path.unwrap())?;
537 let mut file = std::fs::File::open(path.unwrap())?;
@@ -558,10 +552,8 @@ impl Document {
559 /// Sets the [`Document`]'s encoding with the encoding correspondent to `label`.
553 /// Sets the [`Document`]'s encoding with the encoding correspondent to `label`.
560 pub fn set_encoding(&mut self, label: &str) -> Result<(), Error> {
554 pub fn set_encoding(&mut self, label: &str) -> Result<(), Error> {
561− match encoding::Encoding::for_label(label.as_bytes()) {
555+ self.encoding = encoding::Encoding::for_label(label.as_bytes())
562− Some(encoding) => self.encoding = encoding,
563− None => return Err(anyhow::anyhow!("unknown encoding")),
556+ .ok_or_else(|| anyhow!("unknown encoding"))?;
@@ -646,7 +638,6 @@ impl Document {
649− // set modified since accessed
650 self.modified_since_accessed = true;
641 self.modified_since_accessed = true;
@@ -689,7 +680,7 @@ impl Document {
690 if let Some(notify) = notify {
681 if let Some(notify) = notify {
691 tokio::spawn(notify);
682 tokio::spawn(notify);
692− } //.expect("failed to emit textDocument/didChange");
683+ }
@@ -717,11 +708,11 @@ impl Document {
720− /// Undo the last modification to the [`Document`]. Returns whether the undo was successful.
721− pub fn undo(&mut self, view_id: ViewId) -> bool {
711+ fn undo_redo_impl(&mut self, view_id: ViewId, undo: bool) -> bool {
722 let mut history = self.history.take();
712 let mut history = self.history.take();
713+ let txn = if undo { history.undo() } else { history.redo() };
723− let success = if let Some(transaction) = history.undo() {
714+ let success = if let Some(txn) = txn {
724− self.apply_impl(transaction, view_id)
715+ self.apply_impl(txn, view_id)
@@ -734,21 +725,14 @@ impl Document {
728+ /// Undo the last modification to the [`Document`]. Returns whether the undo was successful.
729+ pub fn undo(&mut self, view_id: ViewId) -> bool {
730+ self.undo_redo_impl(view_id, true)
737 /// Redo the last modification to the [`Document`]. Returns whether the redo was sucessful.
733 /// Redo the last modification to the [`Document`]. Returns whether the redo was sucessful.
738 pub fn redo(&mut self, view_id: ViewId) -> bool {
734 pub fn redo(&mut self, view_id: ViewId) -> bool {
739− let mut history = self.history.take();
735+ self.undo_redo_impl(view_id, false)
740− let success = if let Some(transaction) = history.redo() {
741− self.apply_impl(transaction, view_id)
745− self.history.set(history);
748− // reset changeset to fix len
749− self.changes = ChangeSet::new(self.text());
754 pub fn savepoint(&mut self) {
738 pub fn savepoint(&mut self) {
@@ -761,9 +745,12 @@ impl Document {
764− /// Undo modifications to the [`Document`] according to `uk`.
765− pub fn earlier(&mut self, view_id: ViewId, uk: helix_core::history::UndoKind) -> bool {
748+ fn earlier_later_impl(&mut self, view_id: ViewId, uk: UndoKind, earlier: bool) -> bool {
749+ let txns = if earlier {
766− let txns = self.history.get_mut().earlier(uk);
750+ self.history.get_mut().earlier(uk)
752+ self.history.get_mut().later(uk)
767 let mut success = false;
754 let mut success = false;
768 for txn in txns {
755 for txn in txns {
769 if self.apply_impl(&txn, view_id) {
756 if self.apply_impl(&txn, view_id) {
@@ -777,20 +764,14 @@ impl Document {
767+ /// Undo modifications to the [`Document`] according to `uk`.
768+ pub fn earlier(&mut self, view_id: ViewId, uk: UndoKind) -> bool {
769+ self.earlier_later_impl(view_id, uk, true)
780 /// Redo modifications to the [`Document`] according to `uk`.
772 /// Redo modifications to the [`Document`] according to `uk`.
781− pub fn later(&mut self, view_id: ViewId, uk: helix_core::history::UndoKind) -> bool {
773+ pub fn later(&mut self, view_id: ViewId, uk: UndoKind) -> bool {
782− let txns = self.history.get_mut().later(uk);
774+ self.earlier_later_impl(view_id, uk, false)
783− let mut success = false;
785− if self.apply_impl(&txn, view_id) {
790− // reset changeset to fix len
791− self.changes = ChangeSet::new(self.text());
796 /// Commit pending changes to history
777 /// Commit pending changes to history
@@ -850,18 +831,10 @@ impl Document {
850 /// `language-server` configuration, or the document language if no
831 /// `language-server` configuration, or the document language if no
851 /// `language-id` has been specified.
832 /// `language-id` has been specified.
852 pub fn language_id(&self) -> Option<&str> {
833 pub fn language_id(&self) -> Option<&str> {
853− self.language
834+ self.language_config()
855 .and_then(|config| config.language_server.as_ref())
835 .and_then(|config| config.language_server.as_ref())
856− .and_then(|lsp_config| lsp_config.language_id.as_ref())
836+ .and_then(|lsp_config| lsp_config.language_id.as_deref())
859− self.language()
837+ .or_else(|| Some(self.language()?.rsplit_once('.')?.1))
860− .and_then(|s| s.rsplit_once('.'))
861− .map(|(_, language_id)| language_id)
863− |language_id| Some(language_id.as_str()),
867 /// Corresponding [`LanguageConfiguration`].
840 /// Corresponding [`LanguageConfiguration`].
@@ -874,18 +847,10 @@ impl Document {
874 self.version
847 self.version
850+ /// Language server if it has been initialized.
877 pub fn language_server(&self) -> Option<&helix_lsp::Client> {
851 pub fn language_server(&self) -> Option<&helix_lsp::Client> {
878− let server = self.language_server.as_deref();
852+ let server = self.language_server.as_deref()?;
879− let initialized = server
880− .map(|server| server.is_initialized())
853+ server.is_initialized().then(|| server)
883− // only resolve language_server if it's initialized
891 #[inline]
856 #[inline]
@@ -896,8 +861,7 @@ impl Document {
897 /// Tab size in columns.
862 /// Tab size in columns.
898 pub fn tab_width(&self) -> usize {
863 pub fn tab_width(&self) -> usize {
899− self.language
864+ self.language_config()
901 .and_then(|config| config.indent.as_ref())
865 .and_then(|config| config.indent.as_ref())
902 .map_or(4, |config| config.tab_width) // fallback to 4 columns
866 .map_or(4, |config| config.tab_width) // fallback to 4 columns
@@ -922,7 +886,7 @@ impl Document {
923 /// File path as a URL.
887 /// File path as a URL.
924 pub fn url(&self) -> Option<Url> {
888 pub fn url(&self) -> Option<Url> {
925− self.path().map(|path| Url::from_file_path(path).unwrap())
889+ Url::from_file_path(self.path()?).ok()
928 #[inline]
892 #[inline]
@@ -945,10 +909,6 @@ impl Document {
945 .map(helix_core::path::get_relative_path)
909 .map(helix_core::path::get_relative_path)
948− // pub fn slice<R>(&self, range: R) -> RopeSlice where R: RangeBounds {
949− // self.state.doc.slice
952 // transact(Fn) ?
912 // transact(Fn) ?
954 // -- LSP methods
914 // -- LSP methods
@@ -969,7 +929,6 @@ impl Document {
970 pub fn set_diagnostics(&mut self, diagnostics: Vec<Diagnostic>) {
930 pub fn set_diagnostics(&mut self, diagnostics: Vec<Diagnostic>) {
971 self.diagnostics = diagnostics;
931 self.diagnostics = diagnostics;
973 self.diagnostics
932 self.diagnostics
974 .sort_unstable_by_key(|diagnostic| diagnostic.range);
933 .sort_unstable_by_key(|diagnostic| diagnostic.range);