From 6c4093c94634a94adbccb4783cddb90076881c02 Mon Sep 17 00:00:00 2001 From: Blaž Hrastnik Date: Wed, 31 Mar 2021 17:17:01 +0900 Subject: Weave through view_id references so that views into one file have independent selects. --- helix-view/src/document.rs | 51 ++++++++++++++++++++++++++-------------------- helix-view/src/editor.rs | 27 ++++++++++++++++++++---- helix-view/src/view.rs | 2 +- 3 files changed, 53 insertions(+), 27 deletions(-) (limited to 'helix-view') diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index cf160cca..d79cddde 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -8,7 +8,9 @@ use helix_core::{ ChangeSet, Diagnostic, History, Rope, Selection, State, Syntax, Transaction, }; -use crate::DocumentId; +use crate::{DocumentId, ViewId}; + +use std::collections::HashMap; #[derive(Copy, Clone, PartialEq, Eq, Hash)] pub enum Mode { @@ -21,6 +23,7 @@ pub struct Document { // rope + selection pub(crate) id: DocumentId, state: State, + pub(crate) selections: HashMap, path: Option, @@ -73,6 +76,7 @@ impl Document { id: DocumentId::default(), path: None, state: State::new(text), + selections: HashMap::default(), mode: Mode::Normal, restore_cursor: false, syntax: None, @@ -178,12 +182,12 @@ impl Document { self.language_server = language_server; } - pub fn set_selection(&mut self, selection: Selection) { + pub fn set_selection(&mut self, view_id: ViewId, selection: Selection) { // TODO: use a transaction? - self.state.selection = selection; + self.selections.insert(view_id, selection); } - fn _apply(&mut self, transaction: &Transaction) -> bool { + fn _apply(&mut self, transaction: &Transaction, view_id: ViewId) -> bool { let old_doc = self.text().clone(); let success = transaction.changes().apply(&mut self.state.doc); @@ -191,10 +195,11 @@ impl Document { if !transaction.changes().is_empty() { // update the selection: either take the selection specified in the transaction, or map the // current selection through changes. - self.state.selection = transaction + let selection = transaction .selection() .cloned() - .unwrap_or_else(|| self.selection().clone().map(transaction.changes())); + .unwrap_or_else(|| self.selection(view_id).clone().map(transaction.changes())); + self.set_selection(view_id, selection); self.version += 1; @@ -227,14 +232,14 @@ impl Document { success } - pub fn apply(&mut self, transaction: &Transaction) -> bool { + pub fn apply(&mut self, transaction: &Transaction, view_id: ViewId) -> bool { // store the state just before any changes are made. This allows us to undo to the // state just before a transaction was applied. if self.changes.is_empty() && !transaction.changes().is_empty() { self.old_state = Some(self.state.clone()); } - let success = self._apply(&transaction); + let success = self._apply(&transaction, view_id); self.modified = true; // TODO: be smarter about modified by keeping track of saved version instead. That way if @@ -249,9 +254,9 @@ impl Document { success } - pub fn undo(&mut self) -> bool { + pub fn undo(&mut self, view_id: ViewId) -> bool { if let Some(transaction) = self.history.undo() { - let success = self._apply(&transaction); + let success = self._apply(&transaction, view_id); // reset changeset to fix len self.changes = ChangeSet::new(self.text()); @@ -261,9 +266,9 @@ impl Document { false } - pub fn redo(&mut self) -> bool { + pub fn redo(&mut self, view_id: ViewId) -> bool { if let Some(transaction) = self.history.redo() { - let success = self._apply(&transaction); + let success = self._apply(&transaction, view_id); // reset changeset to fix len self.changes = ChangeSet::new(self.text()); @@ -273,7 +278,7 @@ impl Document { false } - pub fn append_changes_to_history(&mut self) { + pub fn append_changes_to_history(&mut self, view_id: ViewId) { if self.changes.is_empty() { return; } @@ -282,7 +287,8 @@ impl Document { 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()); + let transaction = + Transaction::from(changes).with_selection(self.selection(view_id).clone()); // 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"); @@ -362,8 +368,8 @@ impl Document { &self.state.doc } - pub fn selection(&self) -> &Selection { - &self.state.selection + pub fn selection(&self, view_id: ViewId) -> &Selection { + &self.selections[&view_id] } pub fn relative_path(&self) -> Option<&Path> { @@ -400,13 +406,14 @@ mod test { use helix_lsp::{lsp, Client}; let text = Rope::from("hello"); let mut doc = Document::new(text); - doc.set_selection(Selection::single(5, 5)); + let view = ViewId::default(); + doc.set_selection(view, Selection::single(5, 5)); // insert - let transaction = Transaction::insert(doc.text(), doc.selection(), " world".into()); + let transaction = Transaction::insert(doc.text(), doc.selection(view), " world".into()); let old_doc = doc.state.clone(); - doc.apply(&transaction); + doc.apply(&transaction, view); let changes = Client::changeset_to_changes(&old_doc.doc, doc.text(), transaction.changes()); assert_eq!( @@ -425,7 +432,7 @@ mod test { let transaction = transaction.invert(&old_doc.doc); let old_doc = doc.state.clone(); - doc.apply(&transaction); + doc.apply(&transaction, view); let changes = Client::changeset_to_changes(&old_doc.doc, doc.text(), transaction.changes()); // line: 0-based. @@ -450,13 +457,13 @@ mod test { // also tests that changes are layered, positions depend on previous changes. - doc.state.selection = Selection::single(0, 5); + doc.set_selection(view, Selection::single(0, 5)); let transaction = Transaction::change( &doc.state.doc, vec![(0, 2, Some("aei".into())), (3, 5, Some("ou".into()))].into_iter(), ); // aeilou - doc.apply(&transaction); + doc.apply(&transaction, view); let changes = Client::changeset_to_changes(&doc.state.doc, doc.text(), transaction.changes()); diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index f062b55d..f74bbb13 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -91,24 +91,40 @@ impl Editor { }; use crate::tree::Layout; + use helix_core::Selection; match action { Action::Replace => { let view = self.view(); - let jump = (view.doc, self.documents[view.doc].selection().clone()); + let jump = ( + view.doc, + self.documents[view.doc].selection(view.id).clone(), + ); let view = self.view_mut(); view.jumps.push(jump); view.doc = id; view.first_line = 0; + let view_id = view.id; + + // initialize selection for view + let doc = &mut self.documents[id]; + doc.selections.insert(view_id, Selection::point(0)); + return Ok(id); } Action::HorizontalSplit => { let view = View::new(id)?; - self.tree.split(view, Layout::Horizontal); + let view_id = self.tree.split(view, Layout::Horizontal); + // initialize selection for view + let doc = &mut self.documents[id]; + doc.selections.insert(view_id, Selection::point(0)); } Action::VerticalSplit => { let view = View::new(id)?; - self.tree.split(view, Layout::Vertical); + let view_id = self.tree.split(view, Layout::Vertical); + // initialize selection for view + let doc = &mut self.documents[id]; + doc.selections.insert(view_id, Selection::point(0)); } } @@ -134,6 +150,9 @@ impl Editor { smol::block_on(language_server.text_document_did_close(doc.identifier())).unwrap(); } + // remove selection + self.documents[view.doc].selections.remove(&id); + // self.documents.remove(view.doc); self.tree.remove(id); self._refresh(); @@ -183,7 +202,7 @@ impl Editor { const OFFSET: u16 = 7; // 1 diagnostic + 5 linenr + 1 gutter let view = self.view(); let doc = &self.documents[view.doc]; - let cursor = doc.selection().cursor(); + let cursor = doc.selection(view.id).cursor(); if let Some(mut pos) = view.screen_coords_at_pos(doc, doc.text().slice(..), cursor) { pos.col += view.area.x as usize + OFFSET as usize; pos.row += view.area.y as usize; diff --git a/helix-view/src/view.rs b/helix-view/src/view.rs index 9e4c1373..89caaf3e 100644 --- a/helix-view/src/view.rs +++ b/helix-view/src/view.rs @@ -74,7 +74,7 @@ impl View { } pub fn ensure_cursor_in_view(&mut self, doc: &Document) { - let cursor = doc.selection().cursor(); + let cursor = doc.selection(self.id).cursor(); let line = doc.text().char_to_line(cursor); let document_end = self.first_line + (self.area.height as usize).saturating_sub(2); -- cgit v1.2.3-70-g09d2