A simple CPU rendered GUI IDE experience.
colorful
bendn 4 months ago
parent bc3f6b1 · commit 3afb670
-rw-r--r--Cargo.toml2
-rw-r--r--src/com.rs172
-rw-r--r--src/main.rs38
-rw-r--r--src/text.rs15
4 files changed, 150 insertions, 77 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 656685d..8f23f7b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -17,7 +17,7 @@ tree-sitter = "0.25.0"
car = "0.1.2"
memchr = "2.7.5"
lower = "0.2.0"
-amap = "0.1.3"
+amap = { version = "0.1.3", path = "../amap" }
run_times = "0.1.0"
array_chunks = "1.0.0"
rust-fsm = { version = "0.8.0", path = "../rust-fsm/rust-fsm", features = [
diff --git a/src/com.rs b/src/com.rs
index cf30f9f..119480e 100644
--- a/src/com.rs
+++ b/src/com.rs
@@ -1,4 +1,3 @@
-use std::collections::HashSet;
use std::mem::MaybeUninit;
use std::sync::LazyLock;
@@ -9,16 +8,46 @@ use fimg::Image;
use itertools::Itertools;
use lsp_types::*;
-use crate::text::color;
-use crate::{Complete, FG};
+use crate::FG;
+use crate::text::{color, color_, set_a};
-pub fn s(completion: &Complete, c: usize, filter: &str) -> Vec<Cell> {
- let mut out = vec![];
- let x = &completion.r;
- let y = match x {
- CompletionResponse::Array(x) => x,
- CompletionResponse::List(x) => &x.items,
- };
+#[derive(Debug)]
+pub struct Complete {
+ pub r: CompletionResponse,
+ pub start: usize,
+ pub selection: usize,
+ pub vo: usize,
+}
+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;
+ }
+ }
+
+ 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;
+ }
+ }
+ }
+}
+fn score<'a>(
+ x: impl Iterator<Item = &'a CompletionItem>,
+ filter: &'_ str,
+) -> impl Iterator<Item = (u32, &'a CompletionItem, Vec<u32>)> {
#[thread_local]
static mut MATCHER: LazyLock<nucleo::Matcher> =
LazyLock::new(|| nucleo::Matcher::new(nucleo::Config::DEFAULT));
@@ -28,37 +57,50 @@ pub fn s(completion: &Complete, c: usize, filter: &str) -> Vec<Cell> {
nucleo::pattern::CaseMatching::Smart,
nucleo::pattern::Normalization::Smart,
);
- dbg!(filter);
- let mut i = y
- .iter()
- .filter(|y| {
- filter.is_empty()
- || y.filter_text
- .as_deref()
- .unwrap_or(&y.label)
- .chars()
- .collect::<HashSet<_>>()
- .intersection(&filter.chars().collect())
- .count()
- > 0
- })
- .map(|y| {
- let mut utf32 = vec![];
+ x.map(move |y| {
+ let mut utf32 = vec![];
- let hay = y.filter_text.as_deref().unwrap_or(&y.label);
- let mut indices = vec![];
- let score = p
- .indices(
- nucleo::Utf32Str::new(hay, &mut utf32),
- unsafe { &mut *MATCHER },
- &mut indices,
- )
- .unwrap_or(0);
- indices.sort_unstable();
- indices.dedup();
+ let hay = y.filter_text.as_deref().unwrap_or(&y.label);
+ let mut indices = vec![];
+ let score = p
+ .indices(
+ nucleo::Utf32Str::new(hay, &mut utf32),
+ unsafe { &mut *MATCHER },
+ &mut indices,
+ )
+ .unwrap_or(0);
+ indices.sort_unstable();
+ indices.dedup();
+
+ (score, y, indices)
+ })
+}
+fn filter<'a>(
+ completion: &'a Complete,
+ 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| {
+ filter.is_empty()
+ || y.filter_text
+ .as_deref()
+ .unwrap_or(&y.label)
+ .chars()
+ .any(|x| filter.chars().contains(&x))
+ // .collect::<HashSet<_>>()
+ // .intersection(&filter.chars().collect())
+ // .count()
+ // > 0
+ })
+}
- (score, y, indices)
- })
+pub fn s(completion: &Complete, c: usize, f: &str) -> Vec<Cell> {
+ let mut out = vec![];
+ let i = score(filter(completion, f), f)
.sorted_by_key(|x| x.0)
.rev()
.zip(0..)
@@ -130,32 +172,36 @@ fn r(
let ds: Style = Style { bg: bg, color: FG, flags: 0 };
let d: Cell = Cell { letter: None, style: ds };
let mut b = vec![d; c];
- let ty = match x.kind {
- Some(CompletionItemKind::TEXT) => " ",
- Some(
- CompletionItemKind::METHOD | CompletionItemKind::FUNCTION,
- ) => "λ ",
- Some(CompletionItemKind::CONSTRUCTOR) => "->",
- Some(CompletionItemKind::FIELD) => "x.",
- Some(CompletionItemKind::VARIABLE) => "x",
- Some(CompletionItemKind::MODULE) => "::",
- Some(CompletionItemKind::PROPERTY) => "x.",
- Some(CompletionItemKind::VALUE) => "4 ",
- Some(CompletionItemKind::ENUM) => "u󰓹",
- Some(CompletionItemKind::SNIPPET) => "! ",
- Some(CompletionItemKind::INTERFACE) => "t ",
- Some(CompletionItemKind::REFERENCE) => "& ",
- Some(CompletionItemKind::CONSTANT) => "N ",
- Some(CompletionItemKind::STRUCT) => "X{",
- Some(CompletionItemKind::OPERATOR) => "+ ",
- Some(CompletionItemKind::TYPE_PARAMETER) => "T ",
- Some(CompletionItemKind::KEYWORD) => " ",
-
- _ => " ",
+ const MAP: [([u8; 3], [u8; 3], &str); 26] = {
+ car::map!(
+ amap::amap! {
+ const { CompletionItemKind::TEXT.0 as usize } => ("#9a9b9a", " "),
+ const { CompletionItemKind::METHOD.0 as usize } | const { CompletionItemKind::FUNCTION.0 as usize } => ("#FFD173", "λ "),
+ const { CompletionItemKind::CONSTRUCTOR.0 as usize } => ("#FFAD66", "->"),
+ const { CompletionItemKind::FIELD.0 as usize } => ("#E06C75", "x."),
+ const { CompletionItemKind::VARIABLE.0 as usize } => ("#E06C75", "x "),
+ const { CompletionItemKind::MODULE.0 as usize } => ("#D5FF80", "::"),
+ const { CompletionItemKind::PROPERTY.0 as usize } => ("#e6e1cf", "x."),
+ const { CompletionItemKind::VALUE.0 as usize } => ("#DFBFFF", "4 "),
+ const { CompletionItemKind::ENUM.0 as usize } => ("#73b9ff", "u󰓹"),
+ const { CompletionItemKind::ENUM_MEMBER.0 as usize } => ("#73b9ff", ":󰓹"),
+ const { CompletionItemKind::SNIPPET.0 as usize } => ("#9a9b9a", "! "),
+ const { CompletionItemKind::INTERFACE.0 as usize } => ("#E5C07B", "t "),
+ const { CompletionItemKind::REFERENCE.0 as usize } => ("#9a9b9a", "& "),
+ const { CompletionItemKind::CONSTANT.0 as usize } => ("#DFBFFF", "N "),
+ const { CompletionItemKind::STRUCT.0 as usize } => ("#73D0FF", "X{"),
+ const { CompletionItemKind::OPERATOR.0 as usize } => ("#F29E74", "+ "),
+ const { CompletionItemKind::TYPE_PARAMETER.0 as usize } => ("#9a9b9a", "T "),
+ const { CompletionItemKind::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.unwrap_or(CompletionItemKind(50)).0 as usize];
b.iter_mut().zip(ty.chars()).for_each(|(x, c)| {
- *x = Style { bg: T_BG, color: [154, 155, 154], ..default() }
- .basic(c)
+ *x = Style { bg: bgt, color: col, flags: Style::BOLD }.basic(c)
});
let i = &mut b[2..];
diff --git a/src/main.rs b/src/main.rs
index b84dda5..68d46fb 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,6 +1,8 @@
// this looks pretty good though
#![feature(tuple_trait, unboxed_closures, fn_traits)]
#![feature(
+ const_convert,
+ const_result_trait_fn,
thread_local,
result_option_map_or_default,
iter_intersperse,
@@ -474,11 +476,7 @@ r:x,start:c,selection:0,vo:0,
)
};
if let CompletionState::Complete(Some(ref x,),_) = complete {
- let c = com::s(x, 40,&if matches!(text.rope.get_char(text.cursor-1), Some('.' | ':')) {
- "".to_string()
- } else {
- text.rope.slice(text.word_left_p()..text.cursor).chars().collect::<String>()
- });
+ let c = com::s(x, 40,&filter(&text));
let ppem = 20.0;
let met = FONT.metrics(&[]);
@@ -861,6 +859,16 @@ RUNNING.remove(&hover,&RUNNING.guard());
let CompletionState::Complete(c, x) = &mut complete else { panic!()};
*x = Some((h,c.as_ref().map(|x|x.start).or(x.as_ref().map(|x|x.1)).unwrap_or(text.cursor)));
}
+ Some(CDo::SelectNext) => {
+ let CompletionState::Complete(Some(c), x) = &mut complete else { panic!()};
+ c.next(&filter(&text));
+ }
+ Some(CDo::SelectPrevious) => {
+ let CompletionState::Complete(Some(c), x) = &mut complete else { panic!()};
+ c.back(&filter(&text));
+ }
+ Some(CDo::Abort(())) => {}
+
None => {return},
_ => panic!(),
};
@@ -1231,8 +1239,8 @@ rust_fsm::state_machine! {
None => K(_) => _,
// when
- Complete((_x,_y)) => K(Key::Named(NamedKey::Tab) if shift()) => _ [SelectPrevious],
- Complete((_x,_y)) => K(Key::Named(NamedKey::Tab)) => _ [SelectNext],
+ Complete((Some(_x),_y)) => K(Key::Named(NamedKey::Tab) if shift()) => _ [SelectPrevious],
+ Complete((Some(_x),_y)) => K(Key::Named(NamedKey::Tab)) => _ [SelectNext],
// exit cases
Complete((_x, None)) => Click => None,
@@ -1245,15 +1253,19 @@ rust_fsm::state_machine! {
task.map(|(task, _)| task.abort()); x
})]
}
+use com::Complete;
impl Default for CompletionState {
fn default() -> Self {
Self::None
}
}
-#[derive(Debug)]
-struct Complete {
- r: CompletionResponse,
- start: usize,
- selection: usize,
- vo: usize,
+fn filter(text: &TextArea) -> String {
+ if matches!(text.rope.get_char(text.cursor - 1), Some('.' | ':')) {
+ "".to_string()
+ } else {
+ text.rope
+ .slice(text.word_left_p()..text.cursor)
+ .chars()
+ .collect::<String>()
+ }
}
diff --git a/src/text.rs b/src/text.rs
index 13edb6e..e37c8c7 100644
--- a/src/text.rs
+++ b/src/text.rs
@@ -12,6 +12,7 @@ use atools::prelude::*;
use diff_match_patch_rs::{DiffMatchPatch, Patches};
use dsb::Cell;
use dsb::cell::Style;
+use fimg::pixels::convert::PFrom;
use helix_core::Syntax;
use helix_core::syntax::{HighlightEvent, Loader};
use implicit_fn::implicit_fn;
@@ -147,6 +148,20 @@ const fn of(x: &'static str) -> usize {
panic!()
}
+pub const fn color_(x: &str) -> [u8; 3] {
+ let Some([_, x @ ..]): Option<[u8; 7]> = x.as_bytes().try_into().ok()
+ else {
+ panic!()
+ };
+ color(x)
+}
+pub const fn set_a([a, b, c]: [u8; 3], to: f32) -> [u8; 3] {
+ [
+ (((a as f32 / 255.0) * to) * 255.0) as u8,
+ (((b as f32 / 255.0) * to) * 255.0) as u8,
+ (((c as f32 / 255.0) * to) * 255.0) as u8,
+ ]
+}
pub const fn color(x: [u8; 6]) -> [u8; 3] {
car::map!(
car::map!(x, |b| (b & 0xF) + 9 * (b >> 6)).chunked::<2>(),