A simple CPU rendered GUI IDE experience.
-rw-r--r--src/commands.rs10
-rw-r--r--src/edi.rs201
-rw-r--r--src/edi/input_handlers/click.rs3
-rw-r--r--src/edi/input_handlers/keyboard.rs29
-rw-r--r--src/edi/lsp.rs0
-rw-r--r--src/edi/lsp_mn.rs52
-rw-r--r--src/lsp.rs1
-rw-r--r--src/lsp/client.rs19
-rw-r--r--src/lsp/communication.rs22
-rw-r--r--src/lsp/rq.rs29
-rw-r--r--src/main.rs13
-rw-r--r--src/rnd.rs12
12 files changed, 252 insertions, 139 deletions
diff --git a/src/commands.rs b/src/commands.rs
index f91ee2d..014a3f8 100644
--- a/src/commands.rs
+++ b/src/commands.rs
@@ -11,6 +11,7 @@ use lsp_types::*;
use rootcause::{bail, report};
use rust_analyzer::lsp::ext::*;
+use crate::edi::lsp_mn::LSPM;
use crate::edi::{Editor, lsp};
use crate::gotolist::{At, GoToList};
use crate::lsp::{PathURI, Rq, tdpp};
@@ -228,6 +229,7 @@ impl Editor {
z: Cmd,
w: Arc<dyn winit::window::Window>,
kr: &mut KillRing,
+ lsp_mn: &mut LSPM,
) -> rootcause::Result<()> {
match z {
Cmd::GoTo(Some(x)) =>
@@ -288,7 +290,8 @@ impl Editor {
);
}
Cmd::Reload => self.reload(),
- z if z.needs_lsp() => return self.handle_lsp_command(z, w),
+ z if z.needs_lsp() =>
+ return self.handle_lsp_command(z, w, lsp_mn),
x => unimplemented!("{x:?}"),
}
@@ -298,6 +301,7 @@ impl Editor {
&mut self,
z: Cmd,
w: Arc<dyn winit::window::Window>,
+ lsp_mn: &mut LSPM,
) -> rootcause::Result<()> {
let Some((l, o)) = lsp!(self + p) else {
bail!("no lsp");
@@ -337,7 +341,7 @@ impl Editor {
self.bar.last_action = "no such parent".into();
return Ok(());
};
- self.go(x, w)?;
+ self.go(x, w, lsp_mn)?;
}
Cmd::RAJoinLines => {
let teds =
@@ -412,7 +416,7 @@ impl Editor {
else {
bail!("wtf?");
};
- self.go(x, w)?;
+ self.go(x, w, lsp_mn)?;
}
Cmd::RARunnables => {
let p = self.text.to_l_position(*self.text.cursor.first());
diff --git a/src/edi.rs b/src/edi.rs
index 4c1ed73..addcefd 100644
--- a/src/edi.rs
+++ b/src/edi.rs
@@ -16,6 +16,7 @@ use rootcause::report;
use ropey::Rope;
use rust_fsm::StateMachine;
use tokio::sync::oneshot::Sender;
+use tree_house::Language;
use winit::keyboard::NamedKey;
use winit::window::Window;
@@ -23,7 +24,7 @@ mod input_handlers;
pub use input_handlers::handle2;
mod lsp_impl;
-mod lsp_mn;
+pub mod lsp_mn;
mod ra;
pub mod st;
mod wsedit;
@@ -33,6 +34,7 @@ use st::*;
use crate::bar::Bar;
use crate::commands::Cmds;
+use crate::edi::lsp_mn::{LSPM, LoadedLSP};
use crate::error::WDebug;
use crate::gotolist::{At, GoTo};
use crate::hov::{self, HOV_HEIGHT, Hovr, Hovring, Rendered};
@@ -59,7 +61,6 @@ impl Debug for Editor {
.field("origin", &self.origin)
.field("state", &self.state.name())
.field("bar", &self.bar)
- .field("workspace", &self.workspace)
.field("hist", &self.hist)
.field("mtime", &self.mtime)
.finish()
@@ -81,14 +82,11 @@ pub struct Editor {
pub state: State,
#[serde(skip)]
pub bar: Bar,
- pub workspace: Option<PathBuf>,
+ // pub workspace: Option<PathBuf>,
+ #[serde(skip)]
pub git_dir: Option<PathBuf>,
#[serde(skip)]
- pub lsp: Option<(
- Arc<Client>,
- std::thread::JoinHandle<()>,
- Option<Sender<Arc<dyn Window>>>,
- )>,
+ pub lsp: Option<(Arc<Client>, Option<Sender<Arc<dyn Window>>>)>,
// #[serde(skip)]
pub requests: Requests,
#[serde(skip)]
@@ -203,9 +201,9 @@ fn rooter(
}
impl Editor {
- pub fn new() -> rootcause::Result<(Self, Freq, KillRing)> {
- let mut me = Self::default();
-
+ pub fn new(
+ lsp_mn: &mut LSPM,
+ ) -> rootcause::Result<(Self, Freq, KillRing)> {
let mut o = std::env::args()
.nth(1)
.and_then(|x| PathBuf::try_from(x).ok())
@@ -224,7 +222,6 @@ impl Editor {
.set_title("pick dir to open")
.pick_folder()
});
-
if let Some(x) = &o {
match std::fs::read_to_string(x) {
Ok(_) => {}
@@ -258,6 +255,56 @@ impl Editor {
}
}
};
+ Editor::new_for(o, lsp_mn)
+ }
+
+ pub fn upto(&self) -> impl std::ops::Fn(&&Path) -> bool + Clone {
+ let upto = self
+ .git_dir
+ .clone()
+ .or(std::env::current_dir().ok())
+ .unwrap_or(PathBuf::from("/home/"));
+ move |x: &&Path| x.starts_with(&upto)
+ }
+
+ pub fn root_for(&self, o: &Path, l: Language) -> Option<PathBuf> {
+ let l = LOADER.language(l).config();
+
+ o.parent()
+ .and_then(|x| rooter(&x, |f| l.roots.is_match(f), self.upto()))
+ .or(std::env::current_dir().ok())
+ .and_then(|x| x.canonicalize().ok())
+ }
+ pub fn vsc(&self) -> Option<serde_json::Value> {
+ self.origin
+ .as_ref()
+ .and_then(|x| x.parent())
+ .and_then(|x| rooter(&x, |x| x == ".vscode", self.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())
+ }
+ pub fn load_lsp(&mut self, lsp_mn: &mut LSPM) {
+ self.language = self
+ .origin
+ .as_deref()
+ .and_then(|o| LOADER.language_for_filename(o));
+ let ws = self
+ .origin
+ .as_deref()
+ .zip(self.language)
+ .and_then(|(p, l)| self.root_for(p, l));
+ let l = ws
+ .as_ref()
+ .zip(self.language)
+ .and_then(|(w, ln)| lsp_mn.load(w, ln, self.vsc()));
+ self.lsp = l;
+ }
+ pub fn new_for(
+ o: Option<PathBuf>,
+ lsp_mn: &mut LSPM,
+ ) -> rootcause::Result<(Self, Freq, KillRing)> {
+ let mut me = Self::default();
if let Some(o) = o.as_deref()
&& let o = std::fs::read_to_string(o).unwrap()
{
@@ -267,8 +314,7 @@ impl Editor {
let n = o.as_deref().and_then(|o| LOADER.language_for_filename(o));
me.language = n;
- let l =
- n.map(|n| LOADER.languages().nth(n.idx()).unwrap().1.config());
+ let l = n.map(|n| LOADER.language(n).config());
me.git_dir = o
.as_deref()
.and_then(|x| {
@@ -277,43 +323,26 @@ impl Editor {
.map(PathBuf::from)
})
.and_then(|x| x.canonicalize().ok());
- let upto = me
- .git_dir
- .clone()
- .or(std::env::current_dir().ok())
- .unwrap_or(PathBuf::from("/home/"));
- let upto = |x: &&Path| x.starts_with(&upto);
- me.workspace = o
- .as_ref()
- .and_then(|x| x.parent())
- .and_then(|x| {
- l.and_then(|l| rooter(&x, |f| l.roots.is_match(f), upto))
- })
- .or(std::env::current_dir().ok())
- .and_then(|x| x.canonicalize().ok());
- let vsc = o
- .as_ref()
- .and_then(|x| x.parent())
- .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());
+ let ws = o.as_deref().zip(n).and_then(|(p, l)| me.root_for(p, l));
let mut loaded_state = false;
let mut freq = default();
let mut kr = default();
- if let Some(ws) = me.workspace.as_deref()
+ if let Some(ws) = ws.as_deref()
&& let h = hash(&ws)
&& let cf = cfgdir().join(format!("{h:x}"))
&& let at = cf.join(SSTORE)
&& at.exists()
{
+ println!("loaded ");
let x = std::fs::read(at)?;
let x = bendncode::from_bytes::<Editor>(&x)?;
+ let gd = me.git_dir.take();
me = x;
+ me.git_dir = gd;
loaded_state = true;
- assert!(me.workspace.is_some());
+ // assert!(me.workspace.is_some());
if let at = cf.join(FSTORE)
&& at.exists()
{
@@ -327,9 +356,10 @@ impl Editor {
kr = bendncode::from_bytes::<KillRing>(&x)?;
}
}
+ println!("set git dir {:?}", &me.git_dir);
me.language = n;
me.origin = o;
- me.tree = me.workspace.as_ref().map(|x| {
+ me.tree = ws.as_ref().map(|x| {
walkdir::WalkDir::new(x)
.into_iter()
.flatten()
@@ -348,30 +378,20 @@ impl Editor {
.collect::<Vec<_>>()
});
- 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
{
- let w = me.workspace.clone();
- let la = me.language;
- let t = me.tree.clone();
if me.files.len() != 0 {
log::error!(
"too many files? {:?}",
me.files.keys().collect::<Vec<_>>()
);
}
- me.open_or_restore(&o, l, la, None, w)?;
- me.git_dir = g;
- me.tree = t;
+ me.open_or_restore(&o, g, None, lsp_mn)?;
me.language = n;
} else {
- me.lsp = l;
+ me.load_lsp(lsp_mn);
me.hist.lc = me.text.cursor.clone();
me.hist.last = me.text.changes.clone();
if let Some((c, origin)) = lsp!(me + p) {
@@ -428,7 +448,8 @@ impl Editor {
self.bar.last_action = "saved".into();
lsp!(self + p).map(|(l, o)| {
if let Ok(fut) = l.format(o)
- && let Ok(Some(v)) = l.runtime.block_on(fut)
+ && let Ok(Ok(Some(v))) =
+ l.by(fut, tokio::time::Duration::from_millis(500))
&& let Err(x) =
self.text.apply_tedits_adjusting(&mut { v })
{
@@ -559,6 +580,7 @@ impl Editor {
&mut self,
x: &Path,
w: Arc<dyn Window>,
+ lsp_mn: &mut LSPM,
) -> rootcause::Result<()> {
let x = x.canonicalize()?.to_path_buf();
if Some(&*x) == self.origin.as_deref() {
@@ -566,38 +588,33 @@ impl Editor {
return Ok(());
}
let r = self.text.r;
- let ws = self.workspace.clone();
- let git_dir = self.workspace.clone();
+ // let ws = self.workspace.clone();
+ let git_dir = self.git_dir.clone();
let tree = self.tree.clone();
- let lsp = self.lsp.take();
- let l = self.language;
+ // let lsp = self.lsp.take();
let mut me = take(self);
let f = take(&mut me.files);
if let Some(x) = me.origin.clone() {
- lsp.as_ref().map(|l| l.0.close(&x));
+ lsp!(me).as_ref().map(|l| l.close(&x));
self.files.insert(x, me);
self.files.extend(f);
// assert!(f.len() == 0);
}
- self.open_or_restore(&x, lsp, l, Some(w), ws)?;
+ self.open_or_restore(&x, git_dir, Some(w), lsp_mn)?;
self.text.r = r;
self.tree = tree;
- self.git_dir = git_dir; // maybe it should change? you know. sometimes?
Ok(())
}
fn restore(
&mut self,
-
- lsp: Option<(
- Arc<Client>,
- std::thread::JoinHandle<()>,
- Option<Sender<Arc<dyn Window>>>,
- )>,
- l: Option<helix_core::Language>,
+ git_dir: Option<PathBuf>,
+ // lsp: Option<(Arc<Client>, Option<Sender<Arc<dyn Window>>>)>,
+ // l: Option<helix_core::Language>,
with: Editor,
+ lsp_mn: &mut LSPM,
) -> rootcause::Result<()> {
let f = take(&mut self.files);
@@ -627,8 +644,9 @@ impl Editor {
take(&mut self.requests);
self.hist.push(&mut self.text)
}
- self.lsp = lsp;
- self.language = l;
+ self.git_dir = git_dir;
+ self.load_lsp(lsp_mn);
+
if let Some((x, origin)) = lsp!(self + p) {
x.open(
&origin,
@@ -641,19 +659,17 @@ impl Editor {
fn open_or_restore(
&mut self,
x: &Path,
- lsp: Option<(
- Arc<Client>,
- std::thread::JoinHandle<()>,
- Option<Sender<Arc<dyn Window>>>,
- )>,
- l: Option<helix_core::Language>,
+ git_dir: Option<PathBuf>,
+ // lsp: Option<(Arc<Client>, Option<Sender<Arc<dyn Window>>>)>,
+ // l: Option<helix_core::Language>,
w: Option<Arc<dyn Window>>,
- ws: Option<PathBuf>,
+ lsp_mn: &mut LSPM,
+ // ws: Option<PathBuf>,
) -> rootcause::Result<()> {
if let Some(x) = self.files.remove(x) {
- self.restore(lsp, l, x)?
+ self.restore(git_dir, x, lsp_mn)?
} else {
- self.workspace = ws;
+ // self.workspace = ws;
self.origin = Some(x.to_path_buf());
let new = std::fs::read_to_string(&x)?;
@@ -663,8 +679,8 @@ impl Editor {
self.text.cursor.just(0, &self.text.rope);
self.bar.last_action = "open".into();
self.mtime = Self::modify(self.origin.as_deref());
- self.lsp = lsp;
- self.language = l;
+ self.git_dir = git_dir;
+ self.load_lsp(lsp_mn);
if let Some((ls, origin)) = lsp!(self + p) {
take(&mut self.requests);
@@ -676,6 +692,24 @@ impl Editor {
.peel()?;
}
}
+
+ fn is_hidden(entry: &walkdir::DirEntry) -> bool {
+ entry
+ .file_name()
+ .to_str()
+ .map(|s| s.starts_with("."))
+ .unwrap_or(false)
+ }
+
+ self.tree = self.git_dir.as_ref().map(|x| {
+ walkdir::WalkDir::new(x)
+ .into_iter()
+ .filter_entry(|e| !is_hidden(e))
+ .flatten()
+ .filter(|x| !x.path().starts_with("."))
+ .map(|x| x.path().to_owned())
+ .collect::<Vec<_>>()
+ });
self.set_title(w);
Ok(())
}
@@ -687,7 +721,7 @@ impl Editor {
}
}
pub fn title(&self) -> Option<String> {
- [self.workspace.as_deref(), self.origin.as_deref()]
+ [self.git_dir.as_deref(), self.origin.as_deref()]
.try_map(|x| {
x.and_then(Path::file_name).and_then(|x| x.to_str())
})
@@ -699,14 +733,14 @@ impl Editor {
fq: &Freq,
kr: &KillRing,
) -> rootcause::Result<()> {
- let ws = self.workspace.clone();
+ // let ws = self.workspace.clone();
let tree = self.tree.clone();
let mtime = self.mtime.clone();
let origin = self.origin.clone();
- if let Some(w) = self.workspace.clone() {
+ if let Some(w) = self.git_dir.clone() {
let mut me = take(self);
- self.workspace = ws;
+ // self.workspace = ws;
self.tree = tree;
self.mtime = mtime;
self.origin = origin;
@@ -735,10 +769,11 @@ impl Editor {
&mut self,
g: impl Into<GoTo<'_>>,
w: Arc<dyn Window>,
+ lsp_mn: &mut LSPM,
) -> rootcause::Result<()> {
let g = g.into();
let f = g.path.canonicalize()?;
- self.open(&f, w.clone())?;
+ self.open(&f, w.clone(), lsp_mn)?;
match g.at {
At::R(r) => {
diff --git a/src/edi/input_handlers/click.rs b/src/edi/input_handlers/click.rs
index d89552f..2fc4db3 100644
--- a/src/edi/input_handlers/click.rs
+++ b/src/edi/input_handlers/click.rs
@@ -11,6 +11,7 @@ impl Editor {
bt: MouseButton,
cursor_position: (usize, usize),
w: Arc<dyn Window>,
+ lsp_mn: &mut LSPM,
) {
_ = self
.requests
@@ -73,7 +74,7 @@ impl Editor {
_ => None,
})
})
- && let Err(e) = self.go(&x, w.clone())
+ && let Err(e) = self.go(&x, w.clone(),lsp_mn)
{
log::error!("gtd: {e}");
}
diff --git a/src/edi/input_handlers/keyboard.rs b/src/edi/input_handlers/keyboard.rs
index ca74611..b1e780d 100644
--- a/src/edi/input_handlers/keyboard.rs
+++ b/src/edi/input_handlers/keyboard.rs
@@ -19,7 +19,7 @@ use winit::window::Window;
use crate::Freq;
use crate::edi::*;
-use crate::lsp::acceptable_duration;
+use crate::lsp::{Require, acceptable_duration};
impl Editor {
pub fn keyboard(
@@ -28,6 +28,7 @@ impl Editor {
window: &mut Arc<dyn Window>,
freq: &mut Freq,
kr: &mut KillRing,
+ lsp_mn: &mut LSPM,
) -> ControlFlow<()> {
let Some(mut o) =
self.transition(Action::K(event.logical_key.clone()))
@@ -68,9 +69,11 @@ impl Editor {
}
Do::SpawnTerminal => {
if let Err(e) = trm::toggle(
- self.workspace
+ &lsp!(self)
.as_deref()
- .unwrap_or(Path::new("/home/os/")),
+ .map_or(Path::new("/home/os/").into(), |x| {
+ x.workspace.uri.to_file_path().unwrap()
+ }),
) {
log::error!("opening terminal failed {e}");
}
@@ -126,9 +129,12 @@ impl Editor {
self.state = State::Command(x);
}
crate::menu::generic::CorA::Accept => {
- if let Err(e) =
- self.handle_command(z, window.clone(), kr)
- {
+ if let Err(e) = self.handle_command(
+ z,
+ window.clone(),
+ kr,
+ lsp_mn,
+ ) {
self.bar.last_action = format!("{e}");
}
}
@@ -227,7 +233,7 @@ impl Editor {
}
Do::SymbolsSelect(x) =>
if let Some(Ok(x)) = x.sel(Some(freq))
- && let Err(e) = self.go(x.at, window.clone())
+ && let Err(e) = self.go(x.at, window.clone(), lsp_mn)
{
log::error!("alas! {e}")
},
@@ -487,7 +493,7 @@ impl Editor {
}
Do::Paste => self.paste(),
Do::OpenFile(x) => {
- _ = self.open(Path::new(&x), window.clone());
+ _ = self.open(Path::new(&x), window.clone(), lsp_mn);
}
Do::StartSearch(x) => {
let s = Regex::new(&x).unwrap();
@@ -548,7 +554,7 @@ impl Editor {
}
Do::Run(x) =>
if let Some((l, ws)) =
- lsp!(self).zip(self.workspace.as_deref())
+ lsp!(self).zip(self.git_dir.as_deref())
{
l.runtime
.block_on(crate::runnables::run(x, ws))
@@ -568,7 +574,7 @@ impl Editor {
}
Do::GTLSelect(x) =>
if let Some(Ok((g, _))) = x.sel(None)
- && let Err(e) = self.go(g, window.clone())
+ && let Err(e) = self.go(g, window.clone(), lsp_mn)
{
eprintln!("go-to-list select fail: {e}");
},
@@ -828,6 +834,9 @@ impl Editor {
pub fn request_code_actions(&mut self) {
lsp!(let lsp, f = self);
+ if lsp.caps().code_action_provider.is_none() {
+ return;
+ }
let r = lsp
.request::<lsp_request!("textDocument/codeAction")>(
&CodeActionParams {
diff --git a/src/edi/lsp.rs b/src/edi/lsp.rs
deleted file mode 100644
index e69de29..0000000
--- a/src/edi/lsp.rs
+++ /dev/null
diff --git a/src/edi/lsp_mn.rs b/src/edi/lsp_mn.rs
index 6c76bdc..0bc7dce 100644
--- a/src/edi/lsp_mn.rs
+++ b/src/edi/lsp_mn.rs
@@ -11,26 +11,44 @@ use tokio::sync::oneshot::Sender;
use tree_house::Language;
use winit::window::Window;
-struct LSP4 {
- four: HashMap<(Language, PathBuf), &'static Client>,
+pub struct LSPM {
+ pub four: HashMap<(Language, PathBuf), LoadedLSP>,
}
-struct Loaded {
- iot: Option<IoThreads>,
-
+pub struct LoadedLSP {
+ pub c: Arc<Client>,
+ pub iot: Option<IoThreads>,
+ pub comms: std::thread::JoinHandle<()>,
+}
+
+impl LSPM {
+ pub fn load(
+ &mut self,
+ workspace: &PathBuf,
+ l: Language,
+ vsc: Option<serde_json::Value>,
+ ) -> Option<(Arc<Client>, Option<Sender<Arc<dyn Window + 'static>>>)>
+ {
+ let e = match self.four.entry((l, workspace.to_owned())) {
+ std::collections::hash_map::Entry::Occupied(x) => {
+ let x = x.get();
+ return Some((x.c.clone(), None));
+ }
+ std::collections::hash_map::Entry::Vacant(e) => e,
+ };
+ let (l, w) = load(workspace, l, vsc)?;
+ let v = e.insert(l);
+ Some((v.c.clone(), Some(w)))
+ }
}
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>>>,
-)> {
+) -> Option<(LoadedLSP, Sender<Arc<dyn Window>>)> {
let l = super::LOADER.language(l).config();
- let (Connection { sender, receiver }, conf,iot) = if l.language_id
+ let (Connection { sender, receiver }, conf, iot) = if l.language_id
== "rust"
{
let (_jh, a) = super::ra::ra(workspace.clone());
@@ -40,7 +58,7 @@ pub fn load(
&super::LOADER.language_server_configs()["rust-analyzer"],
&l.language_servers[0],
),
- None
+ None,
)
} else {
let (mut c, conf) = l
@@ -88,13 +106,5 @@ pub fn load(
conf,
)
.unwrap();
- Some((Arc::new(c), (t2), Some(changed)))
+ Some((LoadedLSP { iot, c: Arc::new(c), comms: t2 }, changed))
}
-
-fn rah() {
-let stdout = 4;
-super let x =(
- &stdout,
-
- );
-} \ No newline at end of file
diff --git a/src/lsp.rs b/src/lsp.rs
index 95ba0a9..b684d85 100644
--- a/src/lsp.rs
+++ b/src/lsp.rs
@@ -60,6 +60,7 @@ pub fn run(
req_rx: _req_rx,
not_rx,
lsp_data: data,
+ workspace: workspace.clone(),
};
let mut opts = init_opts::get(
workspace,
diff --git a/src/lsp/client.rs b/src/lsp/client.rs
index 059e523..a0db994 100644
--- a/src/lsp/client.rs
+++ b/src/lsp/client.rs
@@ -23,7 +23,7 @@ use tokio::sync::oneshot;
use ttools::*;
use crate::lsp::BehaviourAfter::{self, *};
-use crate::lsp::{RequestError, Require, Requiring, Rq};
+use crate::lsp::{RequestError, Require, Requiring, Rq, RqSendError};
use crate::text::cursor::ceach;
use crate::text::{LOADER, RopeExt, SortTedits, TextArea};
#[derive(Debug, Clone)]
@@ -65,11 +65,16 @@ pub struct Client {
&'static LanguageServerConfiguration,
&'static LanguageServerFeatures,
),
+ pub workspace: WorkspaceFolder,
}
impl Drop for Client {
fn drop(&mut self) {
- println!("dropped lsp");
+ _ = self.notify::<Exit>(&());
+ println!(
+ "dropped lsp({}) @ {}",
+ self.lsp_data.1.name, self.workspace.uri
+ );
// panic!("please dont");
}
}
@@ -577,7 +582,7 @@ impl Client {
) -> Result<
impl Future<Output = Result<Vec<Runnable>, RequestError<Runnables>>>
+ use<>,
- SendError<Message>,
+ RqSendError<Runnables>,
> {
self.request::<Runnables>(&RunnablesParams {
text_document: t.tid(),
@@ -597,7 +602,7 @@ impl Client {
RequestError<ChildModules>,
>,
>,
- SendError<Message>,
+ RqSendError<ChildModules>,
> {
self.request::<ChildModules>(&TextDocumentPositionParams {
position: p,
@@ -615,7 +620,7 @@ impl Client {
RequestError<GotoImplementation>,
>,
> + use<>,
- SendError<Message>,
+ RqSendError<GotoImplementation>,
> {
self.request::<GotoImplementation>(&GotoImplementationParams {
text_document_position_params: tdpp,
@@ -635,7 +640,7 @@ impl Client {
RequestError<References>,
>,
> + use<>,
- SendError<Message>,
+ RqSendError<References>,
> {
self.request::<References>(&ReferenceParams {
text_document_position: tdpp,
@@ -664,7 +669,7 @@ impl Client {
RequestError<CallHierarchyPrepare>,
>,
> + use<>,
- SendError<Message>,
+ RqSendError<CallHierarchyPrepare>,
> {
self.request::<CallHierarchyPrepare>(&CallHierarchyPrepareParams {
text_document_position_params: at,
diff --git a/src/lsp/communication.rs b/src/lsp/communication.rs
index 3e5bc3d..2ef150c 100644
--- a/src/lsp/communication.rs
+++ b/src/lsp/communication.rs
@@ -18,7 +18,7 @@ use tokio::time::error::Elapsed;
use winit::window::Window;
use crate::lsp::BehaviourAfter::{self, *};
-use crate::lsp::RequestError;
+use crate::lsp::{RequestError, RqSendError};
pub fn handler(
window_rx: oneshot::Receiver<Arc<dyn Window + 'static>>,
progress: &papaya::HashMap<
@@ -33,6 +33,7 @@ pub fn handler(
) {
let mut map = HashMap::new();
let w = window_rx.blocking_recv().unwrap();
+ println!("got w");
loop {
crossbeam::select! {
recv(req_rx) -> x => match x {
@@ -149,7 +150,12 @@ impl super::Client {
&'me self,
y: &X::Params,
) -> Result<X::Result, RequestError<X>> {
- self.runtime.block_on(self.request_::<X, { Nil }>(y)?.0)
+ self.runtime
+ .block_on(tokio::time::timeout(
+ tokio::time::Duration::from_secs(20),
+ self.request_::<X, { Nil }>(y)?.0,
+ ))
+ .unwrap()
}
pub fn request_by<'me, X: Request>(
&'me self,
@@ -166,6 +172,14 @@ impl super::Client {
))
}
+ pub fn by<T>(
+ &self,
+ x: impl Future<Output = T>,
+ d: tokio::time::Duration,
+ ) -> Result<T, Elapsed> {
+ let _guard = self.runtime.enter();
+ self.runtime.block_on(tokio::time::timeout(d, x))
+ }
pub fn request<'me, X: Request>(
&'me self,
y: &X::Params,
@@ -174,7 +188,7 @@ impl super::Client {
impl Future<Output = Result<X::Result, RequestError<X>>> + use<X>,
i32,
),
- SendError<Message>,
+ RqSendError<X>,
> {
self.request_::<X, { Redraw }>(y)
}
@@ -188,7 +202,7 @@ impl super::Client {
+ use<X, THEN>,
i32,
),
- SendError<Message>,
+ RqSendError<X>,
> {
let id = self.id.fetch_add(1, std::sync::atomic::Ordering::AcqRel);
self.tx.send(Message::Request(LRq {
diff --git a/src/lsp/rq.rs b/src/lsp/rq.rs
index ef1316f..b7e42e0 100644
--- a/src/lsp/rq.rs
+++ b/src/lsp/rq.rs
@@ -12,7 +12,8 @@ use tokio::task;
use tokio_util::task::AbortOnDropHandle;
use crate::lsp::Void;
-
+#[derive(Serialize, Deserialize)]
+pub struct RqSendError<X>(Message, PhantomData<X>);
#[derive(Serialize, Deserialize)]
pub enum RequestError<X> {
Rx(PhantomData<X>),
@@ -50,16 +51,42 @@ impl<X> From<oneshot::error::RecvError> for RequestError<X> {
Self::Rx(PhantomData)
}
}
+impl<X: Request> std::error::Error for RqSendError<X> {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ None
+ }
+}
impl<X: Request> std::error::Error for RequestError<X> {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
None
}
}
+impl<X> From<SendError<Message>> for RqSendError<X> {
+ fn from(x: SendError<Message>) -> Self {
+ Self(x.into_inner(), PhantomData)
+ }
+}
impl<X> From<SendError<Message>> for RequestError<X> {
fn from(x: SendError<Message>) -> Self {
Self::Send(x.into_inner())
}
}
+impl<X> From<RqSendError<X>> for RequestError<X> {
+ fn from(x: RqSendError<X>) -> Self {
+ Self::Send(x.0)
+ }
+}
+
+impl<X: Request> std::fmt::Display for RqSendError<X> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{} failed; couldnt send {:?}", X::METHOD, self.0)
+ }
+}
+impl<X: Request> std::fmt::Debug for RqSendError<X> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self, f)
+ }
+}
impl<X: Request> std::fmt::Display for RequestError<X> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
diff --git a/src/main.rs b/src/main.rs
index 6cd7223..6dfe02b 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -83,6 +83,7 @@ use winit::window::{
};
use crate::edi::Editor;
+use crate::edi::lsp_mn::LSPM;
use crate::edi::st::*;
use crate::lsp::RqS;
use crate::text::{TextArea, col, is_word};
@@ -140,8 +141,10 @@ extern "C" fn sigint(_: i32) {
type FID = u8;
type Freq = FxHashMap<FID, FxHashMap<u64, u16>>;
pub(crate) fn entry(event_loop: EventLoop) {
+ let mut lsp_mn = LSPM { four: default() };
+
unsafe {
- let (ed, freq, kr) = match Editor::new() {
+ let (ed, freq, kr) = match Editor::new(&mut lsp_mn) {
Err(e) => {
eprintln!("failure to launch: {e}");
return;
@@ -225,6 +228,10 @@ pub(crate) fn entry(event_loop: EventLoop) {
.with_event_handler(
move |(window, _context), surface, window_id, event, elwt| {
elwt.set_control_flow(ControlFlow::Wait);
+ if let Some((.., c)) = &mut ed.lsp && let Some(c) = c.take() {
+ c.send(window.clone()).unwrap();
+ }
+ let lsp_mn = &mut lsp_mn;
let (fw, fh) = dsb::dims(&FONT, ppem);
let (c, r) = dsb::fit(
&FONT,
@@ -325,7 +332,7 @@ pub(crate) fn entry(event_loop: EventLoop) {
if button == MouseButton::Left {
unsafe { CLICKING = true };
}
- ed.click(button, cursor_position, window.clone());
+ ed.click(button, cursor_position, window.clone(), lsp_mn);
window.request_redraw();
}
WindowEvent::PointerButton {
@@ -368,7 +375,7 @@ pub(crate) fn entry(event_loop: EventLoop) {
) {
return;
}
- if ed.keyboard(event, window, freq, kr).is_break() {
+ if ed.keyboard(event, window, freq, kr, lsp_mn).is_break() {
elwt.exit();
}
window.request_redraw();
diff --git a/src/rnd.rs b/src/rnd.rs
index 0deea9f..927418e 100644
--- a/src/rnd.rs
+++ b/src/rnd.rs
@@ -385,7 +385,7 @@ pub fn render(
ed.origin
.as_ref()
.map(|x| {
- ed.workspace
+ ed.git_dir
.as_ref()
.and_then(|w| x.strip_prefix(w).ok())
.unwrap_or(&x)
@@ -847,27 +847,27 @@ pub fn render(
);
}
State::Command(x) if x.should_render() => {
- let ws = ed.workspace.as_deref().unwrap();
+ let ws = ed.git_dir.as_deref().unwrap();
let c = x.cells(50, ws, None);
drawb(&c, 50);
}
State::Symbols(Rq { result: Some(x), .. }) => {
- let ws = ed.workspace.as_deref().unwrap();
+ let ws = ed.git_dir.as_deref().unwrap();
let c = x.cells(50, ws, Some(freq));
drawb(&c, 50);
}
State::Runnables(Rq { result: Some(x), .. }) => {
- let ws = ed.workspace.as_deref().unwrap();
+ let ws = ed.git_dir.as_deref().unwrap();
let c = x.cells(50, ws, None);
drawb(&c, 50);
}
State::GoToL(y) => {
- let ws = ed.workspace.as_deref().unwrap();
+ let ws = ed.git_dir.as_deref().unwrap();
let c = y.cells(50, ws, None);
drawb(&c, 50);
}
State::KillRing(y) => {
- let ws = ed.workspace.as_deref().unwrap();
+ let ws = ed.git_dir.as_deref().unwrap();
let c = y.cells(50, ws, None);
drawb(&c, 50);
}