@@ -15,7 +15,7 @@ use crate::ui::{self, Prompt, PromptEvent};
15use helix_view::{
15use helix_view::{
16 document::Mode,
16 document::Mode,
17 view::{View, PADDING},
17 view::{View, PADDING},
18− Editor,
18+ Document, Editor,
21pub struct Context<'a> {
21pub struct Context<'a> {
@@ -27,9 +27,15 @@ pub struct Context<'a> {
29impl<'a> Context<'a> {
29impl<'a> Context<'a> {
30 pub fn view(&mut self) -> &mut View {
31 pub fn view(&mut self) -> &mut View {
31 self.editor.view_mut()
32 self.editor.view_mut()
36+ pub fn doc(&mut self) -> &mut Document {
37+ &mut self.editor.view_mut().doc
35/// A command is a function that takes the current state and a count, and does a side-effect on the
41/// A command is a function that takes the current state and a count, and does a side-effect on the
@@ -39,45 +45,41 @@ pub type Command = fn(cx: &mut Context);
39pub fn move_char_left(cx: &mut Context) {
45pub fn move_char_left(cx: &mut Context) {
40 let count = cx.count;
46 let count = cx.count;
41 let selection =
47 let selection =
42− cx.view()
48+ cx.doc()
45 .move_selection(Direction::Backward, Granularity::Character, count);
50 .move_selection(Direction::Backward, Granularity::Character, count);
46− cx.view().doc.set_selection(selection);
51+ cx.doc().set_selection(selection);
49pub fn move_char_right(cx: &mut Context) {
54pub fn move_char_right(cx: &mut Context) {
50 let count = cx.count;
55 let count = cx.count;
51 let selection =
56 let selection =
52− cx.view()
57+ cx.doc()
55 .move_selection(Direction::Forward, Granularity::Character, count);
59 .move_selection(Direction::Forward, Granularity::Character, count);
56− cx.view().doc.set_selection(selection);
60+ cx.doc().set_selection(selection);
59pub fn move_line_up(cx: &mut Context) {
63pub fn move_line_up(cx: &mut Context) {
60 let count = cx.count;
64 let count = cx.count;
61− let selection =
65+ let selection = cx
65− .move_selection(Direction::Backward, Granularity::Line, count);
68+ .move_selection(Direction::Backward, Granularity::Line, count);
66− cx.view().doc.set_selection(selection);
69+ cx.doc().set_selection(selection);
69pub fn move_line_down(cx: &mut Context) {
72pub fn move_line_down(cx: &mut Context) {
70 let count = cx.count;
73 let count = cx.count;
71− let selection =
74+ let selection = cx
75− .move_selection(Direction::Forward, Granularity::Line, count);
77+ .move_selection(Direction::Forward, Granularity::Line, count);
76− cx.view().doc.set_selection(selection);
78+ cx.doc().set_selection(selection);
79pub fn move_line_end(cx: &mut Context) {
81pub fn move_line_end(cx: &mut Context) {
80− let lines = selection_lines(&cx.view().doc.state);
82+ let lines = selection_lines(&cx.doc().state);
82 let positions = lines
84 let positions = lines
83 .into_iter()
85 .into_iter()
@@ -86,90 +88,83 @@ pub fn move_line_end(cx: &mut Context) {
87 // Line end is pos at the start of next line - 1
89 // Line end is pos at the start of next line - 1
88 // subtract another 1 because the line ends with \n
90 // subtract another 1 because the line ends with \n
92− .line_to_char(index + 1)
91+ cx.doc().text().line_to_char(index + 1).saturating_sub(2)
95 .map(|pos| Range::new(pos, pos));
93 .map(|pos| Range::new(pos, pos));
97 let selection = Selection::new(positions.collect(), 0);
95 let selection = Selection::new(positions.collect(), 0);
99− cx.view().doc.set_selection(selection);
97+ cx.doc().set_selection(selection);
102pub fn move_line_start(cx: &mut Context) {
100pub fn move_line_start(cx: &mut Context) {
103− let lines = selection_lines(&cx.view().doc.state);
101+ let lines = selection_lines(&cx.doc().state);
105 let positions = lines
103 let positions = lines
106 .into_iter()
104 .into_iter()
107 .map(|index| {
105 .map(|index| {
108 // adjust all positions to the start of the line.
106 // adjust all positions to the start of the line.
109− cx.view().doc.text().line_to_char(index)
107+ cx.doc().text().line_to_char(index)
111 .map(|pos| Range::new(pos, pos));
109 .map(|pos| Range::new(pos, pos));
113 let selection = Selection::new(positions.collect(), 0);
111 let selection = Selection::new(positions.collect(), 0);
115− cx.view().doc.set_selection(selection);
113+ cx.doc().set_selection(selection);
118pub fn move_next_word_start(cx: &mut Context) {
116pub fn move_next_word_start(cx: &mut Context) {
119 let count = cx.count;
117 let count = cx.count;
120− let view = cx.view();
118+ let doc = cx.doc();
121− let pos = view.doc.state.move_pos(
119+ let pos = doc.state.move_pos(
122− view.doc.selection().cursor(),
120+ doc.selection().cursor(),
123 Direction::Forward,
121 Direction::Forward,
124 Granularity::Word,
122 Granularity::Word,
128− view.doc.set_selection(Selection::point(pos));
126+ doc.set_selection(Selection::point(pos));
131pub fn move_prev_word_start(cx: &mut Context) {
129pub fn move_prev_word_start(cx: &mut Context) {
132 let count = cx.count;
130 let count = cx.count;
133− let view = cx.view();
131+ let doc = cx.doc();
134− let pos = view.doc.state.move_pos(
132+ let pos = doc.state.move_pos(
135− view.doc.selection().cursor(),
133+ doc.selection().cursor(),
136 Direction::Backward,
134 Direction::Backward,
137 Granularity::Word,
135 Granularity::Word,
141− view.doc.set_selection(Selection::point(pos));
139+ doc.set_selection(Selection::point(pos));
144pub fn move_next_word_end(cx: &mut Context) {
142pub fn move_next_word_end(cx: &mut Context) {
145 let count = cx.count;
143 let count = cx.count;
146− let view = cx.view();
144+ let doc = cx.doc();
147− let pos = State::move_next_word_end(
145+ let pos = State::move_next_word_end(&doc.text().slice(..), doc.selection().cursor(), count);
148− &view.doc.text().slice(..),
149− view.doc.selection().cursor(),
153− view.doc.set_selection(Selection::point(pos));
147+ doc.set_selection(Selection::point(pos));
156pub fn move_file_start(cx: &mut Context) {
150pub fn move_file_start(cx: &mut Context) {
157− cx.view().doc.set_selection(Selection::point(0));
151+ cx.doc().set_selection(Selection::point(0));
159− cx.view().doc.mode = Mode::Normal;
153+ cx.doc().mode = Mode::Normal;
162pub fn move_file_end(cx: &mut Context) {
156pub fn move_file_end(cx: &mut Context) {
163− let text = &cx.view().doc.text();
157+ let text = &cx.doc().text();
164 let last_line = text.line_to_char(text.len_lines().saturating_sub(2));
158 let last_line = text.line_to_char(text.len_lines().saturating_sub(2));
165− cx.view().doc.set_selection(Selection::point(last_line));
159+ cx.doc().set_selection(Selection::point(last_line));
167− cx.view().doc.mode = Mode::Normal;
161+ cx.doc().mode = Mode::Normal;
170pub fn check_cursor_in_view(view: &View) -> bool {
164pub fn check_cursor_in_view(view: &View) -> bool {
165+ let doc = &view.doc;
171− let cursor = view.doc.selection().cursor();
166+ let cursor = doc.selection().cursor();
172− let line = view.doc.text().char_to_line(cursor);
167+ let line = doc.text().char_to_line(cursor);
173 let document_end = view.first_line + view.size.1.saturating_sub(1) as usize;
168 let document_end = view.first_line + view.size.1.saturating_sub(1) as usize;
175 if (line > document_end.saturating_sub(PADDING)) | (line < view.first_line + PADDING) {
170 if (line > document_end.saturating_sub(PADDING)) | (line < view.first_line + PADDING) {
@@ -235,42 +230,38 @@ pub fn half_page_down(cx: &mut Context) {
236pub fn extend_char_left(cx: &mut Context) {
231pub fn extend_char_left(cx: &mut Context) {
237 let count = cx.count;
232 let count = cx.count;
238− let view = cx.view();
233+ let doc = cx.doc();
239− let selection =
234+ let selection = doc
242− .extend_selection(Direction::Backward, Granularity::Character, count);
236+ .extend_selection(Direction::Backward, Granularity::Character, count);
243− view.doc.set_selection(selection);
237+ doc.set_selection(selection);
246pub fn extend_char_right(cx: &mut Context) {
240pub fn extend_char_right(cx: &mut Context) {
247 let count = cx.count;
241 let count = cx.count;
248− let view = cx.view();
242+ let doc = cx.doc();
249− let selection =
243+ let selection = doc
252− .extend_selection(Direction::Forward, Granularity::Character, count);
245+ .extend_selection(Direction::Forward, Granularity::Character, count);
253− view.doc.set_selection(selection);
246+ doc.set_selection(selection);
256pub fn extend_line_up(cx: &mut Context) {
249pub fn extend_line_up(cx: &mut Context) {
257 let count = cx.count;
250 let count = cx.count;
258− let view = cx.view();
251+ let doc = cx.doc();
259− let selection = view
252+ let selection = doc
262 .extend_selection(Direction::Backward, Granularity::Line, count);
254 .extend_selection(Direction::Backward, Granularity::Line, count);
263− view.doc.set_selection(selection);
255+ doc.set_selection(selection);
266pub fn extend_line_down(cx: &mut Context) {
258pub fn extend_line_down(cx: &mut Context) {
267 let count = cx.count;
259 let count = cx.count;
268− let view = cx.view();
260+ let doc = cx.doc();
269− let selection = view
261+ let selection = doc
272 .extend_selection(Direction::Forward, Granularity::Line, count);
263 .extend_selection(Direction::Forward, Granularity::Line, count);
273− view.doc.set_selection(selection);
264+ doc.set_selection(selection);
276pub fn split_selection(cx: &mut Context) {
267pub fn split_selection(cx: &mut Context) {
@@ -287,7 +278,7 @@ pub fn split_selection(cx: &mut Context) {
287 // # update state
278 // # update state
290− let snapshot = cx.view().doc.state.clone();
281+ let snapshot = cx.doc().state.clone();
292 let prompt = Prompt::new(
283 let prompt = Prompt::new(
293 "split:".to_string(),
284 "split:".to_string(),
@@ -296,8 +287,8 @@ pub fn split_selection(cx: &mut Context) {
296 match event {
287 match event {
297 PromptEvent::Abort => {
288 PromptEvent::Abort => {
298 // revert state
289 // revert state
299− let view = editor.view_mut();
290+ let doc = &mut editor.view_mut().doc;
300− view.doc.state = snapshot.clone();
291+ doc.state = snapshot.clone();
302 PromptEvent::Validate => {
293 PromptEvent::Validate => {
@@ -305,15 +296,15 @@ pub fn split_selection(cx: &mut Context) {
305 PromptEvent::Update => {
296 PromptEvent::Update => {
306 match Regex::new(input) {
297 match Regex::new(input) {
307 Ok(regex) => {
298 Ok(regex) => {
308− let view = editor.view_mut();
299+ let doc = &mut editor.view_mut().doc;
310 // revert state to what it was before the last update
301 // revert state to what it was before the last update
311− view.doc.state = snapshot.clone();
302+ doc.state = snapshot.clone();
313− let text = &view.doc.text().slice(..);
304+ let text = &doc.text().slice(..);
314 let selection =
305 let selection =
315− selection::split_on_matches(text, view.doc.selection(), ®ex);
306+ selection::split_on_matches(text, doc.selection(), ®ex);
316− view.doc.set_selection(selection);
307+ doc.set_selection(selection);
318 Err(_err) => (), // TODO: mark command line as error
309 Err(_err) => (), // TODO: mark command line as error
@@ -330,33 +321,33 @@ pub fn split_selection(cx: &mut Context) {
332pub fn split_selection_on_newline(cx: &mut Context) {
323pub fn split_selection_on_newline(cx: &mut Context) {
333− let view = cx.view();
324+ let doc = cx.doc();
334− let text = &view.doc.text().slice(..);
325+ let text = &doc.text().slice(..);
335 // only compile the regex once
326 // only compile the regex once
336 #[allow(clippy::trivial_regex)]
327 #[allow(clippy::trivial_regex)]
337 static REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"\n").unwrap());
328 static REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"\n").unwrap());
338− let selection = selection::split_on_matches(text, view.doc.selection(), ®EX);
329+ let selection = selection::split_on_matches(text, doc.selection(), ®EX);
339− view.doc.set_selection(selection);
330+ doc.set_selection(selection);
342pub fn select_line(cx: &mut Context) {
333pub fn select_line(cx: &mut Context) {
343 // TODO: count
334 // TODO: count
344− let pos = cx.view().doc.selection().primary();
335+ let pos = cx.doc().selection().primary();
345− let text = cx.view().doc.text();
336+ let text = cx.doc().text();
346 let line = text.char_to_line(pos.head);
337 let line = text.char_to_line(pos.head);
347 let start = text.line_to_char(line);
338 let start = text.line_to_char(line);
348 let end = text.line_to_char(line + 1).saturating_sub(1);
339 let end = text.line_to_char(line + 1).saturating_sub(1);
350− cx.view().doc.set_selection(Selection::single(start, end));
341+ cx.doc().set_selection(Selection::single(start, end));
353// heuristic: append changes to history after each command, unless we're in insert mode
344// heuristic: append changes to history after each command, unless we're in insert mode
355fn _delete_selection(cx: &mut Context) {
346fn _delete_selection(cx: &mut Context) {
356− let transaction = Transaction::change_by_selection(&cx.view().doc.state, |range| {
347+ let transaction = Transaction::change_by_selection(&cx.doc().state, |range| {
357 (range.from(), range.to() + 1, None)
348 (range.from(), range.to() + 1, None)
359− cx.view().doc.apply(&transaction);
350+ cx.doc().apply(&transaction);
362pub fn delete_selection(cx: &mut Context) {
353pub fn delete_selection(cx: &mut Context) {
@@ -377,7 +368,7 @@ pub fn collapse_selection(cx: &mut Context) {
377 .selection()
368 .selection()
378 .transform(|range| Range::new(range.head, range.head));
369 .transform(|range| Range::new(range.head, range.head));
380− cx.view().doc.set_selection(selection);
371+ cx.doc().set_selection(selection);
383pub fn flip_selections(cx: &mut Context) {
374pub fn flip_selections(cx: &mut Context) {
@@ -387,11 +378,11 @@ pub fn flip_selections(cx: &mut Context) {
387 .selection()
378 .selection()
388 .transform(|range| Range::new(range.head, range.anchor));
379 .transform(|range| Range::new(range.head, range.anchor));
390− cx.view().doc.set_selection(selection);
381+ cx.doc().set_selection(selection);
393fn enter_insert_mode(cx: &mut Context) {
384fn enter_insert_mode(cx: &mut Context) {
394− cx.view().doc.mode = Mode::Insert;
385+ cx.doc().mode = Mode::Insert;
396 // TODO: store selection for undo
387 // TODO: store selection for undo
@@ -405,25 +396,25 @@ pub fn insert_mode(cx: &mut Context) {
406 .selection()
397 .selection()
407 .transform(|range| Range::new(range.to(), range.from()));
398 .transform(|range| Range::new(range.to(), range.from()));
408− cx.view().doc.set_selection(selection);
399+ cx.doc().set_selection(selection);
411// inserts at the end of each selection
402// inserts at the end of each selection
412pub fn append_mode(cx: &mut Context) {
403pub fn append_mode(cx: &mut Context) {
413 enter_insert_mode(cx);
404 enter_insert_mode(cx);
414− let view = cx.view();
405+ let doc = cx.doc();
415− view.doc.restore_cursor = true;
406+ doc.restore_cursor = true;
417 // TODO: as transaction
408 // TODO: as transaction
418− let text = &view.doc.text().slice(..);
409+ let text = &doc.text().slice(..);
419− let selection = view.doc.selection().transform(|range| {
410+ let selection = doc.selection().transform(|range| {
420 // TODO: to() + next char
411 // TODO: to() + next char
421 Range::new(
412 Range::new(
422 range.from(),
413 range.from(),
423 graphemes::next_grapheme_boundary(text, range.to()),
414 graphemes::next_grapheme_boundary(text, range.to()),
426− view.doc.set_selection(selection);
417+ doc.set_selection(selection);
429// TODO: I, A, o and O can share a lot of the primitives.
420// TODO: I, A, o and O can share a lot of the primitives.
@@ -545,23 +536,23 @@ pub fn append_to_line(cx: &mut Context) {
545pub fn open_below(cx: &mut Context) {
536pub fn open_below(cx: &mut Context) {
546 enter_insert_mode(cx);
537 enter_insert_mode(cx);
548− let view = cx.view();
539+ let doc = cx.doc();
550− let lines = selection_lines(&view.doc.state);
541+ let lines = selection_lines(&doc.state);
552 let positions: Vec<_> = lines
543 let positions: Vec<_> = lines
553 .into_iter()
544 .into_iter()
554 .map(|index| {
545 .map(|index| {
555 // adjust all positions to the end of the line/start of the next one.
546 // adjust all positions to the end of the line/start of the next one.
556− view.doc.text().line_to_char(index + 1)
547+ doc.text().line_to_char(index + 1)
558 .collect();
549 .collect();
560 let changes = positions.iter().copied().map(|index| {
551 let changes = positions.iter().copied().map(|index| {
561 // TODO: share logic with insert_newline for indentation
552 // TODO: share logic with insert_newline for indentation
562 let indent_level = helix_core::indent::suggested_indent_for_pos(
553 let indent_level = helix_core::indent::suggested_indent_for_pos(
563− view.doc.syntax.as_ref(),
554+ doc.syntax.as_ref(),
564− &view.doc.state,
555+ &doc.state,
@@ -595,29 +586,29 @@ pub fn open_below(cx: &mut Context) {
598− let transaction = Transaction::change(&view.doc.state, changes).with_selection(selection);
589+ let transaction = Transaction::change(&doc.state, changes).with_selection(selection);
600− view.doc.apply(&transaction);
591+ doc.apply(&transaction);
603// O inserts a new line before each line with a selection
594// O inserts a new line before each line with a selection
605fn append_changes_to_history(cx: &mut Context) {
596fn append_changes_to_history(cx: &mut Context) {
606− if cx.view().doc.changes.is_empty() {
597+ if cx.doc().changes.is_empty() {
610 // TODO: change -> change -> undo -> change -> change fails, probably old_state needs reset
601 // TODO: change -> change -> undo -> change -> change fails, probably old_state needs reset
612− let new_changeset = ChangeSet::new(cx.view().doc.text());
603+ let new_changeset = ChangeSet::new(cx.doc().text());
613− let changes = std::mem::replace(&mut cx.view().doc.changes, new_changeset);
604+ let changes = std::mem::replace(&mut cx.doc().changes, new_changeset);
614 // Instead of doing this messy merge we could always commit, and based on transaction
605 // Instead of doing this messy merge we could always commit, and based on transaction
615 // annotations either add a new layer or compose into the previous one.
606 // annotations either add a new layer or compose into the previous one.
616− let transaction = Transaction::from(changes).with_selection(cx.view().doc.selection().clone());
607+ let transaction = Transaction::from(changes).with_selection(cx.doc().selection().clone());
618 // increment document version
609 // increment document version
619 // TODO: needs to happen on undo/redo too
610 // TODO: needs to happen on undo/redo too
620− cx.view().doc.version += 1;
611+ cx.doc().version += 1;
622 // TODO: trigger lsp/documentDidChange with changes
613 // TODO: trigger lsp/documentDidChange with changes
@@ -630,38 +621,35 @@ fn append_changes_to_history(cx: &mut Context) {
630 .expect("no old_state available");
621 .expect("no old_state available");
632 // TODO: take transaction by value?
623 // TODO: take transaction by value?
636− .commit_revision(&transaction, &old_state);
624+ cx.doc().history.commit_revision(&transaction, &old_state);
638 // TODO: notify LSP of changes
626 // TODO: notify LSP of changes
641pub fn normal_mode(cx: &mut Context) {
629pub fn normal_mode(cx: &mut Context) {
642− cx.view().doc.mode = Mode::Normal;
630+ cx.doc().mode = Mode::Normal;
644 append_changes_to_history(cx);
632 append_changes_to_history(cx);
646− let view = cx.view();
634+ let doc = cx.doc();
648 // if leaving append mode, move cursor back by 1
636 // if leaving append mode, move cursor back by 1
649− if view.doc.restore_cursor {
637+ if doc.restore_cursor {
650− let text = &view.doc.text().slice(..);
638+ let text = &doc.text().slice(..);
651− let selection = view.doc.selection().transform(|range| {
639+ let selection = doc.selection().transform(|range| {
652 Range::new(
640 Range::new(
653 range.from(),
641 range.from(),
654 graphemes::prev_grapheme_boundary(text, range.to()),
642 graphemes::prev_grapheme_boundary(text, range.to()),
657− view.doc.set_selection(selection);
645+ doc.set_selection(selection);
659− view.doc.restore_cursor = false;
647+ doc.restore_cursor = false;
663pub fn goto_mode(cx: &mut Context) {
651pub fn goto_mode(cx: &mut Context) {
664− cx.view().doc.mode = Mode::Goto;
652+ cx.doc().mode = Mode::Goto;
667// NOTE: Transactions in this module get appended to history when we switch back to normal mode.
655// NOTE: Transactions in this module get appended to history when we switch back to normal mode.
@@ -670,9 +658,9 @@ pub mod insert {
670 // TODO: insert means add text just before cursor, on exit we should be on the last letter.
658 // TODO: insert means add text just before cursor, on exit we should be on the last letter.
671 pub fn insert_char(cx: &mut Context, c: char) {
659 pub fn insert_char(cx: &mut Context, c: char) {
672 let c = Tendril::from_char(c);
660 let c = Tendril::from_char(c);
673− let transaction = Transaction::insert(&cx.view().doc.state, c);
661+ let transaction = Transaction::insert(&cx.doc().state, c);
675− cx.view().doc.apply(&transaction);
663+ cx.doc().apply(&transaction);
678 pub fn insert_tab(cx: &mut Context) {
666 pub fn insert_tab(cx: &mut Context) {
@@ -680,11 +668,11 @@ pub mod insert {
682 pub fn insert_newline(cx: &mut Context) {
670 pub fn insert_newline(cx: &mut Context) {
683− let view = cx.view();
671+ let doc = cx.doc();
684− let transaction = Transaction::change_by_selection(&view.doc.state, |range| {
672+ let transaction = Transaction::change_by_selection(&doc.state, |range| {
685 let indent_level = helix_core::indent::suggested_indent_for_pos(
673 let indent_level = helix_core::indent::suggested_indent_for_pos(
686− view.doc.syntax.as_ref(),
674+ doc.syntax.as_ref(),
687− &view.doc.state,
675+ &doc.state,
688 range.head,
676 range.head,
@@ -694,36 +682,36 @@ pub mod insert {
694 text.push_str(&indent);
682 text.push_str(&indent);
695 (range.head, range.head, Some(text.into()))
683 (range.head, range.head, Some(text.into()))
697− view.doc.apply(&transaction);
685+ doc.apply(&transaction);
700 // TODO: handle indent-aware delete
688 // TODO: handle indent-aware delete
701 pub fn delete_char_backward(cx: &mut Context) {
689 pub fn delete_char_backward(cx: &mut Context) {
702 let count = cx.count;
690 let count = cx.count;
703− let view = cx.view();
691+ let doc = cx.doc();
704− let text = &view.doc.text().slice(..);
692+ let text = &doc.text().slice(..);
705− let transaction = Transaction::change_by_selection(&view.doc.state, |range| {
693+ let transaction = Transaction::change_by_selection(&doc.state, |range| {
707 graphemes::nth_prev_grapheme_boundary(text, range.head, count),
695 graphemes::nth_prev_grapheme_boundary(text, range.head, count),
708 range.head,
696 range.head,
712− view.doc.apply(&transaction);
700+ doc.apply(&transaction);
715 pub fn delete_char_forward(cx: &mut Context) {
703 pub fn delete_char_forward(cx: &mut Context) {
716 let count = cx.count;
704 let count = cx.count;
717− let view = cx.view();
705+ let doc = cx.doc();
718− let text = &view.doc.text().slice(..);
706+ let text = &doc.text().slice(..);
719− let transaction = Transaction::change_by_selection(&view.doc.state, |range| {
707+ let transaction = Transaction::change_by_selection(&doc.state, |range| {
721 range.head,
709 range.head,
722 graphemes::nth_next_grapheme_boundary(text, range.head, count),
710 graphemes::nth_next_grapheme_boundary(text, range.head, count),
726− view.doc.apply(&transaction);
714+ doc.apply(&transaction);
@@ -737,23 +725,22 @@ pub fn insert_char_prompt(prompt: &mut Prompt, c: char) {
737// storing it?
725// storing it?
739pub fn undo(cx: &mut Context) {
727pub fn undo(cx: &mut Context) {
740− cx.view().doc.undo();
728+ cx.doc().undo();
743pub fn redo(cx: &mut Context) {
731pub fn redo(cx: &mut Context) {
744− cx.view().doc.redo();
732+ cx.doc().redo();
747// Yank / Paste
735// Yank / Paste
749pub fn yank(cx: &mut Context) {
737pub fn yank(cx: &mut Context) {
750 // TODO: should selections be made end inclusive?
738 // TODO: should selections be made end inclusive?
751− let view = cx.view();
739+ let doc = cx.doc();
752− let values = view
740+ let values = doc
755 .selection()
742 .selection()
756− .fragments(&view.doc.text().slice(..))
743+ .fragments(&doc.text().slice(..))
757 .map(|cow| cow.into_owned())
744 .map(|cow| cow.into_owned())
758 .collect();
745 .collect();
@@ -791,34 +778,34 @@ pub fn paste(cx: &mut Context) {
792 let mut values = values.into_iter().map(Tendril::from).chain(repeat);
779 let mut values = values.into_iter().map(Tendril::from).chain(repeat);
794− let view = cx.view();
781+ let doc = cx.doc();
796 let transaction = if linewise {
783 let transaction = if linewise {
797 // paste on the next line
784 // paste on the next line
798 // TODO: can simply take a range + modifier and compute the right pos without ifs
785 // TODO: can simply take a range + modifier and compute the right pos without ifs
799− let text = view.doc.text();
786+ let text = doc.text();
800− Transaction::change_by_selection(&view.doc.state, |range| {
787+ Transaction::change_by_selection(&doc.state, |range| {
801 let line_end = text.line_to_char(text.char_to_line(range.head) + 1);
788 let line_end = text.line_to_char(text.char_to_line(range.head) + 1);
802 (line_end, line_end, Some(values.next().unwrap()))
789 (line_end, line_end, Some(values.next().unwrap()))
805− Transaction::change_by_selection(&view.doc.state, |range| {
792+ Transaction::change_by_selection(&doc.state, |range| {
806 (range.head + 1, range.head + 1, Some(values.next().unwrap()))
793 (range.head + 1, range.head + 1, Some(values.next().unwrap()))
810− view.doc.apply(&transaction);
797+ doc.apply(&transaction);
811 append_changes_to_history(cx);
798 append_changes_to_history(cx);
815−fn get_lines(view: &View) -> Vec<usize> {
802+fn get_lines(doc: &Document) -> Vec<usize> {
816 let mut lines = Vec::new();
803 let mut lines = Vec::new();
818 // Get all line numbers
805 // Get all line numbers
819− for range in view.doc.selection().ranges() {
806+ for range in doc.selection().ranges() {
820− let start = view.doc.text().char_to_line(range.from());
807+ let start = doc.text().char_to_line(range.from());
821− let end = view.doc.text().char_to_line(range.to());
808+ let end = doc.text().char_to_line(range.to());
823 for line in start..=end {
810 for line in start..=end {
824 lines.push(line)
811 lines.push(line)
@@ -830,30 +817,30 @@ fn get_lines(view: &View) -> Vec<usize> {
832pub fn indent(cx: &mut Context) {
819pub fn indent(cx: &mut Context) {
833− let lines = get_lines(cx.view());
821+ let lines = get_lines(doc);
835 // Indent by one level
823 // Indent by one level
836 let indent = Tendril::from(" ".repeat(TAB_WIDTH));
824 let indent = Tendril::from(" ".repeat(TAB_WIDTH));
838− let view = cx.view();
840 let transaction = Transaction::change(
826 let transaction = Transaction::change(
841− &view.doc.state,
827+ &doc.state,
842 lines.into_iter().map(|line| {
828 lines.into_iter().map(|line| {
843− let pos = view.doc.text().line_to_char(line);
829+ let pos = doc.text().line_to_char(line);
844 (pos, pos, Some(indent.clone()))
830 (pos, pos, Some(indent.clone()))
847− cx.view().doc.apply(&transaction);
833+ cx.doc().apply(&transaction);
848 append_changes_to_history(cx);
834 append_changes_to_history(cx);
851pub fn unindent(cx: &mut Context) {
837pub fn unindent(cx: &mut Context) {
852− let lines = get_lines(cx.view());
839+ let lines = get_lines(doc);
853 let mut changes = Vec::with_capacity(lines.len());
840 let mut changes = Vec::with_capacity(lines.len());
855 for line_idx in lines {
842 for line_idx in lines {
856− let line = cx.view().doc.text().line(line_idx);
843+ let line = doc.text().line(line_idx);
857 let mut width = 0;
844 let mut width = 0;
859 for ch in line.chars() {
846 for ch in line.chars() {
@@ -869,14 +856,14 @@ pub fn unindent(cx: &mut Context) {
871 if width > 0 {
858 if width > 0 {
872− let start = cx.view().doc.text().line_to_char(line_idx);
859+ let start = doc.text().line_to_char(line_idx);
873 changes.push((start, start + width, None))
860 changes.push((start, start + width, None))
877− let transaction = Transaction::change(&cx.view().doc.state, changes.into_iter());
864+ let transaction = Transaction::change(&doc.state, changes.into_iter());
879− cx.view().doc.apply(&transaction);
866+ doc.apply(&transaction);
880 append_changes_to_history(cx);
867 append_changes_to_history(cx);
@@ -891,7 +878,7 @@ pub fn save(cx: &mut Context) {
891 // Spawns an async task to actually do the saving. This way we prevent blocking.
878 // Spawns an async task to actually do the saving. This way we prevent blocking.
893 // TODO: handle save errors somehow?
880 // TODO: handle save errors somehow?
894− cx.executor.spawn(cx.view().doc.save()).detach();
881+ cx.executor.spawn(cx.doc().save()).detach();
897pub fn completion(cx: &mut Context) {
884pub fn completion(cx: &mut Context) {
@@ -902,15 +889,14 @@ pub fn completion(cx: &mut Context) {
902 .unwrap();
889 .unwrap();
903 use log::info;
890 use log::info;
905− let view = cx.view();
892+ let doc = cx.doc();
907 // TODO: blocking here is not ideal
894 // TODO: blocking here is not ideal
909− helix_lsp::util::pos_to_lsp_pos(&view.doc.text().slice(..), view.doc.selection().cursor());
895+ let pos = helix_lsp::util::pos_to_lsp_pos(&doc.text().slice(..), doc.selection().cursor());
911 // TODO: handle fails
897 // TODO: handle fails
912− let res = smol::block_on(language_server.completion(cx.view().doc.identifier(), pos))
899+ smol::block_on(language_server.completion(cx.doc().identifier(), pos)).unwrap_or_default();
913− .unwrap_or_default();
915 // TODO: if no completion, show some message or something
901 // TODO: if no completion, show some message or something
916 if !res.is_empty() {
902 if !res.is_empty() {
@@ -946,10 +932,9 @@ pub fn completion(cx: &mut Context) {
949− let view = editor.view_mut();
935+ let doc = &mut editor.view_mut().doc;
951− util::generate_transaction_from_edits(&view.doc.state, vec![edit]);
936+ let transaction = util::generate_transaction_from_edits(&doc.state, vec![edit]);
952− view.doc.apply(&transaction);
937+ doc.apply(&transaction);
953 // TODO: append_changes_to_history(cx); if not in insert mode?
938 // TODO: append_changes_to_history(cx); if not in insert mode?