A simple CPU rendered GUI IDE experience.
| -rw-r--r-- | Cargo.toml | 3 | ||||
| -rw-r--r-- | src/commands.rs | 4 | ||||
| -rw-r--r-- | src/edi.rs | 8 | ||||
| -rw-r--r-- | src/edi/st.rs | 4 | ||||
| -rw-r--r-- | src/lsp.rs | 4 | ||||
| -rw-r--r-- | src/main.rs | 9 | ||||
| -rw-r--r-- | src/runnables.rs | 59 | ||||
| -rw-r--r-- | src/trm.rs | 140 |
8 files changed, 172 insertions, 59 deletions
@@ -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!(), @@ -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; @@ -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:?}") + } + } +} @@ -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)?; }; } |