Skip to content

Commit

Permalink
LSP init
Browse files Browse the repository at this point in the history
  • Loading branch information
Redhawk18 committed May 25, 2024
1 parent 95f9e0a commit 1b162f5
Show file tree
Hide file tree
Showing 10 changed files with 216 additions and 26 deletions.
16 changes: 11 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[package]
name = "blaze"
name = "kuiper"
description = "A blazing fast Integrated Development Environment, meant to give power back to developers."
version.workspace = true
edition.workspace = true
Expand All @@ -9,31 +9,37 @@ license.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
blaze_gui.workspace = true
kuiper_gui.workspace = true
kuiper_lsp.workspace = true
pretty_env_logger.workspace = true

[workspace]
members = [ "gui" ]
members = [ "gui" , "lsp"]

[workspace.package]
version = "0.1.0"
edition = "2021"
authors = ["Redhawk18"]
license = "MIT"
license = "MPL-2.0"

[workspace.dependencies]
blaze_gui = { path = "gui" }
kuiper_gui = { path = "gui" }
kuiper_lsp = { path = "lsp" }

async-lsp = { version = "0.2", features = ["tokio"] }
dark-light = "1.0"
iced = { version = "0.12", features = ["advanced", "tokio"] }
iced_aw = { version = "0.8", features = ["icons", "menu","tab_bar"], default-features = false }
jsonrpc = "0.17.0"
log = "0.4"
lsp-types = "*"
pattern_code = "0.1"
pretty_env_logger = "0.5"
rfd = { version = "0.13", features = ["xdg-portal", "tokio"], default-features = false}
slotmap = "1.0"
snafu = "0.8"
tokio = { version = "1", features = ["fs"] }


[patch.crates-io]
iced_aw = { git = 'https:/iced-rs/iced_aw.git', rev = '99c12f1' }
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<div align="center">

# Blaze
# Kuiper

[![Builds](https://img.shields.io/github/actions/workflow/status/Redhawk18/code-editor/build.yml)](https:/Redhawk18/code-editor/actions/workflows/build.yml)
[![License](https://img.shields.io/github/license/Redhawk18/code-editor)](https:/Redhawk18/code-editor/blob/main/LICENSE)
[![Builds](https://img.shields.io/github/actions/workflow/status/Redhawk18/kuiper/build.yml)](https:/Redhawk18/kuiper/actions/workflows/build.yml)
[![License](https://img.shields.io/github/license/Redhawk18/kuiper)](https:/Redhawk18/kuiper/blob/main/LICENSE)

A blazing fast [Integrated Development Environment](https://en.wikipedia.org/wiki/Integrated_development_environment), meant to give power back to developers.

Expand All @@ -21,13 +21,13 @@ Currently to install
1. Clone the repository

```
git clone [email protected]:Redhawk18/blaze.git
git clone [email protected]:Redhawk18/kuiper.git
```

2. Compile and install the program

```
cargo install --path blaze
cargo install --path kuiper
```

3. Add given path to your `$PATH`
Expand All @@ -40,20 +40,20 @@ If youre operating system needs additional packages please create a pull request
<summary>OpenSuse</summary>

```
sudo zypper install atkmm-devel gdk-pixbuf-devel gdk-pixbuf-xlib-devel glib2-devel gtk3-devel harfbuzz-devel pkg-config rustup
sudo zypper install atkmm-devel pkg-config rustup
```
</details>

1. Clone the repository

```
git clone [email protected]:Redhawk18/blaze.git
git clone [email protected]:Redhawk18/kuiper.git
```

2. Go into the repository

```
cd blaze
cd kuiper
```

3. Compiling
Expand Down
13 changes: 8 additions & 5 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,21 @@

To add some order to this project these objectives need to be completed.

[x] basic gui features (open file, save, quit)
[ x ] basic gui features (open file, save, quit)

[x] gui theme
[ x ] gui theme

[x] pane grid
[ x ] pane grid

[x] file type recognition
[ x ] file type recognition

[x] code icons
[ x ] code icons

### Explore: system shell in gui
A shell widget within iced seems the most simple out of the first few widgets and it is very helpful to users. Revisiting this idea, `iced_term` is what should be used.

### Program: custom text editor widget
We require highlighting and tooltips when the LSP gives us warnings or errors. Also look into inline hints with in the text editor.

### Program: A LSP client
My personal understanding is next to none current, so this will be a giant undertaking.
2 changes: 1 addition & 1 deletion gui/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[package]
name = "blaze_gui"
name = "kuiper_gui"
version.workspace = true
edition.workspace = true
authors.workspace = true
Expand Down
12 changes: 6 additions & 6 deletions gui/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ use slotmap::{DefaultKey, SlotMap};
use std::path::PathBuf;

pub fn start_gui() -> iced::Result {
Blaze::run(Settings::default())
Kuiper::run(Settings::default())
}

pub(crate) struct Blaze {
pub(crate) struct Kuiper {
data: SlotMap<DefaultKey, Buffer>,
panes: Panes,
}
Expand Down Expand Up @@ -73,7 +73,7 @@ pub(crate) enum Message {
TextEditorUpdate(Action),
}

impl Blaze {
impl Kuiper {
pub(crate) fn get_panestate(&self) -> &PaneState {
self.panes.data.get(self.panes.active).unwrap()
}
Expand Down Expand Up @@ -121,15 +121,15 @@ impl PaneState {
}
}

impl Application for Blaze {
impl Application for Kuiper {
type Executor = executor::Default;
type Message = Message;
type Theme = Theme;
type Flags = ();

fn new(_flags: Self::Flags) -> (Self, Command<Self::Message>) {
(
Blaze {
Kuiper {
data: SlotMap::default(),
panes: Panes::default(),
},
Expand All @@ -141,7 +141,7 @@ impl Application for Blaze {
}

fn title(&self) -> String {
String::from("Blaze")
String::from("Kuiper")
}

fn update(&mut self, message: Message) -> Command<Message> {
Expand Down
16 changes: 16 additions & 0 deletions lsp/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "kuiper_lsp"
version.workspace = true
edition.workspace = true
authors.workspace = true
license.workspace = true

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
async-lsp.workspace = true
iced.workspace = true
log.workspace = true
lsp-types.workspace = true
snafu.workspace = true
tokio.workspace = true
156 changes: 156 additions & 0 deletions lsp/src/client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
use async_lsp::{
concurrency::ConcurrencyLayer, panic::CatchUnwindLayer, router::Router, tracing::TracingLayer,
LanguageClient, ResponseError,
};
use log::{info, trace, Level};
use lsp_types::{
notification::{Progress, PublishDiagnostics, ShowMessage},
ClientCapabilities, HoverContents, HoverParams, InitializeParams, MarkupContent,
NumberOrString, Position, ProgressParamsValue, TextDocumentIdentifier,
TextDocumentPositionParams, Url, WindowClientCapabilities, WorkDoneProgress,
WorkDoneProgressParams,
};
use std::{ops::ControlFlow, path::Path, process::Stdio};
use tokio::sync::oneshot;

const TEST_ROOT: &str = ".";

struct ClientState {
indexed_tx: Option<oneshot::Sender<()>>,
}

struct Stop;

impl LanguageClient for ClientState {
type Error = ResponseError;
type NotifyResult = ControlFlow<async_lsp::Result<()>>;
}

pub async fn start_lsp() {
let root_dir = Path::new(TEST_ROOT)
.canonicalize()
.expect("test root should be valid");

let (indexed_tx, indexed_rx) = oneshot::channel();

let (mainloop, mut server) = async_lsp::MainLoop::new_client(|_server| {
let mut router = Router::new(ClientState {
indexed_tx: Some(indexed_tx),
});
router
.notification::<Progress>(|this, prog| {
trace!("{:#?} {:#?}", prog.token, prog.value);
if matches!(prog.token, NumberOrString::String(s) if s == "rustAnalyzer/Indexing")
&& matches!(
prog.value,
ProgressParamsValue::WorkDone(WorkDoneProgress::End(_))
)
{
// Sometimes rust-analyzer auto-index multiple times?
if let Some(tx) = this.indexed_tx.take() {
let _: Result<_, _> = tx.send(());
}
}
ControlFlow::Continue(())
})
.notification::<PublishDiagnostics>(|_, _| ControlFlow::Continue(()))
.notification::<ShowMessage>(|_, params| {
trace!("Message {:?}: {}", params.typ, params.message);
ControlFlow::Continue(())
})
.event(|_, _: Stop| ControlFlow::Break(Ok(())));

ServiceBuilder::new()
.layer(TracingLayer::default())
.layer(CatchUnwindLayer::default())
.layer(ConcurrencyLayer::default())
.service(router)
});

tracing_subscriber::fmt()
.with_max_level(Level::Info)
.with_ansi(false)
.with_writer(std::io::stdout)
.init();

let child = async_process::Command::new("rust-analyzer")
.current_dir(&root_dir)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::inherit())
.kill_on_drop(true)
.spawn()
.expect("Failed run rust-analyzer");
let stdout = child.stdout.unwrap();
let stdin = child.stdin.unwrap();

let mainloop_fut = tokio::spawn(async move {
mainloop.run_buffered(stdout, stdin).await.unwrap();
});

// Initialize.
let root_uri = Url::from_file_path(&root_dir).unwrap();
let init_ret = server
.initialize(InitializeParams {
root_uri: Some(root_uri),
capabilities: ClientCapabilities {
window: Some(WindowClientCapabilities {
work_done_progress: Some(true),
..WindowClientCapabilities::default()
}),
..ClientCapabilities::default()
},
..InitializeParams::default()
})
.await
.unwrap();
info!("Initialized: {init_ret:?}");
server.initialized(InitializedParams {}).unwrap();

// Synchronize documents.
let file_uri = Url::from_file_path(root_dir.join("src/lib.rs")).unwrap();
let text = "fn func() { let var = 1; }";
server
.did_open(DidOpenTextDocumentParams {
text_document: TextDocumentItem {
uri: file_uri.clone(),
language_id: "rust".into(),
version: 0,
text: text.into(),
},
})
.unwrap();

// Wait until indexed.
indexed_rx.await.unwrap();

// Query.
let var_pos = text.find("var").unwrap();
let hover = server
.hover(HoverParams {
text_document_position_params: TextDocumentPositionParams {
text_document: TextDocumentIdentifier { uri: file_uri },
position: Position::new(0, var_pos as _),
},
work_done_progress_params: WorkDoneProgressParams::default(),
})
.await
.unwrap()
.unwrap();
info!("Hover result: {hover:?}");
assert!(
matches!(
hover.contents,
HoverContents::Markup(MarkupContent { value, .. })
if value.contains("let var: i32")
),
"should show the type of `var`",
);

// Shutdown.
server.shutdown(()).await.unwrap();
server.exit(()).unwrap();

server.emit(Stop).unwrap();
mainloop_fut.await.unwrap();
}
2 changes: 2 additions & 0 deletions lsp/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
mod client;
mod subscription;
7 changes: 7 additions & 0 deletions lsp/src/subscription.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
use iced::{subscription, Subscription};

pub enum Event {}

pub fn connect() -> Subscription<Event> {
todo!()
}
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use blaze_gui::start_gui;
use kuiper_gui::start_gui;

fn main() {
pretty_env_logger::init();
Expand Down

0 comments on commit 1b162f5

Please sign in to comment.