aboutsummaryrefslogtreecommitdiff
path: root/helix-view
diff options
context:
space:
mode:
authorSkyler Hawthorne2022-03-17 03:34:21 +0000
committerSkyler Hawthorne2022-06-19 03:54:03 +0000
commit0f3c10a021bbe79e20bde1f55b87465edeec476d (patch)
treea2d54e96885b5761e806eddd9bd8206071d15e8c /helix-view
parent502d3290fb88d8a871b0824adc7987a98104933d (diff)
Fix initial selection of Document in new view
When a new View of a Document is created, a default cursor of 0, 0 is created, and it does not get normalized to a single width cursor until at least one movement of the cursor happens. This appears to have no practical negative effect that I could find, but it makes tests difficult to work with, since the initial selection is not what you expect it to be. This changes the initial selection of a new View to be the width of the first grapheme in the text.
Diffstat (limited to 'helix-view')
-rw-r--r--helix-view/src/document.rs34
-rw-r--r--helix-view/src/editor.rs24
2 files changed, 40 insertions, 18 deletions
diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs
index a2d2af77..00adaa1a 100644
--- a/helix-view/src/document.rs
+++ b/helix-view/src/document.rs
@@ -1,5 +1,6 @@
use anyhow::{anyhow, bail, Context, Error};
use helix_core::auto_pairs::AutoPairs;
+use helix_core::Range;
use serde::de::{self, Deserialize, Deserializer};
use serde::Serialize;
use std::cell::Cell;
@@ -83,7 +84,7 @@ impl Serialize for Mode {
pub struct Document {
pub(crate) id: DocumentId,
text: Rope,
- pub(crate) selections: HashMap<ViewId, Selection>,
+ selections: HashMap<ViewId, Selection>,
path: Option<PathBuf>,
encoding: &'static encoding::Encoding,
@@ -637,6 +638,37 @@ impl Document {
.insert(view_id, selection.ensure_invariants(self.text().slice(..)));
}
+ /// Find the origin selection of the text in a document, i.e. where
+ /// a single cursor would go if it were on the first grapheme. If
+ /// the text is empty, returns (0, 0).
+ pub fn origin(&self) -> Range {
+ if self.text().len_chars() == 0 {
+ return Range::new(0, 0);
+ }
+
+ Range::new(0, 1).grapheme_aligned(self.text().slice(..))
+ }
+
+ /// Reset the view's selection on this document to the
+ /// [origin](Document::origin) cursor.
+ pub fn reset_selection(&mut self, view_id: ViewId) {
+ let origin = self.origin();
+ self.set_selection(view_id, Selection::single(origin.anchor, origin.head));
+ }
+
+ /// Initializes a new selection for the given view if it does not
+ /// already have one.
+ pub fn ensure_view_init(&mut self, view_id: ViewId) {
+ if self.selections.get(&view_id).is_none() {
+ self.reset_selection(view_id);
+ }
+ }
+
+ /// Remove a view's selection from this document.
+ pub fn remove_view(&mut self, view_id: ViewId) {
+ self.selections.remove(&view_id);
+ }
+
/// Apply a [`Transaction`] to the [`Document`] to change its text.
fn apply_impl(&mut self, transaction: &Transaction, view_id: ViewId) -> bool {
let old_doc = self.text().clone();
diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs
index 76ac0b51..8607c65a 100644
--- a/helix-view/src/editor.rs
+++ b/helix-view/src/editor.rs
@@ -32,12 +32,12 @@ use anyhow::{bail, Error};
pub use helix_core::diagnostic::Severity;
pub use helix_core::register::Registers;
+use helix_core::Position;
use helix_core::{
auto_pairs::AutoPairs,
syntax::{self, AutoPairConfig},
Change,
};
-use helix_core::{Position, Selection};
use helix_dap as dap;
use serde::{ser::SerializeMap, Deserialize, Deserializer, Serialize, Serializer};
@@ -645,11 +645,8 @@ impl Editor {
view.offset = Position::default();
let doc = self.documents.get_mut(&doc_id).unwrap();
+ doc.ensure_view_init(view.id);
- // initialize selection for view
- doc.selections
- .entry(view.id)
- .or_insert_with(|| Selection::point(0));
// TODO: reuse align_view
let pos = doc
.selection(view.id)
@@ -719,9 +716,7 @@ impl Editor {
Action::Load => {
let view_id = view!(self).id;
let doc = self.documents.get_mut(&id).unwrap();
- if doc.selections().is_empty() {
- doc.set_selection(view_id, Selection::point(0));
- }
+ doc.ensure_view_init(view_id);
return;
}
Action::HorizontalSplit | Action::VerticalSplit => {
@@ -736,7 +731,7 @@ impl Editor {
);
// initialize selection for view
let doc = self.documents.get_mut(&id).unwrap();
- doc.set_selection(view_id, Selection::point(0));
+ doc.ensure_view_init(view_id);
}
}
@@ -769,7 +764,7 @@ impl Editor {
Ok(self.new_file_from_document(action, Document::from(rope, Some(encoding))))
}
- // ???
+ // ??? possible use for integration tests
pub fn open(&mut self, path: PathBuf, action: Action) -> Result<DocumentId, Error> {
let path = helix_core::path::get_canonicalized_path(&path)?;
let id = self.document_by_path(&path).map(|doc| doc.id);
@@ -791,12 +786,7 @@ impl Editor {
pub fn close(&mut self, id: ViewId) {
let view = self.tree.get(self.tree.focus);
// remove selection
- self.documents
- .get_mut(&view.doc)
- .unwrap()
- .selections
- .remove(&id);
-
+ self.documents.get_mut(&view.doc).unwrap().remove_view(id);
self.tree.remove(id);
self._refresh();
}
@@ -871,7 +861,7 @@ impl Editor {
let view = View::new(doc_id, self.config().gutters.clone());
let view_id = self.tree.insert(view);
let doc = self.documents.get_mut(&doc_id).unwrap();
- doc.set_selection(view_id, Selection::point(0));
+ doc.ensure_view_init(view_id);
}
self._refresh();