A simple CPU rendered GUI IDE experience.
stand-still load
bendn 14 hours ago
parent 87ecb19 · commit 576f932
-rw-r--r--Cargo.toml1
-rw-r--r--src/complete.rs2
-rw-r--r--src/edi.rs161
-rw-r--r--src/edi/lsp_impl.rs37
4 files changed, 145 insertions, 56 deletions
diff --git a/Cargo.toml b/Cargo.toml
index d4fa4d2..1d1b828 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -89,6 +89,7 @@ debug-assertions = false
[profile.release.package]
fimg.debug-assertions = true
rust-analyzer.debug-assertions = false
+hir-ty.debug-assertions = false
[profile.release]
debug = 2
diff --git a/src/complete.rs b/src/complete.rs
index 81c9c2f..bdc5866 100644
--- a/src/complete.rs
+++ b/src/complete.rs
@@ -230,7 +230,7 @@ impl Editor {
..
} = sel.clone()
else {
- panic!()
+ return;
};
match insert_text_format {
Some(InsertTextFormat::SNIPPET) => {
diff --git a/src/edi.rs b/src/edi.rs
index f2ef7b0..75b3e84 100644
--- a/src/edi.rs
+++ b/src/edi.rs
@@ -1,7 +1,7 @@
use std::collections::HashMap;
use std::ffi::OsString;
use std::fmt::Debug;
-use std::io::BufReader;
+use std::io::{BufReader, ErrorKind};
use std::mem::take;
use std::path::{Path, PathBuf};
use std::process::Stdio;
@@ -67,7 +67,13 @@ impl Debug for Editor {
.finish()
}
}
-
+#[derive(
+ Default, serde_derive::Serialize, serde_derive::Deserialize, Debug,
+)]
+pub struct Edithin {
+ pub files: HashMap<PathBuf, Edithin>,
+ pub mtime: Option<std::time::SystemTime>,
+}
#[derive(Default, serde_derive::Serialize, serde_derive::Deserialize)]
pub struct Editor {
pub files: HashMap<PathBuf, Editor>,
@@ -175,38 +181,82 @@ pub(crate) use change;
fn rooter(
x: &Path,
mut search: impl FnMut(OsString) -> bool + Clone,
+ whilst: impl for<'a> FnMut(&&'a Path) -> bool + Clone,
) -> Option<PathBuf> {
for f in std::fs::read_dir(&x).ok()?.filter_map(Result::ok) {
+ println!("{f:?}");
if search(f.file_name()) {
return Some(f.path().with_file_name("").to_path_buf());
}
}
- x.parent().and_then(rooter.rbind(search))
+ x.parent()
+ .filter(whilst.clone())
+ .and_then(rooter.rbind(whilst).rbind(search))
}
impl Editor {
pub fn new() -> rootcause::Result<(Self, Freq)> {
let mut me = Self::default();
- let o = std::env::args()
+ let mut o = std::env::args()
.nth(1)
.and_then(|x| PathBuf::try_from(x).ok())
.and_then(|x| x.canonicalize().ok());
- if let Some(x) = std::env::args().nth(1) {
- me.text.insert(&std::fs::read_to_string(x)?);
- me.text.cursor = default();
+ if let Some(x) = &o {
+ match std::fs::read_to_string(x) {
+ Ok(x) => {
+ me.text.insert(&x);
+ me.text.cursor = default();
+ }
+ Err(e)
+ if e.kind() == ErrorKind::IsADirectory
+ && let h = hash(&x)
+ && let cf = cfgdir().join(format!("{h:x}"))
+ && let at = cf.join(SSTORE)
+ && at.exists() =>
+ {
+ let x = std::fs::read(at)?;
+ let x = bendncode::from_bytes::<Edithin>(&x)?;
+ o = Some(
+ x.files
+ .iter()
+ .max_by_key(|(_, x)| x.mtime)
+ .map(ttools::fst)
+ .expect("file")
+ .clone(),
+ );
+ }
+ Err(e) => {
+ eprintln!("path could not be opened: {e}");
+ std::process::exit(5);
+ }
+ }
};
let n = o.as_deref().and_then(|o| LOADER.language_for_filename(o));
me.language = n;
let l =
n.map(|n| LOADER.languages().nth(n.idx()).unwrap().1.config());
+ me.git_dir = o
+ .as_deref()
+ .and_then(|x| {
+ x.ancestors()
+ .find(|x| x.join(".git").exists())
+ .map(PathBuf::from)
+ })
+ .and_then(|x| x.canonicalize().ok());
+ let upto = me
+ .git_dir
+ .clone()
+ .or(std::env::current_dir().ok())
+ .unwrap_or(PathBuf::from("/home/"));
+ let upto = |x: &&Path| x.starts_with(&upto);
me.workspace = o
.as_ref()
.and_then(|x| x.parent())
.and_then(|x| {
- l.and_then(|l| rooter(&x, |f| l.roots.is_match(f)))
+ l.and_then(|l| rooter(&x, |f| l.roots.is_match(f), upto))
})
.or(std::env::current_dir().ok())
.and_then(|x| x.canonicalize().ok());
@@ -214,7 +264,7 @@ impl Editor {
let vsc = o
.as_ref()
.and_then(|x| x.parent())
- .and_then(|x| rooter(&x, |x| x == ".vscode"))
+ .and_then(|x| rooter(&x, |x| x == ".vscode", upto))
.map(|x| (x.clone(), x.join(".vscode").join("settings.json")))
.filter(|x| x.1.exists())
.and_then(|(ws, x)| (vsc_settings::load(&x, &ws)).ok());
@@ -240,11 +290,6 @@ impl Editor {
}
}
me.language = n;
- me.git_dir = me
- .workspace
- .as_deref()
- .and_then(|x| rooter(&x, |x| x == ".git"))
- .and_then(|x| x.canonicalize().ok());
me.origin = o;
me.tree = me.workspace.as_ref().map(|x| {
walkdir::WalkDir::new(x)
@@ -542,6 +587,56 @@ impl Editor {
Ok(())
}
+ fn restore(
+ &mut self,
+
+ lsp: Option<(
+ &'static Client,
+ std::thread::JoinHandle<()>,
+ Option<Sender<Arc<dyn Window>>>,
+ )>,
+ l: Option<helix_core::Language>,
+ with: Editor,
+ ) -> rootcause::Result<()> {
+ let f = take(&mut self.files);
+
+ *self = with;
+ assert!(self.files.len() == 0);
+ self.files = f;
+ self.bar.last_action = "restored".into();
+ if self.mtime != Self::modify(self.origin.as_deref()) {
+ self.hist.push_if_changed(&mut self.text);
+ self.text.rope = Rope::from_str(
+ &std::fs::read_to_string(
+ self.origin
+ .as_ref()
+ .ok_or(report!("origin missing"))?,
+ )
+ .unwrap(),
+ );
+
+ self.text.cursor.first_mut().position = self
+ .text
+ .cursor
+ .first()
+ .position
+ .min(self.text.rope.len_chars());
+ self.mtime = Self::modify(self.origin.as_deref());
+ self.bar.last_action = "restored -> reloaded".into();
+ take(&mut self.requests);
+ self.hist.push(&mut self.text)
+ }
+ self.lsp = lsp;
+ self.language = l;
+ if let Some((x, origin)) = lsp!(self + p) {
+ x.open(
+ &origin,
+ self.text.rope.to_string(),
+ self.language.unwrap(),
+ )?;
+ }
+ Ok(())
+ }
fn open_or_restore(
&mut self,
x: &Path,
@@ -555,43 +650,7 @@ impl Editor {
ws: Option<PathBuf>,
) -> rootcause::Result<()> {
if let Some(x) = self.files.remove(x) {
- let f = take(&mut self.files);
-
- *self = x;
- assert!(self.files.len() == 0);
- self.files = f;
- self.bar.last_action = "restored".into();
- if self.mtime != Self::modify(self.origin.as_deref()) {
- self.hist.push_if_changed(&mut self.text);
- self.text.rope = Rope::from_str(
- &std::fs::read_to_string(
- self.origin
- .as_ref()
- .ok_or(report!("origin missing"))?,
- )
- .unwrap(),
- );
-
- self.text.cursor.first_mut().position = self
- .text
- .cursor
- .first()
- .position
- .min(self.text.rope.len_chars());
- self.mtime = Self::modify(self.origin.as_deref());
- self.bar.last_action = "restored -> reloaded".into();
- take(&mut self.requests);
- self.hist.push(&mut self.text)
- }
- self.lsp = lsp;
- self.language = l;
- if let Some((x, origin)) = lsp!(self + p) {
- x.open(
- &origin,
- self.text.rope.to_string(),
- self.language.unwrap(),
- )?;
- }
+ self.restore(lsp, l, x)?
} else {
self.workspace = ws;
self.origin = Some(x.to_path_buf());
diff --git a/src/edi/lsp_impl.rs b/src/edi/lsp_impl.rs
index d0e506e..1498458 100644
--- a/src/edi/lsp_impl.rs
+++ b/src/edi/lsp_impl.rs
@@ -32,9 +32,10 @@ pub struct Requests {
(),
RequestError<SignatureHelpRequest>,
>, // vo, lines
- // #[serde(serialize_with = "serialize_tokens")]
- // #[serde(deserialize_with = "deserialize_tokens")]
- #[serde(skip)]
+ #[serde(serialize_with = "serialize_tokens")]
+ #[serde(deserialize_with = "deserialize_tokens")]
+ #[serde(default)]
+ // #[serde(skip)]
pub semantic_tokens: Rq<
Box<[SemanticToken]>,
Box<[SemanticToken]>,
@@ -47,7 +48,7 @@ pub struct Requests {
(),
RequestError<DocumentDiagnosticRequest>,
>,
- #[serde(skip)]
+ #[serde(default)]
pub inlay: Rq<
Vec<InlayHint>,
Vec<InlayHint>,
@@ -70,6 +71,34 @@ pub struct Requests {
#[serde(skip)]
pub git_diff: Rq<imara_diff::Diff, imara_diff::Diff, (), ()>,
}
+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 })
+}
+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,
+ )
+}
impl crate::edi::Editor {
pub fn poll(&mut self) {
let Some((l, ..)) = self.lsp else { return };