on master help sign in
Refactoring: move language_servers into Editor, proper load for doc.
commit05c7fb98df43f7843d441e0dce3e5b361f2d7645 authorBlaž Hrastnik <blaz@mxxn.io> dateThu 21 Jan 2021, 16:55 (6 years ago) parent15dd7ca
7 files changed+307−267
helix-lsp/src/lib.rs+1−1 helix-term/src/application.rs+13−38 helix-term/src/commands.rs+217−174 helix-term/src/compositor.rs−1 helix-term/src/ui/editor.rs+39−43 helix-term/src/ui/mod.rs+4−4 helix-view/src/editor.rs+33−6
helix-lsp/src/lib.rs+1−1
@@ -114,7 +114,7 @@ impl Registry {
114114 pub fn new() -> Self {
115115 let mut inner = HashMap::new();
116116
117− inner.insert("rust".to_string(), OnceCell::new());
117+ inner.insert("source.rust".to_string(), OnceCell::new());
118118
119119 Self {
120120 inner,
helix-term/src/application.rs+13−38
@@ -33,8 +33,6 @@ pub struct Application {
3333 terminal: Terminal,
3434
3535 executor: &'static smol::Executor<'static>,
36− language_server: Arc<helix_lsp::Client>,
37− language_servers: helix_lsp::Registry,
3836}
3937
4038impl Application {
@@ -44,18 +42,8 @@ impl Application {
4442 let mut editor = Editor::new();
4543 let size = terminal.size()?;
4644
47− let language_servers = helix_lsp::Registry::new();
48− let language_server = language_servers.get("rust", &executor).unwrap();
49−
5045 if let Some(file) = args.values_of_t::<PathBuf>("files").unwrap().pop() {
51− editor.open(file, (size.width, size.height))?;
52−
53− // TODO: do this everywhere
54− editor
55− .view_mut()
56− .unwrap()
57− .doc
58− .set_language_server(Some(language_server.clone()));
46+ editor.open(file, (size.width, size.height), executor)?;
5947 }
6048
6149 let mut compositor = Compositor::new();
@@ -67,8 +55,6 @@ impl Application {
6755 compositor,
6856
6957 executor,
70− language_server,
71− language_servers,
7258 };
7359
7460 Ok(app)
@@ -76,15 +62,10 @@ impl Application {
7662
7763 fn render(&mut self) {
7864 let executor = &self.executor;
79− let language_servers = &self.language_servers;
8065 let editor = &mut self.editor;
8166 let compositor = &self.compositor;
8267
83− let mut cx = crate::compositor::Context {
84− editor,
85− executor,
86− language_servers,
87− };
68+ let mut cx = crate::compositor::Context { editor, executor };
8869 let area = self.terminal.size().unwrap();
8970
9071 compositor.render(area, self.terminal.current_buffer_mut(), &mut cx);
@@ -97,12 +78,6 @@ impl Application {
9778 pub async fn event_loop(&mut self) {
9879 let mut reader = EventStream::new();
9980
100− let doc = &self.editor.view().unwrap().doc;
101− self.language_server
102− .text_document_did_open(doc.url().unwrap(), doc.version, doc.text())
103− .await
104− .unwrap();
105−
10681 self.render();
10782
10883 loop {
@@ -115,7 +90,7 @@ impl Application {
11590 event = reader.next().fuse() => {
11691 self.handle_terminal_events(event)
11792 }
118− call = self.language_servers.incoming.next().fuse() => {
93+ call = self.editor.language_servers.incoming.next().fuse() => {
11994 self.handle_language_server_message(call).await
12095 }
12196 }
@@ -126,7 +101,6 @@ impl Application {
126101 let mut cx = crate::compositor::Context {
127102 editor: &mut self.editor,
128103 executor: &self.executor,
129− language_servers: &self.language_servers,
130104 };
131105 // Handle key events
132106 let should_redraw = match event {
@@ -197,16 +171,17 @@ impl Application {
197171 Some(Call::MethodCall(call)) => {
198172 debug!("Method not found {}", call.method);
199173
200− self.language_server.reply(
201− call.id,
202− // TODO: make a Into trait that can cast to Err(jsonrpc::Error)
203− Err(helix_lsp::jsonrpc::Error {
204− code: helix_lsp::jsonrpc::ErrorCode::MethodNotFound,
205− message: "Method not found".to_string(),
206− data: None,
207− }),
208− );
174+ // self.language_server.reply(
175+ // call.id,
176+ // // TODO: make a Into trait that can cast to Err(jsonrpc::Error)
177+ // Err(helix_lsp::jsonrpc::Error {
178+ // code: helix_lsp::jsonrpc::ErrorCode::MethodNotFound,
179+ // message: "Method not found".to_string(),
180+ // data: None,
181+ // }),
182+ // );
209183 }
184+ None => (),
210185 e => unreachable!("{:?}", e),
211186 }
212187 }
helix-term/src/commands.rs+217−174
@@ -18,57 +18,66 @@ use helix_view::{
1818 Editor,
1919};
2020
21−pub struct Context<'a, 'b> {
21+pub struct Context<'a> {
2222 pub count: usize,
23− pub view: &'a mut View,
24− pub executor: &'a smol::Executor<'b>,
25− pub language_servers: &'a helix_lsp::Registry,
23+ pub editor: &'a mut Editor,
24+ pub executor: &'static smol::Executor<'static>,
2625
2726 pub callback: Option<crate::compositor::Callback>,
2827}
2928
29+impl<'a> Context<'a> {
30+ pub fn view(&mut self) -> &mut View {
31+ self.editor.view_mut()
32+ }
33+}
34+
3035/// A command is a function that takes the current state and a count, and does a side-effect on the
3136/// state (usually by creating and applying a transaction).
3237pub type Command = fn(cx: &mut Context);
3338
3439pub fn move_char_left(cx: &mut Context) {
40+ let count = cx.count;
3541 let selection =
36− cx.view
42+ cx.view()
3743 .doc
3844 .state
39− .move_selection(Direction::Backward, Granularity::Character, cx.count);
40− cx.view.doc.set_selection(selection);
45+ .move_selection(Direction::Backward, Granularity::Character, count);
46+ cx.view().doc.set_selection(selection);
4147}
4248
4349pub fn move_char_right(cx: &mut Context) {
50+ let count = cx.count;
4451 let selection =
45− cx.view
52+ cx.view()
4653 .doc
4754 .state
48− .move_selection(Direction::Forward, Granularity::Character, cx.count);
49− cx.view.doc.set_selection(selection);
55+ .move_selection(Direction::Forward, Granularity::Character, count);
56+ cx.view().doc.set_selection(selection);
5057}
5158
5259pub fn move_line_up(cx: &mut Context) {
60+ let count = cx.count;
5361 let selection =
54− cx.view
62+ cx.view()
5563 .doc
5664 .state
57− .move_selection(Direction::Backward, Granularity::Line, cx.count);
58− cx.view.doc.set_selection(selection);
65+ .move_selection(Direction::Backward, Granularity::Line, count);
66+ cx.view().doc.set_selection(selection);
5967}
6068
6169pub fn move_line_down(cx: &mut Context) {
70+ let count = cx.count;
6271 let selection =
63− cx.view
72+ cx.view()
6473 .doc
6574 .state
66− .move_selection(Direction::Forward, Granularity::Line, cx.count);
67− cx.view.doc.set_selection(selection);
75+ .move_selection(Direction::Forward, Granularity::Line, count);
76+ cx.view().doc.set_selection(selection);
6877}
6978
7079pub fn move_line_end(cx: &mut Context) {
71− let lines = selection_lines(&cx.view.doc.state);
80+ let lines = selection_lines(&cx.view().doc.state);
7281
7382 let positions = lines
7483 .into_iter()
@@ -77,75 +86,85 @@ pub fn move_line_end(cx: &mut Context) {
7786
7887 // Line end is pos at the start of next line - 1
7988 // subtract another 1 because the line ends with \n
80− cx.view.doc.text().line_to_char(index + 1).saturating_sub(2)
89+ cx.view()
90+ .doc
91+ .text()
92+ .line_to_char(index + 1)
93+ .saturating_sub(2)
8194 })
8295 .map(|pos| Range::new(pos, pos));
8396
8497 let selection = Selection::new(positions.collect(), 0);
8598
86− cx.view.doc.set_selection(selection);
99+ cx.view().doc.set_selection(selection);
87100}
88101
89102pub fn move_line_start(cx: &mut Context) {
90− let lines = selection_lines(&cx.view.doc.state);
103+ let lines = selection_lines(&cx.view().doc.state);
91104
92105 let positions = lines
93106 .into_iter()
94107 .map(|index| {
95108 // adjust all positions to the start of the line.
96− cx.view.doc.text().line_to_char(index)
109+ cx.view().doc.text().line_to_char(index)
97110 })
98111 .map(|pos| Range::new(pos, pos));
99112
100113 let selection = Selection::new(positions.collect(), 0);
101114
102− cx.view.doc.set_selection(selection);
115+ cx.view().doc.set_selection(selection);
103116}
104117
105118pub fn move_next_word_start(cx: &mut Context) {
106− let pos = cx.view.doc.state.move_pos(
107− cx.view.doc.selection().cursor(),
119+ let count = cx.count;
120+ let view = cx.view();
121+ let pos = view.doc.state.move_pos(
122+ view.doc.selection().cursor(),
108123 Direction::Forward,
109124 Granularity::Word,
110− cx.count,
125+ count,
111126 );
112127
113− cx.view.doc.set_selection(Selection::point(pos));
128+ view.doc.set_selection(Selection::point(pos));
114129}
115130
116131pub fn move_prev_word_start(cx: &mut Context) {
117− let pos = cx.view.doc.state.move_pos(
118− cx.view.doc.selection().cursor(),
132+ let count = cx.count;
133+ let view = cx.view();
134+ let pos = view.doc.state.move_pos(
135+ view.doc.selection().cursor(),
119136 Direction::Backward,
120137 Granularity::Word,
121− cx.count,
138+ count,
122139 );
123140
124− cx.view.doc.set_selection(Selection::point(pos));
141+ view.doc.set_selection(Selection::point(pos));
125142}
126143
127144pub fn move_next_word_end(cx: &mut Context) {
145+ let count = cx.count;
146+ let view = cx.view();
128147 let pos = State::move_next_word_end(
129− &cx.view.doc.text().slice(..),
130− cx.view.doc.selection().cursor(),
131− cx.count,
148+ &view.doc.text().slice(..),
149+ view.doc.selection().cursor(),
150+ count,
132151 );
133152
134− cx.view.doc.set_selection(Selection::point(pos));
153+ view.doc.set_selection(Selection::point(pos));
135154}
136155
137156pub fn move_file_start(cx: &mut Context) {
138− cx.view.doc.set_selection(Selection::point(0));
157+ cx.view().doc.set_selection(Selection::point(0));
139158
140− cx.view.doc.mode = Mode::Normal;
159+ cx.view().doc.mode = Mode::Normal;
141160}
142161
143162pub fn move_file_end(cx: &mut Context) {
144− let text = &cx.view.doc.text();
163+ let text = &cx.view().doc.text();
145164 let last_line = text.line_to_char(text.len_lines().saturating_sub(2));
146− cx.view.doc.set_selection(Selection::point(last_line));
165+ cx.view().doc.set_selection(Selection::point(last_line));
147166
148− cx.view.doc.mode = Mode::Normal;
167+ cx.view().doc.mode = Mode::Normal;
149168}
150169
151170pub fn check_cursor_in_view(view: &View) -> bool {
@@ -160,93 +179,98 @@ pub fn check_cursor_in_view(view: &View) -> bool {
160179}
161180
162181pub fn page_up(cx: &mut Context) {
163− if cx.view.first_line < PADDING {
182+ let view = cx.view();
183+ if view.first_line < PADDING {
164184 return;
165185 }
166186
167− cx.view.first_line = cx.view.first_line.saturating_sub(cx.view.size.1 as usize);
187+ view.first_line = view.first_line.saturating_sub(view.size.1 as usize);
168188
169− if !check_cursor_in_view(cx.view) {
170− let text = cx.view.doc.text();
171− let pos = text.line_to_char(cx.view.last_line().saturating_sub(PADDING));
172− cx.view.doc.set_selection(Selection::point(pos));
189+ if !check_cursor_in_view(view) {
190+ let text = view.doc.text();
191+ let pos = text.line_to_char(view.last_line().saturating_sub(PADDING));
192+ view.doc.set_selection(Selection::point(pos));
173193 }
174194}
175195
176196pub fn page_down(cx: &mut Context) {
177− cx.view.first_line += cx.view.size.1 as usize + PADDING;
197+ let view = cx.view();
198+ view.first_line += view.size.1 as usize + PADDING;
178199
179− if cx.view.first_line < cx.view.doc.text().len_lines() {
180− let text = cx.view.doc.text();
181− let pos = text.line_to_char(cx.view.first_line as usize);
182− cx.view.doc.set_selection(Selection::point(pos));
200+ if view.first_line < view.doc.text().len_lines() {
201+ let text = view.doc.text();
202+ let pos = text.line_to_char(view.first_line as usize);
203+ view.doc.set_selection(Selection::point(pos));
183204 }
184205}
185206
186207pub fn half_page_up(cx: &mut Context) {
187− if cx.view.first_line < PADDING {
208+ let view = cx.view();
209+ if view.first_line < PADDING {
188210 return;
189211 }
190212
191− cx.view.first_line = cx
192− .view
193− .first_line
194− .saturating_sub(cx.view.size.1 as usize / 2);
213+ view.first_line = view.first_line.saturating_sub(view.size.1 as usize / 2);
195214
196− if !check_cursor_in_view(cx.view) {
197− let text = &cx.view.doc.text();
198− let pos = text.line_to_char(cx.view.last_line() - PADDING);
199− cx.view.doc.set_selection(Selection::point(pos));
215+ if !check_cursor_in_view(view) {
216+ let text = &view.doc.text();
217+ let pos = text.line_to_char(view.last_line() - PADDING);
218+ view.doc.set_selection(Selection::point(pos));
200219 }
201220}
202221
203222pub fn half_page_down(cx: &mut Context) {
204− let lines = cx.view.doc.text().len_lines();
205− if cx.view.first_line < lines.saturating_sub(cx.view.size.1 as usize) {
206− cx.view.first_line += cx.view.size.1 as usize / 2;
223+ let view = cx.view();
224+ let lines = view.doc.text().len_lines();
225+ if view.first_line < lines.saturating_sub(view.size.1 as usize) {
226+ view.first_line += view.size.1 as usize / 2;
207227 }
208− if !check_cursor_in_view(cx.view) {
209− let text = cx.view.doc.text();
210− let pos = text.line_to_char(cx.view.first_line as usize);
211− cx.view.doc.set_selection(Selection::point(pos));
228+ if !check_cursor_in_view(view) {
229+ let text = view.doc.text();
230+ let pos = text.line_to_char(view.first_line as usize);
231+ view.doc.set_selection(Selection::point(pos));
212232 }
213233}
214234// avoid select by default by having a visual mode switch that makes movements into selects
215235
216236pub fn extend_char_left(cx: &mut Context) {
237+ let count = cx.count;
238+ let view = cx.view();
217239 let selection =
218− cx.view
219− .doc
240+ view.doc
220241 .state
221− .extend_selection(Direction::Backward, Granularity::Character, cx.count);
222− cx.view.doc.set_selection(selection);
242+ .extend_selection(Direction::Backward, Granularity::Character, count);
243+ view.doc.set_selection(selection);
223244}
224245
225246pub fn extend_char_right(cx: &mut Context) {
247+ let count = cx.count;
248+ let view = cx.view();
226249 let selection =
227− cx.view
228− .doc
250+ view.doc
229251 .state
230− .extend_selection(Direction::Forward, Granularity::Character, cx.count);
231− cx.view.doc.set_selection(selection);
252+ .extend_selection(Direction::Forward, Granularity::Character, count);
253+ view.doc.set_selection(selection);
232254}
233255
234256pub fn extend_line_up(cx: &mut Context) {
235− let selection =
236− cx.view
237− .doc
238− .state
239− .extend_selection(Direction::Backward, Granularity::Line, cx.count);
240− cx.view.doc.set_selection(selection);
257+ let count = cx.count;
258+ let view = cx.view();
259+ let selection = view
260+ .doc
261+ .state
262+ .extend_selection(Direction::Backward, Granularity::Line, count);
263+ view.doc.set_selection(selection);
241264}
242265
243266pub fn extend_line_down(cx: &mut Context) {
244− let selection =
245− cx.view
246− .doc
247− .state
248− .extend_selection(Direction::Forward, Granularity::Line, cx.count);
249− cx.view.doc.set_selection(selection);
267+ let count = cx.count;
268+ let view = cx.view();
269+ let selection = view
270+ .doc
271+ .state
272+ .extend_selection(Direction::Forward, Granularity::Line, count);
273+ view.doc.set_selection(selection);
250274}
251275
252276pub fn split_selection(cx: &mut Context) {
@@ -263,7 +287,7 @@ pub fn split_selection(cx: &mut Context) {
263287 // # update state
264288 // }
265289
266− let snapshot = cx.view.doc.state.clone();
290+ let snapshot = cx.view().doc.state.clone();
267291
268292 let prompt = Prompt::new(
269293 "split:".to_string(),
@@ -272,7 +296,7 @@ pub fn split_selection(cx: &mut Context) {
272296 match event {
273297 PromptEvent::Abort => {
274298 // revert state
275− let view = editor.view_mut().unwrap();
299+ let view = editor.view_mut();
276300 view.doc.state = snapshot.clone();
277301 }
278302 PromptEvent::Validate => {
@@ -281,7 +305,7 @@ pub fn split_selection(cx: &mut Context) {
281305 PromptEvent::Update => {
282306 match Regex::new(input) {
283307 Ok(regex) => {
284− let view = editor.view_mut().unwrap();
308+ let view = editor.view_mut();
285309
286310 // revert state to what it was before the last update
287311 view.doc.state = snapshot.clone();
@@ -306,32 +330,33 @@ pub fn split_selection(cx: &mut Context) {
306330}
307331
308332pub fn split_selection_on_newline(cx: &mut Context) {
309− let text = &cx.view.doc.text().slice(..);
333+ let view = cx.view();
334+ let text = &view.doc.text().slice(..);
310335 // only compile the regex once
311336 #[allow(clippy::trivial_regex)]
312337 static REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"\n").unwrap());
313− let selection = selection::split_on_matches(text, cx.view.doc.selection(), &REGEX);
314− cx.view.doc.set_selection(selection);
338+ let selection = selection::split_on_matches(text, view.doc.selection(), &REGEX);
339+ view.doc.set_selection(selection);
315340}
316341
317342pub fn select_line(cx: &mut Context) {
318343 // TODO: count
319− let pos = cx.view.doc.selection().primary();
320− let text = cx.view.doc.text();
344+ let pos = cx.view().doc.selection().primary();
345+ let text = cx.view().doc.text();
321346 let line = text.char_to_line(pos.head);
322347 let start = text.line_to_char(line);
323348 let end = text.line_to_char(line + 1).saturating_sub(1);
324349
325− cx.view.doc.set_selection(Selection::single(start, end));
350+ cx.view().doc.set_selection(Selection::single(start, end));
326351}
327352
328353// heuristic: append changes to history after each command, unless we're in insert mode
329354
330355fn _delete_selection(cx: &mut Context) {
331− let transaction = Transaction::change_by_selection(&cx.view.doc.state, |range| {
356+ let transaction = Transaction::change_by_selection(&cx.view().doc.state, |range| {
332357 (range.from(), range.to() + 1, None)
333358 });
334− cx.view.doc.apply(&transaction);
359+ cx.view().doc.apply(&transaction);
335360}
336361
337362pub fn delete_selection(cx: &mut Context) {
@@ -347,26 +372,26 @@ pub fn change_selection(cx: &mut Context) {
347372
348373pub fn collapse_selection(cx: &mut Context) {
349374 let selection = cx
350− .view
375+ .view()
351376 .doc
352377 .selection()
353378 .transform(|range| Range::new(range.head, range.head));
354379
355− cx.view.doc.set_selection(selection);
380+ cx.view().doc.set_selection(selection);
356381}
357382
358383pub fn flip_selections(cx: &mut Context) {
359384 let selection = cx
360− .view
385+ .view()
361386 .doc
362387 .selection()
363388 .transform(|range| Range::new(range.head, range.anchor));
364389
365− cx.view.doc.set_selection(selection);
390+ cx.view().doc.set_selection(selection);
366391}
367392
368393fn enter_insert_mode(cx: &mut Context) {
369− cx.view.doc.mode = Mode::Insert;
394+ cx.view().doc.mode = Mode::Insert;
370395
371396 // TODO: store selection for undo
372397}
@@ -376,34 +401,36 @@ pub fn insert_mode(cx: &mut Context) {
376401 enter_insert_mode(cx);
377402
378403 let selection = cx
379− .view
404+ .view()
380405 .doc
381406 .selection()
382407 .transform(|range| Range::new(range.to(), range.from()));
383− cx.view.doc.set_selection(selection);
408+ cx.view().doc.set_selection(selection);
384409}
385410
386411// inserts at the end of each selection
387412pub fn append_mode(cx: &mut Context) {
388413 enter_insert_mode(cx);
389− cx.view.doc.restore_cursor = true;
414+ let view = cx.view();
415+ view.doc.restore_cursor = true;
390416
391417 // TODO: as transaction
392− let text = &cx.view.doc.text().slice(..);
393− let selection = cx.view.doc.selection().transform(|range| {
418+ let text = &view.doc.text().slice(..);
419+ let selection = view.doc.selection().transform(|range| {
394420 // TODO: to() + next char
395421 Range::new(
396422 range.from(),
397423 graphemes::next_grapheme_boundary(text, range.to()),
398424 )
399425 });
400− cx.view.doc.set_selection(selection);
426+ view.doc.set_selection(selection);
401427}
402428
403429// TODO: I, A, o and O can share a lot of the primitives.
404430pub fn command_mode(cx: &mut Context) {
431+ let executor = cx.executor;
405432 cx.callback = Some(Box::new(
406− |compositor: &mut Compositor, editor: &mut Editor| {
433+ move |compositor: &mut Compositor, editor: &mut Editor| {
407434 let prompt = Prompt::new(
408435 ":".to_owned(),
409436 |_input: &str| {
@@ -446,7 +473,7 @@ pub fn command_mode(cx: &mut Context) {
446473 .filter(|command| command.contains(_input))
447474 .collect()
448475 }, // completion
449− |editor: &mut Editor, input: &str, event: PromptEvent| {
476+ move |editor: &mut Editor, input: &str, event: PromptEvent| {
450477 if event != PromptEvent::Validate {
451478 return;
452479 }
@@ -456,9 +483,8 @@ pub fn command_mode(cx: &mut Context) {
456483 match *parts.as_slice() {
457484 ["q"] => editor.should_close = true,
458485 ["o", path] => {
459− // TODO: make view()/view_mut() always contain a view.
460− let size = editor.view().unwrap().size;
461− editor.open(path.into(), size);
486+ let size = editor.view().size;
487+ editor.open(path.into(), size, executor);
462488 }
463489 _ => (),
464490 }
@@ -469,9 +495,9 @@ pub fn command_mode(cx: &mut Context) {
469495 ));
470496}
471497pub fn file_picker(cx: &mut Context) {
498+ let picker = ui::file_picker("./", cx.executor);
472499 cx.callback = Some(Box::new(
473500 |compositor: &mut Compositor, editor: &mut Editor| {
474− let picker = ui::file_picker("./");
475501 compositor.push(Box::new(picker));
476502 },
477503 ));
@@ -519,21 +545,23 @@ pub fn append_to_line(cx: &mut Context) {
519545pub fn open_below(cx: &mut Context) {
520546 enter_insert_mode(cx);
521547
522− let lines = selection_lines(&cx.view.doc.state);
548+ let view = cx.view();
549+
550+ let lines = selection_lines(&view.doc.state);
523551
524552 let positions: Vec<_> = lines
525553 .into_iter()
526554 .map(|index| {
527555 // adjust all positions to the end of the line/start of the next one.
528− cx.view.doc.text().line_to_char(index + 1)
556+ view.doc.text().line_to_char(index + 1)
529557 })
530558 .collect();
531559
532560 let changes = positions.iter().copied().map(|index| {
533561 // TODO: share logic with insert_newline for indentation
534562 let indent_level = helix_core::indent::suggested_indent_for_pos(
535− cx.view.doc.syntax.as_ref(),
536− &cx.view.doc.state,
563+ view.doc.syntax.as_ref(),
564+ &view.doc.state,
537565 index,
538566 true,
539567 );
@@ -567,42 +595,42 @@ pub fn open_below(cx: &mut Context) {
567595 0,
568596 );
569597
570− let transaction = Transaction::change(&cx.view.doc.state, changes).with_selection(selection);
598+ let transaction = Transaction::change(&view.doc.state, changes).with_selection(selection);
571599
572− cx.view.doc.apply(&transaction);
600+ view.doc.apply(&transaction);
573601}
574602
575603// O inserts a new line before each line with a selection
576604
577605fn append_changes_to_history(cx: &mut Context) {
578− if cx.view.doc.changes.is_empty() {
606+ if cx.view().doc.changes.is_empty() {
579607 return;
580608 }
581609
582610 // TODO: change -> change -> undo -> change -> change fails, probably old_state needs reset
583611
584− let new_changeset = ChangeSet::new(cx.view.doc.text());
585− let changes = std::mem::replace(&mut cx.view.doc.changes, new_changeset);
612+ let new_changeset = ChangeSet::new(cx.view().doc.text());
613+ let changes = std::mem::replace(&mut cx.view().doc.changes, new_changeset);
586614 // Instead of doing this messy merge we could always commit, and based on transaction
587615 // annotations either add a new layer or compose into the previous one.
588− let transaction = Transaction::from(changes).with_selection(cx.view.doc.selection().clone());
616+ let transaction = Transaction::from(changes).with_selection(cx.view().doc.selection().clone());
589617
590618 // increment document version
591619 // TODO: needs to happen on undo/redo too
592− cx.view.doc.version += 1;
620+ cx.view().doc.version += 1;
593621
594622 // TODO: trigger lsp/documentDidChange with changes
595623
596624 // HAXX: we need to reconstruct the state as it was before the changes..
597625 let old_state = cx
598− .view
626+ .view()
599627 .doc
600628 .old_state
601629 .take()
602630 .expect("no old_state available");
603631
604632 // TODO: take transaction by value?
605− cx.view
633+ cx.view()
606634 .doc
607635 .history
608636 .commit_revision(&transaction, &old_state);
@@ -611,27 +639,29 @@ fn append_changes_to_history(cx: &mut Context) {
611639}
612640
613641pub fn normal_mode(cx: &mut Context) {
614− cx.view.doc.mode = Mode::Normal;
642+ cx.view().doc.mode = Mode::Normal;
615643
616644 append_changes_to_history(cx);
617645
646+ let view = cx.view();
647+
618648 // if leaving append mode, move cursor back by 1
619− if cx.view.doc.restore_cursor {
620− let text = &cx.view.doc.text().slice(..);
621− let selection = cx.view.doc.selection().transform(|range| {
649+ if view.doc.restore_cursor {
650+ let text = &view.doc.text().slice(..);
651+ let selection = view.doc.selection().transform(|range| {
622652 Range::new(
623653 range.from(),
624654 graphemes::prev_grapheme_boundary(text, range.to()),
625655 )
626656 });
627− cx.view.doc.set_selection(selection);
657+ view.doc.set_selection(selection);
628658
629− cx.view.doc.restore_cursor = false;
659+ view.doc.restore_cursor = false;
630660 }
631661}
632662
633663pub fn goto_mode(cx: &mut Context) {
634− cx.view.doc.mode = Mode::Goto;
664+ cx.view().doc.mode = Mode::Goto;
635665}
636666
637667// NOTE: Transactions in this module get appended to history when we switch back to normal mode.
@@ -640,9 +670,9 @@ pub mod insert {
640670 // TODO: insert means add text just before cursor, on exit we should be on the last letter.
641671 pub fn insert_char(cx: &mut Context, c: char) {
642672 let c = Tendril::from_char(c);
643− let transaction = Transaction::insert(&cx.view.doc.state, c);
673+ let transaction = Transaction::insert(&cx.view().doc.state, c);
644674
645− cx.view.doc.apply(&transaction);
675+ cx.view().doc.apply(&transaction);
646676 }
647677
648678 pub fn insert_tab(cx: &mut Context) {
@@ -650,10 +680,11 @@ pub mod insert {
650680 }
651681
652682 pub fn insert_newline(cx: &mut Context) {
653− let transaction = Transaction::change_by_selection(&cx.view.doc.state, |range| {
683+ let view = cx.view();
684+ let transaction = Transaction::change_by_selection(&view.doc.state, |range| {
654685 let indent_level = helix_core::indent::suggested_indent_for_pos(
655− cx.view.doc.syntax.as_ref(),
656− &cx.view.doc.state,
686+ view.doc.syntax.as_ref(),
687+ &view.doc.state,
657688 range.head,
658689 true,
659690 );
@@ -663,32 +694,36 @@ pub mod insert {
663694 text.push_str(&indent);
664695 (range.head, range.head, Some(text.into()))
665696 });
666− cx.view.doc.apply(&transaction);
697+ view.doc.apply(&transaction);
667698 }
668699
669700 // TODO: handle indent-aware delete
670701 pub fn delete_char_backward(cx: &mut Context) {
671− let text = &cx.view.doc.text().slice(..);
672− let transaction = Transaction::change_by_selection(&cx.view.doc.state, |range| {
702+ let count = cx.count;
703+ let view = cx.view();
704+ let text = &view.doc.text().slice(..);
705+ let transaction = Transaction::change_by_selection(&view.doc.state, |range| {
673706 (
674− graphemes::nth_prev_grapheme_boundary(text, range.head, cx.count),
707+ graphemes::nth_prev_grapheme_boundary(text, range.head, count),
675708 range.head,
676709 None,
677710 )
678711 });
679− cx.view.doc.apply(&transaction);
712+ view.doc.apply(&transaction);
680713 }
681714
682715 pub fn delete_char_forward(cx: &mut Context) {
683− let text = &cx.view.doc.text().slice(..);
684− let transaction = Transaction::change_by_selection(&cx.view.doc.state, |range| {
716+ let count = cx.count;
717+ let view = cx.view();
718+ let text = &view.doc.text().slice(..);
719+ let transaction = Transaction::change_by_selection(&view.doc.state, |range| {
685720 (
686721 range.head,
687− graphemes::nth_next_grapheme_boundary(text, range.head, cx.count),
722+ graphemes::nth_next_grapheme_boundary(text, range.head, count),
688723 None,
689724 )
690725 });
691− cx.view.doc.apply(&transaction);
726+ view.doc.apply(&transaction);
692727 }
693728}
694729
@@ -702,23 +737,23 @@ pub fn insert_char_prompt(prompt: &mut Prompt, c: char) {
702737// storing it?
703738
704739pub fn undo(cx: &mut Context) {
705− cx.view.doc.undo();
740+ cx.view().doc.undo();
706741}
707742
708743pub fn redo(cx: &mut Context) {
709− cx.view.doc.redo();
744+ cx.view().doc.redo();
710745}
711746
712747// Yank / Paste
713748
714749pub fn yank(cx: &mut Context) {
715750 // TODO: should selections be made end inclusive?
716− let values = cx
717− .view
751+ let view = cx.view();
752+ let values = view
718753 .doc
719754 .state
720755 .selection()
721− .fragments(&cx.view.doc.text().slice(..))
756+ .fragments(&view.doc.text().slice(..))
722757 .map(|cow| cow.into_owned())
723758 .collect();
724759
@@ -756,21 +791,23 @@ pub fn paste(cx: &mut Context) {
756791
757792 let mut values = values.into_iter().map(Tendril::from).chain(repeat);
758793
794+ let view = cx.view();
795+
759796 let transaction = if linewise {
760797 // paste on the next line
761798 // TODO: can simply take a range + modifier and compute the right pos without ifs
762− let text = cx.view.doc.text();
763− Transaction::change_by_selection(&cx.view.doc.state, |range| {
799+ let text = view.doc.text();
800+ Transaction::change_by_selection(&view.doc.state, |range| {
764801 let line_end = text.line_to_char(text.char_to_line(range.head) + 1);
765802 (line_end, line_end, Some(values.next().unwrap()))
766803 })
767804 } else {
768− Transaction::change_by_selection(&cx.view.doc.state, |range| {
805+ Transaction::change_by_selection(&view.doc.state, |range| {
769806 (range.head + 1, range.head + 1, Some(values.next().unwrap()))
770807 })
771808 };
772809
773− cx.view.doc.apply(&transaction);
810+ view.doc.apply(&transaction);
774811 append_changes_to_history(cx);
775812 }
776813}
@@ -793,28 +830,30 @@ fn get_lines(view: &View) -> Vec<usize> {
793830}
794831
795832pub fn indent(cx: &mut Context) {
796− let lines = get_lines(cx.view);
833+ let lines = get_lines(cx.view());
797834
798835 // Indent by one level
799836 let indent = Tendril::from(" ".repeat(TAB_WIDTH));
800837
838+ let view = cx.view();
839+
801840 let transaction = Transaction::change(
802− &cx.view.doc.state,
841+ &view.doc.state,
803842 lines.into_iter().map(|line| {
804− let pos = cx.view.doc.text().line_to_char(line);
843+ let pos = view.doc.text().line_to_char(line);
805844 (pos, pos, Some(indent.clone()))
806845 }),
807846 );
808− cx.view.doc.apply(&transaction);
847+ cx.view().doc.apply(&transaction);
809848 append_changes_to_history(cx);
810849}
811850
812851pub fn unindent(cx: &mut Context) {
813− let lines = get_lines(cx.view);
852+ let lines = get_lines(cx.view());
814853 let mut changes = Vec::with_capacity(lines.len());
815854
816855 for line_idx in lines {
817− let line = cx.view.doc.text().line(line_idx);
856+ let line = cx.view().doc.text().line(line_idx);
818857 let mut width = 0;
819858
820859 for ch in line.chars() {
@@ -830,14 +869,14 @@ pub fn unindent(cx: &mut Context) {
830869 }
831870
832871 if width > 0 {
833− let start = cx.view.doc.text().line_to_char(line_idx);
872+ let start = cx.view().doc.text().line_to_char(line_idx);
834873 changes.push((start, start + width, None))
835874 }
836875 }
837876
838− let transaction = Transaction::change(&cx.view.doc.state, changes.into_iter());
877+ let transaction = Transaction::change(&cx.view().doc.state, changes.into_iter());
839878
840− cx.view.doc.apply(&transaction);
879+ cx.view().doc.apply(&transaction);
841880 append_changes_to_history(cx);
842881}
843882
@@ -852,21 +891,25 @@ pub fn save(cx: &mut Context) {
852891 // Spawns an async task to actually do the saving. This way we prevent blocking.
853892
854893 // TODO: handle save errors somehow?
855− cx.executor.spawn(cx.view.doc.save()).detach();
894+ cx.executor.spawn(cx.view().doc.save()).detach();
856895}
857896
858897pub fn completion(cx: &mut Context) {
859− let language_server = cx.language_servers.get("rust", &cx.executor).unwrap();
898+ let language_server = cx
899+ .editor
900+ .language_servers
901+ .get("source.rust", &cx.executor)
902+ .unwrap();
860903 use log::info;
861904
905+ let view = cx.view();
906+
862907 // TODO: blocking here is not ideal
863− let pos = helix_lsp::util::pos_to_lsp_pos(
864− &cx.view.doc.text().slice(..),
865− cx.view.doc.selection().cursor(),
866− );
908+ let pos =
909+ helix_lsp::util::pos_to_lsp_pos(&view.doc.text().slice(..), view.doc.selection().cursor());
867910
868911 // TODO: handle fails
869− let res = smol::block_on(language_server.completion(cx.view.doc.identifier(), pos))
912+ let res = smol::block_on(language_server.completion(cx.view().doc.identifier(), pos))
870913 .unwrap_or_default();
871914
872915 // TODO: if no completion, show some message or something
@@ -903,7 +946,7 @@ pub fn completion(cx: &mut Context) {
903946 }
904947 }
905948
906− let view = editor.view_mut().unwrap();
949+ let view = editor.view_mut();
907950 let transaction =
908951 util::generate_transaction_from_edits(&view.doc.state, vec![edit]);
909952 view.doc.apply(&transaction);
helix-term/src/compositor.rs−1
@@ -39,7 +39,6 @@ use helix_view::{Editor, View};
3939// shared with commands.rs
4040pub struct Context<'a> {
4141 pub editor: &'a mut Editor,
42− pub language_servers: &'a helix_lsp::Registry,
4342 pub executor: &'static smol::Executor<'static>,
4443}
4544
helix-term/src/ui/editor.rs+39−43
@@ -251,55 +251,52 @@ impl Component for EditorView {
251251 Event::Resize(width, height) => {
252252 // TODO: simplistic ensure cursor in view for now
253253 // TODO: loop over views
254− if let Some(view) = cx.editor.view_mut() {
255− view.size = (width, height);
256− view.ensure_cursor_in_view()
257− };
254+ let view = cx.editor.view_mut();
255+ view.size = (width, height);
256+ view.ensure_cursor_in_view();
258257 EventResult::Consumed(None)
259258 }
260259 Event::Key(event) => {
261− if let Some(view) = cx.editor.view_mut() {
262− let keys = vec![event];
263− // TODO: sequences (`gg`)
264− let mode = view.doc.mode();
265− // TODO: handle count other than 1
266− let mut cx = commands::Context {
267− view,
268− executor: cx.executor,
269− language_servers: cx.language_servers,
270− count: 1,
271− callback: None,
272− };
260+ let view = cx.editor.view_mut();
261+
262+ let keys = vec![event];
263+ // TODO: sequences (`gg`)
264+ let mode = view.doc.mode();
265+ // TODO: handle count other than 1
266+ let mut cxt = commands::Context {
267+ executor: cx.executor,
268+ editor: &mut cx.editor,
269+ count: 1,
270+ callback: None,
271+ };
273272
274− match mode {
275− Mode::Insert => {
276− if let Some(command) = self.keymap[&Mode::Insert].get(&keys) {
277− command(&mut cx);
278− } else if let KeyEvent {
279− code: KeyCode::Char(c),
280− ..
281− } = event
282− {
283− commands::insert::insert_char(&mut cx, c);
284− }
273+ match mode {
274+ Mode::Insert => {
275+ if let Some(command) = self.keymap[&Mode::Insert].get(&keys) {
276+ command(&mut cxt);
277+ } else if let KeyEvent {
278+ code: KeyCode::Char(c),
279+ ..
280+ } = event
281+ {
282+ commands::insert::insert_char(&mut cxt, c);
285283 }
286− mode => {
287− if let Some(command) = self.keymap[&mode].get(&keys) {
288− command(&mut cx);
284+ }
285+ mode => {
286+ if let Some(command) = self.keymap[&mode].get(&keys) {
287+ command(&mut cxt);
289288
290− // TODO: simplistic ensure cursor in view for now
291− }
289+ // TODO: simplistic ensure cursor in view for now
292290 }
293291 }
294− // appease borrowck
295− let callback = cx.callback.take();
292+ }
296293
297− view.ensure_cursor_in_view();
294+ // appease borrowck
295+ let callback = cxt.callback.take();
296+ drop(cxt);
297+ cx.editor.view_mut().ensure_cursor_in_view();
298298
299− EventResult::Consumed(callback)
300− } else {
301− EventResult::Ignored
302− }
299+ EventResult::Consumed(callback)
303300 }
304301 Event::Mouse(_) => EventResult::Ignored,
305302 }
@@ -309,9 +306,8 @@ impl Component for EditorView {
309306 // SAFETY: we cheat around the view_mut() borrow because it doesn't allow us to also borrow
310307 // theme. Theme is immutable mutating view won't disrupt theme_ref.
311308 let theme_ref = unsafe { &*(&cx.editor.theme as *const Theme) };
312− if let Some(view) = cx.editor.view_mut() {
313− self.render_view(view, area, surface, theme_ref);
314− }
309+ let view = cx.editor.view_mut();
310+ self.render_view(view, area, surface, theme_ref);
315311
316312 // TODO: drop unwrap
317313 }
@@ -321,7 +317,7 @@ impl Component for EditorView {
321317 // Mode::Insert => write!(stdout, "\x1B[6 q"),
322318 // mode => write!(stdout, "\x1B[2 q"),
323319 // };
324− let view = ctx.editor.view().unwrap();
320+ let view = ctx.editor.view();
325321 let cursor = view.doc.state.selection().cursor();
326322
327323 let mut pos = view
helix-term/src/ui/mod.rs+4−4
@@ -16,7 +16,7 @@ pub fn text_color() -> Style {
1616}
1717
1818use std::path::{Path, PathBuf};
19−pub fn file_picker(root: &str) -> Picker<PathBuf> {
19+pub fn file_picker(root: &str, ex: &'static smol::Executor) -> Picker<PathBuf> {
2020 use ignore::Walk;
2121 // TODO: determine root based on git root
2222 let files = Walk::new(root).filter_map(|entry| match entry {
@@ -40,9 +40,9 @@ pub fn file_picker(root: &str) -> Picker<PathBuf> {
4040 // format_fn
4141 path.strip_prefix("./").unwrap().to_str().unwrap().into()
4242 },
43− |editor: &mut Editor, path: &PathBuf| {
44− let size = editor.view().unwrap().size;
45− editor.open(path.into(), size);
43+ move |editor: &mut Editor, path: &PathBuf| {
44+ let size = editor.view().size;
45+ editor.open(path.into(), size, ex);
4646 },
4747 )
4848}
helix-view/src/editor.rs+33−6
@@ -10,6 +10,7 @@ pub struct Editor {
1010 pub focus: usize,
1111 pub should_close: bool,
1212 pub theme: Theme, // TODO: share one instance
13+ pub language_servers: helix_lsp::Registry,
1314}
1415
1516impl Default for Editor {
@@ -21,28 +22,54 @@ impl Default for Editor {
2122impl Editor {
2223 pub fn new() -> Self {
2324 let theme = Theme::default();
25+ let language_servers = helix_lsp::Registry::new();
2426
2527 Self {
2628 views: Vec::new(),
2729 focus: 0,
2830 should_close: false,
2931 theme,
32+ language_servers,
3033 }
3134 }
3235
33− pub fn open(&mut self, path: PathBuf, size: (u16, u16)) -> Result<(), Error> {
36+ pub fn open(
37+ &mut self,
38+ path: PathBuf,
39+ size: (u16, u16),
40+ executor: &smol::Executor,
41+ ) -> Result<(), Error> {
3442 let pos = self.views.len();
35− let doc = Document::load(path, self.theme.scopes())?;
43+ let mut doc = Document::load(path, self.theme.scopes())?;
44+
45+ // try to find a language server based on the language name
46+ let language_server = doc
47+ .language
48+ .as_ref()
49+ .and_then(|language| self.language_servers.get(&language, &executor));
50+
51+ if let Some(language_server) = language_server {
52+ // TODO: do this everywhere
53+ doc.set_language_server(Some(language_server.clone()));
54+
55+ smol::block_on(language_server.text_document_did_open(
56+ doc.url().unwrap(),
57+ doc.version,
58+ doc.text(),
59+ ))
60+ .unwrap();
61+ }
62+
3663 self.views.push(View::new(doc, size)?);
3764 self.focus = pos;
3865 Ok(())
3966 }
4067
41− pub fn view(&self) -> Option<&View> {
42− self.views.get(self.focus)
68+ pub fn view(&self) -> &View {
69+ self.views.get(self.focus).unwrap()
4370 }
4471
45− pub fn view_mut(&mut self) -> Option<&mut View> {
46− self.views.get_mut(self.focus)
72+ pub fn view_mut(&mut self) -> &mut View {
73+ self.views.get_mut(self.focus).unwrap()
4774 }
4875}