@@ -1,6 +1,11 @@
1use clap::ArgMatches as Args;
1use clap::ArgMatches as Args;
2use helix_core::{indent::TAB_WIDTH, state::Mode, syntax::HighlightEvent, Position, Range, State};
2use helix_core::{indent::TAB_WIDTH, state::Mode, syntax::HighlightEvent, Position, Range, State};
5+ keymap::{self, Keymaps},
3−use helix_view::{commands, keymap, prompt::Prompt, Editor, Theme, View};
7+ Editor, Theme, View,
6 borrow::Cow,
11 borrow::Cow,
@@ -31,14 +36,16 @@ const OFFSET: u16 = 6; // 5 linenr + 1 gutter
32type Terminal = tui::Terminal<CrosstermBackend<std::io::Stdout>>;
37type Terminal = tui::Terminal<CrosstermBackend<std::io::Stdout>>;
34−static EX: smol::Executor = smol::Executor::new();
36const BASE_WIDTH: u16 = 30;
39const BASE_WIDTH: u16 = 30;
38−pub struct Application {
41+pub struct Application<'a> {
39 editor: Editor,
42 editor: Editor,
40 prompt: Option<Prompt>,
43 prompt: Option<Prompt>,
41 terminal: Renderer,
44 terminal: Renderer,
47+ executor: &'a smol::Executor<'a>,
48+ lsp: helix_lsp::Client,
44struct Renderer {
51struct Renderer {
@@ -235,7 +242,7 @@ impl Renderer {
235 .set_string(1, self.size.1 - 2, mode, self.text_color);
242 .set_string(1, self.size.1 - 2, mode, self.text_color);
238− pub fn render_prompt(&mut self, view: &View, prompt: &Prompt) {
245+ pub fn render_prompt(&mut self, view: &View, prompt: &Prompt, theme: &Theme) {
239 // completion
246 // completion
240 if !prompt.completion.is_empty() {
247 if !prompt.completion.is_empty() {
241 // TODO: find out better way of clearing individual lines of the screen
248 // TODO: find out better way of clearing individual lines of the screen
@@ -254,7 +261,7 @@ impl Renderer {
255 self.surface.set_style(
262 self.surface.set_style(
256 Rect::new(0, self.size.1 - col_height - 2, self.size.0, col_height),
263 Rect::new(0, self.size.1 - col_height - 2, self.size.0, col_height),
257− view.theme.get("ui.statusline"),
264+ theme.get("ui.statusline"),
259 for (i, command) in prompt.completion.iter().enumerate() {
266 for (i, command) in prompt.completion.iter().enumerate() {
260 let color = if prompt.completion_selection_index.is_some()
267 let color = if prompt.completion_selection_index.is_some()
@@ -330,8 +337,8 @@ impl Renderer {
333−impl Application {
340+impl<'a> Application<'a> {
334− pub fn new(mut args: Args) -> Result<Self, Error> {
341+ pub fn new(mut args: Args, executor: &'a smol::Executor<'a>) -> Result<Self, Error> {
335 let terminal = Renderer::new()?;
342 let terminal = Renderer::new()?;
336 let mut editor = Editor::new();
343 let mut editor = Editor::new();
@@ -339,11 +346,18 @@ impl Application {
339 editor.open(file, terminal.size)?;
346 editor.open(file, terminal.size)?;
349+ let lsp = helix_lsp::Client::start(&executor, "rust-analyzer", &[]);
342 let mut app = Self {
351 let mut app = Self {
344 terminal,
353 terminal,
345 // TODO; move to state
354 // TODO; move to state
346 prompt: None,
355 prompt: None,
358+ keymap: keymap::default(),
@@ -361,7 +375,7 @@ impl Application {
361 if prompt.should_close {
375 if prompt.should_close {
362 self.prompt = None;
376 self.prompt = None;
364− self.terminal.render_prompt(view, prompt);
378+ self.terminal.render_prompt(view, prompt, theme_ref);
@@ -375,7 +389,13 @@ impl Application {
376 pub async fn event_loop(&mut self) {
390 pub async fn event_loop(&mut self) {
377 let mut reader = EventStream::new();
391 let mut reader = EventStream::new();
378− let keymap = keymap::default();
392+
394+ let res = self.lsp.initialize().await;
397+ .text_document_did_open(&self.editor.view().unwrap().state)
380 self.render();
400 self.render();
@@ -384,126 +404,149 @@ impl Application {
387− // Handle key events
407+ use futures_util::{select, FutureExt};
388− match reader.next().await {
408+ select! {
389− Some(Ok(Event::Resize(width, height))) => {
409+ event = reader.next().fuse() => {
390− self.terminal.resize(width, height);
410+ self.handle_terminal_events(event).await
412+ notification = self.lsp.incoming.next().fuse() => {
413+ self.handle_lsp_notification(notification).await
419+ pub async fn handle_terminal_events(
421+ event: Option<Result<Event, crossterm::ErrorKind>>,
423+ // Handle key events
425+ Some(Ok(Event::Resize(width, height))) => {
426+ self.terminal.resize(width, height);
392− // TODO: simplistic ensure cursor in view for now
428+ // TODO: simplistic ensure cursor in view for now
393− // TODO: loop over views
429+ // TODO: loop over views
394− if let Some(view) = self.editor.view_mut() {
430+ if let Some(view) = self.editor.view_mut() {
395− view.size = self.terminal.size;
431+ view.size = self.terminal.size;
396− view.ensure_cursor_in_view()
432+ view.ensure_cursor_in_view()
437+ Some(Ok(Event::Key(event))) => {
438+ // if there's a prompt, it takes priority
439+ if let Some(prompt) = &mut self.prompt {
443+ .handle_input(event, &mut self.editor);
399 self.render();
445 self.render();
401− Some(Ok(Event::Key(event))) => {
402− // if there's a prompt, it takes priority
403− if let Some(prompt) = &mut self.prompt {
407− .handle_input(event, &mut self.editor);
410− } else if let Some(view) = self.editor.view_mut() {
446+ } else if let Some(view) = self.editor.view_mut() {
411− let keys = vec![event];
447+ let keys = vec![event];
412− // TODO: sequences (`gg`)
448+ // TODO: sequences (`gg`)
413− // TODO: handle count other than 1
449+ // TODO: handle count other than 1
414− match view.state.mode() {
450+ match view.state.mode() {
415− Mode::Insert => {
451+ Mode::Insert => {
416− if let Some(command) = keymap[&Mode::Insert].get(&keys) {
452+ if let Some(command) = self.keymap[&Mode::Insert].get(&keys) {
417− command(view, 1);
453+ command(view, 1);
418− } else if let KeyEvent {
454+ } else if let KeyEvent {
419− code: KeyCode::Char(c),
455+ code: KeyCode::Char(c),
421− } = event
457+ } = event
423− commands::insert::insert_char(view, c);
459+ commands::insert::insert_char(view, c);
425− view.ensure_cursor_in_view();
461+ view.ensure_cursor_in_view();
427− Mode::Normal => {
463+ Mode::Normal => {
428− if let &[KeyEvent {
464+ if let &[KeyEvent {
429− code: KeyCode::Char(':'),
465+ code: KeyCode::Char(':'),
431− }] = keys.as_slice()
467+ }] = keys.as_slice()
433− let prompt = Prompt::new(
469+ let prompt = Prompt::new(
434− ":".to_owned(),
470+ ":".to_owned(),
435− |_input: &str| {
471+ |_input: &str| {
436− // TODO: i need this duplicate list right now to avoid borrow checker issues
472+ // TODO: i need this duplicate list right now to avoid borrow checker issues
437− let command_list = vec![
473+ let command_list = vec![
438− String::from("q"),
474+ String::from("q"),
439− String::from("aaa"),
475+ String::from("aaa"),
440− String::from("bbb"),
476+ String::from("bbb"),
441− String::from("ccc"),
477+ String::from("ccc"),
442− String::from("ddd"),
478+ String::from("ddd"),
443− String::from("eee"),
479+ String::from("eee"),
444− String::from("averylongcommandaverylongcommandaverylongcommandaverylongcommandaverylongcommand"),
480+ String::from("averylongcommandaverylongcommandaverylongcommandaverylongcommandaverylongcommand"),
445− String::from("q"),
481+ String::from("q"),
446− String::from("aaa"),
482+ String::from("aaa"),
447− String::from("bbb"),
483+ String::from("bbb"),
448− String::from("ccc"),
484+ String::from("ccc"),
449− String::from("ddd"),
485+ String::from("ddd"),
450− String::from("eee"),
486+ String::from("eee"),
451− String::from("q"),
487+ String::from("q"),
452− String::from("aaa"),
488+ String::from("aaa"),
453− String::from("bbb"),
489+ String::from("bbb"),
454− String::from("ccc"),
490+ String::from("ccc"),
455− String::from("ddd"),
491+ String::from("ddd"),
456− String::from("eee"),
492+ String::from("eee"),
457− String::from("q"),
493+ String::from("q"),
458− String::from("aaa"),
494+ String::from("aaa"),
459− String::from("bbb"),
495+ String::from("bbb"),
460− String::from("ccc"),
496+ String::from("ccc"),
461− String::from("ddd"),
497+ String::from("ddd"),
462− String::from("eee"),
498+ String::from("eee"),
463− String::from("q"),
499+ String::from("q"),
464− String::from("aaa"),
500+ String::from("aaa"),
465− String::from("bbb"),
501+ String::from("bbb"),
466− String::from("ccc"),
502+ String::from("ccc"),
467− String::from("ddd"),
503+ String::from("ddd"),
468− String::from("eee"),
504+ String::from("eee"),
470− command_list
506+ command_list
471− .into_iter()
507+ .into_iter()
472− .filter(|command| command.contains(_input))
508+ .filter(|command| command.contains(_input))
473− .collect()
509+ .collect()
474− }, // completion
510+ }, // completion
475− |editor: &mut Editor, input: &str| match input {
511+ |editor: &mut Editor, input: &str| match input {
476− "q" => editor.should_close = true,
512+ "q" => editor.should_close = true,
477− _ => (),
513+ _ => (),
481− self.prompt = Some(prompt);
517+ self.prompt = Some(prompt);
483− // HAXX: special casing for command mode
519+ // HAXX: special casing for command mode
484− } else if let Some(command) = keymap[&Mode::Normal].get(&keys) {
520+ } else if let Some(command) = self.keymap[&Mode::Normal].get(&keys) {
485− command(view, 1);
521+ command(view, 1);
487− // TODO: simplistic ensure cursor in view for now
523+ // TODO: simplistic ensure cursor in view for now
488− view.ensure_cursor_in_view();
524+ view.ensure_cursor_in_view();
492− if let Some(command) = keymap[&mode].get(&keys) {
528+ if let Some(command) = self.keymap[&mode].get(&keys) {
493− command(view, 1);
529+ command(view, 1);
495− // TODO: simplistic ensure cursor in view for now
531+ // TODO: simplistic ensure cursor in view for now
496− view.ensure_cursor_in_view();
532+ view.ensure_cursor_in_view();
503− Some(Ok(Event::Mouse(_))) => (), // unhandled
504− Some(Err(x)) => panic!(x),
539+ Some(Ok(Event::Mouse(_))) => (), // unhandled
540+ Some(Err(x)) => panic!(x),
545+ pub async fn handle_lsp_notification(&mut self, notification: Option<helix_lsp::Notification>) {
546+ use helix_lsp::Notification;
547+ match notification {
548+ Some(Notification::PublishDiagnostics(params)) => unimplemented!("{:?}", params),
549+ _ => unreachable!(),