A simple CPU rendered GUI IDE experience.
-rw-r--r--src/edi.rs85
-rw-r--r--src/edi/st.rs15
-rw-r--r--src/gotolist.rs76
-rw-r--r--src/lsp/client.rs46
-rw-r--r--src/main.rs22
-rw-r--r--src/rnd.rs31
-rw-r--r--src/text.rs12
-rw-r--r--src/text/cursor.rs4
8 files changed, 263 insertions, 28 deletions
diff --git a/src/edi.rs b/src/edi.rs
index 489167a..b861cad 100644
--- a/src/edi.rs
+++ b/src/edi.rs
@@ -37,7 +37,7 @@ use crate::complete::Complete;
use crate::error::WDebug;
use crate::hov::{self, Hovr};
use crate::lsp::{
- self, Anonymize, Client, Map_, PathURI, RequestError, Rq,
+ self, Anonymize, Client, Map_, PathURI, RequestError, Rq, tdpp,
};
use crate::menu::generic::MenuData;
use crate::meta::META;
@@ -506,6 +506,54 @@ impl Editor {
})
});
}
+ State::GoToL(z) => match &mut z.data.1 {
+ Some(crate::gotolist::O::Impl(y)) => {
+ y.poll(|x, _| {
+ x.ok().map(|x| {
+ x.and_then(|x| try {
+ z.data.0 = match x {
+ GotoDefinitionResponse::Scalar(
+ location,
+ ) => vec![(
+ location
+ .uri
+ .to_file_path()
+ .ok()?,
+ location.range,
+ )],
+ GotoDefinitionResponse::Array(
+ locations,
+ ) => locations
+ .into_iter()
+ .filter_map(|x| try {
+ (
+ x.uri
+ .to_file_path()
+ .ok()?,
+ x.range,
+ )
+ })
+ .collect(),
+ GotoDefinitionResponse::Link(
+ location_links,
+ ) => location_links
+ .into_iter()
+ .filter_map(|x| try {
+ (
+ x.target_uri
+ .to_file_path()
+ .ok()?,
+ x.target_range,
+ )
+ })
+ .collect(),
+ };
+ });
+ })
+ });
+ }
+ _ => {}
+ },
_ => {}
}
self.requests.def.poll(|x, _| {
@@ -1743,6 +1791,39 @@ impl Editor {
.block_on(crate::runnables::run(x, ws))
.unwrap();
},
+ Some(Do::GoToImplementations) => {
+ let State::GoToL(x) = &mut self.state else {
+ unreachable!()
+ };
+ if let Some(l) = lsp!(self) {
+ x.data.1 = Some(crate::gotolist::O::Impl(Rq::new(
+ l.runtime.spawn(
+ l.go_to_implementations(tdpp!(self)).unwrap(),
+ ),
+ )));
+ }
+ }
+ Some(Do::GTLSelect(x)) => {
+ if let Some(Ok((p, r))) = x.sel()
+ && Some(p) == self.origin.as_deref()
+ {
+ let x = self.text.l_range(r).unwrap();
+ self.text.vo = self.text.char_to_line(x.start);
+ self.text.cursor.just(x.start, &self.text.rope);
+ }
+ }
+ Some(Do::GT) => {
+ let State::GoToL(x) = &mut self.state else {
+ unreachable!()
+ };
+ if let Some(Ok((p, r))) = x.sel()
+ && Some(p) == self.origin.as_deref()
+ {
+ // let x = self.text.l_range(r).unwrap();
+ self.text.scroll_to_ln_centering(r.start.line as _);
+ // self.text.vo = self.text.char_to_line(x.start);
+ }
+ }
None => {}
}
ControlFlow::Continue(())
@@ -1989,7 +2070,7 @@ pub fn handle2<'a>(
Named(ArrowDown) => text.down(),
Named(PageDown) => text.page_down(),
Named(PageUp) => text.page_up(),
- Named(Enter) if let Some((l, p)) = l => l.enter(p, text),
+ Named(Enter) if let Some((l, p)) = l => l.enter(p, text).unwrap(),
Named(Enter) => text.enter(),
Character(x) => {
text.insert(&x);
diff --git a/src/edi/st.rs b/src/edi/st.rs
index 62149b9..cf6c243 100644
--- a/src/edi/st.rs
+++ b/src/edi/st.rs
@@ -9,6 +9,7 @@ use winit::keyboard::{Key, NamedKey, SmolStr};
use crate::commands::Commands;
use crate::edi::handle2;
+use crate::gotolist::GoToList;
use crate::lsp::{AQErr, Rq, RqS};
use crate::menu::generic::{GenericMenu, MenuData};
use crate::sym::{Symbols, SymbolsList};
@@ -51,9 +52,10 @@ Default => {
K(Key::Character("0") if ctrl()) => _ [MatchingBrace],
K(Key::Character("`") if ctrl()) => _ [SpawnTerminal],
K(Key::Character("/") if ctrl()) => Default [Comment(State => State::Default)],
- K(Key::Character("p") if ctrl()) => Command(Commands => Commands::default()),
+ K(Key::Character("p") if ctrl()) => Command(Commands => default()),
K(Key::Named(Backspace) if alt()) => _ [DeleteBracketPair],
K(Key::Named(F1)) => Procure((default(), InputRequest::RenameSymbol)),
+ K(Key::Named(F10)) => GoToL(GoToList => default()) [GoToImplementations],
K(Key::Named(k @ (ArrowUp | ArrowDown)) if alt()) => _ [InsertCursor(Direction => {
if k == ArrowUp {Direction::Above} else { Direction::Below }
})],
@@ -100,6 +102,17 @@ Runnables(_x) => {
C(_) => _,
M(_) => _,
},
+
+GoToL(x) => {
+ K(Key::Named(Tab) if shift()) => GoToL({ let mut x = x; x.next(); x }) [GT],
+ K(Key::Named(ArrowDown)) => GoToL({ let mut x = x; x.next(); x }) [GT],
+ K(Key::Named(ArrowUp | Tab)) => GoToL({ let mut x = x; x.back(); x }) [GT],
+ K(Key::Named(Enter)) => Default [GTLSelect(GoToList => x)],
+ K(Key::Named(Escape)) => Default,
+ // K(_) => _ [GTLHandleKey],
+ C(_) => _,
+ M(_) => _,
+},
Symbols(Rq { result: Some(_x), request: _rq }) => {
K(Key::Named(Tab) if shift()) => _ [SymbolsSelectNext],
K(Key::Named(ArrowDown)) => _ [SymbolsSelectNext],
diff --git a/src/gotolist.rs b/src/gotolist.rs
new file mode 100644
index 0000000..5a38fb9
--- /dev/null
+++ b/src/gotolist.rs
@@ -0,0 +1,76 @@
+use std::path::{Path, PathBuf};
+
+use dsb::Cell;
+use dsb::cell::Style;
+use lsp_types::Range;
+use lsp_types::request::GotoImplementation;
+
+use crate::FG;
+use crate::lsp::RqS;
+use crate::menu::Key;
+use crate::menu::generic::{GenericMenu, MenuData};
+use crate::text::col;
+pub type GoToList = GenericMenu<GTL>;
+pub enum GTL {}
+#[derive(Debug)]
+pub enum O {
+ Impl(RqS<(), GotoImplementation>),
+}
+impl<'a> Key<'a> for (&'a Path, Range) {
+ fn key(&self) -> impl Into<std::borrow::Cow<'a, str>> {
+ self.0.display().to_string()
+ }
+}
+impl MenuData for GTL {
+ type Data = (Vec<(PathBuf, Range)>, Option<O>);
+
+ type Element<'a> = (&'a Path, Range);
+
+ type E = !;
+
+ fn gn<'a>(
+ x: &'a Self::Data,
+ ) -> impl Iterator<Item = Self::Element<'a>> {
+ x.0.iter().map(|(x, y)| (&**x, *y))
+ }
+
+ fn r(
+ _data: &'_ Self::Data,
+ elem: Self::Element<'_>,
+ workspace: &std::path::Path,
+ columns: usize,
+ selected: bool,
+ _indices: &[u32],
+ to: &mut Vec<dsb::Cell>,
+ ) {
+ let bg = if selected { col!("#262d3b") } else { col!("#1c212b") };
+ let mut into =
+ vec![
+ Cell { style: Style::new(FG, bg), ..Default::default() };
+ columns
+ ];
+
+ into.iter_mut()
+ // .skip(1)
+ .zip(
+ elem.0
+ .strip_prefix(workspace)
+ .unwrap_or(&elem.0)
+ .display()
+ .to_string()
+ .chars()
+ .chain(
+ format!(
+ " 󱊀 {}:{} - {}:{}",
+ elem.1.start.line,
+ elem.1.start.character,
+ elem.1.end.line,
+ elem.1.end.character
+ )
+ .chars(),
+ ),
+ )
+ .for_each(|(a, b)| a.letter = Some(b));
+ to.extend(into);
+ }
+}
diff --git a/src/lsp/client.rs b/src/lsp/client.rs
index a137b37..65225db 100644
--- a/src/lsp/client.rs
+++ b/src/lsp/client.rs
@@ -15,6 +15,7 @@ use lsp_types::request::*;
use lsp_types::*;
use rust_analyzer::lsp::ext::*;
use tokio::sync::oneshot;
+use ttools::*;
use crate::lsp::BehaviourAfter::{self, *};
use crate::lsp::{RequestError, Rq};
@@ -474,26 +475,30 @@ impl Client {
Ok(())
}
- pub fn enter<'a>(&self, f: &Path, t: &'a mut TextArea) {
- ceach!(t.cursor, |c| {
+ pub fn enter<'a>(
+ &self,
+ f: &Path,
+ t: &'a mut TextArea,
+ ) -> rootcause::Result<()> {
+ ceach!(t.cursor, |c| try bikeshed rootcause::Result<()> {
let r = self
.request_immediate::<OnEnter>(
&TextDocumentPositionParams {
text_document: f.tid(),
position: t.to_l_position(*c).unwrap(),
},
- )
- .unwrap();
+ )?;
match r {
None => t.enter(),
Some(mut r) => {
r.sort_tedits();
for f in r {
- t.apply_snippet_tedit(&f).unwrap();
+ t.apply_snippet_tedit(&f)?;
}
}
}
- });
+ } => ?);
+ Ok(())
}
pub fn runnables(
&'static self,
@@ -508,7 +513,7 @@ impl Client {
text_document: t.tid(),
position: c,
})
- .map(|(x, _)| x)
+ .map(fst)
}
pub fn _child_modules(
@@ -528,7 +533,26 @@ impl Client {
position: p,
text_document: t.tid(),
})
- .map(|x| x.0)
+ .map(fst)
+ }
+ pub fn go_to_implementations(
+ &self,
+ tdpp: TextDocumentPositionParams,
+ ) -> Result<
+ impl Future<
+ Output = Result<
+ <GotoImplementation as Request>::Result,
+ RequestError<GotoImplementation>,
+ >,
+ >,
+ SendError<Message>,
+ > {
+ self.request::<GotoImplementation>(&GotoImplementationParams {
+ text_document_position_params: tdpp,
+ work_done_progress_params: default(),
+ partial_result_params: default(),
+ })
+ .map(fst)
}
}
@@ -542,3 +566,9 @@ impl PathURI for Path {
}
}
}
+pub macro tdpp($e:expr) {
+ TextDocumentPositionParams {
+ text_document: $e.origin.as_ref().unwrap().tid(),
+ position: $e.text.to_l_position(*$e.text.cursor.first()).unwrap(),
+ }
+}
diff --git a/src/main.rs b/src/main.rs
index 6618bc9..45bbdd1 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,4 +1,6 @@
#![feature(
+ trim_prefix_suffix,
+ const_closures,
yeet_expr,
adt_const_params,
inherent_associated_types,
@@ -48,12 +50,13 @@
#![allow(incomplete_features, irrefutable_let_patterns, static_mut_refs)]
mod act;
mod edi;
+mod error;
mod git;
+mod gotolist;
mod meta;
mod rnd;
mod runnables;
mod sym;
-mod error;
mod trm;
use std::fmt::{Debug, Display};
@@ -126,14 +129,15 @@ extern "C" fn sigint(_: i32) {
#[implicit_fn::implicit_fn]
pub(crate) fn entry(event_loop: EventLoop) {
-
- unsafe { __ED.write(match Editor::new() {
- Err(e) => {
- eprintln!("failure to launch: {e}");
- return
- }
- Ok(x) => x,
- }) };
+ unsafe {
+ __ED.write(match Editor::new() {
+ Err(e) => {
+ eprintln!("failure to launch: {e}");
+ return;
+ }
+ Ok(x) => x,
+ })
+ };
assert_eq!(unsafe { atexit(cleanup) }, 0);
unsafe { signal(libc::SIGINT, sigint as *const () as usize) };
let ed = unsafe { __ED.assume_init_mut() };
diff --git a/src/rnd.rs b/src/rnd.rs
index 405d711..94ec906 100644
--- a/src/rnd.rs
+++ b/src/rnd.rs
@@ -19,6 +19,7 @@ use winit::window::{ImeRequestData, Window};
use crate::edi::st::State;
use crate::edi::{Editor, lsp_m};
use crate::lsp::Rq;
+use crate::sym::{GoTo, UsedSI};
use crate::text::{CoerceOption, RopeExt, col, color_};
use crate::{
BG, BORDER, CompletionAction, CompletionState, FG, FONT, complete,
@@ -79,7 +80,7 @@ pub fn render(
style: Style { fg: BG, secondary_color: BG, bg: BG, flags: 0 },
letter: None,
});
- let x = match &ed.state {
+ let z = match &ed.state {
State::Selection => Some(
text.cursor
.iter()
@@ -95,6 +96,26 @@ pub fn render(
BG,
(cells, (c, r)),
(1, 0),
+ |mut f, y| {
+ if let State::GoToL(menu) = &ed.state
+ && let Some(Ok((p, r))) = menu.sel()
+ && Some(p) == ed.origin.as_deref()
+ {
+ if (r.start.line..=r.end.line).contains(&(y as _)) {
+ f.style.fg = col!("#FFCC66");
+ }
+ }
+ if let State::Symbols(Rq { result: Some(menu), .. }) =
+ &ed.state
+ && let Some(Ok(UsedSI { at: GoTo::R(x), .. })) =
+ menu.sel()
+ {
+ if (x.start.line..=x.end.line).contains(&(y as _)) {
+ f.style.fg = col!("#FFCC66");
+ }
+ }
+ f
+ },
);
let t_ox = text.line_number_offset() + 1;
text.c = c - t_ox;
@@ -116,7 +137,7 @@ pub fn render(
text.write_to((cells, (c, r)),
(t_ox, 0),
- x,
+ z,
|(_c, _r), text, mut x| {
if let Some(hl) = &ed.requests.document_highlights.result {
for DocumentHighlight { range: r, .. } in hl {
@@ -127,6 +148,7 @@ pub fn render(
// };
let (x1, y1) = text.map_to_visual((r.start.character as _, r.start.line as _));
let (x2, y2) = text.map_to_visual((r.end.character as _, r.end.line as _));
+
x.get_simple((x1, y1), (x2, y2)).coerce().for_each(|x| {
x.style.bg = col!("#3a4358");
});
@@ -739,6 +761,11 @@ pub fn render(
let c = x.cells(50, ws);
drawb(&c, 50);
}
+ State::GoToL(y) => {
+ let ws = ed.workspace.as_deref().unwrap();
+ let c = y.cells(50, ws);
+ drawb(&c, 50);
+ }
_ => {}
}
let com = match ed.requests.complete {
diff --git a/src/text.rs b/src/text.rs
index 04e07b5..8b892df 100644
--- a/src/text.rs
+++ b/src/text.rs
@@ -1040,6 +1040,7 @@ impl TextArea {
bg: [u8; 3],
(into, (w, _)): (&mut [Cell], (usize, usize)),
(ox, oy): (usize, usize),
+ mut m: impl FnMut(Cell, usize) -> Cell,
) {
for y in 0..r {
if (self.vo + y) < self.l() {
@@ -1048,10 +1049,13 @@ impl TextArea {
.chars()
.zip(into[(y + oy) * w..].iter_mut().skip(ox))
.for_each(|(a, b)| {
- *b = Cell {
- style: Style::new(color, bg),
- letter: Some(a),
- }
+ *b = m(
+ Cell {
+ style: Style::new(color, bg),
+ letter: Some(a),
+ },
+ self.vo + y,
+ )
});
}
}
diff --git a/src/text/cursor.rs b/src/text/cursor.rs
index 79514ff..07fe471 100644
--- a/src/text/cursor.rs
+++ b/src/text/cursor.rs
@@ -91,10 +91,10 @@ impl Default for Cursors {
pub fn caster<T, U>(x: impl FnMut(T) -> U) -> impl FnMut(T) -> U {
x
}
-pub macro ceach($cursor: expr, $f:expr) {
+pub macro ceach($cursor: expr, $f:expr $( => $q:tt)?) {
for i in (0..$cursor.inner.len()) {
let c = *$cursor.inner.get(i).expect("aw dangit");
- caster::<Cursor, _>($f)(c);
+ caster::<Cursor, _>($f)(c) $($q)?;
}
$cursor.coalesce();
}