on master help sign in
Weave through view_id references so that views into one file have independent selects.
6c4093cBlaž Hrastnik
helix-term/src/commands.rs+247−165
@@ -19,7 +19,7 @@ use std::path::{Path, PathBuf};
19use helix_view::{
19use helix_view::{
20 document::Mode,
20 document::Mode,
21 view::{View, PADDING},
21 view::{View, PADDING},
22− Document, DocumentId, Editor,
22+ Document, DocumentId, Editor, ViewId,
23};
23};
24
24
25use crossterm::event::{KeyCode, KeyEvent};
25use crossterm::event::{KeyCode, KeyEvent};
@@ -31,6 +31,7 @@ use crate::application::{LspCallbackWrapper, LspCallbacks};
31pub struct Context<'a> {
31pub struct Context<'a> {
32 pub count: usize,
32 pub count: usize,
33 pub editor: &'a mut Editor,
33 pub editor: &'a mut Editor,
34+ pub view_id: ViewId,
34
35
35 pub callback: Option<crate::compositor::Callback>,
36 pub callback: Option<crate::compositor::Callback>,
36 pub on_next_key_callback: Option<Box<dyn FnOnce(&mut Context, KeyEvent)>>,
37 pub on_next_key_callback: Option<Box<dyn FnOnce(&mut Context, KeyEvent)>>,
@@ -101,9 +102,10 @@ pub type Command = fn(cx: &mut Context);
101
102
102pub fn move_char_left(cx: &mut Context) {
103pub fn move_char_left(cx: &mut Context) {
103 let count = cx.count;
104 let count = cx.count;
105+ let view_id = cx.view_id;
104 let doc = cx.doc();
106 let doc = cx.doc();
105 let text = doc.text().slice(..);
107 let text = doc.text().slice(..);
106− let selection = doc.selection().transform(|range| {
108+ let selection = doc.selection(view_id).transform(|range| {
107 movement::move_horizontally(
109 movement::move_horizontally(
108 text,
110 text,
109 range,
111 range,
@@ -112,14 +114,15 @@ pub fn move_char_left(cx: &mut Context) {
112 false, /* extend */
114 false, /* extend */
113 )
115 )
114 });
116 });
115− doc.set_selection(selection);
117+ doc.set_selection(view_id, selection);
116}
118}
117
119
118pub fn move_char_right(cx: &mut Context) {
120pub fn move_char_right(cx: &mut Context) {
119 let count = cx.count;
121 let count = cx.count;
122+ let view_id = cx.view_id;
120 let doc = cx.doc();
123 let doc = cx.doc();
121 let text = doc.text().slice(..);
124 let text = doc.text().slice(..);
122− let selection = doc.selection().transform(|range| {
125+ let selection = doc.selection(view_id).transform(|range| {
123 movement::move_horizontally(
126 movement::move_horizontally(
124 text,
127 text,
125 range,
128 range,
@@ -128,14 +131,15 @@ pub fn move_char_right(cx: &mut Context) {
128 false, /* extend */
131 false, /* extend */
129 )
132 )
130 });
133 });
131− doc.set_selection(selection);
134+ doc.set_selection(view_id, selection);
132}
135}
133
136
134pub fn move_line_up(cx: &mut Context) {
137pub fn move_line_up(cx: &mut Context) {
135 let count = cx.count;
138 let count = cx.count;
139+ let view_id = cx.view_id;
136 let doc = cx.doc();
140 let doc = cx.doc();
137 let text = doc.text().slice(..);
141 let text = doc.text().slice(..);
138− let selection = doc.selection().transform(|range| {
142+ let selection = doc.selection(view_id).transform(|range| {
139 movement::move_vertically(
143 movement::move_vertically(
140 text,
144 text,
141 range,
145 range,
@@ -144,14 +148,15 @@ pub fn move_line_up(cx: &mut Context) {
144 false, /* extend */
148 false, /* extend */
145 )
149 )
146 });
150 });
147− doc.set_selection(selection);
151+ doc.set_selection(view_id, selection);
148}
152}
149
153
150pub fn move_line_down(cx: &mut Context) {
154pub fn move_line_down(cx: &mut Context) {
151 let count = cx.count;
155 let count = cx.count;
156+ let view_id = cx.view_id;
152 let doc = cx.doc();
157 let doc = cx.doc();
153 let text = doc.text().slice(..);
158 let text = doc.text().slice(..);
154− let selection = doc.selection().transform(|range| {
159+ let selection = doc.selection(view_id).transform(|range| {
155 movement::move_vertically(
160 movement::move_vertically(
156 text,
161 text,
157 range,
162 range,
@@ -160,12 +165,13 @@ pub fn move_line_down(cx: &mut Context) {
160 false, /* extend */
165 false, /* extend */
161 )
166 )
162 });
167 });
163− doc.set_selection(selection);
168+ doc.set_selection(view_id, selection);
164}
169}
165
170
166pub fn move_line_end(cx: &mut Context) {
171pub fn move_line_end(cx: &mut Context) {
172+ let view_id = cx.view_id;
167 let doc = cx.doc();
173 let doc = cx.doc();
168− let lines = selection_lines(doc.text(), doc.selection());
174+ let lines = selection_lines(doc.text(), doc.selection(view_id));
169
175
170 let positions = lines
176 let positions = lines
171 .into_iter()
177 .into_iter()
@@ -180,12 +186,13 @@ pub fn move_line_end(cx: &mut Context) {
180
186
181 let selection = Selection::new(positions.collect(), 0);
187 let selection = Selection::new(positions.collect(), 0);
182
188
183− doc.set_selection(selection);
189+ doc.set_selection(view_id, selection);
184}
190}
185
191
186pub fn move_line_start(cx: &mut Context) {
192pub fn move_line_start(cx: &mut Context) {
193+ let view_id = cx.view_id;
187 let doc = cx.doc();
194 let doc = cx.doc();
188− let lines = selection_lines(doc.text(), doc.selection());
195+ let lines = selection_lines(doc.text(), doc.selection(view_id));
189
196
190 let positions = lines
197 let positions = lines
191 .into_iter()
198 .into_iter()
@@ -197,7 +204,7 @@ pub fn move_line_start(cx: &mut Context) {
197
204
198 let selection = Selection::new(positions.collect(), 0);
205 let selection = Selection::new(positions.collect(), 0);
199
206
200− doc.set_selection(selection);
207+ doc.set_selection(view_id, selection);
201}
208}
202
209
203// TODO: move vs extend could take an extra type Extend/Move that would
210// 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) {
206
213
207pub fn move_next_word_start(cx: &mut Context) {
214pub fn move_next_word_start(cx: &mut Context) {
208 let count = cx.count;
215 let count = cx.count;
216+ let view_id = cx.view_id;
209 let doc = cx.doc();
217 let doc = cx.doc();
210 let text = doc.text().slice(..);
218 let text = doc.text().slice(..);
211
219
212− let selection = doc.selection().transform(|range| {
220+ let selection = doc.selection(view_id).transform(|range| {
213 let pos = movement::move_next_word_start(text, range.head, count);
221 let pos = movement::move_next_word_start(text, range.head, count);
214 Range::new(pos, pos)
222 Range::new(pos, pos)
215 });
223 });
216
224
217− doc.set_selection(selection);
225+ doc.set_selection(view_id, selection);
218}
226}
219
227
220pub fn move_prev_word_start(cx: &mut Context) {
228pub fn move_prev_word_start(cx: &mut Context) {
221 let count = cx.count;
229 let count = cx.count;
230+ let view_id = cx.view_id;
222 let doc = cx.doc();
231 let doc = cx.doc();
223 let text = doc.text().slice(..);
232 let text = doc.text().slice(..);
224
233
225− let selection = doc.selection().transform(|range| {
234+ let selection = doc.selection(view_id).transform(|range| {
226 let pos = movement::move_prev_word_start(text, range.head, count);
235 let pos = movement::move_prev_word_start(text, range.head, count);
227 Range::new(pos, pos)
236 Range::new(pos, pos)
228 });
237 });
229
238
230− doc.set_selection(selection);
239+ doc.set_selection(view_id, selection);
231}
240}
232
241
233pub fn move_next_word_end(cx: &mut Context) {
242pub fn move_next_word_end(cx: &mut Context) {
234 let count = cx.count;
243 let count = cx.count;
244+ let view_id = cx.view_id;
235 let doc = cx.doc();
245 let doc = cx.doc();
236 let text = doc.text().slice(..);
246 let text = doc.text().slice(..);
237
247
238− let selection = doc.selection().transform(|range| {
248+ let selection = doc.selection(view_id).transform(|range| {
239 let pos = movement::move_next_word_end(text, range.head, count);
249 let pos = movement::move_next_word_end(text, range.head, count);
240 Range::new(pos, pos)
250 Range::new(pos, pos)
241 });
251 });
242
252
243− doc.set_selection(selection);
253+ doc.set_selection(view_id, selection);
244}
254}
245
255
246pub fn move_file_start(cx: &mut Context) {
256pub fn move_file_start(cx: &mut Context) {
247 push_jump(cx);
257 push_jump(cx);
258+ let view_id = cx.view_id;
248 let doc = cx.doc();
259 let doc = cx.doc();
249− doc.set_selection(Selection::point(0));
260+ doc.set_selection(view_id, Selection::point(0));
250}
261}
251
262
252pub fn move_file_end(cx: &mut Context) {
263pub fn move_file_end(cx: &mut Context) {
253 push_jump(cx);
264 push_jump(cx);
265+ let view_id = cx.view_id;
254 let doc = cx.doc();
266 let doc = cx.doc();
255 let text = doc.text();
267 let text = doc.text();
256 let last_line = text.line_to_char(text.len_lines().saturating_sub(2));
268 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));
258}
270}
259
271
260pub fn extend_next_word_start(cx: &mut Context) {
272pub fn extend_next_word_start(cx: &mut Context) {
261 let count = cx.count;
273 let count = cx.count;
274+ let view_id = cx.view_id;
262 let doc = cx.doc();
275 let doc = cx.doc();
263 let text = doc.text().slice(..);
276 let text = doc.text().slice(..);
264
277
265− let selection = doc.selection().transform(|mut range| {
278+ let selection = doc.selection(view_id).transform(|mut range| {
266 let pos = movement::move_next_word_start(text, range.head, count);
279 let pos = movement::move_next_word_start(text, range.head, count);
267 Range::new(range.anchor, pos)
280 Range::new(range.anchor, pos)
268 });
281 });
269
282
270− doc.set_selection(selection);
283+ doc.set_selection(view_id, selection);
271}
284}
272
285
273pub fn extend_prev_word_start(cx: &mut Context) {
286pub fn extend_prev_word_start(cx: &mut Context) {
274 let count = cx.count;
287 let count = cx.count;
288+ let view_id = cx.view_id;
275 let doc = cx.doc();
289 let doc = cx.doc();
276 let text = doc.text().slice(..);
290 let text = doc.text().slice(..);
277
291
278− let selection = doc.selection().transform(|mut range| {
292+ let selection = doc.selection(view_id).transform(|mut range| {
279 let pos = movement::move_prev_word_start(text, range.head, count);
293 let pos = movement::move_prev_word_start(text, range.head, count);
280 Range::new(range.anchor, pos)
294 Range::new(range.anchor, pos)
281 });
295 });
282− doc.set_selection(selection);
296+ doc.set_selection(view_id, selection);
283}
297}
284
298
285pub fn extend_next_word_end(cx: &mut Context) {
299pub fn extend_next_word_end(cx: &mut Context) {
286 let count = cx.count;
300 let count = cx.count;
301+ let view_id = cx.view_id;
287 let doc = cx.doc();
302 let doc = cx.doc();
288 let text = doc.text().slice(..);
303 let text = doc.text().slice(..);
289
304
290− let selection = doc.selection().transform(|mut range| {
305+ let selection = doc.selection(view_id).transform(|mut range| {
291 let pos = movement::move_next_word_end(text, range.head, count);
306 let pos = movement::move_next_word_end(text, range.head, count);
292 Range::new(range.anchor, pos)
307 Range::new(range.anchor, pos)
293 });
308 });
294
309
295− doc.set_selection(selection);
310+ doc.set_selection(view_id, selection);
296}
311}
297
312
298#[inline]
313#[inline]
@@ -313,10 +328,11 @@ where
313 ..
328 ..
314 } = event
329 } = event
315 {
330 {
331+ let view_id = cx.view_id;
316 let doc = cx.doc();
332 let doc = cx.doc();
317 let text = doc.text().slice(..);
333 let text = doc.text().slice(..);
318
334
319− let selection = doc.selection().transform(|mut range| {
335+ let selection = doc.selection(view_id).transform(|mut range| {
320 if let Some(pos) = search::find_nth_next(text, ch, range.head, count, inclusive) {
336 if let Some(pos) = search::find_nth_next(text, ch, range.head, count, inclusive) {
321 if extend {
337 if extend {
322 Range::new(range.anchor, pos)
338 Range::new(range.anchor, pos)
@@ -330,7 +346,7 @@ where
330 }
346 }
331 });
347 });
332
348
333− doc.set_selection(selection);
349+ doc.set_selection(view_id, selection);
334 }
350 }
335 })
351 })
336}
352}
@@ -417,15 +433,16 @@ pub fn replace(cx: &mut Context) {
417 {
433 {
418 let text = Tendril::from_char(ch);
434 let text = Tendril::from_char(ch);
419
435
436+ let view_id = cx.view_id;
420 let doc = cx.doc();
437 let doc = cx.doc();
421
438
422 let transaction =
439 let transaction =
423− Transaction::change_by_selection(doc.text(), doc.selection(), |range| {
440+ Transaction::change_by_selection(doc.text(), doc.selection(view_id), |range| {
424 (range.from(), range.to() + 1, Some(text.clone()))
441 (range.from(), range.to() + 1, Some(text.clone()))
425 });
442 });
426
443
427− doc.apply(&transaction);
444+ doc.apply(&transaction, view_id);
428− doc.append_changes_to_history();
445+ doc.append_changes_to_history(view_id);
429 }
446 }
430 })
447 })
431}
448}
@@ -434,7 +451,7 @@ fn scroll(cx: &mut Context, offset: usize, direction: Direction) {
434 use Direction::*;
451 use Direction::*;
435 let view = cx.editor.view();
452 let view = cx.editor.view();
436 let doc = cx.editor.document(view.doc).unwrap();
453 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());
438 let doc_last_line = doc.text().len_lines() - 1;
455 let doc_last_line = doc.text().len_lines() - 1;
439
456
440 let last_line = view.last_line(doc);
457 let last_line = view.last_line(doc);
@@ -465,6 +482,8 @@ fn scroll(cx: &mut Context, offset: usize, direction: Direction) {
465 last_line.saturating_sub(scrolloff),
482 last_line.saturating_sub(scrolloff),
466 );
483 );
467
484
485+ let view_id = view.id;
486+
468 // view drops here
487 // view drops here
469
488
470 // upgrade to mut reference
489 // upgrade to mut reference
@@ -473,7 +492,7 @@ fn scroll(cx: &mut Context, offset: usize, direction: Direction) {
473 let text = doc.text().slice(..);
492 let text = doc.text().slice(..);
474 let pos = pos_at_coords(text, Position::new(line, cursor.col)); // this func will properly truncate to line end
493 let pos = pos_at_coords(text, Position::new(line, cursor.col)); // this func will properly truncate to line end
475
494
476− doc.set_selection(Selection::point(pos));
495+ doc.set_selection(view_id, Selection::point(pos));
477}
496}
478
497
479pub fn page_up(cx: &mut Context) {
498pub fn page_up(cx: &mut Context) {
@@ -502,9 +521,10 @@ pub fn half_page_down(cx: &mut Context) {
502
521
503pub fn extend_char_left(cx: &mut Context) {
522pub fn extend_char_left(cx: &mut Context) {
504 let count = cx.count;
523 let count = cx.count;
524+ let view_id = cx.view_id;
505 let doc = cx.doc();
525 let doc = cx.doc();
506 let text = doc.text().slice(..);
526 let text = doc.text().slice(..);
507− let selection = doc.selection().transform(|range| {
527+ let selection = doc.selection(view_id).transform(|range| {
508 movement::move_horizontally(
528 movement::move_horizontally(
509 text,
529 text,
510 range,
530 range,
@@ -513,14 +533,15 @@ pub fn extend_char_left(cx: &mut Context) {
513 true, /* extend */
533 true, /* extend */
514 )
534 )
515 });
535 });
516− doc.set_selection(selection);
536+ doc.set_selection(view_id, selection);
517}
537}
518
538
519pub fn extend_char_right(cx: &mut Context) {
539pub fn extend_char_right(cx: &mut Context) {
520 let count = cx.count;
540 let count = cx.count;
541+ let view_id = cx.view_id;
521 let doc = cx.doc();
542 let doc = cx.doc();
522 let text = doc.text().slice(..);
543 let text = doc.text().slice(..);
523− let selection = doc.selection().transform(|range| {
544+ let selection = doc.selection(view_id).transform(|range| {
524 movement::move_horizontally(
545 movement::move_horizontally(
525 text,
546 text,
526 range,
547 range,
@@ -529,14 +550,15 @@ pub fn extend_char_right(cx: &mut Context) {
529 true, /* extend */
550 true, /* extend */
530 )
551 )
531 });
552 });
532− doc.set_selection(selection);
553+ doc.set_selection(view_id, selection);
533}
554}
534
555
535pub fn extend_line_up(cx: &mut Context) {
556pub fn extend_line_up(cx: &mut Context) {
536 let count = cx.count;
557 let count = cx.count;
558+ let view_id = cx.view_id;
537 let doc = cx.doc();
559 let doc = cx.doc();
538 let text = doc.text().slice(..);
560 let text = doc.text().slice(..);
539− let selection = doc.selection().transform(|range| {
561+ let selection = doc.selection(view_id).transform(|range| {
540 movement::move_vertically(
562 movement::move_vertically(
541 text,
563 text,
542 range,
564 range,
@@ -545,14 +567,15 @@ pub fn extend_line_up(cx: &mut Context) {
545 true, /* extend */
567 true, /* extend */
546 )
568 )
547 });
569 });
548− doc.set_selection(selection);
570+ doc.set_selection(view_id, selection);
549}
571}
550
572
551pub fn extend_line_down(cx: &mut Context) {
573pub fn extend_line_down(cx: &mut Context) {
552 let count = cx.count;
574 let count = cx.count;
575+ let view_id = cx.view_id;
553 let doc = cx.doc();
576 let doc = cx.doc();
554 let text = doc.text().slice(..);
577 let text = doc.text().slice(..);
555− let selection = doc.selection().transform(|range| {
578+ let selection = doc.selection(view_id).transform(|range| {
556 movement::move_vertically(
579 movement::move_vertically(
557 text,
580 text,
558 range,
581 range,
@@ -561,21 +584,24 @@ pub fn extend_line_down(cx: &mut Context) {
561 true, /* extend */
584 true, /* extend */
562 )
585 )
563 });
586 });
564− doc.set_selection(selection);
587+ doc.set_selection(view_id, selection);
565}
588}
566
589
567pub fn select_all(cx: &mut Context) {
590pub fn select_all(cx: &mut Context) {
591+ let view_id = cx.view_id;
568 let doc = cx.doc();
592 let doc = cx.doc();
569
593
570 let end = doc.text().len_chars().saturating_sub(1);
594 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))
572}
596}
573
597
574pub fn select_regex(cx: &mut Context) {
598pub fn select_regex(cx: &mut Context) {
599+ let view_id = cx.view_id;
575− let prompt = ui::regex_prompt(cx, "select:".to_string(), |doc, regex| {
600+ let prompt = ui::regex_prompt(cx, "select:".to_string(), move |doc, regex| {
576 let text = doc.text().slice(..);
601 let text = doc.text().slice(..);
577− if let Some(selection) = selection::select_on_matches(text, doc.selection(), &regex) {
602+ if let Some(selection) = selection::select_on_matches(text, doc.selection(view_id), &regex)
603+ {
578− doc.set_selection(selection);
604+ doc.set_selection(view_id, selection);
579 }
605 }
580 });
606 });
581
607
@@ -583,23 +609,25 @@ pub fn select_regex(cx: &mut Context) {
583}
609}
584
610
585pub fn split_selection(cx: &mut Context) {
611pub fn split_selection(cx: &mut Context) {
612+ let view_id = cx.view_id;
586− let prompt = ui::regex_prompt(cx, "split:".to_string(), |doc, regex| {
613+ let prompt = ui::regex_prompt(cx, "split:".to_string(), move |doc, regex| {
587 let text = doc.text().slice(..);
614 let text = doc.text().slice(..);
588− let selection = selection::split_on_matches(text, doc.selection(), &regex);
615+ let selection = selection::split_on_matches(text, doc.selection(view_id), &regex);
589− doc.set_selection(selection);
616+ doc.set_selection(view_id, selection);
590 });
617 });
591
618
592 cx.push_layer(Box::new(prompt));
619 cx.push_layer(Box::new(prompt));
593}
620}
594
621
595pub fn split_selection_on_newline(cx: &mut Context) {
622pub fn split_selection_on_newline(cx: &mut Context) {
623+ let view_id = cx.view_id;
596 let doc = cx.doc();
624 let doc = cx.doc();
597 let text = doc.text().slice(..);
625 let text = doc.text().slice(..);
598 // only compile the regex once
626 // only compile the regex once
599 #[allow(clippy::trivial_regex)]
627 #[allow(clippy::trivial_regex)]
600 static REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"\n").unwrap());
628 static REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"\n").unwrap());
601− let selection = selection::split_on_matches(text, doc.selection(), &REGEX);
629+ let selection = selection::split_on_matches(text, doc.selection(view_id), &REGEX);
602− doc.set_selection(selection);
630+ doc.set_selection(view_id, selection);
603}
631}
604
632
605// search: searches for the first occurence in file, provides a prompt
633// search: searches for the first occurence in file, provides a prompt
@@ -609,9 +637,9 @@ pub fn split_selection_on_newline(cx: &mut Context) {
609// I'd probably collect all the matches right now and store the current index. The cache needs
637// I'd probably collect all the matches right now and store the current index. The cache needs
610// wiping if input happens.
638// wiping if input happens.
611
639
612−fn _search(doc: &mut Document, contents: &str, regex: &Regex) {
640+fn _search(doc: &mut Document, view_id: ViewId, contents: &str, regex: &Regex) {
613 let text = doc.text();
641 let text = doc.text();
614− let start = doc.selection().cursor();
642+ let start = doc.selection(view_id).cursor();
615
643
616 // TODO: use find_at to find the next match after the cursor, loop around the end
644 // TODO: use find_at to find the next match after the cursor, loop around the end
617 if let Some(mat) = regex.find_at(&contents, start) {
645 if let Some(mat) = regex.find_at(&contents, start) {
@@ -619,7 +647,7 @@ fn _search(doc: &mut Document, contents: &str, regex: &Regex) {
619 let end = text.byte_to_char(mat.end());
647 let end = text.byte_to_char(mat.end());
620 let selection = Selection::single(start, end - 1);
648 let selection = Selection::single(start, end - 1);
621 // TODO: (first_match, regex) stuff in register?
649 // TODO: (first_match, regex) stuff in register?
622− doc.set_selection(selection);
650+ doc.set_selection(view_id, selection);
623 };
651 };
624}
652}
625
653
@@ -633,10 +661,11 @@ pub fn search(cx: &mut Context) {
633 // feed chunks into the regex yet
661 // feed chunks into the regex yet
634 let contents = doc.text().slice(..).to_string();
662 let contents = doc.text().slice(..).to_string();
635
663
664+ let view_id = cx.view_id;
636 let prompt = ui::regex_prompt(cx, "search:".to_string(), move |doc, regex| {
665 let prompt = ui::regex_prompt(cx, "search:".to_string(), move |doc, regex| {
637 let text = doc.text();
666 let text = doc.text();
638− let start = doc.selection().cursor();
667+ let start = doc.selection(view_id).cursor();
639− _search(doc, &contents, &regex);
668+ _search(doc, view_id, &contents, &regex);
640
669
641 // TODO: only store on enter (accept), not update
670 // TODO: only store on enter (accept), not update
642 register::set('\\', vec![regex.as_str().to_string()]);
671 register::set('\\', vec![regex.as_str().to_string()]);
@@ -648,17 +677,19 @@ pub fn search(cx: &mut Context) {
648pub fn search_next(cx: &mut Context) {
677pub fn search_next(cx: &mut Context) {
649 if let Some(query) = register::get('\\') {
678 if let Some(query) = register::get('\\') {
650 let query = query.first().unwrap();
679 let query = query.first().unwrap();
680+ let view_id = cx.view_id;
651 let doc = cx.doc();
681 let doc = cx.doc();
652 let contents = doc.text().slice(..).to_string();
682 let contents = doc.text().slice(..).to_string();
653 let regex = Regex::new(&query).unwrap();
683 let regex = Regex::new(&query).unwrap();
654− _search(doc, &contents, &regex);
684+ _search(doc, view_id, &contents, &regex);
655 }
685 }
656}
686}
657
687
658pub fn search_selection(cx: &mut Context) {
688pub fn search_selection(cx: &mut Context) {
689+ let view_id = cx.view_id;
659 let doc = cx.doc();
690 let doc = cx.doc();
660 let contents = doc.text().slice(..);
691 let contents = doc.text().slice(..);
661− let query = doc.selection().primary().fragment(contents);
692+ let query = doc.selection(view_id).primary().fragment(contents);
662 let regex = regex::escape(&query);
693 let regex = regex::escape(&query);
663 register::set('\\', vec![regex]);
694 register::set('\\', vec![regex]);
664 search_next(cx);
695 search_next(cx);
@@ -672,22 +703,24 @@ pub fn search_selection(cx: &mut Context) {
672
703
673pub fn select_line(cx: &mut Context) {
704pub fn select_line(cx: &mut Context) {
674 let count = cx.count;
705 let count = cx.count;
706+ let view_id = cx.view_id;
675 let doc = cx.doc();
707 let doc = cx.doc();
676
708
677− let pos = doc.selection().primary();
709+ let pos = doc.selection(view_id).primary();
678 let text = doc.text();
710 let text = doc.text();
679
711
680 let line = text.char_to_line(pos.head);
712 let line = text.char_to_line(pos.head);
681 let start = text.line_to_char(line);
713 let start = text.line_to_char(line);
682 let end = text.line_to_char(line + count).saturating_sub(1);
714 let end = text.line_to_char(line + count).saturating_sub(1);
683
715
684− doc.set_selection(Selection::single(start, end));
716+ doc.set_selection(view_id, Selection::single(start, end));
685}
717}
686pub fn extend_line(cx: &mut Context) {
718pub fn extend_line(cx: &mut Context) {
719+ let view_id = cx.view_id;
687 let count = cx.count;
720 let count = cx.count;
688 let doc = cx.doc();
721 let doc = cx.doc();
689
722
690− let pos = doc.selection().primary();
723+ let pos = doc.selection(view_id).primary();
691 let text = doc.text();
724 let text = doc.text();
692
725
693 let line_start = text.char_to_line(pos.anchor);
726 let line_start = text.char_to_line(pos.anchor);
@@ -700,47 +733,52 @@ pub fn extend_line(cx: &mut Context) {
700 let start = text.line_to_char(line_start);
733 let start = text.line_to_char(line_start);
701 let end = text.line_to_char(line + 1).saturating_sub(1);
734 let end = text.line_to_char(line + 1).saturating_sub(1);
702
735
703− doc.set_selection(Selection::single(start, end));
736+ doc.set_selection(view_id, Selection::single(start, end));
704}
737}
705
738
706// heuristic: append changes to history after each command, unless we're in insert mode
739// heuristic: append changes to history after each command, unless we're in insert mode
707
740
708−fn _delete_selection(doc: &mut Document) {
741+fn _delete_selection(doc: &mut Document, view_id: ViewId) {
742+ let transaction =
709− let transaction = Transaction::change_by_selection(doc.text(), doc.selection(), |range| {
743+ Transaction::change_by_selection(doc.text(), doc.selection(view_id), |range| {
710− (range.from(), range.to() + 1, None)
744+ (range.from(), range.to() + 1, None)
711− });
745+ });
712− doc.apply(&transaction);
746+ doc.apply(&transaction, view_id);
713}
747}
714
748
715pub fn delete_selection(cx: &mut Context) {
749pub fn delete_selection(cx: &mut Context) {
750+ let view_id = cx.view_id;
716 let doc = cx.doc();
751 let doc = cx.doc();
717− _delete_selection(doc);
752+ _delete_selection(doc, view_id);
718
753
719− doc.append_changes_to_history();
754+ doc.append_changes_to_history(view_id);
720}
755}
721
756
722pub fn change_selection(cx: &mut Context) {
757pub fn change_selection(cx: &mut Context) {
758+ let view_id = cx.view_id;
723 let doc = cx.doc();
759 let doc = cx.doc();
724− _delete_selection(doc);
760+ _delete_selection(doc, view_id);
725 enter_insert_mode(doc);
761 enter_insert_mode(doc);
726}
762}
727
763
728pub fn collapse_selection(cx: &mut Context) {
764pub fn collapse_selection(cx: &mut Context) {
765+ let view_id = cx.view_id;
729 let doc = cx.doc();
766 let doc = cx.doc();
730 let selection = doc
767 let selection = doc
731− .selection()
768+ .selection(view_id)
732 .transform(|range| Range::new(range.head, range.head));
769 .transform(|range| Range::new(range.head, range.head));
733
770
734− doc.set_selection(selection);
771+ doc.set_selection(view_id, selection);
735}
772}
736
773
737pub fn flip_selections(cx: &mut Context) {
774pub fn flip_selections(cx: &mut Context) {
775+ let view_id = cx.view_id;
738 let doc = cx.doc();
776 let doc = cx.doc();
739 let selection = doc
777 let selection = doc
740− .selection()
778+ .selection(view_id)
741 .transform(|range| Range::new(range.head, range.anchor));
779 .transform(|range| Range::new(range.head, range.anchor));
742
780
743− doc.set_selection(selection);
781+ doc.set_selection(view_id, selection);
744}
782}
745
783
746fn enter_insert_mode(doc: &mut Document) {
784fn enter_insert_mode(doc: &mut Document) {
@@ -749,29 +787,31 @@ fn enter_insert_mode(doc: &mut Document) {
749
787
750// inserts at the start of each selection
788// inserts at the start of each selection
751pub fn insert_mode(cx: &mut Context) {
789pub fn insert_mode(cx: &mut Context) {
790+ let view_id = cx.view_id;
752 let doc = cx.doc();
791 let doc = cx.doc();
753 enter_insert_mode(doc);
792 enter_insert_mode(doc);
754
793
755 let selection = doc
794 let selection = doc
756− .selection()
795+ .selection(view_id)
757 .transform(|range| Range::new(range.to(), range.from()));
796 .transform(|range| Range::new(range.to(), range.from()));
758− doc.set_selection(selection);
797+ doc.set_selection(view_id, selection);
759}
798}
760
799
761// inserts at the end of each selection
800// inserts at the end of each selection
762pub fn append_mode(cx: &mut Context) {
801pub fn append_mode(cx: &mut Context) {
802+ let view_id = cx.view_id;
763 let doc = cx.doc();
803 let doc = cx.doc();
764 enter_insert_mode(doc);
804 enter_insert_mode(doc);
765 doc.restore_cursor = true;
805 doc.restore_cursor = true;
766
806
767 let text = doc.text().slice(..);
807 let text = doc.text().slice(..);
768− let selection = doc.selection().transform(|range| {
808+ let selection = doc.selection(view_id).transform(|range| {
769 Range::new(
809 Range::new(
770 range.from(),
810 range.from(),
771 graphemes::next_grapheme_boundary(text, range.to()), // to() + next char
811 graphemes::next_grapheme_boundary(text, range.to()), // to() + next char
772 )
812 )
773 });
813 });
774− doc.set_selection(selection);
814+ doc.set_selection(view_id, selection);
775}
815}
776
816
777const COMMAND_LIST: &[&str] = &["write", "open", "quit"];
817const COMMAND_LIST: &[&str] = &["write", "open", "quit"];
@@ -931,25 +971,27 @@ pub fn prepend_to_line(cx: &mut Context) {
931pub fn append_to_line(cx: &mut Context) {
971pub fn append_to_line(cx: &mut Context) {
932 move_line_end(cx);
972 move_line_end(cx);
933
973
974+ let view_id = cx.view_id;
934 let doc = cx.doc();
975 let doc = cx.doc();
935 enter_insert_mode(doc);
976 enter_insert_mode(doc);
936
977
937 // offset by another 1 char since move_line_end will position on the last char, we want to
978 // offset by another 1 char since move_line_end will position on the last char, we want to
938 // append past that
979 // append past that
939− let selection = doc.selection().transform(|range| {
980+ let selection = doc.selection(view_id).transform(|range| {
940 let pos = range.head + 1;
981 let pos = range.head + 1;
941 Range::new(pos, pos)
982 Range::new(pos, pos)
942 });
983 });
943− doc.set_selection(selection);
984+ doc.set_selection(view_id, selection);
944}
985}
945
986
946// o inserts a new line after each line with a selection
987// o inserts a new line after each line with a selection
947pub fn open_below(cx: &mut Context) {
988pub fn open_below(cx: &mut Context) {
989+ let view_id = cx.view_id;
948 let count = cx.count;
990 let count = cx.count;
949 let doc = cx.doc();
991 let doc = cx.doc();
950 enter_insert_mode(doc);
992 enter_insert_mode(doc);
951
993
952− let lines = selection_lines(doc.text(), doc.selection());
994+ let lines = selection_lines(doc.text(), doc.selection(view_id));
953
995
954 let positions = lines.into_iter().map(|index| {
996 let positions = lines.into_iter().map(|index| {
955 // adjust all positions to the end of the line (next line minus one)
997 // adjust all positions to the end of the line (next line minus one)
@@ -991,16 +1033,17 @@ pub fn open_below(cx: &mut Context) {
991 let transaction =
1033 let transaction =
992 Transaction::change(doc.text(), changes.into_iter()).with_selection(selection);
1034 Transaction::change(doc.text(), changes.into_iter()).with_selection(selection);
993
1035
994− doc.apply(&transaction);
1036+ doc.apply(&transaction, view_id);
995}
1037}
996
1038
997// O inserts a new line before each line with a selection
1039// O inserts a new line before each line with a selection
998pub fn open_above(cx: &mut Context) {
1040pub fn open_above(cx: &mut Context) {
1041+ let view_id = cx.view_id;
999 let count = cx.count;
1042 let count = cx.count;
1000 let doc = cx.doc();
1043 let doc = cx.doc();
1001 enter_insert_mode(doc);
1044 enter_insert_mode(doc);
1002
1045
1003− let lines = selection_lines(doc.text(), doc.selection());
1046+ let lines = selection_lines(doc.text(), doc.selection(view_id));
1004
1047
1005 let positions = lines.into_iter().map(|index| {
1048 let positions = lines.into_iter().map(|index| {
1006 // adjust all positions to the end of the previous line
1049 // adjust all positions to the end of the previous line
@@ -1043,26 +1086,27 @@ pub fn open_above(cx: &mut Context) {
1043 let transaction =
1086 let transaction =
1044 Transaction::change(doc.text(), changes.into_iter()).with_selection(selection);
1087 Transaction::change(doc.text(), changes.into_iter()).with_selection(selection);
1045
1088
1046− doc.apply(&transaction);
1089+ doc.apply(&transaction, view_id);
1047}
1090}
1048
1091
1049pub fn normal_mode(cx: &mut Context) {
1092pub fn normal_mode(cx: &mut Context) {
1093+ let view_id = cx.view_id;
1050 let doc = cx.doc();
1094 let doc = cx.doc();
1051
1095
1052 doc.mode = Mode::Normal;
1096 doc.mode = Mode::Normal;
1053
1097
1054− doc.append_changes_to_history();
1098+ doc.append_changes_to_history(view_id);
1055
1099
1056 // if leaving append mode, move cursor back by 1
1100 // if leaving append mode, move cursor back by 1
1057 if doc.restore_cursor {
1101 if doc.restore_cursor {
1058 let text = doc.text().slice(..);
1102 let text = doc.text().slice(..);
1059− let selection = doc.selection().transform(|range| {
1103+ let selection = doc.selection(view_id).transform(|range| {
1060 Range::new(
1104 Range::new(
1061 range.from(),
1105 range.from(),
1062 graphemes::prev_grapheme_boundary(text, range.to()),
1106 graphemes::prev_grapheme_boundary(text, range.to()),
1063 )
1107 )
1064 });
1108 });
1065− doc.set_selection(selection);
1109+ doc.set_selection(view_id, selection);
1066
1110
1067 doc.restore_cursor = false;
1111 doc.restore_cursor = false;
1068 }
1112 }
@@ -1071,13 +1115,15 @@ pub fn normal_mode(cx: &mut Context) {
1071// Store a jump on the jumplist.
1115// Store a jump on the jumplist.
1072fn push_jump(cx: &mut Context) {
1116fn push_jump(cx: &mut Context) {
1073 let jump = {
1117 let jump = {
1118+ let view_id = cx.view_id;
1074 let doc = cx.doc();
1119 let doc = cx.doc();
1075− (doc.id(), doc.selection().clone())
1120+ (doc.id(), doc.selection(view_id).clone())
1076 };
1121 };
1077 cx.view().jumps.push(jump);
1122 cx.view().jumps.push(jump);
1078}
1123}
1079
1124
1080pub fn goto_mode(cx: &mut Context) {
1125pub fn goto_mode(cx: &mut Context) {
1126+ let view_id = cx.view_id;
1081 let count = cx.count;
1127 let count = cx.count;
1082
1128
1083 if count > 1 {
1129 if count > 1 {
@@ -1087,7 +1133,7 @@ pub fn goto_mode(cx: &mut Context) {
1087 // to 1g
1133 // to 1g
1088 let doc = cx.doc();
1134 let doc = cx.doc();
1089 let pos = doc.text().line_to_char(count - 1);
1135 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));
1091 return;
1137 return;
1092 }
1138 }
1093
1139
@@ -1128,10 +1174,11 @@ fn _goto(cx: &mut Context, locations: Vec<lsp::Location>) {
1128 let id = editor
1174 let id = editor
1129 .open(PathBuf::from(location.uri.path()), action)
1175 .open(PathBuf::from(location.uri.path()), action)
1130 .expect("editor.open failed");
1176 .expect("editor.open failed");
1177+ let view_id = editor.view().id;
1131 let doc = &mut editor.documents[id];
1178 let doc = &mut editor.documents[id];
1132 let definition_pos = location.range.start;
1179 let definition_pos = location.range.start;
1133 let new_pos = helix_lsp::util::lsp_pos_to_pos(doc.text(), definition_pos);
1180 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));
1135 }
1182 }
1136
1183
1137 match locations.as_slice() {
1184 match locations.as_slice() {
@@ -1155,6 +1202,7 @@ fn _goto(cx: &mut Context, locations: Vec<lsp::Location>) {
1155}
1202}
1156
1203
1157pub fn goto_definition(cx: &mut Context) {
1204pub fn goto_definition(cx: &mut Context) {
1205+ let view_id = cx.view_id;
1158 let doc = cx.doc();
1206 let doc = cx.doc();
1159 let language_server = match doc.language_server() {
1207 let language_server = match doc.language_server() {
1160 Some(language_server) => language_server,
1208 Some(language_server) => language_server,
@@ -1162,7 +1210,7 @@ pub fn goto_definition(cx: &mut Context) {
1162 };
1210 };
1163
1211
1164 // TODO: blocking here is not ideal
1212 // 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());
1166
1214
1167 // TODO: handle fails
1215 // TODO: handle fails
1168 let res =
1216 let res =
@@ -1171,6 +1219,7 @@ pub fn goto_definition(cx: &mut Context) {
1171}
1219}
1172
1220
1173pub fn goto_type_definition(cx: &mut Context) {
1221pub fn goto_type_definition(cx: &mut Context) {
1222+ let view_id = cx.view_id;
1174 let doc = cx.doc();
1223 let doc = cx.doc();
1175 let language_server = match doc.language_server() {
1224 let language_server = match doc.language_server() {
1176 Some(language_server) => language_server,
1225 Some(language_server) => language_server,
@@ -1178,7 +1227,7 @@ pub fn goto_type_definition(cx: &mut Context) {
1178 };
1227 };
1179
1228
1180 // TODO: blocking here is not ideal
1229 // 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());
1182
1231
1183 // TODO: handle fails
1232 // TODO: handle fails
1184 let res = smol::block_on(language_server.goto_type_definition(doc.identifier(), pos))
1233 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) {
1187}
1236}
1188
1237
1189pub fn goto_implementation(cx: &mut Context) {
1238pub fn goto_implementation(cx: &mut Context) {
1239+ let view_id = cx.view_id;
1190 let doc = cx.doc();
1240 let doc = cx.doc();
1191 let language_server = match doc.language_server() {
1241 let language_server = match doc.language_server() {
1192 Some(language_server) => language_server,
1242 Some(language_server) => language_server,
@@ -1194,7 +1244,7 @@ pub fn goto_implementation(cx: &mut Context) {
1194 };
1244 };
1195
1245
1196 // TODO: blocking here is not ideal
1246 // 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());
1198
1248
1199 // TODO: handle fails
1249 // TODO: handle fails
1200 let res = smol::block_on(language_server.goto_implementation(doc.identifier(), pos))
1250 let res = smol::block_on(language_server.goto_implementation(doc.identifier(), pos))
@@ -1203,6 +1253,7 @@ pub fn goto_implementation(cx: &mut Context) {
1203}
1253}
1204
1254
1205pub fn goto_reference(cx: &mut Context) {
1255pub fn goto_reference(cx: &mut Context) {
1256+ let view_id = cx.view_id;
1206 let doc = cx.doc();
1257 let doc = cx.doc();
1207 let language_server = match doc.language_server() {
1258 let language_server = match doc.language_server() {
1208 Some(language_server) => language_server,
1259 Some(language_server) => language_server,
@@ -1210,7 +1261,7 @@ pub fn goto_reference(cx: &mut Context) {
1210 };
1261 };
1211
1262
1212 // TODO: blocking here is not ideal
1263 // 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());
1214
1265
1215 // TODO: handle fails
1266 // TODO: handle fails
1216 let res =
1267 let res =
@@ -1219,6 +1270,7 @@ pub fn goto_reference(cx: &mut Context) {
1219}
1270}
1220
1271
1221pub fn signature_help(cx: &mut Context) {
1272pub fn signature_help(cx: &mut Context) {
1273+ let view_id = cx.view_id;
1222 let doc = cx.doc();
1274 let doc = cx.doc();
1223
1275
1224 let language_server = match doc.language_server() {
1276 let language_server = match doc.language_server() {
@@ -1227,7 +1279,7 @@ pub fn signature_help(cx: &mut Context) {
1227 };
1279 };
1228
1280
1229 // TODO: blocking here is not ideal
1281 // 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());
1231
1283
1232 // TODO: handle fails
1284 // TODO: handle fails
1233
1285
@@ -1320,20 +1372,21 @@ pub mod insert {
1320
1372
1321 // TODO: insert means add text just before cursor, on exit we should be on the last letter.
1373 // TODO: insert means add text just before cursor, on exit we should be on the last letter.
1322 pub fn insert_char(cx: &mut Context, c: char) {
1374 pub fn insert_char(cx: &mut Context, c: char) {
1375+ let view_id = cx.view_id;
1323 let doc = cx.doc();
1376 let doc = cx.doc();
1324
1377
1325 // run through insert hooks, stopping on the first one that returns Some(t)
1378 // run through insert hooks, stopping on the first one that returns Some(t)
1326 for hook in HOOKS {
1379 for hook in HOOKS {
1327− if let Some(transaction) = hook(doc.text(), doc.selection(), c) {
1380+ if let Some(transaction) = hook(doc.text(), doc.selection(view_id), c) {
1328− doc.apply(&transaction);
1381+ doc.apply(&transaction, view_id);
1329 return;
1382 return;
1330 }
1383 }
1331 }
1384 }
1332
1385
1333 let t = Tendril::from_char(c);
1386 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);
1335
1388
1336− doc.apply(&transaction);
1389+ doc.apply(&transaction, view_id);
1337
1390
1338 // TODO: need a post insert hook too for certain triggers (autocomplete, signature help, etc)
1391 // TODO: need a post insert hook too for certain triggers (autocomplete, signature help, etc)
1339 // this could also generically look at Transaction, but it's a bit annoying to look at
1392 // this could also generically look at Transaction, but it's a bit annoying to look at
@@ -1344,58 +1397,69 @@ pub mod insert {
1344 }
1397 }
1345
1398
1346 pub fn insert_tab(cx: &mut Context) {
1399 pub fn insert_tab(cx: &mut Context) {
1400+ let view_id = cx.view_id;
1347 let doc = cx.doc();
1401 let doc = cx.doc();
1348 // TODO: round out to nearest indentation level (for example a line with 3 spaces should
1402 // TODO: round out to nearest indentation level (for example a line with 3 spaces should
1349 // indent by one to reach 4 spaces).
1403 // indent by one to reach 4 spaces).
1350
1404
1351 let indent = Tendril::from(doc.indent_unit());
1405 let indent = Tendril::from(doc.indent_unit());
1352− let transaction = Transaction::insert(doc.text(), doc.selection(), indent);
1406+ let transaction = Transaction::insert(doc.text(), doc.selection(view_id), indent);
1353− doc.apply(&transaction);
1407+ doc.apply(&transaction, view_id);
1354 }
1408 }
1355
1409
1356 pub fn insert_newline(cx: &mut Context) {
1410 pub fn insert_newline(cx: &mut Context) {
1411+ let view_id = cx.view_id;
1357 let doc = cx.doc();
1412 let doc = cx.doc();
1358 let text = doc.text().slice(..);
1413 let text = doc.text().slice(..);
1414+ let transaction =
1359− let transaction = Transaction::change_by_selection(doc.text(), doc.selection(), |range| {
1415+ Transaction::change_by_selection(doc.text(), doc.selection(view_id), |range| {
1360− // TODO: offset range.head by 1? when calculating?
1416+ // 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);
1417+ let indent_level = helix_core::indent::suggested_indent_for_pos(
1418+ doc.syntax(),
1419+ text,
1420+ range.head,
1421+ true,
1422+ );
1363− let indent = doc.indent_unit().repeat(indent_level);
1423+ let indent = doc.indent_unit().repeat(indent_level);
1364− let mut text = String::with_capacity(1 + indent.len());
1424+ let mut text = String::with_capacity(1 + indent.len());
1365− text.push('\n');
1425+ text.push('\n');
1366− text.push_str(&indent);
1426+ text.push_str(&indent);
1367− (range.head, range.head, Some(text.into()))
1427+ (range.head, range.head, Some(text.into()))
1368− });
1428+ });
1369− doc.apply(&transaction);
1429+ doc.apply(&transaction, view_id);
1370 }
1430 }
1371
1431
1372 // TODO: handle indent-aware delete
1432 // TODO: handle indent-aware delete
1373 pub fn delete_char_backward(cx: &mut Context) {
1433 pub fn delete_char_backward(cx: &mut Context) {
1434+ let view_id = cx.view_id;
1374 let count = cx.count;
1435 let count = cx.count;
1375 let doc = cx.doc();
1436 let doc = cx.doc();
1376 let text = doc.text().slice(..);
1437 let text = doc.text().slice(..);
1438+ let transaction =
1377− let transaction = Transaction::change_by_selection(doc.text(), doc.selection(), |range| {
1439+ Transaction::change_by_selection(doc.text(), doc.selection(view_id), |range| {
1378− (
1440+ (
1379− graphemes::nth_prev_grapheme_boundary(text, range.head, count),
1441+ graphemes::nth_prev_grapheme_boundary(text, range.head, count),
1380− range.head,
1442+ range.head,
1381− None,
1443+ None,
1382− )
1444+ )
1383− });
1445+ });
1384− doc.apply(&transaction);
1446+ doc.apply(&transaction, view_id);
1385 }
1447 }
1386
1448
1387 pub fn delete_char_forward(cx: &mut Context) {
1449 pub fn delete_char_forward(cx: &mut Context) {
1450+ let view_id = cx.view_id;
1388 let count = cx.count;
1451 let count = cx.count;
1389 let doc = cx.doc();
1452 let doc = cx.doc();
1390 let text = doc.text().slice(..);
1453 let text = doc.text().slice(..);
1454+ let transaction =
1391− let transaction = Transaction::change_by_selection(doc.text(), doc.selection(), |range| {
1455+ Transaction::change_by_selection(doc.text(), doc.selection(view_id), |range| {
1392− (
1456+ (
1393− range.head,
1457+ range.head,
1394− graphemes::nth_next_grapheme_boundary(text, range.head, count),
1458+ graphemes::nth_next_grapheme_boundary(text, range.head, count),
1395− None,
1459+ None,
1396− )
1460+ )
1397− });
1461+ });
1398− doc.apply(&transaction);
1462+ doc.apply(&transaction, view_id);
1399 }
1463 }
1400}
1464}
1401
1465
@@ -1405,20 +1469,23 @@ pub mod insert {
1405// storing it?
1469// storing it?
1406
1470
1407pub fn undo(cx: &mut Context) {
1471pub fn undo(cx: &mut Context) {
1472+ let view_id = cx.view_id;
1408− cx.doc().undo();
1473+ cx.doc().undo(view_id);
1409}
1474}
1410
1475
1411pub fn redo(cx: &mut Context) {
1476pub fn redo(cx: &mut Context) {
1477+ let view_id = cx.view_id;
1412− cx.doc().redo();
1478+ cx.doc().redo(view_id);
1413}
1479}
1414
1480
1415// Yank / Paste
1481// Yank / Paste
1416
1482
1417pub fn yank(cx: &mut Context) {
1483pub fn yank(cx: &mut Context) {
1418 // TODO: should selections be made end inclusive?
1484 // TODO: should selections be made end inclusive?
1485+ let view_id = cx.view_id;
1419 let doc = cx.doc();
1486 let doc = cx.doc();
1420 let values: Vec<String> = doc
1487 let values: Vec<String> = doc
1421− .selection()
1488+ .selection(view_id)
1422 .fragments(doc.text().slice(..))
1489 .fragments(doc.text().slice(..))
1423 .map(|cow| cow.into_owned())
1490 .map(|cow| cow.into_owned())
1424 .collect();
1491 .collect();
@@ -1461,32 +1528,33 @@ pub fn paste(cx: &mut Context) {
1461
1528
1462 let mut values = values.into_iter().map(Tendril::from).chain(repeat);
1529 let mut values = values.into_iter().map(Tendril::from).chain(repeat);
1463
1530
1531+ let view_id = cx.view_id;
1464 let doc = cx.doc();
1532 let doc = cx.doc();
1465
1533
1466 let transaction = if linewise {
1534 let transaction = if linewise {
1467 // paste on the next line
1535 // paste on the next line
1468 // TODO: can simply take a range + modifier and compute the right pos without ifs
1536 // TODO: can simply take a range + modifier and compute the right pos without ifs
1469 let text = doc.text();
1537 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| {
1471 let line_end = text.line_to_char(text.char_to_line(range.head) + 1);
1539 let line_end = text.line_to_char(text.char_to_line(range.head) + 1);
1472 (line_end, line_end, Some(values.next().unwrap()))
1540 (line_end, line_end, Some(values.next().unwrap()))
1473 })
1541 })
1474 } else {
1542 } else {
1475− Transaction::change_by_selection(doc.text(), doc.selection(), |range| {
1543+ Transaction::change_by_selection(doc.text(), doc.selection(view_id), |range| {
1476 (range.head + 1, range.head + 1, Some(values.next().unwrap()))
1544 (range.head + 1, range.head + 1, Some(values.next().unwrap()))
1477 })
1545 })
1478 };
1546 };
1479
1547
1480− doc.apply(&transaction);
1548+ doc.apply(&transaction, view_id);
1481− doc.append_changes_to_history();
1549+ doc.append_changes_to_history(view_id);
1482 }
1550 }
1483}
1551}
1484
1552
1485−fn get_lines(doc: &Document) -> Vec<usize> {
1553+fn get_lines(doc: &Document, view_id: ViewId) -> Vec<usize> {
1486 let mut lines = Vec::new();
1554 let mut lines = Vec::new();
1487
1555
1488 // Get all line numbers
1556 // Get all line numbers
1489− for range in doc.selection() {
1557+ for range in doc.selection(view_id) {
1490 let start = doc.text().char_to_line(range.from());
1558 let start = doc.text().char_to_line(range.from());
1491 let end = doc.text().char_to_line(range.to());
1559 let end = doc.text().char_to_line(range.to());
1492
1560
@@ -1500,8 +1568,9 @@ fn get_lines(doc: &Document) -> Vec<usize> {
1500}
1568}
1501
1569
1502pub fn indent(cx: &mut Context) {
1570pub fn indent(cx: &mut Context) {
1571+ let view_id = cx.view_id;
1503 let doc = cx.doc();
1572 let doc = cx.doc();
1504− let lines = get_lines(doc);
1573+ let lines = get_lines(doc, view_id);
1505
1574
1506 // Indent by one level
1575 // Indent by one level
1507 let indent = Tendril::from(doc.indent_unit());
1576 let indent = Tendril::from(doc.indent_unit());
@@ -1513,13 +1582,14 @@ pub fn indent(cx: &mut Context) {
1513 (pos, pos, Some(indent.clone()))
1582 (pos, pos, Some(indent.clone()))
1514 }),
1583 }),
1515 );
1584 );
1516− doc.apply(&transaction);
1585+ doc.apply(&transaction, view_id);
1517− doc.append_changes_to_history();
1586+ doc.append_changes_to_history(view_id);
1518}
1587}
1519
1588
1520pub fn unindent(cx: &mut Context) {
1589pub fn unindent(cx: &mut Context) {
1590+ let view_id = cx.view_id;
1521 let doc = cx.doc();
1591 let doc = cx.doc();
1522− let lines = get_lines(doc);
1592+ let lines = get_lines(doc, view_id);
1523 let mut changes = Vec::with_capacity(lines.len());
1593 let mut changes = Vec::with_capacity(lines.len());
1524 let tab_width = doc.tab_width();
1594 let tab_width = doc.tab_width();
1525
1595
@@ -1547,12 +1617,13 @@ pub fn unindent(cx: &mut Context) {
1547
1617
1548 let transaction = Transaction::change(doc.text(), changes.into_iter());
1618 let transaction = Transaction::change(doc.text(), changes.into_iter());
1549
1619
1550− doc.apply(&transaction);
1620+ doc.apply(&transaction, view_id);
1551− doc.append_changes_to_history();
1621+ doc.append_changes_to_history(view_id);
1552}
1622}
1553
1623
1554pub fn format_selections(cx: &mut Context) {
1624pub fn format_selections(cx: &mut Context) {
1555 use helix_lsp::lsp;
1625 use helix_lsp::lsp;
1626+ let view_id = cx.view_id;
1556 let doc = cx.doc();
1627 let doc = cx.doc();
1557
1628
1558 // via lsp if available
1629 // via lsp if available
@@ -1561,7 +1632,7 @@ pub fn format_selections(cx: &mut Context) {
1561 // TODO: blocking here is not ideal
1632 // TODO: blocking here is not ideal
1562
1633
1563 let ranges: Vec<lsp::Range> = doc
1634 let ranges: Vec<lsp::Range> = doc
1564− .selection()
1635+ .selection(view_id)
1565 .iter()
1636 .iter()
1566 .map(|range| helix_lsp::util::range_to_lsp_range(doc.text(), *range))
1637 .map(|range| helix_lsp::util::range_to_lsp_range(doc.text(), *range))
1567 .collect();
1638 .collect();
@@ -1583,14 +1654,15 @@ pub fn format_selections(cx: &mut Context) {
1583
1654
1584 let transaction = helix_lsp::util::generate_transaction_from_edits(doc.text(), edits);
1655 let transaction = helix_lsp::util::generate_transaction_from_edits(doc.text(), edits);
1585
1656
1586− doc.apply(&transaction);
1657+ doc.apply(&transaction, view_id);
1587 }
1658 }
1588
1659
1589− doc.append_changes_to_history();
1660+ doc.append_changes_to_history(view_id);
1590}
1661}
1591
1662
1592pub fn join_selections(cx: &mut Context) {
1663pub fn join_selections(cx: &mut Context) {
1593 use movement::skip_over_next;
1664 use movement::skip_over_next;
1665+ let view_id = cx.view_id;
1594 let doc = cx.doc();
1666 let doc = cx.doc();
1595 let text = doc.text();
1667 let text = doc.text();
1596 let slice = doc.text().slice(..);
1668 let slice = doc.text().slice(..);
@@ -1598,7 +1670,7 @@ pub fn join_selections(cx: &mut Context) {
1598 let mut changes = Vec::new();
1670 let mut changes = Vec::new();
1599 let fragment = Tendril::from(" ");
1671 let fragment = Tendril::from(" ");
1600
1672
1601− for selection in doc.selection() {
1673+ for selection in doc.selection(view_id) {
1602 let start = text.char_to_line(selection.from());
1674 let start = text.char_to_line(selection.from());
1603 let mut end = text.char_to_line(selection.to());
1675 let mut end = text.char_to_line(selection.to());
1604 if start == end {
1676 if start == end {
@@ -1629,17 +1701,18 @@ pub fn join_selections(cx: &mut Context) {
1629 // TODO: select inserted spaces
1701 // TODO: select inserted spaces
1630 // .with_selection(selection);
1702 // .with_selection(selection);
1631
1703
1632− doc.apply(&transaction);
1704+ doc.apply(&transaction, view_id);
1633− doc.append_changes_to_history();
1705+ doc.append_changes_to_history(view_id);
1634}
1706}
1635
1707
1636pub fn keep_selections(cx: &mut Context) {
1708pub fn keep_selections(cx: &mut Context) {
1637 // keep selections matching regex
1709 // keep selections matching regex
1710+ let view_id = cx.view_id;
1638− let prompt = ui::regex_prompt(cx, "keep:".to_string(), |doc, regex| {
1711+ let prompt = ui::regex_prompt(cx, "keep:".to_string(), move |doc, regex| {
1639 let text = doc.text().slice(..);
1712 let text = doc.text().slice(..);
1640
1713
1641− if let Some(selection) = selection::keep_matches(text, doc.selection(), &regex) {
1714+ if let Some(selection) = selection::keep_matches(text, doc.selection(view_id), &regex) {
1642− doc.set_selection(selection);
1715+ doc.set_selection(view_id, selection);
1643 }
1716 }
1644 });
1717 });
1645
1718
@@ -1647,11 +1720,12 @@ pub fn keep_selections(cx: &mut Context) {
1647}
1720}
1648
1721
1649pub fn keep_primary_selection(cx: &mut Context) {
1722pub fn keep_primary_selection(cx: &mut Context) {
1723+ let view_id = cx.view_id;
1650 let doc = cx.doc();
1724 let doc = cx.doc();
1651
1725
1652− let range = doc.selection().primary();
1726+ let range = doc.selection(view_id).primary();
1653 let selection = Selection::single(range.anchor, range.head);
1727 let selection = Selection::single(range.anchor, range.head);
1654− doc.set_selection(selection);
1728+ doc.set_selection(view_id, selection);
1655}
1729}
1656
1730
1657//
1731//
@@ -1700,6 +1774,7 @@ pub fn completion(cx: &mut Context) {
1700 // The prefix still has to satisfy `company-minimum-prefix-length' before that
1774 // The prefix still has to satisfy `company-minimum-prefix-length' before that
1701 // happens. The value of nil means no idle completion."
1775 // happens. The value of nil means no idle completion."
1702
1776
1777+ let view_id = cx.view_id;
1703 let doc = cx.doc();
1778 let doc = cx.doc();
1704
1779
1705 let language_server = match doc.language_server() {
1780 let language_server = match doc.language_server() {
@@ -1708,13 +1783,13 @@ pub fn completion(cx: &mut Context) {
1708 };
1783 };
1709
1784
1710 // TODO: blocking here is not ideal
1785 // 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());
1712
1787
1713 // TODO: handle fails
1788 // TODO: handle fails
1714
1789
1715 let res = smol::block_on(language_server.completion(doc.identifier(), pos)).unwrap();
1790 let res = smol::block_on(language_server.completion(doc.identifier(), pos)).unwrap();
1716
1791
1717− let trigger_offset = doc.selection().cursor();
1792+ let trigger_offset = doc.selection(view_id).cursor();
1718
1793
1719 cx.callback(
1794 cx.callback(
1720 res,
1795 res,
@@ -1751,6 +1826,7 @@ pub fn completion(cx: &mut Context) {
1751pub fn hover(cx: &mut Context) {
1826pub fn hover(cx: &mut Context) {
1752 use helix_lsp::lsp;
1827 use helix_lsp::lsp;
1753
1828
1829+ let view_id = cx.view_id;
1754 let doc = cx.doc();
1830 let doc = cx.doc();
1755
1831
1756 let language_server = match doc.language_server() {
1832 let language_server = match doc.language_server() {
@@ -1762,7 +1838,7 @@ pub fn hover(cx: &mut Context) {
1762
1838
1763 // TODO: blocking here is not ideal, make commands async fn?
1839 // TODO: blocking here is not ideal, make commands async fn?
1764 // not like we can process additional input meanwhile though
1840 // 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());
1766
1842
1767 // TODO: handle fails
1843 // TODO: handle fails
1768 let res = smol::block_on(language_server.text_document_hover(doc.identifier(), pos))
1844 let res = smol::block_on(language_server.text_document_hover(doc.identifier(), pos))
@@ -1798,33 +1874,36 @@ pub fn next_view(cx: &mut Context) {
1798
1874
1799// comments
1875// comments
1800pub fn toggle_comments(cx: &mut Context) {
1876pub fn toggle_comments(cx: &mut Context) {
1877+ let view_id = cx.view_id;
1801 let doc = cx.doc();
1878 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));
1803
1880
1804− doc.apply(&transaction);
1881+ doc.apply(&transaction, view_id);
1805− doc.append_changes_to_history();
1882+ doc.append_changes_to_history(view_id);
1806}
1883}
1807
1884
1808// tree sitter node selection
1885// tree sitter node selection
1809
1886
1810pub fn expand_selection(cx: &mut Context) {
1887pub fn expand_selection(cx: &mut Context) {
1888+ let view_id = cx.view_id;
1811 let doc = cx.doc();
1889 let doc = cx.doc();
1812
1890
1813 if let Some(syntax) = doc.syntax() {
1891 if let Some(syntax) = doc.syntax() {
1814 let text = doc.text().slice(..);
1892 let text = doc.text().slice(..);
1815− let selection = object::expand_selection(syntax, text, doc.selection());
1893+ let selection = object::expand_selection(syntax, text, doc.selection(view_id));
1816− doc.set_selection(selection);
1894+ doc.set_selection(view_id, selection);
1817 }
1895 }
1818}
1896}
1819
1897
1820pub fn match_brackets(cx: &mut Context) {
1898pub fn match_brackets(cx: &mut Context) {
1899+ let view_id = cx.view_id;
1821 let doc = cx.doc();
1900 let doc = cx.doc();
1822
1901
1823 if let Some(syntax) = doc.syntax() {
1902 if let Some(syntax) = doc.syntax() {
1824− let pos = doc.selection().cursor();
1903+ let pos = doc.selection(view_id).cursor();
1825 if let Some(pos) = match_brackets::find(syntax, doc.text(), pos) {
1904 if let Some(pos) = match_brackets::find(syntax, doc.text(), pos) {
1826 let selection = Selection::point(pos);
1905 let selection = Selection::point(pos);
1827− doc.set_selection(selection);
1906+ doc.set_selection(view_id, selection);
1828 };
1907 };
1829 }
1908 }
1830}
1909}
@@ -1836,6 +1915,7 @@ pub fn jump_forward(cx: &mut Context) {
1836 let view = cx.view();
1915 let view = cx.view();
1837
1916
1838 if let Some((id, selection)) = view.jumps.forward(count) {
1917 if let Some((id, selection)) = view.jumps.forward(count) {
1918+ // TODO: position first_line so that main cursor is centered
1839 view.first_line = 0;
1919 view.first_line = 0;
1840 view.doc = *id;
1920 view.doc = *id;
1841 };
1921 };
@@ -1846,11 +1926,13 @@ pub fn jump_backward(cx: &mut Context) {
1846 let view = cx.view();
1926 let view = cx.view();
1847
1927
1848 if let Some((id, selection)) = view.jumps.backward(count) {
1928 if let Some((id, selection)) = view.jumps.backward(count) {
1929+ // TODO: position first_line so that main cursor is centered
1849 view.first_line = 0;
1930 view.first_line = 0;
1850 view.doc = *id;
1931 view.doc = *id;
1851 let selection = selection.clone();
1932 let selection = selection.clone();
1933+ let view_id = view.id;
1852 let doc = cx.doc();
1934 let doc = cx.doc();
1853− doc.set_selection(selection);
1935+ doc.set_selection(view_id, selection);
1854 };
1936 };
1855}
1937}
1856
1938
helix-term/src/ui/completion.rs+26−6
@@ -21,6 +21,7 @@ use lsp::CompletionItem;
21pub struct Completion {
21pub struct Completion {
22 popup: Popup<Menu<CompletionItem>>, // TODO: Popup<Menu> need to be able to access contents.
22 popup: Popup<Menu<CompletionItem>>, // TODO: Popup<Menu> need to be able to access contents.
23 trigger_offset: usize,
23 trigger_offset: usize,
24+ // TODO: maintain a completioncontext with trigger kind & trigger char
24}
25}
25
26
26impl Completion {
27impl Completion {
@@ -43,7 +44,9 @@ impl Completion {
43 // doc.state = snapshot.clone();
44 // doc.state = snapshot.clone();
44 }
45 }
45 PromptEvent::Validate => {
46 PromptEvent::Validate => {
46− let id = editor.view().doc;
47+ let view = editor.view();
48+ let view_id = view.id;
49+ let id = view.doc;
47 let doc = &mut editor.documents[id];
50 let doc = &mut editor.documents[id];
48
51
49 // revert state to what it was before the last update
52 // revert state to what it was before the last update
@@ -89,18 +92,18 @@ impl Completion {
89 }
92 }
90
93
91 // if more text was entered, remove it
94 // if more text was entered, remove it
92− let cursor = doc.selection().cursor();
95+ let cursor = doc.selection(view_id).cursor();
93 if trigger_offset < cursor {
96 if trigger_offset < cursor {
94 let remove = Transaction::change(
97 let remove = Transaction::change(
95 doc.text(),
98 doc.text(),
96 vec![(trigger_offset, cursor, None)].into_iter(),
99 vec![(trigger_offset, cursor, None)].into_iter(),
97 );
100 );
98− doc.apply(&remove);
101+ doc.apply(&remove, view_id);
99 }
102 }
100
103
101 let transaction =
104 let transaction =
102 util::generate_transaction_from_edits(doc.text(), vec![edit]);
105 util::generate_transaction_from_edits(doc.text(), vec![edit]);
103− doc.apply(&transaction);
106+ doc.apply(&transaction, view_id);
104 }
107 }
105 _ => (),
108 _ => (),
106 };
109 };
@@ -124,15 +127,32 @@ impl Component for Completion {
124 {
127 {
125 // recompute menu based on matches
128 // recompute menu based on matches
126 let menu = self.popup.contents();
129 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;
128 let doc = cx.editor.document(id).unwrap();
133 let doc = cx.editor.document(id).unwrap();
129
134
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+
130− let cursor = doc.selection().cursor();
145+ let cursor = doc.selection(view_id).cursor();
131 if self.trigger_offset <= cursor {
146 if self.trigger_offset <= cursor {
132 let fragment = doc.text().slice(self.trigger_offset..cursor);
147 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.
133 let text = Cow::from(fragment);
151 let text = Cow::from(fragment);
134 // TODO: logic is same as ui/picker
152 // TODO: logic is same as ui/picker
135 menu.score(&text);
153 menu.score(&text);
154+
155+ // TODO: if after scoring the selection is 0 items, remove popup
136 }
156 }
137 }
157 }
138
158
helix-term/src/ui/editor.rs+8−4
@@ -64,7 +64,7 @@ impl EditorView {
64 // TODO: this seems to prevent setting style later
64 // TODO: this seems to prevent setting style later
65 // surface.set_style(viewport, theme.get("ui.background"));
65 // surface.set_style(viewport, theme.get("ui.background"));
66
66
67− self.render_diagnostics(&doc, area, surface, theme, is_focused);
67+ self.render_diagnostics(&doc, view, area, surface, theme, is_focused);
68
68
69 let area = Rect::new(
69 let area = Rect::new(
70 viewport.x,
70 viewport.x,
@@ -224,7 +224,7 @@ impl EditorView {
224 let selection_style = Style::default().bg(Color::Rgb(84, 0, 153));
224 let selection_style = Style::default().bg(Color::Rgb(84, 0, 153));
225
225
226 for selection in doc
226 for selection in doc
227− .selection()
227+ .selection(view.id)
228 .iter()
228 .iter()
229 .filter(|range| range.overlaps(&screen))
229 .filter(|range| range.overlaps(&screen))
230 {
230 {
@@ -332,6 +332,7 @@ impl EditorView {
332 pub fn render_diagnostics(
332 pub fn render_diagnostics(
333 &self,
333 &self,
334 doc: &Document,
334 doc: &Document,
335+ view: &View,
335 viewport: Rect,
336 viewport: Rect,
336 surface: &mut Surface,
337 surface: &mut Surface,
337 theme: &Theme,
338 theme: &Theme,
@@ -344,7 +345,7 @@ impl EditorView {
344 widgets::{Paragraph, Widget},
345 widgets::{Paragraph, Widget},
345 };
346 };
346
347
347− let cursor = doc.selection().cursor();
348+ let cursor = doc.selection(view.id).cursor();
348 let line = doc.text().char_to_line(cursor);
349 let line = doc.text().char_to_line(cursor);
349
350
350 let diagnostics = doc.diagnostics.iter().filter(|diagnostic| {
351 let diagnostics = doc.diagnostics.iter().filter(|diagnostic| {
@@ -486,11 +487,14 @@ impl Component for EditorView {
486 EventResult::Consumed(None)
487 EventResult::Consumed(None)
487 }
488 }
488 Event::Key(event) => {
489 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;
490 let mode = cx.editor.document(id).unwrap().mode();
493 let mode = cx.editor.document(id).unwrap().mode();
491
494
492 let mut cxt = commands::Context {
495 let mut cxt = commands::Context {
493 editor: &mut cx.editor,
496 editor: &mut cx.editor,
497+ view_id,
494 count: 1,
498 count: 1,
495 callback: None,
499 callback: None,
496 callbacks: cx.callbacks,
500 callbacks: cx.callbacks,
helix-term/src/ui/mod.rs+11−6
@@ -35,7 +35,8 @@ pub fn regex_prompt(
35 prompt: String,
35 prompt: String,
36 fun: impl Fn(&mut Document, Regex) + 'static,
36 fun: impl Fn(&mut Document, Regex) + 'static,
37) -> Prompt {
37) -> Prompt {
38+ let view_id = cx.view().id;
38− let snapshot = cx.doc().selection().clone();
39+ let snapshot = cx.doc().selection(view_id).clone();
39
40
40 Prompt::new(
41 Prompt::new(
41 prompt,
42 prompt,
@@ -44,9 +45,11 @@ pub fn regex_prompt(
44 match event {
45 match event {
45 PromptEvent::Abort => {
46 PromptEvent::Abort => {
46 // TODO: also revert text
47 // 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;
48 let doc = &mut editor.documents[id];
51 let doc = &mut editor.documents[id];
49− doc.set_selection(snapshot.clone());
52+ doc.set_selection(view_id, snapshot.clone());
50 }
53 }
51 PromptEvent::Validate => {
54 PromptEvent::Validate => {
52 // TODO: push_jump to store selection just before jump
55 // TODO: push_jump to store selection just before jump
@@ -60,16 +63,18 @@ pub fn regex_prompt(
60 match Regex::new(input) {
63 match Regex::new(input) {
61 Ok(regex) => {
64 Ok(regex) => {
62 // let view = &mut editor.view_mut();
65 // 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;
64 let doc = &mut editor.documents[id];
69 let doc = &mut editor.documents[id];
65
70
66 // revert state to what it was before the last update
71 // revert state to what it was before the last update
67 // TODO: also revert text
72 // TODO: also revert text
68− doc.set_selection(snapshot.clone());
73+ doc.set_selection(view_id, snapshot.clone());
69
74
70 fun(doc, regex);
75 fun(doc, regex);
71
76
72− editor.ensure_cursor_in_view(editor.view().id);
77+ editor.ensure_cursor_in_view(view_id);
73 }
78 }
74 Err(_err) => (), // TODO: mark command line as error
79 Err(_err) => (), // TODO: mark command line as error
75 }
80 }
helix-view/src/document.rs+29−22
@@ -8,7 +8,9 @@ use helix_core::{
8 ChangeSet, Diagnostic, History, Rope, Selection, State, Syntax, Transaction,
8 ChangeSet, Diagnostic, History, Rope, Selection, State, Syntax, Transaction,
9};
9};
10
10
11−use crate::DocumentId;
11+use crate::{DocumentId, ViewId};
12+
13+use std::collections::HashMap;
12
14
13#[derive(Copy, Clone, PartialEq, Eq, Hash)]
15#[derive(Copy, Clone, PartialEq, Eq, Hash)]
14pub enum Mode {
16pub enum Mode {
@@ -21,6 +23,7 @@ pub struct Document {
21 // rope + selection
23 // rope + selection
22 pub(crate) id: DocumentId,
24 pub(crate) id: DocumentId,
23 state: State,
25 state: State,
26+ pub(crate) selections: HashMap<ViewId, Selection>,
24
27
25 path: Option<PathBuf>,
28 path: Option<PathBuf>,
26
29
@@ -73,6 +76,7 @@ impl Document {
73 id: DocumentId::default(),
76 id: DocumentId::default(),
74 path: None,
77 path: None,
75 state: State::new(text),
78 state: State::new(text),
79+ selections: HashMap::default(),
76 mode: Mode::Normal,
80 mode: Mode::Normal,
77 restore_cursor: false,
81 restore_cursor: false,
78 syntax: None,
82 syntax: None,
@@ -178,12 +182,12 @@ impl Document {
178 self.language_server = language_server;
182 self.language_server = language_server;
179 }
183 }
180
184
181− pub fn set_selection(&mut self, selection: Selection) {
185+ pub fn set_selection(&mut self, view_id: ViewId, selection: Selection) {
182 // TODO: use a transaction?
186 // TODO: use a transaction?
183− self.state.selection = selection;
187+ self.selections.insert(view_id, selection);
184 }
188 }
185
189
186− fn _apply(&mut self, transaction: &Transaction) -> bool {
190+ fn _apply(&mut self, transaction: &Transaction, view_id: ViewId) -> bool {
187 let old_doc = self.text().clone();
191 let old_doc = self.text().clone();
188
192
189 let success = transaction.changes().apply(&mut self.state.doc);
193 let success = transaction.changes().apply(&mut self.state.doc);
@@ -191,10 +195,11 @@ impl Document {
191 if !transaction.changes().is_empty() {
195 if !transaction.changes().is_empty() {
192 // update the selection: either take the selection specified in the transaction, or map the
196 // update the selection: either take the selection specified in the transaction, or map the
193 // current selection through changes.
197 // current selection through changes.
194− self.state.selection = transaction
198+ let selection = transaction
195 .selection()
199 .selection()
196 .cloned()
200 .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);
198
203
199 self.version += 1;
204 self.version += 1;
200
205
@@ -227,14 +232,14 @@ impl Document {
227 success
232 success
228 }
233 }
229
234
230− pub fn apply(&mut self, transaction: &Transaction) -> bool {
235+ pub fn apply(&mut self, transaction: &Transaction, view_id: ViewId) -> bool {
231 // store the state just before any changes are made. This allows us to undo to the
236 // store the state just before any changes are made. This allows us to undo to the
232 // state just before a transaction was applied.
237 // state just before a transaction was applied.
233 if self.changes.is_empty() && !transaction.changes().is_empty() {
238 if self.changes.is_empty() && !transaction.changes().is_empty() {
234 self.old_state = Some(self.state.clone());
239 self.old_state = Some(self.state.clone());
235 }
240 }
236
241
237− let success = self._apply(&transaction);
242+ let success = self._apply(&transaction, view_id);
238
243
239 self.modified = true;
244 self.modified = true;
240 // TODO: be smarter about modified by keeping track of saved version instead. That way if
245 // TODO: be smarter about modified by keeping track of saved version instead. That way if
@@ -249,9 +254,9 @@ impl Document {
249 success
254 success
250 }
255 }
251
256
252− pub fn undo(&mut self) -> bool {
257+ pub fn undo(&mut self, view_id: ViewId) -> bool {
253 if let Some(transaction) = self.history.undo() {
258 if let Some(transaction) = self.history.undo() {
254− let success = self._apply(&transaction);
259+ let success = self._apply(&transaction, view_id);
255
260
256 // reset changeset to fix len
261 // reset changeset to fix len
257 self.changes = ChangeSet::new(self.text());
262 self.changes = ChangeSet::new(self.text());
@@ -261,9 +266,9 @@ impl Document {
261 false
266 false
262 }
267 }
263
268
264− pub fn redo(&mut self) -> bool {
269+ pub fn redo(&mut self, view_id: ViewId) -> bool {
265 if let Some(transaction) = self.history.redo() {
270 if let Some(transaction) = self.history.redo() {
266− let success = self._apply(&transaction);
271+ let success = self._apply(&transaction, view_id);
267
272
268 // reset changeset to fix len
273 // reset changeset to fix len
269 self.changes = ChangeSet::new(self.text());
274 self.changes = ChangeSet::new(self.text());
@@ -273,7 +278,7 @@ impl Document {
273 false
278 false
274 }
279 }
275
280
276− pub fn append_changes_to_history(&mut self) {
281+ pub fn append_changes_to_history(&mut self, view_id: ViewId) {
277 if self.changes.is_empty() {
282 if self.changes.is_empty() {
278 return;
283 return;
279 }
284 }
@@ -282,7 +287,8 @@ impl Document {
282 let changes = std::mem::replace(&mut self.changes, new_changeset);
287 let changes = std::mem::replace(&mut self.changes, new_changeset);
283 // Instead of doing this messy merge we could always commit, and based on transaction
288 // Instead of doing this messy merge we could always commit, and based on transaction
284 // annotations either add a new layer or compose into the previous one.
289 // annotations either add a new layer or compose into the previous one.
290+ let transaction =
285− let transaction = Transaction::from(changes).with_selection(self.selection().clone());
291+ Transaction::from(changes).with_selection(self.selection(view_id).clone());
286
292
287 // HAXX: we need to reconstruct the state as it was before the changes..
293 // HAXX: we need to reconstruct the state as it was before the changes..
288 let old_state = self.old_state.take().expect("no old_state available");
294 let old_state = self.old_state.take().expect("no old_state available");
@@ -362,8 +368,8 @@ impl Document {
362 &self.state.doc
368 &self.state.doc
363 }
369 }
364
370
365− pub fn selection(&self) -> &Selection {
371+ pub fn selection(&self, view_id: ViewId) -> &Selection {
366− &self.state.selection
372+ &self.selections[&view_id]
367 }
373 }
368
374
369 pub fn relative_path(&self) -> Option<&Path> {
375 pub fn relative_path(&self) -> Option<&Path> {
@@ -400,13 +406,14 @@ mod test {
400 use helix_lsp::{lsp, Client};
406 use helix_lsp::{lsp, Client};
401 let text = Rope::from("hello");
407 let text = Rope::from("hello");
402 let mut doc = Document::new(text);
408 let mut doc = Document::new(text);
409+ let view = ViewId::default();
403− doc.set_selection(Selection::single(5, 5));
410+ doc.set_selection(view, Selection::single(5, 5));
404
411
405 // insert
412 // insert
406
413
407− let transaction = Transaction::insert(doc.text(), doc.selection(), " world".into());
414+ let transaction = Transaction::insert(doc.text(), doc.selection(view), " world".into());
408 let old_doc = doc.state.clone();
415 let old_doc = doc.state.clone();
409− doc.apply(&transaction);
416+ doc.apply(&transaction, view);
410 let changes = Client::changeset_to_changes(&old_doc.doc, doc.text(), transaction.changes());
417 let changes = Client::changeset_to_changes(&old_doc.doc, doc.text(), transaction.changes());
411
418
412 assert_eq!(
419 assert_eq!(
@@ -425,7 +432,7 @@ mod test {
425
432
426 let transaction = transaction.invert(&old_doc.doc);
433 let transaction = transaction.invert(&old_doc.doc);
427 let old_doc = doc.state.clone();
434 let old_doc = doc.state.clone();
428− doc.apply(&transaction);
435+ doc.apply(&transaction, view);
429 let changes = Client::changeset_to_changes(&old_doc.doc, doc.text(), transaction.changes());
436 let changes = Client::changeset_to_changes(&old_doc.doc, doc.text(), transaction.changes());
430
437
431 // line: 0-based.
438 // line: 0-based.
@@ -450,13 +457,13 @@ mod test {
450
457
451 // also tests that changes are layered, positions depend on previous changes.
458 // also tests that changes are layered, positions depend on previous changes.
452
459
453− doc.state.selection = Selection::single(0, 5);
460+ doc.set_selection(view, Selection::single(0, 5));
454 let transaction = Transaction::change(
461 let transaction = Transaction::change(
455 &doc.state.doc,
462 &doc.state.doc,
456 vec![(0, 2, Some("aei".into())), (3, 5, Some("ou".into()))].into_iter(),
463 vec![(0, 2, Some("aei".into())), (3, 5, Some("ou".into()))].into_iter(),
457 );
464 );
458 // aeilou
465 // aeilou
459− doc.apply(&transaction);
466+ doc.apply(&transaction, view);
460 let changes =
467 let changes =
461 Client::changeset_to_changes(&doc.state.doc, doc.text(), transaction.changes());
468 Client::changeset_to_changes(&doc.state.doc, doc.text(), transaction.changes());
462
469
helix-view/src/editor.rs+23−4
@@ -91,24 +91,40 @@ impl Editor {
91 };
91 };
92
92
93 use crate::tree::Layout;
93 use crate::tree::Layout;
94+ use helix_core::Selection;
94 match action {
95 match action {
95 Action::Replace => {
96 Action::Replace => {
96 let view = self.view();
97 let view = self.view();
98+ let jump = (
99+ view.doc,
97− let jump = (view.doc, self.documents[view.doc].selection().clone());
100+ self.documents[view.doc].selection(view.id).clone(),
101+ );
98
102
99 let view = self.view_mut();
103 let view = self.view_mut();
100 view.jumps.push(jump);
104 view.jumps.push(jump);
101 view.doc = id;
105 view.doc = id;
102 view.first_line = 0;
106 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+
103 return Ok(id);
113 return Ok(id);
104 }
114 }
105 Action::HorizontalSplit => {
115 Action::HorizontalSplit => {
106 let view = View::new(id)?;
116 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));
108 }
121 }
109 Action::VerticalSplit => {
122 Action::VerticalSplit => {
110 let view = View::new(id)?;
123 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));
112 }
128 }
113 }
129 }
114
130
@@ -134,6 +150,9 @@ impl Editor {
134 smol::block_on(language_server.text_document_did_close(doc.identifier())).unwrap();
150 smol::block_on(language_server.text_document_did_close(doc.identifier())).unwrap();
135 }
151 }
136
152
153+ // remove selection
154+ self.documents[view.doc].selections.remove(&id);
155+
137 // self.documents.remove(view.doc);
156 // self.documents.remove(view.doc);
138 self.tree.remove(id);
157 self.tree.remove(id);
139 self._refresh();
158 self._refresh();
@@ -183,7 +202,7 @@ impl Editor {
183 const OFFSET: u16 = 7; // 1 diagnostic + 5 linenr + 1 gutter
202 const OFFSET: u16 = 7; // 1 diagnostic + 5 linenr + 1 gutter
184 let view = self.view();
203 let view = self.view();
185 let doc = &self.documents[view.doc];
204 let doc = &self.documents[view.doc];
186− let cursor = doc.selection().cursor();
205+ let cursor = doc.selection(view.id).cursor();
187 if let Some(mut pos) = view.screen_coords_at_pos(doc, doc.text().slice(..), cursor) {
206 if let Some(mut pos) = view.screen_coords_at_pos(doc, doc.text().slice(..), cursor) {
188 pos.col += view.area.x as usize + OFFSET as usize;
207 pos.col += view.area.x as usize + OFFSET as usize;
189 pos.row += view.area.y as usize;
208 pos.row += view.area.y as usize;
helix-view/src/view.rs+1−1
@@ -74,7 +74,7 @@ impl View {
74 }
74 }
75
75
76 pub fn ensure_cursor_in_view(&mut self, doc: &Document) {
76 pub fn ensure_cursor_in_view(&mut self, doc: &Document) {
77− let cursor = doc.selection().cursor();
77+ let cursor = doc.selection(self.id).cursor();
78 let line = doc.text().char_to_line(cursor);
78 let line = doc.text().char_to_line(cursor);
79 let document_end = self.first_line + (self.area.height as usize).saturating_sub(2);
79 let document_end = self.first_line + (self.area.height as usize).saturating_sub(2);
80
80