on master help sign in
Refactoring: move language_servers into Editor, proper load for doc.
05c7fb9Blaž Hrastnik
helix-lsp/src/lib.rs+1−1
@@ -114,7 +114,7 @@ impl Registry {
114 pub fn new() -> Self {
114 pub fn new() -> Self {
115 let mut inner = HashMap::new();
115 let mut inner = HashMap::new();
116
116
117− inner.insert("rust".to_string(), OnceCell::new());
117+ inner.insert("source.rust".to_string(), OnceCell::new());
118
118
119 Self {
119 Self {
120 inner,
120 inner,
helix-term/src/application.rs+13−38
@@ -33,8 +33,6 @@ pub struct Application {
33 terminal: Terminal,
33 terminal: Terminal,
34
34
35 executor: &'static smol::Executor<'static>,
35 executor: &'static smol::Executor<'static>,
36− language_server: Arc<helix_lsp::Client>,
37− language_servers: helix_lsp::Registry,
38}
36}
39
37
40impl Application {
38impl Application {
@@ -44,18 +42,8 @@ impl Application {
44 let mut editor = Editor::new();
42 let mut editor = Editor::new();
45 let size = terminal.size()?;
43 let size = terminal.size()?;
46
44
47− let language_servers = helix_lsp::Registry::new();
48− let language_server = language_servers.get("rust", &executor).unwrap();
49−
50 if let Some(file) = args.values_of_t::<PathBuf>("files").unwrap().pop() {
45 if let Some(file) = args.values_of_t::<PathBuf>("files").unwrap().pop() {
51− editor.open(file, (size.width, size.height))?;
46+ editor.open(file, (size.width, size.height), executor)?;
52−
53− // TODO: do this everywhere
54− editor
55− .view_mut()
56− .unwrap()
57− .doc
58− .set_language_server(Some(language_server.clone()));
59 }
47 }
60
48
61 let mut compositor = Compositor::new();
49 let mut compositor = Compositor::new();
@@ -67,8 +55,6 @@ impl Application {
67 compositor,
55 compositor,
68
56
69 executor,
57 executor,
70− language_server,
71− language_servers,
72 };
58 };
73
59
74 Ok(app)
60 Ok(app)
@@ -76,15 +62,10 @@ impl Application {
76
62
77 fn render(&mut self) {
63 fn render(&mut self) {
78 let executor = &self.executor;
64 let executor = &self.executor;
79− let language_servers = &self.language_servers;
80 let editor = &mut self.editor;
65 let editor = &mut self.editor;
81 let compositor = &self.compositor;
66 let compositor = &self.compositor;
82
67
83− let mut cx = crate::compositor::Context {
68+ let mut cx = crate::compositor::Context { editor, executor };
84− editor,
85− executor,
86− language_servers,
87− };
88 let area = self.terminal.size().unwrap();
69 let area = self.terminal.size().unwrap();
89
70
90 compositor.render(area, self.terminal.current_buffer_mut(), &mut cx);
71 compositor.render(area, self.terminal.current_buffer_mut(), &mut cx);
@@ -97,12 +78,6 @@ impl Application {
97 pub async fn event_loop(&mut self) {
78 pub async fn event_loop(&mut self) {
98 let mut reader = EventStream::new();
79 let mut reader = EventStream::new();
99
80
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−
106 self.render();
81 self.render();
107
82
108 loop {
83 loop {
@@ -115,7 +90,7 @@ impl Application {
115 event = reader.next().fuse() => {
90 event = reader.next().fuse() => {
116 self.handle_terminal_events(event)
91 self.handle_terminal_events(event)
117 }
92 }
118− call = self.language_servers.incoming.next().fuse() => {
93+ call = self.editor.language_servers.incoming.next().fuse() => {
119 self.handle_language_server_message(call).await
94 self.handle_language_server_message(call).await
120 }
95 }
121 }
96 }
@@ -126,7 +101,6 @@ impl Application {
126 let mut cx = crate::compositor::Context {
101 let mut cx = crate::compositor::Context {
127 editor: &mut self.editor,
102 editor: &mut self.editor,
128 executor: &self.executor,
103 executor: &self.executor,
129− language_servers: &self.language_servers,
130 };
104 };
131 // Handle key events
105 // Handle key events
132 let should_redraw = match event {
106 let should_redraw = match event {
@@ -197,16 +171,17 @@ impl Application {
197 Some(Call::MethodCall(call)) => {
171 Some(Call::MethodCall(call)) => {
198 debug!("Method not found {}", call.method);
172 debug!("Method not found {}", call.method);
199
173
200− self.language_server.reply(
174+ // self.language_server.reply(
201− call.id,
175+ // call.id,
202− // TODO: make a Into trait that can cast to Err(jsonrpc::Error)
176+ // // TODO: make a Into trait that can cast to Err(jsonrpc::Error)
203− Err(helix_lsp::jsonrpc::Error {
177+ // Err(helix_lsp::jsonrpc::Error {
204− code: helix_lsp::jsonrpc::ErrorCode::MethodNotFound,
178+ // code: helix_lsp::jsonrpc::ErrorCode::MethodNotFound,
205− message: "Method not found".to_string(),
179+ // message: "Method not found".to_string(),
206− data: None,
180+ // data: None,
207− }),
181+ // }),
208− );
182+ // );
209 }
183 }
184+ None => (),
210 e => unreachable!("{:?}", e),
185 e => unreachable!("{:?}", e),
211 }
186 }
212 }
187 }
helix-term/src/commands.rs+217−174
@@ -18,57 +18,66 @@ use helix_view::{
18 Editor,
18 Editor,
19};
19};
20
20
21−pub struct Context<'a, 'b> {
21+pub struct Context<'a> {
22 pub count: usize,
22 pub count: usize,
23− pub view: &'a mut View,
23+ pub editor: &'a mut Editor,
24− pub executor: &'a smol::Executor<'b>,
24+ pub executor: &'static smol::Executor<'static>,
25− pub language_servers: &'a helix_lsp::Registry,
26
25
27 pub callback: Option<crate::compositor::Callback>,
26 pub callback: Option<crate::compositor::Callback>,
28}
27}
29
28
29+impl<'a> Context<'a> {
30+ pub fn view(&mut self) -> &mut View {
31+ self.editor.view_mut()
32+ }
33+}
34+
30/// A command is a function that takes the current state and a count, and does a side-effect on the
35/// A command is a function that takes the current state and a count, and does a side-effect on the
31/// state (usually by creating and applying a transaction).
36/// state (usually by creating and applying a transaction).
32pub type Command = fn(cx: &mut Context);
37pub type Command = fn(cx: &mut Context);
33
38
34pub fn move_char_left(cx: &mut Context) {
39pub fn move_char_left(cx: &mut Context) {
40+ let count = cx.count;
35 let selection =
41 let selection =
36− cx.view
42+ cx.view()
37 .doc
43 .doc
38 .state
44 .state
39− .move_selection(Direction::Backward, Granularity::Character, cx.count);
45+ .move_selection(Direction::Backward, Granularity::Character, count);
40− cx.view.doc.set_selection(selection);
46+ cx.view().doc.set_selection(selection);
41}
47}
42
48
43pub fn move_char_right(cx: &mut Context) {
49pub fn move_char_right(cx: &mut Context) {
50+ let count = cx.count;
44 let selection =
51 let selection =
45− cx.view
52+ cx.view()
46 .doc
53 .doc
47 .state
54 .state
48− .move_selection(Direction::Forward, Granularity::Character, cx.count);
55+ .move_selection(Direction::Forward, Granularity::Character, count);
49− cx.view.doc.set_selection(selection);
56+ cx.view().doc.set_selection(selection);
50}
57}
51
58
52pub fn move_line_up(cx: &mut Context) {
59pub fn move_line_up(cx: &mut Context) {
60+ let count = cx.count;
53 let selection =
61 let selection =
54− cx.view
62+ cx.view()
55 .doc
63 .doc
56 .state
64 .state
57− .move_selection(Direction::Backward, Granularity::Line, cx.count);
65+ .move_selection(Direction::Backward, Granularity::Line, count);
58− cx.view.doc.set_selection(selection);
66+ cx.view().doc.set_selection(selection);
59}
67}
60
68
61pub fn move_line_down(cx: &mut Context) {
69pub fn move_line_down(cx: &mut Context) {
70+ let count = cx.count;
62 let selection =
71 let selection =
63− cx.view
72+ cx.view()
64 .doc
73 .doc
65 .state
74 .state
66− .move_selection(Direction::Forward, Granularity::Line, cx.count);
75+ .move_selection(Direction::Forward, Granularity::Line, count);
67− cx.view.doc.set_selection(selection);
76+ cx.view().doc.set_selection(selection);
68}
77}
69
78
70pub fn move_line_end(cx: &mut Context) {
79pub 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);
72
81
73 let positions = lines
82 let positions = lines
74 .into_iter()
83 .into_iter()
@@ -77,75 +86,85 @@ pub fn move_line_end(cx: &mut Context) {
77
86
78 // Line end is pos at the start of next line - 1
87 // Line end is pos at the start of next line - 1
79 // subtract another 1 because the line ends with \n
88 // subtract another 1 because the line ends with \n
89+ cx.view()
90+ .doc
91+ .text()
80− cx.view.doc.text().line_to_char(index + 1).saturating_sub(2)
92+ .line_to_char(index + 1)
93+ .saturating_sub(2)
81 })
94 })
82 .map(|pos| Range::new(pos, pos));
95 .map(|pos| Range::new(pos, pos));
83
96
84 let selection = Selection::new(positions.collect(), 0);
97 let selection = Selection::new(positions.collect(), 0);
85
98
86− cx.view.doc.set_selection(selection);
99+ cx.view().doc.set_selection(selection);
87}
100}
88
101
89pub fn move_line_start(cx: &mut Context) {
102pub 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);
91
104
92 let positions = lines
105 let positions = lines
93 .into_iter()
106 .into_iter()
94 .map(|index| {
107 .map(|index| {
95 // adjust all positions to the start of the line.
108 // 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)
97 })
110 })
98 .map(|pos| Range::new(pos, pos));
111 .map(|pos| Range::new(pos, pos));
99
112
100 let selection = Selection::new(positions.collect(), 0);
113 let selection = Selection::new(positions.collect(), 0);
101
114
102− cx.view.doc.set_selection(selection);
115+ cx.view().doc.set_selection(selection);
103}
116}
104
117
105pub fn move_next_word_start(cx: &mut Context) {
118pub fn move_next_word_start(cx: &mut Context) {
119+ let count = cx.count;
120+ let view = cx.view();
106− let pos = cx.view.doc.state.move_pos(
121+ let pos = view.doc.state.move_pos(
107− cx.view.doc.selection().cursor(),
122+ view.doc.selection().cursor(),
108 Direction::Forward,
123 Direction::Forward,
109 Granularity::Word,
124 Granularity::Word,
110− cx.count,
125+ count,
111 );
126 );
112
127
113− cx.view.doc.set_selection(Selection::point(pos));
128+ view.doc.set_selection(Selection::point(pos));
114}
129}
115
130
116pub fn move_prev_word_start(cx: &mut Context) {
131pub fn move_prev_word_start(cx: &mut Context) {
132+ let count = cx.count;
133+ let view = cx.view();
117− let pos = cx.view.doc.state.move_pos(
134+ let pos = view.doc.state.move_pos(
118− cx.view.doc.selection().cursor(),
135+ view.doc.selection().cursor(),
119 Direction::Backward,
136 Direction::Backward,
120 Granularity::Word,
137 Granularity::Word,
121− cx.count,
138+ count,
122 );
139 );
123
140
124− cx.view.doc.set_selection(Selection::point(pos));
141+ view.doc.set_selection(Selection::point(pos));
125}
142}
126
143
127pub fn move_next_word_end(cx: &mut Context) {
144pub fn move_next_word_end(cx: &mut Context) {
145+ let count = cx.count;
146+ let view = cx.view();
128 let pos = State::move_next_word_end(
147 let pos = State::move_next_word_end(
129− &cx.view.doc.text().slice(..),
148+ &view.doc.text().slice(..),
130− cx.view.doc.selection().cursor(),
149+ view.doc.selection().cursor(),
131− cx.count,
150+ count,
132 );
151 );
133
152
134− cx.view.doc.set_selection(Selection::point(pos));
153+ view.doc.set_selection(Selection::point(pos));
135}
154}
136
155
137pub fn move_file_start(cx: &mut Context) {
156pub 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));
139
158
140− cx.view.doc.mode = Mode::Normal;
159+ cx.view().doc.mode = Mode::Normal;
141}
160}
142
161
143pub fn move_file_end(cx: &mut Context) {
162pub fn move_file_end(cx: &mut Context) {
144− let text = &cx.view.doc.text();
163+ let text = &cx.view().doc.text();
145 let last_line = text.line_to_char(text.len_lines().saturating_sub(2));
164 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));
147
166
148− cx.view.doc.mode = Mode::Normal;
167+ cx.view().doc.mode = Mode::Normal;
149}
168}
150
169
151pub fn check_cursor_in_view(view: &View) -> bool {
170pub fn check_cursor_in_view(view: &View) -> bool {
@@ -160,93 +179,98 @@ pub fn check_cursor_in_view(view: &View) -> bool {
160}
179}
161
180
162pub fn page_up(cx: &mut Context) {
181pub fn page_up(cx: &mut Context) {
182+ let view = cx.view();
163− if cx.view.first_line < PADDING {
183+ if view.first_line < PADDING {
164 return;
184 return;
165 }
185 }
166
186
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);
168
188
169− if !check_cursor_in_view(cx.view) {
189+ if !check_cursor_in_view(view) {
170− let text = cx.view.doc.text();
190+ let text = view.doc.text();
171− let pos = text.line_to_char(cx.view.last_line().saturating_sub(PADDING));
191+ let pos = text.line_to_char(view.last_line().saturating_sub(PADDING));
172− cx.view.doc.set_selection(Selection::point(pos));
192+ view.doc.set_selection(Selection::point(pos));
173 }
193 }
174}
194}
175
195
176pub fn page_down(cx: &mut Context) {
196pub fn page_down(cx: &mut Context) {
197+ let view = cx.view();
177− cx.view.first_line += cx.view.size.1 as usize + PADDING;
198+ view.first_line += view.size.1 as usize + PADDING;
178
199
179− if cx.view.first_line < cx.view.doc.text().len_lines() {
200+ if view.first_line < view.doc.text().len_lines() {
180− let text = cx.view.doc.text();
201+ let text = view.doc.text();
181− let pos = text.line_to_char(cx.view.first_line as usize);
202+ let pos = text.line_to_char(view.first_line as usize);
182− cx.view.doc.set_selection(Selection::point(pos));
203+ view.doc.set_selection(Selection::point(pos));
183 }
204 }
184}
205}
185
206
186pub fn half_page_up(cx: &mut Context) {
207pub fn half_page_up(cx: &mut Context) {
208+ let view = cx.view();
187− if cx.view.first_line < PADDING {
209+ if view.first_line < PADDING {
188 return;
210 return;
189 }
211 }
190
212
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);
195
214
196− if !check_cursor_in_view(cx.view) {
215+ if !check_cursor_in_view(view) {
197− let text = &cx.view.doc.text();
216+ let text = &view.doc.text();
198− let pos = text.line_to_char(cx.view.last_line() - PADDING);
217+ let pos = text.line_to_char(view.last_line() - PADDING);
199− cx.view.doc.set_selection(Selection::point(pos));
218+ view.doc.set_selection(Selection::point(pos));
200 }
219 }
201}
220}
202
221
203pub fn half_page_down(cx: &mut Context) {
222pub fn half_page_down(cx: &mut Context) {
223+ let view = cx.view();
204− let lines = cx.view.doc.text().len_lines();
224+ let lines = view.doc.text().len_lines();
205− if cx.view.first_line < lines.saturating_sub(cx.view.size.1 as usize) {
225+ if view.first_line < lines.saturating_sub(view.size.1 as usize) {
206− cx.view.first_line += cx.view.size.1 as usize / 2;
226+ view.first_line += view.size.1 as usize / 2;
207 }
227 }
208− if !check_cursor_in_view(cx.view) {
228+ if !check_cursor_in_view(view) {
209− let text = cx.view.doc.text();
229+ let text = view.doc.text();
210− let pos = text.line_to_char(cx.view.first_line as usize);
230+ let pos = text.line_to_char(view.first_line as usize);
211− cx.view.doc.set_selection(Selection::point(pos));
231+ view.doc.set_selection(Selection::point(pos));
212 }
232 }
213}
233}
214// avoid select by default by having a visual mode switch that makes movements into selects
234// avoid select by default by having a visual mode switch that makes movements into selects
215
235
216pub fn extend_char_left(cx: &mut Context) {
236pub fn extend_char_left(cx: &mut Context) {
237+ let count = cx.count;
238+ let view = cx.view();
217 let selection =
239 let selection =
218− cx.view
240+ view.doc
219− .doc
220 .state
241 .state
221− .extend_selection(Direction::Backward, Granularity::Character, cx.count);
242+ .extend_selection(Direction::Backward, Granularity::Character, count);
222− cx.view.doc.set_selection(selection);
243+ view.doc.set_selection(selection);
223}
244}
224
245
225pub fn extend_char_right(cx: &mut Context) {
246pub fn extend_char_right(cx: &mut Context) {
247+ let count = cx.count;
248+ let view = cx.view();
226 let selection =
249 let selection =
227− cx.view
250+ view.doc
228− .doc
229 .state
251 .state
230− .extend_selection(Direction::Forward, Granularity::Character, cx.count);
252+ .extend_selection(Direction::Forward, Granularity::Character, count);
231− cx.view.doc.set_selection(selection);
253+ view.doc.set_selection(selection);
232}
254}
233
255
234pub fn extend_line_up(cx: &mut Context) {
256pub fn extend_line_up(cx: &mut Context) {
235− let selection =
257+ let count = cx.count;
236− cx.view
258+ let view = cx.view();
259+ let selection = view
237− .doc
260+ .doc
238− .state
261+ .state
239− .extend_selection(Direction::Backward, Granularity::Line, cx.count);
262+ .extend_selection(Direction::Backward, Granularity::Line, count);
240− cx.view.doc.set_selection(selection);
263+ view.doc.set_selection(selection);
241}
264}
242
265
243pub fn extend_line_down(cx: &mut Context) {
266pub fn extend_line_down(cx: &mut Context) {
244− let selection =
267+ let count = cx.count;
245− cx.view
268+ let view = cx.view();
269+ let selection = view
246− .doc
270+ .doc
247− .state
271+ .state
248− .extend_selection(Direction::Forward, Granularity::Line, cx.count);
272+ .extend_selection(Direction::Forward, Granularity::Line, count);
249− cx.view.doc.set_selection(selection);
273+ view.doc.set_selection(selection);
250}
274}
251
275
252pub fn split_selection(cx: &mut Context) {
276pub fn split_selection(cx: &mut Context) {
@@ -263,7 +287,7 @@ pub fn split_selection(cx: &mut Context) {
263 // # update state
287 // # update state
264 // }
288 // }
265
289
266− let snapshot = cx.view.doc.state.clone();
290+ let snapshot = cx.view().doc.state.clone();
267
291
268 let prompt = Prompt::new(
292 let prompt = Prompt::new(
269 "split:".to_string(),
293 "split:".to_string(),
@@ -272,7 +296,7 @@ pub fn split_selection(cx: &mut Context) {
272 match event {
296 match event {
273 PromptEvent::Abort => {
297 PromptEvent::Abort => {
274 // revert state
298 // revert state
275− let view = editor.view_mut().unwrap();
299+ let view = editor.view_mut();
276 view.doc.state = snapshot.clone();
300 view.doc.state = snapshot.clone();
277 }
301 }
278 PromptEvent::Validate => {
302 PromptEvent::Validate => {
@@ -281,7 +305,7 @@ pub fn split_selection(cx: &mut Context) {
281 PromptEvent::Update => {
305 PromptEvent::Update => {
282 match Regex::new(input) {
306 match Regex::new(input) {
283 Ok(regex) => {
307 Ok(regex) => {
284− let view = editor.view_mut().unwrap();
308+ let view = editor.view_mut();
285
309
286 // revert state to what it was before the last update
310 // revert state to what it was before the last update
287 view.doc.state = snapshot.clone();
311 view.doc.state = snapshot.clone();
@@ -306,32 +330,33 @@ pub fn split_selection(cx: &mut Context) {
306}
330}
307
331
308pub fn split_selection_on_newline(cx: &mut Context) {
332pub fn split_selection_on_newline(cx: &mut Context) {
333+ let view = cx.view();
309− let text = &cx.view.doc.text().slice(..);
334+ let text = &view.doc.text().slice(..);
310 // only compile the regex once
335 // only compile the regex once
311 #[allow(clippy::trivial_regex)]
336 #[allow(clippy::trivial_regex)]
312 static REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"\n").unwrap());
337 static REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"\n").unwrap());
313− let selection = selection::split_on_matches(text, cx.view.doc.selection(), &REGEX);
338+ let selection = selection::split_on_matches(text, view.doc.selection(), &REGEX);
314− cx.view.doc.set_selection(selection);
339+ view.doc.set_selection(selection);
315}
340}
316
341
317pub fn select_line(cx: &mut Context) {
342pub fn select_line(cx: &mut Context) {
318 // TODO: count
343 // TODO: count
319− let pos = cx.view.doc.selection().primary();
344+ let pos = cx.view().doc.selection().primary();
320− let text = cx.view.doc.text();
345+ let text = cx.view().doc.text();
321 let line = text.char_to_line(pos.head);
346 let line = text.char_to_line(pos.head);
322 let start = text.line_to_char(line);
347 let start = text.line_to_char(line);
323 let end = text.line_to_char(line + 1).saturating_sub(1);
348 let end = text.line_to_char(line + 1).saturating_sub(1);
324
349
325− cx.view.doc.set_selection(Selection::single(start, end));
350+ cx.view().doc.set_selection(Selection::single(start, end));
326}
351}
327
352
328// heuristic: append changes to history after each command, unless we're in insert mode
353// heuristic: append changes to history after each command, unless we're in insert mode
329
354
330fn _delete_selection(cx: &mut Context) {
355fn _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| {
332 (range.from(), range.to() + 1, None)
357 (range.from(), range.to() + 1, None)
333 });
358 });
334− cx.view.doc.apply(&transaction);
359+ cx.view().doc.apply(&transaction);
335}
360}
336
361
337pub fn delete_selection(cx: &mut Context) {
362pub fn delete_selection(cx: &mut Context) {
@@ -347,26 +372,26 @@ pub fn change_selection(cx: &mut Context) {
347
372
348pub fn collapse_selection(cx: &mut Context) {
373pub fn collapse_selection(cx: &mut Context) {
349 let selection = cx
374 let selection = cx
350− .view
375+ .view()
351 .doc
376 .doc
352 .selection()
377 .selection()
353 .transform(|range| Range::new(range.head, range.head));
378 .transform(|range| Range::new(range.head, range.head));
354
379
355− cx.view.doc.set_selection(selection);
380+ cx.view().doc.set_selection(selection);
356}
381}
357
382
358pub fn flip_selections(cx: &mut Context) {
383pub fn flip_selections(cx: &mut Context) {
359 let selection = cx
384 let selection = cx
360− .view
385+ .view()
361 .doc
386 .doc
362 .selection()
387 .selection()
363 .transform(|range| Range::new(range.head, range.anchor));
388 .transform(|range| Range::new(range.head, range.anchor));
364
389
365− cx.view.doc.set_selection(selection);
390+ cx.view().doc.set_selection(selection);
366}
391}
367
392
368fn enter_insert_mode(cx: &mut Context) {
393fn enter_insert_mode(cx: &mut Context) {
369− cx.view.doc.mode = Mode::Insert;
394+ cx.view().doc.mode = Mode::Insert;
370
395
371 // TODO: store selection for undo
396 // TODO: store selection for undo
372}
397}
@@ -376,34 +401,36 @@ pub fn insert_mode(cx: &mut Context) {
376 enter_insert_mode(cx);
401 enter_insert_mode(cx);
377
402
378 let selection = cx
403 let selection = cx
379− .view
404+ .view()
380 .doc
405 .doc
381 .selection()
406 .selection()
382 .transform(|range| Range::new(range.to(), range.from()));
407 .transform(|range| Range::new(range.to(), range.from()));
383− cx.view.doc.set_selection(selection);
408+ cx.view().doc.set_selection(selection);
384}
409}
385
410
386// inserts at the end of each selection
411// inserts at the end of each selection
387pub fn append_mode(cx: &mut Context) {
412pub fn append_mode(cx: &mut Context) {
388 enter_insert_mode(cx);
413 enter_insert_mode(cx);
414+ let view = cx.view();
389− cx.view.doc.restore_cursor = true;
415+ view.doc.restore_cursor = true;
390
416
391 // TODO: as transaction
417 // TODO: as transaction
392− let text = &cx.view.doc.text().slice(..);
418+ let text = &view.doc.text().slice(..);
393− let selection = cx.view.doc.selection().transform(|range| {
419+ let selection = view.doc.selection().transform(|range| {
394 // TODO: to() + next char
420 // TODO: to() + next char
395 Range::new(
421 Range::new(
396 range.from(),
422 range.from(),
397 graphemes::next_grapheme_boundary(text, range.to()),
423 graphemes::next_grapheme_boundary(text, range.to()),
398 )
424 )
399 });
425 });
400− cx.view.doc.set_selection(selection);
426+ view.doc.set_selection(selection);
401}
427}
402
428
403// TODO: I, A, o and O can share a lot of the primitives.
429// TODO: I, A, o and O can share a lot of the primitives.
404pub fn command_mode(cx: &mut Context) {
430pub fn command_mode(cx: &mut Context) {
431+ let executor = cx.executor;
405 cx.callback = Some(Box::new(
432 cx.callback = Some(Box::new(
406− |compositor: &mut Compositor, editor: &mut Editor| {
433+ move |compositor: &mut Compositor, editor: &mut Editor| {
407 let prompt = Prompt::new(
434 let prompt = Prompt::new(
408 ":".to_owned(),
435 ":".to_owned(),
409 |_input: &str| {
436 |_input: &str| {
@@ -446,7 +473,7 @@ pub fn command_mode(cx: &mut Context) {
446 .filter(|command| command.contains(_input))
473 .filter(|command| command.contains(_input))
447 .collect()
474 .collect()
448 }, // completion
475 }, // completion
449− |editor: &mut Editor, input: &str, event: PromptEvent| {
476+ move |editor: &mut Editor, input: &str, event: PromptEvent| {
450 if event != PromptEvent::Validate {
477 if event != PromptEvent::Validate {
451 return;
478 return;
452 }
479 }
@@ -456,9 +483,8 @@ pub fn command_mode(cx: &mut Context) {
456 match *parts.as_slice() {
483 match *parts.as_slice() {
457 ["q"] => editor.should_close = true,
484 ["q"] => editor.should_close = true,
458 ["o", path] => {
485 ["o", path] => {
459− // TODO: make view()/view_mut() always contain a view.
460− let size = editor.view().unwrap().size;
486+ let size = editor.view().size;
461− editor.open(path.into(), size);
487+ editor.open(path.into(), size, executor);
462 }
488 }
463 _ => (),
489 _ => (),
464 }
490 }
@@ -469,9 +495,9 @@ pub fn command_mode(cx: &mut Context) {
469 ));
495 ));
470}
496}
471pub fn file_picker(cx: &mut Context) {
497pub fn file_picker(cx: &mut Context) {
498+ let picker = ui::file_picker("./", cx.executor);
472 cx.callback = Some(Box::new(
499 cx.callback = Some(Box::new(
473 |compositor: &mut Compositor, editor: &mut Editor| {
500 |compositor: &mut Compositor, editor: &mut Editor| {
474− let picker = ui::file_picker("./");
475 compositor.push(Box::new(picker));
501 compositor.push(Box::new(picker));
476 },
502 },
477 ));
503 ));
@@ -519,21 +545,23 @@ pub fn append_to_line(cx: &mut Context) {
519pub fn open_below(cx: &mut Context) {
545pub fn open_below(cx: &mut Context) {
520 enter_insert_mode(cx);
546 enter_insert_mode(cx);
521
547
548+ let view = cx.view();
549+
522− let lines = selection_lines(&cx.view.doc.state);
550+ let lines = selection_lines(&view.doc.state);
523
551
524 let positions: Vec<_> = lines
552 let positions: Vec<_> = lines
525 .into_iter()
553 .into_iter()
526 .map(|index| {
554 .map(|index| {
527 // adjust all positions to the end of the line/start of the next one.
555 // 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)
529 })
557 })
530 .collect();
558 .collect();
531
559
532 let changes = positions.iter().copied().map(|index| {
560 let changes = positions.iter().copied().map(|index| {
533 // TODO: share logic with insert_newline for indentation
561 // TODO: share logic with insert_newline for indentation
534 let indent_level = helix_core::indent::suggested_indent_for_pos(
562 let indent_level = helix_core::indent::suggested_indent_for_pos(
535− cx.view.doc.syntax.as_ref(),
563+ view.doc.syntax.as_ref(),
536− &cx.view.doc.state,
564+ &view.doc.state,
537 index,
565 index,
538 true,
566 true,
539 );
567 );
@@ -567,42 +595,42 @@ pub fn open_below(cx: &mut Context) {
567 0,
595 0,
568 );
596 );
569
597
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);
571
599
572− cx.view.doc.apply(&transaction);
600+ view.doc.apply(&transaction);
573}
601}
574
602
575// O inserts a new line before each line with a selection
603// O inserts a new line before each line with a selection
576
604
577fn append_changes_to_history(cx: &mut Context) {
605fn append_changes_to_history(cx: &mut Context) {
578− if cx.view.doc.changes.is_empty() {
606+ if cx.view().doc.changes.is_empty() {
579 return;
607 return;
580 }
608 }
581
609
582 // TODO: change -> change -> undo -> change -> change fails, probably old_state needs reset
610 // TODO: change -> change -> undo -> change -> change fails, probably old_state needs reset
583
611
584− let new_changeset = ChangeSet::new(cx.view.doc.text());
612+ let new_changeset = ChangeSet::new(cx.view().doc.text());
585− let changes = std::mem::replace(&mut cx.view.doc.changes, new_changeset);
613+ let changes = std::mem::replace(&mut cx.view().doc.changes, new_changeset);
586 // Instead of doing this messy merge we could always commit, and based on transaction
614 // Instead of doing this messy merge we could always commit, and based on transaction
587 // annotations either add a new layer or compose into the previous one.
615 // 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());
589
617
590 // increment document version
618 // increment document version
591 // TODO: needs to happen on undo/redo too
619 // TODO: needs to happen on undo/redo too
592− cx.view.doc.version += 1;
620+ cx.view().doc.version += 1;
593
621
594 // TODO: trigger lsp/documentDidChange with changes
622 // TODO: trigger lsp/documentDidChange with changes
595
623
596 // HAXX: we need to reconstruct the state as it was before the changes..
624 // HAXX: we need to reconstruct the state as it was before the changes..
597 let old_state = cx
625 let old_state = cx
598− .view
626+ .view()
599 .doc
627 .doc
600 .old_state
628 .old_state
601 .take()
629 .take()
602 .expect("no old_state available");
630 .expect("no old_state available");
603
631
604 // TODO: take transaction by value?
632 // TODO: take transaction by value?
605− cx.view
633+ cx.view()
606 .doc
634 .doc
607 .history
635 .history
608 .commit_revision(&transaction, &old_state);
636 .commit_revision(&transaction, &old_state);
@@ -611,27 +639,29 @@ fn append_changes_to_history(cx: &mut Context) {
611}
639}
612
640
613pub fn normal_mode(cx: &mut Context) {
641pub fn normal_mode(cx: &mut Context) {
614− cx.view.doc.mode = Mode::Normal;
642+ cx.view().doc.mode = Mode::Normal;
615
643
616 append_changes_to_history(cx);
644 append_changes_to_history(cx);
617
645
646+ let view = cx.view();
647+
618 // if leaving append mode, move cursor back by 1
648 // if leaving append mode, move cursor back by 1
619− if cx.view.doc.restore_cursor {
649+ if view.doc.restore_cursor {
620− let text = &cx.view.doc.text().slice(..);
650+ let text = &view.doc.text().slice(..);
621− let selection = cx.view.doc.selection().transform(|range| {
651+ let selection = view.doc.selection().transform(|range| {
622 Range::new(
652 Range::new(
623 range.from(),
653 range.from(),
624 graphemes::prev_grapheme_boundary(text, range.to()),
654 graphemes::prev_grapheme_boundary(text, range.to()),
625 )
655 )
626 });
656 });
627− cx.view.doc.set_selection(selection);
657+ view.doc.set_selection(selection);
628
658
629− cx.view.doc.restore_cursor = false;
659+ view.doc.restore_cursor = false;
630 }
660 }
631}
661}
632
662
633pub fn goto_mode(cx: &mut Context) {
663pub fn goto_mode(cx: &mut Context) {
634− cx.view.doc.mode = Mode::Goto;
664+ cx.view().doc.mode = Mode::Goto;
635}
665}
636
666
637// NOTE: Transactions in this module get appended to history when we switch back to normal mode.
667// NOTE: Transactions in this module get appended to history when we switch back to normal mode.
@@ -640,9 +670,9 @@ pub mod insert {
640 // TODO: insert means add text just before cursor, on exit we should be on the last letter.
670 // TODO: insert means add text just before cursor, on exit we should be on the last letter.
641 pub fn insert_char(cx: &mut Context, c: char) {
671 pub fn insert_char(cx: &mut Context, c: char) {
642 let c = Tendril::from_char(c);
672 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);
644
674
645− cx.view.doc.apply(&transaction);
675+ cx.view().doc.apply(&transaction);
646 }
676 }
647
677
648 pub fn insert_tab(cx: &mut Context) {
678 pub fn insert_tab(cx: &mut Context) {
@@ -650,10 +680,11 @@ pub mod insert {
650 }
680 }
651
681
652 pub fn insert_newline(cx: &mut Context) {
682 pub fn insert_newline(cx: &mut Context) {
683+ let view = cx.view();
653− let transaction = Transaction::change_by_selection(&cx.view.doc.state, |range| {
684+ let transaction = Transaction::change_by_selection(&view.doc.state, |range| {
654 let indent_level = helix_core::indent::suggested_indent_for_pos(
685 let indent_level = helix_core::indent::suggested_indent_for_pos(
655− cx.view.doc.syntax.as_ref(),
686+ view.doc.syntax.as_ref(),
656− &cx.view.doc.state,
687+ &view.doc.state,
657 range.head,
688 range.head,
658 true,
689 true,
659 );
690 );
@@ -663,32 +694,36 @@ pub mod insert {
663 text.push_str(&indent);
694 text.push_str(&indent);
664 (range.head, range.head, Some(text.into()))
695 (range.head, range.head, Some(text.into()))
665 });
696 });
666− cx.view.doc.apply(&transaction);
697+ view.doc.apply(&transaction);
667 }
698 }
668
699
669 // TODO: handle indent-aware delete
700 // TODO: handle indent-aware delete
670 pub fn delete_char_backward(cx: &mut Context) {
701 pub fn delete_char_backward(cx: &mut Context) {
702+ let count = cx.count;
703+ let view = cx.view();
671− let text = &cx.view.doc.text().slice(..);
704+ let text = &view.doc.text().slice(..);
672− let transaction = Transaction::change_by_selection(&cx.view.doc.state, |range| {
705+ let transaction = Transaction::change_by_selection(&view.doc.state, |range| {
673 (
706 (
674− graphemes::nth_prev_grapheme_boundary(text, range.head, cx.count),
707+ graphemes::nth_prev_grapheme_boundary(text, range.head, count),
675 range.head,
708 range.head,
676 None,
709 None,
677 )
710 )
678 });
711 });
679− cx.view.doc.apply(&transaction);
712+ view.doc.apply(&transaction);
680 }
713 }
681
714
682 pub fn delete_char_forward(cx: &mut Context) {
715 pub fn delete_char_forward(cx: &mut Context) {
716+ let count = cx.count;
717+ let view = cx.view();
683− let text = &cx.view.doc.text().slice(..);
718+ let text = &view.doc.text().slice(..);
684− let transaction = Transaction::change_by_selection(&cx.view.doc.state, |range| {
719+ let transaction = Transaction::change_by_selection(&view.doc.state, |range| {
685 (
720 (
686 range.head,
721 range.head,
687− graphemes::nth_next_grapheme_boundary(text, range.head, cx.count),
722+ graphemes::nth_next_grapheme_boundary(text, range.head, count),
688 None,
723 None,
689 )
724 )
690 });
725 });
691− cx.view.doc.apply(&transaction);
726+ view.doc.apply(&transaction);
692 }
727 }
693}
728}
694
729
@@ -702,23 +737,23 @@ pub fn insert_char_prompt(prompt: &mut Prompt, c: char) {
702// storing it?
737// storing it?
703
738
704pub fn undo(cx: &mut Context) {
739pub fn undo(cx: &mut Context) {
705− cx.view.doc.undo();
740+ cx.view().doc.undo();
706}
741}
707
742
708pub fn redo(cx: &mut Context) {
743pub fn redo(cx: &mut Context) {
709− cx.view.doc.redo();
744+ cx.view().doc.redo();
710}
745}
711
746
712// Yank / Paste
747// Yank / Paste
713
748
714pub fn yank(cx: &mut Context) {
749pub fn yank(cx: &mut Context) {
715 // TODO: should selections be made end inclusive?
750 // TODO: should selections be made end inclusive?
716− let values = cx
751+ let view = cx.view();
717− .view
752+ let values = view
718 .doc
753 .doc
719 .state
754 .state
720 .selection()
755 .selection()
721− .fragments(&cx.view.doc.text().slice(..))
756+ .fragments(&view.doc.text().slice(..))
722 .map(|cow| cow.into_owned())
757 .map(|cow| cow.into_owned())
723 .collect();
758 .collect();
724
759
@@ -756,21 +791,23 @@ pub fn paste(cx: &mut Context) {
756
791
757 let mut values = values.into_iter().map(Tendril::from).chain(repeat);
792 let mut values = values.into_iter().map(Tendril::from).chain(repeat);
758
793
794+ let view = cx.view();
795+
759 let transaction = if linewise {
796 let transaction = if linewise {
760 // paste on the next line
797 // paste on the next line
761 // TODO: can simply take a range + modifier and compute the right pos without ifs
798 // TODO: can simply take a range + modifier and compute the right pos without ifs
762− let text = cx.view.doc.text();
799+ let text = view.doc.text();
763− Transaction::change_by_selection(&cx.view.doc.state, |range| {
800+ Transaction::change_by_selection(&view.doc.state, |range| {
764 let line_end = text.line_to_char(text.char_to_line(range.head) + 1);
801 let line_end = text.line_to_char(text.char_to_line(range.head) + 1);
765 (line_end, line_end, Some(values.next().unwrap()))
802 (line_end, line_end, Some(values.next().unwrap()))
766 })
803 })
767 } else {
804 } else {
768− Transaction::change_by_selection(&cx.view.doc.state, |range| {
805+ Transaction::change_by_selection(&view.doc.state, |range| {
769 (range.head + 1, range.head + 1, Some(values.next().unwrap()))
806 (range.head + 1, range.head + 1, Some(values.next().unwrap()))
770 })
807 })
771 };
808 };
772
809
773− cx.view.doc.apply(&transaction);
810+ view.doc.apply(&transaction);
774 append_changes_to_history(cx);
811 append_changes_to_history(cx);
775 }
812 }
776}
813}
@@ -793,28 +830,30 @@ fn get_lines(view: &View) -> Vec<usize> {
793}
830}
794
831
795pub fn indent(cx: &mut Context) {
832pub fn indent(cx: &mut Context) {
796− let lines = get_lines(cx.view);
833+ let lines = get_lines(cx.view());
797
834
798 // Indent by one level
835 // Indent by one level
799 let indent = Tendril::from(" ".repeat(TAB_WIDTH));
836 let indent = Tendril::from(" ".repeat(TAB_WIDTH));
800
837
838+ let view = cx.view();
839+
801 let transaction = Transaction::change(
840 let transaction = Transaction::change(
802− &cx.view.doc.state,
841+ &view.doc.state,
803 lines.into_iter().map(|line| {
842 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);
805 (pos, pos, Some(indent.clone()))
844 (pos, pos, Some(indent.clone()))
806 }),
845 }),
807 );
846 );
808− cx.view.doc.apply(&transaction);
847+ cx.view().doc.apply(&transaction);
809 append_changes_to_history(cx);
848 append_changes_to_history(cx);
810}
849}
811
850
812pub fn unindent(cx: &mut Context) {
851pub fn unindent(cx: &mut Context) {
813− let lines = get_lines(cx.view);
852+ let lines = get_lines(cx.view());
814 let mut changes = Vec::with_capacity(lines.len());
853 let mut changes = Vec::with_capacity(lines.len());
815
854
816 for line_idx in lines {
855 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);
818 let mut width = 0;
857 let mut width = 0;
819
858
820 for ch in line.chars() {
859 for ch in line.chars() {
@@ -830,14 +869,14 @@ pub fn unindent(cx: &mut Context) {
830 }
869 }
831
870
832 if width > 0 {
871 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);
834 changes.push((start, start + width, None))
873 changes.push((start, start + width, None))
835 }
874 }
836 }
875 }
837
876
838− let transaction = Transaction::change(&cx.view.doc.state, changes.into_iter());
877+ let transaction = Transaction::change(&cx.view().doc.state, changes.into_iter());
839
878
840− cx.view.doc.apply(&transaction);
879+ cx.view().doc.apply(&transaction);
841 append_changes_to_history(cx);
880 append_changes_to_history(cx);
842}
881}
843
882
@@ -852,21 +891,25 @@ pub fn save(cx: &mut Context) {
852 // Spawns an async task to actually do the saving. This way we prevent blocking.
891 // Spawns an async task to actually do the saving. This way we prevent blocking.
853
892
854 // TODO: handle save errors somehow?
893 // TODO: handle save errors somehow?
855− cx.executor.spawn(cx.view.doc.save()).detach();
894+ cx.executor.spawn(cx.view().doc.save()).detach();
856}
895}
857
896
858pub fn completion(cx: &mut Context) {
897pub 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();
860 use log::info;
903 use log::info;
861
904
905+ let view = cx.view();
906+
862 // TODO: blocking here is not ideal
907 // TODO: blocking here is not ideal
908+ let pos =
863− let pos = helix_lsp::util::pos_to_lsp_pos(
909+ helix_lsp::util::pos_to_lsp_pos(&view.doc.text().slice(..), view.doc.selection().cursor());
864− &cx.view.doc.text().slice(..),
865− cx.view.doc.selection().cursor(),
866− );
867
910
868 // TODO: handle fails
911 // 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))
870 .unwrap_or_default();
913 .unwrap_or_default();
871
914
872 // TODO: if no completion, show some message or something
915 // TODO: if no completion, show some message or something
@@ -903,7 +946,7 @@ pub fn completion(cx: &mut Context) {
903 }
946 }
904 }
947 }
905
948
906− let view = editor.view_mut().unwrap();
949+ let view = editor.view_mut();
907 let transaction =
950 let transaction =
908 util::generate_transaction_from_edits(&view.doc.state, vec![edit]);
951 util::generate_transaction_from_edits(&view.doc.state, vec![edit]);
909 view.doc.apply(&transaction);
952 view.doc.apply(&transaction);
helix-term/src/compositor.rs−1
@@ -39,7 +39,6 @@ use helix_view::{Editor, View};
39// shared with commands.rs
39// shared with commands.rs
40pub struct Context<'a> {
40pub struct Context<'a> {
41 pub editor: &'a mut Editor,
41 pub editor: &'a mut Editor,
42− pub language_servers: &'a helix_lsp::Registry,
43 pub executor: &'static smol::Executor<'static>,
42 pub executor: &'static smol::Executor<'static>,
44}
43}
45
44
helix-term/src/ui/editor.rs+39−43
@@ -251,55 +251,52 @@ impl Component for EditorView {
251 Event::Resize(width, height) => {
251 Event::Resize(width, height) => {
252 // TODO: simplistic ensure cursor in view for now
252 // TODO: simplistic ensure cursor in view for now
253 // TODO: loop over views
253 // TODO: loop over views
254− if let Some(view) = cx.editor.view_mut() {
254+ let view = cx.editor.view_mut();
255− view.size = (width, height);
255+ view.size = (width, height);
256− view.ensure_cursor_in_view()
256+ view.ensure_cursor_in_view();
257− };
258 EventResult::Consumed(None)
257 EventResult::Consumed(None)
259 }
258 }
260 Event::Key(event) => {
259 Event::Key(event) => {
261− if let Some(view) = cx.editor.view_mut() {
260+ let view = cx.editor.view_mut();
261+
262− let keys = vec![event];
262+ let keys = vec![event];
263− // TODO: sequences (`gg`)
263+ // TODO: sequences (`gg`)
264− let mode = view.doc.mode();
264+ let mode = view.doc.mode();
265− // TODO: handle count other than 1
265+ // TODO: handle count other than 1
266− let mut cx = commands::Context {
266+ let mut cxt = commands::Context {
267− view,
268− executor: cx.executor,
267+ executor: cx.executor,
269− language_servers: cx.language_servers,
268+ editor: &mut cx.editor,
270− count: 1,
269+ count: 1,
271− callback: None,
270+ callback: None,
272− };
271+ };
273
272
274− match mode {
273+ match mode {
275− Mode::Insert => {
274+ Mode::Insert => {
276− if let Some(command) = self.keymap[&Mode::Insert].get(&keys) {
275+ if let Some(command) = self.keymap[&Mode::Insert].get(&keys) {
277− command(&mut cx);
276+ command(&mut cxt);
278− } else if let KeyEvent {
277+ } else if let KeyEvent {
279− code: KeyCode::Char(c),
278+ code: KeyCode::Char(c),
280− ..
279+ ..
281− } = event
280+ } = event
282− {
281+ {
283− commands::insert::insert_char(&mut cx, c);
282+ commands::insert::insert_char(&mut cxt, c);
284− }
285 }
283 }
286− mode => {
284+ }
285+ mode => {
287− if let Some(command) = self.keymap[&mode].get(&keys) {
286+ if let Some(command) = self.keymap[&mode].get(&keys) {
288− command(&mut cx);
287+ command(&mut cxt);
289
288
290− // TODO: simplistic ensure cursor in view for now
289+ // TODO: simplistic ensure cursor in view for now
291− }
292 }
290 }
293 }
291 }
294− // appease borrowck
292+ }
295− let callback = cx.callback.take();
296
293
294+ // appease borrowck
295+ let callback = cxt.callback.take();
296+ drop(cxt);
297− view.ensure_cursor_in_view();
297+ cx.editor.view_mut().ensure_cursor_in_view();
298
298
299− EventResult::Consumed(callback)
299+ EventResult::Consumed(callback)
300− } else {
301− EventResult::Ignored
302− }
303 }
300 }
304 Event::Mouse(_) => EventResult::Ignored,
301 Event::Mouse(_) => EventResult::Ignored,
305 }
302 }
@@ -309,9 +306,8 @@ impl Component for EditorView {
309 // SAFETY: we cheat around the view_mut() borrow because it doesn't allow us to also borrow
306 // SAFETY: we cheat around the view_mut() borrow because it doesn't allow us to also borrow
310 // theme. Theme is immutable mutating view won't disrupt theme_ref.
307 // theme. Theme is immutable mutating view won't disrupt theme_ref.
311 let theme_ref = unsafe { &*(&cx.editor.theme as *const Theme) };
308 let theme_ref = unsafe { &*(&cx.editor.theme as *const Theme) };
312− if let Some(view) = cx.editor.view_mut() {
309+ let view = cx.editor.view_mut();
313− self.render_view(view, area, surface, theme_ref);
310+ self.render_view(view, area, surface, theme_ref);
314− }
315
311
316 // TODO: drop unwrap
312 // TODO: drop unwrap
317 }
313 }
@@ -321,7 +317,7 @@ impl Component for EditorView {
321 // Mode::Insert => write!(stdout, "\x1B[6 q"),
317 // Mode::Insert => write!(stdout, "\x1B[6 q"),
322 // mode => write!(stdout, "\x1B[2 q"),
318 // mode => write!(stdout, "\x1B[2 q"),
323 // };
319 // };
324− let view = ctx.editor.view().unwrap();
320+ let view = ctx.editor.view();
325 let cursor = view.doc.state.selection().cursor();
321 let cursor = view.doc.state.selection().cursor();
326
322
327 let mut pos = view
323 let mut pos = view
helix-term/src/ui/mod.rs+4−4
@@ -16,7 +16,7 @@ pub fn text_color() -> Style {
16}
16}
17
17
18use std::path::{Path, PathBuf};
18use 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> {
20 use ignore::Walk;
20 use ignore::Walk;
21 // TODO: determine root based on git root
21 // TODO: determine root based on git root
22 let files = Walk::new(root).filter_map(|entry| match entry {
22 let files = Walk::new(root).filter_map(|entry| match entry {
@@ -40,9 +40,9 @@ pub fn file_picker(root: &str) -> Picker<PathBuf> {
40 // format_fn
40 // format_fn
41 path.strip_prefix("./").unwrap().to_str().unwrap().into()
41 path.strip_prefix("./").unwrap().to_str().unwrap().into()
42 },
42 },
43− |editor: &mut Editor, path: &PathBuf| {
43+ move |editor: &mut Editor, path: &PathBuf| {
44− let size = editor.view().unwrap().size;
44+ let size = editor.view().size;
45− editor.open(path.into(), size);
45+ editor.open(path.into(), size, ex);
46 },
46 },
47 )
47 )
48}
48}
helix-view/src/editor.rs+33−6
@@ -10,6 +10,7 @@ pub struct Editor {
10 pub focus: usize,
10 pub focus: usize,
11 pub should_close: bool,
11 pub should_close: bool,
12 pub theme: Theme, // TODO: share one instance
12 pub theme: Theme, // TODO: share one instance
13+ pub language_servers: helix_lsp::Registry,
13}
14}
14
15
15impl Default for Editor {
16impl Default for Editor {
@@ -21,28 +22,54 @@ impl Default for Editor {
21impl Editor {
22impl Editor {
22 pub fn new() -> Self {
23 pub fn new() -> Self {
23 let theme = Theme::default();
24 let theme = Theme::default();
25+ let language_servers = helix_lsp::Registry::new();
24
26
25 Self {
27 Self {
26 views: Vec::new(),
28 views: Vec::new(),
27 focus: 0,
29 focus: 0,
28 should_close: false,
30 should_close: false,
29 theme,
31 theme,
32+ language_servers,
30 }
33 }
31 }
34 }
32
35
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> {
34 let pos = self.views.len();
42 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+
36 self.views.push(View::new(doc, size)?);
63 self.views.push(View::new(doc, size)?);
37 self.focus = pos;
64 self.focus = pos;
38 Ok(())
65 Ok(())
39 }
66 }
40
67
41− pub fn view(&self) -> Option<&View> {
68+ pub fn view(&self) -> &View {
42− self.views.get(self.focus)
69+ self.views.get(self.focus).unwrap()
43 }
70 }
44
71
45− pub fn view_mut(&mut self) -> Option<&mut View> {
72+ pub fn view_mut(&mut self) -> &mut View {
46− self.views.get_mut(self.focus)
73+ self.views.get_mut(self.focus).unwrap()
47 }
74 }
48}
75}