A simple CPU rendered GUI IDE experience.
Diffstat (limited to 'src/edi.rs')
| -rw-r--r-- | src/edi.rs | 1503 |
1 files changed, 16 insertions, 1487 deletions
@@ -1,142 +1,52 @@ -use std::borrow::Cow; use std::collections::HashMap; use std::fmt::Debug; use std::mem::take; -use std::ops::ControlFlow; use std::path::{Path, PathBuf}; use std::sync::Arc; use std::time::SystemTime; use Default::default; use bind::Bind; -use implicit_fn::implicit_fn; -use lsp_server::{Connection, Request as LRq, ResponseError}; +use lsp_server::Connection; use lsp_types::request::*; use lsp_types::*; use regex::Regex; use rootcause::report; use ropey::Rope; -use rust_analyzer::lsp::ext::OnTypeFormatting; -use rust_fsm::StateMachine; use serde_derive::{Deserialize, Serialize}; use tokio::sync::oneshot::Sender; -use tokio::task::spawn_blocking; -use tokio_util::task::AbortOnDropHandle as DropH; -use winit::event::{KeyEvent, MouseButton}; -use winit::keyboard::{Key, NamedKey}; +use winit::keyboard::NamedKey; use winit::window::Window; +mod input_handlers; +pub use input_handlers::handle2; + +mod lsp_impl; pub mod st; mod wsedit; +pub use lsp_impl::Requests; use st::*; use crate::bar::Bar; use crate::commands::Cmds; -use crate::complete::Complete; use crate::error::WDebug; use crate::gotolist::{At, GoTo}; use crate::hov::{self, Hovr}; use crate::lsp::{ - self, Anonymize, Client, Map_, PathURI, RequestError, Rq, tdpp, + Anonymize, Client, Map_, PathURI, RequestError, Rq, tdpp, }; use crate::menu::generic::MenuData; use crate::meta::META; -use crate::runnables::Runnables; use crate::sym::{Symbols, SymbolsList, SymbolsType}; use crate::text::cursor::{Ronge, ceach}; use crate::text::hist::{ClickHistory, Hist}; use crate::text::{self, Mapping, RopeExt, SortTedits, TextArea}; use crate::{ - BoolRequest, CDo, CompletionAction, CompletionState, act, alt, ctrl, - filter, hash, shift, sig, sym, trm, + BoolRequest, CDo, CompletionAction, CompletionState, alt, ctrl, + filter, hash, shift, sym, trm, }; -#[allow(dead_code)] -pub fn serialize_tokens<S: serde::Serializer>( - s: &Rq< - Box<[SemanticToken]>, - Box<[SemanticToken]>, - (), - RequestError<SemanticTokensFullRequest>, - >, - ser: S, -) -> Result<S::Ok, S::Error> { - SemanticToken::serialize_tokens_opt( - &s.result.clone().map(|x| x.to_vec()), - ser, - ) -} -#[allow(dead_code)] -pub fn deserialize_tokens<'de, D: serde::Deserializer<'de>>( - ser: D, -) -> Result< - Rq< - Box<[SemanticToken]>, - Box<[SemanticToken]>, - (), - RequestError<SemanticTokensFullRequest>, - >, - D::Error, -> { - SemanticToken::deserialize_tokens_opt(ser) - .map(|x| Rq { result: x.map(Into::into), request: None }) -} -#[derive(Default, Debug, Serialize, Deserialize)] -pub struct Requests { - pub hovering: - Rq<Hovr, Option<Hovr>, (usize, usize), RequestError<HoverRequest>>, - pub document_highlights: Rq< - Vec<DocumentHighlight>, - Vec<DocumentHighlight>, - (), - RequestError<DocumentHighlightRequest>, - >, - pub complete: CompletionState, - pub sig_help: Rq< - (SignatureHelp, usize, Option<usize>), - Option<SignatureHelp>, - (), - RequestError<SignatureHelpRequest>, - >, // vo, lines - // #[serde(serialize_with = "serialize_tokens")] - // #[serde(deserialize_with = "deserialize_tokens")] - #[serde(skip)] - pub semantic_tokens: Rq< - Box<[SemanticToken]>, - Box<[SemanticToken]>, - (), - RequestError<SemanticTokensFullRequest>, - >, - pub diag: Rq< - String, - Option<String>, - (), - RequestError<DocumentDiagnosticRequest>, - >, - #[serde(skip)] - pub inlay: Rq< - Vec<InlayHint>, - Vec<InlayHint>, - (), - RequestError<lsp_request!("textDocument/inlayHint")>, - >, - pub def: Rq< - LocationLink, - Option<GotoDefinitionResponse>, - (usize, usize), - RequestError<lsp_request!("textDocument/definition")>, - >, - #[serde(skip)] - pub document_symbols: Rq< - Option<Vec<DocumentSymbol>>, - Option<DocumentSymbolResponse>, - (), - RequestError<lsp_request!("textDocument/documentSymbol")>, - >, - #[serde(skip)] - pub git_diff: Rq<imara_diff::Diff, imara_diff::Diff, (), ()>, -} impl Debug for Editor { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("Editor") @@ -185,13 +95,13 @@ macro_rules! lsp { $self.lsp.as_ref().map(|(x, ..)| *x) }; ($self:ident + p) => { - $crate::edi::lsp_m!($self).zip($self.origin.as_deref()) + $crate::edi::lsp!($self).zip($self.origin.as_deref()) }; } -pub(crate) use lsp as lsp_m; +pub(crate) use lsp; macro_rules! inlay { ($self:ident) => { - $crate::edi::lsp_m!($self + p).map(|(lsp, path)| { + $crate::edi::lsp!($self + p).map(|(lsp, path)| { $self .requests .inlay @@ -208,12 +118,12 @@ macro_rules! change { change!(@$self, Some($w)) }; (just $self:ident) => { - lsp_m!($self + p).map(|(x, origin)| { + lsp!($self + p).map(|(x, origin)| { x.edit(&origin, $self.text.rope.to_string()).unwrap(); }) }; (@$self:ident, $w:expr) => { - lsp_m!($self + p).map(|(x, origin)| { + lsp!($self + p).map(|(x, origin)| { x.edit(&origin, $self.text.rope.to_string()).unwrap(); x.rq_semantic_tokens( &mut $self.requests.semantic_tokens, @@ -336,7 +246,7 @@ impl Editor { rust_analyzer::bin::run_server(b) }) .unwrap(); - let (c, t2, changed) = lsp::run( + let (c, t2, changed) = crate::lsp::run( (a.sender, a.receiver), // lsp_server::stdio::stdio_transport( // BufReader::new(c.stdout.take().unwrap()), @@ -442,469 +352,6 @@ impl Editor { std::fs::write(self.origin.as_ref().unwrap(), &t).unwrap(); self.mtime = Self::modify(self.origin.as_deref()); } - pub fn poll(&mut self) { - let Some((l, ..)) = self.lsp else { return }; - for rq in l.req_rx.try_iter() { - match rq { - LRq { method: "workspace/diagnostic/refresh", .. } => { - // let x = l.pull_diag(o.into(), diag.result.clone()); - // diag.request(l.runtime.spawn(x)); - } - rq => log::debug!("discarding request {rq:?}"), - } - } - self.requests.inlay.poll(|x, p| { - x.ok().or(p.1).inspect(|x| { - self.text.set_inlay(x); - }) - }); - self.requests.document_highlights.poll(|x, _| x.ok()); - self.requests.diag.poll(|x, _| x.ok().flatten()); - if let CompletionState::Complete(rq) = &mut self.requests.complete - { - rq.poll(|f, (c, _)| { - f.ok().flatten().map(|x| Complete { - r: x, - start: c, - selection: 0, - vo: 0, - }) - }); - }; - match &mut self.state { - State::Symbols(x) => { - x.poll(|x, (_, p)| { - let Some(p) = p else { unreachable!() }; - x.ok().flatten().map(|r| sym::Symbols { - data: (r, p.data.1, p.data.2, p.data.3, p.data.4), - selection: 0, - vo: 0, - ..p - }) - }); - } - State::CodeAction(x) => { - if x.poll(|x, _| { - let lems: Vec<CodeAction> = x - .ok()?? - .into_iter() - .map(|x| match x { - CodeActionOrCommand::CodeAction(x) => x, - _ => panic!("alas we dont like these"), - }) - .collect(); - if lems.is_empty() { - self.bar.last_action = - "no code actions available".into(); - None - } else { - self.bar.last_action = - format!("{} code actions", lems.len()); - Some(act::CodeActions::new(lems)) - } - }) && x.result.is_none() - { - self.state = State::Default; - } - } - State::Runnables(x) => { - x.poll(|x, ((), old)| { - Some(Runnables { - data: x.ok()?, - ..old.unwrap_or_default() - }) - }); - } - State::GoToL(z) => match &mut z.data.1 { - Some(crate::gotolist::O::References(y)) => { - y.poll(|x, _| { - x.ok().flatten().map(|x| { - z.data.0 = x.iter().map(GoTo::from).collect() - }) - }); - } - Some(crate::gotolist::O::Impl(y)) => { - y.poll(|x, _| { - x.ok().map(|x| { - x.and_then(|x| try { - z.data.0 = match x { - GotoDefinitionResponse::Scalar( - location, - ) => vec![GoTo::from( - location, - )], - GotoDefinitionResponse::Array( - locations, - ) => locations - .into_iter() - .map(GoTo::from) - .collect(), - GotoDefinitionResponse::Link( - location_links, - ) => location_links - .into_iter() - .map(|LocationLink {target_uri, target_range, .. }| { - GoTo::from( - Location { - uri: target_uri, - range: target_range, - } - ) - }) - .collect(), - }; - }); - }) - }); - } - _ => {} - }, - _ => {} - } - self.requests.def.poll(|x, _| { - x.ok().flatten().and_then(|x| match &x { - GotoDefinitionResponse::Link([x, ..]) => Some(x.clone()), - _ => None, - }) - }); - self.requests - .semantic_tokens - .poll(|x, _| x.ok().inspect(|x| self.text.set_toks(&x))); - self.requests.sig_help.poll(|x, ((), y)| { - x.ok().flatten().map(|x| { - if let Some((old_sig, vo, max)) = y - && &sig::active(&old_sig) == &sig::active(&x) - { - (x, vo, max) - } else { - (x, 0, None) - } - }) - }); - self.requests.hovering.poll(|x, _| x.ok().flatten()); - self.requests.git_diff.poll(|x, _| x.ok()); - self.requests.document_symbols.poll(|x, _| { - x.ok().flatten().map(|x| match x { - DocumentSymbolResponse::Flat(_) => None, - DocumentSymbolResponse::Nested(x) => Some(x), - }) - }); - } - #[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) - && let Some((cl, o)) = lsp!(self + p) => - '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(); - } - 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 { - break 'out; - }; - let (x, y) = text.xy(abspos as _).unwrap(); - let Some(mut begin) = text.reverse_source_map(y) - else { - break 'out; - }; - 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 = - cl.runtime.spawn( - cl.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 - { - break 'out; - } - // if !running.insert(hover) {return} - let (rx, _) = cl - .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>, _>, - > = cl.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(); - // }); - // }); - } - Some(Do::Hover) => { - self.requests.def.result = None; - self.requests.hovering.result = None; - w.request_redraw(); - } - None => {} - x => unreachable!("{x:?}"), - } - } - pub fn click( - &mut self, - bt: MouseButton, - cursor_position: (usize, usize), - w: Arc<dyn Window>, - ) { - let text = &mut self.text; - _ = self - .requests - .complete - .consume(CompletionAction::Click) - .unwrap(); - match self.state.consume(Action::M(bt)).unwrap() { - Some(Do::MoveCursor) => { - text.cursor.just( - text.mapped_index_at(cursor_position), - &text.rope, - ); - if let Some((lsp, path)) = lsp!(self + p) { - if self.requests.sig_help.result.is_some() { - self.requests.sig_help.request(lsp.runtime.spawn( - lsp.request_sig_help( - path, - text.primary_cursor(), - ), - )); - } - self.requests.document_highlights.request( - lsp.runtime.spawn( - lsp.document_highlights( - path, - text.to_l_position( - text.cursor.first().position, - ) - .unwrap(), - ), - ), - ); - } - self.hist.lc = text.cursor.clone(); - self.chist.push(text.primary_cursor()); - text.cursor.first().setc(&text.rope); - } - Some(Do::NavForward) => self.nav_forward(), - Some(Do::NavBack) => self.nav_back(), - Some(Do::ExtendSelectionToMouse) => { - let p = text.mapped_index_at(cursor_position); - text.cursor.first_mut().extend_selection_to(p, &text.rope); - } - Some(Do::StartSelection) => { - let p = text.mapped_index_at(cursor_position); - - let x = *text.cursor.first(); - text.cursor.first_mut().sel = Some((x..x).into()); - text.cursor.first_mut().extend_selection_to(p, &text.rope); - self.hist.lc = text.cursor.clone(); - } - Some(Do::GoToDefinition) => { - if let Some(x) = self.requests.def.result.clone() - && let Err(e) = self.go(&x, w.clone()) - { - log::error!("gtd: {e}"); - } - } - Some(Do::InsertCursorAtMouse) => { - text.cursor.add( - text.mapped_index_at(cursor_position), - &text.rope, - ); - self.hist.lc = text.cursor.clone(); - self.chist.push(text.primary_cursor()); - text.cursor.first().setc(&text.rope); - } - None => {} - _ => unreachable!(), - } - } pub fn nav_back(&mut self) { self.chist.back().map(|x| { @@ -943,872 +390,7 @@ impl Editor { } inlay!(self); } - pub fn keyboard( - &mut self, - event: KeyEvent, - window: &mut Arc<dyn Window>, - ) -> ControlFlow<()> { - let mut o: Option<Do> = self - .state - .consume(Action::K(event.logical_key.clone())) - .unwrap(); - match o { - Some(Do::Reinsert) => - o = self - .state - .consume(Action::K(event.logical_key.clone())) - .unwrap(), - _ => {} - } - match o { - Some(Do::Escape) => { - take(&mut self.requests.complete); - take(&mut self.requests.sig_help); - self.text.cursor.alone(); - } - Some(Do::Comment(p)) => { - ceach!(self.text.cursor, |cursor| { - Some( - if let Some(x) = cursor.sel - && matches!(p, State::Selection) - { - self.text.comment(x.into()); - } else { - self.text - .comment(cursor.position..cursor.position); - }, - ) - }); - self.text.cursor.clear_selections(); - change!(self, window.clone()); - } - Some(Do::SpawnTerminal) => { - if let Err(e) = trm::toggle( - self.workspace - .as_deref() - .unwrap_or(Path::new("/home/os/")), - ) { - log::error!("opening terminal failed {e}"); - } - } - Some(Do::MatchingBrace) => { - if let Some((l, f)) = lsp!(self + p) { - l.matching_brace(f, &mut self.text); - } - } - Some(Do::DeleteBracketPair) => { - if let Some((l, f)) = lsp!(self + p) { - if let Ok(x) = l.matching_brace_at( - f, - self.text.cursor.positions(&self.text.rope), - ) { - use itertools::Itertools; - for p in - // self.text.cursor.iter() - x - .iter() - .flatten() - .flat_map(|(a, b)| { - [a, b].map(|c| { - self.text - .rope - .l_position(*c) - .unwrap() - }) - }) - .sorted() - .rev() - { - self.text.remove(p..p + 1).unwrap(); - } - } - } - } - Some(Do::Symbols) => - if let Some((lsp, o)) = lsp!(self + p) { - let mut q = Rq::new( - lsp.runtime.spawn( - lsp.workspace_symbols("".into()) - .map(|x| x.anonymize()) - .map(|x| { - x.map(|x| { - x.map(SymbolsList::Workspace) - }) - }), - ), - ); - q.result = Some(Symbols::new( - self.tree.as_deref().unwrap(), - self.text.bookmarks.clone(), - o.into(), - )); - self.state = State::Symbols(q); - }, - Some(Do::SwitchType) => - if let Some((lsp, p)) = lsp!(self + p) { - let State::Symbols(Rq { result: Some(x), request }) = - &mut self.state - else { - unreachable!() - }; - x.data.3 = sym::SymbolsType::Document; - let p = p.to_owned(); - take(&mut x.data.0); - *request = Some(( - DropH::new(lsp.runtime.spawn(async move { - lsp.document_symbols(&p) - .await - .anonymize() - .map(|x| x.map(SymbolsList::Document)) - })), - (), - )); - }, - Some(Do::ProcessCommand(mut x, z)) => - match Cmds::complete_or_accept(&z) { - crate::menu::generic::CorA::Complete => { - x.tedit.rope = - Rope::from_str(&format!("{} ", z.name())); - x.tedit.cursor.end(&x.tedit.rope); - self.state = State::Command(x); - } - crate::menu::generic::CorA::Accept => { - if let Err(e) = - self.handle_command(z, window.clone()) - { - self.bar.last_action = format!("{e}"); - } - } - }, - Some(Do::CmdTyped) => { - let State::Command(x) = &self.state else { - unreachable!() - }; - if let Some(Ok(crate::commands::Cmd::GoTo(Some(x)))) = - x.sel() - { - self.text.scroll_to_ln_centering(x as _); - } - } - Some(Do::SymbolsHandleKey) => { - if let Some(lsp) = lsp!(self) { - let State::Symbols(Rq { result: Some(x), request }) = - &mut self.state - else { - unreachable!() - }; - let ptedit = x.tedit.rope.clone(); - if handle2( - &event.logical_key, - &mut x.tedit, - lsp!(self + p), - ) - .is_some() - || ptedit != x.tedit.rope - { - if x.data.3 == SymbolsType::Workspace { - *request = Some(( - DropH::new( - lsp.runtime.spawn( - lsp.workspace_symbols( - x.tedit.rope.to_string(), - ) - .map(|x| { - x.anonymize().map(|x| { - x.map( - SymbolsList::Workspace, - ) - }) - }), - ), - ), - (), - )); - } else { - x.selection = 0; - x.vo = 0; - } - // state = State::Symbols(Rq::new(lsp.runtime.spawn(lsp.symbols("".into())))); - } - } - } - Some(Do::SymbolsSelectNext) => { - let State::Symbols(Rq { result: Some(x), .. }) = - &mut self.state - else { - unreachable!() - }; - x.next(); - if let Some(Ok(x)) = x.sel() - && Some(&*x.at.path) == self.origin.as_deref() - { - match x.at { - sym::GoTo { path: _, at: At::R(x) } => { - let x = self.text.l_range(x).unwrap(); - self.text.vo = self.text.char_to_line(x.start); - } - sym::GoTo { path: _, at: At::P(x) } => - self.text.vo = self.text.char_to_line(x), - } - } - } - Some(Do::SymbolsSelectPrev) => { - let State::Symbols(Rq { result: Some(x), .. }) = - &mut self.state - else { - unreachable!() - }; - x.back(); - if let Some(Ok(x)) = x.sel() - && Some(&*x.at.path) == self.origin.as_deref() - { - match x.at.at { - At::R(x) => { - let x = self.text.l_range(x).unwrap(); - self.text.vo = self.text.char_to_line(x.start); - } - At::P(x) => - self.text.vo = self.text.char_to_line(x), - } - } - } - Some(Do::SymbolsSelect(x)) => - if let Some(Ok(x)) = x.sel() - && let Err(e) = self.go(x.at, window.clone()) - { - log::error!("alas! {e}"); - }, - Some(Do::RenameSymbol(to)) => { - if let Some((lsp, f)) = lsp!(self + p) { - let x = lsp - .request_immediate::<lsp_request!("textDocument/rename")>( - &RenameParams { - text_document_position: - TextDocumentPositionParams { - text_document: f.tid(), - position: self - .text - .to_l_position( - self.text - .cursor - .first() - .position, - ) - .unwrap(), - }, - new_name: to, - work_done_progress_params: default(), - }, - ); - - match x { - Ok(Some(x)) => - if let Err(e) = - self.apply_wsedit(x, &f.to_owned()) - { - println!( - "couldnt apply one or more wsedits: \ - {e}" - ); - }, - Err(RequestError::Failure( - lsp_server::Response { - result: None, - error: - Some(ResponseError { - code: -32602, - message, - data: None, - }), - .. - }, - .., - )) => self.bar.last_action = message, - _ => {} - } - } - } - Some(Do::CodeAction) => { - if let Some((lsp, f)) = lsp!(self + p) { - let r = lsp - .request::<lsp_request!("textDocument/codeAction")>( - &CodeActionParams { - text_document: f.tid(), - range: self - .text - .to_l_range( - self.text.cursor.first().position..self.text.cursor.first().position, - ) - .unwrap(), - context: CodeActionContext { - trigger_kind: Some( - CodeActionTriggerKind::INVOKED, - ), - // diagnostics: if let Some((lsp, p)) = lsp!() && let uri = Url::from_file_path(p).unwrap() && let Some(diag) = lsp.requests.diagnostics.get(&uri, &lsp.requests.diagnostics.guard()) { dbg!(diag.iter().filter(|x| { - // self.text.l_range(x.range).unwrap().contains(&self.text.cursor) - // }).cloned().collect()) } else { vec![] }, - ..default() - }, - work_done_progress_params: default(), - partial_result_params: default(), - }, - ) - .unwrap(); - - self.state = - State::CodeAction(Rq::new(lsp.runtime.spawn(r.0))); - } - } - Some(Do::CASelectLeft) => { - let State::CodeAction(Rq { result: Some(c), .. }) = - &mut self.state - else { - panic!() - }; - c.left(); - } - Some(Do::CASelectRight) => 'out: { - let Some((lsp, f)) = lsp!(self + p) else { - unreachable!() - }; - let State::CodeAction(Rq { result: Some(c), .. }) = - &mut self.state - else { - panic!() - }; - let Some(act) = c.right() else { break 'out }; - let act = act.clone(); - self.state = State::Default; - self.hist.lc = self.text.cursor.clone(); - self.hist.test_push(&mut self.text); - let act = lsp - .request_immediate::<CodeActionResolveRequest>(&act) - .unwrap(); - let f = f.to_owned(); - if let Some(x) = act.edit - && let Err(e) = self.apply_wsedit(x, &f) - { - log::error!("{e}"); - } - } - Some(Do::CASelectNext) => { - let State::CodeAction(Rq { result: Some(c), .. }) = - &mut self.state - else { - panic!() - }; - c.down(); - } - Some(Do::CASelectPrev) => { - let State::CodeAction(Rq { result: Some(c), .. }) = - &mut self.state - else { - panic!() - }; - c.up(); - } - Some(Do::NavBack) => self.nav_back(), - Some(Do::NavForward) => self.nav_forward(), - Some( - Do::Reinsert - | Do::GoToDefinition - | Do::MoveCursor - | Do::ExtendSelectionToMouse - | Do::Hover - | Do::InsertCursorAtMouse, - ) => panic!(), - Some(Do::Save) => match &self.origin { - Some(_) => { - self.state.consume(Action::Saved).unwrap(); - self.save(); - } - None => { - self.state.consume(Action::RequireFilename).unwrap(); - } - }, - Some(Do::SaveTo(x)) => { - self.origin = Some(PathBuf::try_from(x).unwrap()); - self.save(); - } - Some(Do::Edit) => { - self.text.cursor.clear_selections(); - self.hist.test_push(&mut self.text); - let cb4 = self.text.cursor.first(); - if let Key::Named(Enter | ArrowUp | ArrowDown | Tab) = - event.logical_key - && let CompletionState::Complete(..) = - self.requests.complete - { - } else { - if let Some(x) = handle2( - &event.logical_key, - &mut self.text, - lsp!(self + p), - ) && let Some((l, p)) = lsp!(self + p) - && let Some( - InitializeResult { - capabilities: - ServerCapabilities { - document_on_type_formatting_provider: - Some(DocumentOnTypeFormattingOptions { - first_trigger_character, - more_trigger_character: Some(t), - }), - .. - }, - .. - }, - .., - ) = &l.initialized - && (first_trigger_character == first_trigger_character - || t.iter().any(|y| y == x)) - && self.text.cursor.inner.len() == 1 - && change!(just self).is_some() - && let Ok(Some(mut x)) = l - .request_immediate::<OnTypeFormatting>( - &DocumentOnTypeFormattingParams { - text_document_position: - TextDocumentPositionParams { - text_document: p.tid(), - position: self - .text - .to_l_position( - *self.text.cursor.first(), - ) - .unwrap(), - }, - ch: x.into(), - options: FormattingOptions { - tab_size: 4, - ..default() - }, - }, - ) - { - x.sort_tedits(); - for x in x { - self.text.apply_snippet_tedit(&x).unwrap(); - } - } - }; - self.text.scroll_to_cursor(); - if cb4 != self.text.cursor.first() - && let CompletionState::Complete(Rq { - result: Some(c), - .. - }) = &self.requests.complete - && let at = - self.text.cursor.first().at_(&self.text.rope) - && ((self.text.cursor.first() < c.start) - || (!super::is_word(at) - && (at != '.' || at != ':'))) - { - self.requests.complete = CompletionState::None; - } - if self.requests.sig_help.running() - && cb4 != self.text.cursor.first() - && let Some((lsp, path)) = lsp!(self + p) - { - self.requests.sig_help.request( - lsp.runtime.spawn( - lsp.request_sig_help( - path, - self.text - .cursor - .first() - .cursor(&self.text.rope), - ), - ), - ); - } - if self.hist.record(&self.text) { - change!(self, window.clone()); - } - lsp!(self + p).map(|(lsp, o)| { - match event.logical_key.as_ref() { - Key::Character(y) - if let Some(x) = &lsp.initialized - && let Some(x) = &x - .capabilities - .signature_help_provider - && let Some(x) = &x.trigger_characters - && x.contains(&y.to_string()) => - { - self.requests.sig_help.request( - lsp.runtime.spawn( - lsp.request_sig_help( - o, - self.text - .cursor - .first() - .cursor(&self.text.rope), - ), - ), - ); - } - _ => {} - } - match self - .requests - .complete - .consume(CompletionAction::K( - event.logical_key.as_ref(), - )) - .unwrap() - { - Some(CDo::Request(ctx)) => { - let h = DropH::new( - lsp.runtime.spawn( - lsp.request_complete( - o, - self.text - .cursor - .first() - .cursor(&self.text.rope), - ctx, - ), - ), - ); - let CompletionState::Complete(Rq { - request: x, - result: c, - }) = &mut self.requests.complete - else { - panic!() - }; - *x = Some(( - h, - c.as_ref() - .map(|x| x.start) - .or(x.as_ref().map(|x| x.1)) - .unwrap_or(*self.text.cursor.first()), - )); - } - Some(CDo::SelectNext) => { - let CompletionState::Complete(Rq { - result: Some(c), - .. - }) = &mut self.requests.complete - else { - panic!() - }; - c.next(&filter(&self.text)); - } - Some(CDo::SelectPrevious) => { - let CompletionState::Complete(Rq { - result: Some(c), - .. - }) = &mut self.requests.complete - else { - panic!() - }; - c.back(&filter(&self.text)); - } - Some(CDo::Finish(x)) => { - let sel = x.sel(&filter(&self.text)); - let sel = lsp.resolve(sel.clone()).unwrap(); - let CompletionItem { - text_edit: - Some(CompletionTextEdit::Edit(ed)), - additional_text_edits, - insert_text_format, - .. - } = sel.clone() - else { - panic!() - }; - match insert_text_format { - Some(InsertTextFormat::SNIPPET) => { - self.text.apply_snippet(&ed).unwrap(); - } - _ => { - self.text.apply(&ed).unwrap(); - // self.text - // .cursor - // .first_mut() - // .position = - // s + ed.new_text.chars().count(); - } - } - if let Some(mut additional_tedits) = - additional_text_edits - { - additional_tedits.sort_tedits(); - for additional in additional_tedits { - self.text - .apply_adjusting(&additional) - .unwrap(); - } - } - if self.hist.record(&self.text) { - change!(self, window.clone()); - } - self.requests.sig_help = Rq::new( - lsp.runtime.spawn( - lsp.request_sig_help( - o, - self.text - .cursor - .first() - .cursor(&self.text.rope), - ), - ), - ); - } - None => return, - }; - }); - } - Some(Do::Undo) => { - self.hist.test_push(&mut self.text); - self.hist.undo(&mut self.text).unwrap(); - self.bar.last_action = "undid".to_string(); - change!(self, window.clone()); - } - Some(Do::Redo) => { - self.hist.test_push(&mut self.text); - self.hist.redo(&mut self.text).unwrap(); - self.bar.last_action = "redid".to_string(); - change!(self, window.clone()); - } - Some(Do::Quit) => return ControlFlow::Break(()), - Some(Do::SetCursor(x)) => { - self.text.cursor.each(|c| { - let Some(r) = c.sel else { return }; - match x { - LR::Left => c.position = r.start, - LR::Right => c.position = r.end, - } - }); - self.text.cursor.clear_selections(); - } - Some(Do::StartSelection) => { - let Key::Named(y) = event.logical_key else { panic!() }; - // let mut z = vec![]; - self.text.cursor.each(|x| { - x.sel = Some(Ronge::from(**x..**x)); - x.extend_selection( - y, - // **x..**x, - &self.text.rope, - &mut self.text.vo, - self.text.r, - ); - }); - // *self.state.sel() = z; - } - Some(Do::UpdateSelection) => { - let Key::Named(y) = event.logical_key else { panic!() }; - self.text.cursor.each(|x| { - x.extend_selection( - y, - // dbg!(r.clone()), - &self.text.rope, - &mut self.text.vo, - self.text.r, - ); - }); - - self.text.scroll_to_cursor(); - inlay!(self); - } - Some(Do::Insert(c)) => { - // self.text.cursor.inner.clear(); - self.hist.push_if_changed(&mut self.text); - ceach!(self.text.cursor, |cursor| { - let Some(r) = cursor.sel else { return }; - _ = self.text.remove(r.into()); - // self.text.cursor.first().setc(&self.text.rope); - }); - self.text.insert(&c); - self.text.cursor.clear_selections(); - self.hist.push_if_changed(&mut self.text); - change!(self, window.clone()); - } - Some(Do::Delete) => { - self.hist.push_if_changed(&mut self.text); - ceach!(self.text.cursor, |cursor| { - let Some(r) = cursor.sel else { return }; - _ = self.text.remove(r.into()); - }); - self.text.cursor.clear_selections(); - self.hist.push_if_changed(&mut self.text); - change!(self, window.clone()); - } - - Some(Do::Copy) => { - self.hist.push_if_changed(&mut self.text); - unsafe { take(&mut META) }; - let mut clip = String::new(); - self.text.cursor.each_ref(|x| { - if let Some(x) = x.sel { - unsafe { - META.count += 1; - META.splits.push(clip.len()); - } - clip.extend(self.text.rope.slice(x).chars()); - } - }); - unsafe { - META.splits.push(clip.len()); - META.hash = hash(&clip) - }; - clipp::copy(clip); - self.text.cursor.clear_selections(); - self.hist.push_if_changed(&mut self.text); - change!(self, window.clone()); - } - Some(Do::Cut) => { - self.hist.push_if_changed(&mut self.text); - unsafe { take(&mut META) }; - let mut clip = String::new(); - self.text.cursor.each_ref(|x| { - if let Some(x) = x.sel { - unsafe { - META.count += 1; - META.splits.push(clip.len()); - } - clip.extend(self.text.rope.slice(x).chars()); - } - }); - unsafe { - META.splits.push(clip.len()); - META.hash = hash(&clip) - }; - clipp::copy(clip); - ceach!(self.text.cursor, |x| { - if let Some(x) = x.sel { - self.text.remove(x.into()).unwrap(); - } - }); - self.text.cursor.clear_selections(); - self.hist.push_if_changed(&mut self.text); - change!(self, window.clone()); - } - Some(Do::PasteOver) => { - self.hist.push_if_changed(&mut self.text); - ceach!(self.text.cursor, |cursor| { - let Some(r) = cursor.sel else { return }; - _ = self.text.remove(r.into()); - }); - self.text.cursor.clear_selections(); - self.paste(); - // self.hist.push_if_changed(&mut self.text); - } - Some(Do::Paste) => self.paste(), - Some(Do::OpenFile(x)) => { - _ = self.open(Path::new(&x), window.clone()); - } - Some(Do::StartSearch(x)) => { - let s = Regex::new(&x).unwrap(); - let n = s - .find_iter(&self.text.rope.to_string()) - .enumerate() - .count(); - s.clone() - .find_iter(&self.text.rope.to_string()) - .enumerate() - .find(|(_, x)| x.start() > *self.text.cursor.first()) - .map(|(x, m)| { - self.state = State::Search(s, x, n); - self.text.cursor.just( - self.text.rope.byte_to_char(m.end()), - &self.text.rope, - ); - self.text.scroll_to_cursor_centering(); - inlay!(self); - }) - .unwrap_or_else(|| { - self.bar.last_action = "no matches".into() - }); - } - Some(Do::SearchChanged) => { - let (re, index, _) = self.state.search(); - let s = self.text.rope.to_string(); - let m = re.find_iter(&s).nth(*index).unwrap(); - self.text.cursor.just( - self.text.rope.byte_to_char(m.end()), - &self.text.rope, - ); - self.text.scroll_to_cursor_centering(); - inlay!(self); - } - Some(Do::Boolean(BoolRequest::ReloadFile, true)) => { - self.hist.push_if_changed(&mut self.text); - self.text.rope = Rope::from_str( - &std::fs::read_to_string( - self.origin.as_ref().unwrap(), - ) - .unwrap(), - ); - - self.text.cursor.first_mut().position = self - .text - .cursor - .first() - .position - .min(self.text.rope.len_chars()); - self.mtime = Self::modify(self.origin.as_deref()); - self.bar.last_action = "reloaded".into(); - self.hist.push(&mut self.text) - } - Some(Do::Boolean(BoolRequest::ReloadFile, false)) => {} - Some(Do::InsertCursor(dir)) => { - let (x, y) = match dir { - Direction::Above => self.text.cursor.min(), - Direction::Below => self.text.cursor.max(), - } - .cursor(&self.text.rope); - let y = match dir { - Direction::Above => y - 1, - Direction::Below => y + 1, - }; - let position = self.text.line_to_char(y); - self.text.cursor.add(position + x, &self.text.rope); - } - Some(Do::Run(x)) => - if let Some((l, ws)) = - lsp!(self).zip(self.workspace.as_deref()) - { - l.runtime - .block_on(crate::runnables::run(x, ws)) - .unwrap(); - }, - Some(Do::GoToImplementations) => { - let State::GoToL(x) = &mut self.state else { - unreachable!() - }; - if let Some(l) = lsp!(self) { - x.data.1 = Some(crate::gotolist::O::Impl(Rq::new( - l.runtime.spawn( - l.go_to_implementations(tdpp!(self)).unwrap(), - ), - ))); - } - } - Some(Do::GTLSelect(x)) => - if let Some(Ok(g)) = x.sel() - && let Err(e) = self.go(g, window.clone()) - { - eprintln!("go-to-list select fail: {e}"); - }, - Some(Do::GT) => { - let State::GoToL(x) = &mut self.state else { - unreachable!() - }; - if let Some(Ok(GoTo { path: p, at: At::R(r) })) = x.sel() - && Some(&*p) == self.origin.as_deref() - { - // let x = self.text.l_range(r).unwrap(); - self.text.scroll_to_ln_centering(r.start.line as _); - // self.text.vo = self.text.char_to_line(x.start); - } - } - None => {} - } - ControlFlow::Continue(()) - } pub fn paste(&mut self) { self.hist.push_if_changed(&mut self.text); let r = clipp::paste(); @@ -2012,59 +594,6 @@ impl Editor { } use NamedKey::*; -pub fn handle2<'a>( - key: &'a Key, - text: &mut TextArea, - l: Option<(&Client, &Path)>, -) -> Option<&'a str> { - use Key::*; - - match key { - Character(" ") => text.insert(" "), - Named(Backspace) if ctrl() => text.backspace_word(), - Named(Backspace) => text.backspace(), - Named(Home) if ctrl() => { - text.cursor.just(0, &text.rope); - text.vo = 0; - } - Named(End) if ctrl() => { - text.cursor.just(text.rope.len_chars(), &text.rope); - text.vo = text.l().saturating_sub(text.r); - } - Character("e") if alt() => text.end(), - Character("q") if alt() => text.home(), - Named(Home) => text.home(), - Named(End) => text.end(), - Named(Tab) => text.tab(), - Named(Delete) => { - text.right(); - text.backspace() - } - Character("a") if alt() && ctrl() => text.word_left(), - Character("d") if alt() && ctrl() => text.word_right(), - Character("a") if alt() => text.left(), - Character("w") if alt() => text.up(), - Character("s") if alt() => text.down(), - Character("d") if alt() => text.right(), - Named(ArrowLeft) if ctrl() => text.word_left(), - Named(ArrowRight) if ctrl() => text.word_right(), - Named(ArrowLeft) => text.left(), - Named(ArrowRight) => text.right(), - Named(ArrowUp) => text.up(), - Named(ArrowDown) => text.down(), - Named(PageDown) => text.page_down(), - Named(PageUp) => text.page_up(), - Named(Enter) if let Some((l, p)) = l => l.enter(p, text).unwrap(), - Named(Enter) => text.enter(), - Character(x) => { - text.insert(&x); - return Some(x); - } - _ => {} - }; - None -} - impl State { fn search(&mut self) -> (&mut Regex, &mut usize, &mut usize) { let State::Search(x, y, z) = self else { panic!() }; |