Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--Cargo.toml90
-rw-r--r--README.md10
-rw-r--r--dist/gracilaria.svg1
-rw-r--r--dist/image.pngbin0 -> 162072 bytes
-rw-r--r--languages.toml2
-rw-r--r--src/act.rs20
-rw-r--r--src/bar.rs25
-rw-r--r--src/commands.rs61
-rw-r--r--src/complete.rs70
-rw-r--r--src/edi.rs589
-rw-r--r--src/edi/input_handlers.rs12
-rw-r--r--src/edi/input_handlers/click.rs72
-rw-r--r--src/edi/input_handlers/cursor.rs104
-rw-r--r--src/edi/input_handlers/keyboard.rs410
-rw-r--r--src/edi/lsp_impl.rs187
-rw-r--r--src/edi/lsp_mn.rs119
-rw-r--r--src/edi/lsp_mn/stdio.rs75
-rw-r--r--src/edi/ra.rs9
-rw-r--r--src/edi/st.rs85
-rw-r--r--src/edi/wsedit.rs312
-rw-r--r--src/gotolist.rs37
-rw-r--r--src/hov.rs22
-rw-r--r--src/killring.rs58
-rw-r--r--src/lsp.rs30
-rw-r--r--src/lsp/client.rs346
-rw-r--r--src/lsp/communication.rs126
-rw-r--r--src/lsp/init_opts.rs180
-rw-r--r--src/lsp/rq.rs57
-rw-r--r--src/lsp/vsc_settings.rs2
-rw-r--r--src/main.rs99
-rw-r--r--src/menu.rs3
-rw-r--r--src/menu/generic.rs28
-rw-r--r--src/rnd.rs103
-rw-r--r--src/runnables.rs5
-rw-r--r--src/sig.rs19
-rw-r--r--src/sym.rs165
-rw-r--r--src/text.rs58
-rw-r--r--src/text/cursor.rs17
-rw-r--r--src/text/hist.rs13
-rw-r--r--src/text/inlay.rs12
-rw-r--r--src/text/semantic_tokens.rs3
41 files changed, 2454 insertions, 1182 deletions
diff --git a/Cargo.toml b/Cargo.toml
index a51fc46..11b7659 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -9,80 +9,92 @@ fimg = { git = "https://git.bendn.org/fimg" }
pattypan = { git = "https://git.bendn.org/pattypan" }
implicit-fn = "0.1.0"
ropey = "1.6.1"
-softbuffer = "0.4.6"
-swash = "0.2.5"
-winit = "0.31.0-beta.2"
+softbuffer = { version = "0.4.8", default-features = false, features = ["wayland", "x11"] }
+swash = "0.2.10"
+winit = { version = "0.31.0-beta.2", default-features = false, features = ["wayland", "x11"] }
-tree-sitter = "0.25.0"
-memchr = "2.7.5"
-lower = "0.2.0"
+tree-sitter = "0.26.12"
+memchr = "2.8.3"
+lower = "0.2.1"
amap = "0.1.4"
run_times = "0.1.0"
array_chunks = "1.0.0"
rust-fsm = { git = "https://git.bendn.org/rust-fsm", features = ["diagram"] }
-clipp = "0.1.0"
-regex = { version = "1.11.3", features = ["unstable", "use_std"] }
-tree-house = { version = "0.3.0", features = ["fixtures"] }
+clipp = "0.1.1"
+regex = { version = "1.13.1", features = ["unstable", "use_std"] }
+tree-house = { version = "0.4.0", features = ["fixtures"] }
# for tree house grammar loading
helix-loader = { git = "https://git.bendn.org/helix" }
helix-core = { git = "https://git.bendn.org/helix" }
-lsp-types = { git = "https://git.bendn.org/helix", package = "helix-lsp-types", features = [
- "proposed",
-] }
+# lsp-types = { git = "https://git.bendn.org/helix", package = "helix-lsp-types", features = [
+ # "proposed",
+# ] }
-lsp-server = { git = "https://git.bendn.org/rust-analyzer" }
-rust-analyzer = { git = "https://git.bendn.org/rust-analyzer" }
+
+lsp-server = { version = "0.7.9" }
+# rust-analyzer = { git = "https://git.bendn.org/rust-analyzer" }
# lsp-server = { path = "../rust-analyzer/lib/lsp-server" }
-# rust-analyzer = { path = "../rust-analyzer/crates/rust-analyzer" }
+rust-analyzer = { path = "../rust-analyzer/crates/rust-analyzer" }
-serde_json = "1.0.145"
-serde = { version = "1.0.228", features = ["unstable"] }
-serde_derive = "1.0.228"
-log = "0.4.28"
+serde_json = "1.0.151"
+serde = { version = "1.0.229", features = ["unstable"] }
+serde_derive = "1.0.229"
+log = "0.4.33"
crossbeam = { version = "0.8.4", features = ["nightly", "crossbeam-channel"] }
-test-log = "0.2.18"
-env_logger = "0.11.8"
-url = "2.5.7"
-tokio = { version = "1.47.1", features = ["rt-multi-thread", "sync", "time"] }
+test-log = "0.2.21"
+env_logger = "0.11.11"
+url = "2.5.8"
+tokio = { version = "1.53.1", features = ["rt-multi-thread", "sync", "time"] }
regex-cursor = "0.1.5"
-papaya = "0.2.3"
+papaya = "0.2.4"
markdown = "1.0.0"
-itertools = "0.14.0"
-pin-project = "1.1.10"
+itertools = "0.15.0"
+pin-project = "1.1.13"
replace_with = "0.1.8"
nucleo = "0.5.0"
-tokio-util = { version = "0.7.17", features = ["rt"] }
+tokio-util = { version = "0.7.19", features = ["rt"] }
scopeguard = "1.2.0"
-arc-swap = "1.7.1"
-atools = "0.1.10"
+arc-swap = "1.9.2"
+atools = "0.1.13"
swizzle = "0.1.0"
walkdir = "2.5.0"
-niri = { package = "niri-ipc", version = "25.11.0" }
-libc = "0.2.180"
-rustc-hash = "=2.1.1"
-bendy = { version = "0.6.1", features = ["serde"] }
-git2 = "0.20.4"
+libc = "0.2.189"
+rustc-hash = "2.1.3"
+git2 = "0.21.0"
imara-diff = "0.2.0"
vecto = "0.1.1"
rangemap = { version = "1.7.1", features = ["const_fn", "nightly", "serde1"] }
itern = "0.1.1"
-kitty-rc = { version = "0.4.2", git = "https://github.com/bend-n/kitty-rc-rs" }
+
smol_str = "0.3.6"
-futures = "0.3.32"
-rootcause = { version = "0.12.1", features = ["compat-anyhow1"] }
+futures = "0.3.33"
+rootcause = { version = "0.13.0", features = ["compat-anyhow1"] }
ttools = { git = "https://git.bendn.org/ttools" }
# ttools = { path = "../ttools/" }
ftools = { git = "https://git.bendn.org/ftools" }
json_value_merge = "2.0.1"
annotate-snippets = "0.12.16"
-toml = "1.1.2"
+toml = "1.1.4"
+bendncode = { git = "https://git.bendn.org/bendncode" }
+rfd = "0.17.2"
+lsp-types = { version = "0.11.0", package = "gen-lsp-types", features = ["url"] }
+rayon = "1.12.0"
+tracing-subscriber = "0.3.23"
+crossbeam-channel = "0.5.16"
+
+[target.'cfg(unix)'.dependencies]
+kitty-rc = { version = "0.4.2", git = "https://github.com/bend-n/kitty-rc-rs" }
+niri = { package = "niri-ipc", version = "25.11.0" }
+
[profile.dev.package]
rust-analyzer.opt-level = 3
fimg.opt-level = 3
nucleo.opt-level = 3
tree-house.debug-assertions = false
+
+
[profile.release.package.tree-house]
debug-assertions = false
@@ -102,4 +114,6 @@ incremental = false
[patch.crates-io]
smol_str = { git = "https://git.bendn.org/rust-analyzer" }
ttools = { git = "https://git.bendn.org/ttools" }
+# lsp-server = { path = "../rust-analyzer/lib/lsp-server" }
# winit = { git = "https://github.com/rust-windowing/winit" }
+
diff --git a/README.md b/README.md
index ec0d37b..bb43eff 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,9 @@
-# gracilaria
+<h1><svg xmlns="http://www.w3.org/2000/svg" style="height: 1em; vertical-align: middle; display: inline-block" viewBox="0 0 121.876 121.876"><circle cx="60.938" cy="60.938" r="60.938" style="fill:#0a3d81;fill-rule:evenodd;stroke-width:7.14375;stroke-linecap:round;stroke-dasharray:none;paint-order:markers stroke fill;fill-opacity:1"/><path fill="none" d="M64.282 145.583c.55.043 1.1.085 3.91 2.96 2.812 2.874 7.884 8.58 12.98 12.87 5.096 4.292 10.215 7.166 13.366 5.39 3.152-1.775 4.335-8.2 8.33-8.348s10.8 5.981 17.268 5.03c6.467-.951 12.597-8.982 18.261-8.961 5.665.021 10.864 8.095 16.063 16.169" style="fill:#0f0;fill-opacity:0;fill-rule:evenodd;stroke:#e0605c;stroke-width:15.734;stroke-linecap:round;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" transform="translate(-54.874 -94.9)"/><path d="m88.944 95.828-.75-15.062-14.587-3.837 12.67-8.184-3.97-14.552 13.42 6.884 10.617-10.714.752 15.064 14.585 3.834-12.67 8.185 3.97 14.552-13.42-6.885z" style="fill:#ffb30c;fill-opacity:1;fill-rule:evenodd;stroke:#0cff48;stroke-width:0;stroke-linecap:round;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill"/></svg> gracilaria</h1>
-readme for testing cgit
+lsp-enabled gui text editor / ide
+
+![picture](/gracilaria/plain/dist/image.png)
+
+### installation steps
+
+`cargo build -r`
diff --git a/dist/gracilaria.svg b/dist/gracilaria.svg
new file mode 100644
index 0000000..a38781f
--- /dev/null
+++ b/dist/gracilaria.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="460.634" height="460.634" viewBox="0 0 121.876 121.876"><path d="M18.21 209.008h159.257v153.159H18.21z" style="fill:#0a3d81;fill-opacity:1;fill-rule:evenodd;stroke:#0cff48;stroke-width:0;stroke-linecap:round;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" transform="translate(-35.069 -216.54)"/><path fill="none" d="M64.282 145.583c.55.043 1.1.085 3.91 2.96 2.812 2.874 7.884 8.58 12.98 12.87 5.096 4.292 10.215 7.166 13.366 5.39 3.152-1.775 4.335-8.2 8.33-8.348s10.8 5.981 17.268 5.03c6.467-.951 12.597-8.982 18.261-8.961 5.665.021 10.864 8.095 16.063 16.169" style="fill:#0f0;fill-opacity:0;fill-rule:evenodd;stroke:#e0605c;stroke-width:15.734;stroke-linecap:round;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" transform="translate(-54.874 -94.9)"/><path d="m133.155 245.006-4.046-2.166-3.288 3.203-.148-4.588-4.418-1.246 3.9-2.421-1.13-4.449 4.047 2.166 3.287-3.203.148 4.588 4.418 1.246-3.9 2.421z" style="fill:#ffb30c;fill-opacity:1;fill-rule:evenodd;stroke:#0cff48;stroke-width:0;stroke-linecap:round;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" transform="rotate(58.987 890.717 143.189)scale(3.28598)"/></svg> \ No newline at end of file
diff --git a/dist/image.png b/dist/image.png
new file mode 100644
index 0000000..e60b96b
--- /dev/null
+++ b/dist/image.png
Binary files differ
diff --git a/languages.toml b/languages.toml
index ea92bab..61ed0fc 100644
--- a/languages.toml
+++ b/languages.toml
@@ -287,6 +287,8 @@ typing.triggerChars = ".=<>{(+"
assist.preferSelf = true
checkOnSave = true
diagnostics.enable = true
+diagnostics.experimental.enable = true
+diagnostics.styleLints.enable = true
semanticHighlighting.punctuation.separate.macroBang = true
semanticHighlighting.punctuation.specialization.enable = true
semanticHighlighting.punctuation.enable = true
diff --git a/src/act.rs b/src/act.rs
index d35cd3a..0428ddb 100644
--- a/src/act.rs
+++ b/src/act.rs
@@ -1,7 +1,8 @@
use dsb::Cell;
use dsb::cell::Style;
use itertools::Itertools;
-use lsp_types::{CodeAction, CodeActionKind};
+use lsp_types::CodeActionKind;
+use rust_analyzer::lsp::ext::CodeAction;
#[derive(Debug, Clone)]
pub enum N<T> {
@@ -165,14 +166,15 @@ fn write(x: &CodeAction, c: usize, selected: bool, to: &mut Vec<Cell>) {
vec![Cell { style: Style::new(FG, bg), ..Default::default() }; c];
let t = match &x.kind {
- Some(x) if x == &CodeActionKind::QUICKFIX => '󰁨',
- Some(x)
- if x == &CodeActionKind::REFACTOR
- || x == &CodeActionKind::REFACTOR_EXTRACT
- || x == &CodeActionKind::REFACTOR_INLINE
- || x == &CodeActionKind::REFACTOR_REWRITE =>
- '󰷥',
- Some(x) if x == &CodeActionKind::SOURCE => '󱇧',
+ Some(CodeActionKind::QuickFix) => '󰁨',
+ Some(
+ CodeActionKind::Refactor
+ | CodeActionKind::RefactorExtract
+ | CodeActionKind::RefactorInline
+ | CodeActionKind::RefactorRewrite
+ | CodeActionKind::RefactorMove,
+ ) => '󰷥',
+ Some(CodeActionKind::Source) => '󱇧',
_ => '', /* 󱢇☭ */
};
into[0].style.fg = col!("#E5C07B");
diff --git a/src/bar.rs b/src/bar.rs
index c4d9009..bc80da0 100644
--- a/src/bar.rs
+++ b/src/bar.rs
@@ -1,9 +1,11 @@
use std::iter::{chain, repeat};
+use std::sync::Arc;
use dsb::Cell;
use dsb::cell::Style;
-use lsp_types::WorkDoneProgress;
+use crate::killring::KillRM;
+use crate::lsp::communication::WorkDoneProgress;
use crate::lsp::{Client, Rq};
use crate::rnd::simplify_path;
use crate::sym::Symbols;
@@ -23,7 +25,7 @@ impl Bar {
fname: &str,
state: &super::State,
_t: &TextArea,
- lsp: Option<&Client>,
+ lsp: Option<Arc<Client>>,
) {
let fname = simplify_path(fname);
let row = &mut into[oy * w..oy * w + w];
@@ -128,6 +130,19 @@ impl Bar {
}
});
}
+ State::KillRing(KillRM { tedit, .. }) => {
+ "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()
@@ -164,6 +179,12 @@ impl Bar {
x.letter = Some(c);
});
}
+ State::GoToL(x) => format!("list of {}", x.name())
+ .chars()
+ .zip(row)
+ .for_each(|(c, x)| {
+ x.letter = Some(c);
+ }),
State::Save => unreachable!(),
_ => {}
}
diff --git a/src/commands.rs b/src/commands.rs
index 1273cfe..b020c22 100644
--- a/src/commands.rs
+++ b/src/commands.rs
@@ -11,7 +11,7 @@ use lsp_types::*;
use rootcause::{bail, report};
use rust_analyzer::lsp::ext::*;
-use crate::FG;
+use crate::edi::lsp_mn::LSPM;
use crate::edi::{Editor, lsp};
use crate::gotolist::{At, GoToList};
use crate::lsp::{PathURI, Rq, tdpp};
@@ -19,6 +19,7 @@ use crate::menu::charc;
use crate::menu::generic::{CorA, GenericMenu, MenuData};
use crate::sym::GoTo;
use crate::text::{Bookmark, RopeExt, SortTedits, TextArea, col, color_};
+use crate::{FG, KillRing};
macro_rules! repl {
($x:ty, $($with:tt)+) => {
@@ -115,6 +116,10 @@ commands!(
@ Incoming: "callers-of",
/// Functions this function calls
@ Outgoing: "calling",
+ /// loads up the kill ring
+ | KillRing: "killring",
+ /// Reloads the file from disk.
+ | Reload: "reload",
// /// View child modules
// @ ViewChildModules: "child-modules",
/// GoTo line,
@@ -129,6 +134,7 @@ commands!(
pub enum Cmds {}
impl MenuData for Cmds {
+ const NAME: &'static str = "commands";
const HEIGHT: usize = 30;
type Data = ();
type Element<'a> = Cmd;
@@ -222,6 +228,8 @@ impl Editor {
&mut self,
z: Cmd,
w: Arc<dyn winit::window::Window>,
+ kr: &mut KillRing,
+ lsp_mn: &mut LSPM,
) -> rootcause::Result<()> {
match z {
Cmd::GoTo(Some(x)) =>
@@ -271,7 +279,19 @@ impl Editor {
..default()
});
}
- z if z.needs_lsp() => return self.handle_lsp_command(z, w),
+ Cmd::KillRing => {
+ self.state = crate::edi::st::State::KillRing(
+ crate::killring::KillRM {
+ data: kr.clone(),
+ tedit: default(),
+ selection: 0,
+ vo: 0,
+ },
+ );
+ }
+ Cmd::Reload => self.reload(),
+ z if z.needs_lsp() =>
+ return self.handle_lsp_command(z, w, lsp_mn),
x => unimplemented!("{x:?}"),
}
@@ -281,6 +301,7 @@ impl Editor {
&mut self,
z: Cmd,
w: Arc<dyn winit::window::Window>,
+ lsp_mn: &mut LSPM,
) -> rootcause::Result<()> {
let Some((l, o)) = lsp!(self + p) else {
bail!("no lsp");
@@ -291,7 +312,7 @@ impl Editor {
.text
.to_l_position(*self.text.cursor.first())
.unwrap();
- let mut x = l.request_immediate::<rust_analyzer::lsp::ext::MoveItem>(&MoveItemParams {
+ let mut x = l.request_immediate::<rust_analyzer::lsp::ext::MoveItemRequest>(&MoveItemParams {
direction: if let Cmd::RAMoveIU = z { MoveItemDirection::Up } else { MoveItemDirection::Down },
text_document: o.tid(),
range: Range { start : r, end : r},
@@ -303,11 +324,11 @@ impl Editor {
}
}
Cmd::RARestart => {
- _ = l.request::<ReloadWorkspace>(&())?.0;
+ _ = l.request::<ReloadWorkspaceRequest>(&())?.0;
}
Cmd::RAParent => {
- let Some(GotoDefinitionResponse::Link([ref x])) =
- l.request_immediate::<ParentModule>(
+ let Some(DefinitionResponse::DefinitionLinkList([ref x])) =
+ l.request_immediate::<ParentModuleRequest>(
&TextDocumentPositionParams {
text_document: o.tid(),
position: self
@@ -320,11 +341,11 @@ impl Editor {
self.bar.last_action = "no such parent".into();
return Ok(());
};
- self.go(x, w)?;
+ self.go(x, w, lsp_mn)?;
}
Cmd::RAJoinLines => {
- let teds =
- l.request_immediate::<JoinLines>(&JoinLinesParams {
+ let teds = l.request_immediate::<JoinLinesRequest>(
+ &JoinLinesParams {
ranges: self
.text
.cursor
@@ -336,13 +357,14 @@ impl Editor {
})
.collect(),
text_document: o.tid(),
- })?;
+ },
+ )?;
self.text
.apply_tedits(&mut { teds })
.map_err(|_| report!("couldnt apply edits"))?;
}
Cmd::RADocs => {
- let u = l.request_immediate::<ExternalDocs>(
+ let u = l.request_immediate::<ExternalDocsRequest>(
&TextDocumentPositionParams {
position: self
.text
@@ -384,18 +406,19 @@ impl Editor {
.unwrap();
}
Cmd::RARebuildProcMacros => {
- _ = l.request::<RebuildProcMacros>(&())?;
+ _ = l.request::<RebuildProcMacrosRequest>(&())?;
}
- Cmd::RACancelFlycheck => l.notify::<CancelFlycheck>(&())?,
+ Cmd::RACancelFlycheck =>
+ l.notify::<CancelFlycheckNotification>(&())?,
Cmd::RAOpenCargoToml => {
- let Some(GotoDefinitionResponse::Scalar(x)) =
- &l.request_immediate::<OpenCargoToml>(
+ let Some(DefinitionResponse::Definition(x)) =
+ &l.request_immediate::<OpenCargoTomlRequest>(
&OpenCargoTomlParams { text_document: o.tid() },
)?
else {
bail!("wtf?");
};
- self.go(x, w)?;
+ self.go(x, w, lsp_mn)?;
}
Cmd::RARunnables => {
let p = self.text.to_l_position(*self.text.cursor.first());
@@ -415,7 +438,8 @@ impl Editor {
..default()
}),
Cmd::Incoming => {
- let x = l.runtime.spawn(l.callers(tdpp!(self)));
+ let l2 = l.clone();
+ let x = l.runtime.spawn(l2.callers(tdpp!(self)));
self.state = crate::edi::st::State::GoToL(GoToList {
data: (
vec![],
@@ -425,7 +449,8 @@ impl Editor {
});
}
Cmd::Outgoing => {
- let x = l.runtime.spawn(l.calling(tdpp!(self)));
+ let l2 = l.clone();
+ let x = l.runtime.spawn(l2.calling(tdpp!(self)));
self.state = crate::edi::st::State::GoToL(GoToList {
data: (
vec![],
diff --git a/src/complete.rs b/src/complete.rs
index 81c9c2f..3ab13d3 100644
--- a/src/complete.rs
+++ b/src/complete.rs
@@ -63,8 +63,8 @@ fn filter_c<'a>(
) -> impl Iterator<Item = &'a CompletionItem> {
let x = &completion.r;
let y = match x {
- CompletionResponse::Array(x) => x,
- CompletionResponse::List(x) => &x.items,
+ CompletionResponse::CompletionItemList(x) => x,
+ CompletionResponse::CompletionList(x) => &x.items,
};
filter(y.iter(), f)
}
@@ -82,7 +82,9 @@ pub fn s(completion: &Complete, c: usize, f: &str) -> Vec<Cell> {
});
out
-}
+}pub const fn i<T:Copy>(x: T) -> usize {
+ (unsafe { *<*const _>::from(&x).cast::<u32>() }) as usize
+ }
#[implicit_fn::implicit_fn]
fn r(
x: &CompletionItem,
@@ -96,34 +98,36 @@ fn r(
let ds = Style::new(FG, bg);
let d: Cell = Cell { letter: None, style: ds };
let mut b = vec![d; c];
+
const MAP: [([u8; 3], [u8; 3], &str); 26] = {
(
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"),
+ const { i(CompletionItemKind::Text) } => ("#9a9b9a", " "),
+ const { i(CompletionItemKind::Method) } | const { i(CompletionItemKind::Function) } => ("#FFD173", "λ "),
+ const { i(CompletionItemKind::Constructor) } => ("#FFAD66", "->"),
+ const { i(CompletionItemKind::Field) } => ("#E06C75", "x."),
+ const { i(CompletionItemKind::Variable) } => ("#E06C75", "x "),
+ const { i(CompletionItemKind::Module) } => ("#D5FF80", "::"),
+ const { i(CompletionItemKind::Property) } => ("#e6e1cf", "x."),
+ const { i(CompletionItemKind::Value) } => ("#DFBFFF", "4 "),
+ const { i(CompletionItemKind::Enum) } => ("#73b9ff", "󰓹u"),
+ const { i(CompletionItemKind::EnumMember) } => ("#73b9ff", "󰓹:"),
+ const { i(CompletionItemKind::Snippet) } => ("#9a9b9a", "! "),
+ const { i(CompletionItemKind::Interface) } => ("#E5C07B", "t "),
+ const { i(CompletionItemKind::Reference) } => ("#9a9b9a", "& "),
+ const { i(CompletionItemKind::Constant) } => ("#DFBFFF", "N "),
+ const { i(CompletionItemKind::Struct) } => ("#73D0FF", "X{"),
+ const { i(CompletionItemKind::Operator) } => ("#F29E74", "+ "),
+ const { i(CompletionItemKind::TypeParameter) } => ("#9a9b9a", "T "),
+ const { i(CompletionItemKind::Keyword) } => ("#FFAD66", "as"),
+
_ => ("#9a9b9a", " ")
}).map(const
|(x, y)| (set_a(color_(x), 0.5), color_(x), y),
)
};
let (bgt, col, ty) =
- MAP[x.kind.unwrap_or(CompletionItemKind(25)).0 as usize];
+ MAP[i(x.kind.unwrap_or(CompletionItemKind::Text))];
b.iter_mut().zip(ty.chars()).for_each(|(x, c)| {
*x = (Style::new(col, bgt) | Style::BOLD).basic(c)
});
@@ -159,20 +163,30 @@ fn r(
}))
.for_each(|(a, b)| *a = b);
}
+ let s = if let Some(ref ft) = x.filter_text
+ && &x.label != ft
+ // l = &x
+ // ft = x
+ && let Some(e) = x.label.find(ft)
+ {
+ -(e as i32)
+ } else {
+ 0
+ };
i.iter_mut()
.zip(
- x.label.chars().map(|x| ds.basic(x)).zip(0..).chain(
+ x.label.chars().map(|x| ds.basic(x)).zip(s..).chain(
label_details
.map(|x| {
Style { bg, fg: color_("#858685"), ..default() }
.basic(x)
})
- .zip(repeat(u32::MAX)),
+ .zip(repeat(i32::MAX)),
),
)
.for_each(|(a, (b, i))| {
*a = b;
- if indices.contains(&i) {
+ if indices.contains(&(i as u32)) {
a.style |= (Style::BOLD, color_("#ffcc66"));
}
});
@@ -224,16 +238,16 @@ impl Editor {
let sel = x.sel(&crate::filter(&self.text));
let sel = lsp.resolve(sel.clone()).unwrap();
let CompletionItem {
- text_edit: Some(CompletionTextEdit::Edit(ed)),
+ text_edit: Some(CompletionItemTextEdit::TextEdit(ed)),
additional_text_edits,
insert_text_format,
..
} = sel.clone()
else {
- panic!()
+ return;
};
match insert_text_format {
- Some(InsertTextFormat::SNIPPET) => {
+ Some(InsertTextFormat::Snippet) => {
self.text.apply_snippet(&ed).unwrap();
}
_ => {
diff --git a/src/edi.rs b/src/edi.rs
index d648885..9d01fb8 100644
--- a/src/edi.rs
+++ b/src/edi.rs
@@ -1,24 +1,21 @@
use std::collections::HashMap;
use std::ffi::OsString;
use std::fmt::Debug;
-use std::io::BufReader;
+use std::io::ErrorKind;
use std::mem::take;
use std::path::{Path, PathBuf};
-use std::process::Stdio;
use std::sync::Arc;
use std::time::SystemTime;
use Default::default;
use ftools::Bind;
-use helix_core::syntax::config::FileType;
-use log::info;
-use lsp_server::Connection;
use lsp_types::*;
use regex::Regex;
use rootcause::report;
use ropey::Rope;
use rust_fsm::StateMachine;
use tokio::sync::oneshot::Sender;
+use tree_house::Language;
use winit::keyboard::NamedKey;
use winit::window::Window;
@@ -26,6 +23,7 @@ mod input_handlers;
pub use input_handlers::handle2;
mod lsp_impl;
+pub mod lsp_mn;
mod ra;
pub mod st;
mod wsedit;
@@ -35,6 +33,7 @@ use st::*;
use crate::bar::Bar;
use crate::commands::Cmds;
+use crate::edi::lsp_mn::LSPM;
use crate::error::WDebug;
use crate::gotolist::{At, GoTo};
use crate::hov::{self, HOV_HEIGHT, Hovr, Hovring, Rendered};
@@ -49,8 +48,8 @@ use crate::text::cursor::{Ronge, ceach};
use crate::text::hist::{ClickHistory, Hist};
use crate::text::{LOADER, Mapping, RopeExt, SortTedits, TextArea};
use crate::{
- BoolRequest, CDo, CompletionAction, CompletionState, alt, ctrl,
- filter, hash, shift, sym, trm,
+ BoolRequest, CDo, CompletionAction, CompletionState, Freq, KillRing,
+ alt, ctrl, filter, hash, shift, sym,
};
impl Debug for Editor {
@@ -61,13 +60,18 @@ impl Debug for Editor {
.field("origin", &self.origin)
.field("state", &self.state.name())
.field("bar", &self.bar)
- .field("workspace", &self.workspace)
.field("hist", &self.hist)
.field("mtime", &self.mtime)
.finish()
}
}
-
+#[derive(
+ Default, serde_derive::Serialize, serde_derive::Deserialize, Debug,
+)]
+pub struct Edithin {
+ pub files: HashMap<PathBuf, Edithin>,
+ pub mtime: Option<std::time::SystemTime>,
+}
#[derive(Default, serde_derive::Serialize, serde_derive::Deserialize)]
pub struct Editor {
pub files: HashMap<PathBuf, Editor>,
@@ -77,14 +81,11 @@ pub struct Editor {
pub state: State,
#[serde(skip)]
pub bar: Bar,
- pub workspace: Option<PathBuf>,
+ // pub workspace: Option<PathBuf>,
+ #[serde(skip)]
pub git_dir: Option<PathBuf>,
#[serde(skip)]
- pub lsp: Option<(
- &'static Client,
- std::thread::JoinHandle<()>,
- Option<Sender<Arc<dyn Window>>>,
- )>,
+ pub lsp: Option<(Arc<Client>, Option<Sender<Arc<dyn Window>>>)>,
// #[serde(skip)]
pub requests: Requests,
#[serde(skip)]
@@ -98,9 +99,13 @@ pub struct Editor {
// pub git_diff:
// Option<std::rc::Rc<std::cell::RefCell<imara_diff::Diff>>>,
}
+
macro_rules! lsp {
+ (&$self:ident) => {
+ $self.lsp.as_ref().map(|(x,..)| x)
+ };
($self:ident) => {
- $self.lsp.as_ref().map(|(x, ..)| *x)
+ $self.lsp.as_ref().map(|(x, ..)| x.clone())
};
($self:ident + p) => {
$crate::edi::lsp!($self).zip($self.origin.as_deref())
@@ -112,6 +117,13 @@ macro_rules! lsp {
return $($else)?;
};
};
+ (let $lsp:ident = $self:ident $(else $else:expr)?) => {
+ let Some($lsp) =
+ $crate::edi::lsp!($self)
+ else {
+ return $($else)?;
+ };
+ };
}
pub(crate) use lsp;
macro_rules! inlay {
@@ -171,170 +183,237 @@ macro_rules! change {
}
pub(crate) use change;
-fn rooter(
+fn rooter_(
x: &Path,
mut search: impl FnMut(OsString) -> bool + Clone,
-) -> Option<PathBuf> {
- for f in std::fs::read_dir(&x).ok()?.filter_map(Result::ok) {
+ whilst: impl for<'a> FnMut(&&'a Path) -> bool + Clone,
+ found: &mut Vec<PathBuf>,
+) {
+ let Some(d) = std::fs::read_dir(&x).ok() else { return };
+ for f in d.filter_map(Result::ok) {
if search(f.file_name()) {
- return Some(f.path().with_file_name("").to_path_buf());
+ found.push(f.path().with_file_name("").to_path_buf());
}
}
- x.parent().and_then(rooter.rbind(search))
+ x.parent()
+ .filter(whilst.clone())
+ .map(|x| rooter_(x, search, whilst, found));
}
-impl Editor {
- pub fn new() -> rootcause::Result<Self> {
- let mut me = Self::default();
+fn rooter(
+ x: &Path,
+ search: impl FnMut(OsString) -> bool + Clone,
- let o = std::env::args()
+ whilst: impl for<'a> FnMut(&&'a Path) -> bool + Clone,
+) -> Option<PathBuf> {
+ let mut v = vec![];
+ rooter_(x, search, whilst, &mut v);
+ v.try_remove(v.len().checked_sub(1)?)
+}
+
+impl Editor {
+ pub fn new(
+ lsp_mn: &mut LSPM,
+ ) -> rootcause::Result<(Self, Freq, KillRing)> {
+ let mut o = std::env::args()
.nth(1)
.and_then(|x| PathBuf::try_from(x).ok())
- .and_then(|x| x.canonicalize().ok());
+ .and_then(|x| {
+ x.canonicalize()
+ .inspect_err(|_| {
+ _ = std::fs::File::create(&x);
+ })
+ .ok()
+ .or_else(|| x.canonicalize().ok())
+ .or(Some(x))
+ })
+ .or_else(|| {
+ rfd::FileDialog::new()
+ .set_can_create_directories(true)
+ .set_title("pick dir to open")
+ .pick_folder()
+ });
+ if let Some(x) = &o {
+ match std::fs::read_to_string(x)
+ .map(|x| x.replace("\r\n", "\n"))
+ {
+ Ok(_) => {}
+ Err(e)
+ if e.kind() == ErrorKind::IsADirectory
+ && let h = hash(&x)
+ && let cf = cfgdir().join(format!("{h:x}"))
+ && let at = cf.join(SSTORE)
+ && at.exists() =>
+ {
+ let x = std::fs::read(at)?;
+ let x = bendncode::from_bytes::<Edithin>(&x)?;
+ o = Some(
+ x.files
+ .iter()
+ .max_by_key(|(_, x)| x.mtime)
+ .map(ttools::fst)
+ .expect("file")
+ .clone(),
+ );
+ }
+ Err(e) if e.kind() == ErrorKind::IsADirectory =>
+ o = rfd::FileDialog::new()
+ .set_directory(x)
+ .set_can_create_directories(true)
+ .set_title("pick file in project to open")
+ .pick_file(),
+ Err(e) => {
+ eprintln!("path could not be opened: {e}");
+ std::process::exit(5);
+ }
+ }
+ };
+ Editor::new_for(o, lsp_mn)
+ }
- if let Some(x) = std::env::args().nth(1) {
- me.text.insert(&std::fs::read_to_string(x)?);
+ pub fn upto(&self) -> impl std::ops::Fn(&&Path) -> bool + Clone {
+ let upto = self
+ .git_dir
+ .clone()
+ .or(std::env::current_dir().ok())
+ .unwrap_or(PathBuf::from("/home/"));
+ move |x: &&Path| x.starts_with(&upto)
+ }
+
+ pub fn root_for(&self, o: &Path, l: Language) -> Option<PathBuf> {
+ let l = LOADER.language(l).config();
+
+ o.parent()
+ .and_then(|x| rooter(&x, |f| l.roots.is_match(f), self.upto()))
+ .or(std::env::current_dir().ok())
+ .and_then(|x| x.canonicalize().ok())
+ }
+ pub fn vsc(&self) -> Option<serde_json::Value> {
+ self.origin
+ .as_ref()
+ .and_then(|x| x.parent())
+ .and_then(|x| rooter(&x, |x| x == ".vscode", self.upto()))
+ .map(|x| (x.clone(), x.join(".vscode").join("settings.json")))
+ .filter(|x| x.1.exists())
+ .and_then(|(ws, x)| vsc_settings::load(&x, &ws).ok())
+ }
+ pub fn load_lsp(&mut self, lsp_mn: &mut LSPM) {
+ self.language = self
+ .origin
+ .as_deref()
+ .and_then(|o| LOADER.language_for_filename(o));
+ let ws = self
+ .origin
+ .as_deref()
+ .zip(self.language)
+ .and_then(|(p, l)| self.root_for(p, l));
+ let l = ws
+ .as_ref()
+ .zip(self.language)
+ .and_then(|(w, ln)| lsp_mn.load(w, ln, self.vsc()));
+ self.lsp = l;
+ }
+ pub fn new_for(
+ o: Option<PathBuf>,
+ lsp_mn: &mut LSPM,
+ ) -> rootcause::Result<(Self, Freq, KillRing)> {
+ let mut me = Self::default();
+ if let Some(o) = o.as_deref()
+ && let o = std::fs::read_to_string(o)
+ .map(|x| x.replace("\r\n", "\n"))
+ .unwrap()
+ {
+ me.text.insert(&o);
me.text.cursor = default();
- };
+ }
let n = o.as_deref().and_then(|o| LOADER.language_for_filename(o));
me.language = n;
- let l =
- n.map(|n| LOADER.languages().nth(n.idx()).unwrap().1.config());
- me.workspace = o
- .as_ref()
- .and_then(|x| x.parent())
+ let l = n.map(|n| LOADER.language(n).config());
+ me.git_dir = o
+ .as_deref()
.and_then(|x| {
- l.and_then(|l| rooter(&x, |f| l.roots.is_match(f)))
+ x.ancestors()
+ .find(|x| x.join(".git").exists())
+ .map(PathBuf::from)
})
- .or(std::env::current_dir().ok())
.and_then(|x| x.canonicalize().ok());
- let vsc = o
- .as_ref()
- .and_then(|x| x.parent())
- .and_then(|x| rooter(&x, |x| x == ".vscode"))
- .map(|x| (x.clone(), x.join(".vscode").join("settings.json")))
- .filter(|x| x.1.exists())
- .and_then(|(ws, x)| (vsc_settings::load(&x, &ws)).ok());
+ let ws = o.as_deref().zip(n).and_then(|(p, l)| me.root_for(p, l));
let mut loaded_state = false;
- if let Some(ws) = me.workspace.as_deref()
+ let mut freq = default();
+ let mut kr = default();
+ if let Some(ws) = ws.as_deref()
&& let h = hash(&ws)
- && let at = cfgdir().join(format!("{h:x}")).join(STORE)
+ && let cf = cfgdir().join(format!("{h:x}"))
+ && let at = cf.join(SSTORE)
&& at.exists()
{
+ println!("loaded ");
let x = std::fs::read(at)?;
- let x = bendy::serde::from_bytes::<Editor>(&x)?;
+ let x = bendncode::from_bytes::<Editor>(&x)?;
+ let gd = me.git_dir.take();
me = x;
+ me.git_dir = gd;
loaded_state = true;
- assert!(me.workspace.is_some());
+ // assert!(me.workspace.is_some());
+ if let at = cf.join(FSTORE)
+ && at.exists()
+ {
+ let x = std::fs::read(at)?;
+ freq = bendncode::from_bytes::<Freq>(&x)?;
+ }
+ if let at = cf.join(KSTORE)
+ && at.exists()
+ {
+ let x = std::fs::read(at)?;
+ kr = bendncode::from_bytes::<KillRing>(&x)?;
+ }
}
+ println!("set git dir {:?}", &me.git_dir);
me.language = n;
- me.git_dir = me
- .workspace
- .as_deref()
- .and_then(|x| rooter(&x, |x| x == ".git"))
- .and_then(|x| x.canonicalize().ok());
me.origin = o;
- me.tree = me.workspace.as_ref().map(|x| {
- walkdir::WalkDir::new(x)
- .into_iter()
- .flatten()
- .filter(|x| {
- let x = x.path();
- l.is_some_and(|l| {
- l.file_types.iter().any(|y| match y {
- FileType::Extension(e) =>
- x.extension().is_some_and(|x| x == &**e),
- FileType::Glob(glob) =>
- glob.compile_matcher().is_match(x),
- })
- })
- })
- .map(|x| x.path().to_owned())
- .collect::<Vec<_>>()
- });
- let l = me.workspace.as_ref().zip(l).map(|(workspace, l)| {
- let (Connection { sender, receiver }, conf) = if l.language_id
- == "rust"
- {
- super let (_jh, a) = ra::ra(workspace.clone());
- (
- a,
- (
- &LOADER.language_server_configs()["rust-analyzer"],
- &l.language_servers[0],
- ),
- )
- } else {
- let (mut c, conf) = l
- .language_servers
- .iter()
- .find_map(|l| {
- let lc = LOADER
- .language_server_configs()
- .get(&l.name)?;
- std::process::Command::new(&lc.command)
- .args(&lc.args)
- .stdin(Stdio::piped())
- .stdout(Stdio::piped())
- .stderr(Stdio::inherit())
- .spawn()
- .ok()
- .zip(Some((lc, l)))
- })
- .ok_or(report!(
- "no lsp for this language; install one of {:?}",
- l.language_servers
- ))
- .unwrap();
- super let (x, _iot) =
- Connection::stdio(
- BufReader::new(c.stdout.take().unwrap()),
- c.stdin.take().unwrap(),
- );
- (x, conf)
- };
- info!("spawned {conf:?}");
- let (c, t2, changed) = crate::lsp::run(
- (sender, receiver),
- WorkspaceFolder {
- uri: Url::from_file_path(&workspace).unwrap(),
- name: workspace
- .file_name()
- .unwrap()
- .to_string_lossy()
- .into_owned(),
- },
- vsc,
- conf,
- )
- .unwrap();
- (&*Box::leak(Box::new(c)), (t2), Some(changed))
- });
+ // me.tree = ws.as_ref().map(|x| {
+ // walkdir::WalkDir::new(x)
+ // .into_iter()
+ // .flatten()
+ // .filter(|x| {
+ // let x = x.path();
+ // l.is_some_and(|l| {
+ // l.file_types.iter().any(|y| match y {
+ // FileType::Extension(e) =>
+ // x.extension().is_some_and(|x| x == &**e),
+ // FileType::Glob(glob) =>
+ // glob.compile_matcher().is_match(x),
+ // })
+ // })
+ // })
+ // .map(|x| x.path().to_owned())
+ // .collect::<Vec<_>>()
+ // });
+
let g = me.git_dir.clone();
if let Some(o) = me.origin.clone()
&& loaded_state
{
- let w = me.workspace.clone();
- let la = me.language;
- let t = me.tree.clone();
- assert!(me.files.len() != 0);
- me.open_or_restore(&o, l, la, None, w)?;
- me.git_dir = g;
- me.tree = t;
+ if me.files.len() != 0 {
+ log::error!(
+ "too many files? {:?}",
+ me.files.keys().collect::<Vec<_>>()
+ );
+ }
+ me.open_or_restore(&o, g, None, lsp_mn)?;
me.language = n;
} else {
- me.lsp = l;
+ me.load_lsp(lsp_mn);
me.hist.lc = me.text.cursor.clone();
me.hist.last = me.text.changes.clone();
- if let Some(((c, ..), origin)) =
- me.lsp.as_ref().zip(me.origin.as_deref())
- {
+ if let Some((c, origin)) = lsp!(me + p) {
c.open(
&origin,
- std::fs::read_to_string(&origin)?,
+ std::fs::read_to_string(&origin)
+ .map(|x| x.replace("\r\n", "\n"))?,
me.language.unwrap(),
)?;
c.rq_semantic_tokens(
@@ -345,7 +424,7 @@ impl Editor {
}
me.git_dir = g;
me.mtime = Self::modify(me.origin.as_deref());
-
+ me.tree();
// me.hist.last = me.text.clone();
// me.lsp.as_ref().zip(me.origin.as_deref()).map(
// |((x, ..), origin)| {
@@ -358,7 +437,7 @@ impl Editor {
// },
// );
}
- Ok(me)
+ Ok((me, freq, kr))
}
#[must_use = "please apply this"]
@@ -385,7 +464,8 @@ impl Editor {
self.bar.last_action = "saved".into();
lsp!(self + p).map(|(l, o)| {
if let Ok(fut) = l.format(o)
- && let Ok(Some(v)) = l.runtime.block_on(fut)
+ && let Ok(Ok(Some(v))) =
+ l.by(fut, tokio::time::Duration::from_millis(500))
&& let Err(x) =
self.text.apply_tedits_adjusting(&mut { v })
{
@@ -472,6 +552,30 @@ impl Editor {
inlay!(self);
}
+ pub fn paste_m<T: AsRef<str>>(
+ &mut self,
+ r: impl Iterator<Item = T> + DoubleEndedIterator + ExactSizeIterator,
+ ) {
+ // let bounds = unsafe { &*META.splits };
+ // let pieces = bounds.windows(2).map(|w| unsafe {
+ // std::str::from_utf8_unchecked(&r.as_bytes()[w[0]..w[1]])
+ // });
+ if r.len() == self.text.cursor.iter().len() {
+ for (piece, cursor) in
+ r.rev().zip(0..self.text.cursor.iter().count())
+ {
+ let c = self.text.cursor.iter().nth(cursor).unwrap();
+ self.text.insert_at(*c, piece.as_ref()).unwrap();
+ }
+ } else {
+ let new = r
+ .fold(String::default(), |acc, x| acc + x.as_ref() + "\n");
+
+ // vscode behaviour: insane?
+ self.text.insert(&new);
+ eprintln!("hrmst");
+ }
+ }
pub fn paste(&mut self) {
self.hist.push_if_changed(&mut self.text);
let r = clipp::paste();
@@ -480,19 +584,7 @@ impl Editor {
let pieces = bounds.windows(2).map(|w| unsafe {
std::str::from_utf8_unchecked(&r.as_bytes()[w[0]..w[1]])
});
- if unsafe { META.count } == self.text.cursor.iter().len() {
- for (piece, cursor) in
- pieces.zip(0..self.text.cursor.iter().count())
- {
- let c = self.text.cursor.iter().nth(cursor).unwrap();
- self.text.insert_at(*c, piece).unwrap();
- }
- } else {
- let new = pieces.intersperse("\n").collect::<String>();
- // vscode behaviour: insane?
- self.text.insert(&new);
- eprintln!("hrmst");
- }
+ self.paste_m(pieces);
} else {
self.text.insert(&clipp::paste());
}
@@ -504,6 +596,7 @@ impl Editor {
&mut self,
x: &Path,
w: Arc<dyn Window>,
+ lsp_mn: &mut LSPM,
) -> rootcause::Result<()> {
let x = x.canonicalize()?.to_path_buf();
if Some(&*x) == self.origin.as_deref() {
@@ -511,91 +604,99 @@ impl Editor {
return Ok(());
}
let r = self.text.r;
- let ws = self.workspace.clone();
- let git_dir = self.workspace.clone();
- let tree = self.tree.clone();
- let lsp = self.lsp.take();
- let l = self.language;
+ // let ws = self.workspace.clone();
+ let git_dir = self.git_dir.clone();
+ // let lsp = self.lsp.take();
let mut me = take(self);
let f = take(&mut me.files);
if let Some(x) = me.origin.clone() {
- lsp.as_ref().map(|l| l.0.close(&x));
+ lsp!(me).as_ref().map(|l| l.close(&x));
self.files.insert(x, me);
self.files.extend(f);
// assert!(f.len() == 0);
}
- self.open_or_restore(&x, lsp, l, Some(w), ws)?;
+ self.open_or_restore(&x, git_dir, Some(w), lsp_mn)?;
self.text.r = r;
- self.tree = tree;
- self.git_dir = git_dir; // maybe it should change? you know. sometimes?
Ok(())
}
+ fn restore(
+ &mut self,
+ git_dir: Option<PathBuf>,
+ // lsp: Option<(Arc<Client>, Option<Sender<Arc<dyn Window>>>)>,
+ // l: Option<helix_core::Language>,
+ with: Editor,
+ lsp_mn: &mut LSPM,
+ ) -> rootcause::Result<()> {
+ let f = take(&mut self.files);
+
+ *self = with;
+ assert!(self.files.len() == 0);
+ self.files = f;
+ self.bar.last_action = "restored".into();
+ if self.mtime != Self::modify(self.origin.as_deref()) {
+ self.hist.push_if_changed(&mut self.text);
+ self.text.rope = Rope::from_str(
+ &std::fs::read_to_string(
+ self.origin
+ .as_ref()
+ .ok_or(report!("origin missing"))?,
+ )
+ .map(|x| x.replace("\r\n", "\n"))
+ .unwrap(),
+ );
+
+ self.text.cursor.first_mut().position = self
+ .text
+ .cursor
+ .first()
+ .position
+ .min(self.text.rope.len_chars());
+ self.mtime = Self::modify(self.origin.as_deref());
+ self.bar.last_action = "restored -> reloaded".into();
+ take(&mut self.requests);
+ self.hist.push(&mut self.text)
+ }
+ self.git_dir = git_dir;
+ self.load_lsp(lsp_mn);
+
+ if let Some((x, origin)) = lsp!(self + p) {
+ x.open(
+ &origin,
+ self.text.rope.to_string(),
+ self.language.unwrap(),
+ )?;
+ }
+ Ok(())
+ }
fn open_or_restore(
&mut self,
x: &Path,
- lsp: Option<(
- &'static Client,
- std::thread::JoinHandle<()>,
- Option<Sender<Arc<dyn Window>>>,
- )>,
- l: Option<helix_core::Language>,
+ git_dir: Option<PathBuf>,
+ // lsp: Option<(Arc<Client>, Option<Sender<Arc<dyn Window>>>)>,
+ // l: Option<helix_core::Language>,
w: Option<Arc<dyn Window>>,
- ws: Option<PathBuf>,
+ lsp_mn: &mut LSPM,
+ // ws: Option<PathBuf>,
) -> rootcause::Result<()> {
if let Some(x) = self.files.remove(x) {
- let f = take(&mut self.files);
-
- *self = x;
- assert!(self.files.len() == 0);
- self.files = f;
- self.bar.last_action = "restored".into();
- if self.mtime != Self::modify(self.origin.as_deref()) {
- self.hist.push_if_changed(&mut self.text);
- self.text.rope = Rope::from_str(
- &std::fs::read_to_string(
- self.origin
- .as_ref()
- .ok_or(report!("origin missing"))?,
- )
- .unwrap(),
- );
-
- self.text.cursor.first_mut().position = self
- .text
- .cursor
- .first()
- .position
- .min(self.text.rope.len_chars());
- self.mtime = Self::modify(self.origin.as_deref());
- self.bar.last_action = "restored -> reloaded".into();
- take(&mut self.requests);
- self.hist.push(&mut self.text)
- }
- self.lsp = lsp;
- self.language = l;
- if let Some((x, origin)) = lsp!(self + p) {
- x.open(
- &origin,
- self.text.rope.to_string(),
- self.language.unwrap(),
- )?;
- }
+ self.restore(git_dir, x, lsp_mn)?
} else {
- self.workspace = ws;
+ // self.workspace = ws;
self.origin = Some(x.to_path_buf());
- let new = std::fs::read_to_string(&x)?;
+ let new = std::fs::read_to_string(&x)
+ .map(|x| x.replace("\r\n", "\n"))?;
take(&mut self.text);
self.text.insert(&new);
take(&mut self.text.changes);
self.text.cursor.just(0, &self.text.rope);
self.bar.last_action = "open".into();
self.mtime = Self::modify(self.origin.as_deref());
- self.lsp = lsp;
- self.language = l;
+ self.git_dir = git_dir;
+ self.load_lsp(lsp_mn);
if let Some((ls, origin)) = lsp!(self + p) {
take(&mut self.requests);
@@ -607,9 +708,30 @@ impl Editor {
.peel()?;
}
}
+
+ self.tree();
self.set_title(w);
Ok(())
}
+ pub fn tree(&mut self) {
+ fn is_hidden(entry: &walkdir::DirEntry) -> bool {
+ entry
+ .file_name()
+ .to_str()
+ .map(|s| s.starts_with("."))
+ .unwrap_or(false)
+ }
+ self.tree = self.git_dir.as_ref().map(|x| {
+ walkdir::WalkDir::new(x)
+ .into_iter()
+ .filter_entry(|e| !is_hidden(e))
+ .flatten()
+ .filter(|x| !x.path().starts_with("."))
+ .filter(|x| !x.path().is_dir())
+ .map(|x| x.path().to_owned())
+ .collect::<Vec<_>>()
+ });
+ }
pub fn set_title(&self, w: Option<Arc<dyn Window>>) {
if let Some(x) = w
&& let Some(t) = self.title()
@@ -618,22 +740,26 @@ impl Editor {
}
}
pub fn title(&self) -> Option<String> {
- [self.workspace.as_deref(), self.origin.as_deref()]
+ [self.git_dir.as_deref(), self.origin.as_deref()]
.try_map(|x| {
x.and_then(Path::file_name).and_then(|x| x.to_str())
})
.map(|[wo, or]| format!("gracilaria - {wo} - {or}"))
}
- pub fn store(&mut self) -> rootcause::Result<()> {
- let ws = self.workspace.clone();
+ pub fn store(
+ &mut self,
+ fq: &Freq,
+ kr: &KillRing,
+ ) -> rootcause::Result<()> {
+ // let ws = self.workspace.clone();
let tree = self.tree.clone();
let mtime = self.mtime.clone();
let origin = self.origin.clone();
- if let Some(w) = self.workspace.clone() {
+ if let Some(w) = self.git_dir.clone() {
let mut me = take(self);
- self.workspace = ws;
+ // self.workspace = ws;
self.tree = tree;
self.mtime = mtime;
self.origin = origin;
@@ -647,9 +773,13 @@ impl Editor {
let cfgdir = cfgdir();
let p = cfgdir.join(format!("{hash:x}"));
std::fs::create_dir_all(&p)?;
- let b = bendy::serde::to_bytes(&self).unwrap();
- bendy::serde::from_bytes::<Editor>(&b)?;
- std::fs::write(p.join(STORE), &b)?;
+ let b = bendncode::to_bytes(&self)?;
+ bendncode::from_bytes::<Editor>(&b)?;
+ std::fs::write(p.join(SSTORE), &b)?;
+ let b = bendncode::to_bytes(fq)?;
+ std::fs::write(p.join(FSTORE), &b)?;
+ let b = bendncode::to_bytes(kr)?;
+ std::fs::write(p.join(KSTORE), &b)?;
}
Ok(())
}
@@ -658,10 +788,11 @@ impl Editor {
&mut self,
g: impl Into<GoTo<'_>>,
w: Arc<dyn Window>,
+ lsp_mn: &mut LSPM,
) -> rootcause::Result<()> {
let g = g.into();
let f = g.path.canonicalize()?;
- self.open(&f, w.clone())?;
+ self.open(&f, w.clone(), lsp_mn)?;
match g.at {
At::R(r) => {
@@ -697,17 +828,11 @@ fn cfgdir() -> PathBuf {
std::env::var("HOME")
.map(PathBuf::from)
.map(|x| x.join(".config"))
+ .or(std::env::var("AppData").map(PathBuf::from))
})
.unwrap_or("/tmp/".into())
.join("gracilaria")
}
-const STORE: &str = "state.torrent";
-#[track_caller]
-#[allow(dead_code)]
-fn rtt<T: serde::Serialize + serde::Deserialize<'static>>(
- x: &T,
-) -> Result<T, bendy::serde::Error> {
- bendy::serde::from_bytes::<T>(
- bendy::serde::to_bytes(x).unwrap().leak(),
- )
-}
+const SSTORE: &str = "state.bendn";
+const FSTORE: &str = "freq.bendn";
+const KSTORE: &str = "killring.bendn";
diff --git a/src/edi/input_handlers.rs b/src/edi/input_handlers.rs
index 6457787..aa9e6a3 100644
--- a/src/edi/input_handlers.rs
+++ b/src/edi/input_handlers.rs
@@ -8,7 +8,7 @@ use crate::edi::*;
pub fn handle2<'a>(
key: &'a Key,
text: &mut TextArea,
- l: Option<(&Client, &Path)>,
+ l: Option<(Arc<Client>, &Path)>,
) -> Option<&'a str> {
use Key::*;
@@ -58,3 +58,13 @@ pub fn handle2<'a>(
};
None
}
+impl Editor {
+ #[track_caller]
+ pub fn transition(&mut self, a: Action) -> Option<Do> {
+ self.state
+ .consume(a)
+ .inspect_err(|e| log::error!("transition failed: {e}"))
+ .ok()
+ .flatten()
+ }
+}
diff --git a/src/edi/input_handlers/click.rs b/src/edi/input_handlers/click.rs
index d687c60..82ddd2b 100644
--- a/src/edi/input_handlers/click.rs
+++ b/src/edi/input_handlers/click.rs
@@ -11,15 +11,23 @@ impl Editor {
bt: MouseButton,
cursor_position: (usize, usize),
w: Arc<dyn Window>,
+ lsp_mn: &mut LSPM,
) {
- let text = &mut self.text;
_ = self
.requests
.complete
.consume(CompletionAction::Click)
- .unwrap();
- match self.state.consume(Action::M(bt)).unwrap() {
- Some(Do::ClickedHover | Do::MoveCursor) => {
+ .inspect_err(|x| log::error!("transition comact {x:?}"));
+
+ let Some(mut o) = self.transition(Action::M(bt)) else { return };
+ if let Do::Reinsert = o {
+ let Some(o2) = self.transition(Action::M(bt)) else { return };
+ o = o2;
+ };
+
+ let text = &mut self.text;
+ match o {
+ Do::MoveCursor => {
text.cursor.just(
text.mapped_index_at(cursor_position),
&text.rope,
@@ -36,13 +44,13 @@ impl Editor {
text.cursor.first().setc(&text.rope);
self.refresh_document_highlights();
}
- Some(Do::NavForward) => self.nav_forward(),
- Some(Do::NavBack) => self.nav_back(),
- Some(Do::ExtendSelectionToMouse) => {
+ Do::NavForward => self.nav_forward(),
+ Do::NavBack => self.nav_back(),
+ Do::ExtendSelectionToMouse => {
let p = text.mapped_index_at(cursor_position);
text.cursor.first_mut().extend_selection_to(p, &text.rope);
}
- Some(Do::StartSelection) => {
+ Do::StartSelection => {
let p = text.mapped_index_at(cursor_position);
let x = *text.cursor.first();
@@ -50,37 +58,51 @@ impl Editor {
text.cursor.first_mut().extend_selection_to(p, &text.rope);
self.hist.lc = text.cursor.clone();
}
- Some(Do::GoToDefinition(tdpp)) => {
+ Do::GoToDefinition(tdpp) => {
dbg!(&tdpp);
- if let Some(x) = self.requests.def.result.clone().or_else(|| {
- tdpp.zip(lsp!(self)).and_then(|(tdpp, lsp)| {
- lsp.request_immediate::<lsp_request!("textDocument/definition")>(
- &GotoDefinitionParams {
+ if let Some(x) = self.requests.def.result.clone()
+ && let Err(e) = self.go(&x, w.clone(), lsp_mn)
+ {
+ log::error!("gtd: {e}");
+ } else if let Some(x) = {
+ tdpp.zip(lsp!(self)).and_then(|(tdpp, lsp)| {
+ lsp.request_immediate::< lsp_request!("textDocument/definition")>(
+ &DefinitionParams {
text_document_position_params: tdpp,
work_done_progress_params: default(),
partial_result_params: default(),
},
).ok()
}).flatten().and_then(|x| match &x {
- GotoDefinitionResponse::Link([x, ..]) => Some(x.clone()),
+ DefinitionResponse::Definition(Definition::Location(x)) => Some(x.clone()),
+ DefinitionResponse::Definition(Definition::LocationList([x])) => Some(x.clone()),
+ // DefinitionResponse::DefinitionLinkList([x, ..]) => Some(x.clone()),
_ => None,
})
- })
- && let Err(e) = self.go(&x, w.clone())
+ } && let Err(e) = self.go(&x, w.clone(), lsp_mn)
{
log::error!("gtd: {e}");
}
}
- Some(Do::InsertCursorAtMouse) => {
- text.cursor.add(
- text.mapped_index_at(cursor_position),
- &text.rope,
- );
- self.hist.lc = text.cursor.clone();
- self.chist.push(text.primary_cursor());
- text.cursor.first().setc(&text.rope);
+ Do::InsertCursorAtMouse => {
+ let p = text.mapped_index_at(cursor_position);
+
+ let v = (text.cursor.inner.len() != 1)
+ .then(|| {
+ text.cursor
+ .inner
+ .extract_if(.., |x| *x == p)
+ .next()
+ })
+ .flatten();
+ if let None = v {
+ text.cursor.add(p, &text.rope);
+ self.hist.lc = text.cursor.clone();
+ self.chist.push(text.primary_cursor());
+ text.cursor.first().setc(&text.rope);
+ }
}
- None => {}
+
_ => unreachable!(),
}
}
diff --git a/src/edi/input_handlers/cursor.rs b/src/edi/input_handlers/cursor.rs
index 092bc5d..8887045 100644
--- a/src/edi/input_handlers/cursor.rs
+++ b/src/edi/input_handlers/cursor.rs
@@ -3,11 +3,11 @@ use std::sync::Arc;
use Default::default;
use implicit_fn::implicit_fn;
-use lsp_types::request::*;
use lsp_types::*;
use rust_fsm::StateMachine;
use tokio::task::spawn_blocking;
use tokio_util::task::AbortOnDropHandle as DropH;
+use url::Url;
use winit::window::Window;
enum Set<T> {
To(T),
@@ -17,6 +17,7 @@ enum Set<T> {
use crate::edi::*;
use crate::hov::{DiagnosticHovr, Hoverable, Hovring};
use crate::lsp::BehaviourAfter;
+use crate::lsp::communication::send;
use crate::rnd::CellBuffer;
impl Editor {
#[implicit_fn]
@@ -26,7 +27,7 @@ impl Editor {
w: Arc<dyn Window>,
c: usize,
) {
- match self.state.consume(Action::C(cursor_position)).unwrap() {
+ match self.transition(Action::C(cursor_position)) {
Some(Do::ExtendSelectionToMouse) => {
let p = self.text.mapped_index_at(cursor_position);
self.text
@@ -53,9 +54,7 @@ impl Editor {
&& !e.is_whitespace() =>
'out: {
match self
- .state
- .consume(Action::HOnSomething(cursor_position))
- .unwrap()
+ .transition(Action::HOnSomething(cursor_position))
{
Some(Do::SetHovering) => {
let State::Hovering(l) = &mut self.state else {
@@ -109,8 +108,10 @@ impl Editor {
// let l = &mut self.requests.hovering.result;
}
Some(Do::Hover) => {
- self.state.consume(Action::HOnNothing).unwrap();
- w.request_redraw();
+ match self.state.consume(Action::HOnNothing).unwrap() {
+ Some(st::Do::R(false)) => {}
+ _ => w.request_redraw(),
+ }
}
None => {}
x => unreachable!("{x:?}"),
@@ -221,12 +222,15 @@ impl Editor {
.is_none_or(|&(_, x)| x != cursor_position)
{
let handle = lsp.runtime.spawn(
- lsp.request::<lsp_request!("textDocument/definition")>(
- &GotoDefinitionParams {
- text_document_position_params: tdpp.clone(),
- work_done_progress_params: default(),
- partial_result_params: default(),
- },
+ send!(
+ lsp.request,
+ "textDocument/definition",
+ _ {
+ text_document_position_params: tdpp
+ .clone(),
+ work_done_progress_params: default(),
+ partial_result_params: default(),
+ },
)
.unwrap()
.0,
@@ -267,44 +271,42 @@ impl Editor {
let tdp = tdpp.clone();
let l = self.language;
let window = w.clone();
+ let x = lsp.request_::<HoverRequest, { BehaviourAfter::Nil }>(
+ &HoverParams {
+ text_document_position_params: tdp.clone(),
+ work_done_progress_params: default(),
+ },
+ );
let handle: tokio::task::JoinHandle<Result<Option<Hovr>, _>> =
lsp.runtime.spawn(async move {
- let Some(x) = lsp
- .request_::<HoverRequest, { BehaviourAfter::Nil }>(
- &HoverParams {
- text_document_position_params: tdp.clone(),
- work_done_progress_params: default(),
- },
- )?
- .0
- .await?
- else {
+ let Some(x) = x?.0.await? else {
return Ok(None::<Hovr>);
};
let (width, cells) = spawn_blocking(move || {
+ #[allow(deprecated)]
let mut x = match &x.contents {
- lsp_types::HoverContents::Scalar(
- marked_string,
- ) => match marked_string {
- MarkedString::LanguageString(x) =>
- Cow::Borrowed(&*x.value),
- MarkedString::String(x) => Cow::Borrowed(&**x),
- },
- lsp_types::HoverContents::Array(
- marked_strings,
- ) => Cow::Owned(
- marked_strings
- .iter()
- .map(|x| match x {
- MarkedString::LanguageString(x) =>
- &*x.value,
- MarkedString::String(x) => &*x,
- })
- .collect::<String>(),
- ),
- lsp_types::HoverContents::Markup(
- markup_content,
- ) => Cow::Borrowed(&*markup_content.value),
+ Contents::MarkedString(marked_string) =>
+ match marked_string {
+ MarkedString::MarkedStringWithLanguage(
+ x,
+ ) => Cow::Borrowed(&*x.value),
+ MarkedString::String(x) =>
+ Cow::Borrowed(&**x),
+ },
+ Contents::MarkedStringList(marked_strings) =>
+ Cow::Owned(
+ marked_strings
+ .iter()
+ .map(|x| match x {
+ MarkedString::MarkedStringWithLanguage(
+ x,
+ ) => &*x.value,
+ MarkedString::String(x) => &*x,
+ })
+ .collect::<String>(),
+ ),
+ Contents::MarkupContent(markup_content) =>
+ Cow::Borrowed(&*markup_content.value),
};
if l.is_some_and(|l| {
matches!(
@@ -358,13 +360,11 @@ impl Editor {
});
let diags = self.find_diags(cursor_position, &w);
println!("requesting hover");
- self.state
- .consume(Action::SetHovering(
- diags.map(|of| Hovring { of, ..default() }),
- handle,
- (cursor_position, tdpp),
- ))
- .unwrap();
+ self.transition(Action::SetHovering(
+ diags.map(|of| Hovring { of, ..default() }),
+ handle,
+ (cursor_position, tdpp),
+ ));
// self.requests.hovering.request =
// (DropH::new(handle), cursor_position).into();
// requests.hovering.result = None;
diff --git a/src/edi/input_handlers/keyboard.rs b/src/edi/input_handlers/keyboard.rs
index f61a338..08376aa 100644
--- a/src/edi/input_handlers/keyboard.rs
+++ b/src/edi/input_handlers/keyboard.rs
@@ -5,11 +5,9 @@ use std::sync::Arc;
use Default::default;
use lsp_server::ResponseError;
-use lsp_types::request::*;
use lsp_types::*;
use regex::Regex;
use ropey::Rope;
-use rust_analyzer::lsp::ext::OnTypeFormatting;
use rust_fsm::StateMachine;
use tokio_util::task::AbortOnDropHandle as DropH;
use ttools::{IteratorOfTuples, IteratorOfTuplesWithF, hrf};
@@ -19,6 +17,7 @@ use winit::window::Window;
use crate::Freq;
use crate::edi::*;
+use crate::lsp::{Require, acceptable_duration};
impl Editor {
pub fn keyboard(
@@ -26,27 +25,31 @@ impl Editor {
event: KeyEvent,
window: &mut Arc<dyn Window>,
freq: &mut Freq,
+ kr: &mut KillRing,
+ lsp_mn: &mut LSPM,
) -> ControlFlow<()> {
- let mut o: Option<Do> = self
- .state
- .consume(Action::K(event.logical_key.clone()))
- .unwrap();
+ let Some(mut o) =
+ self.transition(Action::K(event.logical_key.clone()))
+ else {
+ return ControlFlow::Continue(());
+ };
+ if let Do::Reinsert = o {
+ let Some(o2) =
+ self.transition(Action::K(event.logical_key.clone()))
+ else {
+ return ControlFlow::Continue(());
+ };
+ dbg!(&o2);
+ o = o2;
+ };
match o {
- Some(Do::Reinsert) =>
- o = self
- .state
- .consume(Action::K(event.logical_key.clone()))
- .unwrap(),
- _ => {}
- }
- match o {
- Some(Do::Escape) => {
+ Do::Escape => {
take(&mut self.requests.complete);
take(&mut self.requests.sig_help);
self.text.cursor.alone();
}
- Some(Do::Comment(p)) => {
+ Do::Comment(p) => {
ceach!(self.text.cursor, |cursor| {
Some(
if let Some(x) = cursor.sel
@@ -62,29 +65,46 @@ impl Editor {
self.text.cursor.clear_selections();
change!(self, window.clone());
}
- Some(Do::SpawnTerminal) => {
- if let Err(e) = trm::toggle(
- self.workspace
+ #[cfg(target_family = "unix")]
+ Do::SpawnTerminal => {
+ if let Err(e) = crate::trm::toggle(
+ &lsp!(self)
.as_deref()
- .unwrap_or(Path::new("/home/os/")),
+ .map_or(Path::new("/home/os/").into(), |x| {
+ x.workspace.uri.to_file_path().unwrap()
+ }),
) {
log::error!("opening terminal failed {e}");
}
}
- Some(Do::MatchingBrace) =>
+ #[cfg(not(target_family = "unix"))]
+ Do::SpawnTerminal => {
+ unimplemented!()
+ }
+ Do::MatchingBrace =>
if let Some((l, f)) = lsp!(self + p) {
l.matching_brace(f, &mut self.text)
},
- Some(Do::DeleteBracketPair) => self.delete_bracket_pair(),
- Some(Do::Symbols) =>
+ Do::DeleteBracketPair => self.delete_bracket_pair(),
+ Do::Symbols
if let Some((lsp, o)) = lsp!(self + p)
- && let Ok(syms) = lsp.workspace_symbols("".into())
- {
- let mut q = Rq::new(lsp.runtime.spawn(
- syms.map(Anonymize::anonymize).map(|x| {
- x.map(|x| x.map(SymbolsList::Workspace))
- }),
- ));
+ && let Ok(syms) = lsp.workspace_symbols("".into()) =>
+ {
+ let mut q = Rq::new(
+ lsp.runtime.spawn(syms.map(Anonymize::anonymize).map(
+ |x| x.map(|x| x.map(SymbolsList::Workspace)),
+ )),
+ );
+ q.result = Some(Symbols::new(
+ self.tree.as_deref().unwrap(),
+ self.text.bookmarks.clone(),
+ o.into(),
+ ));
+ self.state = State::Symbols(q);
+ }
+ Do::Symbols =>
+ if let Some(o) = &self.origin {
+ let mut q = Rq::default();
q.result = Some(Symbols::new(
self.tree.as_deref().unwrap(),
self.text.bookmarks.clone(),
@@ -92,7 +112,7 @@ impl Editor {
));
self.state = State::Symbols(q);
},
- Some(Do::SwitchType) =>
+ Do::SwitchType =>
if let Some((lsp, p)) = lsp!(self + p) {
let State::Symbols(Rq { result: Some(x), request }) =
&mut self.state
@@ -113,7 +133,7 @@ impl Editor {
));
}
},
- Some(Do::ProcessCommand(mut x, z)) =>
+ Do::ProcessCommand(mut x, z) =>
match Cmds::complete_or_accept(&z) {
crate::menu::generic::CorA::Complete => {
x.tedit.rope =
@@ -122,14 +142,17 @@ impl Editor {
self.state = State::Command(x);
}
crate::menu::generic::CorA::Accept => {
- if let Err(e) =
- self.handle_command(z, window.clone())
- {
+ if let Err(e) = self.handle_command(
+ z,
+ window.clone(),
+ kr,
+ lsp_mn,
+ ) {
self.bar.last_action = format!("{e}");
}
}
},
- Some(Do::CmdTyped) => {
+ Do::CmdTyped => {
let State::Command(x) = &self.state else {
unreachable!()
};
@@ -139,13 +162,11 @@ impl Editor {
self.text.scroll_to_ln_centering(x as _);
}
}
- Some(Do::SymbolsHandleKey) => {
- if let Some(lsp) = lsp!(self) {
- let State::Symbols(Rq { result: Some(x), request }) =
+ Do::SymbolsHandleKey => {
+ if let Some(lsp) = lsp!(self)
+ && let State::Symbols(Rq { result: Some(x), request }) =
&mut self.state
- else {
- unreachable!()
- };
+ {
let ptedit = x.tedit.rope.clone();
if handle2(
&event.logical_key,
@@ -183,7 +204,7 @@ impl Editor {
}
}
}
- Some(Do::SymbolsSelectNext) => {
+ Do::SymbolsSelectNext => {
let State::Symbols(Rq { result: Some(x), .. }) =
&mut self.state
else {
@@ -203,7 +224,7 @@ impl Editor {
}
}
}
- Some(Do::SymbolsSelectPrev) => {
+ Do::SymbolsSelectPrev => {
let State::Symbols(Rq { result: Some(x), .. }) =
&mut self.state
else {
@@ -223,15 +244,15 @@ impl Editor {
}
}
}
- Some(Do::SymbolsSelect(x)) =>
+ Do::SymbolsSelect(x) =>
if let Some(Ok(x)) = x.sel(Some(freq))
- && let Err(e) = self.go(x.at, window.clone())
+ && let Err(e) = self.go(x.at, window.clone(), lsp_mn)
{
log::error!("alas! {e}")
},
- Some(Do::RenameSymbol(to)) => self.rename_symbol(to),
- Some(Do::CodeAction) => self.request_code_actions(),
- Some(Do::CASelectLeft) => {
+ Do::RenameSymbol(to) => self.rename_symbol(to),
+ Do::CodeAction => self.request_code_actions(),
+ Do::CASelectLeft => {
let State::CodeAction(Rq { result: Some(c), .. }) =
&mut self.state
else {
@@ -239,7 +260,7 @@ impl Editor {
};
c.left();
}
- Some(Do::CASelectRight) => 'out: {
+ Do::CASelectRight => 'out: {
let Some(lsp) = lsp!(self) else { unreachable!() };
let State::CodeAction(Rq { result: Some(c), .. }) =
&mut self.state
@@ -252,15 +273,15 @@ impl Editor {
self.hist.lc = self.text.cursor.clone();
self.hist.test_push(&mut self.text);
let act = lsp
- .request_immediate::<CodeActionResolveRequest>(&act)
+ .request_immediate::<rust_analyzer::lsp::ext::CodeActionResolveRequest>(&act)
.unwrap();
if let Some(x) = act.edit
- && let Err(e) = self.apply_wsedit(x)
+ && let Err(e) = self.apply_swsedit(x)
{
log::error!("{e}");
}
}
- Some(Do::CASelectNext) => {
+ Do::CASelectNext => {
let State::CodeAction(Rq { result: Some(c), .. }) =
&mut self.state
else {
@@ -268,7 +289,7 @@ impl Editor {
};
c.down();
}
- Some(Do::CASelectPrev) => {
+ Do::CASelectPrev => {
let State::CodeAction(Rq { result: Some(c), .. }) =
&mut self.state
else {
@@ -276,7 +297,7 @@ impl Editor {
};
c.up();
}
- Some(Do::GoToMatch)
+ Do::GoToMatch
if let Some(x) =
&self.requests.document_highlights.result =>
'out: {
@@ -295,8 +316,10 @@ impl Editor {
}))
.max_by_key(|x| x.0.start)
else {
- self.bar.last_action =
- "couldnt get symbol here".into();
+ self.requests.document_highlights.result = None;
+ self.refresh_document_highlights();
+ // self.bar.last_action =
+ // "couldnt get symbol here".into();
break 'out;
};
if self.text.cursor.inner.len() == 1
@@ -314,37 +337,35 @@ impl Editor {
}
}
}
- Some(Do::GoToMatch) =>
+ Do::GoToMatch =>
if self.requests.document_highlights.request.is_none() {
self.refresh_document_highlights();
},
- Some(Do::NavBack) => self.nav_back(),
- Some(Do::NavForward) => self.nav_forward(),
- Some(
- Do::Reinsert
- | Do::GoToDefinition(_)
- | Do::MoveCursor
- | Do::ExtendSelectionToMouse
- | Do::Hover
- | Do::InsertCursorAtMouse
- | Do::SetHovering
- | Do::ClickedHover,
- ) => panic!(),
- Some(Do::Save) => match &self.origin {
+ Do::NavBack => self.nav_back(),
+ Do::NavForward => self.nav_forward(),
+
+ Do::Reinsert
+ | Do::GoToDefinition(_)
+ | Do::MoveCursor
+ | Do::ExtendSelectionToMouse
+ | Do::Hover
+ | Do::InsertCursorAtMouse
+ | Do::SetHovering => panic!(),
+ Do::Save => match &self.origin {
Some(_) => {
- self.state.consume(Action::Saved).unwrap();
+ self.transition(Action::Saved);
self.save();
}
None => {
- self.state.consume(Action::RequireFilename).unwrap();
+ self.transition(Action::RequireFilename);
}
},
- Some(Do::SaveTo(x)) => {
+ Do::SaveTo(x) => {
self.origin = Some(PathBuf::try_from(x).unwrap());
self.save();
}
- Some(Do::Edit) => self.handle_edit(event),
- Some(Do::Undo) => {
+ Do::Edit => self.handle_edit(event),
+ Do::Undo => {
self.hist.test_push(&mut self.text);
if let Err(e) = self.hist.undo(&mut self.text) {
eprintln!("undo failed: {e}");
@@ -353,14 +374,14 @@ impl Editor {
change!(self, window.clone());
}
- Some(Do::Redo) => {
+ Do::Redo => {
self.hist.test_push(&mut self.text);
self.hist.redo(&mut self.text).unwrap();
self.bar.last_action = "redid".to_string();
change!(self, window.clone());
}
- Some(Do::Quit) => return ControlFlow::Break(()),
- Some(Do::SetCursor(x)) => {
+ Do::Quit => return ControlFlow::Break(()),
+ Do::SetCursor(x) => {
self.text.cursor.each(|c| {
let Some(r) = c.sel else { return };
match x {
@@ -370,7 +391,7 @@ impl Editor {
});
self.text.cursor.clear_selections();
}
- Some(Do::StartSelection) => {
+ Do::StartSelection => {
let Key::Named(y) = event.logical_key else { panic!() };
// let mut z = vec![];
self.text.cursor.each(|x| {
@@ -385,7 +406,7 @@ impl Editor {
});
// *self.state.sel() = z;
}
- Some(Do::UpdateSelection) => {
+ Do::UpdateSelection => {
let Key::Named(y) = event.logical_key else { panic!() };
self.text.cursor.each(|x| {
x.extend_selection(
@@ -400,9 +421,10 @@ impl Editor {
self.text.scroll_to_cursor();
inlay!(self);
}
- Some(Do::Insert(c)) => {
+ Do::Insert(c) => {
// self.text.cursor.inner.clear();
self.hist.push_if_changed(&mut self.text);
+ self.kill(kr);
ceach!(self.text.cursor, |cursor| {
let Some(r) = cursor.sel else { return };
_ = self.text.remove(r.into());
@@ -413,30 +435,29 @@ impl Editor {
self.hist.push_if_changed(&mut self.text);
change!(self, window.clone());
}
- Some(Do::Delete) => {
+ Do::Delete => {
self.hist.push_if_changed(&mut self.text);
+ self.kill(kr);
ceach!(self.text.cursor, |cursor| {
let Some(r) = cursor.sel else { return };
_ = self.text.remove(r.into());
});
self.text.cursor.clear_selections();
- self.hist.push_if_changed(&mut self.text);
change!(self, window.clone());
}
- Some(Do::Copy) => {
+ Do::Copy => {
self.hist.push_if_changed(&mut self.text);
unsafe { take(&mut META) };
let mut clip = String::new();
- self.text.cursor.each_ref(|x| {
- if let Some(x) = x.sel {
- unsafe {
- META.count += 1;
- META.splits.push(clip.len());
- }
- clip.extend(self.text.rope.slice(x).chars());
+ self.kill(kr);
+ for sel in self.text.cursor.sels(&self.text) {
+ unsafe {
+ META.count += 1;
+ META.splits.push(clip.len());
}
- });
+ clip.extend(sel.chars());
+ }
unsafe {
META.splits.push(clip.len());
META.hash = hash(&clip)
@@ -446,19 +467,18 @@ impl Editor {
self.hist.push_if_changed(&mut self.text);
change!(self, window.clone());
}
- Some(Do::Cut) => {
+ Do::Cut => {
self.hist.push_if_changed(&mut self.text);
unsafe { take(&mut META) };
let mut clip = String::new();
- self.text.cursor.each_ref(|x| {
- if let Some(x) = x.sel {
- unsafe {
- META.count += 1;
- META.splits.push(clip.len());
- }
- clip.extend(self.text.rope.slice(x).chars());
+ self.kill(kr);
+ for sel in self.text.cursor.sels(&self.text) {
+ unsafe {
+ META.count += 1;
+ META.splits.push(clip.len());
}
- });
+ clip.extend(sel.chars());
+ }
unsafe {
META.splits.push(clip.len());
META.hash = hash(&clip)
@@ -473,8 +493,9 @@ impl Editor {
self.hist.push_if_changed(&mut self.text);
change!(self, window.clone());
}
- Some(Do::PasteOver) => {
+ Do::PasteOver => {
self.hist.push_if_changed(&mut self.text);
+ self.kill(kr);
ceach!(self.text.cursor, |cursor| {
let Some(r) = cursor.sel else { return };
_ = self.text.remove(r.into());
@@ -483,11 +504,11 @@ impl Editor {
self.paste();
// self.hist.push_if_changed(&mut self.text);
}
- Some(Do::Paste) => self.paste(),
- Some(Do::OpenFile(x)) => {
- _ = self.open(Path::new(&x), window.clone());
+ Do::Paste => self.paste(),
+ Do::OpenFile(x) => {
+ _ = self.open(Path::new(&x), window.clone(), lsp_mn);
}
- Some(Do::StartSearch(x)) => {
+ Do::StartSearch(x) => {
let s = Regex::new(&x).unwrap();
let n = s
.find_iter(&self.text.rope.to_string())
@@ -510,7 +531,7 @@ impl Editor {
self.bar.last_action = "no matches".into()
});
}
- Some(Do::SearchChanged) => {
+ Do::SearchChanged => {
let (re, index, _) = self.state.search();
let s = self.text.rope.to_string();
let m = re.find_iter(&s).nth(*index).unwrap();
@@ -521,48 +542,41 @@ impl Editor {
self.text.scroll_to_cursor_centering();
inlay!(self);
}
- Some(Do::Boolean(BoolRequest::ReloadFile, true)) => {
- self.hist.push_if_changed(&mut self.text);
- self.text.rope = Rope::from_str(
- &std::fs::read_to_string(
- self.origin.as_ref().unwrap(),
- )
- .unwrap(),
- );
-
- self.text.cursor.first_mut().position = self
- .text
+ Do::Boolean(BoolRequest::ReloadFile, true) => self.reload(),
+ Do::Boolean(BoolRequest::ReloadFile, false) => {}
+ Do::InsertCursor(dir) => {
+ self.text
.cursor
- .first()
- .position
- .min(self.text.rope.len_chars());
- self.mtime = Self::modify(self.origin.as_deref());
- self.bar.last_action = "reloaded".into();
- self.hist.push(&mut self.text)
- }
- Some(Do::Boolean(BoolRequest::ReloadFile, false)) => {}
- Some(Do::InsertCursor(dir)) => {
- let (x, y) = match dir {
- Direction::Above => self.text.cursor.min(),
- Direction::Below => self.text.cursor.max(),
- }
- .cursor(&self.text.rope);
- let y = match dir {
- Direction::Above => y - 1,
- Direction::Below => y + 1,
- };
- let position = self.text.line_to_char(y);
- self.text.cursor.add(position + x, &self.text.rope);
+ .inner
+ .iter()
+ .filter_map(|cursor| {
+ let (x, y) = cursor.cursor(&self.text.rope);
+ let y = match dir {
+ Direction::Above => y.checked_sub(1)?,
+ Direction::Below => y + 1,
+ };
+ let position = self.text.line_to_char(y) + x;
+ Some(position)
+ })
+ .filter(|&p| self.text.cursor.iter().all(|x| x != p))
+ .collect::<Vec<_>>()
+ .into_iter()
+ .for_each(|x| {
+ self.text.cursor.add(x, &self.text.rope);
+ });
}
- Some(Do::Run(x)) =>
+ #[cfg(target_family = "unix")]
+ Do::Run(x) =>
if let Some((l, ws)) =
- lsp!(self).zip(self.workspace.as_deref())
+ lsp!(self).zip(self.git_dir.as_deref())
{
l.runtime
.block_on(crate::runnables::run(x, ws))
.unwrap();
},
- Some(Do::GoToImplementations) => {
+ #[cfg(not(target_family = "unix"))]
+ Do::Run(_) => {}
+ Do::GoToImplementations => {
let State::GoToL(x) = &mut self.state else {
unreachable!()
};
@@ -574,13 +588,13 @@ impl Editor {
)));
}
}
- Some(Do::GTLSelect(x)) =>
+ Do::GTLSelect(x) =>
if let Some(Ok((g, _))) = x.sel(None)
- && let Err(e) = self.go(g, window.clone())
+ && let Err(e) = self.go(g, window.clone(), lsp_mn)
{
eprintln!("go-to-list select fail: {e}");
},
- Some(Do::GT) => {
+ Do::GT => {
let State::GoToL(x) = &mut self.state else {
unreachable!()
};
@@ -593,7 +607,28 @@ impl Editor {
// self.text.vo = self.text.char_to_line(x.start);
}
}
- None => {}
+ // Do::KillRing => {
+ // self.state = State::KillRing(KillRM {
+ // data: kr.clone(),
+ // tedit: default(),
+ // selection: 0,
+ // vo: 0,
+ // });
+ // }
+ Do::KillRMHandleKey => {
+ if let State::KillRing(x) = &mut self.state {
+ handle2(
+ &event.logical_key,
+ &mut x.tedit,
+ lsp!(self + p),
+ );
+ }
+ }
+ Do::Revive(x) =>
+ if let Some(Ok(x)) = x.sel(Some(freq)) {
+ self.paste_m(x.iter())
+ },
+ Do::R(_) => {}
}
ControlFlow::Continue(())
}
@@ -628,25 +663,21 @@ impl Editor {
|| t.iter().any(|y| y == x))
&& self.text.cursor.inner.len() == 1
&& change!(just self).is_some()
- && let Ok(Some(mut x)) = l
- .request_immediate::<OnTypeFormatting>(
+ && let Ok(Ok(Some(mut x))) = l
+ .request_by::<rust_analyzer::lsp::ext::DocumentOnTypeFormattingRequest>(
&DocumentOnTypeFormattingParams {
- text_document_position:
- TextDocumentPositionParams {
- text_document: p.tid(),
- position: self
- .text
- .to_l_position(
- *self.text.cursor.first(),
- )
- .unwrap(),
- },
+ text_document: p.tid(),
+ position: self
+ .text
+ .to_l_position(*self.text.cursor.first())
+ .unwrap(),
ch: x.into(),
options: FormattingOptions {
tab_size: 4,
..default()
},
},
+ acceptable_duration(),
)
{
x.sort_tedits();
@@ -699,7 +730,11 @@ impl Editor {
.requests
.complete
.consume(CompletionAction::K(event.logical_key.as_ref()))
- .unwrap()
+ .inspect_err(|e| {
+ log::error!("failure: {e}");
+ })
+ .ok()
+ .flatten()
{
Some(CDo::Request(ctx)) => {
if let Ok(fut) = lsp.request_complete(
@@ -776,15 +811,16 @@ impl Editor {
let x = lsp
.request_immediate::<lsp_request!("textDocument/rename")>(
&RenameParams {
- text_document_position: TextDocumentPositionParams {
- text_document: f.tid(),
- position: self
- .text
- .to_l_position(
- self.text.cursor.first().position,
- )
- .unwrap(),
- },
+ text_document_position_params:
+ TextDocumentPositionParams {
+ text_document: f.tid(),
+ position: self
+ .text
+ .to_l_position(
+ self.text.cursor.first().position,
+ )
+ .unwrap(),
+ },
new_name,
work_done_progress_params: default(),
},
@@ -814,8 +850,11 @@ impl Editor {
pub fn request_code_actions(&mut self) {
lsp!(let lsp, f = self);
+ if lsp.caps().code_action_provider.is_none() {
+ return;
+ }
let r = lsp
- .request::<lsp_request!("textDocument/codeAction")>(
+ .request::<rust_analyzer::lsp::ext::CodeActionRequest>(
&CodeActionParams {
text_document: f.tid(),
range: self
@@ -826,7 +865,7 @@ impl Editor {
)
.unwrap(),
context: CodeActionContext {
- trigger_kind: Some(CodeActionTriggerKind::INVOKED),
+ trigger_kind: Some(CodeActionTriggerKind::Invoked),
// diagnostics: if let Some((lsp, p)) = lsp!() && let uri = Url::from_file_path(p).unwrap() && let Some(diag) = lsp.requests.diagnostics.get(&uri, &lsp.requests.diagnostics.guard()) { dbg!(diag.iter().filter(|x| {
// self.text.l_range(x.range).unwrap().contains(&self.text.cursor)
// }).cloned().collect()) } else { vec![] },
@@ -854,4 +893,35 @@ impl Editor {
.request(lsp.runtime.spawn(fut));
}
}
+ pub fn reload(&mut self) {
+ self.hist.push_if_changed(&mut self.text);
+ self.text.rope = Rope::from_str(
+ &std::fs::read_to_string(self.origin.as_ref().unwrap())
+ .map(|x| x.replace("\r\n", "\n"))
+ .unwrap(),
+ );
+
+ self.text.cursor.first_mut().position = self
+ .text
+ .cursor
+ .first()
+ .position
+ .min(self.text.rope.len_chars());
+ self.mtime = Self::modify(self.origin.as_deref());
+ self.bar.last_action = "reloaded".into();
+ self.hist.push(&mut self.text)
+ }
+ pub fn kill(&mut self, kr: &mut KillRing) {
+ if let x = self
+ .text
+ .cursor
+ .sels(&self.text)
+ .map(String::from)
+ .collect::<Box<[_]>>()
+ && !x.is_empty()
+ {
+ println!("kill {x:?}");
+ kr.push(x);
+ }
+ }
}
diff --git a/src/edi/lsp_impl.rs b/src/edi/lsp_impl.rs
index d0e506e..6026a3d 100644
--- a/src/edi/lsp_impl.rs
+++ b/src/edi/lsp_impl.rs
@@ -2,16 +2,16 @@ use std::iter::repeat;
use Default::default;
use lsp_server::Request as LRq;
-use lsp_types::request::*;
use lsp_types::*;
+use rust_analyzer::lsp::ext::CodeAction;
use serde::{Deserialize, Serialize};
use ttools::{Tupl, With};
use crate::complete::Complete;
+use crate::edi::lsp;
use crate::edi::st::*;
use crate::hov::{Hoverable, Hovring};
use crate::lsp::{RequestError, Rq};
-use crate::runnables::Runnables;
use crate::sym::GoTo;
use crate::{CompletionState, act, sig, sym};
@@ -32,14 +32,15 @@ pub struct Requests {
(),
RequestError<SignatureHelpRequest>,
>, // vo, lines
- // #[serde(serialize_with = "serialize_tokens")]
- // #[serde(deserialize_with = "deserialize_tokens")]
- #[serde(skip)]
+ #[serde(serialize_with = "serialize_tokens")]
+ #[serde(deserialize_with = "deserialize_tokens")]
+ #[serde(default)]
+ // #[serde(skip)]
pub semantic_tokens: Rq<
Box<[SemanticToken]>,
Box<[SemanticToken]>,
(),
- RequestError<SemanticTokensFullRequest>,
+ RequestError<lsp_request!("textDocument/semanticTokens/full")>,
>,
pub diag: Rq<
String,
@@ -47,18 +48,18 @@ pub struct Requests {
(),
RequestError<DocumentDiagnosticRequest>,
>,
- #[serde(skip)]
+ #[serde(default)]
pub inlay: Rq<
Vec<InlayHint>,
Vec<InlayHint>,
(),
RequestError<lsp_request!("textDocument/inlayHint")>,
>,
- pub def: Rq<
+ pub def: crate::RqS<
LocationLink,
- Option<GotoDefinitionResponse>,
+ lsp_request!("textDocument/definition"),
(usize, usize),
- RequestError<lsp_request!("textDocument/definition")>,
+ // RequestError<lsp_request!("textDocument/definition")>,
>,
#[serde(skip)]
pub document_symbols: Rq<
@@ -70,9 +71,138 @@ pub struct Requests {
#[serde(skip)]
pub git_diff: Rq<imara_diff::Diff, imara_diff::Diff, (), ()>,
}
+use serde::ser::SerializeSeq;
+
+fn untokenr<'de, D>(
+ deserializer: D,
+) -> Result<Vec<SemanticToken>, D::Error>
+where
+ D: serde::Deserializer<'de>,
+{
+ let data = Vec::<u32>::deserialize(deserializer)?;
+ let chunks = data.chunks_exact(5);
+
+ if !chunks.remainder().is_empty() {
+ return Result::Err(serde::de::Error::custom(
+ "Length is not divisible by 5",
+ ));
+ }
+
+ Result::Ok(
+ chunks
+ .map(|chunk| SemanticToken {
+ delta_line: chunk[0],
+ delta_start: chunk[1],
+ length: chunk[2],
+ token_type: chunk[3],
+ token_modifiers_bitset: chunk[4],
+ })
+ .collect(),
+ )
+}
+
+fn tokenr<S>(
+ tokens: &[SemanticToken],
+ serializer: S,
+) -> Result<S::Ok, S::Error>
+where
+ S: serde::Serializer,
+{
+ let mut seq = serializer.serialize_seq(Some(tokens.len() * 5))?;
+ for token in tokens.iter() {
+ seq.serialize_element(&token.delta_line)?;
+ seq.serialize_element(&token.delta_start)?;
+ seq.serialize_element(&token.length)?;
+ seq.serialize_element(&token.token_type)?;
+ seq.serialize_element(&token.token_modifiers_bitset)?;
+ }
+ seq.end()
+}
+
+fn deserialize_tokens_opt<'de, D>(
+ deserializer: D,
+) -> Result<Option<Vec<SemanticToken>>, D::Error>
+where
+ D: serde::Deserializer<'de>,
+{
+ #[derive(Deserialize)]
+ #[serde(transparent)]
+ struct Wrapper {
+ #[serde(deserialize_with = "untokenr")]
+ tokens: Vec<SemanticToken>,
+ }
+
+ Ok(Option::<Wrapper>::deserialize(deserializer)?
+ .map(|wrapper| wrapper.tokens))
+}
+
+fn serialize_tokens_opt<S>(
+ data: Option<&[SemanticToken]>,
+ serializer: S,
+) -> Result<S::Ok, S::Error>
+where
+ S: serde::Serializer,
+{
+ #[derive(Serialize)]
+ #[serde(transparent)]
+ struct Wrapper<'a> {
+ #[serde(serialize_with = "tokenr")]
+ tokens: &'a [SemanticToken],
+ }
+
+ let opt = data.as_ref().map(|t| Wrapper { tokens: t });
+
+ opt.serialize(serializer)
+}
+pub fn deserialize_tokens<'de, D: serde::Deserializer<'de>>(
+ ser: D,
+) -> Result<
+ Rq<
+ Box<[SemanticToken]>,
+ Box<[SemanticToken]>,
+ (),
+ RequestError<lsp_request!("textDocument/semanticTokens/full")>,
+ >,
+ D::Error,
+> {
+ {
+ #[derive(Deserialize)]
+ #[serde(transparent)]
+ struct Wrapper {
+ #[serde(deserialize_with = "untokenr")]
+ tokens: Vec<SemanticToken>,
+ }
+
+ Ok(Option::<Wrapper>::deserialize(ser)?
+ .map(|wrapper| wrapper.tokens))
+ }
+ .map(|x| Rq { result: x.map(Into::into), request: None })
+}
+pub fn serialize_tokens<S: serde::Serializer>(
+ s: &Rq<
+ Box<[SemanticToken]>,
+ Box<[SemanticToken]>,
+ (),
+ RequestError<lsp_request!("textDocument/semanticTokens/full")>,
+ >,
+ ser: S,
+) -> Result<S::Ok, S::Error> {
+ {
+ let data: &Option<Vec<SemanticToken>> =
+ &s.result.clone().map(|x| x.to_vec());
+ #[derive(Serialize)]
+ #[serde(transparent)]
+ struct Wrapper {
+ #[serde(serialize_with = "tokenr")]
+ tokens: Vec<SemanticToken>,
+ }
+ let opt = data.as_ref().map(|t| Wrapper { tokens: t.to_vec() });
+ opt.serialize(ser)
+ }
+}
impl crate::edi::Editor {
pub fn poll(&mut self) {
- let Some((l, ..)) = self.lsp else { return };
+ lsp!(let l = self);
for rq in l.req_rx.try_iter() {
match rq {
LRq { method: "workspace/diagnostic/refresh", .. } => {
@@ -120,14 +250,7 @@ impl crate::edi::Editor {
}
State::CodeAction(x) => {
if x.poll(|x, _| {
- let lems: Vec<CodeAction> = x
- .ok()??
- .into_iter()
- .map(|x| match x {
- CodeActionOrCommand::CodeAction(x) => x,
- _ => panic!("alas we dont like these"),
- })
- .collect();
+ let lems = x.ok()??;
if lems.is_empty() {
self.bar.last_action =
"no code actions available".into();
@@ -142,9 +265,10 @@ impl crate::edi::Editor {
self.state = State::Default;
}
}
+ #[cfg(target_family = "unix")]
State::Runnables(x) => {
x.poll(|x, ((), old)| {
- Some(Runnables {
+ Some(crate::runnables::Runnables {
data: x.ok()?,
..old.unwrap_or_default()
})
@@ -188,18 +312,13 @@ impl crate::edi::Editor {
x.ok().map(|x| {
x.and_then(|x| try {
z.data.0 = match x {
- GotoDefinitionResponse::Scalar(
- location,
+ ImplementationResponse::Definition(
+ Definition::Location(location),
) => vec![(GoTo::from(
location,
),None)],
- GotoDefinitionResponse::Array(
- locations,
- ) => locations
- .into_iter()
- .map(GoTo::from).zip(repeat(None))
- .collect(),
- GotoDefinitionResponse::Link(
+
+ ImplementationResponse::DefinitionLinkList(
location_links,
) => location_links
.into_iter()
@@ -212,6 +331,7 @@ impl crate::edi::Editor {
)
}).zip(repeat(None))
.collect(),
+ ImplementationResponse::Definition(Definition::LocationList(x)) => {unimplemented!()},
};
});
})
@@ -251,7 +371,10 @@ impl crate::edi::Editor {
}
self.requests.def.poll(|x, _| {
x.ok().flatten().and_then(|x| match &x {
- GotoDefinitionResponse::Link([x, ..]) => Some(x.clone()),
+ // DefinitionResponse::Definition(x) => Some(x.clone()),
+ DefinitionResponse::DefinitionLinkList([x, ..]) =>
+ Some(x.clone()),
+ // DefinitionRequest::Definition([x, ..]) => Some(x.clone()),
_ => None,
})
});
@@ -273,8 +396,8 @@ impl crate::edi::Editor {
self.requests.git_diff.poll(|x, _| x.ok());
self.requests.document_symbols.poll(|x, _| {
x.ok().flatten().map(|x| match x {
- DocumentSymbolResponse::Flat(_) => None,
- DocumentSymbolResponse::Nested(x) => Some(x),
+ DocumentSymbolResponse::SymbolInformationList(_) => None,
+ DocumentSymbolResponse::DocumentSymbolList(x) => Some(x),
})
});
}
diff --git a/src/edi/lsp_mn.rs b/src/edi/lsp_mn.rs
new file mode 100644
index 0000000..45cfd24
--- /dev/null
+++ b/src/edi/lsp_mn.rs
@@ -0,0 +1,119 @@
+use std::collections::HashMap;
+use std::io::BufReader;
+use std::path::PathBuf;
+use std::process::Stdio;
+use std::sync::Arc;
+
+use lsp_server::Connection;
+use lsp_types::*;
+use tokio::sync::oneshot::Sender;
+use tree_house::Language;
+use url::Url;
+use winit::window::Window;
+
+pub struct LSPM {
+ pub four: HashMap<(Language, PathBuf), LoadedLSP>,
+}
+
+pub struct LoadedLSP {
+ pub c: Arc<Client>,
+ pub iot: Option<IoThreads>,
+ pub comms: std::thread::JoinHandle<()>,
+}
+impl LoadedLSP {
+ pub fn status(&self) {
+ assert!(!self.comms.is_finished());
+ }
+}
+mod stdio;
+impl LSPM {
+ pub fn load(
+ &mut self,
+ workspace: &PathBuf,
+ l: Language,
+ vsc: Option<serde_json::Value>,
+ ) -> Option<(Arc<Client>, Option<Sender<Arc<dyn Window + 'static>>>)>
+ {
+ let ra_conn_used = self
+ .four
+ .values()
+ .any(|x| x.c.lsp_data.1.name == "rust-analyzer");
+ let e = match self.four.entry((l, workspace.to_owned())) {
+ std::collections::hash_map::Entry::Occupied(x) => {
+ let x = x.get();
+ return Some((x.c.clone(), None));
+ }
+ std::collections::hash_map::Entry::Vacant(e) => e,
+ };
+ let (l, w) = load(workspace, l, vsc, ra_conn_used)?;
+ let v = e.insert(l);
+ Some((v.c.clone(), Some(w)))
+ }
+}
+use crate::edi::lsp_mn::stdio::IoThreads;
+use crate::lsp::Client;
+pub fn load(
+ workspace: &PathBuf,
+ l: Language,
+ vsc: Option<serde_json::Value>,
+ ra_conn_used: bool,
+) -> Option<(LoadedLSP, Sender<Arc<dyn Window>>)> {
+ let l = super::LOADER.language(l).config();
+ let use_builtin_ra = l.language_id == "rust" && !ra_conn_used;
+ let (Connection { sender, receiver }, conf, iot) = if use_builtin_ra {
+ let (_jh, a) = super::ra::ra(workspace.clone());
+ (
+ a,
+ (
+ &super::LOADER.language_server_configs()["rust-analyzer"],
+ &l.language_servers[0],
+ ),
+ None,
+ )
+ } else {
+ let (mut c, conf) = l
+ .language_servers
+ .iter()
+ .find_map(|l| {
+ let lc = super::LOADER
+ .language_server_configs()
+ .get(&l.name)?;
+ std::process::Command::new(&lc.command)
+ .args(&lc.args)
+ .stdin(Stdio::piped())
+ .stdout(Stdio::piped())
+ .stderr(Stdio::inherit())
+ .spawn()
+ .ok()
+ .zip(Some((lc, l)))
+ })
+ .ok_or_else(|| {
+ log::error!(
+ "no lsp for this language; install one of {:?}",
+ l.language_servers
+ )
+ })
+ .ok()?;
+
+ let (x, iot) = stdio::transport(
+ BufReader::new(c.stdout.take().unwrap()),
+ c.stdin.take().unwrap(),
+ );
+ (x, conf, Some(iot))
+ };
+ let (c, t2, changed) = crate::lsp::run(
+ (sender, receiver),
+ WorkspaceFolder {
+ uri: Url::from_file_path(&workspace).unwrap(),
+ name: workspace
+ .file_name()
+ .unwrap()
+ .to_string_lossy()
+ .into_owned(),
+ },
+ vsc.and_then(|x| x.as_object()?.get(&conf.1.name).cloned()),
+ conf,
+ )
+ .unwrap();
+ Some((LoadedLSP { iot, c: Arc::new(c), comms: t2 }, changed))
+}
diff --git a/src/edi/lsp_mn/stdio.rs b/src/edi/lsp_mn/stdio.rs
new file mode 100644
index 0000000..fa5a480
--- /dev/null
+++ b/src/edi/lsp_mn/stdio.rs
@@ -0,0 +1,75 @@
+use std::io::{self, Read, Stdin, Stdout, Write, stdin, stdout};
+use std::thread;
+
+use crossbeam_channel::{Receiver, Sender, bounded, unbounded};
+use log::trace;
+use lsp_server::{Connection, Message};
+/// Creates an LSP connection via stdio.
+pub fn transport(
+ mut read_from: impl Read + std::io::BufRead + Sync + Send + 'static,
+ mut write_to: impl Write + Sync + Send + 'static,
+) -> (Connection, IoThreads) {
+ let (writer_sender, writer_receiver) = unbounded::<Message>();
+ let writer = thread::Builder::new()
+ .name("send to lsp".to_owned())
+ .spawn(move || {
+ loop {
+ let it = writer_receiver.recv().unwrap();
+ trace!("sent message {it:#?}");
+ let result = it.write(&mut write_to).unwrap();
+ result
+ }
+ })
+ .unwrap();
+ let (reader_sender, reader_receiver) = bounded::<Message>(0);
+ let reader: thread::JoinHandle<Result<(), io::Error>> = thread::Builder::new()
+ .name("read from lsp".to_owned())
+ .spawn(move || {
+ while let Some(msg) = Message::read(&mut read_from)? {
+ let is_exit = matches!(&msg, Message::Notification(n) if n.method == "exit");
+ trace!("received message {msg:#?}");
+ if let Err(e) = reader_sender.send(msg) {
+ return Err(io::Error::other(e));
+ }
+
+ if is_exit {
+ break;
+ }
+ }
+ Ok(())
+ })
+ .unwrap();
+ let threads = IoThreads { reader, writer };
+ (
+ Connection { sender: writer_sender, receiver: reader_receiver },
+ threads,
+ )
+}
+
+// Creates an IoThreads
+pub(crate) fn make_io_threads(
+ reader: thread::JoinHandle<io::Result<()>>,
+ writer: thread::JoinHandle<io::Result<()>>,
+) -> IoThreads {
+ IoThreads { reader, writer }
+}
+
+pub struct IoThreads {
+ pub reader: thread::JoinHandle<io::Result<()>>,
+ pub writer: thread::JoinHandle<io::Result<()>>,
+}
+
+impl IoThreads {
+ pub fn join(self) -> io::Result<()> {
+ match self.reader.join() {
+ Ok(r) => r?,
+ Err(err) => std::panic::panic_any(err),
+ }
+ match self.writer.join() {
+ Ok(r) => r,
+ Err(err) => {
+ std::panic::panic_any(err);
+ }
+ }
+ }
+}
diff --git a/src/edi/ra.rs b/src/edi/ra.rs
index ef0c7c8..bed6931 100644
--- a/src/edi/ra.rs
+++ b/src/edi/ra.rs
@@ -31,7 +31,14 @@ pub fn ra(
println!("RA panic @ {}", info.location().unwrap());
}
}));
- rust_analyzer::bin::run_server(b).into_rootcause()
+
+ rayon::ThreadPoolBuilder::new()
+ .thread_name(|ix| format!("RayonWorker{}", ix))
+ .build_global()
+ .unwrap();
+
+ rust_analyzer::session::run_session(b, None, None)
+ .into_rootcause()
})
.unwrap();
(jh, a)
diff --git a/src/edi/st.rs b/src/edi/st.rs
index 3fe6b31..40be312 100644
--- a/src/edi/st.rs
+++ b/src/edi/st.rs
@@ -1,10 +1,9 @@
#![allow(dead_code, unused, unexpected_cfgs)]
use Default::default;
use NamedKey::*;
-use lsp_types::request::HoverRequest;
use lsp_types::*;
use regex::Regex;
-use rust_analyzer::lsp::ext::Runnable;
+use rust_analyzer::lsp::ext::{CodeAction, Runnable};
use winit::event::MouseButton;
use winit::keyboard::{Key, NamedKey, SmolStr};
@@ -35,6 +34,11 @@ pub enum LR {
Left,
Right,
}
+
+#[cfg(target_family = "unix")]
+type Run = crate::runnables::Runnables;
+#[cfg(not(target_family = "unix"))]
+type Run = ();
rust_fsm::state_machine! {
#[derive(Debug)]
pub(crate) State => #[derive(Debug)] pub(crate) Action => #[derive(Debug)] pub(crate) Do
@@ -78,9 +82,15 @@ Default => {
K(_) => _ [Edit],
M(_) => _,
},
+// Matches(x) => {
+ // K(Key::Character("d") if ctrl()) => _ [GoToMatch],
+ // C(_) => Default [Reinsert],
+ // K(_) => Default [Reinsert],
+ // K(_) => Default [Reinsert],
+// },
Hovered => {
HOnSomething(((usize, usize)) => pos) => Hovering(Rq<Hovring, Option<Hovr>, ((usize, usize), TextDocumentPositionParams), RequestError<HoverRequest>> => default()) [SetHovering],
- HOnNothing => Default,
+ HOnNothing => Default [R(bool => false)],
},
Hovering(x) => {
// now hovering over something else, cancel existing hover
@@ -93,46 +103,10 @@ Hovering(x) => {
C(_) => _ [Hover],
MovedOut => Default,
Scrolled => Default,
- // reconsidering
- K(Key::Character("s") if ctrl()) => Save [Save],
- K(Key::Character("q") if ctrl()) => Dead [Quit],
- K(Key::Character("v") if ctrl()) => Default [Paste],
- K(Key::Character("z") if ctrl()) => Default [Undo],
- K(Key::Character("d") if ctrl()) => Default [GoToMatch],
- K(Key::Character("y") if ctrl()) => Default [Redo],
- K(Key::Character("f") if ctrl()) => Procure((default(), InputRequest::Search)),
- K(Key::Character("o") if ctrl()) => Procure((default(), InputRequest::OpenFile)),
- K(Key::Character("c") if ctrl()) => Default ,
- K(Key::Character("l") if ctrl()) => Default [Symbols],
- K(Key::Character(".") if ctrl()) => Default [CodeAction],
- K(Key::Character("0") if ctrl()) => Default [MatchingBrace],
- K(Key::Character("`") if ctrl()) => Default [SpawnTerminal],
- K(Key::Character("/") if ctrl()) => Default [Comment(State => State::Default)],
- K(Key::Character("p") if ctrl()) => Command(Commands => default()),
- K(Key::Named(Backspace) if alt()) => Default [DeleteBracketPair],
- K(Key::Named(F1)) => Procure((default(), InputRequest::RenameSymbol)),
- K(Key::Named(F10)) => GoToL(GoToList => default()) [GoToImplementations],
- K(Key::Named(k @ (ArrowUp | ArrowDown)) if alt()) => Default [InsertCursor(Direction => {
- if k == ArrowUp {Direction::Above} else { Direction::Below }
- })],
- K(Key::Named(ArrowUp | ArrowLeft | ArrowDown | ArrowRight | Home | End) if shift()) => Selection [StartSelection],
- M(MouseButton::Left if shift()) => Selection [StartSelection],
- M(MouseButton::Left if alt()) => Default [InsertCursorAtMouse],
- M(MouseButton::Left if ctrl()) => Default [GoToDefinition(Option<TextDocumentPositionParams> => None)],
- M(MouseButton::Left) => Default [MoveCursor],
- K(Key::Character("=") if ctrl()) => Default [NavForward],
- K(Key::Character("-") if ctrl()) => Default [NavBack],
- M(MouseButton::Back) => Default [NavBack],
- M(MouseButton::Forward) => _ [NavForward],
- C(((usize, usize)) => .. if unsafe { CLICKING }) => Selection [StartSelection],
- Changed => RequestBoolean(BoolRequest => BoolRequest::ReloadFile),
- K(Key::Named(Escape)) => Default [Escape],
- K(_) => Default [Edit],
- // duplicate zone
-
+ K(_) => Default [Reinsert],
M(MouseButton::Left if ctrl()) => Default [GoToDefinition(x.request.map(|x| x.1.1).or(x.result.and_then(|x| x.of.iter().find_map(|x| x.tdpp()))))],
- M(_) => _ [ClickedHover],
+ M(_) => Default [Reinsert],
},
Command(_) => K(Key::Named(Escape)) => Default,
Command(t) => K(Key::Named(Enter) if let Some(Ok(x)) = t.sel(None)) => Default [ProcessCommand((Commands, crate::commands::Cmd) => (t, x))],
@@ -144,21 +118,32 @@ Command(mut t) => K(k) => Command({ if let Some(_) = handle2(&k, &mut t.tedit, N
}; t }) [CmdTyped],
Command(t) => C(_) => _,
Command(t) => K(_) => _,
+#[cfg(target_family = "unix")]
Runnables(_x) => {
+ #[cfg(target_family = "unix")]
K(Key::Named(Escape)) => Default,
},
-Runnables(RqS::<crate::runnables::Runnables, rust_analyzer::lsp::ext::Runnables> => Rq { result: Some(mut x), request }) => {
+#[cfg(target_family = "unix")]
+Runnables(RqS::<Run, rust_analyzer::lsp::ext::RunnablesRequest> => Rq { result: Some(mut x), request }) => {
+ #[cfg(target_family = "unix")]
K(Key::Named(Tab) if shift()) => Runnables({ x.next(); Rq { result: Some(x), request }}),
+ #[cfg(target_family = "unix")]
K(Key::Named(ArrowDown)) => Runnables({ x.next(); Rq { result: Some(x), request }}),
+ #[cfg(target_family = "unix")]
K(Key::Named(ArrowUp | Tab)) => Runnables({ x.back(); Rq { result: Some(x), request }}),
+ #[cfg(target_family = "unix")]
K(Key::Named(Enter) if let Some(Ok(x_)) = x.clone().sel(None)) => Default [Run(Runnable => x_.clone())],
+ #[cfg(target_family = "unix")]
K(k) => Runnables({
if let Some(_) = handle2(&k, &mut x.tedit, None) {
x.selection = 0; x.vo = 0;
}; Rq { result: Some(x), request } }),
},
+#[cfg(target_family = "unix")]
Runnables(_x) => {
+ #[cfg(target_family = "unix")]
C(_) => _,
+ #[cfg(target_family = "unix")]
M(_) => _,
},
@@ -186,6 +171,20 @@ Symbols(Rq::<Symbols, Option<SymbolsList>, (), AQErr> => _rq) => {
C(_) => _,
M(_) => _,
},
+
+
+KillRing(crate::killring::KillRM => x) => {
+ K(Key::Named(Tab) if shift()) => KillRing({ let mut x = x; x.next(); x }),
+ K(Key::Named(ArrowDown)) => KillRing({ let mut x = x; x.next(); x }),
+ K(Key::Named(ArrowUp | Tab)) => KillRing({ let mut x = x; x.back(); x }),
+ K(Key::Named(Enter)) => Default [Revive(crate::killring::KillRM => x)],
+ K(Key::Named(Escape)) => Default,
+ K(_) => _ [KillRMHandleKey],
+ // K(_) => _ [GTLHandleKey],
+ C(_) => _,
+ M(_) => _,
+},
+
CodeAction(Rq { result : Some(_x), request }) => {
K(Key::Named(Tab) if shift()) => _ [CASelectPrev],
K(Key::Named(ArrowDown | Tab)) => _ [CASelectNext],
@@ -193,7 +192,7 @@ CodeAction(Rq { result : Some(_x), request }) => {
K(Key::Named(Enter | ArrowRight)) => _ [CASelectRight],
K(Key::Named(ArrowLeft)) => _ [CASelectLeft],
},
-CodeAction(RqS<act::CodeActions, lsp_request!("textDocument/codeAction")> => rq) => {
+CodeAction(RqS<act::CodeActions, rust_analyzer::lsp::ext::CodeActionRequest> => rq) => {
K(Key::Named(Escape)) => Default,
C(_) => _,
M(_) => _,
diff --git a/src/edi/wsedit.rs b/src/edi/wsedit.rs
index eb11a8b..55e0827 100644
--- a/src/edi/wsedit.rs
+++ b/src/edi/wsedit.rs
@@ -5,6 +5,10 @@ use lsp_types::*;
use rootcause::prelude::{IteratorExt, ResultExt};
use rootcause::report;
use ropey::Rope;
+use rust_analyzer::lsp::ext::{
+ SnippetDocumentChangeOperation, SnippetTextDocumentEdit,
+ SnippetWorkspaceEdit,
+};
use super::*;
use crate::error::WDebug;
@@ -52,23 +56,221 @@ impl Editor {
) -> rootcause::Result<()> {
self.apply_tds(
&text_document
+ .text_document_identifier
.uri
.to_file_path()
.map_err(|_| report!("sad"))?,
edits,
- TextArea::apply_snippet_tedit,
- TextArea::apply_snippet_tedit_raw,
+ |t, e| match e {
+ Edit::AnnotatedTextEdit(AnnotatedTextEdit {
+ text_edit,
+ ..
+ })
+ | Edit::TextEdit(text_edit) =>
+ Ok(drop(t.apply(text_edit)?)),
+ Edit::SnippetTextEdit(SnippetTextEdit {
+ range,
+ snippet,
+ annotation_id,
+ }) => {
+ let x2 = rust_analyzer::lsp::ext::SnippetTextEdit {
+ range: *range,
+ new_text: snippet.value.clone(),
+ insert_text_format: None,
+ annotation_id: annotation_id.clone(),
+ };
+ t.apply_snippet_tedit(&x2)
+ }
+ },
+ |e, t| match e {
+ Edit::AnnotatedTextEdit(AnnotatedTextEdit {
+ text_edit,
+ ..
+ })
+ | Edit::TextEdit(text_edit) =>
+ TextArea::apply_raw(text_edit, t),
+ Edit::SnippetTextEdit(SnippetTextEdit {
+ range,
+ snippet,
+ annotation_id,
+ }) => {
+ let x2 = rust_analyzer::lsp::ext::SnippetTextEdit {
+ range: *range,
+ new_text: snippet.value.clone(),
+ insert_text_format: None,
+ annotation_id: annotation_id.clone(),
+ };
+ TextArea::apply_snippet_tedit_raw(&x2, t)
+ }
+ },
+ // TextArea::apply_snippet_tedit,
+ // TextArea::apply_snippet_tedit_raw,
)
}
- fn apply_dco(
+ fn apply_sdc(
&mut self,
- op: DocumentChangeOperation,
+ op: SnippetDocumentChangeOperation,
) -> rootcause::Result<()> {
match op.clone() {
- DocumentChangeOperation::Edit(t) => self.apply_tde(t)?,
- DocumentChangeOperation::Op(ResourceOp::Create(
- CreateFile { uri, options, .. },
- )) => {
+ SnippetDocumentChangeOperation::Edit(
+ SnippetTextDocumentEdit { text_document, edits },
+ ) => self.apply_tds(
+ &text_document
+ .text_document_identifier
+ .uri
+ .to_file_path()
+ .map_err(|_| report!("sad"))?,
+ edits,
+ TextArea::apply_snippet_tedit,
+ TextArea::apply_snippet_tedit_raw,
+ ),
+ SnippetDocumentChangeOperation::Change(dc) =>
+ self.apply_dc(dc),
+ }
+ }
+ // pub fn apply_sdc(
+ // &mut self,
+ // x: SnippetDocumentChangeOperation,
+ // ) -> rootcause::Result<()> {
+ // match x {
+ // // self.apply_tde(x)
+ // DocumentChange::TextDocumentEdit(text_document_edit) =>
+ // self.apply_tde(text_document_edit)?,
+ // DocumentChange::CreateFile(CreateFile {
+ // uri,
+ // options,
+ // ..
+ // }) => {
+ // let f = uri
+ // .to_file_path()
+ // .map_err(|()| report!("not path"))?;
+ // let mut opts = OpenOptions::new();
+ // opts.write(true)
+ // // .create(true)
+ // .create(matches!(
+ // options,
+ // Some(CreateFileOptions {
+ // ignore_if_exists: Some(true) | None,
+ // ..
+ // }) | None
+ // ))
+ // .create_new(matches!(
+ // options,
+ // Some(CreateFileOptions {
+ // ignore_if_exists: Some(false),
+ // ..
+ // })
+ // ))
+ // .truncate(true);
+ // match opts.open(&f) {
+ // Ok(_f) => {}
+ // Err(e)
+ // if let Some(CreateFileOptions {
+ // overwrite: Some(true),
+ // ..
+ // }) = options
+ // && e.kind()
+ // == std::io::ErrorKind::AlreadyExists => {}
+ // Err(e) =>
+ // Err(e)
+ // .context_custom::<WDebug, _>(f)
+ // .context_custom::<WDebug, _>((opts, options))?,
+ // };
+ // }
+ // DocumentChange::RenameFile(RenameFile {
+ // old_uri,
+ // new_uri,
+ // options,
+ // annotation_id,
+ // }) => {
+ // let old_f = old_uri
+ // .to_file_path()
+ // .map_err(|()| report!("not path"))?;
+ // let new_f = new_uri
+ // .to_file_path()
+ // .map_err(|()| report!("not path"))?;
+
+ // // FIXME: overwrite
+ // if let Some(p) = new_f.parent()
+ // && !p.exists()
+ // {
+ // std::fs::create_dir_all(p)?;
+ // }
+ // match std::fs::rename(&old_f, &new_f) {
+ // Err(e)
+ // if e.kind()
+ // == std::io::ErrorKind::IsADirectory =>
+ // {
+ // do yeet report!("unhandled case: dir rename");
+ // }
+ // Err(e)
+ // if let Some(RenameFileOptions {
+ // ignore_if_exists: Some(true),
+ // ..
+ // }) = options
+ // && e.kind()
+ // == std::io::ErrorKind::AlreadyExists => {}
+ // Ok(_) => {}
+ // Err(e) => Err(e).context_with(|| {
+ // format!("renaming {old_f:?} to {new_f:?}")
+ // })?,
+ // }
+ // if let Some(f) = self.files.get_mut(&old_f)
+ // // .or(Some(self).filter(|x| x.origin == Some(old_f)))
+ // {
+ // f.bar.last_action =
+ // annotation_id.unwrap_or("renamed".into());
+ // f.origin = Some(new_f);
+ // f.mtime = Editor::modify(f.origin.as_deref());
+ // } else if self.origin == Some(old_f) {
+ // self.bar.last_action =
+ // annotation_id.unwrap_or("renamed".into());
+ // self.origin = Some(new_f);
+ // self.mtime = Editor::modify(self.origin.as_deref());
+ // }
+ // }
+ // DocumentChange::DeleteFile(DeleteFile {
+ // uri,
+ // options,
+ // ..
+ // }) => {
+ // let f = uri
+ // .to_file_path()
+ // .map_err(|()| report!("not path"))?;
+ // match std::fs::remove_file(&f) {
+ // Ok(()) => (),
+ // Err(e)
+ // if e.kind()
+ // == std::io::ErrorKind::IsADirectory =>
+ // {
+ // std::fs::remove_dir_all(f)?;
+ // }
+ // Err(e)
+ // if let Some(DeleteFileOptions {
+ // ignore_if_not_exists: Some(true),
+ // ..
+ // }) = options
+ // && e.kind()
+ // == std::io::ErrorKind::NotFound => {}
+ // Err(e) => do yeet e,
+ // }
+ // }
+ // };
+ // Ok(())
+ // }
+ pub fn apply_dc(
+ &mut self,
+ x: DocumentChange,
+ ) -> rootcause::Result<()> {
+ match x {
+ // self.apply_tde(x)
+ DocumentChange::TextDocumentEdit(text_document_edit) =>
+ self.apply_tde(text_document_edit)?,
+ DocumentChange::CreateFile(CreateFile {
+ uri,
+ options,
+ ..
+ }) => {
let f = uri
.to_file_path()
.map_err(|()| report!("not path"))?;
@@ -105,9 +307,12 @@ impl Editor {
.context_custom::<WDebug, _>((opts, options))?,
};
}
- DocumentChangeOperation::Op(ResourceOp::Rename(
- RenameFile { old_uri, new_uri, options, annotation_id },
- )) => {
+ DocumentChange::RenameFile(RenameFile {
+ old_uri,
+ new_uri,
+ options,
+ annotation_id,
+ }) => {
let old_f = old_uri
.to_file_path()
.map_err(|()| report!("not path"))?;
@@ -154,31 +359,11 @@ impl Editor {
self.mtime = Editor::modify(self.origin.as_deref());
}
}
- DocumentChangeOperation::Op(ResourceOp::Delete(
- DeleteFile {
- uri,
- options:
- Some(DeleteFileOptions {
- recursive: Some(true), // ??? seems redundant
- ignore_if_not_exists,
- ..
- }),
- },
- )) => {
- let f = uri
- .to_file_path()
- .map_err(|()| report!("not path"))?;
- match std::fs::remove_dir_all(f) {
- Ok(()) => (),
- Err(e)
- if e.kind() == std::io::ErrorKind::NotFound
- && ignore_if_not_exists == Some(true) => {}
- Err(e) => do yeet e,
- }
- }
- DocumentChangeOperation::Op(ResourceOp::Delete(
- DeleteFile { uri, options },
- )) => {
+ DocumentChange::DeleteFile(DeleteFile {
+ uri,
+ options,
+ ..
+ }) => {
let f = uri
.to_file_path()
.map_err(|()| report!("not path"))?;
@@ -200,8 +385,41 @@ impl Editor {
Err(e) => do yeet e,
}
}
+ };
+ Ok(())
+ }
+ pub fn apply_swsedit(
+ &mut self,
+ x: SnippetWorkspaceEdit,
+ ) -> rootcause::Result<()> {
+ match x {
+ SnippetWorkspaceEdit { document_changes: Some(x), .. } => x
+ .into_iter()
+ .map(|x| self.apply_sdc(x))
+ .collect_reports()
+ .context("couldnt apply one or more wsedits")?,
+ SnippetWorkspaceEdit { changes: Some(x), .. } => x
+ .into_iter()
+ .map(|(p, e)| {
+ self.apply_tds(
+ &p.to_file_path().map_err(|_| {
+ report!("evil path")
+ .context_custom::<WDebug, _>(e.clone())
+ })?,
+ e.clone(),
+ |x, y| x.apply(y).map(drop),
+ TextArea::apply_raw,
+ )
+ .context_custom::<WDebug, _>(e)
+ })
+ .collect_reports()
+ .context("couldnt apply one or more fs operations")?,
+ x =>
+ do yeet report!("strange workspace edit")
+ .context_custom::<WDebug, _>(x),
}
-
+ change!(self);
+ self.hist.record(&self.text);
Ok(())
}
#[must_use]
@@ -210,27 +428,11 @@ impl Editor {
x: WorkspaceEdit,
) -> rootcause::Result<()> {
match x {
- WorkspaceEdit {
- document_changes: Some(DocumentChanges::Edits(x)),
- ..
- } => x
+ WorkspaceEdit { document_changes: Some(x), .. } => x
.into_iter()
- .map(|x| self.apply_tde(x))
+ .map(|x| self.apply_dc(x))
.collect_reports()
.context("couldnt apply one or more wsedits")?,
- WorkspaceEdit {
- document_changes: Some(DocumentChanges::Operations(x)),
- ..
- } => x
- .clone()
- .into_iter()
- .map(|op: DocumentChangeOperation| {
- self.apply_dco(op.clone())
- .context_custom::<WDebug, _>(op)
- })
- .collect_reports()
- .context("couldnt apply one or more fs operations")
- .context_custom::<WDebug, _>(x)?,
WorkspaceEdit { changes: Some(x), .. } => x
.into_iter()
.map(|(p, e)| {
diff --git a/src/gotolist.rs b/src/gotolist.rs
index 2e7b304..1999446 100644
--- a/src/gotolist.rs
+++ b/src/gotolist.rs
@@ -4,10 +4,10 @@ use std::path::Path;
use dsb::Cell;
use dsb::cell::Style;
-use lsp_types::request::GotoImplementation;
use lsp_types::{
- CallHierarchyIncomingCall, CallHierarchyOutgoingCall, Location,
- LocationLink, Range,
+ CallHierarchyIncomingCall, CallHierarchyOutgoingCall, Definition,
+ DefinitionResponse, ImplementationRequest, Location, LocationLink,
+ LocationUriOnly, Range, WorkspaceSymbolLocation,
};
use crate::FG;
@@ -20,8 +20,8 @@ pub type GoToList = GenericMenu<GTL>;
pub enum GTL {}
#[derive(Debug)]
pub enum O {
- Impl(RqS<(), GotoImplementation>),
- References(RqS<(), lsp_types::request::References>),
+ Impl(RqS<(), ImplementationRequest>),
+ References(RqS<(), lsp_types::ReferencesRequest>),
Incoming(
Rq<(), Vec<CallHierarchyIncomingCall>, (), rootcause::Report>,
),
@@ -38,6 +38,7 @@ impl<'a> Key<'a> for (GoTo<'a>, Option<&'a str>) {
}
impl MenuData for GTL {
+ const NAME: &'static str = "!";
type Data = (Vec<(GoTo<'static>, Option<String>)>, Option<O>);
type Element<'a> = (GoTo<'a>, Option<&'a str>);
@@ -117,6 +118,22 @@ impl<'a> Hash for GoTo<'a> {
self.path.hash(state);
}
}
+impl From<&LocationUriOnly> for GoTo<'static> {
+ fn from(LocationUriOnly { uri }: &LocationUriOnly) -> Self {
+ Self {
+ path: Cow::Owned(uri.to_file_path().unwrap()),
+ at: At::P(0),
+ }
+ }
+}
+impl<'a> From<&'a WorkspaceSymbolLocation> for GoTo<'static> {
+ fn from(value: &'a WorkspaceSymbolLocation) -> Self {
+ match value {
+ WorkspaceSymbolLocation::Location(location) => location.into(),
+ WorkspaceSymbolLocation::LocationUriOnly(x) => x.into(),
+ }
+ }
+}
impl From<Location> for GoTo<'static> {
fn from(Location { uri, range }: Location) -> Self {
Self {
@@ -134,6 +151,16 @@ impl From<&Location> for GoTo<'static> {
}
}
+impl From<&Definition> for GoTo<'static> {
+ fn from(x: &Definition) -> Self {
+ match x {
+ Definition::LocationList([x]) | Definition::Location(x) =>
+ x.into(),
+ _ => panic!(),
+ }
+ }
+}
+
impl From<&LocationLink> for GoTo<'static> {
fn from(
LocationLink { target_uri, target_range, .. }: &LocationLink,
diff --git a/src/hov.rs b/src/hov.rs
index 48ab1cd..96725dc 100644
--- a/src/hov.rs
+++ b/src/hov.rs
@@ -1,6 +1,5 @@
use std::fmt::Debug;
use std::iter::{empty, once, repeat_n};
-use std::os::fd::AsFd;
use std::pin::pin;
use std::str::FromStr;
use std::sync::Arc;
@@ -310,7 +309,7 @@ fn t() {
let (w, h) = (400, 8000);
let (c, r) = dsb::fit(&crate::FONT, ppem, lh, (w, h));
- let cells = markdown2(c, &p(include_str!("vec.md")).unwrap());
+ let cells = markdown2(c, &p(include_str!("vec.md")).unwrap(), None);
dbg!(l(&p(include_str!("vec.md")).unwrap()));
dbg!(cells.len() / c);
dbg!(w, h);
@@ -399,7 +398,13 @@ impl DiagnosticHovr {
simplify_path(&dawg.replace('\n', "\r\n").replace("⸬", ":"))
.bytes()
{
- t.rx(b, std::fs::File::open("/dev/null").unwrap().as_fd());
+ t.rx(
+ b,
+ #[cfg(target_family = "unix")]
+ std::os::fd::AsFd::as_fd(
+ &std::fs::File::open("/dev/null").unwrap(),
+ ),
+ );
}
let y_lim = t
.cells
@@ -491,12 +496,15 @@ pub fn to_snippet<'a: 'c, 'b: 'c, 'c>(
) -> annotate_snippets::Group<'c> {
use annotate_snippets::*;
match severity {
- Some(DiagnosticSeverity::WARNING) => Level::WARNING,
- Some(DiagnosticSeverity::INFORMATION) => Level::INFO,
- Some(DiagnosticSeverity::HINT) => Level::HELP,
+ Some(DiagnosticSeverity::Warning) => Level::WARNING,
+ Some(DiagnosticSeverity::Information) => Level::INFO,
+ Some(DiagnosticSeverity::Hint) => Level::HELP,
_ => Level::ERROR,
}
- .primary_title(message)
+ .primary_title(match message {
+ lsp_types::Message::String(x) => x,
+ lsp_types::Message::MarkupContent(_) => unimplemented!(),
+ })
.element(Snippet::source(t).annotation(
AnnotationKind::Primary.span(t.l_range(*range).unwrap()),
))
diff --git a/src/killring.rs b/src/killring.rs
new file mode 100644
index 0000000..5f6438d
--- /dev/null
+++ b/src/killring.rs
@@ -0,0 +1,58 @@
+use std::path::Path;
+
+use dsb::Cell;
+use dsb::cell::Style;
+
+use crate::menu::Key;
+use crate::menu::generic::{GenericMenu, MenuData};
+use crate::text::{col, color_};
+use crate::{FG, KillRing};
+impl<'a> Key<'a> for &'a [String] {
+ fn key(&self) -> impl Into<std::borrow::Cow<'a, str>> {
+ self.join("")
+ }
+}
+pub enum KillR {}
+impl MenuData for KillR {
+ const NAME: &'static str = "symbols";
+ type Data = KillRing;
+
+ type Element<'a> = &'a [String];
+
+ fn gn(d: &Self::Data) -> impl Iterator<Item = Self::Element<'_>> {
+ println!("x{d:?}");
+ d.iter()
+ .inspect(|x| {
+ dbg!(&x);
+ })
+ .map(|x| &**x)
+ }
+
+ fn r(
+ _: &Self::Data,
+ x: Self::Element<'_>,
+ _: &Path,
+ c: usize,
+ selected: bool,
+ indices: &[u32],
+ to: &mut Vec<Cell>,
+ ) {
+ let bg = if selected { col!("#262d3b") } else { col!("#1c212b") };
+ let ds: Style = Style::new(FG, bg);
+ let mut b = vec![Cell { style: ds, letter: None }; c];
+ x.join("").chars().zip(&mut b).zip(1..).for_each(
+ |((x, y), i)| {
+ y.letter = Some(x);
+ if indices.contains(&i) {
+ y.style |= (Style::BOLD, color_("#ffcc66"));
+ }
+ },
+ );
+ to.extend(b);
+ }
+
+ fn hash<'b>(x: &'b Self::Element<'_>) -> Option<impl std::hash::Hash> {
+ Some(x)
+ }
+}
+pub type KillRM = GenericMenu<KillR>;
diff --git a/src/lsp.rs b/src/lsp.rs
index 9628740..4312cf8 100644
--- a/src/lsp.rs
+++ b/src/lsp.rs
@@ -10,15 +10,14 @@ use helix_core::syntax::config::{
LanguageServerConfiguration, LanguageServerFeatures,
};
use json_value_merge::Merge;
+use log::info;
use lsp_server::Message;
-use lsp_types::notification::*;
-use lsp_types::request::*;
use lsp_types::*;
use rootcause::report;
use tokio::sync::oneshot;
use winit::window::Window;
mod client;
-mod communication;
+pub(crate) mod communication;
pub use client::*;
mod init_opts;
mod rq;
@@ -44,12 +43,14 @@ pub fn run(
let (not_tx, not_rx) = unbounded();
let (_req_tx, _req_rx) = unbounded();
let (window_tx, window_rx) = oneshot::channel::<Arc<dyn Window>>();
+ let mut rt = tokio::runtime::Builder::new_multi_thread();
+ #[cfg(target_family = "unix")]
+ rt.enable_io();
let mut c = Client {
- tx,
+ tx: Tx(tx),
progress: Box::leak(Box::new(papaya::HashMap::new())),
- runtime: tokio::runtime::Builder::new_multi_thread()
+ runtime: rt
.enable_time()
- .enable_io()
.worker_threads(3)
.thread_name("lsp runtime")
.build()?,
@@ -60,24 +61,31 @@ pub fn run(
req_rx: _req_rx,
not_rx,
lsp_data: data,
+ workspace: workspace.clone(),
};
let mut opts = init_opts::get(
workspace,
&data.0.config,
data.1.name == "rust-analyzer",
);
+
if let Some(v) = vscode_conf {
match opts.initialization_options {
Some(ref mut x) => x.merge(&v),
None => opts.initialization_options = Some(v),
}
};
- _ = c.request::<Initialize>(&opts)?;
+ info!("spawned {}", serde_json::to_string_pretty(&opts).unwrap());
+ _ = c.request::<InitializeRequest>(&opts)?;
let x = rx
.iter()
.find_map(|x| {
serde_json::from_value::<InitializeResult>(
- x.response()?.result?,
+ match x {
+ Message::Notification(_) | Message::Request(_) => None,
+ Message::Response(response) => Some(response),
+ }?
+ .result?,
)
.ok()
})
@@ -88,10 +96,8 @@ pub fn run(
// Some(PositionEncodingKind::UTF8)
// );
c.initialized = Some(x);
- c.notify::<lsp_types::notification::Initialized>(
- &InitializedParams {},
- )?;
- c.notify::<SetTrace>(&SetTraceParams {
+ c.notify::<lsp_types::InitializedNotification>(&InitializedParams {})?;
+ c.notify::<SetTraceNotification>(&SetTraceParams {
value: lsp_types::TraceValue::Verbose,
})?;
let progress = c.progress;
diff --git a/src/lsp/client.rs b/src/lsp/client.rs
index 9bc85b5..ddbe7c4 100644
--- a/src/lsp/client.rs
+++ b/src/lsp/client.rs
@@ -1,5 +1,6 @@
use std::fmt::Debug;
use std::path::{Path, PathBuf};
+use std::sync::Arc;
use std::sync::atomic::AtomicI32;
use std::sync::atomic::Ordering::Relaxed;
@@ -13,24 +14,39 @@ use log::debug;
use lsp_server::{
Message, Notification as N, Request as LRq, Response as Re,
};
-use lsp_types::notification::*;
-use lsp_types::request::*;
use lsp_types::*;
use rootcause::option_ext::OptionExt;
use rust_analyzer::lsp::ext::*;
use tokio::sync::oneshot;
use ttools::*;
+use url::Url;
use crate::lsp::BehaviourAfter::{self, *};
-use crate::lsp::{RequestError, Require, Requiring, Rq};
+use crate::lsp::communication::{WorkDoneProgress, send};
+use crate::lsp::{RequestError, Require, Requiring, Rq, RqSendError};
use crate::text::cursor::ceach;
use crate::text::{LOADER, RopeExt, SortTedits, TextArea};
+#[derive(Debug, Clone)]
+pub struct Tx(pub Sender<Message>);
+impl std::ops::Deref for Client {
+ type Target = Tx;
+ fn deref(&self) -> &Self::Target {
+ &self.tx
+ }
+}
+impl std::ops::Deref for Tx {
+ type Target = Sender<Message>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
#[derive(Debug)]
pub struct Client {
pub runtime: tokio::runtime::Runtime,
- pub tx: Sender<Message>,
+ pub tx: Tx,
pub id: AtomicI32,
pub initialized: Option<InitializeResult>,
// pub pending: HashMap<i32, oneshot::Sender<Re>>,
@@ -39,7 +55,7 @@ pub struct Client {
ProgressToken,
Option<(WorkDoneProgress, WorkDoneProgressBegin)>,
>,
- pub diagnostics: &'static papaya::HashMap<Url, Vec<Diagnostic>>,
+ pub diagnostics: &'static papaya::HashMap<url::Url, Vec<Diagnostic>>,
#[allow(dead_code)]
// TODO: handle notifications from the server
pub not_rx: Receiver<N>,
@@ -49,11 +65,17 @@ pub struct Client {
&'static LanguageServerConfiguration,
&'static LanguageServerFeatures,
),
+ pub workspace: WorkspaceFolder,
}
impl Drop for Client {
fn drop(&mut self) {
- panic!("please dont");
+ _ = self.notify::<ExitNotification>(&());
+ println!(
+ "dropped lsp({}) @ {}",
+ self.lsp_data.1.name, self.workspace.uri
+ );
+ // panic!("please dont");
}
}
@@ -68,22 +90,25 @@ impl Client {
l: helix_core::Language,
) -> Result<(), SendError<Message>> {
let l = LOADER.language(l).config();
- self.notify::<DidOpenTextDocument>(&DidOpenTextDocumentParams {
- text_document: TextDocumentItem {
- uri: url::Url::from_file_path(f).unwrap(),
- language_id: l
- .language_server_language_id
- .clone()
- .unwrap_or(l.language_id.clone()),
- version: 0,
- text,
+ self.notify::<DidOpenTextDocumentNotification>(
+ &DidOpenTextDocumentParams {
+ text_document: TextDocumentItem {
+ uri: url::Url::from_file_path(f).unwrap(),
+ language_id: l
+ .language_server_language_id
+ .clone()
+ .unwrap_or(l.language_id.clone())
+ .into(),
+ version: 0,
+ text,
+ },
},
- })
+ )
}
pub fn close(&self, f: &Path) -> Result<(), SendError<Message>> {
- self.notify::<DidCloseTextDocument>(&DidCloseTextDocumentParams {
- text_document: f.tid(),
- })
+ self.notify::<DidCloseTextDocumentNotification>(
+ &DidCloseTextDocumentParams { text_document: f.tid() },
+ )
}
pub fn edit(
&self,
@@ -91,17 +116,16 @@ impl Client {
text: String,
) -> Result<(), SendError<Message>> {
static V: AtomicI32 = AtomicI32::new(0);
- self.notify::<lsp_types::notification::DidChangeTextDocument>(
+ self.notify::<lsp_types::DidChangeTextDocumentNotification>(
&DidChangeTextDocumentParams {
text_document: VersionedTextDocumentIdentifier {
- uri: url::Url::from_file_path(f).unwrap(),
+ text_document_identifier: f.tid(),
version: V.fetch_add(1, Relaxed),
},
- content_changes: vec![TextDocumentContentChangeEvent {
- range: None,
- range_length: None,
- text,
- }],
+ content_changes: vec![
+ (TextDocumentContentChangeWholeDocument { text })
+ .into(),
+ ],
},
)
}
@@ -109,8 +133,13 @@ impl Client {
pub fn resolve(
&self,
x: CompletionItem,
- ) -> Result<CompletionItem, RequestError<ResolveCompletionItem>> {
- self.request_immediate::<ResolveCompletionItem>(&x)
+ ) -> Result<
+ CompletionItem,
+ RequestError<lsp_request!("completionItem/resolve")>,
+ > {
+ self.request_immediate::<lsp_request!("completionItem/resolve")>(
+ &x,
+ )
}
pub fn request_complete<'me>(
@@ -123,18 +152,15 @@ impl Client {
impl Future<
Output = Result<
Option<CompletionResponse>,
- RequestError<Completion>,
+ RequestError<lsp_request!("textDocument/completion")>,
>,
- > + use<'me>,
+ > + use<>,
> {
self.caps().completion_provider.require()?;
let (rx, _) = self
- .request_::<Completion, { Redraw }>(&CompletionParams {
- text_document_position: TextDocumentPositionParams {
- text_document: f.tid(),
- position: Position { line: y as _, character: x as _ },
- },
+ .request_::<lsp_request!("textDocument/completion"), { Redraw }>(&CompletionParams {
+ text_document_position_params: TextDocumentPositionParams::new(f.tid(), Position { line: y as _, character: x as _ }),
work_done_progress_params: default(),
partial_result_params: default(),
context: Some(c),
@@ -154,7 +180,7 @@ impl Client {
Option<SignatureHelp>,
RequestError<SignatureHelpRequest>,
>,
- > + use<'me>,
+ > + use<>,
> {
self.caps().signature_help_provider.require()?;
Ok(self
@@ -246,7 +272,7 @@ impl Client {
.diagnostic_provider
.as_ref()?
{
- DiagnosticServerCapabilities::RegistrationOptions(
+ DiagnosticProvider::DiagnosticRegistrationOptions(
x,
) => x.diagnostic_options.identifier.clone()?,
_ => None?,
@@ -271,8 +297,8 @@ impl Client {
};
// dbg!(&x);
match x.clone() {
- DocumentDiagnosticReportResult::Report(
- DocumentDiagnosticReport::Full(
+ // DocumentDiagnosticReport::DocumentDiagnosticReport(
+ DocumentDiagnosticReport::RelatedFullDocumentDiagnosticReport(
RelatedFullDocumentDiagnosticReport {
related_documents,
full_document_diagnostic_report:
@@ -281,7 +307,7 @@ impl Client {
result_id,
},
},
- ),
+
) => {
let l = self.diagnostics.guard();
self.diagnostics.insert(f.tid().uri, items, &l);
@@ -289,14 +315,14 @@ impl Client {
related_documents.into_iter().flatten()
{
match rel {
- DocumentDiagnosticReportKind::Full(
+ RelatedDocument::FullDocumentDiagnosticReport(
FullDocumentDiagnosticReport {
items, ..
},
) => {
self.diagnostics.insert(uri, items, &l);
}
- DocumentDiagnosticReportKind::Unchanged(_) => {
+ RelatedDocument::UnchangedDocumentDiagnosticReport(_) => {
}
}
}
@@ -318,24 +344,23 @@ impl Client {
Vec<DocumentHighlight>,
RequestError<DocumentHighlightRequest>,
>,
- > + use<'me>,
+ > + use<>,
> {
self.caps().document_highlight_provider.require()?;
- let p = DocumentHighlightParams {
+ Ok(send!(self.request_::<{Redraw}>, "textDocument/documentHighlight", _ {
text_document_position_params: TextDocumentPositionParams {
text_document: f.tid(),
position: cursor,
},
work_done_progress_params: default(),
partial_result_params: default(),
- };
- Ok(self.request_::<lsp_request!("textDocument/documentHighlight"), {Redraw}>(&p)
+ })
.unwrap()
.0
.map(|x| x.map(|x| x.unwrap_or_default())))
}
pub fn document_symbols(
- &'static self,
+ &self,
p: &Path,
) -> Requiring<
"document_symbol",
@@ -347,8 +372,7 @@ impl Client {
> + use<>,
> {
self.caps().document_symbol_provider.require()?;
- Ok(self.request_::<lsp_request!("textDocument/documentSymbol"), { Redraw }>(
- &DocumentSymbolParams {
+ Ok(send!(self.request_::<{ Redraw }>, "textDocument/documentSymbol", _ {
text_document: p.tid(),
work_done_progress_params: default(),
partial_result_params: default(),
@@ -358,27 +382,29 @@ impl Client {
.0)
}
pub fn workspace_symbols(
- &'static self,
+ &self,
f: String,
) -> Requiring<
"workspace_symbol",
impl Future<
Output = Result<
Option<WorkspaceSymbolResponse>,
- RequestError<lsp_request!("workspace/symbol")>,
+ RequestError<
+ rust_analyzer::lsp::ext::WorkspaceSymbolRequest,
+ >,
>,
- >,
+ > + use<>,
> {
self.caps().workspace_symbol_provider.require()?;
Ok(self
- .request_::<lsp_request!("workspace/symbol"), { Redraw }>(
- &lsp_types::WorkspaceSymbolParams {
+ .request_::<rust_analyzer::lsp::ext::WorkspaceSymbolRequest, { Redraw }>(
+ &rust_analyzer::lsp::ext::WorkspaceSymbolParams {
query: f,
search_scope: Some(
- lsp_types::WorkspaceSymbolSearchScope::Workspace,
+ WorkspaceSymbolSearchScope::Workspace,
),
search_kind: Some(
- lsp_types::WorkspaceSymbolSearchKind::AllSymbols,
+ WorkspaceSymbolSearchKind::AllSymbols,
),
..Default::default()
},
@@ -391,36 +417,38 @@ impl Client {
&self,
f: &Path,
x: Vec<Position>,
- ) -> Result<Vec<Option<Position>>, RequestError<MatchingBrace>> {
- self.request_immediate::<MatchingBrace>(&MatchingBraceParams {
- text_document: f.tid(),
- positions: x,
- })
+ ) -> Result<Vec<[Position;2]>, RequestError<MatchingBraceRequest>> {
+ self.request_immediate::<MatchingBraceRequest>(
+ &MatchingBraceParams { text_document: f.tid(), positions: x },
+ )
}
- pub fn matching_brace<'a>(
- &'static self,
- f: &Path,
- t: &'a mut TextArea,
- ) {
+ pub fn matching_brace<'a>(&self, f: &Path, t: &'a mut TextArea) {
if let Ok(x) =
self.matching_brace_at(f, t.cursor.positions(&t.rope))
{
for (c, p) in t.cursor.inner.iter_mut().zip(x) {
- if let Some(p) = p {
- c.position = t.rope.l_position(p).unwrap();
- }
+ // if let Some(p) = p {
+ c.position = t.rope.l_position(p[1]).unwrap();
+ // }
}
}
}
pub fn legend(&self) -> Option<&SemanticTokensLegend> {
- match &self.caps(){
- ServerCapabilities {semantic_tokens_provider:Some(SemanticTokensServerCapabilities::SemanticTokensOptions(SemanticTokensOptions{legend,..})), ..}=> {Some(legend)},_ => None,
+ match &self.caps() {
+ ServerCapabilities {
+ semantic_tokens_provider:
+ Some(SemanticTokensProvider::SemanticTokensOptions(
+ SemanticTokensOptions { legend, .. },
+ )),
+ ..
+ } => Some(legend),
+ _ => None,
}
}
pub fn inlay(
- &'static self,
+ &self,
f: &Path,
t: &TextArea,
) -> Requiring<
@@ -433,7 +461,7 @@ impl Client {
> + use<>,
> {
self.caps().inlay_hint_provider.require()?;
- Ok(self.request_::<lsp_request!("textDocument/inlayHint"), { Redraw }>(&InlayHintParams {
+ Ok(send!(self.request_::<{ Redraw }>, "textDocument/inlayHint", _ {
work_done_progress_params: default(),
text_document: f.tid(),
range: t.to_l_range(lower::saturating::math!{
@@ -456,48 +484,49 @@ impl Client {
// }
}
pub fn format(
- &'static self,
+ &self,
f: &Path,
) -> Requiring<
"document_formatting",
impl Future<
Output = Result<
Option<Vec<TextEdit>>,
- RequestError<Formatting>,
+ RequestError<lsp_request!("textDocument/formatting")>,
>,
>,
> {
self.caps().document_formatting_provider.require()?;
- Ok(self
- .request::<lsp_request!("textDocument/formatting")>(
- &DocumentFormattingParams {
- text_document: f.tid(),
- options: FormattingOptions {
- tab_size: 4,
- insert_spaces: false,
- properties: default(),
- trim_trailing_whitespace: Some(true),
- insert_final_newline: Some(true),
- trim_final_newlines: Some(false),
- },
- work_done_progress_params: default(),
- },
- )
- .unwrap()
- .0)
+ Ok(send!(self.request, "textDocument/formatting",
+ _ {
+ text_document: f.tid(),
+ options: FormattingOptions {
+ tab_size: 4,
+ insert_spaces: false,
+ // properties: default(),
+ trim_trailing_whitespace: Some(true),
+ insert_final_newline: Some(true),
+ trim_final_newlines: Some(false),
+ },
+ work_done_progress_params: default(),
+ })
+ .unwrap()
+ .0)
}
pub fn rq_semantic_tokens(
- &'static self,
+ &self,
to: &mut Rq<
Box<[SemanticToken]>,
Box<[SemanticToken]>,
(),
- RequestError<SemanticTokensFullRequest>,
+ RequestError<lsp_request!("textDocument/semanticTokens/full")>,
>,
f: &Path,
) -> Requiring<
"semantic_tokens",
- Result<(), RequestError<SemanticTokensFullRequest>>,
+ Result<
+ (),
+ RequestError<lsp_request!("textDocument/semanticTokens/full")>,
+ >,
> {
self.caps().semantic_tokens_provider.require()?;
debug!("requested semantic tokens");
@@ -506,25 +535,23 @@ impl Client {
// return Ok(());
// };
Ok(try bikeshed Result<(), RequestError<_>> {
- let (rx, _) = self.request::<SemanticTokensFullRequest>(
- &SemanticTokensParams {
- work_done_progress_params: default(),
- partial_result_params: default(),
- text_document: f.tid(),
- },
- )?;
+ let (rx, _) = send!(self.request, "textDocument/semanticTokens/full", _ {
+ work_done_progress_params: default(),
+ partial_result_params: default(),
+ text_document: f.tid(),
+ })?;
let x = self.runtime.spawn(async move {
let t = rx.await;
let y =
t?.ok_or(RequestError::Rx(std::marker::PhantomData))?;
debug!("received semantic tokens");
- let r = match y {
- SemanticTokensResult::Partial(_) =>
- panic!("i told the lsp i dont support this"),
- SemanticTokensResult::Tokens(x) =>
- x.data.into_boxed_slice(),
- };
- Ok(r)
+ // let r = match y {
+ // SemanticTokensResult::Partial(_) =>
+ // panic!("i told the lsp i dont support this"),
+ // SemanticTokensResult::Tokens(x) =>
+ // x.data.into_boxed_slice(),
+ // };
+ Ok(y.data.into_boxed_slice())
});
to.request(x);
})
@@ -537,15 +564,17 @@ impl Client {
) -> rootcause::Result<()> {
ceach!(t.cursor, |c| try bikeshed rootcause::Result<()> {
let r = self
- .request_immediate::<OnEnter>(
+ .request_by::<OnEnterRequest>(
&TextDocumentPositionParams {
text_document: f.tid(),
position: t.to_l_position(*c).unwrap(),
},
+ acceptable_duration(),
);
match r {
- Ok(None) | Err(_) => t.enter(),
- Ok(Some(mut r)) => {
+ Ok(Ok(None)) | Err(_) | Ok(Err(_)) => { println!("hmm") ;t.enter() },
+ Ok(Ok(Some(mut r))) => {
+ println!("applying");
r.sort_tedits();
for f in r {
t.apply_snippet_tedit(&f)?;
@@ -556,15 +585,16 @@ impl Client {
Ok(())
}
pub fn runnables(
- &'static self,
+ &self,
t: &Path,
c: Option<Position>,
) -> Result<
- impl Future<Output = Result<Vec<Runnable>, RequestError<Runnables>>>
- + use<>,
- SendError<Message>,
+ impl Future<
+ Output = Result<Vec<Runnable>, RequestError<RunnablesRequest>>,
+ > + use<>,
+ RqSendError<RunnablesRequest>,
> {
- self.request::<Runnables>(&RunnablesParams {
+ self.request::<RunnablesRequest>(&RunnablesParams {
text_document: t.tid(),
position: c,
})
@@ -572,19 +602,19 @@ impl Client {
}
pub fn _child_modules(
- &'static self,
+ &self,
p: Position,
t: &Path,
) -> Result<
impl Future<
Output = Result<
- <ChildModules as Request>::Result,
- RequestError<ChildModules>,
+ <ChildModulesRequest as Request>::Result,
+ RequestError<ChildModulesRequest>,
>,
>,
- SendError<Message>,
+ RqSendError<ChildModulesRequest>,
> {
- self.request::<ChildModules>(&TextDocumentPositionParams {
+ self.request::<ChildModulesRequest>(&TextDocumentPositionParams {
position: p,
text_document: t.tid(),
})
@@ -596,17 +626,19 @@ impl Client {
) -> Result<
impl Future<
Output = Result<
- <GotoImplementation as Request>::Result,
- RequestError<GotoImplementation>,
+ <lsp_request!("textDocument/implementation") as Request>::Result,
+ RequestError<lsp_request!("textDocument/implementation")>,
>,
- >,
- SendError<Message>,
- > {
- self.request::<GotoImplementation>(&GotoImplementationParams {
- text_document_position_params: tdpp,
- work_done_progress_params: default(),
- partial_result_params: default(),
- })
+ > + use<>,
+ RqSendError<lsp_request!("textDocument/implementation")>,
+ >{
+ send!(self.request, "textDocument/implementation",
+ _ {
+ text_document_position_params: tdpp,
+ work_done_progress_params: default(),
+ partial_result_params: default(),
+ },
+ )
.map(fst)
}
@@ -617,17 +649,19 @@ impl Client {
impl Future<
Output = Result<
Option<Vec<Location>>,
- RequestError<References>,
+ RequestError<lsp_request!("textDocument/references")>,
>,
- >,
- SendError<Message>,
+ > + use<>,
+ RqSendError<lsp_request!("textDocument/references")>,
> {
- self.request::<References>(&ReferenceParams {
- text_document_position: tdpp,
- work_done_progress_params: default(),
- partial_result_params: default(),
- context: ReferenceContext { include_declaration: false },
- })
+ send!(self.request, "textDocument/references",
+ _ {
+ text_document_position_params: tdpp,
+ work_done_progress_params: default(),
+ partial_result_params: default(),
+ context: ReferenceContext { include_declaration: false },
+ },
+ )
.map(fst)
}
@@ -646,24 +680,28 @@ impl Client {
impl Future<
Output = Result<
Option<CallHierarchyItem>,
- RequestError<CallHierarchyPrepare>,
+ RequestError<
+ lsp_request!("textDocument/prepareCallHierarchy"),
+ >,
>,
- >,
- SendError<Message>,
+ > + use<>,
+ RqSendError<lsp_request!("textDocument/prepareCallHierarchy")>,
> {
- self.request::<CallHierarchyPrepare>(&CallHierarchyPrepareParams {
- text_document_position_params: at,
- work_done_progress_params: default(),
- })
+ send!(self.request, "textDocument/prepareCallHierarchy",
+ _ {
+ text_document_position_params: at,
+ work_done_progress_params: default(),
+ }
+ )
.map(fst)
.map(|x| x.map(|x| x.map(|x| x.and_then(|mut x| x.try_remove(0)))))
}
pub async fn callers(
- &self,
+ self: Arc<Self>,
at: TextDocumentPositionParams,
) -> rootcause::Result<Vec<CallHierarchyIncomingCall>> {
let calls = self
- .request::<CallHierarchyIncomingCalls>(
+ .request::<CallHierarchyIncomingCallsRequest>(
&CallHierarchyIncomingCallsParams {
item: self
.find_function(at)?
@@ -679,11 +717,11 @@ impl Client {
Ok(calls)
}
pub async fn calling(
- &self,
+ self: Arc<Self>,
at: TextDocumentPositionParams,
) -> rootcause::Result<Vec<CallHierarchyOutgoingCall>> {
let calls = self
- .request::<CallHierarchyOutgoingCalls>(
+ .request::<CallHierarchyOutgoingCallsRequest>(
&CallHierarchyOutgoingCallsParams {
item: self
.find_function(at)?
@@ -716,3 +754,7 @@ pub macro tdpp($e:expr) {
position: $e.text.to_l_position(*$e.text.cursor.first()).unwrap(),
}
}
+
+pub fn acceptable_duration() -> tokio::time::Duration {
+ tokio::time::Duration::from_millis(50)
+}
diff --git a/src/lsp/communication.rs b/src/lsp/communication.rs
index 7bc6b7c..efc44ee 100644
--- a/src/lsp/communication.rs
+++ b/src/lsp/communication.rs
@@ -7,21 +7,29 @@ use std::time::Instant;
use crossbeam::channel::{Receiver, RecvError, SendError, Sender};
use log::{debug, error, trace};
use lsp_server::{
- ErrorCode, Message, Notification as N, Request as LRq, Response as Re,
- ResponseError,
+ ErrorCode, ExtractError, Message, Notification as N, Request as LRq,
+ RequestId, Response as Re, ResponseError,
};
-use lsp_types::notification::*;
-use lsp_types::request::*;
use lsp_types::*;
+use serde::{Deserialize, Serialize};
use tokio::sync::oneshot;
+use tokio::time::error::Elapsed;
+use url::Url;
use winit::window::Window;
+#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)]
+#[serde(untagged)]
+pub enum WorkDoneProgress {
+ Begin(WorkDoneProgressBegin),
+ Report(WorkDoneProgressReport),
+ End(WorkDoneProgressEnd),
+}
use crate::lsp::BehaviourAfter::{self, *};
-use crate::lsp::RequestError;
+use crate::lsp::{RequestError, RqSendError};
pub fn handler(
window_rx: oneshot::Receiver<Arc<dyn Window + 'static>>,
progress: &papaya::HashMap<
- NumberOrString,
+ ProgressToken,
Option<(WorkDoneProgress, WorkDoneProgressBegin)>,
>,
_req_tx: Sender<LRq>,
@@ -32,19 +40,20 @@ pub fn handler(
) {
let mut map = HashMap::new();
let w = window_rx.blocking_recv().unwrap();
+ println!("got w");
loop {
crossbeam::select! {
recv(req_rx) -> x => match x {
Ok((.., BehaviourAfter::RedrawNow)) => w.request_redraw(),
Ok((x, y, and)) => {
debug!("received request {x}");
- assert!(map.insert(x, (y, Instant::now(), and)).is_none());
+ assert!(map.insert(RequestId::from(x), (y, Instant::now(), and)).is_none());
}
Err(RecvError) => return,
},
recv(rx) -> x => match x {
Ok(Message::Request(rq @ LRq { method: "window/workDoneProgress/create", .. })) => {
- match rq.load::<WorkDoneProgressCreate>() {
+ match load_rq::<lsp_request!("window/workDoneProgress/create")>(rq) {
Ok((_, x)) => {
let g = progress.guard();
progress.insert(x.token, None, &g);
@@ -65,13 +74,13 @@ pub fn handler(
if let Some(e) = &x.error {
if e.code == ErrorCode::RequestCanceled as i32 {}
else if e.code == ErrorCode::ServerCancelled as i32 {
- if let Some((s, _, t)) = map.remove(&x.id.i32()) {
+ if let Some((s, _, t)) = map.remove(&x.id) {
log::info!("request {} cancelled", x.id);
_ = s.send(x);
if t == Redraw { w.request_redraw() }
}
} else {
- if let Some((s, _, t)) = map.remove(&x.id.i32()) {
+ if let Some((s, _, t)) = map.remove(&x.id) {
_ = s.send(x.clone());
if t == Redraw { w.request_redraw() }
trace!("received error from lsp for response {x:?}");
@@ -80,7 +89,7 @@ pub fn handler(
}
}
}
- else if let Some((s, took, t)) = map.remove(&x.id.i32()) {
+ else if let Some((s, took, t)) = map.remove(&x.id) {
log::debug!("request {} took {:?}", x.id, took.elapsed());
match s.send(x) {
Ok(()) => {}
@@ -98,7 +107,7 @@ pub fn handler(
}
Ok(Message::Notification(rq @ N { method: "textDocument/publishDiagnostics", .. })) => {
debug!("got diagnostics");
- match rq.load::<PublishDiagnostics>() {
+ match load_n::<lsp_notification!("textDocument/publishDiagnostics")>(rq) {
Ok(x) => {
d.insert(x.uri, x.diagnostics, &d.guard());
w.request_redraw();
@@ -107,7 +116,8 @@ pub fn handler(
}
},
Ok(Message::Notification(x @ N { method: "$/progress", .. })) => {
- let ProgressParams {token,value:ProgressParamsValue::WorkDone(x) } = x.load::<Progress>().unwrap();
+ let ProgressParams {token,value:x } = load_n::<lsp_notification!("$/progress")>(x).unwrap();
+ let Ok(x) = serde_json::from_value::<WorkDoneProgress>(x.clone()) else { error!("{x:?}"); continue };
match x.clone() {
WorkDoneProgress::Begin(y) => {
progress.update(token, move |_| Some((x.clone(), y.clone())), &progress.guard());
@@ -129,36 +139,95 @@ pub fn handler(
}
}
}
-impl super::Client {
+#[derive(Debug)]
+#[allow(dead_code)]
+pub enum ExtractErr<T> {
+ /// The extracted message was of a different method than expected.
+ MethodMismatch(T),
+ /// Failed to deserialize the message.
+ JsonError { method: String, error: serde_json::Error },
+}
+fn load_n<T: lsp_types::Notification>(
+ me: lsp_server::Notification,
+) -> Result<T::Params, ExtractErr<lsp_server::Notification>> {
+ (T::METHOD.as_str() == me.method)
+ .ok_or(ExtractErr::MethodMismatch(me.clone()))?;
+ serde_json::from_value(me.params)
+ .map_err(|e| ExtractErr::JsonError { method: me.method, error: e })
+}
+pub fn load_rq<P: lsp_types::Request>(
+ me: LRq,
+) -> Result<(RequestId, P::Params), ExtractError<LRq>> {
+ if me.method != P::METHOD.to_string() {
+ return Err(ExtractError::MethodMismatch(me));
+ }
+ match serde_json::from_value(me.params) {
+ Ok(params) => Ok((me.id, params)),
+ Err(error) =>
+ Err(ExtractError::JsonError { method: me.method, error }),
+ }
+}
+impl super::Tx {
pub fn notify<X: Notification>(
&self,
y: &X::Params,
) -> Result<(), SendError<Message>> {
- self.tx.send(Message::Notification(N {
+ self.send(Message::Notification(N {
method: X::METHOD.into(),
params: serde_json::to_value(y).unwrap(),
}))
}
pub fn cancel(&self, rid: i32) {
- _ = self.notify::<Cancel>(&CancelParams { id: rid.into() });
+ _ = self.notify::<CancelNotification>(&CancelParams {
+ id: rid.into(),
+ });
}
+}
+impl super::Client {
pub fn request_immediate<'me, X: Request>(
&'me self,
y: &X::Params,
) -> Result<X::Result, RequestError<X>> {
- self.runtime.block_on(self.request_::<X, { Nil }>(y)?.0)
+ let _guard = self.runtime.enter();
+ self.runtime
+ .block_on(tokio::time::timeout(
+ tokio::time::Duration::from_secs(20),
+ self.request_::<X, { Nil }>(y)?.0,
+ ))
+ .unwrap()
+ }
+ pub fn request_by<'me, X: Request>(
+ &'me self,
+ y: &X::Params,
+ d: tokio::time::Duration,
+ ) -> Result<Result<X::Result, RequestError<X>>, Elapsed> {
+ let _guard = self.runtime.enter();
+ self.runtime.block_on(tokio::time::timeout(
+ d,
+ match self.request_::<X, { Nil }>(y) {
+ Err(e) => return Ok(Err(e.into())),
+ Ok((x, _)) => x,
+ },
+ ))
}
+ pub fn by<T>(
+ &self,
+ x: impl Future<Output = T>,
+ d: tokio::time::Duration,
+ ) -> Result<T, Elapsed> {
+ let _guard = self.runtime.enter();
+ self.runtime.block_on(tokio::time::timeout(d, x))
+ }
pub fn request<'me, X: Request>(
&'me self,
y: &X::Params,
) -> Result<
(
- impl Future<Output = Result<X::Result, RequestError<X>>>
- + use<'me, X>,
+ impl Future<Output = Result<X::Result, RequestError<X>>> + use<X>,
i32,
),
- SendError<Message>,
+ RqSendError<X>,
> {
self.request_::<X, { Redraw }>(y)
}
@@ -169,10 +238,10 @@ impl super::Client {
) -> Result<
(
impl Future<Output = Result<X::Result, RequestError<X>>>
- + use<'me, X, THEN>,
+ + use<X, THEN>,
i32,
),
- SendError<Message>,
+ RqSendError<X>,
> {
let id = self.id.fetch_add(1, std::sync::atomic::Ordering::AcqRel);
self.tx.send(Message::Request(LRq {
@@ -187,10 +256,11 @@ impl super::Client {
.send((id, tx, THEN))
.expect("oughtnt really fail");
}
+ let tx = self.tx.clone();
Ok((
async move {
let g = scopeguard::guard((), |()| {
- self.cancel(id);
+ tx.cancel(id);
});
let mut x = rx.await?;
@@ -234,3 +304,13 @@ impl super::Client {
self.send_to.send((0, tx, BehaviourAfter::RedrawNow))
}
}
+macro_rules! send
+ {
+ ($c:ident.$call:ident$(::<$($arg:block),*>)?, $request:tt, _ { $($field:ident: $expr:expr),* $(,)? $(,..$base:expr)? } $(,)?) => {{
+ type R = lsp_request!($request);
+ type P = <R as Request>::Params;
+ $c.$call::<R $($(,$arg)*)?>(&P { $($field: $expr),* })
+ }};
+}
+
+pub(crate) use send;
diff --git a/src/lsp/init_opts.rs b/src/lsp/init_opts.rs
index 345e2a4..797ba17 100644
--- a/src/lsp/init_opts.rs
+++ b/src/lsp/init_opts.rs
@@ -6,13 +6,13 @@ pub fn get(
conf: &Option<serde_json::Value>,
is_ra: bool,
) -> InitializeParams {
- let sym = Some(if is_ra {
- SymbolKind::ALL.to_vec()
- } else {
- (1..=26).map(SymbolKind).collect()
- });
+ // let sym = Some(if is_ra {
+ // SymbolKind::ALL.to_vec()
+ // } else {
+ // (1..=26).map(SymbolKind).collect()
+ // });
InitializeParams {
- process_id: Some(std::process::id()),
+ process_id: Some(std::process::id() as _),
capabilities: ClientCapabilities {
window: Some(WindowClientCapabilities {
@@ -21,20 +21,18 @@ pub fn get(
}),
workspace: Some(WorkspaceClientCapabilities {
symbol: Some(WorkspaceSymbolClientCapabilities {
- symbol_kind: Some(SymbolKindCapability {
- value_set: sym.clone(),
+ // symbol_kind: Some(ClientSymbolKindOptions {
+ // value_set: sym.clone(),
+ // }),
+ // tag_support: Some(ClientSymbolTagOptions {
+ // value_set: SymbolTag::ALL.to_vec(),
+ // }),
+ resolve_support: Some(ClientSymbolResolveOptions {
+ properties: vec!["location".into()],
}),
- tag_support: Some(TagSupport {
- value_set: SymbolTag::ALL.to_vec(),
- }),
- resolve_support: Some(
- WorkspaceSymbolResolveSupportCapability {
- properties: vec!["location".into()],
- },
- ),
..default()
}),
- diagnostic: Some(DiagnosticWorkspaceClientCapabilities {
+ diagnostics: Some(DiagnosticWorkspaceClientCapabilities {
refresh_support: Some(true),
}),
inlay_hint: Some(InlayHintWorkspaceClientCapabilities {
@@ -50,10 +48,12 @@ pub fn get(
failure_handling: Some(FailureHandlingKind::Abort),
normalizes_line_endings: Some(false),
change_annotation_support: Some(
- ChangeAnnotationWorkspaceEditClientCapabilities {
+ ChangeAnnotationsSupportOptions {
groups_on_label: Some(false),
},
),
+ metadata_support: None,
+ snippet_edit_support: Some(true),
}),
..default()
}),
@@ -64,47 +64,45 @@ pub fn get(
},
),
document_highlight: Some(default()),
- formatting: Some(DynamicRegistrationClientCapabilities {
+ formatting: Some(DocumentFormattingClientCapabilities {
dynamic_registration: Some(false),
}),
inlay_hint: Some(InlayHintClientCapabilities {
dynamic_registration: None,
- resolve_support: Some(
- InlayHintResolveClientCapabilities {
- properties: vec![
- "textEdits".into(),
- "tooltip".into(),
- "label.tooltip".into(),
- "label.command".into(),
- ],
- },
- ),
+ resolve_support: Some(ClientInlayHintResolveOptions {
+ properties: vec![
+ "textEdits".into(),
+ "tooltip".into(),
+ "label.tooltip".into(),
+ "label.command".into(),
+ ],
+ }),
}),
document_symbol: Some(DocumentSymbolClientCapabilities {
- tag_support: Some(TagSupport {
- value_set: SymbolTag::ALL.to_vec(),
- }),
- symbol_kind: Some(SymbolKindCapability {
- value_set: sym,
- }),
+ // tag_support: Some(ClientSymbolTagSupport {
+ // value_set: SymbolTag::ALL.to_vec(),
+ // }),
+ // symbol_kind: Some(ClientSymbolKindOptions {
+ // value_set: sym,
+ // }),
hierarchical_document_symbol_support: Some(true),
..default()
}),
- definition: Some(GotoCapability {
+ definition: Some(DefinitionClientCapabilities {
link_support: Some(true),
..default()
}),
code_action: Some(CodeActionClientCapabilities {
data_support: Some(true),
resolve_support: Some(
- CodeActionCapabilityResolveSupport {
+ ClientCodeActionResolveOptions {
properties: vec!["edit".to_string()],
},
),
code_action_literal_support: Some(
- CodeActionLiteralSupport {
+ ClientCodeActionLiteralOptions {
code_action_kind:
- CodeActionKindLiteralSupport {
+ ClientCodeActionKindOptions {
value_set: [
"",
"Empty",
@@ -123,7 +121,7 @@ pub fn get(
"source",
"source.organizeImports",
]
- .map(String::from)
+ .map(Into::into)
.into(),
},
},
@@ -133,7 +131,7 @@ pub fn get(
rename: Some(RenameClientCapabilities {
prepare_support: Some(true),
prepare_support_default_behavior: Some(
- PrepareSupportDefaultBehavior::IDENTIFIER,
+ PrepareSupportDefaultBehavior::Identifier,
),
honors_change_annotations: Some(false),
..default()
@@ -148,36 +146,40 @@ pub fn get(
diagnostic: Some(DiagnosticClientCapabilities {
dynamic_registration: None,
related_document_support: Some(true),
+ markup_message_support: None,
+ diagnostics_capabilities: default(),
}),
publish_diagnostics: Some(
PublishDiagnosticsClientCapabilities {
- related_information: Some(true),
- code_description_support: Some(true),
- data_support: Some(true),
+ // related_information: Some(true),
+ // code_description_support: Some(true),
+ // data_support: Some(true),
..default()
},
),
signature_help: Some(SignatureHelpClientCapabilities {
dynamic_registration: None,
signature_information: Some(
- SignatureInformationSettings {
+ ClientSignatureInformationOptions {
documentation_format: Some(vec![
MarkupKind::Markdown,
MarkupKind::PlainText,
]),
parameter_information: Some(
- ParameterInformationSettings {
+ ClientSignatureParameterInformationOptions {
label_offset_support: Some(true),
},
),
active_parameter_support: Some(true),
+ no_active_parameter_support: Some(true),
+
},
),
context_support: Some(false),
}),
completion: Some(CompletionClientCapabilities {
dynamic_registration: Some(false),
- completion_item: Some(CompletionItemCapability {
+ completion_item: Some(ClientCompletionItemOptions {
snippet_support: Some(true),
commit_characters_support: Some(true),
documentation_format: Some(vec![
@@ -186,12 +188,12 @@ pub fn get(
]),
deprecated_support: None,
preselect_support: None,
- tag_support: Some(TagSupport {
- value_set: vec![CompletionItemTag::DEPRECATED],
+ tag_support: Some(CompletionItemTagOptions {
+ value_set: vec![CompletionItemTag::Deprecated],
}),
resolve_support: Some(
- CompletionItemCapabilityResolveSupport {
+ ClientCompletionItemResolveOptions {
properties: vec![
"additionalTextEdits".into(),
"documentation".into(),
@@ -200,60 +202,56 @@ pub fn get(
),
insert_replace_support: Some(false),
insert_text_mode_support: Some(
- InsertTextModeSupport {
- value_set: vec![InsertTextMode::AS_IS],
+ ClientCompletionItemInsertTextModeOptions {
+ value_set: vec![InsertTextMode::AsIs],
},
),
label_details_support: Some(true),
..default()
}),
completion_item_kind: Some(
- CompletionItemKindCapability {
+ ClientCompletionItemOptionsKind {
value_set: Some(vec![
- CompletionItemKind::TEXT,
- CompletionItemKind::METHOD,
- CompletionItemKind::FUNCTION,
- CompletionItemKind::CONSTRUCTOR,
- CompletionItemKind::FIELD,
- CompletionItemKind::VARIABLE,
- CompletionItemKind::CLASS,
- CompletionItemKind::INTERFACE,
- CompletionItemKind::MODULE,
- CompletionItemKind::PROPERTY,
- CompletionItemKind::UNIT,
- CompletionItemKind::VALUE,
- CompletionItemKind::ENUM,
- CompletionItemKind::KEYWORD,
- CompletionItemKind::SNIPPET,
- CompletionItemKind::COLOR,
- CompletionItemKind::FILE,
- CompletionItemKind::REFERENCE,
- CompletionItemKind::FOLDER,
- CompletionItemKind::ENUM_MEMBER,
- CompletionItemKind::CONSTANT,
- CompletionItemKind::STRUCT,
- CompletionItemKind::EVENT,
- CompletionItemKind::OPERATOR,
- CompletionItemKind::TYPE_PARAMETER,
+ CompletionItemKind::Text,
+ CompletionItemKind::Method,
+ CompletionItemKind::Function,
+ CompletionItemKind::Constructor,
+ CompletionItemKind::Field,
+ CompletionItemKind::Variable,
+ CompletionItemKind::Class,
+ CompletionItemKind::Interface,
+ CompletionItemKind::Module,
+ CompletionItemKind::Property,
+ CompletionItemKind::Unit,
+ CompletionItemKind::Value,
+ CompletionItemKind::Enum,
+ CompletionItemKind::Keyword,
+ CompletionItemKind::Snippet,
+ CompletionItemKind::Color,
+ CompletionItemKind::File,
+ CompletionItemKind::Reference,
+ CompletionItemKind::Folder,
+ CompletionItemKind::EnumMember,
+ CompletionItemKind::Constant,
+ CompletionItemKind::Struct,
+ CompletionItemKind::Event,
+ CompletionItemKind::Operator,
+ CompletionItemKind::TypeParameter,
]),
- // value_set: Some(vec![CompletionItemKind::]),
},
),
context_support: None,
- insert_text_mode: Some(InsertTextMode::AS_IS),
- completion_list: Some(CompletionListCapability {
+ insert_text_mode: Some(InsertTextMode::AsIs),
+ completion_list: Some(CompletionListCapabilities {
item_defaults: None,
+ apply_kind_support: None,
}),
}),
semantic_tokens: Some(SemanticTokensClientCapabilities {
dynamic_registration: Some(false),
- requests: SemanticTokensClientCapabilitiesRequests {
- range: Some(true),
- full: Some(
- lsp_types::SemanticTokensFullOptions::Bool(
- true,
- ),
- ),
+ requests: ClientSemanticTokensRequestOptions {
+ range: Some(true.into()),
+ full: Some(true.into()),
},
token_modifiers: [
"associated",
@@ -313,8 +311,10 @@ pub fn get(
}),
initialization_options: conf.clone(),
trace: None,
- workspace_folders: Some(vec![workspace]),
-
+ workspace_folders_initialize_params:
+ WorkspaceFoldersInitializeParams {
+ workspace_folders: Some(vec![workspace].into()),
+ },
..default()
}
}
diff --git a/src/lsp/rq.rs b/src/lsp/rq.rs
index 1d7ef09..50a6fd3 100644
--- a/src/lsp/rq.rs
+++ b/src/lsp/rq.rs
@@ -4,15 +4,18 @@ use std::marker::PhantomData;
use crossbeam::channel::SendError;
use lsp_server::{Message, Response as Re};
-use lsp_types::DiagnosticServerCancellationData;
-use lsp_types::request::Request;
+use lsp_types::{
+ DiagnosticServerCancellationData, LspRequestMethod, MessageDirection,
+ Request,
+};
use serde::{Deserialize, Serialize};
use tokio::sync::oneshot;
use tokio::task;
use tokio_util::task::AbortOnDropHandle;
use crate::lsp::Void;
-
+#[derive(Serialize, Deserialize)]
+pub struct RqSendError<X>(Message, PhantomData<X>);
#[derive(Serialize, Deserialize)]
pub enum RequestError<X> {
Rx(PhantomData<X>),
@@ -25,7 +28,10 @@ pub type AQErr = RequestError<LSPError>;
impl Request for LSPError {
type Params = ();
type Result = ();
- const METHOD: &'static str = "<unknown method>";
+ const MESSAGE_DIRECTION: lsp_types::MessageDirection =
+ MessageDirection::ServerToClient;
+ const METHOD: LspRequestMethod<'static> =
+ LspRequestMethod::Custom("<unknown method>");
}
#[derive(Debug)]
pub struct LSPError {}
@@ -50,16 +56,42 @@ impl<X> From<oneshot::error::RecvError> for RequestError<X> {
Self::Rx(PhantomData)
}
}
+impl<X: Request> std::error::Error for RqSendError<X> {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ None
+ }
+}
impl<X: Request> std::error::Error for RequestError<X> {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
None
}
}
+impl<X> From<SendError<Message>> for RqSendError<X> {
+ fn from(x: SendError<Message>) -> Self {
+ Self(x.into_inner(), PhantomData)
+ }
+}
impl<X> From<SendError<Message>> for RequestError<X> {
fn from(x: SendError<Message>) -> Self {
Self::Send(x.into_inner())
}
}
+impl<X> From<RqSendError<X>> for RequestError<X> {
+ fn from(x: RqSendError<X>) -> Self {
+ Self::Send(x.0)
+ }
+}
+
+impl<X: Request> std::fmt::Display for RqSendError<X> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{} failed; couldnt send {:?}", X::METHOD, self.0)
+ }
+}
+impl<X: Request> std::fmt::Debug for RqSendError<X> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self, f)
+ }
+}
impl<X: Request> std::fmt::Display for RequestError<X> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
@@ -99,14 +131,15 @@ impl<const R: &'static str> Display for Unsupported<R> {
write!(f, "request {} isnt supported by this LSP", R)
}
}
-pub trait Peel<E> {
- fn peel(self) -> Result<(), E>;
+pub trait Peel<E, T> {
+ fn peel(self) -> Result<Option<T>, E>;
}
-impl<E, N> Peel<E> for Result<Result<(), E>, N> {
- fn peel(self) -> Result<(), E> {
+impl<E, N, T> Peel<E, T> for Result<Result<T, E>, N> {
+ fn peel(self) -> Result<Option<T>, E> {
match self {
Ok(Err(e)) => Err(e),
- Ok(Ok(_)) | Err(_) => Ok(()),
+ Ok(Ok(x)) => Ok(Some(x)),
+ Err(_) => Ok(None),
}
}
}
@@ -130,11 +163,11 @@ impl<T: Clone, R, D, E> Clone for Rq<T, R, D, E> {
}
}
#[derive(serde_derive::Serialize, serde_derive::Deserialize)]
-pub struct Rq<T, R, D = (), E = RequestError<R>> {
+pub struct Rq<Output, Res, Data = (), Error = LSPError> {
#[serde(skip_serializing_if = "Option::is_none", default = "none")]
- pub result: Option<T>,
+ pub result: Option<Output>,
#[serde(skip, default = "none")]
- pub request: Option<(AbortOnDropHandle<Result<R, E>>, D)>,
+ pub request: Option<(AbortOnDropHandle<Result<Res, Error>>, Data)>,
}
impl<T: Debug, R, D: Debug, E> Debug for Rq<T, R, D, E> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
diff --git a/src/lsp/vsc_settings.rs b/src/lsp/vsc_settings.rs
index 570ebe3..1734c75 100644
--- a/src/lsp/vsc_settings.rs
+++ b/src/lsp/vsc_settings.rs
@@ -6,7 +6,7 @@ use rootcause::report;
pub fn load(p: &Path, ws: &Path) -> rootcause::Result<serde_json::Value> {
let std::process::Output {stdout, stderr,.. } = std::process::Command::new("jq").stdout(Stdio::piped())
- .args(["-M", "-c", "-r", r#"reduce to_entries[] as $x ({}; setpath(($x.key | split(".")); $x.value)) | ."rust-analyzer""#, &p.to_string_lossy()]).spawn()?.wait_with_output()
+ .args(["-M", "-c", "-r", r#"reduce to_entries[] as $x ({}; setpath(($x.key | split(".")); $x.value))"#, &p.to_string_lossy()]).spawn()?.wait_with_output()
?;
let stdout = String::from_utf8(stdout)?.replace(
"${workspaceFolder}",
diff --git a/src/main.rs b/src/main.rs
index 95d2c5e..9ac477a 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,5 +1,6 @@
#![feature(
-unsized_const_params,
+ const_convert,
+ unsized_const_params,
exact_div,
yeet_expr,
const_array,
@@ -45,13 +46,15 @@ mod edi;
mod error;
mod git;
mod gotolist;
+mod killring;
mod meta;
mod rnd;
+#[cfg(target_family = "unix")]
mod runnables;
mod sym;
+#[cfg(target_family = "unix")]
mod trm;
-use std::any::TypeId;
use std::fmt::{Debug, Display};
use std::hash::Hash;
use std::mem::MaybeUninit;
@@ -62,8 +65,10 @@ use Default::default;
use NamedKey::*;
use dsb::cell::Style;
use dsb::{Cell, F};
+use env_logger::{Env, TimestampPrecision};
use fimg::Image;
use libc::{atexit, signal};
+use log::LevelFilter;
use lsp::Rq;
use lsp_types::*;
use rust_fsm::StateMachine;
@@ -83,6 +88,7 @@ use winit::window::{
};
use crate::edi::Editor;
+use crate::edi::lsp_mn::LSPM;
use crate::edi::st::*;
use crate::lsp::RqS;
use crate::text::{TextArea, col, is_word};
@@ -100,10 +106,15 @@ fn main() {
let _x = 4;
// let x = HashMap::new();
unsafe { std::env::set_var("CARGO_UNSTABLE_RUSTC_UNICODE", "true") };
- env_logger::builder()
- .filter_level(log::LevelFilter::Info)
- .parse_env("GRA_LOG")
- .init();
+ env_logger::builder().filter_level(LevelFilter::Error).init();
+ // .format_timestamp(Some(TimestampPrecision::Seconds))
+ // .filter(Some("regex_cursor"), LevelFilter::Error)
+ // .filter(Some("calloop"), LevelFilter::Error)
+ // .filter(Some("tracing::span"), LevelFilter::Error)
+ // .parse_env(Env::new().default_filter_or("info"))
+ // .filter_level(log::LevelFilter::Info)
+ // .parse_env("G"RA_LOG")
+ // .init();
// lsp::x();
entry(EventLoop::new().unwrap())
}
@@ -113,35 +124,55 @@ static mut CLICKING: bool = false;
const BG: [u8; 3] = col!("#1f2430");
const FG: [u8; 3] = [204, 202, 194];
const BORDER: [u8; 3] = col!("#ffffff");
-
+type KillRing = Vec<Box<[String]>>;
+static mut __KR: MaybeUninit<KillRing> = MaybeUninit::uninit();
static mut __ED: MaybeUninit<Editor> = MaybeUninit::uninit();
+static mut __FREQ: MaybeUninit<Freq> = MaybeUninit::uninit();
+static mut __CLEAN: bool = false;
extern "C" fn cleanup() {
- unsafe { __ED.assume_init_mut().store().unwrap() };
+ unsafe {
+ if __CLEAN == false {
+ __CLEAN = true;
+
+ match __ED
+ .assume_init_read()
+ .store(__FREQ.assume_init_mut(), __KR.assume_init_mut())
+ {
+ Ok(_) => {}
+ Err(e) => eprintln!("{e}"),
+ };
+ }
+ }
}
extern "C" fn sigint(_: i32) {
cleanup();
std::process::exit(12);
}
-type Freq = FxHashMap<TypeId, FxHashMap<u64, u16>>;
+type FID = u8;
+type Freq = FxHashMap<FID, FxHashMap<u64, u16>>;
pub(crate) fn entry(event_loop: EventLoop) {
+ let mut lsp_mn = LSPM { four: default() };
+
unsafe {
- __ED.write(match Editor::new() {
+ let (ed, freq, kr) = match Editor::new(&mut lsp_mn) {
Err(e) => {
eprintln!("failure to launch: {e}");
return;
}
Ok(x) => x,
- })
+ };
+ __ED.write(ed);
+ __FREQ.write(freq);
+ __KR.write(kr);
};
assert_eq!(unsafe { atexit(cleanup) }, 0);
unsafe { signal(libc::SIGINT, sigint as *const () as usize) };
let ed: &'static mut Editor = unsafe { __ED.assume_init_mut() };
-
- let mut freq: Freq = default();
+ let freq = unsafe { __FREQ.assume_init_mut() };
+ let kr = unsafe { __KR.assume_init_mut() };
let ppem = 18.0;
let ls = 20.0;
// let ed = Box::leak(Box::new(ed));
-
let mut fonts = dsb::Fonts::new(
F::FontRef(*FONT, &[]),
F::FontRef(*BFONT, &[]),
@@ -161,9 +192,11 @@ pub(crate) fn entry(event_loop: EventLoop) {
let app = winit_app::WinitAppBuilder::with_init(
move |elwt| {
let window = winit_app::make_window(elwt, |x| {
+ #[cfg(target_family = "unix")]
+ let x = x.with_platform_attributes(
+ Box::new(winit::platform::wayland::WindowAttributesWayland::default().with_name("com.bendn.gracilaria", "com.bendn.gracilaria"))
+ ).with_decorations(false);
x.with_title("gracilaria")
- .with_platform_attributes(Box::new(winit::platform::wayland::WindowAttributesWayland::default().with_name("com.bendn.gracilaria", "com.bendn.gracilaria")))
- .with_decorations(false)
// .with_name("com.bendn.gracilaria", "")
// .with_resize_increments(PhysicalSize::new(fw, fh))
.with_window_icon(Some(
@@ -175,6 +208,7 @@ pub(crate) fn entry(event_loop: EventLoop) {
.unwrap().into()
))
});
+
if let Some(x) = w.take() {
x.send(window.clone()).unwrap();
}
@@ -207,6 +241,15 @@ pub(crate) fn entry(event_loop: EventLoop) {
.with_event_handler(
move |(window, _context), surface, window_id, event, elwt| {
elwt.set_control_flow(ControlFlow::Wait);
+ if let Some((.., c)) = &mut ed.lsp && let Some(c) = c.take() {
+ c.send(window.clone()).unwrap();
+ }
+
+ let lsp_mn = &mut lsp_mn;
+ for lem in &lsp_mn.four {
+ lem.1.status();
+ // dbg!(lem.1);
+ }
let (fw, fh) = dsb::dims(&FONT, ppem);
let (c, r) = dsb::fit(
&FONT,
@@ -307,13 +350,13 @@ pub(crate) fn entry(event_loop: EventLoop) {
if button == MouseButton::Left {
unsafe { CLICKING = true };
}
- ed.click(button, cursor_position, window.clone());
+ ed.click(button, cursor_position, window.clone(), lsp_mn);
window.request_redraw();
}
WindowEvent::PointerButton {
button: ButtonSource::Mouse(MouseButton::Left),
..
- } => unsafe { CLICKING = false },
+ } => unsafe { CLICKING = false },
WindowEvent::MouseWheel {
device_id: _,
delta: MouseScrollDelta::LineDelta(_, rows),
@@ -322,6 +365,14 @@ pub(crate) fn entry(event_loop: EventLoop) {
ed.scroll(rows);
window.request_redraw();
}
+ WindowEvent::MouseWheel {
+ device_id: _,
+ delta: MouseScrollDelta::PixelDelta(PhysicalPosition { x:_, y }),
+ phase: _,
+ } => {
+ ed.scroll(y as f32 *5.0);
+ window.request_redraw();
+ }
WindowEvent::ModifiersChanged(modifiers) => {
unsafe { MODIFIERS = modifiers.state() };
window.request_redraw();
@@ -342,7 +393,7 @@ pub(crate) fn entry(event_loop: EventLoop) {
) {
return;
}
- if ed.keyboard(event, window,&mut freq).is_break() {
+ if ed.keyboard(event, window, freq, kr, lsp_mn).is_break() {
elwt.exit();
}
window.request_redraw();
@@ -466,11 +517,11 @@ rust_fsm::state_machine! {
pub(crate) CompletionState => #[derive(Debug)] pub(crate) CompletionAction<'i> => pub(crate) CDo
None => Click => None,
None => K(Key<&'i str> => Key::Character(k @ ("." | ":"))) => Complete(
- RqS<Complete, lsp_types::request::Completion, usize> => default()
- ) [Request(CompletionContext => CompletionContext {trigger_kind: CompletionTriggerKind::TRIGGER_CHARACTER, trigger_character:Some(k.to_string()) })],
- None => K(Key::Character(" ") if ctrl()) => Complete(default()) [Request(CompletionContext { trigger_kind: CompletionTriggerKind::INVOKED, trigger_character:None })],
+ RqS<Complete, lsp_types::CompletionRequest, usize> => default()
+ ) [Request(CompletionContext => CompletionContext {trigger_kind: CompletionTriggerKind::TriggerCharacter, trigger_character:Some(k.to_string()) })],
+ None => K(Key::Character(" ") if ctrl()) => Complete(default()) [Request(CompletionContext { trigger_kind: CompletionTriggerKind::Invoked, trigger_character:None })],
None => K(Key::Character(x) if x.chars().all(char::is_alphabetic)
- && !matches!(x, "w"|"a"|"s"|"d" if alt())) => Complete(default()) [Request(CompletionContext { trigger_kind: CompletionTriggerKind::INVOKED, trigger_character:None })],
+ && !matches!(x, "w"|"a"|"s"|"d" if alt())) => Complete(default()) [Request(CompletionContext { trigger_kind: CompletionTriggerKind::Invoked, trigger_character:None })],
None => K(_) => _,
// when
@@ -488,7 +539,7 @@ rust_fsm::state_machine! {
Complete(Rq { result: Some(x), .. }) => K(Key::Named(NamedKey::Enter)) => None [Finish(Complete => x)],
- Complete(_x) => K(_) => _ [Request(CompletionContext { trigger_kind: CompletionTriggerKind::TRIGGER_FOR_INCOMPLETE_COMPLETIONS, trigger_character:None })],
+ Complete(_x) => K(_) => _ [Request(CompletionContext { trigger_kind: CompletionTriggerKind::TriggerForIncompleteCompletions, trigger_character:None })],
}
use complete::Complete;
diff --git a/src/menu.rs b/src/menu.rs
index 7186908..ca5cb47 100644
--- a/src/menu.rs
+++ b/src/menu.rs
@@ -1,5 +1,4 @@
pub mod generic;
-use std::any::TypeId;
use std::borrow::Cow;
use std::cmp::Reverse;
use std::sync::LazyLock;
@@ -51,7 +50,7 @@ pub fn score<'a, T: Key<'a>, D: MenuData<Element<'a> = T> + 'static>(
.map(move |y| {
if let Some(f) = freq
&& filter == ""
- && let Some(f) = f.get(&TypeId::of::<D>())
+ && let Some(f) = f.get(&D::ID)
{
return (
f.get(&D::hashed(&y).unwrap())
diff --git a/src/menu/generic.rs b/src/menu/generic.rs
index 51be7e7..da465c5 100644
--- a/src/menu/generic.rs
+++ b/src/menu/generic.rs
@@ -1,4 +1,3 @@
-use std::any::TypeId;
use std::fmt::Debug;
use std::hash::Hash;
use std::path::Path;
@@ -6,9 +5,9 @@ use std::path::Path;
use Default::default;
use dsb::Cell;
-use crate::Freq;
use crate::menu::{Key, back, filter, next, score};
use crate::text::TextArea;
+use crate::{FID, Freq};
pub struct GenericMenu<T: MenuData> {
pub data: T::Data,
@@ -53,7 +52,25 @@ pub enum CorA {
Complete,
Accept,
}
-pub trait MenuData: Sized + 'static {
+
+pub trait ID {
+ const ID: FID;
+}
+impl ID for crate::commands::Cmds {
+ const ID: u8 = 0;
+}
+impl ID for crate::gotolist::GTL {
+ const ID: u8 = 1;
+}
+// RunB = 2
+impl ID for crate::sym::Symb {
+ const ID: u8 = 3;
+}
+impl ID for crate::killring::KillR {
+ const ID: u8 = 4;
+}
+pub trait MenuData: Sized + 'static + ID {
+ const NAME: &'static str;
const HEIGHT: usize = 30;
type Data;
type Element<'a>: Key<'a>;
@@ -127,6 +144,9 @@ impl<T: MenuData + 'static> GenericMenu<T> {
// coz its bottom up
back::<{ T::HEIGHT }>(n, &mut self.selection, &mut self.vo);
}
+ pub fn name(&self) -> &'static str {
+ T::NAME
+ }
pub fn sel(
&self,
@@ -144,7 +164,7 @@ impl<T: MenuData + 'static> GenericMenu<T> {
"if calling with freq, please impl hash",
);
- *fq.entry(TypeId::of::<T>())
+ *fq.entry(T::ID)
.or_default()
.entry(x)
.or_default() += 1;
diff --git a/src/rnd.rs b/src/rnd.rs
index 41d877c..181f48b 100644
--- a/src/rnd.rs
+++ b/src/rnd.rs
@@ -102,7 +102,27 @@ pub fn render(
),
_ => None,
};
-
+ let sym_sel =
+ if let State::Symbols(Rq { result: Some(menu), .. }) =
+ &ed.state
+ && let Some(Ok(UsedSI {
+ at: GoTo { at: At::R(x), .. },
+ ..
+ })) = menu.sel(None)
+ {
+ Some(x)
+ } else {
+ None
+ };
+ let gen_sel = if let State::GoToL(menu) = &ed.state
+ && let Some(Ok((GoTo { at: At::R(r), path }, _))) =
+ menu.sel(None)
+ && Some(&*path) == ed.origin.as_deref()
+ {
+ Some(r)
+ } else {
+ None
+ };
text.line_numbers(
(c, r - 1),
[67, 76, 87],
@@ -110,22 +130,12 @@ pub fn render(
(cells, (c, r)),
(1, 0),
|_text, mut f, y| {
- if let State::GoToL(menu) = &ed.state
- && let Some(Ok((GoTo { at: At::R(r), path }, _))) =
- menu.sel(None)
- && Some(&*path) == ed.origin.as_deref()
- {
+ if let Some(r) = gen_sel {
if (r.start.line..=r.end.line).contains(&(y as _)) {
f.style.fg = col!("#FFCC66");
}
}
- if let State::Symbols(Rq { result: Some(menu), .. }) =
- &ed.state
- && let Some(Ok(UsedSI {
- at: GoTo { at: At::R(x), .. },
- ..
- })) = menu.sel(None)
- {
+ if let Some(x) = sym_sel {
if (x.start.line..=x.end.line).contains(&(y as _)) {
f.style.fg = col!("#FFCC66");
}
@@ -252,14 +262,23 @@ pub fn render(
.flat_map(|diag| {
let sev = diag
.severity
- .unwrap_or(DiagnosticSeverity::ERROR);
+ .unwrap_or(DiagnosticSeverity::Error);
let sev_ = match sev {
- DiagnosticSeverity::ERROR => EType::Error,
- DiagnosticSeverity::WARNING => EType::Warning,
- DiagnosticSeverity::HINT => EType::Hint,
+ DiagnosticSeverity::Error => EType::Error,
+ DiagnosticSeverity::Warning => EType::Warning,
+ DiagnosticSeverity::Hint => EType::Hint,
_ => EType::Info,
};
- once((diag.range, &*diag.message, sev_)).chain(
+ once((
+ diag.range,
+ match &diag.message {
+ Message::String(x) => &**x,
+ Message::MarkupContent(x) =>
+ unimplemented!(),
+ },
+ sev_,
+ ))
+ .chain(
diag.related_information
.iter()
.flatten()
@@ -275,7 +294,7 @@ pub fn render(
})
.for_each(|(mut r, m, sev)| {
if let EType::Related(x) = sev
- && x != DiagnosticSeverity::ERROR
+ && x != DiagnosticSeverity::Error
{
return;
}
@@ -291,7 +310,7 @@ pub fn render(
| EType::Hint
| EType::Info => col!("#9469242c"),
EType::Related(
- DiagnosticSeverity::ERROR,
+ DiagnosticSeverity::Error,
) => col!("#dfbfff26"),
EType::Related(_) => col!("#ffad6625"),
});
@@ -332,7 +351,7 @@ pub fn render(
col!("#ff942f1b", "#f26462")
}
EType::Related(
- DiagnosticSeverity::WARNING,
+ DiagnosticSeverity::Warning,
) => {
col!("#dfbfff26", "#DFBFFF")
}
@@ -373,7 +392,7 @@ pub fn render(
z,
wt,
ed.origin.as_deref(),
- lsp!(ed).and_then(|x| x.legend()),
+ lsp!(&ed).and_then(|x| x.legend()),
ed.language,
);
@@ -385,7 +404,7 @@ pub fn render(
ed.origin
.as_ref()
.map(|x| {
- ed.workspace
+ ed.git_dir
.as_ref()
.and_then(|w| x.strip_prefix(w).ok())
.unwrap_or(&x)
@@ -571,13 +590,13 @@ pub fn render(
continue;
}
- let r = if let Some(r) = e.sticky_range {
- let r = text.l_range(r).unwrap();
- text.char_to_line(r.start)..=text.char_to_line(r.end)
- } else {
- let x = text.char_to_line(p);
- x..=x
- };
+ // let r = if let Some(r) = e.sticky_range {
+ // let r = text.l_range(r).unwrap();
+ // text.char_to_line(r.start)..=text.char_to_line(r.end)
+ // } else {
+ let x = text.char_to_line(p);
+ let r = x..=x;
+ // };
let d = Cell {
style: Style {
@@ -592,7 +611,7 @@ pub fn render(
// chain([Cell::default()], x.to_string().chars().map(Cell::basic)).chain([Cell::default()]).collect();
for (x, rel, mut cell) in text
- .colored_lines(r, lsp!(ed).and_then(|x| x.legend()))
+ .colored_lines(r, lsp!(&ed).and_then(|x| x.legend()))
{
if rel == 0 {
let rem = cells.len() % c;
@@ -847,22 +866,28 @@ pub fn render(
);
}
State::Command(x) if x.should_render() => {
- let ws = ed.workspace.as_deref().unwrap();
+ let ws = ed.git_dir.as_deref().unwrap();
let c = x.cells(50, ws, None);
drawb(&c, 50);
}
State::Symbols(Rq { result: Some(x), .. }) => {
- let ws = ed.workspace.as_deref().unwrap();
+ let ws = ed.git_dir.as_deref().unwrap();
let c = x.cells(50, ws, Some(freq));
drawb(&c, 50);
}
+ #[cfg(target_family = "unix")]
State::Runnables(Rq { result: Some(x), .. }) => {
- let ws = ed.workspace.as_deref().unwrap();
+ let ws = ed.git_dir.as_deref().unwrap();
let c = x.cells(50, ws, None);
drawb(&c, 50);
}
State::GoToL(y) => {
- let ws = ed.workspace.as_deref().unwrap();
+ let ws = ed.git_dir.as_deref().unwrap();
+ let c = y.cells(50, ws, None);
+ drawb(&c, 50);
+ }
+ State::KillRing(y) => {
+ let ws = ed.git_dir.as_deref().unwrap();
let c = y.cells(50, ws, None);
drawb(&c, 50);
}
@@ -1088,7 +1113,13 @@ pub fn simplify_path(x: &str) -> String {
static RUST_SRC: LazyLock<Regex> = LazyLock::new(|| {
Regex::new(r".rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library").unwrap()
});
- let x = x.replace(env!("HOME"), " ");
+ let x = x.replace(
+ #[cfg(target_family = "unix")]
+ env!("HOME"),
+ #[cfg(target_family = "windows")]
+ env!("HOMEPATH"),
+ " ",
+ );
[(&*RUST_SRC, " "), (&*DEP, " /$name"), (&*DEP2, " /$name")]
.into_iter()
.fold(x, |acc, (r, repl)| r.replace(&acc, repl).into_owned())
diff --git a/src/runnables.rs b/src/runnables.rs
index ee3970d..e70aab9 100644
--- a/src/runnables.rs
+++ b/src/runnables.rs
@@ -16,6 +16,7 @@ use crate::trm;
pub enum Runb {}
impl MenuData for Runb {
+ const NAME: &'static str = "runnables";
type Data = Vec<Runnable>;
type Element<'a> = &'a Runnable;
@@ -190,3 +191,7 @@ pub fn run(
}
}
}
+
+impl crate::menu::generic::ID for crate::runnables::Runb {
+ const ID: u8 = 2;
+}
diff --git a/src/sig.rs b/src/sig.rs
index e1e0cfd..884fbac 100644
--- a/src/sig.rs
+++ b/src/sig.rs
@@ -3,8 +3,8 @@ use std::iter::repeat_n;
use dsb::Cell;
use dsb::cell::Style;
use lsp_types::{
- MarkupContent, ParameterInformation, SignatureHelp,
- SignatureInformation,
+ MarkupContent, ParameterInformation, ParameterInformationLabel,
+ SignatureHelp, SignatureInformation,
};
use crate::FG;
@@ -16,9 +16,14 @@ pub fn active(
let y = &sig.signatures.get(sig.active_signature? as usize)?;
Some((
y,
- sig.active_parameter
- .zip(y.parameters.as_ref())
- .and_then(|(i, x)| x.get(i as usize)),
+ sig.active_parameter.zip(y.parameters.as_ref()).and_then(
+ |(i, x)| {
+ x.get(match i {
+ lsp_types::ActiveParameter::Int(n) => n as usize,
+ lsp_types::ActiveParameter::Null => return None,
+ })
+ },
+ ),
))
}
@@ -32,8 +37,8 @@ pub fn sig(
let sig = y.label.chars().zip(0..).map(|(x, i)| {
let mut a = ds.basic(x);
if p.is_some_and(|x| match x.label {
- lsp_types::ParameterLabel::Simple(_) => false,
- lsp_types::ParameterLabel::LabelOffsets([a, b]) =>
+ ParameterInformationLabel::String(_) => false,
+ ParameterInformationLabel::Tuple((a, b)) =>
(a..b).contains(&i),
}) {
a.style |= (Style::BOLD, color_("#ffcc66"));
diff --git a/src/sym.rs b/src/sym.rs
index c569741..fbffbef 100644
--- a/src/sym.rs
+++ b/src/sym.rs
@@ -5,10 +5,12 @@ use std::path::{Path, PathBuf};
use Default::default;
use dsb::Cell;
use dsb::cell::Style;
-use itern::Iter3;
+use itern::{Iter3, Iter4};
use lsp_types::*;
+use url::Url;
use crate::FG;
+use crate::complete::i;
use crate::gotolist::At;
pub use crate::gotolist::GoTo;
use crate::menu::generic::{GenericMenu, MenuData};
@@ -17,6 +19,7 @@ use crate::rnd::simplify_path;
use crate::text::{Bookmarks, col, color_, set_a};
pub enum Symb {}
impl MenuData for Symb {
+ const NAME: &'static str = "symbols";
type Data = (
SymbolsList,
Vec<SymbolInformation>,
@@ -31,38 +34,48 @@ impl MenuData for Symb {
(r, tree, bmks, _, origin): &Self::Data,
) -> impl Iterator<Item = Self::Element<'_>> {
match r {
- SymbolsList::Document(DocumentSymbolResponse::Flat(x)) =>
- Iter3::A(x.iter().map(UsedSI::from)),
- SymbolsList::Document(DocumentSymbolResponse::Nested(x)) =>
- Iter3::B(
- gen {
- for bmk in &**bmks {
- yield UsedSI {
- name: &bmk.text,
- kind: SymbolKind::BOOKMARK,
- tags: None,
- at: GoTo {
- path: origin.into(),
- at: At::P(bmk.position),
- },
- right: None,
- }
+ SymbolsList::Document(
+ DocumentSymbolResponse::SymbolInformationList(x),
+ ) => Iter4::A(x.iter().map(UsedSI::from)),
+ SymbolsList::Document(
+ DocumentSymbolResponse::DocumentSymbolList(x),
+ ) => Iter4::B(
+ gen {
+ for bmk in &**bmks {
+ yield UsedSI {
+ name: &bmk.text,
+ // kind: SymbolKind::Bookmark,
+ kind: SymbolKind::Class, // FIXME
+ tags: None,
+ at: GoTo {
+ path: origin.into(),
+ at: At::P(bmk.position),
+ },
+ right: None,
}
}
- .chain(x.iter().flat_map(
- move |x| gen move {
- let mut q = VecDeque::with_capacity(12);
- q.push_back(x);
- while let Some(x) = q.pop_front() {
- q.extend(x.children.iter().flatten());
- yield (x, origin).into();
- }
- },
- )),
- ),
- SymbolsList::Workspace(WorkspaceSymbolResponse::Flat(x)) =>
- Iter3::C(chain(tree, x.iter()).map(UsedSI::from)),
- _ => unreachable!("please no"),
+ }
+ .chain(x.iter().flat_map(
+ move |x| gen move {
+ let mut q = VecDeque::with_capacity(12);
+ q.push_back(x);
+ while let Some(x) = q.pop_front() {
+ q.extend(x.children.iter().flatten());
+ yield (x, origin).into();
+ }
+ },
+ )),
+ ),
+ SymbolsList::Workspace(
+ WorkspaceSymbolResponse::WorkspaceSymbolList(x),
+ ) => Iter4::C(chain(
+ tree.iter().map(UsedSI::from),
+ x.iter().map(UsedSI::from),
+ )),
+ SymbolsList::Workspace(
+ WorkspaceSymbolResponse::SymbolInformationList(x),
+ ) => Iter4::D(chain(tree, x.iter()).map(UsedSI::from)),
+ // _ => unreachable!("please no"),
}
}
@@ -96,7 +109,7 @@ pub struct UsedSI<'a> {
impl<'a> std::hash::Hash for UsedSI<'a> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.name.hash(state);
- self.kind.0.hash(state);
+ self.kind.hash(state);
self.at.hash(state);
self.right.hash(state);
}
@@ -104,11 +117,9 @@ impl<'a> std::hash::Hash for UsedSI<'a> {
impl<'a> From<&'a SymbolInformation> for UsedSI<'a> {
fn from(
SymbolInformation {
- name,
- kind,
- tags,
+ base_symbol_information:
+ BaseSymbolInformation { name, kind, tags, container_name },
location,
- container_name,
..
}: &'a SymbolInformation,
) -> Self {
@@ -121,6 +132,24 @@ impl<'a> From<&'a SymbolInformation> for UsedSI<'a> {
}
}
}
+impl<'a> From<&'a WorkspaceSymbol> for UsedSI<'a> {
+ fn from(
+ WorkspaceSymbol {
+ location,
+ data: _,
+ base_symbol_information:
+ BaseSymbolInformation { name, kind, tags, container_name },
+ }: &'a WorkspaceSymbol,
+ ) -> Self {
+ UsedSI {
+ name,
+ kind: *kind,
+ tags: tags.as_deref(),
+ at: location.into(),
+ right: container_name.as_deref(),
+ }
+ }
+}
impl<'a> From<(&'a DocumentSymbol, &'a PathBuf)> for UsedSI<'a> {
fn from(
(
@@ -159,7 +188,9 @@ pub enum SymbolsList {
}
impl Default for SymbolsList {
fn default() -> Self {
- Self::Workspace(WorkspaceSymbolResponse::Flat(vec![]))
+ Self::Workspace(WorkspaceSymbolResponse::WorkspaceSymbolList(
+ vec![],
+ ))
}
}
@@ -168,8 +199,17 @@ impl GenericMenu<Symb> {
let tree = tree
.iter()
.map(|x| SymbolInformation {
- name: x.file_name().unwrap().to_str().unwrap().to_string(),
- kind: SymbolKind::FILE,
+ base_symbol_information: BaseSymbolInformation {
+ name: x
+ .file_name()
+ .unwrap()
+ .to_str()
+ .unwrap()
+ .to_string(),
+ kind: SymbolKind::File,
+ container_name: None,
+ tags: None,
+ },
location: Location {
range: lsp_types::Range {
end: default(),
@@ -177,10 +217,9 @@ impl GenericMenu<Symb> {
},
uri: Url::from_file_path(&x).unwrap(),
},
- container_name: None,
+
#[allow(deprecated)]
deprecated: None,
- tags: None,
})
.collect();
Self { data: (default(), tree, bmk, default(), orig), ..default() }
@@ -210,35 +249,35 @@ fn r<'a>(
const MAP: [([u8; 3], [u8; 3], &str); 85] = {
(
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"),
+ const { i(SymbolKind::File) } => ("#9a9b9a", "󰈙 "),
+ const { i(SymbolKind::Method) } | const { i(SymbolKind::Function) } => ("#FFD173", "λ "),
+ const { i(SymbolKind::Constructor) } => ("#FFAD66", "->"),
+ const { i(SymbolKind::Field) } => ("#E06C75", "x."),
+ const { i(SymbolKind::Variable) } => ("#E06C75", "x "),
+ const { i(SymbolKind::Module) } => ("#D5FF80", "::"),
+ const { i(SymbolKind::Property) } => ("#e6e1cf", "x."),
+ // const { SymbolKind::Val.0 as usize } => ("#DFBFFF", "4 "),
+ const { i(SymbolKind::Enum) } => ("#73b9ff", "u󰓹"),
+ const { i(SymbolKind::EnumMember) } => ("#73b9ff", ":󰓹"),
+ // const { SymbolKind::Snipp.0 as usize } => ("#9a9b9a", "! "),
+ const { i(SymbolKind::Interface) } => ("#E5C07B", "t "),
+ // const { SymbolKind::Referen.0 as usize } => ("#9a9b9a", "& "),
+ const { i(SymbolKind::Constant) } => ("#DFBFFF", "N "),
+ const { i(SymbolKind::Struct) } => ("#73D0FF", "X{"),
+ const { i(SymbolKind::Operator) } => ("#F29E74", "+ "),
+ const { i(SymbolKind::TypeParameter) } => ("#9a9b9a", "T "),
+ // const { SymbolKind::Keyword.0 as usize } => ("#FFAD66", "as"),
- const { SymbolKind::MACRO.0 as usize } => ("#f28f74", "! "),
- const { SymbolKind::PROC_MACRO.0 as usize } => ("#f28f74", "r!"),
- const { SymbolKind::BOOKMARK.0 as usize } => ("#73D0FF", "󰃀 "),
+ // const { SymbolKind::Macro.0 as usize } => ("#f28f74", "! "),
+ // const { SymbolKind::ProcMacro.0 as usize } => ("#f28f74", "r!"),
+ // const { SymbolKind::Bookmark.0 as usize } => ("#73D0FF", "󰃀 "),
_ => ("#9a9b9a", " ")
})
.map(
const |(x, y)| (set_a(color_(x), 0.5), color_(x), y),
)
};
- let (bgt, col, ty) = MAP[x.kind.0 as usize];
+ let (bgt, col, ty) = MAP[i(x.kind)];
b.iter_mut().zip(ty.chars()).for_each(|(x, c)| {
*x = (Style::new(col, bgt) | Style::BOLD).basic(c)
});
diff --git a/src/text.rs b/src/text.rs
index 923a23d..59dd5ae 100644
--- a/src/text.rs
+++ b/src/text.rs
@@ -16,14 +16,14 @@ use helix_core::syntax::{HighlightEvent, Loader};
use implicit_fn::implicit_fn;
use itertools::Itertools;
use lsp_types::{
- DocumentSymbol, Location, SemanticTokensLegend, SnippetTextEdit,
- TextEdit,
+ DocumentSymbol, Edit, Location, SemanticTokensLegend, TextEdit,
};
pub use manipulations::Manip;
use rootcause::option_ext::OptionExt;
use rootcause::prelude::{IteratorExt, ResultExt};
use rootcause::report;
use ropey::{Rope, RopeSlice};
+use rust_analyzer::lsp::ext::SnippetTextEdit;
use serde::{Deserialize, Serialize};
use tree_house::Language;
pub mod cursor;
@@ -275,16 +275,14 @@ impl TextArea {
self.changes
.inner
.push(Action::Inserted { at: c, insert: with.to_string() });
+ let cc = with.chars().count();
let manip = |x| {
- if x < c {
- Manip::Unmoved(x)
- } else {
- Manip::Moved(x + with.chars().count())
- }
+ if x < c { Manip::Unmoved(x) } else { Manip::Moved(x + cc) }
};
self.tabstops.as_mut().map(|x| x.manipulate(manip));
self.cursor.manipulate(manip);
self.bookmarks.manipulate(manip);
+
for m in self
.inlays
.range(Marking::idx(c as _)..)
@@ -297,7 +295,7 @@ impl TextArea {
std::collections::btree_set::Entry::Vacant(_) =>
unreachable!(),
};
- m.position += with.chars().count() as u32;
+ m.position += cc as u32;
self.inlays.insert(m);
}
self.tokens.iter_mut().for_each(|d| d.manip(manip));
@@ -360,7 +358,7 @@ impl TextArea {
text: &'b mut Rope,
) -> rootcause::Result<()> {
match insert_text_format {
- Some(lsp_types::InsertTextFormat::SNIPPET) => {
+ Some(lsp_types::InsertTextFormat::Snippet) => {
let begin = text.l_position(range.start).ok_or_report()?;
let end = text.l_position(range.end).ok_or_report()?;
text.try_remove(begin..end)?;
@@ -382,7 +380,7 @@ impl TextArea {
SnippetTextEdit { range,new_text, insert_text_format, .. }: &'b SnippetTextEdit,
) -> rootcause::Result<()> {
match insert_text_format {
- Some(lsp_types::InsertTextFormat::SNIPPET) => self
+ Some(lsp_types::InsertTextFormat::Snippet) => self
.apply_snippet(&TextEdit {
range: range.clone(),
new_text: new_text.clone(),
@@ -525,13 +523,11 @@ impl TextArea {
Some(x) => {
self.cursor.one(Cursor::new(x.r().end, &self.rope));
}
- None => {
- self.cursor.one(Cursor::new(
- x.last.clone().unwrap().r().end,
- &self.rope,
- ));
+ None if let Some(x) = &x.last => {
+ self.cursor.one(Cursor::new(x.r().end, &self.rope));
self.tabstops = None;
}
+ None => self.tabstops = None,
},
}
}
@@ -806,9 +802,9 @@ impl TextArea {
.take(c)
.zip(0..)
{
- if e.c() != '\n' {
+ if e.c() != '\n' && e.c() != '\r' {
cells.get((x + self.ho, y)).unwrap().letter =
- Some(e.c());
+ Some(if e.c() == '\t' { ' ' } else { e.c() });
let s =
&mut cells.get((x + self.ho, y)).unwrap().style;
@@ -1353,7 +1349,7 @@ fn apply() {
}
"#,
);
-
+ use lsp_types::*;
t.apply_snippet(&TextEdit {
range: lsp_types::Range {
start: Position { line: 0, character: 8 },
@@ -1386,7 +1382,7 @@ fn apply2() {
}",
);
- use lsp_types::Range;
+ use lsp_types::*;
let mut th = [
TextEdit {
range: Range {
@@ -1451,12 +1447,21 @@ fn apply2() {
pub trait SortTedits {
fn sort_tedits(&mut self);
}
+impl SortTedits for [Edit] {
+ fn sort_tedits(&mut self) {
+ self.as_mut().sort_by_key(|t| match t {
+ Edit::TextEdit(t) => Reverse(t.range.start),
+ Edit::AnnotatedTextEdit(t) => Reverse(t.text_edit.range.start),
+ Edit::SnippetTextEdit(t) => Reverse(t.range.start),
+ });
+ }
+}
impl SortTedits for [TextEdit] {
fn sort_tedits(&mut self) {
self.as_mut().sort_by_key(|t| Reverse(t.range.start));
}
}
-impl SortTedits for [SnippetTextEdit] {
+impl SortTedits for [rust_analyzer::lsp::ext::SnippetTextEdit] {
fn sort_tedits(&mut self) {
self.as_mut().sort_by_key(|t| Reverse(t.range.start));
}
@@ -1464,13 +1469,13 @@ impl SortTedits for [SnippetTextEdit] {
#[test]
fn inlays() {
- use lsp_types::{InlayHint, InlayHintLabel};
+ use lsp_types::InlayHint;
let mut t = TextArea::default();
_ = t.insert("let x = 4;");
t.set_inlay(&[InlayHint {
- position: Position { line: 0, character: 4 },
- label: InlayHintLabel::String("u".into()),
- kind: Some(lsp_types::InlayHintKind::TYPE),
+ position: lsp_types::Position { line: 0, character: 4 },
+ label: lsp_types::Label::String("u".into()),
+ kind: Some(lsp_types::InlayHintKind::Type),
text_edits: None,
tooltip: None,
padding_left: None,
@@ -1486,7 +1491,10 @@ fn inlays() {
Char('t', 2, 2),
Char(' ', 3, 3),
Fake(
- &Marking { position: 4, data: Box::new([('u', None)]) },
+ Cow::Owned(Marking {
+ position: 4,
+ data: vec![('u', None)].into_boxed_slice(),
+ }),
0,
4,
'u'
diff --git a/src/text/cursor.rs b/src/text/cursor.rs
index 32b33a7..077a750 100644
--- a/src/text/cursor.rs
+++ b/src/text/cursor.rs
@@ -93,8 +93,11 @@ pub fn caster<T, U>(x: impl FnMut(T) -> U) -> impl FnMut(T) -> U {
}
pub macro ceach($cursor: expr, $f:expr $( => $q:tt)?) {
for i in (0..$cursor.inner.len()) {
- let c = *$cursor.inner.get(i).expect("aw dangit");
- caster::<Cursor, _>($f)(c) $($q)?;
+ if let Some(&c) = $cursor.inner.get(i) {
+ caster::<Cursor, _>($f)(c) $($q)?;
+ } else {
+ log::error!("for some reason the number of cursors has changed.");
+ }
}
$cursor.coalesce();
}
@@ -506,4 +509,14 @@ impl Cursors {
// ) -> Vec<std::ops::Range<usize>> {
// panic!();
// }
+
+ pub fn sels<'a>(
+ &self,
+ text: &'a Rope,
+ ) -> std::iter::FilterMap<
+ impl Iterator<Item = Cursor> + ExactSizeIterator,
+ impl FnMut(Cursor) -> Option<RopeSlice<'a>>,
+ > {
+ self.iter().filter_map(|x| Some(text.get_slice(x.sel?)?))
+ }
}
diff --git a/src/text/hist.rs b/src/text/hist.rs
index 97a05c7..05a5bcb 100644
--- a/src/text/hist.rs
+++ b/src/text/hist.rs
@@ -197,7 +197,7 @@ impl Hist {
let c = take(&mut x.changes);
self.history.push(Diff(c, [take(&mut self.lc), x.cursor.clone()]));
self.lc = x.cursor.clone();
- println!("push {}", self.history.last().unwrap());
+ // println!("push {}", self.history.last().unwrap());
self.redo_history.clear();
take(&mut self.last);
self.last_edit = Instant::now();
@@ -211,14 +211,21 @@ impl Hist {
}
pub fn undo(&mut self, t: &mut TextArea) -> ropey::Result<Option<()>> {
self.push_if_changed(t);
- self.undo_()
+ let r = self
+ .undo_()
.map(|x| {
let r = x.apply(t, false);
self.lc = t.cursor.clone();
self.last = t.changes.clone();
r
})
- .transpose()
+ .transpose();
+ let l = t.len_chars();
+ t.cursor
+ .inner
+ .iter_mut()
+ .for_each(|x| x.position = x.position.min(l));
+ r
}
pub fn redo(&mut self, t: &mut TextArea) -> ropey::Result<Option<()>> {
self.redo_()
diff --git a/src/text/inlay.rs b/src/text/inlay.rs
index 37b98cf..049aad7 100644
--- a/src/text/inlay.rs
+++ b/src/text/inlay.rs
@@ -1,5 +1,5 @@
use Default::default;
-use lsp_types::{InlayHint, InlayHintLabel, Location};
+use lsp_types::{InlayHint, Label, Location};
use serde_derive::{Deserialize, Serialize};
use crate::text::{RopeExt, TextArea};
@@ -37,11 +37,11 @@ impl TextArea {
pub fn set_inlay(&mut self, inlay: &[InlayHint]) {
self.inlays = inlay
.iter()
- .map(|i| {
+ .filter_map(|i| {
let mut label = match &i.label {
- InlayHintLabel::String(x) =>
+ Label::String(x) =>
x.chars().map(|x| (x, None)).collect::<Vec<_>>(),
- InlayHintLabel::LabelParts(v) => v
+ Label::InlayHintLabelPartList(v) => v
.iter()
.flat_map(|x| {
x.value
@@ -56,8 +56,8 @@ impl TextArea {
if i.padding_right == Some(true) {
label.push((' ', None));
}
- let position = self.l_position(i.position).unwrap() as _;
- Marking { position, data: label.into() }
+ let position = self.l_position(i.position)? as _;
+ Some(Marking { position, data: label.into() })
})
.collect();
}
diff --git a/src/text/semantic_tokens.rs b/src/text/semantic_tokens.rs
index f7c414a..8b09851 100644
--- a/src/text/semantic_tokens.rs
+++ b/src/text/semantic_tokens.rs
@@ -14,8 +14,11 @@ use crate::text::manipulations::Manip;
Copy, Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize,
)]
pub struct TokenD {
+ #[serde(rename = "0")]
pub range: (u32, u32),
+ #[serde(rename = "1")]
pub ty: u32,
+ #[serde(rename = "2")]
pub modifiers: u32,
}
impl TokenD {