A simple CPU rendered GUI IDE experience.
| -rw-r--r-- | Cargo.toml | 14 | ||||
| -rw-r--r-- | src/edi.rs | 31 | ||||
| -rw-r--r-- | src/edi/input_handlers/keyboard.rs | 11 | ||||
| -rw-r--r-- | src/edi/lsp_impl.rs | 4 | ||||
| -rw-r--r-- | src/edi/lsp_mn.rs | 12 | ||||
| -rw-r--r-- | src/edi/st.rs | 18 | ||||
| -rw-r--r-- | src/hov.rs | 9 | ||||
| -rw-r--r-- | src/lsp.rs | 2 | ||||
| -rw-r--r-- | src/main.rs | 9 | ||||
| -rw-r--r-- | src/menu/generic.rs | 4 | ||||
| -rw-r--r-- | src/rnd.rs | 9 | ||||
| -rw-r--r-- | src/runnables.rs | 4 | ||||
| -rw-r--r-- | src/text.rs | 4 | ||||
| -rw-r--r-- | src/text/hist.rs | 11 |
14 files changed, 106 insertions, 36 deletions
@@ -9,9 +9,9 @@ fimg = { git = "https://git.bendn.org/fimg" } pattypan = { git = "https://git.bendn.org/pattypan" } implicit-fn = "0.1.0" ropey = "1.6.1" -softbuffer = "0.4.8" +softbuffer = { version = "0.4.8", default-features = false, features = ["wayland", "x11"] } swash = "0.2.9" -winit = "0.31.0-beta.2" +winit = { version = "0.31.0-beta.2", default-features = false, features = ["wayland", "x11"] } tree-sitter = "0.25.10" memchr = "2.8.2" @@ -58,7 +58,6 @@ arc-swap = "1.9.1" atools = "0.1.12" swizzle = "0.1.0" walkdir = "2.5.0" -niri = { package = "niri-ipc", version = "25.11.0" } libc = "0.2.186" rustc-hash = "=2.1.1" git2 = "0.20.4" @@ -66,7 +65,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" } + smol_str = "0.3.6" futures = "0.3.32" rootcause = { version = "0.12.1", features = ["compat-anyhow1"] } @@ -78,12 +77,19 @@ annotate-snippets = "0.12.16" toml = "1.1.2" bendncode = { git = "https://git.bendn.org/bendncode" } rfd = "0.17.2" + +[target.'cfg(unix)'.dependencies] +kitty-rc = { version = "0.4.2", git = "https://github.com/bend-n/kitty-rc-rs" } +niri = { package = "niri-ipc", version = "25.11.0" } + [profile.dev.package] rust-analyzer.opt-level = 3 fimg.opt-level = 3 nucleo.opt-level = 3 tree-house.debug-assertions = false + + [profile.release.package.tree-house] debug-assertions = false @@ -9,7 +9,6 @@ use std::time::SystemTime; use Default::default; use ftools::Bind; -use helix_core::syntax::config::FileType; use lsp_types::*; use regex::Regex; use rootcause::report; @@ -34,7 +33,7 @@ use st::*; use crate::bar::Bar; use crate::commands::Cmds; -use crate::edi::lsp_mn::{LSPM, LoadedLSP}; +use crate::edi::lsp_mn::LSPM; use crate::error::WDebug; use crate::gotolist::{At, GoTo}; use crate::hov::{self, HOV_HEIGHT, Hovr, Hovring, Rendered}; @@ -50,7 +49,7 @@ use crate::text::hist::{ClickHistory, Hist}; use crate::text::{LOADER, Mapping, RopeExt, SortTedits, TextArea}; use crate::{ BoolRequest, CDo, CompletionAction, CompletionState, Freq, KillRing, - alt, ctrl, filter, hash, shift, sym, trm, + alt, ctrl, filter, hash, shift, sym, }; impl Debug for Editor { @@ -223,7 +222,9 @@ impl Editor { .pick_folder() }); if let Some(x) = &o { - match std::fs::read_to_string(x) { + match std::fs::read_to_string(x) + .map(|x| x.replace("\r\n", "\n")) + { Ok(_) => {} Err(e) if e.kind() == ErrorKind::IsADirectory @@ -306,7 +307,9 @@ impl Editor { ) -> 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() + && let o = std::fs::read_to_string(o) + .map(|x| x.replace("\r\n", "\n")) + .unwrap() { me.text.insert(&o); me.text.cursor = default(); @@ -397,7 +400,8 @@ impl Editor { if let Some((c, origin)) = lsp!(me + p) { c.open( &origin, - std::fs::read_to_string(&origin)?, + std::fs::read_to_string(&origin) + .map(|x| x.replace("\r\n", "\n"))?, me.language.unwrap(), )?; c.rq_semantic_tokens( @@ -408,7 +412,7 @@ impl Editor { } me.git_dir = g; me.mtime = Self::modify(me.origin.as_deref()); - + me.tree(); // me.hist.last = me.text.clone(); // me.lsp.as_ref().zip(me.origin.as_deref()).map( // |((x, ..), origin)| { @@ -628,6 +632,7 @@ impl Editor { .as_ref() .ok_or(report!("origin missing"))?, ) + .map(|x| x.replace("\r\n", "\n")) .unwrap(), ); @@ -670,7 +675,8 @@ impl Editor { // self.workspace = ws; self.origin = Some(x.to_path_buf()); - let new = std::fs::read_to_string(&x)?; + let new = std::fs::read_to_string(&x) + .map(|x| x.replace("\r\n", "\n"))?; take(&mut self.text); self.text.insert(&new); take(&mut self.text.changes); @@ -691,6 +697,11 @@ impl Editor { } } + self.tree(); + self.set_title(w); + Ok(()) + } + pub fn tree(&mut self) { fn is_hidden(entry: &walkdir::DirEntry) -> bool { entry .file_name() @@ -698,7 +709,6 @@ impl Editor { .map(|s| s.starts_with(".")) .unwrap_or(false) } - self.tree = self.git_dir.as_ref().map(|x| { walkdir::WalkDir::new(x) .into_iter() @@ -708,8 +718,6 @@ impl Editor { .map(|x| x.path().to_owned()) .collect::<Vec<_>>() }); - self.set_title(w); - Ok(()) } pub fn set_title(&self, w: Option<Arc<dyn Window>>) { if let Some(x) = w @@ -807,6 +815,7 @@ fn cfgdir() -> PathBuf { std::env::var("HOME") .map(PathBuf::from) .map(|x| x.join(".config")) + .or(std::env::var("AppData").map(PathBuf::from)) }) .unwrap_or("/tmp/".into()) .join("gracilaria") diff --git a/src/edi/input_handlers/keyboard.rs b/src/edi/input_handlers/keyboard.rs index d91e562..7dadc9b 100644 --- a/src/edi/input_handlers/keyboard.rs +++ b/src/edi/input_handlers/keyboard.rs @@ -67,8 +67,9 @@ impl Editor { self.text.cursor.clear_selections(); change!(self, window.clone()); } + #[cfg(target_family = "unix")] Do::SpawnTerminal => { - if let Err(e) = trm::toggle( + if let Err(e) = crate::trm::toggle( &lsp!(self) .as_deref() .map_or(Path::new("/home/os/").into(), |x| { @@ -78,6 +79,10 @@ impl Editor { log::error!("opening terminal failed {e}"); } } + #[cfg(not(target_family = "unix"))] + Do::SpawnTerminal => { + unimplemented!() + } Do::MatchingBrace => if let Some((l, f)) = lsp!(self + p) { l.matching_brace(f, &mut self.text) @@ -562,6 +567,7 @@ impl Editor { self.text.cursor.add(x, &self.text.rope); }); } + #[cfg(target_family = "unix")] Do::Run(x) => if let Some((l, ws)) = lsp!(self).zip(self.git_dir.as_deref()) @@ -570,6 +576,8 @@ impl Editor { .block_on(crate::runnables::run(x, ws)) .unwrap(); }, + #[cfg(not(target_family = "unix"))] + Do::Run(_) => {} Do::GoToImplementations => { let State::GoToL(x) = &mut self.state else { unreachable!() @@ -891,6 +899,7 @@ impl Editor { self.hist.push_if_changed(&mut self.text); self.text.rope = Rope::from_str( &std::fs::read_to_string(self.origin.as_ref().unwrap()) + .map(|x| x.replace("\r\n", "\n")) .unwrap(), ); diff --git a/src/edi/lsp_impl.rs b/src/edi/lsp_impl.rs index 105595f..269ddb0 100644 --- a/src/edi/lsp_impl.rs +++ b/src/edi/lsp_impl.rs @@ -12,7 +12,6 @@ use crate::edi::lsp; use crate::edi::st::*; use crate::hov::{Hoverable, Hovring}; use crate::lsp::{RequestError, Rq}; -use crate::runnables::Runnables; use crate::sym::GoTo; use crate::{CompletionState, act, sig, sym}; @@ -172,9 +171,10 @@ impl crate::edi::Editor { self.state = State::Default; } } + #[cfg(target_family = "unix")] State::Runnables(x) => { x.poll(|x, ((), old)| { - Some(Runnables { + Some(crate::runnables::Runnables { data: x.ok()?, ..old.unwrap_or_default() }) diff --git a/src/edi/lsp_mn.rs b/src/edi/lsp_mn.rs index 0bc7dce..a505e5c 100644 --- a/src/edi/lsp_mn.rs +++ b/src/edi/lsp_mn.rs @@ -29,6 +29,10 @@ impl LSPM { vsc: Option<serde_json::Value>, ) -> Option<(Arc<Client>, Option<Sender<Arc<dyn Window + 'static>>>)> { + let ra_conn_used = self + .four + .values() + .any(|x| x.c.lsp_data.1.name == "rust-analyzer"); let e = match self.four.entry((l, workspace.to_owned())) { std::collections::hash_map::Entry::Occupied(x) => { let x = x.get(); @@ -36,7 +40,7 @@ impl LSPM { } std::collections::hash_map::Entry::Vacant(e) => e, }; - let (l, w) = load(workspace, l, vsc)?; + let (l, w) = load(workspace, l, vsc, ra_conn_used)?; let v = e.insert(l); Some((v.c.clone(), Some(w))) } @@ -46,11 +50,11 @@ pub fn load( workspace: &PathBuf, l: Language, vsc: Option<serde_json::Value>, + ra_conn_used: bool, ) -> Option<(LoadedLSP, Sender<Arc<dyn Window>>)> { let l = super::LOADER.language(l).config(); - let (Connection { sender, receiver }, conf, iot) = if l.language_id - == "rust" - { + let use_builtin_ra = l.language_id == "rust" && !ra_conn_used; + let (Connection { sender, receiver }, conf, iot) = if use_builtin_ra { let (_jh, a) = super::ra::ra(workspace.clone()); ( a, diff --git a/src/edi/st.rs b/src/edi/st.rs index db98b9a..efc2081 100644 --- a/src/edi/st.rs +++ b/src/edi/st.rs @@ -35,6 +35,11 @@ pub enum LR { Left, Right, } + +#[cfg(target_family = "unix")] +type Run = crate::runnables::Runnables; +#[cfg(not(target_family = "unix"))] +type Run = (); rust_fsm::state_machine! { #[derive(Debug)] pub(crate) State => #[derive(Debug)] pub(crate) Action => #[derive(Debug)] pub(crate) Do @@ -114,21 +119,32 @@ Command(mut t) => K(k) => Command({ if let Some(_) = handle2(&k, &mut t.tedit, N }; t }) [CmdTyped], Command(t) => C(_) => _, Command(t) => K(_) => _, +#[cfg(target_family = "unix")] Runnables(_x) => { + #[cfg(target_family = "unix")] K(Key::Named(Escape)) => Default, }, -Runnables(RqS::<crate::runnables::Runnables, rust_analyzer::lsp::ext::Runnables> => Rq { result: Some(mut x), request }) => { +#[cfg(target_family = "unix")] +Runnables(RqS::<Run, rust_analyzer::lsp::ext::Runnables> => Rq { result: Some(mut x), request }) => { + #[cfg(target_family = "unix")] K(Key::Named(Tab) if shift()) => Runnables({ x.next(); Rq { result: Some(x), request }}), + #[cfg(target_family = "unix")] K(Key::Named(ArrowDown)) => Runnables({ x.next(); Rq { result: Some(x), request }}), + #[cfg(target_family = "unix")] K(Key::Named(ArrowUp | Tab)) => Runnables({ x.back(); Rq { result: Some(x), request }}), + #[cfg(target_family = "unix")] K(Key::Named(Enter) if let Some(Ok(x_)) = x.clone().sel(None)) => Default [Run(Runnable => x_.clone())], + #[cfg(target_family = "unix")] K(k) => Runnables({ if let Some(_) = handle2(&k, &mut x.tedit, None) { x.selection = 0; x.vo = 0; }; Rq { result: Some(x), request } }), }, +#[cfg(target_family = "unix")] Runnables(_x) => { + #[cfg(target_family = "unix")] C(_) => _, + #[cfg(target_family = "unix")] M(_) => _, }, @@ -1,6 +1,5 @@ use std::fmt::Debug; use std::iter::{empty, once, repeat_n}; -use std::os::fd::AsFd; use std::pin::pin; use std::str::FromStr; use std::sync::Arc; @@ -399,7 +398,13 @@ impl DiagnosticHovr { simplify_path(&dawg.replace('\n', "\r\n").replace("⸬", ":")) .bytes() { - t.rx(b, std::fs::File::open("/dev/null").unwrap().as_fd()); + t.rx( + b, + #[cfg(target_family = "unix")] + std::os::fd::AsFd::as_fd( + &std::fs::File::open("/dev/null").unwrap(), + ), + ); } let y_lim = t .cells @@ -49,7 +49,7 @@ pub fn run( progress: Box::leak(Box::new(papaya::HashMap::new())), runtime: tokio::runtime::Builder::new_multi_thread() .enable_time() - .enable_io() + // .enable_io() .worker_threads(3) .thread_name("lsp runtime") .build()?, diff --git a/src/main.rs b/src/main.rs index 7e81e5e..8c617ba 100644 --- a/src/main.rs +++ b/src/main.rs @@ -48,8 +48,10 @@ mod gotolist; mod killring; mod meta; mod rnd; +#[cfg(target_family = "unix")] mod runnables; mod sym; +#[cfg(target_family = "unix")] mod trm; use std::fmt::{Debug, Display}; @@ -182,9 +184,11 @@ pub(crate) fn entry(event_loop: EventLoop) { let app = winit_app::WinitAppBuilder::with_init( move |elwt| { let window = winit_app::make_window(elwt, |x| { + #[cfg(target_family = "unix")] + let x = x.with_platform_attributes( + Box::new(winit::platform::wayland::WindowAttributesWayland::default().with_name("com.bendn.gracilaria", "com.bendn.gracilaria")) + ).with_decorations(false); x.with_title("gracilaria") - .with_platform_attributes(Box::new(winit::platform::wayland::WindowAttributesWayland::default().with_name("com.bendn.gracilaria", "com.bendn.gracilaria"))) - .with_decorations(false) // .with_name("com.bendn.gracilaria", "") // .with_resize_increments(PhysicalSize::new(fw, fh)) .with_window_icon(Some( @@ -196,6 +200,7 @@ pub(crate) fn entry(event_loop: EventLoop) { .unwrap().into() )) }); + if let Some(x) = w.take() { x.send(window.clone()).unwrap(); } diff --git a/src/menu/generic.rs b/src/menu/generic.rs index 2584f9e..da465c5 100644 --- a/src/menu/generic.rs +++ b/src/menu/generic.rs @@ -62,9 +62,7 @@ impl ID for crate::commands::Cmds { impl ID for crate::gotolist::GTL { const ID: u8 = 1; } -impl ID for crate::runnables::Runb { - const ID: u8 = 2; -} +// RunB = 2 impl ID for crate::sym::Symb { const ID: u8 = 3; } @@ -856,6 +856,7 @@ pub fn render( let c = x.cells(50, ws, Some(freq)); drawb(&c, 50); } + #[cfg(target_family = "unix")] State::Runnables(Rq { result: Some(x), .. }) => { let ws = ed.git_dir.as_deref().unwrap(); let c = x.cells(50, ws, None); @@ -1093,7 +1094,13 @@ pub fn simplify_path(x: &str) -> String { static RUST_SRC: LazyLock<Regex> = LazyLock::new(|| { Regex::new(r".rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library").unwrap() }); - let x = x.replace(env!("HOME"), " "); + let x = x.replace( + #[cfg(target_family = "unix")] + env!("HOME"), + #[cfg(target_family = "windows")] + env!("HOMEPATH"), + " ", + ); [(&*RUST_SRC, " "), (&*DEP, " /$name"), (&*DEP2, " /$name")] .into_iter() .fold(x, |acc, (r, repl)| r.replace(&acc, repl).into_owned()) diff --git a/src/runnables.rs b/src/runnables.rs index 287868c..e70aab9 100644 --- a/src/runnables.rs +++ b/src/runnables.rs @@ -191,3 +191,7 @@ pub fn run( } } } + +impl crate::menu::generic::ID for crate::runnables::Runb { + const ID: u8 = 2; +} diff --git a/src/text.rs b/src/text.rs index dac9e52..f3677b0 100644 --- a/src/text.rs +++ b/src/text.rs @@ -804,9 +804,9 @@ impl TextArea { .take(c) .zip(0..) { - if e.c() != '\n' { + if e.c() != '\n' && e.c() != '\r' { cells.get((x + self.ho, y)).unwrap().letter = - Some(e.c()); + Some(if e.c() == '\t' { ' ' } else { e.c() }); let s = &mut cells.get((x + self.ho, y)).unwrap().style; diff --git a/src/text/hist.rs b/src/text/hist.rs index 6edb771..df678d2 100644 --- a/src/text/hist.rs +++ b/src/text/hist.rs @@ -211,14 +211,21 @@ impl Hist { } pub fn undo(&mut self, t: &mut TextArea) -> ropey::Result<Option<()>> { self.push_if_changed(t); - self.undo_() + let r = self + .undo_() .map(|x| { let r = x.apply(t, false); self.lc = t.cursor.clone(); self.last = t.changes.clone(); r }) - .transpose() + .transpose(); + let l = t.len_chars(); + t.cursor + .inner + .iter_mut() + .for_each(|x| x.position = x.position.max(l)); + r } pub fn redo(&mut self, t: &mut TextArea) -> ropey::Result<Option<()>> { self.redo_() |