A simple CPU rendered GUI IDE experience.
-rw-r--r--src/com.rs44
-rw-r--r--src/lsp.rs33
-rw-r--r--src/main.rs22
-rw-r--r--src/text.rs9
4 files changed, 67 insertions, 41 deletions
diff --git a/src/com.rs b/src/com.rs
index 119480e..441ca8a 100644
--- a/src/com.rs
+++ b/src/com.rs
@@ -31,6 +31,10 @@ impl Complete {
}
}
+ pub fn sel(&self, f: &str) -> &CompletionItem {
+ score(filter(self, f), f)[self.selection].1
+ }
+
pub fn back(&mut self, f: &str) {
let n = filter(self, f).count();
if self.selection == 0 {
@@ -47,7 +51,7 @@ impl Complete {
fn score<'a>(
x: impl Iterator<Item = &'a CompletionItem>,
filter: &'_ str,
-) -> impl Iterator<Item = (u32, &'a CompletionItem, Vec<u32>)> {
+) -> Vec<(u32, &'a CompletionItem, Vec<u32>)> {
#[thread_local]
static mut MATCHER: LazyLock<nucleo::Matcher> =
LazyLock::new(|| nucleo::Matcher::new(nucleo::Config::DEFAULT));
@@ -57,23 +61,28 @@ fn score<'a>(
nucleo::pattern::CaseMatching::Smart,
nucleo::pattern::Normalization::Smart,
);
- x.map(move |y| {
- let mut utf32 = vec![];
+ let mut v = 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)
- })
+ (score, y, indices)
+ })
+ .collect::<Vec<_>>();
+ v.sort_by_key(|x| x.0);
+ v.reverse();
+ v
}
fn filter<'a>(
completion: &'a Complete,
@@ -101,8 +110,7 @@ fn filter<'a>(
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()
+ .into_iter()
.zip(0..)
.skip(completion.vo)
.take(N);
diff --git a/src/lsp.rs b/src/lsp.rs
index 1942819..a301be9 100644
--- a/src/lsp.rs
+++ b/src/lsp.rs
@@ -278,6 +278,11 @@ pub fn run(
value_set: vec![CompletionItemTag::DEPRECATED],
}),
+ insert_replace_support: Some(false),
+ insert_text_mode_support:Some(InsertTextModeSupport{
+ value_set: vec![InsertTextMode::AS_IS]
+ }),
+ resolve_support: Some(CompletionItemCapabilityResolveSupport { properties: vec!["documentation".into()] } ),
label_details_support: None,
..default()
}),
@@ -285,29 +290,29 @@ pub fn run(
CompletionItemKindCapability {
value_set: Some(
vec![CompletionItemKind::TEXT,
-CompletionItemKind::METHOD, // ()
-CompletionItemKind::FUNCTION, // ()
-CompletionItemKind::CONSTRUCTOR, // ->
-CompletionItemKind::FIELD, // x.
-CompletionItemKind::VARIABLE, // x
+CompletionItemKind::METHOD,
+CompletionItemKind::FUNCTION,
+CompletionItemKind::CONSTRUCTOR,
+CompletionItemKind::FIELD,
+CompletionItemKind::VARIABLE,
CompletionItemKind::CLASS,
CompletionItemKind::INTERFACE,
-CompletionItemKind::MODULE, // ::
-CompletionItemKind::PROPERTY, // x.
+CompletionItemKind::MODULE,
+CompletionItemKind::PROPERTY,
CompletionItemKind::UNIT,
-CompletionItemKind::VALUE, // 4
-CompletionItemKind::ENUM, // un
+CompletionItemKind::VALUE,
+CompletionItemKind::ENUM,
CompletionItemKind::KEYWORD,
-CompletionItemKind::SNIPPET, // !
+CompletionItemKind::SNIPPET,
CompletionItemKind::COLOR,
CompletionItemKind::FILE,
-CompletionItemKind::REFERENCE, // &
+CompletionItemKind::REFERENCE,
CompletionItemKind::FOLDER,
CompletionItemKind::ENUM_MEMBER,
-CompletionItemKind::CONSTANT, // N
-CompletionItemKind::STRUCT, // X
+CompletionItemKind::CONSTANT,
+CompletionItemKind::STRUCT,
CompletionItemKind::EVENT,
-CompletionItemKind::OPERATOR, // +
+CompletionItemKind::OPERATOR,
CompletionItemKind::TYPE_PARAMETER]
),
diff --git a/src/main.rs b/src/main.rs
index 68d46fb..a3e2b5b 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -45,12 +45,9 @@ use diff_match_patch_rs::PatchInput;
use dsb::cell::Style;
use dsb::{Cell, F};
use fimg::{Image, OverlayAt};
-use lsp_types::request::{Completion, HoverRequest};
+use lsp_types::request::{ HoverRequest};
use lsp_types::{
- CompletionContext, CompletionResponse, CompletionTriggerKind, Hover,
- HoverParams, MarkedString, Position, SemanticTokensOptions,
- SemanticTokensServerCapabilities, ServerCapabilities,
- TextDocumentIdentifier, TextDocumentPositionParams, WorkspaceFolder,
+ CompletionContext, CompletionResponse, CompletionTextEdit, CompletionTriggerKind, Hover, HoverParams, MarkedString, Position, SemanticTokensOptions, SemanticTokensServerCapabilities, ServerCapabilities, TextDocumentIdentifier, TextDocumentPositionParams, WorkspaceFolder
};
use parking_lot::Mutex;
use regex::Regex;
@@ -335,7 +332,7 @@ pub(crate) fn entry(event_loop: EventLoop<()>) {
r:x,start:c,selection:0,vo:0,
} );
if let Some(x) = o {
- // std::fs::write("complete_", serde_json::to_string_pretty(&x.r).unwrap()).unwrap();
+ std::fs::write("complete_", serde_json::to_string_pretty(&x.r).unwrap()).unwrap();
// println!("resolved")
}
// println!("{complete:#?}");
@@ -867,6 +864,12 @@ RUNNING.remove(&hover,&RUNNING.guard());
let CompletionState::Complete(Some(c), x) = &mut complete else { panic!()};
c.back(&filter(&text));
}
+ Some(CDo::Finish(x)) => {
+ let Some(CompletionTextEdit::Edit(ed)) = x.sel(&filter(&text)).clone().text_edit else { panic!() };
+ text.apply(ed.clone()).unwrap();
+ text.cursor = text.l_position(ed.range.start).unwrap() + ed.new_text.chars().count();
+ if hist.record(&text) { change!();}
+ }
Some(CDo::Abort(())) => {}
None => {return},
@@ -1244,14 +1247,17 @@ rust_fsm::state_machine! {
// exit cases
Complete((_x, None)) => Click => None,
+ Complete((_x, Some((y, _))))=> K(Key::Named(Escape)) => None [Abort(((),) => y.abort())],
+ Complete((_x, None)) => K(Key::Named(Escape)) => None,
Complete((_x, Some((y, _)))) => Click => None [Abort(((),) => y.abort())],
Complete((_x, Some((y, _)))) => K(Key::Character(x) if !x.chars().all(is_word)) => None [Abort(y.abort())],
Complete((_x, None)) => K(Key::Character(x) if !x.chars().all(is_word)) => None,
- Complete((_x, _y)) => K(_) => _ [Request(CompletionContext { trigger_kind: CompletionTriggerKind::TRIGGER_FOR_INCOMPLETE_COMPLETIONS, trigger_character:None })],
Complete((Some(x), task)) => K(Key::Named(NamedKey::Enter)) => None [Finish(Complete => {
task.map(|(task, _)| task.abort()); x
- })]
+ })],
+
+ Complete((_x, _y)) => K(_) => _ [Request(CompletionContext { trigger_kind: CompletionTriggerKind::TRIGGER_FOR_INCOMPLETE_COMPLETIONS, trigger_character:None })],
}
use com::Complete;
impl Default for CompletionState {
diff --git a/src/text.rs b/src/text.rs
index e37c8c7..293244f 100644
--- a/src/text.rs
+++ b/src/text.rs
@@ -17,7 +17,7 @@ use helix_core::Syntax;
use helix_core::syntax::{HighlightEvent, Loader};
use implicit_fn::implicit_fn;
use log::error;
-use lsp_types::{Position, SemanticToken, SemanticTokensLegend};
+use lsp_types::{Position, SemanticToken, SemanticTokensLegend, TextEdit};
use ropey::{Rope, RopeSlice};
use tree_house::Language;
use winit::keyboard::{NamedKey, SmolStr};
@@ -308,6 +308,13 @@ impl TextArea {
self.set_ho();
}
+ pub fn apply(&mut self, x: TextEdit) -> Result<(), ropey::Error> {
+ let begin = self.l_position(x.range.start)?;
+ let end = self.l_position(x.range.end)?;
+ self.rope.try_remove(begin..end)?;
+ self.rope.try_insert(begin, &x.new_text)?;
+ Ok(())
+ }
pub fn cursor(&self) -> (usize, usize) {
self.xy(self.cursor)
}