A simple CPU rendered GUI IDE experience.
Diffstat (limited to 'src/commands.rs')
-rw-r--r--src/commands.rs395
1 files changed, 139 insertions, 256 deletions
diff --git a/src/commands.rs b/src/commands.rs
index 9e01796..05135cb 100644
--- a/src/commands.rs
+++ b/src/commands.rs
@@ -1,281 +1,164 @@
use std::iter::repeat;
use std::path::Path;
-use std::process::Stdio;
-use std::sync::Arc;
use Default::default;
-use Into::into;
-use anyhow::{anyhow, bail};
use dsb::Cell;
use dsb::cell::Style;
-use lsp_types::*;
-use rust_analyzer::lsp::ext::*;
use crate::FG;
-use crate::edi::{Editor, lsp_m};
-use crate::lsp::{Anonymize, PathURI};
-use crate::menu::charc;
-use crate::menu::generic::{GenericMenu, MenuData};
-use crate::text::{RopeExt, SortTedits, col, color_};
+use crate::menu::{back, filter, next, score};
+use crate::text::{TextArea, col, color_};
-macro_rules! commands {
- ($(#[doc = $d: literal] $t:tt $identifier: ident: $c:literal),+ $(,)?) => {
- #[derive(Copy, Clone, PartialEq, Eq)]
- pub enum Cmd {
- $(#[doc = $d] $identifier),+
- }
- impl Cmd {
- pub const ALL: [Cmd; { [$($c),+].len() }] = [$(Self::$identifier,)+];
- pub fn name(self) -> &'static str {
- match self {
- $(Self::$identifier => $c,)+
- }
- }
- pub fn desc(self) -> &'static str {
- match self {
- $(Self::$identifier => $d,)+
- }
- }
- pub fn needs_lsp(self) -> bool {
- match self {
- $(Self::$identifier => stringify!($t) == "@",)+
- }
- }
- }
- };
+const COMMANDS: [(&str, &str); 3] = [
+ ("w", "Write / Save"),
+ ("q", "Quit"),
+ ("exit-vim-mode", "Go back to default editting mode"),
+];
+
+#[derive(Debug, Default)]
+pub struct Commands {
+ pub tedit: TextArea,
+ pub selection: usize,
+ pub vo: usize,
}
-commands!(
- /// move item at cursor down
- @ RAMoveID: "move-item-down",
- /// move item at cursor up
- @ RAMoveIU: "move-item-up",
- /// restart rust analyzer
- @ RARestart: "ra-restart",
- /// go to parent module
- @ RAParent: "parent",
- /// join lines under cursors.
- @ RAJoinLines: "join-lines",
- /// gets list of runnables
- @ RARunnables: "runnables",
- /// Open docs for type at cursor
- @ RADocs: "open-docs",
- /// Rebuilds rust-analyzer proc macros
- @ RARebuildProcMacros: "rebuild-proc-macros",
- /// Cancels current running rust-analyzer check process
- @ RACancelFlycheck: "cancel-flycheck",
- /// Opens Cargo.toml file for this workspace
- @ RAOpenCargoToml: "open-cargo-toml",
- /// Runs the test at the cursor
- @ RARunTest: "run-test",
-);
-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()
+const N: usize = 30;
+impl Commands {
+ 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) -> &str {
+ 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();
- 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") };
+ // let Some((s, x)) = i.next() else {
+ // return vec![];
+ // };
- 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 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)
});
- 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);
+ out
}
}
-pub type Commands = GenericMenu<Cmds>;
-impl<'a> crate::menu::Key<'a> for Cmd {
+fn score_c<'a>(
+ x: impl Iterator<Item = &'a str>,
+ filter: &'_ str,
+) -> Vec<(u32, &'a str, Vec<u32>)> {
+ score(x, filter)
+}
+
+fn filter_c<'a>(
+ _me: &'a Commands,
+ f: &'_ str,
+) -> impl Iterator<Item = &'a str> {
+ filter(COMMANDS.into_iter().map(|(x, _)| x), f)
+}
+impl<'a> crate::menu::Key<'a> for &'a str {
fn key(&self) -> impl Into<std::borrow::Cow<'a, str>> {
- self.name()
+ *self
}
}
+fn charc(c: &str) -> usize {
+ c.chars().count()
+}
+#[implicit_fn::implicit_fn]
+fn r(
+ x: &str,
+ _workspace: &Path,
+ c: usize,
+ selected: bool,
+ indices: &[u32],
+ to: &mut Vec<Cell>,
+) {
+ let bg = if selected { col!("#262d3b") } else { col!("#1c212b") };
-impl Editor {
- pub fn handle_command(
- &mut self,
- z: Cmd,
- w: Arc<winit::window::Window>,
- ) -> anyhow::Result<()> {
- if !z.needs_lsp() {
- return Ok(());
- }
- let Some((l, o)) = lsp_m!(self + p) else {
- bail!("no lsp");
- };
-
- match z {
- Cmd::RAMoveIU | Cmd::RAMoveID => {
- let r = self
- .text
- .to_l_position(*self.text.cursor.first())
- .unwrap();
- let mut x = l.request_immediate::<rust_analyzer::lsp::ext::MoveItem>(&MoveItemParams {
- direction: if let Cmd::RAMoveIU = z { MoveItemDirection::Up } else { MoveItemDirection::Down },
- text_document: o.tid(),
- range: Range { start : r, end : r},
- })?;
+ 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[2..];
+ let qualifier = COMMANDS.iter().find(|y| y.0 == x).unwrap().1.chars();
+ let _left = i.len() as i32
+ - (charc(&x) as i32 + qualifier.clone().count() as i32)
+ - 3;
- x.sort_tedits();
- for t in x {
- self.text.apply_snippet_tedit(&t)?;
- }
- }
- Cmd::RARestart => {
- _ = l.request::<ReloadWorkspace>(&())?.0;
- }
- Cmd::RAParent => {
- let Some(GotoDefinitionResponse::Link([ref x])) =
- l.request_immediate::<ParentModule>(
- &TextDocumentPositionParams {
- text_document: o.tid(),
- position: self
- .text
- .to_l_position(*self.text.cursor.first())
- .unwrap(),
- },
- )?
- else {
- self.bar.last_action = "no such parent".into();
- return Ok(());
- };
- self.open_loclink(x, w);
- }
- Cmd::RAJoinLines => {
- let teds =
- l.request_immediate::<JoinLines>(&JoinLinesParams {
- ranges: self
- .text
- .cursor
- .iter()
- .filter_map(|x| {
- self.text.to_l_range(
- x.sel.map(into).unwrap_or(*x..*x),
- )
- })
- .collect(),
- text_document: o.tid(),
- })?;
- self.text
- .apply_tedits(&mut { teds })
- .map_err(|_| anyhow!("couldnt apply edits"))?;
- }
- Cmd::RADocs => {
- let u = l.request_immediate::<ExternalDocs>(
- &TextDocumentPositionParams {
- position: self
- .text
- .to_l_position(*self.text.cursor.first())
- .unwrap(),
- text_document: o.tid(),
- },
- )?;
- use rust_analyzer::lsp::ext::ExternalDocsResponse::*;
- std::process::Command::new("firefox-nightly")
- .arg(
- match &u {
- WithLocal(ExternalDocsPair {
- web: Some(x),
- ..
- }) if let Some("doc.rust-lang.org") =
- x.domain()
- && let Some(x) =
- x.path().strip_prefix("/nightly/")
- && option_env!("USER") == Some("os") =>
- format!("http://127.0.0.1:3242/{x}"), // i have a lighttpd server running
- WithLocal(ExternalDocsPair {
- local: Some(url),
- ..
- }) if let Ok(p) = url.to_file_path()
- && p.exists() =>
- url.to_string(),
- WithLocal(ExternalDocsPair {
- web: Some(url),
- ..
- })
- | Simple(Some(url)) => url.to_string(),
- _ => return Ok(()),
- }
- .to_string(),
- )
- .stdout(Stdio::null())
- .spawn()
- .unwrap();
+ i.iter_mut()
+ .zip(
+ x.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"));
}
- Cmd::RARebuildProcMacros => {
- _ = l.request::<RebuildProcMacros>(&())?;
- }
- Cmd::RACancelFlycheck => l.notify::<CancelFlycheck>(&())?,
- Cmd::RAOpenCargoToml => {
- let Some(GotoDefinitionResponse::Scalar(x)) =
- &l.request_immediate::<OpenCargoToml>(
- &OpenCargoTomlParams { text_document: o.tid() },
- )?
- else {
- bail!("wtf?");
- };
- 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!(),
- }
-
- Ok(())
- }
+ });
+ to.extend(b);
}