Make some Document fields read-only.
This commit is contained in:
parent
7da6bd6a71
commit
9132c6a591
5 changed files with 74 additions and 70 deletions
|
@ -198,9 +198,6 @@ impl State {
|
|||
granularity: Granularity,
|
||||
count: usize,
|
||||
) -> Selection {
|
||||
// move all selections according to normal cursor move semantics by collapsing it
|
||||
// into cursors and moving them vertically
|
||||
|
||||
self.selection
|
||||
.transform(|range| self.move_range(range, dir, granularity, count, false))
|
||||
}
|
||||
|
@ -255,7 +252,6 @@ fn move_vertically(
|
|||
let pos = pos_at_coords(text, Position::new(new_line, new_col));
|
||||
|
||||
let mut range = Range::new(if extend { range.anchor } else { pos }, pos);
|
||||
use std::convert::TryInto;
|
||||
range.horiz = Some(horiz);
|
||||
range
|
||||
}
|
||||
|
|
|
@ -137,7 +137,7 @@ impl Application {
|
|||
.tree
|
||||
.views()
|
||||
.map(|(view, _key)| view)
|
||||
.find(|view| view.doc.path == path);
|
||||
.find(|view| view.doc.path() == path.as_ref());
|
||||
|
||||
if let Some(view) = view {
|
||||
let doc = view.doc.text().slice(..);
|
||||
|
|
|
@ -442,7 +442,7 @@ pub fn delete_selection(cx: &mut Context) {
|
|||
let doc = cx.doc();
|
||||
_delete_selection(doc);
|
||||
|
||||
append_changes_to_history(doc);
|
||||
doc.append_changes_to_history();
|
||||
}
|
||||
|
||||
pub fn change_selection(cx: &mut Context) {
|
||||
|
@ -492,7 +492,6 @@ pub fn append_mode(cx: &mut Context) {
|
|||
enter_insert_mode(doc);
|
||||
doc.restore_cursor = true;
|
||||
|
||||
// TODO: as transaction
|
||||
let text = doc.text().slice(..);
|
||||
let selection = doc.selection().transform(|range| {
|
||||
// TODO: to() + next char
|
||||
|
@ -510,7 +509,6 @@ pub fn command_mode(cx: &mut Context) {
|
|||
let prompt = Prompt::new(
|
||||
":".to_owned(),
|
||||
|_input: &str| {
|
||||
// TODO: i need this duplicate list right now to avoid borrow checker issues
|
||||
let command_list = vec![
|
||||
"q".to_string(),
|
||||
"o".to_string(),
|
||||
|
@ -650,40 +648,12 @@ pub fn open_below(cx: &mut Context) {
|
|||
|
||||
// O inserts a new line before each line with a selection
|
||||
|
||||
fn append_changes_to_history(doc: &mut Document) {
|
||||
if doc.changes.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: change -> change -> undo -> change -> change fails, probably old_state needs reset
|
||||
|
||||
let new_changeset = ChangeSet::new(doc.text());
|
||||
let changes = std::mem::replace(&mut doc.changes, new_changeset);
|
||||
// Instead of doing this messy merge we could always commit, and based on transaction
|
||||
// annotations either add a new layer or compose into the previous one.
|
||||
let transaction = Transaction::from(changes).with_selection(doc.selection().clone());
|
||||
|
||||
// increment document version
|
||||
// TODO: needs to happen on undo/redo too
|
||||
doc.version += 1;
|
||||
|
||||
// TODO: trigger lsp/documentDidChange with changes
|
||||
|
||||
// HAXX: we need to reconstruct the state as it was before the changes..
|
||||
let old_state = doc.old_state.take().expect("no old_state available");
|
||||
|
||||
// TODO: take transaction by value?
|
||||
doc.history.commit_revision(&transaction, &old_state);
|
||||
|
||||
// TODO: notify LSP of changes
|
||||
}
|
||||
|
||||
pub fn normal_mode(cx: &mut Context) {
|
||||
let doc = cx.doc();
|
||||
|
||||
doc.mode = Mode::Normal;
|
||||
|
||||
append_changes_to_history(doc);
|
||||
doc.append_changes_to_history();
|
||||
|
||||
// if leaving append mode, move cursor back by 1
|
||||
if doc.restore_cursor {
|
||||
|
@ -848,7 +818,7 @@ pub fn paste(cx: &mut Context) {
|
|||
};
|
||||
|
||||
doc.apply(&transaction);
|
||||
append_changes_to_history(doc);
|
||||
doc.append_changes_to_history();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -884,7 +854,7 @@ pub fn indent(cx: &mut Context) {
|
|||
}),
|
||||
);
|
||||
doc.apply(&transaction);
|
||||
append_changes_to_history(doc);
|
||||
doc.append_changes_to_history();
|
||||
}
|
||||
|
||||
pub fn unindent(cx: &mut Context) {
|
||||
|
@ -917,7 +887,7 @@ pub fn unindent(cx: &mut Context) {
|
|||
let transaction = Transaction::change(&doc.state, changes.into_iter());
|
||||
|
||||
doc.apply(&transaction);
|
||||
append_changes_to_history(doc);
|
||||
doc.append_changes_to_history();
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -1010,7 +980,7 @@ pub fn completion(cx: &mut Context) {
|
|||
let transaction =
|
||||
util::generate_transaction_from_edits(&doc.state, vec![edit]);
|
||||
doc.apply(&transaction);
|
||||
// TODO: append_changes_to_history(doc); if not in insert mode?
|
||||
// TODO: doc.append_changes_to_history(); if not in insert mode?
|
||||
}
|
||||
_ => (),
|
||||
};
|
||||
|
|
|
@ -17,7 +17,7 @@ pub enum Mode {
|
|||
pub struct Document {
|
||||
pub state: State, // rope + selection
|
||||
/// File path on disk.
|
||||
pub path: Option<PathBuf>,
|
||||
path: Option<PathBuf>,
|
||||
|
||||
/// Current editing mode.
|
||||
pub mode: Mode,
|
||||
|
@ -26,13 +26,16 @@ pub struct Document {
|
|||
/// Tree-sitter AST tree
|
||||
pub syntax: Option<Syntax>,
|
||||
/// Corresponding language scope name. Usually `source.<lang>`.
|
||||
pub language: Option<String>,
|
||||
language: Option<String>,
|
||||
|
||||
/// Pending changes since last history commit.
|
||||
pub changes: ChangeSet,
|
||||
pub old_state: Option<State>,
|
||||
pub history: History,
|
||||
pub version: i32, // should be usize?
|
||||
changes: ChangeSet,
|
||||
/// State at last commit. Used for calculating reverts.
|
||||
old_state: Option<State>,
|
||||
/// Undo tree.
|
||||
history: History,
|
||||
/// Current document version, incremented at each change.
|
||||
version: i32, // should be usize?
|
||||
|
||||
pub diagnostics: Vec<Diagnostic>,
|
||||
pub language_server: Option<Arc<helix_lsp::Client>>,
|
||||
|
@ -90,23 +93,8 @@ impl Document {
|
|||
|
||||
let mut doc = Self::new(State::new(doc));
|
||||
|
||||
if let Some(language_config) = LOADER.language_config_for_file_name(path.as_path()) {
|
||||
let highlight_config = language_config.highlight_config(scopes).unwrap().unwrap();
|
||||
// TODO: config.configure(scopes) is now delayed, is that ok?
|
||||
|
||||
let syntax = Syntax::new(&doc.state.doc, highlight_config.clone());
|
||||
|
||||
doc.syntax = Some(syntax);
|
||||
// TODO: maybe just keep an Arc<> pointer to the language_config?
|
||||
doc.language = Some(language_config.scope().to_string());
|
||||
|
||||
// TODO: this ties lsp support to tree-sitter enabled languages for now. Language
|
||||
// config should use Option<HighlightConfig> to let us have non-tree-sitter configs.
|
||||
|
||||
// TODO: circular dep: view <-> lsp
|
||||
// helix_lsp::REGISTRY;
|
||||
// view should probably depend on lsp
|
||||
};
|
||||
let language_config = LOADER.language_config_for_file_name(path.as_path());
|
||||
doc.set_language(language_config, scopes);
|
||||
|
||||
// canonicalize path to absolute value
|
||||
doc.path = Some(std::fs::canonicalize(path)?);
|
||||
|
@ -140,17 +128,35 @@ impl Document {
|
|||
} // and_then notify save
|
||||
}
|
||||
|
||||
pub fn set_language(&mut self, scope: &str, scopes: &[String]) {
|
||||
if let Some(language_config) = LOADER.language_config_for_scope(scope) {
|
||||
pub fn set_language(
|
||||
&mut self,
|
||||
language_config: Option<Arc<helix_core::syntax::LanguageConfiguration>>,
|
||||
scopes: &[String],
|
||||
) {
|
||||
if let Some(language_config) = language_config {
|
||||
// TODO: maybe just keep an Arc<> pointer to the language_config?
|
||||
self.language = Some(language_config.scope().to_string());
|
||||
|
||||
// TODO: this ties lsp support to tree-sitter enabled languages for now. Language
|
||||
// config should use Option<HighlightConfig> to let us have non-tree-sitter configs.
|
||||
|
||||
let highlight_config = language_config.highlight_config(scopes).unwrap().unwrap();
|
||||
// TODO: config.configure(scopes) is now delayed, is that ok?
|
||||
|
||||
let syntax = Syntax::new(&self.state.doc, highlight_config.clone());
|
||||
|
||||
self.syntax = Some(syntax);
|
||||
} else {
|
||||
self.syntax = None;
|
||||
self.language = None;
|
||||
};
|
||||
}
|
||||
|
||||
pub fn set_language2(&mut self, scope: &str, scopes: &[String]) {
|
||||
let language_config = LOADER.language_config_for_scope(scope);
|
||||
self.set_language(language_config, scopes);
|
||||
}
|
||||
|
||||
pub fn set_language_server(&mut self, language_server: Option<Arc<helix_lsp::Client>>) {
|
||||
self.language_server = language_server;
|
||||
}
|
||||
|
@ -238,11 +244,44 @@ impl Document {
|
|||
false
|
||||
}
|
||||
|
||||
pub fn append_changes_to_history(&mut self) {
|
||||
if self.changes.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: change -> change -> undo -> change -> change fails, probably old_state needs reset
|
||||
|
||||
let new_changeset = ChangeSet::new(self.text());
|
||||
let changes = std::mem::replace(&mut self.changes, new_changeset);
|
||||
// Instead of doing this messy merge we could always commit, and based on transaction
|
||||
// annotations either add a new layer or compose into the previous one.
|
||||
let transaction = Transaction::from(changes).with_selection(self.selection().clone());
|
||||
|
||||
// increment document version
|
||||
self.version += 1;
|
||||
|
||||
// HAXX: we need to reconstruct the state as it was before the changes..
|
||||
let old_state = self.old_state.take().expect("no old_state available");
|
||||
|
||||
self.history.commit_revision(&transaction, &old_state);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn mode(&self) -> Mode {
|
||||
self.mode
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// Corresponding language scope name. Usually `source.<lang>`.
|
||||
pub fn language(&self) -> Option<&str> {
|
||||
self.language.as_ref().map(String::as_str)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn version(&self) -> i32 {
|
||||
self.version
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn path(&self) -> Option<&PathBuf> {
|
||||
self.path.as_ref()
|
||||
|
|
|
@ -37,9 +37,8 @@ impl Editor {
|
|||
|
||||
// try to find a language server based on the language name
|
||||
let language_server = doc
|
||||
.language
|
||||
.as_ref()
|
||||
.and_then(|language| self.language_servers.get(&language, &executor));
|
||||
.language()
|
||||
.and_then(|language| self.language_servers.get(language, &executor));
|
||||
|
||||
if let Some(language_server) = language_server {
|
||||
// TODO: do this everywhere
|
||||
|
@ -47,7 +46,7 @@ impl Editor {
|
|||
|
||||
smol::block_on(language_server.text_document_did_open(
|
||||
doc.url().unwrap(),
|
||||
doc.version,
|
||||
doc.version(),
|
||||
doc.text(),
|
||||
))
|
||||
.unwrap();
|
||||
|
|
Loading…
Reference in a new issue