A simple CPU rendered GUI IDE experience.
generic menu
| -rw-r--r-- | src/act.rs | 10 | ||||
| -rw-r--r-- | src/commands.rs | 175 | ||||
| -rw-r--r-- | src/edi.rs | 8 | ||||
| -rw-r--r-- | src/edi/st.rs | 4 | ||||
| -rw-r--r-- | src/main.rs | 1 | ||||
| -rw-r--r-- | src/menu.rs | 1 | ||||
| -rw-r--r-- | src/menu/generic.rs | 129 | ||||
| -rw-r--r-- | src/sym.rs | 121 |
8 files changed, 254 insertions, 195 deletions
@@ -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!(), } @@ -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 + } +} @@ -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>, |