A simple CPU rendered GUI IDE experience.
lifetime management
| -rw-r--r-- | src/bar.rs | 3 | ||||
| -rw-r--r-- | src/commands.rs | 6 | ||||
| -rw-r--r-- | src/edi.rs | 97 | ||||
| -rw-r--r-- | src/edi/input_handlers.rs | 2 | ||||
| -rw-r--r-- | src/edi/input_handlers/cursor.rs | 17 | ||||
| -rw-r--r-- | src/edi/input_handlers/keyboard.rs | 1 | ||||
| -rw-r--r-- | src/edi/lsp.rs | 0 | ||||
| -rw-r--r-- | src/edi/lsp_impl.rs | 3 | ||||
| -rw-r--r-- | src/edi/lsp_mn.rs | 100 | ||||
| -rw-r--r-- | src/lsp.rs | 2 | ||||
| -rw-r--r-- | src/lsp/client.rs | 59 | ||||
| -rw-r--r-- | src/lsp/communication.rs | 14 | ||||
| -rw-r--r-- | src/lsp/rq.rs | 11 | ||||
| -rw-r--r-- | src/lsp/vsc_settings.rs | 2 | ||||
| -rw-r--r-- | src/main.rs | 4 | ||||
| -rw-r--r-- | src/rnd.rs | 6 |
16 files changed, 196 insertions, 131 deletions
@@ -1,4 +1,5 @@ use std::iter::{chain, repeat}; +use std::sync::Arc; use dsb::Cell; use dsb::cell::Style; @@ -24,7 +25,7 @@ impl Bar { fname: &str, state: &super::State, _t: &TextArea, - lsp: Option<&Client>, + lsp: Option<Arc<Client>>, ) { let fname = simplify_path(fname); let row = &mut into[oy * w..oy * w + w]; diff --git a/src/commands.rs b/src/commands.rs index 13f77fb..f91ee2d 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -432,7 +432,8 @@ impl Editor { ..default() }), Cmd::Incoming => { - let x = l.runtime.spawn(l.callers(tdpp!(self))); + let l2 = l.clone(); + let x = l.runtime.spawn(l2.callers(tdpp!(self))); self.state = crate::edi::st::State::GoToL(GoToList { data: ( vec![], @@ -442,7 +443,8 @@ impl Editor { }); } Cmd::Outgoing => { - let x = l.runtime.spawn(l.calling(tdpp!(self))); + let l2 = l.clone(); + let x = l.runtime.spawn(l2.calling(tdpp!(self))); self.state = crate::edi::st::State::GoToL(GoToList { data: ( vec![], @@ -1,18 +1,15 @@ use std::collections::HashMap; use std::ffi::OsString; use std::fmt::Debug; -use std::io::{BufReader, ErrorKind}; +use std::io::ErrorKind; use std::mem::take; use std::path::{Path, PathBuf}; -use std::process::Stdio; use std::sync::Arc; use std::time::SystemTime; use Default::default; use ftools::Bind; use helix_core::syntax::config::FileType; -use log::info; -use lsp_server::Connection; use lsp_types::*; use regex::Regex; use rootcause::report; @@ -26,6 +23,7 @@ mod input_handlers; pub use input_handlers::handle2; mod lsp_impl; +mod lsp_mn; mod ra; pub mod st; mod wsedit; @@ -87,7 +85,7 @@ pub struct Editor { pub git_dir: Option<PathBuf>, #[serde(skip)] pub lsp: Option<( - &'static Client, + Arc<Client>, std::thread::JoinHandle<()>, Option<Sender<Arc<dyn Window>>>, )>, @@ -106,8 +104,11 @@ pub struct Editor { } macro_rules! lsp { + (&$self:ident) => { + $self.lsp.as_ref().map(|(x,..)| x) + }; ($self:ident) => { - $self.lsp.as_ref().map(|(x, ..)| *x) + $self.lsp.as_ref().map(|(x, ..)| x.clone()) }; ($self:ident + p) => { $crate::edi::lsp!($self).zip($self.origin.as_deref()) @@ -119,6 +120,13 @@ macro_rules! lsp { return $($else)?; }; }; + (let $lsp:ident = $self:ident $(else $else:expr)?) => { + let Some($lsp) = + $crate::edi::lsp!($self) + else { + return $($else)?; + }; + }; } pub(crate) use lsp; macro_rules! inlay { @@ -290,7 +298,7 @@ impl Editor { .and_then(|x| rooter(&x, |x| x == ".vscode", upto)) .map(|x| (x.clone(), x.join(".vscode").join("settings.json"))) .filter(|x| x.1.exists()) - .and_then(|(ws, x)| (vsc_settings::load(&x, &ws)).ok()); + .and_then(|(ws, x)| vsc_settings::load(&x, &ws).ok()); let mut loaded_state = false; let mut freq = default(); @@ -339,67 +347,12 @@ impl Editor { .map(|x| x.path().to_owned()) .collect::<Vec<_>>() }); - let l = me.workspace.as_ref().zip(l).and_then(|(workspace, l)| { - let (Connection { sender, receiver }, conf) = if l.language_id - == "rust" - { - super let (_jh, a) = ra::ra(workspace.clone()); - ( - a, - ( - &LOADER.language_server_configs()["rust-analyzer"], - &l.language_servers[0], - ), - ) - } else { - let (mut c, conf) = l - .language_servers - .iter() - .find_map(|l| { - let lc = LOADER - .language_server_configs() - .get(&l.name)?; - std::process::Command::new(&lc.command) - .args(&lc.args) - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .stderr(Stdio::inherit()) - .spawn() - .ok() - .zip(Some((lc, l))) - }) - .ok_or_else(|| { - log::error!( - "no lsp for this language; install one of \ - {:?}", - l.language_servers - ) - }) - .ok()?; - super let (x, _iot) = - Connection::stdio( - BufReader::new(c.stdout.take().unwrap()), - c.stdin.take().unwrap(), - ); - (x, conf) - }; - info!("spawned {conf:?}"); - let (c, t2, changed) = crate::lsp::run( - (sender, receiver), - WorkspaceFolder { - uri: Url::from_file_path(&workspace).unwrap(), - name: workspace - .file_name() - .unwrap() - .to_string_lossy() - .into_owned(), - }, - vsc, - conf, - ) - .unwrap(); - Some((&*Box::leak(Box::new(c)), (t2), Some(changed))) - }); + + let l = me + .workspace + .as_ref() + .zip(n) + .and_then(|(w, ln)| lsp_mn::load(w, ln, vsc)); let g = me.git_dir.clone(); if let Some(o) = me.origin.clone() && loaded_state @@ -421,9 +374,7 @@ impl Editor { me.lsp = l; me.hist.lc = me.text.cursor.clone(); me.hist.last = me.text.changes.clone(); - if let Some(((c, ..), origin)) = - me.lsp.as_ref().zip(me.origin.as_deref()) - { + if let Some((c, origin)) = lsp!(me + p) { c.open( &origin, std::fs::read_to_string(&origin)?, @@ -641,7 +592,7 @@ impl Editor { &mut self, lsp: Option<( - &'static Client, + Arc<Client>, std::thread::JoinHandle<()>, Option<Sender<Arc<dyn Window>>>, )>, @@ -691,7 +642,7 @@ impl Editor { &mut self, x: &Path, lsp: Option<( - &'static Client, + Arc<Client>, std::thread::JoinHandle<()>, Option<Sender<Arc<dyn Window>>>, )>, diff --git a/src/edi/input_handlers.rs b/src/edi/input_handlers.rs index e169edb..aa9e6a3 100644 --- a/src/edi/input_handlers.rs +++ b/src/edi/input_handlers.rs @@ -8,7 +8,7 @@ use crate::edi::*; pub fn handle2<'a>( key: &'a Key, text: &mut TextArea, - l: Option<(&Client, &Path)>, + l: Option<(Arc<Client>, &Path)>, ) -> Option<&'a str> { use Key::*; diff --git a/src/edi/input_handlers/cursor.rs b/src/edi/input_handlers/cursor.rs index 089a4a7..953d320 100644 --- a/src/edi/input_handlers/cursor.rs +++ b/src/edi/input_handlers/cursor.rs @@ -267,18 +267,15 @@ impl Editor { let tdp = tdpp.clone(); let l = self.language; let window = w.clone(); + let x = lsp.request_::<HoverRequest, { BehaviourAfter::Nil }>( + &HoverParams { + text_document_position_params: tdp.clone(), + work_done_progress_params: default(), + }, + ); let handle: tokio::task::JoinHandle<Result<Option<Hovr>, _>> = lsp.runtime.spawn(async move { - let Some(x) = lsp - .request_::<HoverRequest, { BehaviourAfter::Nil }>( - &HoverParams { - text_document_position_params: tdp.clone(), - work_done_progress_params: default(), - }, - )? - .0 - .await? - else { + let Some(x) = x?.0.await? else { return Ok(None::<Hovr>); }; let (width, cells) = spawn_blocking(move || { diff --git a/src/edi/input_handlers/keyboard.rs b/src/edi/input_handlers/keyboard.rs index f76cd18..ca74611 100644 --- a/src/edi/input_handlers/keyboard.rs +++ b/src/edi/input_handlers/keyboard.rs @@ -19,7 +19,6 @@ use winit::window::Window; use crate::Freq; use crate::edi::*; -use crate::killring::KillRM; use crate::lsp::acceptable_duration; impl Editor { diff --git a/src/edi/lsp.rs b/src/edi/lsp.rs new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/edi/lsp.rs diff --git a/src/edi/lsp_impl.rs b/src/edi/lsp_impl.rs index 1498458..105595f 100644 --- a/src/edi/lsp_impl.rs +++ b/src/edi/lsp_impl.rs @@ -8,6 +8,7 @@ use serde::{Deserialize, Serialize}; use ttools::{Tupl, With}; use crate::complete::Complete; +use crate::edi::lsp; use crate::edi::st::*; use crate::hov::{Hoverable, Hovring}; use crate::lsp::{RequestError, Rq}; @@ -101,7 +102,7 @@ pub fn serialize_tokens<S: serde::Serializer>( } impl crate::edi::Editor { pub fn poll(&mut self) { - let Some((l, ..)) = self.lsp else { return }; + lsp!(let l = self); for rq in l.req_rx.try_iter() { match rq { LRq { method: "workspace/diagnostic/refresh", .. } => { diff --git a/src/edi/lsp_mn.rs b/src/edi/lsp_mn.rs new file mode 100644 index 0000000..6c76bdc --- /dev/null +++ b/src/edi/lsp_mn.rs @@ -0,0 +1,100 @@ +use std::collections::HashMap; +use std::io::BufReader; +use std::path::PathBuf; +use std::process::Stdio; +use std::sync::Arc; + +use log::info; +use lsp_server::{Connection, IoThreads}; +use lsp_types::*; +use tokio::sync::oneshot::Sender; +use tree_house::Language; +use winit::window::Window; + +struct LSP4 { + four: HashMap<(Language, PathBuf), &'static Client>, +} + +struct Loaded { + iot: Option<IoThreads>, + +} +use crate::lsp::Client; +pub fn load( + workspace: &PathBuf, + l: Language, + vsc: Option<serde_json::Value>, +) -> Option<( + Arc<Client>, + std::thread::JoinHandle<()>, + Option<Sender<Arc<dyn Window + 'static>>>, +)> { + let l = super::LOADER.language(l).config(); + let (Connection { sender, receiver }, conf,iot) = if l.language_id + == "rust" + { + let (_jh, a) = super::ra::ra(workspace.clone()); + ( + a, + ( + &super::LOADER.language_server_configs()["rust-analyzer"], + &l.language_servers[0], + ), + None + ) + } else { + let (mut c, conf) = l + .language_servers + .iter() + .find_map(|l| { + let lc = super::LOADER + .language_server_configs() + .get(&l.name)?; + std::process::Command::new(&lc.command) + .args(&lc.args) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::inherit()) + .spawn() + .ok() + .zip(Some((lc, l))) + }) + .ok_or_else(|| { + log::error!( + "no lsp for this language; install one of {:?}", + l.language_servers + ) + }) + .ok()?; + + let (x, iot) = Connection::stdio( + BufReader::new(c.stdout.take().unwrap()), + c.stdin.take().unwrap(), + ); + (x, conf, Some(iot)) + }; + info!("spawned {conf:?}"); + let (c, t2, changed) = crate::lsp::run( + (sender, receiver), + WorkspaceFolder { + uri: Url::from_file_path(&workspace).unwrap(), + name: workspace + .file_name() + .unwrap() + .to_string_lossy() + .into_owned(), + }, + vsc.and_then(|x| x.as_object()?.get(&conf.1.name).cloned()), + conf, + ) + .unwrap(); + Some((Arc::new(c), (t2), Some(changed))) +} + +fn rah() { +let stdout = 4; +super let x =( + &stdout, + + ); +}
\ No newline at end of file @@ -45,7 +45,7 @@ pub fn run( let (_req_tx, _req_rx) = unbounded(); let (window_tx, window_rx) = oneshot::channel::<Arc<dyn Window>>(); let mut c = Client { - tx, + tx: Tx(tx), progress: Box::leak(Box::new(papaya::HashMap::new())), runtime: tokio::runtime::Builder::new_multi_thread() .enable_time() diff --git a/src/lsp/client.rs b/src/lsp/client.rs index ff8d610..059e523 100644 --- a/src/lsp/client.rs +++ b/src/lsp/client.rs @@ -1,5 +1,6 @@ use std::fmt::Debug; use std::path::{Path, PathBuf}; +use std::sync::Arc; use std::sync::atomic::AtomicI32; use std::sync::atomic::Ordering::Relaxed; @@ -25,12 +26,27 @@ use crate::lsp::BehaviourAfter::{self, *}; use crate::lsp::{RequestError, Require, Requiring, Rq}; use crate::text::cursor::ceach; use crate::text::{LOADER, RopeExt, SortTedits, TextArea}; +#[derive(Debug, Clone)] +pub struct Tx(pub Sender<Message>); +impl std::ops::Deref for Client { + type Target = Tx; + fn deref(&self) -> &Self::Target { + &self.tx + } +} +impl std::ops::Deref for Tx { + type Target = Sender<Message>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} #[derive(Debug)] pub struct Client { pub runtime: tokio::runtime::Runtime, - pub tx: Sender<Message>, + pub tx: Tx, pub id: AtomicI32, pub initialized: Option<InitializeResult>, // pub pending: HashMap<i32, oneshot::Sender<Re>>, @@ -53,7 +69,8 @@ pub struct Client { impl Drop for Client { fn drop(&mut self) { - panic!("please dont"); + println!("dropped lsp"); + // panic!("please dont"); } } @@ -125,7 +142,7 @@ impl Client { Option<CompletionResponse>, RequestError<Completion>, >, - > + use<'me>, + > + use<>, > { self.caps().completion_provider.require()?; @@ -154,7 +171,7 @@ impl Client { Option<SignatureHelp>, RequestError<SignatureHelpRequest>, >, - > + use<'me>, + > + use<>, > { self.caps().signature_help_provider.require()?; Ok(self @@ -318,7 +335,7 @@ impl Client { Vec<DocumentHighlight>, RequestError<DocumentHighlightRequest>, >, - > + use<'me>, + > + use<>, > { self.caps().document_highlight_provider.require()?; let p = DocumentHighlightParams { @@ -335,7 +352,7 @@ impl Client { .map(|x| x.map(|x| x.unwrap_or_default()))) } pub fn document_symbols( - &'static self, + &self, p: &Path, ) -> Requiring< "document_symbol", @@ -358,7 +375,7 @@ impl Client { .0) } pub fn workspace_symbols( - &'static self, + &self, f: String, ) -> Requiring< "workspace_symbol", @@ -367,7 +384,7 @@ impl Client { Option<WorkspaceSymbolResponse>, RequestError<lsp_request!("workspace/symbol")>, >, - >, + > + use<>, > { self.caps().workspace_symbol_provider.require()?; Ok(self @@ -398,11 +415,7 @@ impl Client { }) } - pub fn matching_brace<'a>( - &'static self, - f: &Path, - t: &'a mut TextArea, - ) { + pub fn matching_brace<'a>(&self, f: &Path, t: &'a mut TextArea) { if let Ok(x) = self.matching_brace_at(f, t.cursor.positions(&t.rope)) { @@ -420,7 +433,7 @@ impl Client { } } pub fn inlay( - &'static self, + &self, f: &Path, t: &TextArea, ) -> Requiring< @@ -456,7 +469,7 @@ impl Client { // } } pub fn format( - &'static self, + &self, f: &Path, ) -> Requiring< "document_formatting", @@ -487,7 +500,7 @@ impl Client { .0) } pub fn rq_semantic_tokens( - &'static self, + &self, to: &mut Rq< Box<[SemanticToken]>, Box<[SemanticToken]>, @@ -558,7 +571,7 @@ impl Client { Ok(()) } pub fn runnables( - &'static self, + &self, t: &Path, c: Option<Position>, ) -> Result< @@ -574,7 +587,7 @@ impl Client { } pub fn _child_modules( - &'static self, + &self, p: Position, t: &Path, ) -> Result< @@ -601,7 +614,7 @@ impl Client { <GotoImplementation as Request>::Result, RequestError<GotoImplementation>, >, - >, + > + use<>, SendError<Message>, > { self.request::<GotoImplementation>(&GotoImplementationParams { @@ -621,7 +634,7 @@ impl Client { Option<Vec<Location>>, RequestError<References>, >, - >, + > + use<>, SendError<Message>, > { self.request::<References>(&ReferenceParams { @@ -650,7 +663,7 @@ impl Client { Option<CallHierarchyItem>, RequestError<CallHierarchyPrepare>, >, - >, + > + use<>, SendError<Message>, > { self.request::<CallHierarchyPrepare>(&CallHierarchyPrepareParams { @@ -661,7 +674,7 @@ impl Client { .map(|x| x.map(|x| x.map(|x| x.and_then(|mut x| x.try_remove(0))))) } pub async fn callers( - &self, + self: Arc<Self>, at: TextDocumentPositionParams, ) -> rootcause::Result<Vec<CallHierarchyIncomingCall>> { let calls = self @@ -681,7 +694,7 @@ impl Client { Ok(calls) } pub async fn calling( - &self, + self: Arc<Self>, at: TextDocumentPositionParams, ) -> rootcause::Result<Vec<CallHierarchyOutgoingCall>> { let calls = self diff --git a/src/lsp/communication.rs b/src/lsp/communication.rs index 30764a2..3e5bc3d 100644 --- a/src/lsp/communication.rs +++ b/src/lsp/communication.rs @@ -130,12 +130,12 @@ pub fn handler( } } } -impl super::Client { +impl super::Tx { pub fn notify<X: Notification>( &self, y: &X::Params, ) -> Result<(), SendError<Message>> { - self.tx.send(Message::Notification(N { + self.send(Message::Notification(N { method: X::METHOD.into(), params: serde_json::to_value(y).unwrap(), })) @@ -143,6 +143,8 @@ impl super::Client { pub fn cancel(&self, rid: i32) { _ = self.notify::<Cancel>(&CancelParams { id: rid.into() }); } +} +impl super::Client { pub fn request_immediate<'me, X: Request>( &'me self, y: &X::Params, @@ -169,8 +171,7 @@ impl super::Client { y: &X::Params, ) -> Result< ( - impl Future<Output = Result<X::Result, RequestError<X>>> - + use<'me, X>, + impl Future<Output = Result<X::Result, RequestError<X>>> + use<X>, i32, ), SendError<Message>, @@ -184,7 +185,7 @@ impl super::Client { ) -> Result< ( impl Future<Output = Result<X::Result, RequestError<X>>> - + use<'me, X, THEN>, + + use<X, THEN>, i32, ), SendError<Message>, @@ -202,10 +203,11 @@ impl super::Client { .send((id, tx, THEN)) .expect("oughtnt really fail"); } + let tx = self.tx.clone(); Ok(( async move { let g = scopeguard::guard((), |()| { - self.cancel(id); + tx.cancel(id); }); let mut x = rx.await?; diff --git a/src/lsp/rq.rs b/src/lsp/rq.rs index 1d7ef09..ef1316f 100644 --- a/src/lsp/rq.rs +++ b/src/lsp/rq.rs @@ -99,14 +99,15 @@ impl<const R: &'static str> Display for Unsupported<R> { write!(f, "request {} isnt supported by this LSP", R) } } -pub trait Peel<E> { - fn peel(self) -> Result<(), E>; +pub trait Peel<E, T> { + fn peel(self) -> Result<Option<T>, E>; } -impl<E, N> Peel<E> for Result<Result<(), E>, N> { - fn peel(self) -> Result<(), E> { +impl<E, N, T> Peel<E, T> for Result<Result<T, E>, N> { + fn peel(self) -> Result<Option<T>, E> { match self { Ok(Err(e)) => Err(e), - Ok(Ok(_)) | Err(_) => Ok(()), + Ok(Ok(x)) => Ok(Some(x)), + Err(_) => Ok(None), } } } diff --git a/src/lsp/vsc_settings.rs b/src/lsp/vsc_settings.rs index 570ebe3..1734c75 100644 --- a/src/lsp/vsc_settings.rs +++ b/src/lsp/vsc_settings.rs @@ -6,7 +6,7 @@ use rootcause::report; pub fn load(p: &Path, ws: &Path) -> rootcause::Result<serde_json::Value> { let std::process::Output {stdout, stderr,.. } = std::process::Command::new("jq").stdout(Stdio::piped()) - .args(["-M", "-c", "-r", r#"reduce to_entries[] as $x ({}; setpath(($x.key | split(".")); $x.value)) | ."rust-analyzer""#, &p.to_string_lossy()]).spawn()?.wait_with_output() + .args(["-M", "-c", "-r", r#"reduce to_entries[] as $x ({}; setpath(($x.key | split(".")); $x.value))"#, &p.to_string_lossy()]).spawn()?.wait_with_output() ?; let stdout = String::from_utf8(stdout)?.replace( "${workspaceFolder}", diff --git a/src/main.rs b/src/main.rs index de0fcb9..6cd7223 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,7 +8,6 @@ unsized_const_params, inherent_associated_types, never_type, random, - substr_range, btree_set_entry, associated_type_defaults, array_try_map, @@ -123,8 +122,9 @@ extern "C" fn cleanup() { unsafe { if __CLEAN == false { __CLEAN = true; + match __ED - .assume_init_mut() + .assume_init_read() .store(__FREQ.assume_init_mut(), __KR.assume_init_mut()) { Ok(_) => {} @@ -373,7 +373,7 @@ pub fn render( z, wt, ed.origin.as_deref(), - lsp!(ed).and_then(|x| x.legend()), + lsp!(&ed).and_then(|x| x.legend()), ed.language, ); @@ -592,7 +592,7 @@ pub fn render( // chain([Cell::default()], x.to_string().chars().map(Cell::basic)).chain([Cell::default()]).collect(); for (x, rel, mut cell) in text - .colored_lines(r, lsp!(ed).and_then(|x| x.legend())) + .colored_lines(r, lsp!(&ed).and_then(|x| x.legend())) { if rel == 0 { let rem = cells.len() % c; @@ -867,10 +867,8 @@ pub fn render( drawb(&c, 50); } State::KillRing(y) => { - dbg!(y); let ws = ed.workspace.as_deref().unwrap(); let c = y.cells(50, ws, None); - println!("???? {c:?}"); drawb(&c, 50); } _ => {} |