A simple CPU rendered GUI IDE experience.
generic menu
bendn 30 hours ago
parent fae2e73 · commit cae20b1
-rw-r--r--src/act.rs10
-rw-r--r--src/commands.rs175
-rw-r--r--src/edi.rs8
-rw-r--r--src/edi/st.rs4
-rw-r--r--src/main.rs1
-rw-r--r--src/menu.rs1
-rw-r--r--src/menu/generic.rs129
-rw-r--r--src/sym.rs121
8 files changed, 254 insertions, 195 deletions
diff --git a/src/act.rs b/src/act.rs
index 3912c65..d35cd3a 100644
--- a/src/act.rs
+++ b/src/act.rs
@@ -48,16 +48,6 @@ impl CodeActions {
}
pub fn down(&mut self) {
- // let mut adj = |y: &mut usize, max| {
- // *y += 1;
- // if *y == max {
- // self.vo = 0;
- // *y = 0;
- // }
- // if *y >= self.vo + 13 {
- // self.vo += 1;
- // }
- // };
match &mut self.inner {
N::Many(x, Entry::Outside(y), _) => {
let n = x.len();
diff --git a/src/commands.rs b/src/commands.rs
index 78dea1a..9e01796 100644
--- a/src/commands.rs
+++ b/src/commands.rs
@@ -13,9 +13,10 @@ use rust_analyzer::lsp::ext::*;
use crate::FG;
use crate::edi::{Editor, lsp_m};
-use crate::lsp::PathURI;
-use crate::menu::{back, charc, filter, next, score};
-use crate::text::{RopeExt, SortTedits, TextArea, col, color_};
+use crate::lsp::{Anonymize, PathURI};
+use crate::menu::charc;
+use crate::menu::generic::{GenericMenu, MenuData};
+use crate::text::{RopeExt, SortTedits, col, color_};
macro_rules! commands {
($(#[doc = $d: literal] $t:tt $identifier: ident: $c:literal),+ $(,)?) => {
@@ -68,116 +69,74 @@ commands!(
@ RARunTest: "run-test",
);
-#[derive(Debug, Default)]
-pub struct Commands {
- pub tedit: TextArea,
- pub selection: usize,
- pub vo: usize,
-}
-
-const N: usize = 30;
-impl Commands {
- fn f(&self) -> String {
- self.tedit.rope.to_string()
- }
- pub fn next(mut self) -> Self {
- let n = filter_c(&self.f()).count();
- // coz its bottom up
- back::<N>(n, &mut self.selection, &mut self.vo);
- self
+pub enum Cmds {}
+impl MenuData for Cmds {
+ const HEIGHT: usize = 30;
+ type Data = ();
+ type Element<'a> = Cmd;
+ fn gn((): &()) -> impl Iterator<Item = Cmd> {
+ Cmd::ALL.into_iter()
}
- pub fn sel(&self) -> Cmd {
- let f = self.f();
- score_c(filter_c(&f), &f)[self.selection].1
- }
+ fn r(
+ _: &Self::Data,
+ x: Cmd,
+ _: &Path,
+ c: usize,
+ selected: bool,
+ indices: &[u32],
+ to: &mut Vec<Cell>,
+ ) {
+ let bg = if selected { col!("#262d3b") } else { col!("#1c212b") };
- pub fn back(mut self) -> Self {
- let n = filter_c(&self.f()).count();
- next::<N>(n, &mut self.selection, &mut self.vo);
- self
- }
- pub fn cells(&self, c: usize, ws: &Path) -> Vec<Cell> {
- let f = self.f();
- let mut out = vec![];
- let v = score_c(filter_c(&f), &f);
- let vlen = v.len();
- let i = v.into_iter().zip(0..vlen).skip(self.vo).take(N).rev();
-
- i.for_each(|((_, x, indices), i)| {
- r(x, ws, c, i == self.selection, &indices, &mut out)
+ let ds: Style = Style::new(FG, bg);
+ let d: Cell = Cell { letter: None, style: ds };
+ let mut b = vec![d; c];
+ let (bgt, col, ty) = (col!("#FFFFFF"), col!("#ACACAC"), "");
+ b.iter_mut().zip(ty.chars()).for_each(|(x, c)| {
+ *x = (Style::new(col, bgt) | Style::BOLD).basic(c)
});
+ let i = &mut b[..];
+ let qualifier = x.desc().chars();
+ let _left = i.len() as i32
+ - (charc(&x.name()) as i32 + qualifier.clone().count() as i32)
+ - 3;
- out
+ i.iter_mut()
+ .zip(
+ x.name()
+ .chars()
+ .chain([' '])
+ .map(|x| ds.basic(x))
+ .zip(0..)
+ .chain(
+ qualifier
+ .map(|x| {
+ Style {
+ bg,
+ fg: color_("#858685"),
+ ..default()
+ }
+ .basic(x)
+ })
+ .zip(repeat(u32::MAX)),
+ ),
+ )
+ .for_each(|(a, (b, i))| {
+ *a = b;
+ if indices.contains(&i) {
+ a.style |= (Style::BOLD, color_("#ffcc66"));
+ }
+ });
+ to.extend(b);
}
}
-fn score_c(
- x: impl Iterator<Item = Cmd>,
- filter: &'_ str,
-) -> Vec<(u32, Cmd, Vec<u32>)> {
- score(x, filter)
-}
-
-fn filter_c(f: &'_ str) -> impl Iterator<Item = Cmd> {
- filter(Cmd::ALL.into_iter(), f)
-}
-impl crate::menu::Key<'static> for Cmd {
- fn key(&self) -> impl Into<std::borrow::Cow<'static, str>> {
+pub type Commands = GenericMenu<Cmds>;
+impl<'a> crate::menu::Key<'a> for Cmd {
+ fn key(&self) -> impl Into<std::borrow::Cow<'a, str>> {
self.name()
}
}
-#[implicit_fn::implicit_fn]
-fn r(
- x: Cmd,
- _workspace: &Path,
- c: usize,
- selected: bool,
- indices: &[u32],
- to: &mut Vec<Cell>,
-) {
- let bg = if selected { col!("#262d3b") } else { col!("#1c212b") };
-
- let ds: Style = Style::new(FG, bg);
- let d: Cell = Cell { letter: None, style: ds };
- let mut b = vec![d; c];
- let (bgt, col, ty) = (col!("#FFFFFF"), col!("#ACACAC"), "");
- b.iter_mut().zip(ty.chars()).for_each(|(x, c)| {
- *x = (Style::new(col, bgt) | Style::BOLD).basic(c)
- });
- let i = &mut b[..];
- let qualifier = x.desc().chars();
- let _left = i.len() as i32
- - (charc(&x.name()) as i32 + qualifier.clone().count() as i32)
- - 3;
-
- i.iter_mut()
- .zip(
- x.name()
- .chars()
- .chain([' '])
- .map(|x| ds.basic(x))
- .zip(0..)
- .chain(
- qualifier
- .map(|x| {
- Style {
- bg,
- fg: color_("#858685"),
- ..default()
- }
- .basic(x)
- })
- .zip(repeat(u32::MAX)),
- ),
- )
- .for_each(|(a, (b, i))| {
- *a = b;
- if indices.contains(&i) {
- a.style |= (Style::BOLD, color_("#ffcc66"));
- }
- });
- to.extend(b);
-}
impl Editor {
pub fn handle_command(
@@ -304,6 +263,16 @@ impl Editor {
};
self.open_loc(x, w);
}
+ Cmd::RARunnables => {
+ let x = l
+ .runtime
+ .block_on(l.runnables(
+ o,
+ self.text.to_l_position(*self.text.cursor.first()),
+ )?)
+ .anonymize()?;
+ // self.state = State::Runnables;
+ }
_ => unimplemented!(),
}
diff --git a/src/edi.rs b/src/edi.rs
index 62ca936..d840540 100644
--- a/src/edi.rs
+++ b/src/edi.rs
@@ -453,7 +453,7 @@ impl Editor {
|x, (_, p)| {
let Some(p) = p else { unreachable!() };
x.ok().flatten().map(|r| sym::Symbols {
- r,
+ data: (r, p.data.1, p.data.2),
selection: 0,
vo: 0,
..p
@@ -941,9 +941,9 @@ impl Editor {
else {
unreachable!()
};
- x.ty = sym::SymbolsType::Document;
+ x.data.2 = sym::SymbolsType::Document;
let p = p.to_owned();
- take(&mut x.r);
+ take(&mut x.data.0);
*request = Some((
DropH::new(lsp.runtime.spawn(
window.redraw_after(async move {
@@ -978,7 +978,7 @@ impl Editor {
.is_some()
|| ptedit != x.tedit.rope
{
- if x.ty == SymbolsType::Workspace {
+ if x.data.2 == SymbolsType::Workspace {
*request = Some((
DropH::new(
lsp.runtime.spawn(
diff --git a/src/edi/st.rs b/src/edi/st.rs
index 8844425..de25b1b 100644
--- a/src/edi/st.rs
+++ b/src/edi/st.rs
@@ -73,8 +73,8 @@ Default => {
},
Command(_) => K(Key::Named(Escape)) => Default,
Command(t) => K(Key::Named(Enter)) => Default [ProcessCommand(Commands => t)],
-Command(t) => K(Key::Named(Tab) if shift()) => Command(t.back()),
-Command(t) => K(Key::Named(Tab)) => Command(t.next()),
+Command(mut t) => K(Key::Named(Tab) if shift()) => Command({ t.back();t }),
+Command(mut t) => K(Key::Named(Tab)) => Command({ t.next(); t }),
Command(mut t) => K(k) => Command({ handle2(&k, &mut t.tedit, None); t }),
Command(t) => C(_) => _,
Command(t) => K(_) => _,
diff --git a/src/main.rs b/src/main.rs
index 8f9786b..cdde4c4 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,5 +1,6 @@
#![feature(
btree_set_entry,
+ associated_type_defaults,
array_try_map,
tuple_trait,
unboxed_closures,
diff --git a/src/menu.rs b/src/menu.rs
index f900189..3c5f7a1 100644
--- a/src/menu.rs
+++ b/src/menu.rs
@@ -1,3 +1,4 @@
+pub mod generic;
use std::borrow::Cow;
use std::cmp::Reverse;
use std::sync::LazyLock;
diff --git a/src/menu/generic.rs b/src/menu/generic.rs
new file mode 100644
index 0000000..ba48d76
--- /dev/null
+++ b/src/menu/generic.rs
@@ -0,0 +1,129 @@
+use std::fmt::Debug;
+use std::path::Path;
+
+use Default::default;
+use dsb::Cell;
+
+use crate::menu::{Key, back, filter, next, score};
+use crate::text::TextArea;
+
+pub struct GenericMenu<T: MenuData> {
+ pub data: T::Data,
+ pub tedit: TextArea,
+ pub selection: usize,
+ pub vo: usize,
+}
+impl<T: MenuData<Data: Clone>> Clone for GenericMenu<T> {
+ fn clone(&self) -> Self {
+ Self {
+ data: self.data.clone(),
+ tedit: self.tedit.clone(),
+ selection: self.selection.clone(),
+ vo: self.vo.clone(),
+ }
+ }
+}
+impl<T: MenuData<Data: Default>> Default for GenericMenu<T> {
+ fn default() -> Self {
+ Self {
+ data: default(),
+ tedit: default(),
+ selection: default(),
+ vo: default(),
+ }
+ }
+}
+impl<T: MenuData<Data: Debug>> Debug for GenericMenu<T> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.debug_struct(&format!(
+ "GenericMenu<{}>",
+ std::any::type_name::<T>()
+ ))
+ .field("data", &self.data)
+ .field("tedit", &self.tedit)
+ .field("selection", &self.selection)
+ .field("vo", &self.vo)
+ .finish()
+ }
+}
+pub trait MenuData {
+ const HEIGHT: usize = 30;
+ type Data;
+ type Element<'a>: Key<'a>;
+
+ fn gn<'a>(
+ x: &'a Self::Data,
+ ) -> impl Iterator<Item = Self::Element<'a>>;
+ fn r(
+ data: &'_ Self::Data,
+ elem: Self::Element<'_>,
+ workspace: &Path,
+ columns: usize,
+ selected: bool,
+ indices: &[u32],
+ to: &mut Vec<Cell>,
+ );
+ fn filter_c<'a>(
+ x: &'a Self::Data,
+ f: &str,
+ ) -> impl Iterator<Item = Self::Element<'a>> {
+ filter(Self::gn(x), f)
+ }
+ fn score_c<'a>(
+ x: impl Iterator<Item = Self::Element<'a>>,
+ f: &str,
+ ) -> Vec<(u32, Self::Element<'a>, Vec<u32>)> {
+ score(x, f)
+ }
+}
+
+impl<T: MenuData> GenericMenu<T> {
+ fn f(&self) -> String {
+ self.tedit.rope.to_string()
+ }
+ pub fn next(&mut self)
+ where
+ [(); T::HEIGHT]:,
+ {
+ let n = T::filter_c(&self.data, &self.f()).count();
+ // coz its bottom up
+ back::<{ T::HEIGHT }>(n, &mut self.selection, &mut self.vo);
+ }
+
+ pub fn sel(&self) -> T::Element<'_> {
+ let f = self.f();
+ T::score_c(T::filter_c(&self.data, &f), &f)
+ .swap_remove(self.selection)
+ .1
+ }
+
+ pub fn back(&mut self)
+ where
+ [(); T::HEIGHT]:,
+ {
+ let n = T::filter_c(&self.data, &self.f()).count();
+ next::<{ T::HEIGHT }>(n, &mut self.selection, &mut self.vo);
+ }
+ pub fn cells(&self, c: usize, ws: &Path) -> Vec<Cell> {
+ let f = self.f();
+ let mut out = vec![];
+ let v = T::score_c(T::filter_c(&self.data, &f), &f);
+ let vlen = v.len();
+ let i =
+ v.into_iter().zip(0..vlen).skip(self.vo).take(T::HEIGHT).rev();
+
+ i.for_each(|((_, x, indices), i)| {
+ T::r(
+ &self.data,
+ x,
+ ws,
+ c,
+ i == self.selection,
+ &indices,
+ &mut out,
+ )
+ });
+
+ out
+ }
+}
diff --git a/src/sym.rs b/src/sym.rs
index 8db08dd..1a0db44 100644
--- a/src/sym.rs
+++ b/src/sym.rs
@@ -9,18 +9,50 @@ use itern::Iter3;
use lsp_types::*;
use crate::FG;
-use crate::menu::{Key, back, charc, filter, next, score};
-use crate::text::{TextArea, col, color_, set_a};
+use crate::menu::generic::{GenericMenu, MenuData};
+use crate::menu::{Key, charc};
+use crate::text::{col, color_, set_a};
+pub enum Symb {}
+impl MenuData for Symb {
+ type Data = (SymbolsList, Vec<SymbolInformation>, SymbolsType);
-#[derive(Debug, Default)]
-pub struct Symbols {
- pub r: SymbolsList,
- pub tree: Vec<SymbolInformation>,
- pub tedit: TextArea,
- pub selection: usize,
- pub vo: usize,
- pub ty: SymbolsType,
+ type Element<'a> = UsedSI<'a>;
+
+ fn gn(
+ (r, tree, _): &Self::Data,
+ ) -> impl Iterator<Item = Self::Element<'_>> {
+ match r {
+ SymbolsList::Document(DocumentSymbolResponse::Flat(x)) =>
+ Iter3::A(x.iter().map(UsedSI::from)),
+ SymbolsList::Document(DocumentSymbolResponse::Nested(x)) =>
+ Iter3::B(x.iter().flat_map(|x| gen move {
+ let mut q = VecDeque::with_capacity(12);
+ q.push_back(x);
+ while let Some(x) = q.pop_front() {
+ q.extend(x.children.iter().flatten());
+ yield x.into();
+ }
+ })),
+ SymbolsList::Workspace(WorkspaceSymbolResponse::Flat(x)) =>
+ Iter3::C(chain(tree, x.iter()).map(UsedSI::from)),
+ _ => unreachable!("please no"),
+ }
+ }
+
+ fn r(
+ &(.., sty): &Self::Data,
+ x: Self::Element<'_>,
+ workspace: &Path,
+ c: usize,
+ selected: bool,
+ indices: &[u32],
+ to: &mut Vec<Cell>,
+ ) {
+ r(x, workspace, c, selected, indices, to, sty)
+ }
}
+pub type Symbols = GenericMenu<Symb>;
+
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
pub enum GoTo<'a> {
Loc(&'a Location),
@@ -92,8 +124,8 @@ impl Default for SymbolsList {
Self::Workspace(WorkspaceSymbolResponse::Flat(vec![]))
}
}
-const N: usize = 30;
-impl Symbols {
+
+impl GenericMenu<Symb> {
pub fn new(tree: &[PathBuf]) -> Self {
let tree = tree
.iter()
@@ -113,38 +145,7 @@ impl Symbols {
tags: None,
})
.collect();
- Self { tree, ..Default::default() }
- }
- fn f(&self) -> String {
- self.tedit.rope.to_string()
- }
- pub fn next(&mut self) {
- let n = filter_c(self, &self.f()).count();
- // coz its bottom up
- back::<N>(n, &mut self.selection, &mut self.vo);
- }
-
- pub fn sel(&self) -> UsedSI<'_> {
- let f = self.f();
- score_c(filter_c(self, &f), &f)[self.selection].1
- }
-
- pub fn back(&mut self) {
- let n = filter_c(self, &self.f()).count();
- next::<N>(n, &mut self.selection, &mut self.vo);
- }
- pub fn cells(&self, c: usize, ws: &Path) -> Vec<Cell> {
- let f = self.f();
- let mut out = vec![];
- let v = score_c(filter_c(self, &f), &f);
- let vlen = v.len();
- let i = v.into_iter().zip(0..vlen).skip(self.vo).take(N).rev();
-
- i.for_each(|((_, x, indices), i)| {
- r(x, ws, c, i == self.selection, &indices, &mut out, self.ty)
- });
-
- out
+ Self { data: (default(), tree, default()), ..default() }
}
}
@@ -153,38 +154,6 @@ impl<'a> Key<'a> for UsedSI<'a> {
self.name
}
}
-fn score_c<'a>(
- x: impl Iterator<Item = UsedSI<'a>>,
- filter: &'_ str,
-) -> Vec<(u32, UsedSI<'a>, Vec<u32>)> {
- score(x, filter)
-}
-
-fn filter_c<'a>(
- syms: &'a Symbols,
- f: &'_ str,
-) -> impl Iterator<Item = UsedSI<'a>> {
- let x = &syms.r;
- filter(
- match x {
- SymbolsList::Document(DocumentSymbolResponse::Flat(x)) =>
- Iter3::A(x.iter().map(UsedSI::from)),
- SymbolsList::Document(DocumentSymbolResponse::Nested(x)) =>
- Iter3::B(x.iter().flat_map(|x| gen move {
- let mut q = VecDeque::with_capacity(12);
- q.push_back(x);
- while let Some(x) = q.pop_front() {
- q.extend(x.children.iter().flatten());
- yield x.into();
- }
- })),
- SymbolsList::Workspace(WorkspaceSymbolResponse::Flat(x)) =>
- Iter3::C(chain(&syms.tree, x.iter()).map(UsedSI::from)),
- _ => unreachable!("please no"),
- },
- f,
- )
-}
#[implicit_fn::implicit_fn]
fn r<'a>(
x: UsedSI<'a>,