A simple CPU rendered GUI IDE experience.
basic file navigation
bendn 8 weeks ago
parent 70f85a9 · commit bfef06a
-rw-r--r--Cargo.toml4
-rw-r--r--src/act.rs47
-rw-r--r--src/bar.rs26
-rw-r--r--src/com.rs108
-rw-r--r--src/lsp.rs32
-rw-r--r--src/main.rs108
-rw-r--r--src/sym.rs227
-rw-r--r--src/text.rs5
8 files changed, 472 insertions, 85 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 2dda033..8c404eb 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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" }
diff --git a/src/act.rs b/src/act.rs
index fc4a221..248baeb 100644
--- a/src/act.rs
+++ b/src/act.rs
@@ -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!(),
}
diff --git a/src/bar.rs b/src/bar.rs
index 0ca8294..3b843eb 100644
--- a/src/bar.rs
+++ b/src/bar.rs
@@ -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()
diff --git a/src/com.rs b/src/com.rs
index a8358c4..5ee4174 100644
--- a/src/com.rs
+++ b/src/com.rs
@@ -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)
diff --git a/src/lsp.rs b/src/lsp.rs
index 323ebac..6b1aac6 100644
--- a/src/lsp.rs
+++ b/src/lsp.rs
@@ -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()