A simple CPU rendered GUI IDE experience.
Diffstat (limited to 'src/edi/input_handlers/cursor.rs')
| -rw-r--r-- | src/edi/input_handlers/cursor.rs | 245 |
1 files changed, 245 insertions, 0 deletions
diff --git a/src/edi/input_handlers/cursor.rs b/src/edi/input_handlers/cursor.rs new file mode 100644 index 0000000..bb283af --- /dev/null +++ b/src/edi/input_handlers/cursor.rs @@ -0,0 +1,245 @@ +use std::borrow::Cow; +use std::sync::Arc; + +use Default::default; +use implicit_fn::implicit_fn; +use lsp_types::request::*; +use lsp_types::*; +use rust_fsm::StateMachine; +use tokio::task::spawn_blocking; +use tokio_util::task::AbortOnDropHandle as DropH; +use winit::window::Window; + +use crate::edi::*; +impl Editor { + #[implicit_fn] + pub fn cursor_moved( + &mut self, + cursor_position: (usize, usize), + w: Arc<dyn Window>, + c: usize, + ) { + match self.state.consume(Action::C(cursor_position)).unwrap() { + Some(Do::ExtendSelectionToMouse) => { + let p = self.text.mapped_index_at(cursor_position); + self.text + .cursor + .first_mut() + .extend_selection_to(p, &self.text.rope); + w.request_redraw(); + } + Some(Do::StartSelection) => { + let x = self.text.mapped_index_at(cursor_position); + self.text.cursor.first_mut().position = x; + self.text.cursor.first_mut().sel = Some((x..x).into()); + self.hist.lc = self.text.cursor.clone(); + } + Some(Do::Hover) + if let Some(hover) = self + .text + .visual_index_at(cursor_position) + .map(Mapping::own) + && let Some(_) = lsp!(self) => + 'out: { + let l = &mut self.requests.hovering.result; + if let Some(Hovr { + span: Some([(_x, _y), (_x2, _)]), .. + }) = &*l + && let Some(_y) = _y.checked_sub(self.text.vo) + && let Some(_x) = _x.checked_sub(self.text.ho) + && let Some(_x2) = _x2.checked_sub(self.text.ho) + && cursor_position.1 == _y + && (_x..=_x2).contains( + &&(cursor_position.0 + - self.text.line_number_offset() + - 1), + ) + { + break 'out; + } else { + // println!("span no longer below cursor; cancel hover {_x}..{_x2} {}", cursor_position.0 - text.line_number_offset() - 1); + *l = None; + w.request_redraw(); + } + self.rq_hover(hover, cursor_position, c); + } + Some(Do::Hover) => { + self.requests.def.result = None; + self.requests.hovering.result = None; + w.request_redraw(); + } + None => {} + x => unreachable!("{x:?}"), + } + } + #[implicit_fn] + pub fn rq_hover( + &mut self, + hover: Mapping<'_>, + cursor_position: (usize, usize), + c: usize, + ) { + let (lsp, o) = lsp!(self + p).unwrap(); + let text = self.text.clone(); + let mut rang = None; + let z = match hover { + Mapping::Char(_, _, i) => TextDocumentPositionParams { + position: text.to_l_position(i).unwrap(), + text_document: o.tid(), + }, + Mapping::Fake(mark, relpos, abspos, _) => { + let Some(ref loc) = mark.data[relpos as usize].1 else { + return; + }; + let (x, y) = text.xy(abspos as _).unwrap(); + let Some(mut begin) = text.reverse_source_map(y) else { + return; + }; + let start = begin.nth(x.saturating_sub(1)).unwrap() + 1; + let left = mark.data[..relpos as usize] + .iter() + .rev() + .take_while(_.1.as_ref() == Some(loc)) + .count(); + let start = start + relpos as usize - left; + let length = mark.data[relpos as usize..] + .iter() + .take_while(_.1.as_ref() == Some(loc)) + .count() + + left; + rang = Some([(start, y), (start + length, y)]); + TextDocumentPositionParams { + text_document: TextDocumentIdentifier { + uri: loc.uri.clone(), + }, + position: loc.range.start, + } + } + }; + if ctrl() { + if self + .requests + .def + .request + .as_ref() + .is_none_or(|&(_, x)| x != cursor_position) + { + let handle = lsp.runtime.spawn( + lsp.request::<lsp_request!("textDocument/definition")>( + &GotoDefinitionParams { + text_document_position_params: z.clone(), + work_done_progress_params: default(), + partial_result_params: default(), + }, + ) + .unwrap() + .0, + ); + self.requests.def.request = + Some((DropH::new(handle), cursor_position)); + } else if self.requests.def.result.as_ref().is_some_and(|em| { + let z = em.origin_selection_range.unwrap(); + (z.start.character..z.end.character).contains( + &((cursor_position.0 - text.line_number_offset() - 1) + as _), + ) + }) { + self.requests.def.result = None; + } + } else { + self.requests.def.result = None; + } + if let Some((_, c)) = self.requests.hovering.request + && c == cursor_position + { + return; + } + // if !running.insert(hover) {return} + let (rx, _) = lsp + .request::<HoverRequest>(&HoverParams { + text_document_position_params: z, + work_done_progress_params: default(), + }) + .unwrap(); + // println!("rq hov of {hover:?} (cur {})", requests.hovering.request.is_some()); + let handle: tokio::task::JoinHandle<Result<Option<Hovr>, _>> = + lsp.runtime.spawn(async move { + let Some(x) = rx.await? else { + return Ok(None::<Hovr>); + }; + let (w, cells) = spawn_blocking(move || { + let x = match &x.contents { + lsp_types::HoverContents::Scalar( + marked_string, + ) => match marked_string { + MarkedString::LanguageString(x) => + Cow::Borrowed(&*x.value), + MarkedString::String(x) => Cow::Borrowed(&**x), + }, + lsp_types::HoverContents::Array( + marked_strings, + ) => Cow::Owned( + marked_strings + .iter() + .map(|x| match x { + MarkedString::LanguageString(x) => + &*x.value, + MarkedString::String(x) => &*x, + }) + .collect::<String>(), + ), + lsp_types::HoverContents::Markup( + markup_content, + ) => Cow::Borrowed(&*markup_content.value), + }; + let x = hov::p(&x).unwrap(); + let m = hov::l(&x) + .into_iter() + .max() + .map(_ + 2) + .unwrap_or(usize::MAX) + .min(c - 10); + (m, hov::markdown2(m, &x)) + }) + .await + .unwrap(); + let span = rang.or_else(|| { + x.range.and_then(|range| try { + let (startx, starty) = + text.l_pos_to_char(range.start)?; + let (endx, endy) = + text.l_pos_to_char(range.end)?; + let x1 = text + .reverse_source_map(starty)? + .nth(startx)?; + let x2 = + text.reverse_source_map(endy)?.nth(endx)?; + [ + (x1, range.start.line as _), + (x2, range.start.line as _), + ] + }) + }); + Ok(Some( + hov::Hovr { + span, + item: text::CellBuffer { + c: w, + vo: 0, + cells: cells.into(), + }, + range: x.range, + // range: x.range.and_then(|x| text.l_range(x)), + } + .into(), + )) + }); + self.requests.hovering.request = + (DropH::new(handle), cursor_position).into(); + // requests.hovering.result = None; + // lsp!().map(|(cl, o)| { + // let window = window.clone(); + // }); + // }); + } +} |