A simple CPU rendered GUI IDE experience.
saving
bendn 6 weeks ago
parent 36e03ea · commit 5164319
-rw-r--r--Cargo.toml1
-rw-r--r--src/com.rs3
-rw-r--r--src/edi.rs57
-rw-r--r--src/edi/st.rs3
-rw-r--r--src/hov.rs3
-rw-r--r--src/lsp.rs12
-rw-r--r--src/main.rs13
-rw-r--r--src/text.rs1
8 files changed, 81 insertions, 12 deletions
diff --git a/Cargo.toml b/Cargo.toml
index cd3dcb1..6b8dd49 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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
diff --git a/src/com.rs b/src/com.rs
index 711591a..ef859d9 100644
--- a/src/com.rs
+++ b/src/com.rs
@@ -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,
diff --git a/src/edi.rs b/src/edi.rs
index 52f80cf..e762c77 100644
--- a/src/edi.rs
+++ b/src/edi.rs
@@ -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))],
diff --git a/src/hov.rs b/src/hov.rs
index ce9c510..3791ffd 100644
--- a/src/hov.rs
+++ b/src/hov.rs
@@ -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,
diff --git a/src/lsp.rs b/src/lsp.rs
index 46c7633..e0c6d9b 100644
--- a/src/lsp.rs
+++ b/src/lsp.rs
@@ -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,