A simple CPU rendered GUI IDE experience.
saving
| -rw-r--r-- | Cargo.toml | 1 | ||||
| -rw-r--r-- | src/com.rs | 3 | ||||
| -rw-r--r-- | src/edi.rs | 57 | ||||
| -rw-r--r-- | src/edi/st.rs | 3 | ||||
| -rw-r--r-- | src/hov.rs | 3 | ||||
| -rw-r--r-- | src/lsp.rs | 12 | ||||
| -rw-r--r-- | src/main.rs | 13 | ||||
| -rw-r--r-- | src/text.rs | 1 |
8 files changed, 81 insertions, 12 deletions
@@ -65,6 +65,7 @@ walkdir = "2.5.0" niri = { package = "niri-ipc", version = "25.11.0" } libc = "0.2.180" serde_bencode = "0.2.4" +rustc-hash = "=2.1.1" [profile.dev.package] rust-analyzer.opt-level = 3 @@ -8,11 +8,12 @@ use dsb::Cell; use dsb::cell::Style; use itertools::Itertools; use lsp_types::*; +use serde::{Deserialize, Serialize}; use crate::FG; use crate::text::{col, color_, set_a}; -#[derive(Debug)] +#[derive(Debug, Serialize, Deserialize)] pub struct Complete { pub r: CompletionResponse, pub start: usize, @@ -14,6 +14,7 @@ use lsp_types::*; use regex::Regex; use ropey::Rope; use rust_fsm::StateMachine; +use serde_derive::{Deserialize, Serialize}; use tokio::sync::oneshot::Sender; use tokio::task::spawn_blocking; use tokio_util::task::AbortOnDropHandle as DropH; @@ -33,7 +34,37 @@ use crate::{ BoolRequest, CDo, ClickHistory, CompletionAction, CompletionState, Hist, act, alt, ctrl, filter, shift, sig, sym, trm, }; -#[derive(Default, Debug)] +pub fn serialize_tokens<S: serde::Serializer>( + s: &Rq< + Box<[SemanticToken]>, + Box<[SemanticToken]>, + (), + RequestError<SemanticTokensFullRequest>, + >, + ser: S, +) -> Result<S::Ok, S::Error> { + SemanticToken::serialize_tokens_opt( + &s.result.clone().map(|x| x.to_vec()), + ser, + ) +} + +pub fn deserialize_tokens<'de, D: serde::Deserializer<'de>>( + ser: D, +) -> Result< + Rq< + Box<[SemanticToken]>, + Box<[SemanticToken]>, + (), + RequestError<SemanticTokensFullRequest>, + >, + D::Error, +> { + SemanticToken::deserialize_tokens_opt(ser) + .map(|x| Rq { result: x.map(Into::into), request: None }) +} + +#[derive(Default, Debug, Serialize, Deserialize)] pub struct Requests { pub hovering: Rq<Hovr, Option<Hovr>, (usize, usize), anyhow::Error>, pub document_highlights: Rq< @@ -49,6 +80,8 @@ pub struct Requests { (), RequestError<SignatureHelpRequest>, >, // vo, lines + #[serde(serialize_with = "serialize_tokens")] + #[serde(deserialize_with = "deserialize_tokens")] pub semantic_tokens: Rq< Box<[SemanticToken]>, Box<[SemanticToken]>, @@ -1362,8 +1395,26 @@ impl Editor { } Ok(()) } - pub fn store(&mut self) { - // serde_bencode::to_bytes(self); + pub fn store(&mut self) -> anyhow::Result<()> { + if let Some(w) = &self.workspace { + let hash = crate::hash(&w); + let cfgdir = std::env::var("XDG_CONFIG_HOME") + .map(PathBuf::from) + .or_else(|_| { + std::env::var("HOME") + .map(PathBuf::from) + .map(|x| x.join(".config")) + }) + .unwrap_or("/tmp/".into()); + + let p = cfgdir.join("gracilaria").join(format!("{hash:x}")); + std::fs::create_dir_all(&p)?; + std::fs::write( + p.join("state.torrent"), + serde_bencode::to_bytes(self)?, + )?; + } + Ok(()) } } use NamedKey::*; diff --git a/src/edi/st.rs b/src/edi/st.rs index 65be1d9..d00d539 100644 --- a/src/edi/st.rs +++ b/src/edi/st.rs @@ -21,7 +21,7 @@ impl Default for State { } rust_fsm::state_machine! { #[derive(Debug)] -pub(crate) State => Action => Do +pub(crate) State => #[derive(Debug)] pub(crate) Action => #[derive(Debug)] pub(crate) Do Dead => K(Key => _) => Dead, Default => { @@ -103,6 +103,7 @@ Procure((t, InputRequest::Search)) => K(Key::Named(Enter)) => Default [StartSear Procure((t, InputRequest::SaveFile)) => K(Key::Named(Enter)) => Default [SaveTo(String => t.rope.to_string())], Procure((t, InputRequest::OpenFile)) => K(Key::Named(Enter)) => Default [OpenFile(String => t.rope.to_string())], Procure((t, a)) => K(k) => Procure((handle(k, t), a)), +Procure((t, a)) => C(_) => Procure((t, a)), RequestBoolean(t) => { K(Key::Character(x) if x == "y") => Default [Boolean((BoolRequest, bool) => (t, true))], K(Key::Character(x) if x == "n") => Default [Boolean((t, false))], @@ -8,6 +8,7 @@ use dsb::cell::Style; use itertools::Itertools; use markdown::mdast::{self, Node}; use ropey::Rope; +use serde_derive::{Deserialize, Serialize}; const D: Cell = Cell { letter: None, style: Style::new(FG, BG) }; use crate::{FG, text}; @@ -302,7 +303,7 @@ fn t() { println!("{:?}", now.elapsed()); x.as_ref().save("x"); } -#[derive(Debug)] +#[derive(Debug, Serialize, Deserialize)] pub struct Hovr { pub(crate) span: Option<[(VisualX, usize); 2]>, pub(crate) item: crate::text::CellBuffer, @@ -24,6 +24,7 @@ use lsp_server::{ use lsp_types::notification::*; use lsp_types::request::*; use lsp_types::*; +use serde::{Deserialize, Serialize}; use serde_json::json; use tokio::sync::oneshot; use tokio_util::task::AbortOnDropHandle; @@ -51,9 +52,10 @@ impl Drop for Client { panic!("please dont") } } +#[derive(Serialize, Deserialize)] pub enum RequestError<X> { Rx(PhantomData<X>), - Failure(Re, Backtrace), + Failure(Re, #[serde(skip)] Option<Backtrace>), Cancelled(Re, DiagnosticServerCancellationData), } // impl<X> Debug for RequestError<X> {} @@ -135,7 +137,7 @@ impl Client { ); Err(RequestError::Cancelled(x, e.expect("lsp??"))) } else { - Err(RequestError::Failure(x, Backtrace::capture())) + Err(RequestError::Failure(x, Some(Backtrace::capture()))) } } else { Ok(serde_json::from_value::<X::Result>( @@ -1085,9 +1087,13 @@ impl<R: Request> std::fmt::Debug for RequestError<R> { } } -#[derive(Debug)] +fn none<T>() ->Option<T> { + None +} +#[derive(Debug, serde_derive::Serialize, serde_derive::Deserialize)] pub struct Rq<T, R, D = (), E = RequestError<R>> { pub result: Option<T>, + #[serde(skip, default = "none")] pub request: Option<(AbortOnDropHandle<Result<R, E>>, D)>, } pub type RqS<T, R: Request, D = ()> = Rq<T, R::Result, D, RequestError<R>>; diff --git a/src/main.rs b/src/main.rs index 8130ba2..7adae38 100644 --- a/src/main.rs +++ b/src/main.rs @@ -41,6 +41,7 @@ mod sym; mod trm; use std::fmt::{Debug, Display}; +use std::hash::Hash; use std::mem::MaybeUninit; use std::num::NonZeroU32; use std::sync::LazyLock; @@ -223,9 +224,10 @@ const BORDER: [u8; 3] = col!("#ffffff"); static mut __ED: MaybeUninit<Editor> = MaybeUninit::uninit(); extern "C" fn cleanup() { - unsafe { __ED.assume_init_mut().store() }; + unsafe { __ED.assume_init_mut().store().unwrap() }; } extern "C" fn sigint(_: i32) { + cleanup(); std::process::exit(12); } @@ -551,8 +553,8 @@ impl<T> M<T> for Option<T> { } rust_fsm::state_machine! { - #[derive(Debug)] - pub(crate) CompletionState => CompletionAction<'i> => CDo + #[derive(Debug,Serialize,Deserialize)] + pub(crate) CompletionState => #[derive(Debug)] pub(crate) CompletionAction<'i> => pub(crate) CDo None => Click => None, None => K(Key<&'i str> => Key::Character(k @ ("." | ":"))) => Complete( RqS<Complete, lsp_types::request::Completion, usize> => default() @@ -599,3 +601,8 @@ fn filter(text: &TextArea) -> String { .collect::<String>() } } + +pub fn hash(x: &impl Hash) -> u64 { + use std::hash::BuildHasher; + rustc_hash::FxBuildHasher::default().hash_one(x) +} diff --git a/src/text.rs b/src/text.rs index 93205f9..acfca4e 100644 --- a/src/text.rs +++ b/src/text.rs @@ -297,6 +297,7 @@ pub struct Mark { } const INLAY: u8 = 0; +#[derive(Serialize, Deserialize)] pub struct CellBuffer { pub c: usize, pub vo: usize, |