Refactor document methods

pull/1651/head
Gokul Soumya 3 years ago committed by Blaž Hrastnik
parent fa83426011
commit 59b5bf3178

@ -1,4 +1,4 @@
use anyhow::{anyhow, Context, Error}; use anyhow::{anyhow, bail, Context, Error};
use serde::de::{self, Deserialize, Deserializer}; use serde::de::{self, Deserialize, Deserializer};
use serde::Serialize; use serde::Serialize;
use std::cell::Cell; use std::cell::Cell;
@ -11,7 +11,7 @@ use std::sync::Arc;
use helix_core::{ use helix_core::{
encoding, encoding,
history::History, history::{History, UndoKind},
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},
@ -54,7 +54,7 @@ impl FromStr for Mode {
"normal" => Ok(Mode::Normal), "normal" => Ok(Mode::Normal),
"select" => Ok(Mode::Select), "select" => Ok(Mode::Select),
"insert" => Ok(Mode::Insert), "insert" => Ok(Mode::Insert),
_ => Err(anyhow!("Invalid mode '{}'", s)), _ => bail!("Invalid mode '{}'", s),
} }
} }
} }
@ -396,7 +396,7 @@ impl Document {
/// The same as [`format`], but only returns formatting changes if auto-formatting /// The same as [`format`], but only returns formatting changes if auto-formatting
/// is configured. /// is configured.
pub fn auto_format(&self) -> Option<impl Future<Output = LspFormatting> + 'static> { pub fn auto_format(&self) -> Option<impl Future<Output = LspFormatting> + 'static> {
if self.language_config().map(|c| c.auto_format) == Some(true) { if self.language_config()?.auto_format {
self.format() self.format()
} else { } else {
None None
@ -406,30 +406,27 @@ impl Document {
/// If supported, returns the changes that should be applied to this document in order /// If supported, returns the changes that should be applied to this document in order
/// to format it nicely. /// to format it nicely.
pub fn format(&self) -> Option<impl Future<Output = LspFormatting> + 'static> { pub fn format(&self) -> Option<impl Future<Output = LspFormatting> + 'static> {
if let Some(language_server) = self.language_server() { let language_server = self.language_server()?;
let text = self.text.clone(); let text = self.text.clone();
let offset_encoding = language_server.offset_encoding(); let offset_encoding = language_server.offset_encoding();
let request = language_server.text_document_formatting( let request = language_server.text_document_formatting(
self.identifier(), self.identifier(),
lsp::FormattingOptions::default(), lsp::FormattingOptions::default(),
None, None,
)?; )?;
let fut = async move { let fut = async move {
let edits = request.await.unwrap_or_else(|e| { let edits = request.await.unwrap_or_else(|e| {
log::warn!("LSP formatting failed: {}", e); log::warn!("LSP formatting failed: {}", e);
Default::default() Default::default()
}); });
LspFormatting { LspFormatting {
doc: text, doc: text,
edits, edits,
offset_encoding, offset_encoding,
} }
}; };
Some(fut) Some(fut)
} else {
None
}
} }
pub fn save(&mut self) -> impl Future<Output = Result<(), anyhow::Error>> { pub fn save(&mut self) -> impl Future<Output = Result<(), anyhow::Error>> {
@ -473,9 +470,7 @@ impl Document {
if let Some(parent) = path.parent() { if let Some(parent) = path.parent() {
// TODO: display a prompt asking the user if the directories should be created // TODO: display a prompt asking the user if the directories should be created
if !parent.exists() { if !parent.exists() {
return Err(Error::msg( bail!("can't save file, parent directory does not exist");
"can't save file, parent directory does not exist",
));
} }
} }
@ -522,8 +517,7 @@ impl Document {
/// line ending. /// line ending.
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 self.language_config()
.as_ref()
.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))
}); });
@ -537,7 +531,7 @@ impl Document {
// If there is no path or the path no longer exists. // If there is no path or the path no longer exists.
if path.is_none() { if path.is_none() {
return Err(anyhow!("can't find file to reload from")); bail!("can't find file to reload from");
} }
let mut file = std::fs::File::open(path.unwrap())?; let mut file = std::fs::File::open(path.unwrap())?;
@ -558,10 +552,8 @@ impl Document {
/// Sets the [`Document`]'s encoding with the encoding correspondent to `label`. /// Sets the [`Document`]'s encoding with the encoding correspondent to `label`.
pub fn set_encoding(&mut self, label: &str) -> Result<(), Error> { pub fn set_encoding(&mut self, label: &str) -> Result<(), Error> {
match encoding::Encoding::for_label(label.as_bytes()) { self.encoding = encoding::Encoding::for_label(label.as_bytes())
Some(encoding) => self.encoding = encoding, .ok_or_else(|| anyhow!("unknown encoding"))?;
None => return Err(anyhow::anyhow!("unknown encoding")),
}
Ok(()) Ok(())
} }
@ -646,7 +638,6 @@ impl Document {
); );
} }
// set modified since accessed
self.modified_since_accessed = true; self.modified_since_accessed = true;
} }
@ -689,7 +680,7 @@ impl Document {
if let Some(notify) = notify { if let Some(notify) = notify {
tokio::spawn(notify); tokio::spawn(notify);
} //.expect("failed to emit textDocument/didChange"); }
} }
} }
success success
@ -717,11 +708,11 @@ impl Document {
success success
} }
/// Undo the last modification to the [`Document`]. Returns whether the undo was successful. fn undo_redo_impl(&mut self, view_id: ViewId, undo: bool) -> bool {
pub fn undo(&mut self, view_id: ViewId) -> bool {
let mut history = self.history.take(); let mut history = self.history.take();
let success = if let Some(transaction) = history.undo() { let txn = if undo { history.undo() } else { history.redo() };
self.apply_impl(transaction, view_id) let success = if let Some(txn) = txn {
self.apply_impl(txn, view_id)
} else { } else {
false false
}; };
@ -734,21 +725,14 @@ impl Document {
success success
} }
/// Undo the last modification to the [`Document`]. Returns whether the undo was successful.
pub fn undo(&mut self, view_id: ViewId) -> bool {
self.undo_redo_impl(view_id, true)
}
/// Redo the last modification to the [`Document`]. Returns whether the redo was sucessful. /// Redo the last modification to the [`Document`]. Returns whether the redo was sucessful.
pub fn redo(&mut self, view_id: ViewId) -> bool { pub fn redo(&mut self, view_id: ViewId) -> bool {
let mut history = self.history.take(); self.undo_redo_impl(view_id, false)
let success = if let Some(transaction) = history.redo() {
self.apply_impl(transaction, view_id)
} else {
false
};
self.history.set(history);
if success {
// reset changeset to fix len
self.changes = ChangeSet::new(self.text());
}
success
} }
pub fn savepoint(&mut self) { pub fn savepoint(&mut self) {
@ -761,9 +745,12 @@ impl Document {
} }
} }
/// Undo modifications to the [`Document`] according to `uk`. fn earlier_later_impl(&mut self, view_id: ViewId, uk: UndoKind, earlier: bool) -> bool {
pub fn earlier(&mut self, view_id: ViewId, uk: helix_core::history::UndoKind) -> bool { let txns = if earlier {
let txns = self.history.get_mut().earlier(uk); self.history.get_mut().earlier(uk)
} else {
self.history.get_mut().later(uk)
};
let mut success = false; let mut success = false;
for txn in txns { for txn in txns {
if self.apply_impl(&txn, view_id) { if self.apply_impl(&txn, view_id) {
@ -777,20 +764,14 @@ impl Document {
success success
} }
/// Undo modifications to the [`Document`] according to `uk`.
pub fn earlier(&mut self, view_id: ViewId, uk: UndoKind) -> bool {
self.earlier_later_impl(view_id, uk, true)
}
/// Redo modifications to the [`Document`] according to `uk`. /// Redo modifications to the [`Document`] according to `uk`.
pub fn later(&mut self, view_id: ViewId, uk: helix_core::history::UndoKind) -> bool { pub fn later(&mut self, view_id: ViewId, uk: UndoKind) -> bool {
let txns = self.history.get_mut().later(uk); self.earlier_later_impl(view_id, uk, false)
let mut success = false;
for txn in txns {
if self.apply_impl(&txn, view_id) {
success = true;
}
}
if success {
// reset changeset to fix len
self.changes = ChangeSet::new(self.text());
}
success
} }
/// Commit pending changes to history /// Commit pending changes to history
@ -850,18 +831,10 @@ impl Document {
/// `language-server` configuration, or the document language if no /// `language-server` configuration, or the document language if no
/// `language-id` has been specified. /// `language-id` has been specified.
pub fn language_id(&self) -> Option<&str> { pub fn language_id(&self) -> Option<&str> {
self.language self.language_config()
.as_ref()
.and_then(|config| config.language_server.as_ref()) .and_then(|config| config.language_server.as_ref())
.and_then(|lsp_config| lsp_config.language_id.as_ref()) .and_then(|lsp_config| lsp_config.language_id.as_deref())
.map_or_else( .or_else(|| Some(self.language()?.rsplit_once('.')?.1))
|| {
self.language()
.and_then(|s| s.rsplit_once('.'))
.map(|(_, language_id)| language_id)
},
|language_id| Some(language_id.as_str()),
)
} }
/// Corresponding [`LanguageConfiguration`]. /// Corresponding [`LanguageConfiguration`].
@ -874,18 +847,10 @@ impl Document {
self.version self.version
} }
/// Language server if it has been initialized.
pub fn language_server(&self) -> Option<&helix_lsp::Client> { pub fn language_server(&self) -> Option<&helix_lsp::Client> {
let server = self.language_server.as_deref(); let server = self.language_server.as_deref()?;
let initialized = server server.is_initialized().then(|| server)
.map(|server| server.is_initialized())
.unwrap_or(false);
// only resolve language_server if it's initialized
if initialized {
server
} else {
None
}
} }
#[inline] #[inline]
@ -896,8 +861,7 @@ impl Document {
/// Tab size in columns. /// Tab size in columns.
pub fn tab_width(&self) -> usize { pub fn tab_width(&self) -> usize {
self.language self.language_config()
.as_ref()
.and_then(|config| config.indent.as_ref()) .and_then(|config| config.indent.as_ref())
.map_or(4, |config| config.tab_width) // fallback to 4 columns .map_or(4, |config| config.tab_width) // fallback to 4 columns
} }
@ -922,7 +886,7 @@ impl Document {
/// File path as a URL. /// File path as a URL.
pub fn url(&self) -> Option<Url> { pub fn url(&self) -> Option<Url> {
self.path().map(|path| Url::from_file_path(path).unwrap()) Url::from_file_path(self.path()?).ok()
} }
#[inline] #[inline]
@ -945,10 +909,6 @@ impl Document {
.map(helix_core::path::get_relative_path) .map(helix_core::path::get_relative_path)
} }
// pub fn slice<R>(&self, range: R) -> RopeSlice where R: RangeBounds {
// self.state.doc.slice
// }
// transact(Fn) ? // transact(Fn) ?
// -- LSP methods // -- LSP methods
@ -969,7 +929,6 @@ impl Document {
pub fn set_diagnostics(&mut self, diagnostics: Vec<Diagnostic>) { pub fn set_diagnostics(&mut self, diagnostics: Vec<Diagnostic>) {
self.diagnostics = diagnostics; self.diagnostics = diagnostics;
// sort by range
self.diagnostics self.diagnostics
.sort_unstable_by_key(|diagnostic| diagnostic.range); .sort_unstable_by_key(|diagnostic| diagnostic.range);
} }

Loading…
Cancel
Save