A simple CPU rendered GUI IDE experience.
-rw-r--r--Cargo.toml3
-rw-r--r--src/commands.rs4
-rw-r--r--src/edi.rs8
-rw-r--r--src/edi/st.rs4
-rw-r--r--src/lsp.rs4
-rw-r--r--src/main.rs9
-rw-r--r--src/runnables.rs59
-rw-r--r--src/trm.rs140
8 files changed, 172 insertions, 59 deletions
diff --git a/Cargo.toml b/Cargo.toml
index b59988a..05b8b15 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -44,7 +44,7 @@ test-log = "0.2.18"
env_logger = "0.11.8"
url = "2.5.7"
anyhow = "1.0.100"
-tokio = { version = "1.47.1", features = ["rt-multi-thread", "sync"] }
+tokio = { version = "1.47.1", features = ["rt-multi-thread", "sync", "time"] }
regex-cursor = "0.1.5"
papaya = "0.2.3"
markdown = "1.0.0"
@@ -67,6 +67,7 @@ imara-diff = "0.2.0"
vecto = "0.1.1"
rangemap = { version = "1.7.1", features = ["const_fn", "nightly", "serde1"] }
itern = "0.1.1"
+kitty-rc = { version = "0.4.2", git = "https://github.com/bend-n/kitty-rc-rs" }
[profile.dev.package]
rust-analyzer.opt-level = 3
diff --git a/src/commands.rs b/src/commands.rs
index 31e7102..ab398dc 100644
--- a/src/commands.rs
+++ b/src/commands.rs
@@ -13,7 +13,7 @@ use rust_analyzer::lsp::ext::*;
use crate::FG;
use crate::edi::{Editor, lsp_m};
-use crate::lsp::{Anonymize, PathURI, Rq};
+use crate::lsp::{PathURI, Rq};
use crate::menu::charc;
use crate::menu::generic::{GenericMenu, MenuData};
use crate::text::{RopeExt, SortTedits, col, color_};
@@ -266,7 +266,7 @@ impl Editor {
Cmd::RARunnables => {
let p = self.text.to_l_position(*self.text.cursor.first());
let o = o.to_owned();
- let x = l.runtime.spawn(l.runnables(&o, None)?);
+ let x = l.runtime.spawn(l.runnables(&o, p)?);
self.state = crate::edi::st::State::Runnables(Rq::new(x));
}
_ => unimplemented!(),
diff --git a/src/edi.rs b/src/edi.rs
index 7594977..8421d96 100644
--- a/src/edi.rs
+++ b/src/edi.rs
@@ -1736,6 +1736,14 @@ impl Editor {
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();
+ },
None => {}
}
ControlFlow::Continue(())
diff --git a/src/edi/st.rs b/src/edi/st.rs
index a8f5b0a..5c423e9 100644
--- a/src/edi/st.rs
+++ b/src/edi/st.rs
@@ -1,9 +1,10 @@
-#![allow(unused_parens, unused_variables, dead_code)]
+#![allow(dead_code, unused)]
use Default::default;
use NamedKey::*;
use lsp_types::*;
use regex::Regex;
+use rust_analyzer::lsp::ext::Runnable;
use winit::event::MouseButton;
use winit::keyboard::{Key, NamedKey, SmolStr};
@@ -87,6 +88,7 @@ Runnables(RqS::<crate::runnables::Runnables, rust_analyzer::lsp::ext::Runnables>
K(Key::Named(Tab) if shift()) => Runnables({ x.next(); Rq { result: Some(x), request }}),
K(Key::Named(ArrowDown)) => Runnables({ x.next(); Rq { result: Some(x), request }}),
K(Key::Named(ArrowUp | Tab)) => Runnables({ x.back(); Rq { result: Some(x), request }}),
+ K(Key::Named(Enter)) => Default [Run(Runnable => x.sel().clone())],
K(k) => Runnables({
if let Some(_) = handle2(&k, &mut x.tedit, None) {
x.selection = 0; x.vo = 0;
diff --git a/src/lsp.rs b/src/lsp.rs
index 5533f07..1c88d04 100644
--- a/src/lsp.rs
+++ b/src/lsp.rs
@@ -651,7 +651,9 @@ pub fn run(
tx,
progress: Box::leak(Box::new(papaya::HashMap::new())),
runtime: tokio::runtime::Builder::new_multi_thread()
- .worker_threads(2)
+ .enable_time()
+ .enable_io()
+ .worker_threads(3)
.thread_name("lsp runtime")
.build()
.unwrap(),
diff --git a/src/main.rs b/src/main.rs
index 7327c59..9325aca 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,4 +1,5 @@
#![feature(
+ random,
btree_set_entry,
associated_type_defaults,
array_try_map,
@@ -435,12 +436,12 @@ fn history_test() {
h.push(&mut t);
t.insert(" test");
h.push(&mut t);
- h.undo(&mut t);
- h.redo(&mut t);
- h.undo(&mut t);
+ h.undo(&mut t).unwrap();
+ h.redo(&mut t).unwrap();
+ h.undo(&mut t).unwrap();
t.insert(" good");
h.push(&mut t);
- h.undo(&mut t);
+ h.undo(&mut t).unwrap();
assert_eq!(t.rope.to_string(), "echo");
}
pub trait M<T> {
diff --git a/src/runnables.rs b/src/runnables.rs
index 3c1b261..a373881 100644
--- a/src/runnables.rs
+++ b/src/runnables.rs
@@ -1,14 +1,18 @@
-use std::iter::{empty, repeat};
+use std::iter::{chain, empty, repeat};
use Default::default;
+use Into::into;
use dsb::Cell;
use dsb::cell::Style;
+use itertools::Itertools;
+use kitty_rc::LaunchCommand;
use lsp_types::LocationLink;
-use rust_analyzer::lsp::ext::{Runnable, RunnableKind};
+use rust_analyzer::lsp::ext::{Runnable, RunnableArgs, RunnableKind};
use crate::menu::generic::{GenericMenu, MenuData};
use crate::menu::{Key, charc};
use crate::text::{col, color_, set_a};
+use crate::trm;
pub enum Runb {}
impl MenuData for Runb {
@@ -137,3 +141,54 @@ impl<'a> Key<'a> for &'a Runnable {
&self.label
}
}
+
+pub fn run(
+ run: Runnable,
+ ws: &std::path::Path,
+) -> impl Future<Output = Result<(), kitty_rc::KittyError>> {
+ match run.args {
+ RunnableArgs::Cargo(x) => {
+ // let mut a = x.cargo_args;
+ let a = if !x.executable_args.is_empty() {
+ [x.cargo_args, vec!["--".into()], x.executable_args]
+ .concat()
+ } else {
+ x.cargo_args
+ };
+ let x = LaunchCommand::new()
+ .args([
+ "bash",
+ "-c",
+ &format!(
+ "{}; exec xonsh",
+ chain(
+ [x.override_cargo.unwrap_or("cargo".into())],
+ a
+ )
+ .join(" ")
+ ),
+ ])
+ .window_type("tab")
+ .tab_title(run.label)
+ // .keep_focus(true)
+ .cwd(
+ x.workspace_root
+ .as_ref()
+ .map(|x| x.as_str())
+ .unwrap_or("."),
+ )
+ .env(serde_json::Map::from_iter(
+ x.environment
+ .into_iter()
+ .chain([["RUST_BACKTRACE", "short"]
+ .map(into)
+ .into()])
+ .map(|(x, y)| (x, serde_json::Value::from(y))),
+ ));
+ trm::launch(x, ws)
+ }
+ RunnableArgs::Shell(x) => {
+ todo!("{x:?}")
+ }
+ }
+}
diff --git a/src/trm.rs b/src/trm.rs
index 36c91e1..8abaab2 100644
--- a/src/trm.rs
+++ b/src/trm.rs
@@ -1,66 +1,110 @@
use std::path::Path;
-use std::sync::atomic::AtomicU64;
use std::sync::atomic::Ordering::Relaxed;
+use std::sync::atomic::{AtomicU32, AtomicU64};
use std::time::Duration;
-use niri::ColumnDisplay::Normal;
+use kitty_rc::{KittyError, LaunchCommand};
+use niri::socket::Socket;
use niri::{Action, Request, Response};
static LAST: AtomicU64 = AtomicU64::new(!0);
+static KITTY_SOCK: AtomicU32 = AtomicU32::new(!0);
+
+pub fn is_running(niri: &mut Socket) -> std::io::Result<bool> {
+ let l = LAST.load(Relaxed);
+ if l != !0 {
+ let Ok(Response::Windows(x)) = niri.send(Request::Windows)? else {
+ unreachable!()
+ };
+ if x.iter().any(|x| x.id == l) {
+ return Ok(true);
+ }
+ // it died :(
+ }
+ Ok(false)
+}
+
+pub async fn launch(
+ x: LaunchCommand,
+ at: &Path,
+) -> Result<(), KittyError> {
+ let mut niri = niri::socket::Socket::connect()?;
+ if !is_running(&mut niri)? {
+ runk(&mut niri, at)?;
+ }
+ let mut k = kitty_rc::KittyBuilder::new()
+ .socket_path(format!(
+ "/tmp/kitty-{:x}.sock",
+ KITTY_SOCK.load(Relaxed)
+ ))
+ .connect()
+ .await?;
+
+ k.execute(&dbg!(x.build()?)).await?;
+ Ok(())
+}
+
+pub fn runk(niri: &mut Socket, at: &Path) -> std::io::Result<()> {
+ let n: u32 = std::random::random(..);
+ _ = niri.send(Request::Action(Action::Spawn {
+ command: [
+ "kitty",
+ "--listen-on",
+ &format!("unix:/tmp/kitty-{n:x}.sock"),
+ "-o",
+ "allow_remote_control=yes",
+ "--class",
+ "gratty",
+ at.to_str().unwrap(),
+ ]
+ .map(String::from)
+ .to_vec(),
+ }))?;
+
+ std::thread::sleep(Duration::from_millis(500));
+ _ = niri.send(Request::Action(Action::ConsumeOrExpelWindowLeft {
+ id: None,
+ }))?;
+ _ = niri.send(Request::Action(Action::SetWindowHeight {
+ id: None,
+ change: niri::SizeChange::SetFixed(400),
+ }))?;
+ let Ok(Ok(Response::FocusedWindow(Some(ot)))) =
+ niri.send(Request::FocusedWindow)
+ else {
+ unreachable!()
+ };
+ KITTY_SOCK.store(n, Relaxed);
+ LAST.store(ot.id, Relaxed);
+ Ok(())
+}
pub fn toggle(at: &Path) {
_ = try bikeshed anyhow::Result<()> {
let l = LAST.load(Relaxed);
let mut niri = niri::socket::Socket::connect()?;
+ if is_running(&mut niri)? {
+ _ =
+ niri.send(Request::Action(Action::FocusWindow { id: l }))?;
+
+ // std::thread::sleep(Duration::from_millis(500));
+ // let Ok(Ok(Response::FocusedWindow(Some(x)))) = niri.send(Request::FocusedWindow) else { unreachable!() };
+ // dbg!(&x);
+ // if x.layout.window_size.1 < 200 {
+ _ = niri.send(Request::Action(Action::SetColumnDisplay {
+ display: niri::ColumnDisplay::Normal,
+ }))?;
+ _ = niri.send(Request::Action(Action::SetWindowHeight {
+ id: Some(l),
+ change: niri::SizeChange::SetFixed(400),
+ }))?;
+ // }
+ return;
+ }
// let Ok(Ok(Response::FocusedWindow(Some(focused)))) =
// niri.send(Request::FocusedWindow)
// else {
// unreachable!()
// };
- if l != !0 {
- let Ok(Ok(Response::Windows(x))) = niri.send(Request::Windows)
- else {
- unreachable!()
- };
- _ = niri.send(Request::Action(Action::SetColumnDisplay {
- display: Normal,
- }))?;
- if x.iter().any(|x| x.id == l) {
- _ = niri.send(Request::Action(Action::FocusWindow {
- id: l,
- }))?;
-
- // std::thread::sleep(Duration::from_millis(500));
- // let Ok(Ok(Response::FocusedWindow(Some(x)))) = niri.send(Request::FocusedWindow) else { unreachable!() };
- // dbg!(&x);
- // if x.layout.window_size.1 < 200 {
- _ =
- niri.send(Request::Action(Action::SetWindowHeight {
- id: Some(l),
- change: niri::SizeChange::SetFixed(400),
- }))?;
- // }
- return;
- }
- // it died :(
- }
- _ = niri.send(Request::Action(Action::Spawn {
- command: ["kitty", "--class", "gratty", at.to_str().unwrap()]
- .map(String::from)
- .to_vec(),
- }))?;
- std::thread::sleep(Duration::from_millis(500));
- _ = niri.send(Request::Action(
- Action::ConsumeOrExpelWindowLeft { id: None },
- ))?;
- _ = niri.send(Request::Action(Action::SetWindowHeight {
- id: None,
- change: niri::SizeChange::SetFixed(400),
- }))?;
- let Ok(Ok(Response::FocusedWindow(Some(ot)))) =
- niri.send(Request::FocusedWindow)
- else {
- unreachable!()
- };
- LAST.store(ot.id, Relaxed);
+ runk(&mut niri, at)?;
};
}