mirror of https://github.com/helix-editor/helix
Compare commits
4 Commits
880d9f1363
...
e5c13077ba
Author | SHA1 | Date |
---|---|---|
|
e5c13077ba | |
|
7681cc93fd | |
|
c0f8e18437 | |
|
6f49ff2229 |
|
@ -167,6 +167,8 @@
|
||||||
| `extend_to_line_start` | Extend to line start | select: `` <home> `` |
|
| `extend_to_line_start` | Extend to line start | select: `` <home> `` |
|
||||||
| `extend_to_first_nonwhitespace` | Extend to first non-blank in line | |
|
| `extend_to_first_nonwhitespace` | Extend to first non-blank in line | |
|
||||||
| `extend_to_line_end` | Extend to line end | select: `` <end> `` |
|
| `extend_to_line_end` | Extend to line end | select: `` <end> `` |
|
||||||
|
| `undo_selection` | Go to previous selection | normal: `` <A-k> ``, select: `` <A-k> `` |
|
||||||
|
| `redo_selection` | Go to next selection | normal: `` <A-w> ``, select: `` <A-w> `` |
|
||||||
| `extend_to_line_end_newline` | Extend to line end | |
|
| `extend_to_line_end_newline` | Extend to line end | |
|
||||||
| `signature_help` | Show signature help | |
|
| `signature_help` | Show signature help | |
|
||||||
| `smart_tab` | Insert tab if all cursors have all whitespace to their left; otherwise, run a separate command. | insert: `` <tab> `` |
|
| `smart_tab` | Insert tab if all cursors have all whitespace to their left; otherwise, run a separate command. | insert: `` <tab> `` |
|
||||||
|
|
|
@ -44,7 +44,7 @@ use helix_core::{
|
||||||
Selection, SmallVec, Syntax, Tendril, Transaction,
|
Selection, SmallVec, Syntax, Tendril, Transaction,
|
||||||
};
|
};
|
||||||
use helix_view::{
|
use helix_view::{
|
||||||
document::{FormatterError, Mode, SCRATCH_BUFFER_NAME},
|
document::{FormatterError, Mode, SelectionDirection, SCRATCH_BUFFER_NAME},
|
||||||
editor::Action,
|
editor::Action,
|
||||||
info::Info,
|
info::Info,
|
||||||
input::KeyEvent,
|
input::KeyEvent,
|
||||||
|
@ -467,6 +467,8 @@ impl MappableCommand {
|
||||||
extend_to_line_start, "Extend to line start",
|
extend_to_line_start, "Extend to line start",
|
||||||
extend_to_first_nonwhitespace, "Extend to first non-blank in line",
|
extend_to_first_nonwhitespace, "Extend to first non-blank in line",
|
||||||
extend_to_line_end, "Extend to line end",
|
extend_to_line_end, "Extend to line end",
|
||||||
|
undo_selection, "Go to previous selection",
|
||||||
|
redo_selection, "Go to next selection",
|
||||||
extend_to_line_end_newline, "Extend to line end",
|
extend_to_line_end_newline, "Extend to line end",
|
||||||
signature_help, "Show signature help",
|
signature_help, "Show signature help",
|
||||||
smart_tab, "Insert tab if all cursors have all whitespace to their left; otherwise, run a separate command.",
|
smart_tab, "Insert tab if all cursors have all whitespace to their left; otherwise, run a separate command.",
|
||||||
|
@ -840,6 +842,18 @@ fn goto_line_end(cx: &mut Context) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn undo_selection(cx: &mut Context) {
|
||||||
|
let count = cx.count();
|
||||||
|
let (view, doc) = current!(cx.editor);
|
||||||
|
doc.select_history(view.id, SelectionDirection::Undo(count));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn redo_selection(cx: &mut Context) {
|
||||||
|
let count = cx.count();
|
||||||
|
let (view, doc) = current!(cx.editor);
|
||||||
|
doc.select_history(view.id, SelectionDirection::Redo(count));
|
||||||
|
}
|
||||||
|
|
||||||
fn extend_to_line_end(cx: &mut Context) {
|
fn extend_to_line_end(cx: &mut Context) {
|
||||||
let (view, doc) = current!(cx.editor);
|
let (view, doc) = current!(cx.editor);
|
||||||
goto_line_end_impl(view, doc, Movement::Extend)
|
goto_line_end_impl(view, doc, Movement::Extend)
|
||||||
|
|
|
@ -86,6 +86,8 @@ pub fn default() -> HashMap<Mode, KeyTrie> {
|
||||||
"S" => split_selection,
|
"S" => split_selection,
|
||||||
";" => collapse_selection,
|
";" => collapse_selection,
|
||||||
"A-;" => flip_selections,
|
"A-;" => flip_selections,
|
||||||
|
"A-w" => redo_selection,
|
||||||
|
"A-k" => undo_selection,
|
||||||
"A-o" | "A-up" => expand_selection,
|
"A-o" | "A-up" => expand_selection,
|
||||||
"A-i" | "A-down" => shrink_selection,
|
"A-i" | "A-down" => shrink_selection,
|
||||||
"A-I" | "A-S-down" => select_all_children,
|
"A-I" | "A-S-down" => select_all_children,
|
||||||
|
|
|
@ -142,6 +142,7 @@ pub struct Document {
|
||||||
pub(crate) id: DocumentId,
|
pub(crate) id: DocumentId,
|
||||||
text: Rope,
|
text: Rope,
|
||||||
selections: HashMap<ViewId, Selection>,
|
selections: HashMap<ViewId, Selection>,
|
||||||
|
selections_history: HashMap<ViewId, SelectionHistory>,
|
||||||
view_data: HashMap<ViewId, ViewData>,
|
view_data: HashMap<ViewId, ViewData>,
|
||||||
pub active_snippet: Option<ActiveSnippet>,
|
pub active_snippet: Option<ActiveSnippet>,
|
||||||
|
|
||||||
|
@ -216,6 +217,33 @@ pub struct Document {
|
||||||
syn_loader: Arc<ArcSwap<syntax::Loader>>,
|
syn_loader: Arc<ArcSwap<syntax::Loader>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub enum SelectionDirection {
|
||||||
|
Undo(usize),
|
||||||
|
Redo(usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct SelectionHistory {
|
||||||
|
selections: Vec<Selection>,
|
||||||
|
current: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SelectionHistory {
|
||||||
|
pub fn goto(&mut self, direction: SelectionDirection) -> Option<&Selection> {
|
||||||
|
let mut position = match direction {
|
||||||
|
SelectionDirection::Undo(count) => self.current.checked_sub(count)?,
|
||||||
|
SelectionDirection::Redo(count) => self.current.checked_add(count)?,
|
||||||
|
};
|
||||||
|
let max = self.selections.len() - 1;
|
||||||
|
if position > max {
|
||||||
|
position = max
|
||||||
|
}
|
||||||
|
self.current = position;
|
||||||
|
self.selections.get(self.current)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct DocumentColorSwatches {
|
pub struct DocumentColorSwatches {
|
||||||
pub color_swatches: Vec<InlineAnnotation>,
|
pub color_swatches: Vec<InlineAnnotation>,
|
||||||
|
@ -300,6 +328,7 @@ impl fmt::Debug for Document {
|
||||||
.field("inlay_hints_oudated", &self.inlay_hints_oudated)
|
.field("inlay_hints_oudated", &self.inlay_hints_oudated)
|
||||||
.field("text_annotations", &self.inlay_hints)
|
.field("text_annotations", &self.inlay_hints)
|
||||||
.field("view_data", &self.view_data)
|
.field("view_data", &self.view_data)
|
||||||
|
.field("selections_history", &self.selections_history)
|
||||||
.field("path", &self.path)
|
.field("path", &self.path)
|
||||||
.field("encoding", &self.encoding)
|
.field("encoding", &self.encoding)
|
||||||
.field("restore_cursor", &self.restore_cursor)
|
.field("restore_cursor", &self.restore_cursor)
|
||||||
|
@ -700,6 +729,7 @@ impl Document {
|
||||||
has_bom,
|
has_bom,
|
||||||
text,
|
text,
|
||||||
selections: HashMap::default(),
|
selections: HashMap::default(),
|
||||||
|
selections_history: HashMap::default(),
|
||||||
inlay_hints: HashMap::default(),
|
inlay_hints: HashMap::default(),
|
||||||
inlay_hints_oudated: false,
|
inlay_hints_oudated: false,
|
||||||
view_data: Default::default(),
|
view_data: Default::default(),
|
||||||
|
@ -1320,17 +1350,43 @@ impl Document {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Select text within the [`Document`].
|
fn select(&mut self, view_id: ViewId, selection: Selection) {
|
||||||
pub fn set_selection(&mut self, view_id: ViewId, selection: Selection) {
|
|
||||||
// TODO: use a transaction?
|
// TODO: use a transaction?
|
||||||
self.selections
|
self.selections.insert(view_id, selection);
|
||||||
.insert(view_id, selection.ensure_invariants(self.text().slice(..)));
|
|
||||||
helix_event::dispatch(SelectionDidChange {
|
helix_event::dispatch(SelectionDidChange {
|
||||||
doc: self,
|
doc: self,
|
||||||
view: view_id,
|
view: view_id,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Select text within the [`Document`].
|
||||||
|
pub fn set_selection(&mut self, view_id: ViewId, selection: Selection) {
|
||||||
|
// TODO: use a transaction?
|
||||||
|
let selection = selection.ensure_invariants(self.text().slice(..));
|
||||||
|
self.save_selection_to_history(view_id, selection.clone());
|
||||||
|
self.select(view_id, selection);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn save_selection_to_history(&mut self, view_id: ViewId, selection: Selection) {
|
||||||
|
let entry = self
|
||||||
|
.selections_history
|
||||||
|
.entry(view_id)
|
||||||
|
.or_insert(SelectionHistory {
|
||||||
|
selections: vec![],
|
||||||
|
current: 0,
|
||||||
|
});
|
||||||
|
entry.selections.push(selection);
|
||||||
|
entry.current = entry.selections.len() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn select_history(&mut self, view_id: ViewId, direction: SelectionDirection) {
|
||||||
|
self.selections_history
|
||||||
|
.get_mut(&view_id)
|
||||||
|
.and_then(|history| history.goto(direction).cloned())
|
||||||
|
.into_iter()
|
||||||
|
.for_each(|selection| self.select(view_id, selection));
|
||||||
|
}
|
||||||
|
|
||||||
/// Find the origin selection of the text in a document, i.e. where
|
/// 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
|
/// a single cursor would go if it were on the first grapheme. If
|
||||||
/// the text is empty, returns (0, 0).
|
/// the text is empty, returns (0, 0).
|
||||||
|
@ -1367,6 +1423,7 @@ impl Document {
|
||||||
/// Remove a view's selection and inlay hints from this document.
|
/// Remove a view's selection and inlay hints from this document.
|
||||||
pub fn remove_view(&mut self, view_id: ViewId) {
|
pub fn remove_view(&mut self, view_id: ViewId) {
|
||||||
self.selections.remove(&view_id);
|
self.selections.remove(&view_id);
|
||||||
|
self.selections_history.remove(&view_id);
|
||||||
self.inlay_hints.remove(&view_id);
|
self.inlay_hints.remove(&view_id);
|
||||||
self.jump_labels.remove(&view_id);
|
self.jump_labels.remove(&view_id);
|
||||||
}
|
}
|
||||||
|
@ -1412,6 +1469,9 @@ impl Document {
|
||||||
.ensure_invariants(self.text.slice(..));
|
.ensure_invariants(self.text.slice(..));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset the selection history after any change
|
||||||
|
self.selections_history.clear();
|
||||||
|
|
||||||
for view_data in self.view_data.values_mut() {
|
for view_data in self.view_data.values_mut() {
|
||||||
view_data.view_position.anchor = transaction
|
view_data.view_position.anchor = transaction
|
||||||
.changes()
|
.changes()
|
||||||
|
|
Loading…
Reference in New Issue