A simple CPU rendered GUI IDE experience.
Diffstat (limited to 'src/edi.rs')
-rw-r--r--src/edi.rs1503
1 files changed, 16 insertions, 1487 deletions
diff --git a/src/edi.rs b/src/edi.rs
index b9cad5b..d025911 100644
--- a/src/edi.rs
+++ b/src/edi.rs
@@ -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!() };