on master help sign in
Weave through view_id references so that views into one file have independent selects.
commit6c4093c94634a94adbccb4783cddb90076881c02 authorBlaž Hrastnik <blaz@mxxn.io> dateWed 31 Mar 2021, 17:17 (6 years ago) parent9eaef6e
7 files changed+345−208
helix-term/src/commands.rs+247−165 helix-term/src/ui/completion.rs+26−6 helix-term/src/ui/editor.rs+8−4 helix-term/src/ui/mod.rs+11−6 helix-view/src/document.rs+29−22 helix-view/src/editor.rs+23−4 helix-view/src/view.rs+1−1
helix-term/src/commands.rs+247−165
@@ -19,7 +19,7 @@ use std::path::{Path, PathBuf};
1919use helix_view::{
2020 document::Mode,
2121 view::{View, PADDING},
22− Document, DocumentId, Editor,
22+ Document, DocumentId, Editor, ViewId,
2323};
2424
2525use crossterm::event::{KeyCode, KeyEvent};
@@ -31,6 +31,7 @@ use crate::application::{LspCallbackWrapper, LspCallbacks};
3131pub struct Context<'a> {
3232 pub count: usize,
3333 pub editor: &'a mut Editor,
34+ pub view_id: ViewId,
3435
3536 pub callback: Option<crate::compositor::Callback>,
3637 pub on_next_key_callback: Option<Box<dyn FnOnce(&mut Context, KeyEvent)>>,
@@ -101,9 +102,10 @@ pub type Command = fn(cx: &mut Context);
101102
102103pub fn move_char_left(cx: &mut Context) {
103104 let count = cx.count;
105+ let view_id = cx.view_id;
104106 let doc = cx.doc();
105107 let text = doc.text().slice(..);
106− let selection = doc.selection().transform(|range| {
108+ let selection = doc.selection(view_id).transform(|range| {
107109 movement::move_horizontally(
108110 text,
109111 range,
@@ -112,14 +114,15 @@ pub fn move_char_left(cx: &mut Context) {
112114 false, /* extend */
113115 )
114116 });
115− doc.set_selection(selection);
117+ doc.set_selection(view_id, selection);
116118}
117119
118120pub fn move_char_right(cx: &mut Context) {
119121 let count = cx.count;
122+ let view_id = cx.view_id;
120123 let doc = cx.doc();
121124 let text = doc.text().slice(..);
122− let selection = doc.selection().transform(|range| {
125+ let selection = doc.selection(view_id).transform(|range| {
123126 movement::move_horizontally(
124127 text,
125128 range,
@@ -128,14 +131,15 @@ pub fn move_char_right(cx: &mut Context) {
128131 false, /* extend */
129132 )
130133 });
131− doc.set_selection(selection);
134+ doc.set_selection(view_id, selection);
132135}
133136
134137pub fn move_line_up(cx: &mut Context) {
135138 let count = cx.count;
139+ let view_id = cx.view_id;
136140 let doc = cx.doc();
137141 let text = doc.text().slice(..);
138− let selection = doc.selection().transform(|range| {
142+ let selection = doc.selection(view_id).transform(|range| {
139143 movement::move_vertically(
140144 text,
141145 range,
@@ -144,14 +148,15 @@ pub fn move_line_up(cx: &mut Context) {
144148 false, /* extend */
145149 )
146150 });
147− doc.set_selection(selection);
151+ doc.set_selection(view_id, selection);
148152}
149153
150154pub fn move_line_down(cx: &mut Context) {
151155 let count = cx.count;
156+ let view_id = cx.view_id;
152157 let doc = cx.doc();
153158 let text = doc.text().slice(..);
154− let selection = doc.selection().transform(|range| {
159+ let selection = doc.selection(view_id).transform(|range| {
155160 movement::move_vertically(
156161 text,
157162 range,
@@ -160,12 +165,13 @@ pub fn move_line_down(cx: &mut Context) {
160165 false, /* extend */
161166 )
162167 });
163− doc.set_selection(selection);
168+ doc.set_selection(view_id, selection);
164169}
165170
166171pub fn move_line_end(cx: &mut Context) {
172+ let view_id = cx.view_id;
167173 let doc = cx.doc();
168− let lines = selection_lines(doc.text(), doc.selection());
174+ let lines = selection_lines(doc.text(), doc.selection(view_id));
169175
170176 let positions = lines
171177 .into_iter()
@@ -180,12 +186,13 @@ pub fn move_line_end(cx: &mut Context) {
180186
181187 let selection = Selection::new(positions.collect(), 0);
182188
183− doc.set_selection(selection);
189+ doc.set_selection(view_id, selection);
184190}
185191
186192pub fn move_line_start(cx: &mut Context) {
193+ let view_id = cx.view_id;
187194 let doc = cx.doc();
188− let lines = selection_lines(doc.text(), doc.selection());
195+ let lines = selection_lines(doc.text(), doc.selection(view_id));
189196
190197 let positions = lines
191198 .into_iter()
@@ -197,7 +204,7 @@ pub fn move_line_start(cx: &mut Context) {
197204
198205 let selection = Selection::new(positions.collect(), 0);
199206
200− doc.set_selection(selection);
207+ doc.set_selection(view_id, selection);
201208}
202209
203210// TODO: move vs extend could take an extra type Extend/Move that would
@@ -206,93 +213,101 @@ pub fn move_line_start(cx: &mut Context) {
206213
207214pub fn move_next_word_start(cx: &mut Context) {
208215 let count = cx.count;
216+ let view_id = cx.view_id;
209217 let doc = cx.doc();
210218 let text = doc.text().slice(..);
211219
212− let selection = doc.selection().transform(|range| {
220+ let selection = doc.selection(view_id).transform(|range| {
213221 let pos = movement::move_next_word_start(text, range.head, count);
214222 Range::new(pos, pos)
215223 });
216224
217− doc.set_selection(selection);
225+ doc.set_selection(view_id, selection);
218226}
219227
220228pub fn move_prev_word_start(cx: &mut Context) {
221229 let count = cx.count;
230+ let view_id = cx.view_id;
222231 let doc = cx.doc();
223232 let text = doc.text().slice(..);
224233
225− let selection = doc.selection().transform(|range| {
234+ let selection = doc.selection(view_id).transform(|range| {
226235 let pos = movement::move_prev_word_start(text, range.head, count);
227236 Range::new(pos, pos)
228237 });
229238
230− doc.set_selection(selection);
239+ doc.set_selection(view_id, selection);
231240}
232241
233242pub fn move_next_word_end(cx: &mut Context) {
234243 let count = cx.count;
244+ let view_id = cx.view_id;
235245 let doc = cx.doc();
236246 let text = doc.text().slice(..);
237247
238− let selection = doc.selection().transform(|range| {
248+ let selection = doc.selection(view_id).transform(|range| {
239249 let pos = movement::move_next_word_end(text, range.head, count);
240250 Range::new(pos, pos)
241251 });
242252
243− doc.set_selection(selection);
253+ doc.set_selection(view_id, selection);
244254}
245255
246256pub fn move_file_start(cx: &mut Context) {
247257 push_jump(cx);
258+ let view_id = cx.view_id;
248259 let doc = cx.doc();
249− doc.set_selection(Selection::point(0));
260+ doc.set_selection(view_id, Selection::point(0));
250261}
251262
252263pub fn move_file_end(cx: &mut Context) {
253264 push_jump(cx);
265+ let view_id = cx.view_id;
254266 let doc = cx.doc();
255267 let text = doc.text();
256268 let last_line = text.line_to_char(text.len_lines().saturating_sub(2));
257− doc.set_selection(Selection::point(last_line));
269+ doc.set_selection(view_id, Selection::point(last_line));
258270}
259271
260272pub fn extend_next_word_start(cx: &mut Context) {
261273 let count = cx.count;
274+ let view_id = cx.view_id;
262275 let doc = cx.doc();
263276 let text = doc.text().slice(..);
264277
265− let selection = doc.selection().transform(|mut range| {
278+ let selection = doc.selection(view_id).transform(|mut range| {
266279 let pos = movement::move_next_word_start(text, range.head, count);
267280 Range::new(range.anchor, pos)
268281 });
269282
270− doc.set_selection(selection);
283+ doc.set_selection(view_id, selection);
271284}
272285
273286pub fn extend_prev_word_start(cx: &mut Context) {
274287 let count = cx.count;
288+ let view_id = cx.view_id;
275289 let doc = cx.doc();
276290 let text = doc.text().slice(..);
277291
278− let selection = doc.selection().transform(|mut range| {
292+ let selection = doc.selection(view_id).transform(|mut range| {
279293 let pos = movement::move_prev_word_start(text, range.head, count);
280294 Range::new(range.anchor, pos)
281295 });
282− doc.set_selection(selection);
296+ doc.set_selection(view_id, selection);
283297}
284298
285299pub fn extend_next_word_end(cx: &mut Context) {
286300 let count = cx.count;
301+ let view_id = cx.view_id;
287302 let doc = cx.doc();
288303 let text = doc.text().slice(..);
289304
290− let selection = doc.selection().transform(|mut range| {
305+ let selection = doc.selection(view_id).transform(|mut range| {
291306 let pos = movement::move_next_word_end(text, range.head, count);
292307 Range::new(range.anchor, pos)
293308 });
294309
295− doc.set_selection(selection);
310+ doc.set_selection(view_id, selection);
296311}
297312
298313#[inline]
@@ -313,10 +328,11 @@ where
313328 ..
314329 } = event
315330 {
331+ let view_id = cx.view_id;
316332 let doc = cx.doc();
317333 let text = doc.text().slice(..);
318334
319− let selection = doc.selection().transform(|mut range| {
335+ let selection = doc.selection(view_id).transform(|mut range| {
320336 if let Some(pos) = search::find_nth_next(text, ch, range.head, count, inclusive) {
321337 if extend {
322338 Range::new(range.anchor, pos)
@@ -330,7 +346,7 @@ where
330346 }
331347 });
332348
333− doc.set_selection(selection);
349+ doc.set_selection(view_id, selection);
334350 }
335351 })
336352}
@@ -417,15 +433,16 @@ pub fn replace(cx: &mut Context) {
417433 {
418434 let text = Tendril::from_char(ch);
419435
436+ let view_id = cx.view_id;
420437 let doc = cx.doc();
421438
422439 let transaction =
423− Transaction::change_by_selection(doc.text(), doc.selection(), |range| {
440+ Transaction::change_by_selection(doc.text(), doc.selection(view_id), |range| {
424441 (range.from(), range.to() + 1, Some(text.clone()))
425442 });
426443
427− doc.apply(&transaction);
428− doc.append_changes_to_history();
444+ doc.apply(&transaction, view_id);
445+ doc.append_changes_to_history(view_id);
429446 }
430447 })
431448}
@@ -434,7 +451,7 @@ fn scroll(cx: &mut Context, offset: usize, direction: Direction) {
434451 use Direction::*;
435452 let view = cx.editor.view();
436453 let doc = cx.editor.document(view.doc).unwrap();
437− let cursor = coords_at_pos(doc.text().slice(..), doc.selection().cursor());
454+ let cursor = coords_at_pos(doc.text().slice(..), doc.selection(view.id).cursor());
438455 let doc_last_line = doc.text().len_lines() - 1;
439456
440457 let last_line = view.last_line(doc);
@@ -465,6 +482,8 @@ fn scroll(cx: &mut Context, offset: usize, direction: Direction) {
465482 last_line.saturating_sub(scrolloff),
466483 );
467484
485+ let view_id = view.id;
486+
468487 // view drops here
469488
470489 // upgrade to mut reference
@@ -473,7 +492,7 @@ fn scroll(cx: &mut Context, offset: usize, direction: Direction) {
473492 let text = doc.text().slice(..);
474493 let pos = pos_at_coords(text, Position::new(line, cursor.col)); // this func will properly truncate to line end
475494
476− doc.set_selection(Selection::point(pos));
495+ doc.set_selection(view_id, Selection::point(pos));
477496}
478497
479498pub fn page_up(cx: &mut Context) {
@@ -502,9 +521,10 @@ pub fn half_page_down(cx: &mut Context) {
502521
503522pub fn extend_char_left(cx: &mut Context) {
504523 let count = cx.count;
524+ let view_id = cx.view_id;
505525 let doc = cx.doc();
506526 let text = doc.text().slice(..);
507− let selection = doc.selection().transform(|range| {
527+ let selection = doc.selection(view_id).transform(|range| {
508528 movement::move_horizontally(
509529 text,
510530 range,
@@ -513,14 +533,15 @@ pub fn extend_char_left(cx: &mut Context) {
513533 true, /* extend */
514534 )
515535 });
516− doc.set_selection(selection);
536+ doc.set_selection(view_id, selection);
517537}
518538
519539pub fn extend_char_right(cx: &mut Context) {
520540 let count = cx.count;
541+ let view_id = cx.view_id;
521542 let doc = cx.doc();
522543 let text = doc.text().slice(..);
523− let selection = doc.selection().transform(|range| {
544+ let selection = doc.selection(view_id).transform(|range| {
524545 movement::move_horizontally(
525546 text,
526547 range,
@@ -529,14 +550,15 @@ pub fn extend_char_right(cx: &mut Context) {
529550 true, /* extend */
530551 )
531552 });
532− doc.set_selection(selection);
553+ doc.set_selection(view_id, selection);
533554}
534555
535556pub fn extend_line_up(cx: &mut Context) {
536557 let count = cx.count;
558+ let view_id = cx.view_id;
537559 let doc = cx.doc();
538560 let text = doc.text().slice(..);
539− let selection = doc.selection().transform(|range| {
561+ let selection = doc.selection(view_id).transform(|range| {
540562 movement::move_vertically(
541563 text,
542564 range,
@@ -545,14 +567,15 @@ pub fn extend_line_up(cx: &mut Context) {
545567 true, /* extend */
546568 )
547569 });
548− doc.set_selection(selection);
570+ doc.set_selection(view_id, selection);
549571}
550572
551573pub fn extend_line_down(cx: &mut Context) {
552574 let count = cx.count;
575+ let view_id = cx.view_id;
553576 let doc = cx.doc();
554577 let text = doc.text().slice(..);
555− let selection = doc.selection().transform(|range| {
578+ let selection = doc.selection(view_id).transform(|range| {
556579 movement::move_vertically(
557580 text,
558581 range,
@@ -561,21 +584,24 @@ pub fn extend_line_down(cx: &mut Context) {
561584 true, /* extend */
562585 )
563586 });
564− doc.set_selection(selection);
587+ doc.set_selection(view_id, selection);
565588}
566589
567590pub fn select_all(cx: &mut Context) {
591+ let view_id = cx.view_id;
568592 let doc = cx.doc();
569593
570594 let end = doc.text().len_chars().saturating_sub(1);
571− doc.set_selection(Selection::single(0, end))
595+ doc.set_selection(view_id, Selection::single(0, end))
572596}
573597
574598pub fn select_regex(cx: &mut Context) {
575− let prompt = ui::regex_prompt(cx, "select:".to_string(), |doc, regex| {
599+ let view_id = cx.view_id;
600+ let prompt = ui::regex_prompt(cx, "select:".to_string(), move |doc, regex| {
576601 let text = doc.text().slice(..);
577− if let Some(selection) = selection::select_on_matches(text, doc.selection(), &regex) {
578− doc.set_selection(selection);
602+ if let Some(selection) = selection::select_on_matches(text, doc.selection(view_id), &regex)
603+ {
604+ doc.set_selection(view_id, selection);
579605 }
580606 });
581607
@@ -583,23 +609,25 @@ pub fn select_regex(cx: &mut Context) {
583609}
584610
585611pub fn split_selection(cx: &mut Context) {
586− let prompt = ui::regex_prompt(cx, "split:".to_string(), |doc, regex| {
612+ let view_id = cx.view_id;
613+ let prompt = ui::regex_prompt(cx, "split:".to_string(), move |doc, regex| {
587614 let text = doc.text().slice(..);
588− let selection = selection::split_on_matches(text, doc.selection(), &regex);
589− doc.set_selection(selection);
615+ let selection = selection::split_on_matches(text, doc.selection(view_id), &regex);
616+ doc.set_selection(view_id, selection);
590617 });
591618
592619 cx.push_layer(Box::new(prompt));
593620}
594621
595622pub fn split_selection_on_newline(cx: &mut Context) {
623+ let view_id = cx.view_id;
596624 let doc = cx.doc();
597625 let text = doc.text().slice(..);
598626 // only compile the regex once
599627 #[allow(clippy::trivial_regex)]
600628 static REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"\n").unwrap());
601− let selection = selection::split_on_matches(text, doc.selection(), &REGEX);
602− doc.set_selection(selection);
629+ let selection = selection::split_on_matches(text, doc.selection(view_id), &REGEX);
630+ doc.set_selection(view_id, selection);
603631}
604632
605633// search: searches for the first occurence in file, provides a prompt
@@ -609,9 +637,9 @@ pub fn split_selection_on_newline(cx: &mut Context) {
609637// I'd probably collect all the matches right now and store the current index. The cache needs
610638// wiping if input happens.
611639
612−fn _search(doc: &mut Document, contents: &str, regex: &Regex) {
640+fn _search(doc: &mut Document, view_id: ViewId, contents: &str, regex: &Regex) {
613641 let text = doc.text();
614− let start = doc.selection().cursor();
642+ let start = doc.selection(view_id).cursor();
615643
616644 // TODO: use find_at to find the next match after the cursor, loop around the end
617645 if let Some(mat) = regex.find_at(&contents, start) {
@@ -619,7 +647,7 @@ fn _search(doc: &mut Document, contents: &str, regex: &Regex) {
619647 let end = text.byte_to_char(mat.end());
620648 let selection = Selection::single(start, end - 1);
621649 // TODO: (first_match, regex) stuff in register?
622− doc.set_selection(selection);
650+ doc.set_selection(view_id, selection);
623651 };
624652}
625653
@@ -633,10 +661,11 @@ pub fn search(cx: &mut Context) {
633661 // feed chunks into the regex yet
634662 let contents = doc.text().slice(..).to_string();
635663
664+ let view_id = cx.view_id;
636665 let prompt = ui::regex_prompt(cx, "search:".to_string(), move |doc, regex| {
637666 let text = doc.text();
638− let start = doc.selection().cursor();
639− _search(doc, &contents, &regex);
667+ let start = doc.selection(view_id).cursor();
668+ _search(doc, view_id, &contents, &regex);
640669
641670 // TODO: only store on enter (accept), not update
642671 register::set('\\', vec![regex.as_str().to_string()]);
@@ -648,17 +677,19 @@ pub fn search(cx: &mut Context) {
648677pub fn search_next(cx: &mut Context) {
649678 if let Some(query) = register::get('\\') {
650679 let query = query.first().unwrap();
680+ let view_id = cx.view_id;
651681 let doc = cx.doc();
652682 let contents = doc.text().slice(..).to_string();
653683 let regex = Regex::new(&query).unwrap();
654− _search(doc, &contents, &regex);
684+ _search(doc, view_id, &contents, &regex);
655685 }
656686}
657687
658688pub fn search_selection(cx: &mut Context) {
689+ let view_id = cx.view_id;
659690 let doc = cx.doc();
660691 let contents = doc.text().slice(..);
661− let query = doc.selection().primary().fragment(contents);
692+ let query = doc.selection(view_id).primary().fragment(contents);
662693 let regex = regex::escape(&query);
663694 register::set('\\', vec![regex]);
664695 search_next(cx);
@@ -672,22 +703,24 @@ pub fn search_selection(cx: &mut Context) {
672703
673704pub fn select_line(cx: &mut Context) {
674705 let count = cx.count;
706+ let view_id = cx.view_id;
675707 let doc = cx.doc();
676708
677− let pos = doc.selection().primary();
709+ let pos = doc.selection(view_id).primary();
678710 let text = doc.text();
679711
680712 let line = text.char_to_line(pos.head);
681713 let start = text.line_to_char(line);
682714 let end = text.line_to_char(line + count).saturating_sub(1);
683715
684− doc.set_selection(Selection::single(start, end));
716+ doc.set_selection(view_id, Selection::single(start, end));
685717}
686718pub fn extend_line(cx: &mut Context) {
719+ let view_id = cx.view_id;
687720 let count = cx.count;
688721 let doc = cx.doc();
689722
690− let pos = doc.selection().primary();
723+ let pos = doc.selection(view_id).primary();
691724 let text = doc.text();
692725
693726 let line_start = text.char_to_line(pos.anchor);
@@ -700,47 +733,52 @@ pub fn extend_line(cx: &mut Context) {
700733 let start = text.line_to_char(line_start);
701734 let end = text.line_to_char(line + 1).saturating_sub(1);
702735
703− doc.set_selection(Selection::single(start, end));
736+ doc.set_selection(view_id, Selection::single(start, end));
704737}
705738
706739// heuristic: append changes to history after each command, unless we're in insert mode
707740
708−fn _delete_selection(doc: &mut Document) {
709− let transaction = Transaction::change_by_selection(doc.text(), doc.selection(), |range| {
710− (range.from(), range.to() + 1, None)
711− });
712− doc.apply(&transaction);
741+fn _delete_selection(doc: &mut Document, view_id: ViewId) {
742+ let transaction =
743+ Transaction::change_by_selection(doc.text(), doc.selection(view_id), |range| {
744+ (range.from(), range.to() + 1, None)
745+ });
746+ doc.apply(&transaction, view_id);
713747}
714748
715749pub fn delete_selection(cx: &mut Context) {
750+ let view_id = cx.view_id;
716751 let doc = cx.doc();
717− _delete_selection(doc);
752+ _delete_selection(doc, view_id);
718753
719− doc.append_changes_to_history();
754+ doc.append_changes_to_history(view_id);
720755}
721756
722757pub fn change_selection(cx: &mut Context) {
758+ let view_id = cx.view_id;
723759 let doc = cx.doc();
724− _delete_selection(doc);
760+ _delete_selection(doc, view_id);
725761 enter_insert_mode(doc);
726762}
727763
728764pub fn collapse_selection(cx: &mut Context) {
765+ let view_id = cx.view_id;
729766 let doc = cx.doc();
730767 let selection = doc
731− .selection()
768+ .selection(view_id)
732769 .transform(|range| Range::new(range.head, range.head));
733770
734− doc.set_selection(selection);
771+ doc.set_selection(view_id, selection);
735772}
736773
737774pub fn flip_selections(cx: &mut Context) {
775+ let view_id = cx.view_id;
738776 let doc = cx.doc();
739777 let selection = doc
740− .selection()
778+ .selection(view_id)
741779 .transform(|range| Range::new(range.head, range.anchor));
742780
743− doc.set_selection(selection);
781+ doc.set_selection(view_id, selection);
744782}
745783
746784fn enter_insert_mode(doc: &mut Document) {
@@ -749,29 +787,31 @@ fn enter_insert_mode(doc: &mut Document) {
749787
750788// inserts at the start of each selection
751789pub fn insert_mode(cx: &mut Context) {
790+ let view_id = cx.view_id;
752791 let doc = cx.doc();
753792 enter_insert_mode(doc);
754793
755794 let selection = doc
756− .selection()
795+ .selection(view_id)
757796 .transform(|range| Range::new(range.to(), range.from()));
758− doc.set_selection(selection);
797+ doc.set_selection(view_id, selection);
759798}
760799
761800// inserts at the end of each selection
762801pub fn append_mode(cx: &mut Context) {
802+ let view_id = cx.view_id;
763803 let doc = cx.doc();
764804 enter_insert_mode(doc);
765805 doc.restore_cursor = true;
766806
767807 let text = doc.text().slice(..);
768− let selection = doc.selection().transform(|range| {
808+ let selection = doc.selection(view_id).transform(|range| {
769809 Range::new(
770810 range.from(),
771811 graphemes::next_grapheme_boundary(text, range.to()), // to() + next char
772812 )
773813 });
774− doc.set_selection(selection);
814+ doc.set_selection(view_id, selection);
775815}
776816
777817const COMMAND_LIST: &[&str] = &["write", "open", "quit"];
@@ -931,25 +971,27 @@ pub fn prepend_to_line(cx: &mut Context) {
931971pub fn append_to_line(cx: &mut Context) {
932972 move_line_end(cx);
933973
974+ let view_id = cx.view_id;
934975 let doc = cx.doc();
935976 enter_insert_mode(doc);
936977
937978 // offset by another 1 char since move_line_end will position on the last char, we want to
938979 // append past that
939− let selection = doc.selection().transform(|range| {
980+ let selection = doc.selection(view_id).transform(|range| {
940981 let pos = range.head + 1;
941982 Range::new(pos, pos)
942983 });
943− doc.set_selection(selection);
984+ doc.set_selection(view_id, selection);
944985}
945986
946987// o inserts a new line after each line with a selection
947988pub fn open_below(cx: &mut Context) {
989+ let view_id = cx.view_id;
948990 let count = cx.count;
949991 let doc = cx.doc();
950992 enter_insert_mode(doc);
951993
952− let lines = selection_lines(doc.text(), doc.selection());
994+ let lines = selection_lines(doc.text(), doc.selection(view_id));
953995
954996 let positions = lines.into_iter().map(|index| {
955997 // adjust all positions to the end of the line (next line minus one)
@@ -991,16 +1033,17 @@ pub fn open_below(cx: &mut Context) {
9911033 let transaction =
9921034 Transaction::change(doc.text(), changes.into_iter()).with_selection(selection);
9931035
994− doc.apply(&transaction);
1036+ doc.apply(&transaction, view_id);
9951037}
9961038
9971039// O inserts a new line before each line with a selection
9981040pub fn open_above(cx: &mut Context) {
1041+ let view_id = cx.view_id;
9991042 let count = cx.count;
10001043 let doc = cx.doc();
10011044 enter_insert_mode(doc);
10021045
1003− let lines = selection_lines(doc.text(), doc.selection());
1046+ let lines = selection_lines(doc.text(), doc.selection(view_id));
10041047
10051048 let positions = lines.into_iter().map(|index| {
10061049 // adjust all positions to the end of the previous line
@@ -1043,26 +1086,27 @@ pub fn open_above(cx: &mut Context) {
10431086 let transaction =
10441087 Transaction::change(doc.text(), changes.into_iter()).with_selection(selection);
10451088
1046− doc.apply(&transaction);
1089+ doc.apply(&transaction, view_id);
10471090}
10481091
10491092pub fn normal_mode(cx: &mut Context) {
1093+ let view_id = cx.view_id;
10501094 let doc = cx.doc();
10511095
10521096 doc.mode = Mode::Normal;
10531097
1054− doc.append_changes_to_history();
1098+ doc.append_changes_to_history(view_id);
10551099
10561100 // if leaving append mode, move cursor back by 1
10571101 if doc.restore_cursor {
10581102 let text = doc.text().slice(..);
1059− let selection = doc.selection().transform(|range| {
1103+ let selection = doc.selection(view_id).transform(|range| {
10601104 Range::new(
10611105 range.from(),
10621106 graphemes::prev_grapheme_boundary(text, range.to()),
10631107 )
10641108 });
1065− doc.set_selection(selection);
1109+ doc.set_selection(view_id, selection);
10661110
10671111 doc.restore_cursor = false;
10681112 }
@@ -1071,13 +1115,15 @@ pub fn normal_mode(cx: &mut Context) {
10711115// Store a jump on the jumplist.
10721116fn push_jump(cx: &mut Context) {
10731117 let jump = {
1118+ let view_id = cx.view_id;
10741119 let doc = cx.doc();
1075− (doc.id(), doc.selection().clone())
1120+ (doc.id(), doc.selection(view_id).clone())
10761121 };
10771122 cx.view().jumps.push(jump);
10781123}
10791124
10801125pub fn goto_mode(cx: &mut Context) {
1126+ let view_id = cx.view_id;
10811127 let count = cx.count;
10821128
10831129 if count > 1 {
@@ -1087,7 +1133,7 @@ pub fn goto_mode(cx: &mut Context) {
10871133 // to 1g
10881134 let doc = cx.doc();
10891135 let pos = doc.text().line_to_char(count - 1);
1090− doc.set_selection(Selection::point(pos));
1136+ doc.set_selection(view_id, Selection::point(pos));
10911137 return;
10921138 }
10931139
@@ -1128,10 +1174,11 @@ fn _goto(cx: &mut Context, locations: Vec<lsp::Location>) {
11281174 let id = editor
11291175 .open(PathBuf::from(location.uri.path()), action)
11301176 .expect("editor.open failed");
1177+ let view_id = editor.view().id;
11311178 let doc = &mut editor.documents[id];
11321179 let definition_pos = location.range.start;
11331180 let new_pos = helix_lsp::util::lsp_pos_to_pos(doc.text(), definition_pos);
1134− doc.set_selection(Selection::point(new_pos));
1181+ doc.set_selection(view_id, Selection::point(new_pos));
11351182 }
11361183
11371184 match locations.as_slice() {
@@ -1155,6 +1202,7 @@ fn _goto(cx: &mut Context, locations: Vec<lsp::Location>) {
11551202}
11561203
11571204pub fn goto_definition(cx: &mut Context) {
1205+ let view_id = cx.view_id;
11581206 let doc = cx.doc();
11591207 let language_server = match doc.language_server() {
11601208 Some(language_server) => language_server,
@@ -1162,7 +1210,7 @@ pub fn goto_definition(cx: &mut Context) {
11621210 };
11631211
11641212 // TODO: blocking here is not ideal
1165− let pos = helix_lsp::util::pos_to_lsp_pos(doc.text(), doc.selection().cursor());
1213+ let pos = helix_lsp::util::pos_to_lsp_pos(doc.text(), doc.selection(view_id).cursor());
11661214
11671215 // TODO: handle fails
11681216 let res =
@@ -1171,6 +1219,7 @@ pub fn goto_definition(cx: &mut Context) {
11711219}
11721220
11731221pub fn goto_type_definition(cx: &mut Context) {
1222+ let view_id = cx.view_id;
11741223 let doc = cx.doc();
11751224 let language_server = match doc.language_server() {
11761225 Some(language_server) => language_server,
@@ -1178,7 +1227,7 @@ pub fn goto_type_definition(cx: &mut Context) {
11781227 };
11791228
11801229 // TODO: blocking here is not ideal
1181− let pos = helix_lsp::util::pos_to_lsp_pos(doc.text(), doc.selection().cursor());
1230+ let pos = helix_lsp::util::pos_to_lsp_pos(doc.text(), doc.selection(view_id).cursor());
11821231
11831232 // TODO: handle fails
11841233 let res = smol::block_on(language_server.goto_type_definition(doc.identifier(), pos))
@@ -1187,6 +1236,7 @@ pub fn goto_type_definition(cx: &mut Context) {
11871236}
11881237
11891238pub fn goto_implementation(cx: &mut Context) {
1239+ let view_id = cx.view_id;
11901240 let doc = cx.doc();
11911241 let language_server = match doc.language_server() {
11921242 Some(language_server) => language_server,
@@ -1194,7 +1244,7 @@ pub fn goto_implementation(cx: &mut Context) {
11941244 };
11951245
11961246 // TODO: blocking here is not ideal
1197− let pos = helix_lsp::util::pos_to_lsp_pos(doc.text(), doc.selection().cursor());
1247+ let pos = helix_lsp::util::pos_to_lsp_pos(doc.text(), doc.selection(view_id).cursor());
11981248
11991249 // TODO: handle fails
12001250 let res = smol::block_on(language_server.goto_implementation(doc.identifier(), pos))
@@ -1203,6 +1253,7 @@ pub fn goto_implementation(cx: &mut Context) {
12031253}
12041254
12051255pub fn goto_reference(cx: &mut Context) {
1256+ let view_id = cx.view_id;
12061257 let doc = cx.doc();
12071258 let language_server = match doc.language_server() {
12081259 Some(language_server) => language_server,
@@ -1210,7 +1261,7 @@ pub fn goto_reference(cx: &mut Context) {
12101261 };
12111262
12121263 // TODO: blocking here is not ideal
1213− let pos = helix_lsp::util::pos_to_lsp_pos(doc.text(), doc.selection().cursor());
1264+ let pos = helix_lsp::util::pos_to_lsp_pos(doc.text(), doc.selection(view_id).cursor());
12141265
12151266 // TODO: handle fails
12161267 let res =
@@ -1219,6 +1270,7 @@ pub fn goto_reference(cx: &mut Context) {
12191270}
12201271
12211272pub fn signature_help(cx: &mut Context) {
1273+ let view_id = cx.view_id;
12221274 let doc = cx.doc();
12231275
12241276 let language_server = match doc.language_server() {
@@ -1227,7 +1279,7 @@ pub fn signature_help(cx: &mut Context) {
12271279 };
12281280
12291281 // TODO: blocking here is not ideal
1230− let pos = helix_lsp::util::pos_to_lsp_pos(doc.text(), doc.selection().cursor());
1282+ let pos = helix_lsp::util::pos_to_lsp_pos(doc.text(), doc.selection(view_id).cursor());
12311283
12321284 // TODO: handle fails
12331285
@@ -1320,20 +1372,21 @@ pub mod insert {
13201372
13211373 // TODO: insert means add text just before cursor, on exit we should be on the last letter.
13221374 pub fn insert_char(cx: &mut Context, c: char) {
1375+ let view_id = cx.view_id;
13231376 let doc = cx.doc();
13241377
13251378 // run through insert hooks, stopping on the first one that returns Some(t)
13261379 for hook in HOOKS {
1327− if let Some(transaction) = hook(doc.text(), doc.selection(), c) {
1328− doc.apply(&transaction);
1380+ if let Some(transaction) = hook(doc.text(), doc.selection(view_id), c) {
1381+ doc.apply(&transaction, view_id);
13291382 return;
13301383 }
13311384 }
13321385
13331386 let t = Tendril::from_char(c);
1334− let transaction = Transaction::insert(doc.text(), doc.selection(), t);
1387+ let transaction = Transaction::insert(doc.text(), doc.selection(view_id), t);
13351388
1336− doc.apply(&transaction);
1389+ doc.apply(&transaction, view_id);
13371390
13381391 // TODO: need a post insert hook too for certain triggers (autocomplete, signature help, etc)
13391392 // this could also generically look at Transaction, but it's a bit annoying to look at
@@ -1344,58 +1397,69 @@ pub mod insert {
13441397 }
13451398
13461399 pub fn insert_tab(cx: &mut Context) {
1400+ let view_id = cx.view_id;
13471401 let doc = cx.doc();
13481402 // TODO: round out to nearest indentation level (for example a line with 3 spaces should
13491403 // indent by one to reach 4 spaces).
13501404
13511405 let indent = Tendril::from(doc.indent_unit());
1352− let transaction = Transaction::insert(doc.text(), doc.selection(), indent);
1353− doc.apply(&transaction);
1406+ let transaction = Transaction::insert(doc.text(), doc.selection(view_id), indent);
1407+ doc.apply(&transaction, view_id);
13541408 }
13551409
13561410 pub fn insert_newline(cx: &mut Context) {
1411+ let view_id = cx.view_id;
13571412 let doc = cx.doc();
13581413 let text = doc.text().slice(..);
1359− let transaction = Transaction::change_by_selection(doc.text(), doc.selection(), |range| {
1360− // TODO: offset range.head by 1? when calculating?
1361− let indent_level =
1362− helix_core::indent::suggested_indent_for_pos(doc.syntax(), text, range.head, true);
1363− let indent = doc.indent_unit().repeat(indent_level);
1364− let mut text = String::with_capacity(1 + indent.len());
1365− text.push('\n');
1366− text.push_str(&indent);
1367− (range.head, range.head, Some(text.into()))
1368− });
1369− doc.apply(&transaction);
1414+ let transaction =
1415+ Transaction::change_by_selection(doc.text(), doc.selection(view_id), |range| {
1416+ // TODO: offset range.head by 1? when calculating?
1417+ let indent_level = helix_core::indent::suggested_indent_for_pos(
1418+ doc.syntax(),
1419+ text,
1420+ range.head,
1421+ true,
1422+ );
1423+ let indent = doc.indent_unit().repeat(indent_level);
1424+ let mut text = String::with_capacity(1 + indent.len());
1425+ text.push('\n');
1426+ text.push_str(&indent);
1427+ (range.head, range.head, Some(text.into()))
1428+ });
1429+ doc.apply(&transaction, view_id);
13701430 }
13711431
13721432 // TODO: handle indent-aware delete
13731433 pub fn delete_char_backward(cx: &mut Context) {
1434+ let view_id = cx.view_id;
13741435 let count = cx.count;
13751436 let doc = cx.doc();
13761437 let text = doc.text().slice(..);
1377− let transaction = Transaction::change_by_selection(doc.text(), doc.selection(), |range| {
1378− (
1379− graphemes::nth_prev_grapheme_boundary(text, range.head, count),
1380− range.head,
1381− None,
1382− )
1383− });
1384− doc.apply(&transaction);
1438+ let transaction =
1439+ Transaction::change_by_selection(doc.text(), doc.selection(view_id), |range| {
1440+ (
1441+ graphemes::nth_prev_grapheme_boundary(text, range.head, count),
1442+ range.head,
1443+ None,
1444+ )
1445+ });
1446+ doc.apply(&transaction, view_id);
13851447 }
13861448
13871449 pub fn delete_char_forward(cx: &mut Context) {
1450+ let view_id = cx.view_id;
13881451 let count = cx.count;
13891452 let doc = cx.doc();
13901453 let text = doc.text().slice(..);
1391− let transaction = Transaction::change_by_selection(doc.text(), doc.selection(), |range| {
1392− (
1393− range.head,
1394− graphemes::nth_next_grapheme_boundary(text, range.head, count),
1395− None,
1396− )
1397− });
1398− doc.apply(&transaction);
1454+ let transaction =
1455+ Transaction::change_by_selection(doc.text(), doc.selection(view_id), |range| {
1456+ (
1457+ range.head,
1458+ graphemes::nth_next_grapheme_boundary(text, range.head, count),
1459+ None,
1460+ )
1461+ });
1462+ doc.apply(&transaction, view_id);
13991463 }
14001464}
14011465
@@ -1405,20 +1469,23 @@ pub mod insert {
14051469// storing it?
14061470
14071471pub fn undo(cx: &mut Context) {
1408− cx.doc().undo();
1472+ let view_id = cx.view_id;
1473+ cx.doc().undo(view_id);
14091474}
14101475
14111476pub fn redo(cx: &mut Context) {
1412− cx.doc().redo();
1477+ let view_id = cx.view_id;
1478+ cx.doc().redo(view_id);
14131479}
14141480
14151481// Yank / Paste
14161482
14171483pub fn yank(cx: &mut Context) {
14181484 // TODO: should selections be made end inclusive?
1485+ let view_id = cx.view_id;
14191486 let doc = cx.doc();
14201487 let values: Vec<String> = doc
1421− .selection()
1488+ .selection(view_id)
14221489 .fragments(doc.text().slice(..))
14231490 .map(|cow| cow.into_owned())
14241491 .collect();
@@ -1461,32 +1528,33 @@ pub fn paste(cx: &mut Context) {
14611528
14621529 let mut values = values.into_iter().map(Tendril::from).chain(repeat);
14631530
1531+ let view_id = cx.view_id;
14641532 let doc = cx.doc();
14651533
14661534 let transaction = if linewise {
14671535 // paste on the next line
14681536 // TODO: can simply take a range + modifier and compute the right pos without ifs
14691537 let text = doc.text();
1470− Transaction::change_by_selection(doc.text(), doc.selection(), |range| {
1538+ Transaction::change_by_selection(doc.text(), doc.selection(view_id), |range| {
14711539 let line_end = text.line_to_char(text.char_to_line(range.head) + 1);
14721540 (line_end, line_end, Some(values.next().unwrap()))
14731541 })
14741542 } else {
1475− Transaction::change_by_selection(doc.text(), doc.selection(), |range| {
1543+ Transaction::change_by_selection(doc.text(), doc.selection(view_id), |range| {
14761544 (range.head + 1, range.head + 1, Some(values.next().unwrap()))
14771545 })
14781546 };
14791547
1480− doc.apply(&transaction);
1481− doc.append_changes_to_history();
1548+ doc.apply(&transaction, view_id);
1549+ doc.append_changes_to_history(view_id);
14821550 }
14831551}
14841552
1485−fn get_lines(doc: &Document) -> Vec<usize> {
1553+fn get_lines(doc: &Document, view_id: ViewId) -> Vec<usize> {
14861554 let mut lines = Vec::new();
14871555
14881556 // Get all line numbers
1489− for range in doc.selection() {
1557+ for range in doc.selection(view_id) {
14901558 let start = doc.text().char_to_line(range.from());
14911559 let end = doc.text().char_to_line(range.to());
14921560
@@ -1500,8 +1568,9 @@ fn get_lines(doc: &Document) -> Vec<usize> {
15001568}
15011569
15021570pub fn indent(cx: &mut Context) {
1571+ let view_id = cx.view_id;
15031572 let doc = cx.doc();
1504− let lines = get_lines(doc);
1573+ let lines = get_lines(doc, view_id);
15051574
15061575 // Indent by one level
15071576 let indent = Tendril::from(doc.indent_unit());
@@ -1513,13 +1582,14 @@ pub fn indent(cx: &mut Context) {
15131582 (pos, pos, Some(indent.clone()))
15141583 }),
15151584 );
1516− doc.apply(&transaction);
1517− doc.append_changes_to_history();
1585+ doc.apply(&transaction, view_id);
1586+ doc.append_changes_to_history(view_id);
15181587}
15191588
15201589pub fn unindent(cx: &mut Context) {
1590+ let view_id = cx.view_id;
15211591 let doc = cx.doc();
1522− let lines = get_lines(doc);
1592+ let lines = get_lines(doc, view_id);
15231593 let mut changes = Vec::with_capacity(lines.len());
15241594 let tab_width = doc.tab_width();
15251595
@@ -1547,12 +1617,13 @@ pub fn unindent(cx: &mut Context) {
15471617
15481618 let transaction = Transaction::change(doc.text(), changes.into_iter());
15491619
1550− doc.apply(&transaction);
1551− doc.append_changes_to_history();
1620+ doc.apply(&transaction, view_id);
1621+ doc.append_changes_to_history(view_id);
15521622}
15531623
15541624pub fn format_selections(cx: &mut Context) {
15551625 use helix_lsp::lsp;
1626+ let view_id = cx.view_id;
15561627 let doc = cx.doc();
15571628
15581629 // via lsp if available
@@ -1561,7 +1632,7 @@ pub fn format_selections(cx: &mut Context) {
15611632 // TODO: blocking here is not ideal
15621633
15631634 let ranges: Vec<lsp::Range> = doc
1564− .selection()
1635+ .selection(view_id)
15651636 .iter()
15661637 .map(|range| helix_lsp::util::range_to_lsp_range(doc.text(), *range))
15671638 .collect();
@@ -1583,14 +1654,15 @@ pub fn format_selections(cx: &mut Context) {
15831654
15841655 let transaction = helix_lsp::util::generate_transaction_from_edits(doc.text(), edits);
15851656
1586− doc.apply(&transaction);
1657+ doc.apply(&transaction, view_id);
15871658 }
15881659
1589− doc.append_changes_to_history();
1660+ doc.append_changes_to_history(view_id);
15901661}
15911662
15921663pub fn join_selections(cx: &mut Context) {
15931664 use movement::skip_over_next;
1665+ let view_id = cx.view_id;
15941666 let doc = cx.doc();
15951667 let text = doc.text();
15961668 let slice = doc.text().slice(..);
@@ -1598,7 +1670,7 @@ pub fn join_selections(cx: &mut Context) {
15981670 let mut changes = Vec::new();
15991671 let fragment = Tendril::from(" ");
16001672
1601− for selection in doc.selection() {
1673+ for selection in doc.selection(view_id) {
16021674 let start = text.char_to_line(selection.from());
16031675 let mut end = text.char_to_line(selection.to());
16041676 if start == end {
@@ -1629,17 +1701,18 @@ pub fn join_selections(cx: &mut Context) {
16291701 // TODO: select inserted spaces
16301702 // .with_selection(selection);
16311703
1632− doc.apply(&transaction);
1633− doc.append_changes_to_history();
1704+ doc.apply(&transaction, view_id);
1705+ doc.append_changes_to_history(view_id);
16341706}
16351707
16361708pub fn keep_selections(cx: &mut Context) {
16371709 // keep selections matching regex
1638− let prompt = ui::regex_prompt(cx, "keep:".to_string(), |doc, regex| {
1710+ let view_id = cx.view_id;
1711+ let prompt = ui::regex_prompt(cx, "keep:".to_string(), move |doc, regex| {
16391712 let text = doc.text().slice(..);
16401713
1641− if let Some(selection) = selection::keep_matches(text, doc.selection(), &regex) {
1642− doc.set_selection(selection);
1714+ if let Some(selection) = selection::keep_matches(text, doc.selection(view_id), &regex) {
1715+ doc.set_selection(view_id, selection);
16431716 }
16441717 });
16451718
@@ -1647,11 +1720,12 @@ pub fn keep_selections(cx: &mut Context) {
16471720}
16481721
16491722pub fn keep_primary_selection(cx: &mut Context) {
1723+ let view_id = cx.view_id;
16501724 let doc = cx.doc();
16511725
1652− let range = doc.selection().primary();
1726+ let range = doc.selection(view_id).primary();
16531727 let selection = Selection::single(range.anchor, range.head);
1654− doc.set_selection(selection);
1728+ doc.set_selection(view_id, selection);
16551729}
16561730
16571731//
@@ -1700,6 +1774,7 @@ pub fn completion(cx: &mut Context) {
17001774 // The prefix still has to satisfy `company-minimum-prefix-length' before that
17011775 // happens. The value of nil means no idle completion."
17021776
1777+ let view_id = cx.view_id;
17031778 let doc = cx.doc();
17041779
17051780 let language_server = match doc.language_server() {
@@ -1708,13 +1783,13 @@ pub fn completion(cx: &mut Context) {
17081783 };
17091784
17101785 // TODO: blocking here is not ideal
1711− let pos = helix_lsp::util::pos_to_lsp_pos(doc.text(), doc.selection().cursor());
1786+ let pos = helix_lsp::util::pos_to_lsp_pos(doc.text(), doc.selection(view_id).cursor());
17121787
17131788 // TODO: handle fails
17141789
17151790 let res = smol::block_on(language_server.completion(doc.identifier(), pos)).unwrap();
17161791
1717− let trigger_offset = doc.selection().cursor();
1792+ let trigger_offset = doc.selection(view_id).cursor();
17181793
17191794 cx.callback(
17201795 res,
@@ -1751,6 +1826,7 @@ pub fn completion(cx: &mut Context) {
17511826pub fn hover(cx: &mut Context) {
17521827 use helix_lsp::lsp;
17531828
1829+ let view_id = cx.view_id;
17541830 let doc = cx.doc();
17551831
17561832 let language_server = match doc.language_server() {
@@ -1762,7 +1838,7 @@ pub fn hover(cx: &mut Context) {
17621838
17631839 // TODO: blocking here is not ideal, make commands async fn?
17641840 // not like we can process additional input meanwhile though
1765− let pos = helix_lsp::util::pos_to_lsp_pos(doc.text(), doc.selection().cursor());
1841+ let pos = helix_lsp::util::pos_to_lsp_pos(doc.text(), doc.selection(view_id).cursor());
17661842
17671843 // TODO: handle fails
17681844 let res = smol::block_on(language_server.text_document_hover(doc.identifier(), pos))
@@ -1798,33 +1874,36 @@ pub fn next_view(cx: &mut Context) {
17981874
17991875// comments
18001876pub fn toggle_comments(cx: &mut Context) {
1877+ let view_id = cx.view_id;
18011878 let doc = cx.doc();
1802− let transaction = comment::toggle_line_comments(doc.text(), doc.selection());
1879+ let transaction = comment::toggle_line_comments(doc.text(), doc.selection(view_id));
18031880
1804− doc.apply(&transaction);
1805− doc.append_changes_to_history();
1881+ doc.apply(&transaction, view_id);
1882+ doc.append_changes_to_history(view_id);
18061883}
18071884
18081885// tree sitter node selection
18091886
18101887pub fn expand_selection(cx: &mut Context) {
1888+ let view_id = cx.view_id;
18111889 let doc = cx.doc();
18121890
18131891 if let Some(syntax) = doc.syntax() {
18141892 let text = doc.text().slice(..);
1815− let selection = object::expand_selection(syntax, text, doc.selection());
1816− doc.set_selection(selection);
1893+ let selection = object::expand_selection(syntax, text, doc.selection(view_id));
1894+ doc.set_selection(view_id, selection);
18171895 }
18181896}
18191897
18201898pub fn match_brackets(cx: &mut Context) {
1899+ let view_id = cx.view_id;
18211900 let doc = cx.doc();
18221901
18231902 if let Some(syntax) = doc.syntax() {
1824− let pos = doc.selection().cursor();
1903+ let pos = doc.selection(view_id).cursor();
18251904 if let Some(pos) = match_brackets::find(syntax, doc.text(), pos) {
18261905 let selection = Selection::point(pos);
1827− doc.set_selection(selection);
1906+ doc.set_selection(view_id, selection);
18281907 };
18291908 }
18301909}
@@ -1836,6 +1915,7 @@ pub fn jump_forward(cx: &mut Context) {
18361915 let view = cx.view();
18371916
18381917 if let Some((id, selection)) = view.jumps.forward(count) {
1918+ // TODO: position first_line so that main cursor is centered
18391919 view.first_line = 0;
18401920 view.doc = *id;
18411921 };
@@ -1846,11 +1926,13 @@ pub fn jump_backward(cx: &mut Context) {
18461926 let view = cx.view();
18471927
18481928 if let Some((id, selection)) = view.jumps.backward(count) {
1929+ // TODO: position first_line so that main cursor is centered
18491930 view.first_line = 0;
18501931 view.doc = *id;
18511932 let selection = selection.clone();
1933+ let view_id = view.id;
18521934 let doc = cx.doc();
1853− doc.set_selection(selection);
1935+ doc.set_selection(view_id, selection);
18541936 };
18551937}
18561938
helix-term/src/ui/completion.rs+26−6
@@ -21,6 +21,7 @@ use lsp::CompletionItem;
2121pub struct Completion {
2222 popup: Popup<Menu<CompletionItem>>, // TODO: Popup<Menu> need to be able to access contents.
2323 trigger_offset: usize,
24+ // TODO: maintain a completioncontext with trigger kind & trigger char
2425}
2526
2627impl Completion {
@@ -43,7 +44,9 @@ impl Completion {
4344 // doc.state = snapshot.clone();
4445 }
4546 PromptEvent::Validate => {
46− let id = editor.view().doc;
47+ let view = editor.view();
48+ let view_id = view.id;
49+ let id = view.doc;
4750 let doc = &mut editor.documents[id];
4851
4952 // revert state to what it was before the last update
@@ -89,18 +92,18 @@ impl Completion {
8992 }
9093
9194 // if more text was entered, remove it
92− let cursor = doc.selection().cursor();
95+ let cursor = doc.selection(view_id).cursor();
9396 if trigger_offset < cursor {
9497 let remove = Transaction::change(
9598 doc.text(),
9699 vec![(trigger_offset, cursor, None)].into_iter(),
97100 );
98− doc.apply(&remove);
101+ doc.apply(&remove, view_id);
99102 }
100103
101104 let transaction =
102105 util::generate_transaction_from_edits(doc.text(), vec![edit]);
103− doc.apply(&transaction);
106+ doc.apply(&transaction, view_id);
104107 }
105108 _ => (),
106109 };
@@ -124,15 +127,32 @@ impl Component for Completion {
124127 {
125128 // recompute menu based on matches
126129 let menu = self.popup.contents();
127− let id = cx.editor.view().doc;
130+ let view = cx.editor.view();
131+ let view_id = view.id;
132+ let id = view.doc;
128133 let doc = cx.editor.document(id).unwrap();
129134
130− let cursor = doc.selection().cursor();
135+ // cx.hooks()
136+ // cx.add_hook(enum type, ||)
137+ // cx.trigger_hook(enum type, &str, ...) <-- there has to be enough to identify doc/view
138+ // callback with editor & compositor
139+ //
140+ // trigger_hook sends event into channel, that's consumed in the global loop and
141+ // triggers all registered callbacks
142+ // TODO: hooks should get processed immediately so maybe do it after select!(), before
143+ // looping?
144+
145+ let cursor = doc.selection(view_id).cursor();
131146 if self.trigger_offset <= cursor {
132147 let fragment = doc.text().slice(self.trigger_offset..cursor);
148+ // ^ problem seems to be that we handle events here before the editor layer, so the
149+ // keypress isn't included in the editor layer yet...
150+ // so we can't use ..= for now.
133151 let text = Cow::from(fragment);
134152 // TODO: logic is same as ui/picker
135153 menu.score(&text);
154+
155+ // TODO: if after scoring the selection is 0 items, remove popup
136156 }
137157 }
138158
helix-term/src/ui/editor.rs+8−4
@@ -64,7 +64,7 @@ impl EditorView {
6464 // TODO: this seems to prevent setting style later
6565 // surface.set_style(viewport, theme.get("ui.background"));
6666
67− self.render_diagnostics(&doc, area, surface, theme, is_focused);
67+ self.render_diagnostics(&doc, view, area, surface, theme, is_focused);
6868
6969 let area = Rect::new(
7070 viewport.x,
@@ -224,7 +224,7 @@ impl EditorView {
224224 let selection_style = Style::default().bg(Color::Rgb(84, 0, 153));
225225
226226 for selection in doc
227− .selection()
227+ .selection(view.id)
228228 .iter()
229229 .filter(|range| range.overlaps(&screen))
230230 {
@@ -332,6 +332,7 @@ impl EditorView {
332332 pub fn render_diagnostics(
333333 &self,
334334 doc: &Document,
335+ view: &View,
335336 viewport: Rect,
336337 surface: &mut Surface,
337338 theme: &Theme,
@@ -344,7 +345,7 @@ impl EditorView {
344345 widgets::{Paragraph, Widget},
345346 };
346347
347− let cursor = doc.selection().cursor();
348+ let cursor = doc.selection(view.id).cursor();
348349 let line = doc.text().char_to_line(cursor);
349350
350351 let diagnostics = doc.diagnostics.iter().filter(|diagnostic| {
@@ -486,11 +487,14 @@ impl Component for EditorView {
486487 EventResult::Consumed(None)
487488 }
488489 Event::Key(event) => {
489− let id = cx.editor.view().doc;
490+ let view = cx.editor.view();
491+ let view_id = view.id;
492+ let id = view.doc;
490493 let mode = cx.editor.document(id).unwrap().mode();
491494
492495 let mut cxt = commands::Context {
493496 editor: &mut cx.editor,
497+ view_id,
494498 count: 1,
495499 callback: None,
496500 callbacks: cx.callbacks,
helix-term/src/ui/mod.rs+11−6
@@ -35,7 +35,8 @@ pub fn regex_prompt(
3535 prompt: String,
3636 fun: impl Fn(&mut Document, Regex) + 'static,
3737) -> Prompt {
38− let snapshot = cx.doc().selection().clone();
38+ let view_id = cx.view().id;
39+ let snapshot = cx.doc().selection(view_id).clone();
3940
4041 Prompt::new(
4142 prompt,
@@ -44,9 +45,11 @@ pub fn regex_prompt(
4445 match event {
4546 PromptEvent::Abort => {
4647 // TODO: also revert text
47− let id = editor.view().doc;
48+ let view = editor.view();
49+ let view_id = view.id;
50+ let id = view.doc;
4851 let doc = &mut editor.documents[id];
49− doc.set_selection(snapshot.clone());
52+ doc.set_selection(view_id, snapshot.clone());
5053 }
5154 PromptEvent::Validate => {
5255 // TODO: push_jump to store selection just before jump
@@ -60,16 +63,18 @@ pub fn regex_prompt(
6063 match Regex::new(input) {
6164 Ok(regex) => {
6265 // let view = &mut editor.view_mut();
63− let id = editor.view().doc;
66+ let view = editor.view();
67+ let view_id = view.id;
68+ let id = view.doc;
6469 let doc = &mut editor.documents[id];
6570
6671 // revert state to what it was before the last update
6772 // TODO: also revert text
68− doc.set_selection(snapshot.clone());
73+ doc.set_selection(view_id, snapshot.clone());
6974
7075 fun(doc, regex);
7176
72− editor.ensure_cursor_in_view(editor.view().id);
77+ editor.ensure_cursor_in_view(view_id);
7378 }
7479 Err(_err) => (), // TODO: mark command line as error
7580 }
helix-view/src/document.rs+29−22
@@ -8,7 +8,9 @@ use helix_core::{
88 ChangeSet, Diagnostic, History, Rope, Selection, State, Syntax, Transaction,
99};
1010
11−use crate::DocumentId;
11+use crate::{DocumentId, ViewId};
12+
13+use std::collections::HashMap;
1214
1315#[derive(Copy, Clone, PartialEq, Eq, Hash)]
1416pub enum Mode {
@@ -21,6 +23,7 @@ pub struct Document {
2123 // rope + selection
2224 pub(crate) id: DocumentId,
2325 state: State,
26+ pub(crate) selections: HashMap<ViewId, Selection>,
2427
2528 path: Option<PathBuf>,
2629
@@ -73,6 +76,7 @@ impl Document {
7376 id: DocumentId::default(),
7477 path: None,
7578 state: State::new(text),
79+ selections: HashMap::default(),
7680 mode: Mode::Normal,
7781 restore_cursor: false,
7882 syntax: None,
@@ -178,12 +182,12 @@ impl Document {
178182 self.language_server = language_server;
179183 }
180184
181− pub fn set_selection(&mut self, selection: Selection) {
185+ pub fn set_selection(&mut self, view_id: ViewId, selection: Selection) {
182186 // TODO: use a transaction?
183− self.state.selection = selection;
187+ self.selections.insert(view_id, selection);
184188 }
185189
186− fn _apply(&mut self, transaction: &Transaction) -> bool {
190+ fn _apply(&mut self, transaction: &Transaction, view_id: ViewId) -> bool {
187191 let old_doc = self.text().clone();
188192
189193 let success = transaction.changes().apply(&mut self.state.doc);
@@ -191,10 +195,11 @@ impl Document {
191195 if !transaction.changes().is_empty() {
192196 // update the selection: either take the selection specified in the transaction, or map the
193197 // current selection through changes.
194− self.state.selection = transaction
198+ let selection = transaction
195199 .selection()
196200 .cloned()
197− .unwrap_or_else(|| self.selection().clone().map(transaction.changes()));
201+ .unwrap_or_else(|| self.selection(view_id).clone().map(transaction.changes()));
202+ self.set_selection(view_id, selection);
198203
199204 self.version += 1;
200205
@@ -227,14 +232,14 @@ impl Document {
227232 success
228233 }
229234
230− pub fn apply(&mut self, transaction: &Transaction) -> bool {
235+ pub fn apply(&mut self, transaction: &Transaction, view_id: ViewId) -> bool {
231236 // store the state just before any changes are made. This allows us to undo to the
232237 // state just before a transaction was applied.
233238 if self.changes.is_empty() && !transaction.changes().is_empty() {
234239 self.old_state = Some(self.state.clone());
235240 }
236241
237− let success = self._apply(&transaction);
242+ let success = self._apply(&transaction, view_id);
238243
239244 self.modified = true;
240245 // TODO: be smarter about modified by keeping track of saved version instead. That way if
@@ -249,9 +254,9 @@ impl Document {
249254 success
250255 }
251256
252− pub fn undo(&mut self) -> bool {
257+ pub fn undo(&mut self, view_id: ViewId) -> bool {
253258 if let Some(transaction) = self.history.undo() {
254− let success = self._apply(&transaction);
259+ let success = self._apply(&transaction, view_id);
255260
256261 // reset changeset to fix len
257262 self.changes = ChangeSet::new(self.text());
@@ -261,9 +266,9 @@ impl Document {
261266 false
262267 }
263268
264− pub fn redo(&mut self) -> bool {
269+ pub fn redo(&mut self, view_id: ViewId) -> bool {
265270 if let Some(transaction) = self.history.redo() {
266− let success = self._apply(&transaction);
271+ let success = self._apply(&transaction, view_id);
267272
268273 // reset changeset to fix len
269274 self.changes = ChangeSet::new(self.text());
@@ -273,7 +278,7 @@ impl Document {
273278 false
274279 }
275280
276− pub fn append_changes_to_history(&mut self) {
281+ pub fn append_changes_to_history(&mut self, view_id: ViewId) {
277282 if self.changes.is_empty() {
278283 return;
279284 }
@@ -282,7 +287,8 @@ impl Document {
282287 let changes = std::mem::replace(&mut self.changes, new_changeset);
283288 // Instead of doing this messy merge we could always commit, and based on transaction
284289 // annotations either add a new layer or compose into the previous one.
285− let transaction = Transaction::from(changes).with_selection(self.selection().clone());
290+ let transaction =
291+ Transaction::from(changes).with_selection(self.selection(view_id).clone());
286292
287293 // HAXX: we need to reconstruct the state as it was before the changes..
288294 let old_state = self.old_state.take().expect("no old_state available");
@@ -362,8 +368,8 @@ impl Document {
362368 &self.state.doc
363369 }
364370
365− pub fn selection(&self) -> &Selection {
366− &self.state.selection
371+ pub fn selection(&self, view_id: ViewId) -> &Selection {
372+ &self.selections[&view_id]
367373 }
368374
369375 pub fn relative_path(&self) -> Option<&Path> {
@@ -400,13 +406,14 @@ mod test {
400406 use helix_lsp::{lsp, Client};
401407 let text = Rope::from("hello");
402408 let mut doc = Document::new(text);
403− doc.set_selection(Selection::single(5, 5));
409+ let view = ViewId::default();
410+ doc.set_selection(view, Selection::single(5, 5));
404411
405412 // insert
406413
407− let transaction = Transaction::insert(doc.text(), doc.selection(), " world".into());
414+ let transaction = Transaction::insert(doc.text(), doc.selection(view), " world".into());
408415 let old_doc = doc.state.clone();
409− doc.apply(&transaction);
416+ doc.apply(&transaction, view);
410417 let changes = Client::changeset_to_changes(&old_doc.doc, doc.text(), transaction.changes());
411418
412419 assert_eq!(
@@ -425,7 +432,7 @@ mod test {
425432
426433 let transaction = transaction.invert(&old_doc.doc);
427434 let old_doc = doc.state.clone();
428− doc.apply(&transaction);
435+ doc.apply(&transaction, view);
429436 let changes = Client::changeset_to_changes(&old_doc.doc, doc.text(), transaction.changes());
430437
431438 // line: 0-based.
@@ -450,13 +457,13 @@ mod test {
450457
451458 // also tests that changes are layered, positions depend on previous changes.
452459
453− doc.state.selection = Selection::single(0, 5);
460+ doc.set_selection(view, Selection::single(0, 5));
454461 let transaction = Transaction::change(
455462 &doc.state.doc,
456463 vec![(0, 2, Some("aei".into())), (3, 5, Some("ou".into()))].into_iter(),
457464 );
458465 // aeilou
459− doc.apply(&transaction);
466+ doc.apply(&transaction, view);
460467 let changes =
461468 Client::changeset_to_changes(&doc.state.doc, doc.text(), transaction.changes());
462469
helix-view/src/editor.rs+23−4
@@ -91,24 +91,40 @@ impl Editor {
9191 };
9292
9393 use crate::tree::Layout;
94+ use helix_core::Selection;
9495 match action {
9596 Action::Replace => {
9697 let view = self.view();
97− let jump = (view.doc, self.documents[view.doc].selection().clone());
98+ let jump = (
99+ view.doc,
100+ self.documents[view.doc].selection(view.id).clone(),
101+ );
98102
99103 let view = self.view_mut();
100104 view.jumps.push(jump);
101105 view.doc = id;
102106 view.first_line = 0;
107+ let view_id = view.id;
108+
109+ // initialize selection for view
110+ let doc = &mut self.documents[id];
111+ doc.selections.insert(view_id, Selection::point(0));
112+
103113 return Ok(id);
104114 }
105115 Action::HorizontalSplit => {
106116 let view = View::new(id)?;
107− self.tree.split(view, Layout::Horizontal);
117+ let view_id = self.tree.split(view, Layout::Horizontal);
118+ // initialize selection for view
119+ let doc = &mut self.documents[id];
120+ doc.selections.insert(view_id, Selection::point(0));
108121 }
109122 Action::VerticalSplit => {
110123 let view = View::new(id)?;
111− self.tree.split(view, Layout::Vertical);
124+ let view_id = self.tree.split(view, Layout::Vertical);
125+ // initialize selection for view
126+ let doc = &mut self.documents[id];
127+ doc.selections.insert(view_id, Selection::point(0));
112128 }
113129 }
114130
@@ -134,6 +150,9 @@ impl Editor {
134150 smol::block_on(language_server.text_document_did_close(doc.identifier())).unwrap();
135151 }
136152
153+ // remove selection
154+ self.documents[view.doc].selections.remove(&id);
155+
137156 // self.documents.remove(view.doc);
138157 self.tree.remove(id);
139158 self._refresh();
@@ -183,7 +202,7 @@ impl Editor {
183202 const OFFSET: u16 = 7; // 1 diagnostic + 5 linenr + 1 gutter
184203 let view = self.view();
185204 let doc = &self.documents[view.doc];
186− let cursor = doc.selection().cursor();
205+ let cursor = doc.selection(view.id).cursor();
187206 if let Some(mut pos) = view.screen_coords_at_pos(doc, doc.text().slice(..), cursor) {
188207 pos.col += view.area.x as usize + OFFSET as usize;
189208 pos.row += view.area.y as usize;
helix-view/src/view.rs+1−1
@@ -74,7 +74,7 @@ impl View {
7474 }
7575
7676 pub fn ensure_cursor_in_view(&mut self, doc: &Document) {
77− let cursor = doc.selection().cursor();
77+ let cursor = doc.selection(self.id).cursor();
7878 let line = doc.text().char_to_line(cursor);
7979 let document_end = self.first_line + (self.area.height as usize).saturating_sub(2);
8080