A simple CPU rendered GUI IDE experience.
basic file navigation
| -rw-r--r-- | Cargo.toml | 4 | ||||
| -rw-r--r-- | src/act.rs | 47 | ||||
| -rw-r--r-- | src/bar.rs | 26 | ||||
| -rw-r--r-- | src/com.rs | 108 | ||||
| -rw-r--r-- | src/lsp.rs | 32 | ||||
| -rw-r--r-- | src/main.rs | 108 | ||||
| -rw-r--r-- | src/sym.rs | 227 | ||||
| -rw-r--r-- | src/text.rs | 5 |
8 files changed, 472 insertions, 85 deletions
@@ -30,7 +30,9 @@ tree-house = { version = "0.3.0", features = ["fixtures"] } helix-loader = { git = "https://github.com/bend-n/helix" } helix-core = { git = "https://github.com/bend-n/helix" } -lsp-types = { git = "https://github.com/bend-n/helix", package = "helix-lsp-types" } +lsp-types = { git = "https://github.com/bend-n/helix", package = "helix-lsp-types", features = [ + "proposed", +] } lsp-server = { git = "https://github.com/bend-n/rust-analyzer" } rust-analyzer = { git = "https://github.com/bend-n/rust-analyzer" } @@ -21,6 +21,7 @@ pub struct CodeActions { pub vo: usize, } use crate::FG; +use crate::com::{back, next}; use crate::text::{col, set_a}; const N: usize = 13; @@ -47,31 +48,31 @@ 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; - } - }; + // 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), so) => { let n = x.len(); - adj(y, n); + next::<{ N }>(n, y, &mut self.vo); } N::Many(x, Entry::Inside(g_sel), _) => { let z = &x[*g_sel]; let n = z.len(); // TODO: think about this - adj(&mut self.selection, n); + next::<{ N }>(n, &mut self.selection, &mut self.vo); } N::One(x) => { let n = x.len(); - adj(&mut self.selection, n); + next::<{ N }>(n, &mut self.selection, &mut self.vo); } }; } @@ -109,28 +110,12 @@ impl CodeActions { pub fn up(&mut self) { if let Some(x) = self.innr() { let n = x.len(); - if self.selection == 0 { - self.vo = n - N; - self.selection = n - 1; - } else { - self.selection -= 1; - if self.selection < self.vo { - self.vo -= 1; - } - } + back::<{ N }>(n, &mut self.selection, &mut self.vo); } else { match &mut self.inner { N::Many(_, Entry::Outside(y), z) => { let n = z.len(); - if *y == 0 { - self.vo = n - N; - *y = n - 1; - } else { - *y = *y - 1; - if *y < self.vo { - self.vo -= 1; - } - } + back::<{ N }>(n, y, &mut self.vo); } _ => unreachable!(), } @@ -1,10 +1,11 @@ -use std::iter::repeat; +use std::iter::{chain, repeat}; use dsb::Cell; use dsb::cell::Style; use lsp_types::WorkDoneProgress; -use crate::lsp::Client; +use crate::lsp::{Client, Rq}; +use crate::sym::Symbols; use crate::text::TextArea; pub struct Bar { @@ -94,6 +95,27 @@ impl Bar { } }); } + State::Symbols(Rq { + result: Some(Symbols { tedit, .. }), + request, + }) => { + chain( + [match request { + Some(_) => '…', + None => '_', + }], + "filter: ".chars(), + ) + .zip(repeat(Style::BOLD | Style::ITALIC)) + .chain(s(&tedit.rope.to_string())) + .zip(row) + .for_each(|((x, z), y)| { + *y = Cell { + letter: Some(x), + style: Style { flags: z, ..y.style }, + } + }); + } State::RequestBoolean(x) => { x.prompt() .chars() @@ -1,3 +1,4 @@ +use std::cmp::Reverse; use std::iter::repeat; use std::mem::MaybeUninit; use std::sync::LazyLock; @@ -18,41 +19,50 @@ pub struct Complete { pub selection: usize, pub vo: usize, } +#[lower::apply(saturating)] +pub fn next<const N: usize>(n: usize, sel: &mut usize, vo: &mut usize) { + *sel += 1; + if *sel == n { + *vo = 0; + *sel = 0; + } + if *sel >= *vo + N { + *vo += 1; + } +} +#[lower::apply(saturating)] +pub fn back<const N: usize>(n: usize, sel: &mut usize, vo: &mut usize) { + if *sel == 0 { + *vo = n - N; + *sel = n - 1; + } else { + *sel -= 1; + if *sel < *vo { + *vo -= 1; + } + } +} impl Complete { pub fn next(&mut self, f: &str) { - let n = filter(self, f).count(); - self.selection += 1; - if self.selection == n { - self.vo = 0; - self.selection = 0; - } - if self.selection >= self.vo + N { - self.vo += 1; - } + let n = filter_c(self, f).count(); + next::<N>(n, &mut self.selection, &mut self.vo); } pub fn sel(&self, f: &str) -> &CompletionItem { - score(filter(self, f), f)[self.selection].1 + score_c(filter_c(self, f), f)[self.selection].1 } - #[lower::apply(saturating)] pub fn back(&mut self, f: &str) { - let n = filter(self, f).count(); - if self.selection == 0 { - self.vo = n - N; - self.selection = n - 1; - } else { - self.selection -= 1; - if self.selection < self.vo { - self.vo -= 1; - } - } + let n = filter_c(self, f).count(); + back::<N>(n, &mut self.selection, &mut self.vo); } } -fn score<'a>( - x: impl Iterator<Item = &'a CompletionItem>, + +pub fn score<'a, T: 'a>( + x: impl Iterator<Item = &'a T>, + f: impl Fn(&'a T) -> &'a str, filter: &'_ str, -) -> Vec<(u32, &'a CompletionItem, Vec<u32>)> { +) -> Vec<(u32, &'a T, Vec<u32>)> { #[thread_local] static mut MATCHER: LazyLock<nucleo::Matcher> = LazyLock::new(|| nucleo::Matcher::new(nucleo::Config::DEFAULT)); @@ -66,7 +76,7 @@ fn score<'a>( .map(move |y| { let mut utf32 = vec![]; // std::env::args().nth(1).unwrap().as_bytes().fi .fold(0, |acc, x| acc * 10 + x - b'0'); - let hay = y.filter_text.as_deref().unwrap_or(&y.label); + let hay = f(y); let mut indices = vec![]; let score = p .indices( @@ -85,26 +95,28 @@ fn score<'a>( // "com", // v.iter().map(|x| x.1.label.clone() + "\n").collect::<String>(), // ); - v.sort_by_key(|x| x.0); - v.reverse(); + v.sort_by_key(|x| Reverse(x.0)); v } -fn filter<'a>( - completion: &'a Complete, + +fn com_as_str(y: &CompletionItem) -> &str { + y.filter_text.as_deref().unwrap_or(&y.label) +} +fn score_c<'a>( + x: impl Iterator<Item = &'a CompletionItem>, filter: &'_ str, -) -> impl Iterator<Item = &'a CompletionItem> { - let x = &completion.r; - let y = match x { - CompletionResponse::Array(x) => x, - CompletionResponse::List(x) => &x.items, - }; - y.iter().filter(|y| { +) -> Vec<(u32, &'a CompletionItem, Vec<u32>)> { + score(x, com_as_str, filter) +} + +pub fn filter<'a, T: 'a>( + i: impl Iterator<Item = &'a T>, + f: impl Fn(&'a T) -> &'a str, + filter: &'_ str, +) -> impl Iterator<Item = &'a T> { + i.filter(move |y| { filter.is_empty() - || y.filter_text - .as_deref() - .unwrap_or(&y.label) - .chars() - .any(|x| filter.chars().contains(&x)) + || f(y).chars().any(|x| filter.chars().contains(&x)) // .collect::<HashSet<_>>() // .intersection(&filter.chars().collect()) // .count() @@ -112,9 +124,21 @@ fn filter<'a>( }) } +fn filter_c<'a>( + completion: &'a Complete, + f: &'_ str, +) -> impl Iterator<Item = &'a CompletionItem> { + let x = &completion.r; + let y = match x { + CompletionResponse::Array(x) => x, + CompletionResponse::List(x) => &x.items, + }; + filter(y.iter(), com_as_str, f) +} + pub fn s(completion: &Complete, c: usize, f: &str) -> Vec<Cell> { let mut out = vec![]; - let i = score(filter(completion, f), f) + let i = score_c(filter_c(completion, f), f) .into_iter() .zip(0..) .skip(completion.vo) @@ -354,7 +354,21 @@ impl Client { } } } - + pub fn symbols(&'static self, f: String) -> impl Future<Output = Result<Vec<SymbolInformation>, RequestError<lsp_request!("workspace/symbol")>>> { + self.request::<lsp_request!("workspace/symbol")>(&WorkspaceSymbolParams { + query: f, + search_scope: Some(WorkspaceSymbolSearchScope::Workspace), + search_kind: Some(WorkspaceSymbolSearchKind::AllSymbols), + ..Default::default() + }).unwrap().0 + .map(|x| x.map(|x| x.map(|x| { + // std::fs::write("syms", serde_json::to_string_pretty(&x).unwrap()); + match x { + WorkspaceSymbolResponse::Flat(x) => x, + WorkspaceSymbolResponse::Nested(_) => unreachable!(), + } + }).unwrap_or_default())) + } pub fn inlay( &'static self, f: &Path, @@ -464,6 +478,14 @@ pub fn run( ..default() }), workspace: Some(WorkspaceClientCapabilities { + symbol: Some(WorkspaceSymbolClientCapabilities { + symbol_kind: Some(SymbolKindCapability { value_set: Some(SymbolKind::ALL.to_vec()) }), + tag_support: Some(TagSupport { value_set: SymbolTag::ALL.to_vec() }), + resolve_support: Some(WorkspaceSymbolResolveSupportCapability { + properties: vec!["location".into()], + }), + ..default() + }), diagnostic: Some(DiagnosticWorkspaceClientCapabilities { refresh_support: Some(true) }), inlay_hint: Some(InlayHintWorkspaceClientCapabilities { refresh_support: Some(true) }), workspace_edit: Some( @@ -629,6 +651,7 @@ pub fn run( "codeActionGroup": true, "serverStatusNotification": true, "hoverActions": true, + "workspaceSymbolScopeKindFiltering": true, }}), ..default() }, @@ -664,6 +687,11 @@ pub fn run( "enable": true } }, + "workspace": { + "symbol": { + "search": { "limit": 1024 } + } + }, "showUnlinkedFileNotification": false, "completion": { "fullFunctionSignatures": { "enable": true, }, @@ -688,7 +716,7 @@ pub fn run( x.capabilities.position_encoding, Some(PositionEncodingKind::UTF8) ); - c.initialized = Some(x); + c.initialized = Some(dbg!(x)); c.notify::<lsp_types::notification::Initialized>( &InitializedParams {}, ) diff --git a/src/main.rs b/src/main.rs index 3cbb307..bc1a4f9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -35,6 +35,7 @@ use std::borrow::Cow; use std::iter::once; mod act; +mod sym; use std::num::NonZeroU32; use std::os::fd::AsFd; use std::path::{Path, PathBuf}; @@ -73,6 +74,7 @@ use winit::window::Icon; use crate::bar::Bar; use crate::hov::Hovr; use crate::lsp::{RedrawAfter, RequestError, RqS}; +use crate::sym::Symbols; use crate::text::{Diff, Mapping, TextArea, col, is_word}; mod bar; pub mod com; @@ -222,7 +224,7 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { let (a, b) = Connection::memory(); std::thread::Builder::new() .name("Rust Analyzer".into()) - .stack_size(1024 * 1024 * 8) + .stack_size(1024 * 1024 * 8) .spawn(move || { let ra = std::thread::current_id(); std::panic::set_hook(Box::new(move |info| { @@ -404,6 +406,15 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { f.ok().flatten().map(|x| {Complete {r:x,start:c,selection:0,vo:0,}}) }, &l.runtime); }; + + if let State::Symbols(x) = &mut state { + x.poll(|x, (_, p)| x.ok().map(|r| { + sym::Symbols { + tedit: p.map(_.tedit).unwrap_or_default(), + r,..default() // dont care about previous selection + } + }), &l.runtime); + } if let State::CodeAction(x) = &mut state { x.poll(|x, _| { let lems: Vec<CodeAction> = x.ok()??.into_iter().map(|x| match x { @@ -683,7 +694,9 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { let mut r = c.len()/columns; assert_eq!(c.len()%columns, 0); let (w, h) = dsb::size(&fonts.regular, ppem, ls, (columns, r)); - if w >= window.inner_size().width as usize || position.1 + h >= window.inner_size().height as usize { + if w >= window.inner_size().width as usize + // || position.1 + h >= window.inner_size().height as usize + { unsafe { dsb::render_owned(c, (columns, c.len() / columns), 18.0, fonts, 1.1, true).save("fail.png") }; return Err(()); } @@ -778,6 +791,15 @@ pub(crate) fn entry(event_loop: EventLoop<()>) { let Ok((is_above,left, top, w, mut h)) = place_around((_x, _y), &mut fonts, i.as_mut(), &c, m, ppem, ls, 0., 0., 0.)else { println!("ra?"); break 'out}; i.r#box((left .saturating_sub(1) as _, top.saturating_sub(1) as _), w as _,h as _, BORDER); }, + State::Symbols(Rq { result: Some(x),..}) => 'out: { + let ws = workspace.as_deref().unwrap(); + let c = x.cells(50,ws); + // let (_x, _y) = text.cursor_visual(); + let _x = 0; + let _y = r - 1; + let Ok((is_above,left, top, w, mut h)) = place_around((_x, _y), &mut fonts, i.as_mut(), &c, 50, ppem, ls, 0., 0., 0.)else { println!("ra?"); break 'out}; + i.r#box((left .saturating_sub(1) as _, top.saturating_sub(1) as _), w as _,h as _, BORDER); + } _ =>{}, } let com = match complete { @@ -1137,13 +1159,18 @@ hovering.request = (DropH::new(handle), cursor_position).into(); }, .. } if event.state == ElementState::Pressed => { + // if event.logical_key == Key::Named(NamedKey::F12) { + // lsp.unwrap().runtime.spawn(async move { + // lsp.unwrap().symbols().await; + // }); + // } if matches!( event.logical_key, Key::Named(Shift | Alt | Control | Super) ) { return; } - let mut o = state + let mut o: Option<Do> = state .consume(Action::K(event.logical_key.clone())) .unwrap(); match o { @@ -1156,6 +1183,62 @@ hovering.request = (DropH::new(handle), cursor_position).into(); _ => {} } match o { + Some(Do::Symbols) => { + if let Some(lsp) = lsp { + state = State::Symbols(Rq::new(lsp.runtime.spawn(window.redraw_after(lsp.symbols("".into()))))); + } + } + Some(Do::SymbolsHandleKey) => { + if let Some(lsp) = lsp { + let State::Symbols(Rq { result :Some(x), request}) = &mut state else {unreachable!()}; + let ptedit = x.tedit.rope.clone(); + if handle2(&event.logical_key, &mut x.tedit).is_some() || ptedit != x.tedit.rope { + *request = Some((DropH::new(lsp.runtime.spawn(window.redraw_after(lsp.symbols(x.tedit.rope.to_string())))), ())); + // state = State::Symbols(Rq::new(lsp.runtime.spawn(lsp.symbols("".into())))); + } + } + } + Some(Do::SymbolsSelectNext) => { + let State::Symbols(Rq { result :Some(x), ..}) = &mut state else {unreachable!()}; + x.next(); + }, + Some(Do::SymbolsSelectPrev) => { + let State::Symbols(Rq { result :Some(x), ..}) = &mut state else {unreachable!()}; + x.back(); + }, + Some(Do::SymbolsSelect) + => { let State::Symbols(Rq { result :Some(x), ..}) = &mut state else {unreachable!()}; + let x = x.sel(); // TODO dedup + let _: anyhow::Result<()> = try { + let f = x.location.uri.to_file_path().map_err(|()| anyhow::anyhow!("dammit"))?.canonicalize().map_err(anyhow::Error::from)?; + origin = Some(f.clone()); + let r = text.r; + text = default(); + text.r = r; + let new = std::fs::read_to_string(f).map_err(anyhow::Error::from)?; + text.insert(&new); + text.cursor = text.l_position(x.location.range.start).ok_or(anyhow::anyhow!("dangit"))?; + text.scroll_to_cursor_centering(); + hist = Hist { + history: vec![], + redo_history: vec![], + last: text.clone(), + last_edit: Instant::now(), + changed: false, + }; + complete = CompletionState::None; + mtime = modify!(); + + lsp!().map(|(x, origin)| { + (def, semantic_tokens, inlay, sig_help, complete, hovering) = (default(), default(), default(), default(), default(), default()); + x.open(&origin,new).unwrap(); + x.rq_semantic_tokens(&mut semantic_tokens, origin, Some(window.clone())).unwrap(); + }); + state = State::Default; + bar.last_action = "open".to_string(); + }; + + }, Some(Do::CodeAction) => { if let Some((lsp, f)) = lsp!() { let r = lsp.request::<lsp_request!("textDocument/codeAction")>(&CodeActionParams { @@ -1590,6 +1673,7 @@ Default => { K(Key::Character(x) if x == "f" && ctrl()) => Procure((default(), InputRequest::Search)), K(Key::Character(x) if x == "o" && ctrl()) => Procure((default(), InputRequest::OpenFile)), K(Key::Character(x) if x == "c" && ctrl()) => _, + K(Key::Character(x) if x == "l" && ctrl()) => _ [Symbols], K(Key::Character(x) if x == "." && ctrl()) => _ [CodeAction], K(Key::Named(ArrowUp | ArrowLeft | ArrowDown | ArrowRight | Home | End) if shift()) => Selection(Range<usize> => 0..0) [StartSelection], M(MouseButton => MouseButton::Left if shift()) => Selection(Range<usize> => 0..0) [StartSelection], @@ -1601,14 +1685,28 @@ Default => { K(_) => _ [Edit], M(_) => _, }, -CodeAction(Rq<act::CodeActions, Option<CodeActionResponse>,()> => Rq { result : Some(_x), request: None, }) => { +Symbols(Rq { result: Some(_x), request: None }) => { + K(Key::Named(Tab) if shift()) => _ [SymbolsSelectNext], + K(Key::Named(ArrowDown)) => _ [SymbolsSelectNext], + K(Key::Named(ArrowUp | Tab)) => _ [SymbolsSelectPrev], + K(Key::Named(Enter)) => _ [SymbolsSelect], + K(Key::Named(Escape)) => Default, + K(_) => _ [SymbolsHandleKey], +}, +Symbols(Rq::<Symbols, Vec<SymbolInformation>, (), RequestError<lsp_request!("workspace/symbol")>> => _rq) => { + K(Key::Named(Escape)) => Default, + C(_) => _, + M(_) => _, + K(_) => _, +}, +CodeAction(Rq { result : Some(_x), request }) => { K(Key::Named(Tab) if shift()) => _ [CASelectPrev], K(Key::Named(ArrowDown | Tab)) => _ [CASelectNext], K(Key::Named(ArrowUp)) => _ [CASelectPrev], K(Key::Named(Enter | ArrowRight)) => _ [CASelectRight], K(Key::Named(ArrowLeft)) => _ [CASelectLeft], }, -CodeAction(Rq<act::CodeActions, Option<CodeActionResponse>,(), RequestError<lsp_request!("textDocument/codeAction")>> => rq) => { +CodeAction(RqS<act::CodeActions, lsp_request!("textDocument/codeAction")> => rq) => { K(Key::Named(Escape)) => Default, C(_) => _, M(_) => _, diff --git a/src/sym.rs b/src/sym.rs new file mode 100644 index 0000000..9c9e50e --- /dev/null +++ b/src/sym.rs @@ -0,0 +1,227 @@ +use std::iter::repeat; +use std::path::Path; + +use Default::default; +use dsb::Cell; +use dsb::cell::Style; +use lsp_types::*; + +use crate::FG; +use crate::com::{back, filter, next, score}; +use crate::text::{TextArea, col, color_, set_a}; + +#[derive(Debug, Default)] +pub struct Symbols { + pub r: Vec<SymbolInformation>, + pub tedit: TextArea, + pub selection: usize, + pub vo: usize, +} +const N: usize = 30; +impl Symbols { + 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) -> &SymbolInformation { + 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(); + + // let Some((s, x)) = i.next() else { + // return vec![]; + // }; + + // let mut q = Dq::<_, 13>::new((s, x)); + // for (s, x) in i { + // if q.first().0 <= s { + // q.push_front((s, x)); + // } + // } + + // fuzzy_aho_corasick::FuzzyAhoCorasickBuilder::new() + // .fuzzy( + // FuzzyLimits::new() + // .insertions(20) + // .deletions(2) + // .edits(4) + // .substitutions(5) + // .swaps(3), + // .penalties(FuzzyPenalties { + // ) + // insertion: 0.0, + // deletion: 1.0, + // substitution: 0.5, + // swap: 0.5, + // }) + // .build( + // y.iter().map(|x| x.filter_text.as_deref().unwrap_or(&x.label)), + // ) + // .search(filter, 0.25) + // .into_iter() + // .map(|x| &y[x.pattern_index]) + // // .take(13); + // // for x in y + // // .iter() + // // .filter(|x| { + // // x.filter_text + // // .as_deref() + // // .unwrap_or(&x.label) + // // .starts_with(filter) + // // }) + // .take(13) + i.for_each(|((_, x, indices), i)| { + r(x, ws, c, i == self.selection, &indices, &mut out) + }); + + out + } +} +fn score_c<'a>( + x: impl Iterator<Item = &'a SymbolInformation>, + filter: &'_ str, +) -> Vec<(u32, &'a SymbolInformation, Vec<u32>)> { + score(x, sym_as_str, filter) +} + +fn filter_c<'a>( + completion: &'a Symbols, + f: &'_ str, +) -> impl Iterator<Item = &'a SymbolInformation> { + let x = &completion.r; + filter(x.iter(), sym_as_str, f) +} +fn sym_as_str(x: &SymbolInformation) -> &str { + &x.name +} +fn charc(c: &str) -> usize { + c.chars().count() +} +#[implicit_fn::implicit_fn] +fn r( + x: &SymbolInformation, + 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 { bg: bg, color: FG, flags: 0 }; + let d: Cell = Cell { letter: None, style: ds }; + let mut b = vec![d; c]; + const MAP: [([u8; 3], [u8; 3], &str); 51] = { + car::map!( + amap::amap! { + const { SymbolKind::FILE.0 as usize } => ("#9a9b9a", " "), + const { SymbolKind::METHOD.0 as usize } | const { SymbolKind::FUNCTION.0 as usize } => ("#FFD173", "λ "), + const { SymbolKind::CONSTRUCTOR.0 as usize } => ("#FFAD66", "->"), + const { SymbolKind::FIELD.0 as usize } => ("#E06C75", "x."), + const { SymbolKind::VARIABLE.0 as usize } => ("#E06C75", "x "), + const { SymbolKind::MODULE.0 as usize } => ("#D5FF80", "::"), + const { SymbolKind::PROPERTY.0 as usize } => ("#e6e1cf", "x."), + // const { SymbolKind::VALUE.0 as usize } => ("#DFBFFF", "4 "), + const { SymbolKind::ENUM.0 as usize } => ("#73b9ff", "u"), + const { SymbolKind::ENUM_MEMBER.0 as usize } => ("#73b9ff", ":"), + // const { SymbolKind::SNIPPET.0 as usize } => ("#9a9b9a", "! "), + const { SymbolKind::INTERFACE.0 as usize } => ("#E5C07B", "t "), + // const { SymbolKind::REFERENCE.0 as usize } => ("#9a9b9a", "& "), + const { SymbolKind::CONSTANT.0 as usize } => ("#DFBFFF", "N "), + const { SymbolKind::STRUCT.0 as usize } => ("#73D0FF", "X{"), + const { SymbolKind::OPERATOR.0 as usize } => ("#F29E74", "+ "), + const { SymbolKind::TYPE_PARAMETER.0 as usize } => ("#9a9b9a", "T "), + // const { SymbolKind::KEYWORD.0 as usize } => ("#FFAD66", "as"), + _ => ("#9a9b9a", " ") + }, + |(x, y)| (set_a(color_(x), 0.5), color_(x), y) + ) + }; + let (bgt, col, ty) = MAP[x.kind.0 as usize]; + b.iter_mut().zip(ty.chars()).for_each(|(x, c)| { + *x = Style { bg: bgt, color: col, flags: Style::BOLD }.basic(c) + }); + let i = &mut b[2..]; + let qualifier = x + .container_name + .as_ref() + .into_iter() + // .flat_map(|x| &x.detail) + .flat_map(_.chars()); + let left = i.len() as i32 + - (charc(&x.name) as i32 + qualifier.clone().count() as i32) + - 3; + let loc = x.location.uri.to_file_path().unwrap(); + let locs = + loc.strip_prefix(workspace).unwrap_or(&loc).to_str().unwrap_or(""); + let loc = locs.chars().rev().collect::<Vec<_>>().into_iter(); + let q = if left < charc(&locs) as i32 { + locs.chars() + .take(left as _) + .chain(['…']) + .collect::<Vec<_>>() + .into_iter() + .rev() + .collect::<Vec<_>>() + .into_iter() + } else { + loc + }; + i.iter_mut() + .rev() + .zip(q.map(|x| { + Style { bg, color: color_("#979794"), ..default() }.basic(x) + })) + .for_each(|(a, b)| *a = b); + + // i.iter_mut() + // .rev() + // .zip(loc.map(|x| { + // Style { bg, color: color_("#979794"), ..default() } + // .basic(x) + // })) + // .for_each(|(a, b)| *a = b); + i.iter_mut() + .zip( + x.name + .chars() + .chain([' ']) + .map(|x| ds.basic(x)) + .zip(0..) + .chain( + qualifier + .map(|x| { + Style { + bg, + color: 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); +} diff --git a/src/text.rs b/src/text.rs index 0c963fc..8dec0ae 100644 --- a/src/text.rs +++ b/src/text.rs @@ -210,7 +210,8 @@ impl Diff { let (cu, co, vo) = self.data[redo as usize]; t.cursor = cu; t.column = co; - t.vo = vo; + t.scroll_to_cursor_centering(); + // t.vo = vo; } } @@ -1768,7 +1769,7 @@ impl<'a> Output<'a> { pub trait CoerceOption<T> { fn coerce(self) -> impl Iterator<Item = T>; } -impl<I: Iterator<Item = T>, T> CoerceOption<T> for Option<I> { +impl<I: IntoIterator<Item = T>, T> CoerceOption<T> for Option<I> { #[allow(refining_impl_trait)] fn coerce(self) -> std::iter::Flatten<std::option::IntoIter<I>> { self.into_iter().flatten() |