aboutsummaryrefslogtreecommitdiff
path: root/helix-view
diff options
context:
space:
mode:
authorBlaž Hrastnik2021-03-31 08:17:01 +0000
committerBlaž Hrastnik2021-03-31 08:17:01 +0000
commit6c4093c94634a94adbccb4783cddb90076881c02 (patch)
tree34d4691fe6daca0d14ce77b434830cdef72deb47 /helix-view
parent9eaef6e33376407931162780cd402297c44f26c4 (diff)
Weave through view_id references so that views into one file have independent selects.
Diffstat (limited to 'helix-view')
-rw-r--r--helix-view/src/document.rs51
-rw-r--r--helix-view/src/editor.rs27
-rw-r--r--helix-view/src/view.rs2
3 files changed, 53 insertions, 27 deletions
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<ViewId, Selection>,
path: Option<PathBuf>,
@@ -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);