From 5733da9a1543c07f57e0cd92c872f4117a2a59ed Mon Sep 17 00:00:00 2001 From: Josias Date: Tue, 3 Feb 2026 14:40:23 +0100 Subject: [PATCH 01/30] edit contributions.md and edit urls --- CONTRIBUTING.md | 15 ++++++++------- Cargo.lock | 4 ---- Cargo.toml | 9 ++++----- README.md | 2 +- crates/umide/Cargo.toml | 2 +- umide-proxy/Cargo.toml | 3 +-- umide-rpc/Cargo.toml | 2 +- 7 files changed, 16 insertions(+), 21 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6fd0e72a..38bcf864 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,17 +1,18 @@ # How to contribute -Thank you for your interest in contributing to Lapce! No contribution is too small and we consider _all_ contributions to the project. There are many ways to contribute (a few are listed here) but if you think of something else, join us on [Discord](https://discord.gg/n8tGJ6Rn6D) or let us know via an [issue](https://github.com/lapce/lapce/issues). + +Thank you for your interest in contributing to Lapce! No contribution is too small and we consider _all_ contributions to the project. There are many ways to contribute (a few are listed here) but if you think of something else, join us on [Discord](https://discord.gg/n8tGJ6Rn6D) or let us know via an [issue](https://github.com/bridgerust/umide/issues). ## Questions -We're always around hanging on our [Discord](https://discord.gg/n8tGJ6Rn6D) server but if you're only participating on GitHub, you can open a [Discussion](https://github.com/lapce/lapce/discussions) +We're always around hanging on our [Discord](https://discord.gg/n8tGJ6Rn6D) server but if you're only participating on GitHub, you can open a [Discussion](https://github.com/bridgerust/umide/discussions) ## Feature Requests -A feature request is _editor behaviour that you want to have included in Lapce_. We track feature requests on GitHub via [issues](https://github.com/lapce/lapce/issues). There are generally few kinds of features: +A feature request is _editor behaviour that you want to have included in Lapce_. We track feature requests on GitHub via [issues](https://github.com/bridgerust/umide/issues). There are generally few kinds of features: ### Core features -A feature more suited to the core development of Lapce. If this is the case please make a suggestion in an [issue](https://github.com/lapce/lapce/issues). +A feature more suited to the core development of Lapce. If this is the case please make a suggestion in an [issue](https://github.com/bridgerust/umide/issues). ### Programming language support (autocompletion/intellisense/formatting) @@ -20,7 +21,7 @@ We do not track plugins development here, each plugin should have own issue trac ### Syntax highlighting -There is main issue for tracking syntax highlighting grammars support at https://github.com/lapce/lapce/issues/272. +There is main issue for tracking syntax highlighting grammars support at https://github.com/bridgerust/umide/issues/272. --- @@ -28,7 +29,7 @@ To reduce the number of duplicate requests, please search through the issues to ## Bug Reports -Bugs should also be reported on GitHub via [issues](https://github.com/lapce/lapce/issues). This allows us to track them and see how prevalent they are. +Bugs should also be reported on GitHub via [issues](https://github.com/bridgerust/umide/issues). This allows us to track them and see how prevalent they are. If you encounter a bug when using Lapce, check the issues to see if anyone else has encountered it. If it already exists, you can use emoji reactions so we can see community interest in specific issues and how important they are. @@ -36,7 +37,7 @@ Please follow the rule of [NoPlusOne](https://github.com/golang/go/wiki/NoPlusOn ## Pull Requests -If you want to write some code, develop the documentation, or otherwise work on a certain feature or bug, let us know by replying to or creating an [issue](https://github.com/lapce/lapce/issues). +If you want to write some code, develop the documentation, or otherwise work on a certain feature or bug, let us know by replying to or creating an [issue](https://github.com/bridgerust/umide/issues). Run `cargo fmt --all` and `cargo clippy` on your code before submitting pull requests and fix any issues; this makes sure that the CI runs only fail on genuine build errors and not formatting/Clippy lints. diff --git a/Cargo.lock b/Cargo.lock index 3451bac4..1adb9ae3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4431,7 +4431,6 @@ checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" [[package]] name = "locale_config" version = "0.3.1-alpha.0" -source = "git+https://github.com/lapce/locale_config.git?branch=lapce#54c9fe6a247c3618c224ec57e6c3a747bc3a96e4" dependencies = [ "lazy_static", "objc2 0.5.2", @@ -4473,7 +4472,6 @@ checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" [[package]] name = "lsp-types" version = "0.95.1" -source = "git+https://github.com/lapce/lsp-types?rev=feaa1e2ec80975c9dadd400a238ceacf071058e6#feaa1e2ec80975c9dadd400a238ceacf071058e6" dependencies = [ "bitflags 1.3.2", "serde", @@ -5942,7 +5940,6 @@ dependencies = [ [[package]] name = "psp-types" version = "0.1.0" -source = "git+https://github.com/lapce/psp-types?rev=f7fea28f59e7b2d6faa1034a21679ad49b3524ad#f7fea28f59e7b2d6faa1034a21679ad49b3524ad" dependencies = [ "lsp-types", "serde", @@ -7314,7 +7311,6 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "structdesc" version = "0.1.0" -source = "git+https://github.com/lapce/structdesc?rev=bb56969f22fdb2c2d6c03f158fd4a2bdc983b659#bb56969f22fdb2c2d6c03f158fd4a2bdc983b659" dependencies = [ "darling", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index f401c073..cf8b7dd8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,8 +28,8 @@ version = "0.4.6" edition = "2024" rust-version = "1.87.0" license = "Apache-2.0" -homepage = "https://lapce.dev" -authors = ["Dongdong Zhou "] +homepage = "https://github.com/bridgerust/umide" +authors = ["KOLOGO JOSIAS "] [workspace.dependencies] anyhow = { version = "1.0" } @@ -69,7 +69,7 @@ url = { version = "2.5.0" } zstd = { version = "0.11.2" } # follow same version wasmtime-cache in lockfile lsp-types = { version = "0.95.1", features = ["proposed"] } # not following semver, so should be locked to patch version updates only -psp-types = { git = "https://github.com/lapce/psp-types", rev = "f7fea28f59e7b2d6faa1034a21679ad49b3524ad" } +psp-types = { path = "vendor/psp-types" } lapce-xi-rope = { version = "0.4.0", features = ["serde"] } @@ -83,10 +83,9 @@ umide_native = { path = "./crates/umide_native" } floem = { path = "../floem", features = ["editor", "serde", "default-image-formats"] } # floem-editor-core = { git = "https://github.com/lapce/floem", rev = "e0dd862564e3afbad5cba8ebe60df166a7a41e56", features = ["serde"] } floem-editor-core = { path = "../floem/editor-core/", features = ["serde"] } - [patch.crates-io] # Temporarily patch lsp-types with a version that adds message-type debug -lsp-types = { git = "https://github.com/lapce/lsp-types", rev = "feaa1e2ec80975c9dadd400a238ceacf071058e6" } +lsp-types = { path = "vendor/lsp-types" } [workspace.dependencies.tracing] diff --git a/README.md b/README.md index 6acf7fca..7d6ae791 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ UMIDE is a unified IDE for cross-platform mobile development (React Native + Flu ## License -Copyright 2024 UMIDE contributors +Copyright 2026 UMIDE contributors Portions (original editor) Copyright 2023 Lapce contributors Released under the Apache License Version 2. diff --git a/crates/umide/Cargo.toml b/crates/umide/Cargo.toml index 751da60f..a7489070 100644 --- a/crates/umide/Cargo.toml +++ b/crates/umide/Cargo.toml @@ -58,7 +58,7 @@ unicode-width = { version = "0.2.2" } nucleo = { version = "0.5.0" } bytemuck = { version = "1.22.0" } config = { version = "0.15.19", default-features = false, features = ["toml"] } -structdesc = { git = "https://github.com/lapce/structdesc", rev = "bb56969f22fdb2c2d6c03f158fd4a2bdc983b659" } +structdesc = { path = "../../vendor/structdesc" } base64 = { version = "0.22.1" } sha2 = { version = "0.10.8" } zip = { version = "7.2.0", default-features = false, features = ["deflate"] } diff --git a/umide-proxy/Cargo.toml b/umide-proxy/Cargo.toml index 3160fe71..91bdfc36 100644 --- a/umide-proxy/Cargo.toml +++ b/umide-proxy/Cargo.toml @@ -64,5 +64,4 @@ wasi-common = "14.0.0" path = "../vendor/wasi-experimental-http/crates/wasi-experimental-http-wasmtime" [target.'cfg(target_os = "macos")'.dependencies.locale_config] -git = "https://github.com/lapce/locale_config.git" -branch = "lapce" +path = "../vendor/locale_config" diff --git a/umide-rpc/Cargo.toml b/umide-rpc/Cargo.toml index d907cc0d..f3f53c9f 100644 --- a/umide-rpc/Cargo.toml +++ b/umide-rpc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "umide-rpc" -description = "Data formats between lapce components" +description = "Data formats between umide components" license = { workspace = true } version = { workspace = true } authors = { workspace = true } From a629b172f1b31c022d32204bb95619ad9888aadc Mon Sep 17 00:00:00 2001 From: Josias Date: Tue, 3 Feb 2026 15:43:42 +0100 Subject: [PATCH 02/30] refactor: rename Lapce to Umide across the codebase. --- .agent/rules/umide-roadmap.md | 12 +- .github/ISSUE_TEMPLATE/bug_report.md | 12 +- .github/ISSUE_TEMPLATE/config.yml | 8 +- .github/workflows/release.yml | 34 +- CHANGELOG.md | 16 +- CONTRIBUTING.md | 12 +- Cargo.toml | 2 +- LICENSE | 2 +- Makefile | 14 +- README.md | 4 +- crates/umide/src/about.rs | 28 +- crates/umide/src/alert.rs | 28 +- crates/umide/src/app.rs | 368 +++++++++--------- crates/umide/src/app/grammars.rs | 2 +- crates/umide/src/app/logging.rs | 4 +- crates/umide/src/code_action.rs | 2 +- crates/umide/src/command.rs | 40 +- crates/umide/src/completion.rs | 8 +- crates/umide/src/config.rs | 158 ++++---- crates/umide/src/config/color.rs | 4 +- crates/umide/src/config/color_theme.rs | 8 +- crates/umide/src/config/core.rs | 4 +- crates/umide/src/config/icon.rs | 4 +- crates/umide/src/db.rs | 36 +- crates/umide/src/debug.rs | 6 +- crates/umide/src/doc.rs | 44 +-- crates/umide/src/editor.rs | 56 +-- crates/umide/src/editor/diff.rs | 16 +- crates/umide/src/editor/gutter.rs | 14 +- crates/umide/src/editor/view.rs | 160 ++++---- crates/umide/src/editor_tab.rs | 28 +- crates/umide/src/file_explorer/data.rs | 10 +- crates/umide/src/file_explorer/view.rs | 48 +-- crates/umide/src/global_search.rs | 2 +- crates/umide/src/inline_completion.rs | 4 +- crates/umide/src/keymap.rs | 72 ++-- crates/umide/src/keypress.rs | 22 +- crates/umide/src/keypress/condition.rs | 2 +- crates/umide/src/markdown.rs | 28 +- crates/umide/src/palette.rs | 52 +-- crates/umide/src/palette/item.rs | 10 +- crates/umide/src/palette/kind.rs | 40 +- crates/umide/src/panel/call_hierarchy_view.rs | 16 +- crates/umide/src/panel/data.rs | 4 +- crates/umide/src/panel/debug_view.rs | 70 ++-- crates/umide/src/panel/document_symbol.rs | 16 +- crates/umide/src/panel/emulator_view.rs | 14 +- crates/umide/src/panel/global_search_view.rs | 30 +- crates/umide/src/panel/implementation_view.rs | 22 +- crates/umide/src/panel/kind.rs | 28 +- crates/umide/src/panel/plugin_view.rs | 22 +- crates/umide/src/panel/problem_view.rs | 42 +- crates/umide/src/panel/source_control_view.rs | 40 +- crates/umide/src/panel/terminal_view.rs | 34 +- crates/umide/src/panel/view.rs | 40 +- crates/umide/src/plugin.rs | 38 +- crates/umide/src/proxy.rs | 10 +- crates/umide/src/proxy/remote.rs | 4 +- crates/umide/src/rename.rs | 4 +- crates/umide/src/settings.rs | 72 ++-- crates/umide/src/source_control.rs | 2 +- crates/umide/src/status.rs | 76 ++-- crates/umide/src/terminal/data.rs | 16 +- crates/umide/src/terminal/panel.rs | 6 +- crates/umide/src/terminal/tab.rs | 6 +- crates/umide/src/terminal/view.rs | 30 +- crates/umide/src/text_area.rs | 12 +- crates/umide/src/text_input.rs | 10 +- crates/umide/src/title.rs | 114 +++--- crates/umide/src/update.rs | 2 +- crates/umide/src/window.rs | 28 +- crates/umide/src/window_tab.rs | 78 ++-- crates/umide/src/workspace.rs | 38 +- crates/umide_native/src/macos.rs | 22 +- defaults/dark-theme.toml | 2 +- defaults/icon-theme.toml | 2 +- defaults/light-theme.toml | 2 +- defaults/settings.toml | 4 +- docs/architecture.md | 2 +- docs/building-from-source.md | 13 +- docs/installing-with-package-manager.md | 9 +- docs/new-release.md | 2 +- extra/linux/dev.lapce.lapce.metainfo.xml | 8 +- extra/linux/docker/fedora/Dockerfile | 2 +- extra/proxy.ps1 | 4 +- extra/windows/wix/lapce.wxs | 30 +- lapce.spec | 2 +- umide-core/build.rs | 2 +- umide-core/src/directory.rs | 4 +- umide-core/src/language.rs | 280 ++++++------- umide-core/src/syntax/highlight.rs | 6 +- umide-core/src/syntax/mod.rs | 18 +- umide-proxy/src/lib.rs | 8 +- umide-proxy/src/plugin/dap.rs | 2 +- umide-proxy/src/plugin/wasi.rs | 2 +- 95 files changed, 1407 insertions(+), 1367 deletions(-) diff --git a/.agent/rules/umide-roadmap.md b/.agent/rules/umide-roadmap.md index 9809c3ba..6378505b 100644 --- a/.agent/rules/umide-roadmap.md +++ b/.agent/rules/umide-roadmap.md @@ -35,13 +35,13 @@ Future-proof for complex graphics (Metal/Vulkan/OpenGL) No IDE rewrite -Lapce remains the editor core +Umide remains the editor core 2. High-Level Architecture (Layered & Decoupled) ┌────────────────────────────────────────────┐ │ UMIDE (Shell) │ │ │ - │ ┌───────────── Lapce / Floem ───────────┐ │ + │ ┌───────────── Umide / Floem ───────────┐ │ │ │ Editor, LSP, Git, Commands, Panels │ │ │ └────────────────────────────────────────┘ │ │ │ @@ -62,12 +62,12 @@ Lapce remains the editor core │ │ └────────────────────────────────────────────┘ -3. Why Lapce + C++ Is the Correct Choice +3. Why Umide + C++ Is the Correct Choice Why NOT rewrite the IDE Editor/LSP/keybindings are hard problems already solved -Lapce is fast, native, modern +Umide is fast, native, modern Floem is evolving rapidly @@ -128,7 +128,7 @@ It is a native GPU surface embedded into the window. Create a native GPU surface -Attach it to the same window Lapce owns +Attach it to the same window Umide owns Share the graphics context @@ -165,7 +165,7 @@ Future rendering APIs └─ NativeSurfaceHandle ─────▶ C++ Emulator Core Responsibilities -Rust (Lapce side) +Rust (Umide side) Layout & docking diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 2dad4588..869d172f 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,21 +1,21 @@ --- name: Bug report about: Create a report to help us improve -title: '' -labels: 'C-bug' -assignees: '' - +title: "" +labels: "C-bug" +assignees: "" --- -## Lapce Version +## Umide Version -The Lapce version you are using, which can be found in "About Lapce" at the top right settings icon. +The Umide version you are using, which can be found in "About Umide" at the top right settings icon. ## System information the operating system used, including its version, e.g. Windows 10, Ubuntu 18.04 ## Describe the bug + A clear and concise description of what the bug is. ## Additional information diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index aac61aa4..ab7739a7 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,11 +1,11 @@ blank_issues_enabled: false contact_links: - - name: Lapce community on Discord + - name: Umide community on Discord url: https://discord.gg/n8tGJ6Rn6D about: Please ask and answer questions here. - - name: Lapce community on Matrix + - name: Umide community on Matrix url: https://matrix.to/#/#lapce-editor:matrix.org about: Please ask and answer questions here. - - name: Lapce documentation + - name: Umide documentation url: https://docs.lapce.dev/ - about: Documentation for Lapce + about: Documentation for Umide diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index eba040d9..43661717 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -76,14 +76,14 @@ jobs: -out "./lapce.wixobj" "extra/windows/wix/lapce.wxs" light.exe -ext WixUIExtension -ext WixUtilExtension \ - -out "./Lapce-windows.msi" -sice:ICE61 -sice:ICE91 \ + -out "./Umide-windows.msi" -sice:ICE61 -sice:ICE91 \ "./lapce.wixobj" - name: Create portable shell: pwsh run: | cargo build --profile release-lto --features lapce-app/portable - Compress-Archive ./target/release-lto/lapce.exe ./Lapce-windows-portable.zip + Compress-Archive ./target/release-lto/lapce.exe ./Umide-windows-portable.zip - name: Create lapce-proxy archive shell: pwsh @@ -100,8 +100,8 @@ jobs: name: lapce-windows path: | ./lapce-proxy-windows-*.gz - ./Lapce-windows-portable.zip - ./Lapce-windows.msi + ./Umide-windows-portable.zip + ./Umide-windows.msi retention-days: 1 linux: @@ -118,15 +118,15 @@ jobs: - name: Gzip run: | - mkdir Lapce - cp ./target/linux_amd64/lapce Lapce/ - tar -zcvf ./lapce-linux-amd64.tar.gz Lapce + mkdir Umide + cp ./target/linux_amd64/lapce Umide/ + tar -zcvf ./lapce-linux-amd64.tar.gz Umide - rm -rf Lapce + rm -rf Umide - mkdir Lapce - cp ./target/linux_arm64/lapce Lapce/ - tar -zcvf ./lapce-linux-arm64.tar.gz Lapce + mkdir Umide + cp ./target/linux_arm64/lapce Umide/ + tar -zcvf ./lapce-linux-arm64.tar.gz Umide - name: Fetch dependencies run: cargo fetch --locked @@ -276,7 +276,7 @@ jobs: - name: Rename run: | - cp ./target/release-lto/macos/Lapce.dmg ./target/release-lto/macos/Lapce-macos.dmg + cp ./target/release-lto/macos/Umide.dmg ./target/release-lto/macos/Umide-macos.dmg - name: Gzip lapce-proxy run: | @@ -286,7 +286,7 @@ jobs: - name: Notarize Release Build uses: lando/notarize-action@v2 with: - product-path: "./target/release-lto/macos/Lapce-macos.dmg" + product-path: "./target/release-lto/macos/Umide-macos.dmg" appstore-connect-username: ${{ secrets.NOTARIZE_USERNAME }} appstore-connect-password: ${{ secrets.NOTARIZE_PASSWORD }} appstore-connect-team-id: CYSGAZFR8D @@ -296,14 +296,14 @@ jobs: - name: "Staple Release Build" uses: lapce/xcode-staple@062485d6eeafe841c18a412f012e80f49e23c517 with: - product-path: "./target/release-lto/macos/Lapce-macos.dmg" + product-path: "./target/release-lto/macos/Umide-macos.dmg" - uses: actions/upload-artifact@v4 with: name: lapce-macos path: | ./target/release-lto/macos/lapce-proxy-darwin-*.gz - ./target/release-lto/macos/Lapce-macos.dmg + ./target/release-lto/macos/Umide-macos.dmg retention-days: 3 publish: @@ -341,7 +341,7 @@ jobs: - if: env.TAG_NAME == 'nightly' run: | { - echo 'SUBJECT=Lapce development build' + echo 'SUBJECT=Umide development build' echo 'PRERELEASE=--prerelease' } | tee -a $GITHUB_ENV @@ -354,7 +354,7 @@ jobs: - if: env.TAG_NAME != 'nightly' run: | { - echo 'SUBJECT=Lapce release build' + echo 'SUBJECT=Umide release build' echo 'PRERELEASE=' } | tee -a $GITHUB_ENV diff --git a/CHANGELOG.md b/CHANGELOG.md index c1f0f9ec..d8f89f9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -147,14 +147,14 @@ - [#2190](https://github.com/lapce/lapce/pull/2190): Rewrite with Floem UI - [#2425](https://github.com/lapce/lapce/pull/2425): Reimplement completion lens -- [#2498](https://github.com/lapce/lapce/pull/2498): Show Lapce as an option when doing "Open With..." on Linux +- [#2498](https://github.com/lapce/lapce/pull/2498): Show Umide as an option when doing "Open With..." on Linux - [#2549](https://github.com/lapce/lapce/pull/2549): Implement multi-line vim-motion yank and delete (`3dd`, `2yy`, etc.) - [#2553](https://github.com/lapce/lapce/pull/2553): Implement search and replace - [#1809](https://github.com/lapce/lapce/pull/1809): Implement debug adapter protocol ### Bug Fixes -- [#2650](https://github.com/lapce/lapce/pull/2650): Inform language servers that Lapce supports LSP diagnostics +- [#2650](https://github.com/lapce/lapce/pull/2650): Inform language servers that Umide supports LSP diagnostics ## 0.2.8 @@ -172,7 +172,7 @@ ### Bug Fixes - [#2209](https://github.com/lapce/lapce/pull/2209): Fix macOS crashes -- [#2228](https://github.com/lapce/lapce/pull/2228): Fix `.desktop` entry to properly associate with Lapce on Wayland +- [#2228](https://github.com/lapce/lapce/pull/2228): Fix `.desktop` entry to properly associate with Umide on Wayland ## 0.2.6 @@ -200,7 +200,7 @@ - [#2045](https://github.com/lapce/lapce/pull/2045): Add 'Rename Symbol' option on right-click - [#2071](https://github.com/lapce/lapce/pull/2071): Add command and keybinds to delete line - [#2073](https://github.com/lapce/lapce/pull/2073): Add Ctrl+{a,e,k} keybinds on macOS -- [#2128](https://github.com/lapce/lapce/pull/2128): Add Lapce app icon to logo collection +- [#2128](https://github.com/lapce/lapce/pull/2128): Add Umide app icon to logo collection - [#2127](https://github.com/lapce/lapce/pull/2127): Extended double-click options with file-only and file + folders mode - [#1944](https://github.com/lapce/lapce/pull/1944): Add filter input in git branch selection - ![image](https://user-images.githubusercontent.com/4404609/211232461-293e3b31-4e17-457e-825c-3018699a6fc2.png) @@ -304,7 +304,7 @@ - [#1472](https://github.com/lapce/lapce/pull/1472): Added SQL language support - [#1531](https://github.com/lapce/lapce/pull/1531): Improved Ctrl+Left command on spaces at the beginning of a line - [#1491](https://github.com/lapce/lapce/pull/1491): Added Vim shift+c to delete remainder of line -- [#1508](https://github.com/lapce/lapce/pull/1508): Show in progress when Lapce is self updating +- [#1508](https://github.com/lapce/lapce/pull/1508): Show in progress when Umide is self updating - [#1475](https://github.com/lapce/lapce/pull/1475): Add editor setting: "Cursor Surrounding Lines" which sets minimum number of lines above and below cursor - [#1525](https://github.com/lapce/lapce/pull/1525): Add editor indent guide - [#1521](https://github.com/lapce/lapce/pull/1521): Show unique paths to disambiguate same file names @@ -360,7 +360,7 @@ - [#1440](https://github.com/lapce/lapce/pull/1440): IME support - [#1449](https://github.com/lapce/lapce/pull/1449): Plugin settings in the editor support. Though this still needs some work from plugins to expose them all nicely! - [#1441](https://github.com/lapce/lapce/pull/1441): Button for Case-Sensitive search -- [#1471](https://github.com/lapce/lapce/pull/1471): Add command to (un)install Lapce from/to PATH +- [#1471](https://github.com/lapce/lapce/pull/1471): Add command to (un)install Umide from/to PATH - [#1419](https://github.com/lapce/lapce/pull/1419): Add atomic soft tabs: now you can move your cursor over four spaces as if it was a single block ### Syntax / Extensions @@ -388,7 +388,7 @@ - [#1030](https://github.com/lapce/lapce/pull/1030): Don't try to open an font file with an empty name if there is no font family set - [9f0120d](https://github.com/lapce/lapce/commit/9f0120df85e3aaaef7fbb43385bb15d88443260a): Fix excessive CPU usage in part of the code -- [bf5a98a](https://github.com/lapce/lapce/commit/bf5a98a6d432f9d2abdc1737da2d075e204771fb): Fix issue where sometimes Lapce can't open +- [bf5a98a](https://github.com/lapce/lapce/commit/bf5a98a6d432f9d2abdc1737da2d075e204771fb): Fix issue where sometimes Umide can't open - [#1084](https://github.com/lapce/lapce/pull/1084): Use host shell in terminal when running inside Flatpak - [#1120](https://github.com/lapce/lapce/pull/1120): Make Alt+Backspace work in the terminal properly - [#1127](https://github.com/lapce/lapce/pull/1127): Improve Julia highlighting @@ -410,7 +410,7 @@ ### Other -- [#1191](https://github.com/lapce/lapce/pull/1191): Tone down default inlay hint background color in Lapce dark theme +- [#1191](https://github.com/lapce/lapce/pull/1191): Tone down default inlay hint background color in Umide dark theme - [#1227](https://github.com/lapce/lapce/pull/1227): Don't restore cursor mode on undo - [#1413](https://github.com/lapce/lapce/pull/1413): Disable format-on-save by default. Remember to re-enable this if you want it! - [#1404](https://github.com/lapce/lapce/pull/1404): Log panics with full backtrace as error diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 38bcf864..5d9da3aa 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,6 @@ # How to contribute -Thank you for your interest in contributing to Lapce! No contribution is too small and we consider _all_ contributions to the project. There are many ways to contribute (a few are listed here) but if you think of something else, join us on [Discord](https://discord.gg/n8tGJ6Rn6D) or let us know via an [issue](https://github.com/bridgerust/umide/issues). +Thank you for your interest in contributing to Umide! No contribution is too small and we consider _all_ contributions to the project. There are many ways to contribute (a few are listed here) but if you think of something else, join us on [Discord](https://discord.gg/n8tGJ6Rn6D) or let us know via an [issue](https://github.com/bridgerust/umide/issues). ## Questions @@ -8,16 +8,16 @@ We're always around hanging on our [Discord](https://discord.gg/n8tGJ6Rn6D) serv ## Feature Requests -A feature request is _editor behaviour that you want to have included in Lapce_. We track feature requests on GitHub via [issues](https://github.com/bridgerust/umide/issues). There are generally few kinds of features: +A feature request is _editor behaviour that you want to have included in Umide_. We track feature requests on GitHub via [issues](https://github.com/bridgerust/umide/issues). There are generally few kinds of features: ### Core features -A feature more suited to the core development of Lapce. If this is the case please make a suggestion in an [issue](https://github.com/bridgerust/umide/issues). +A feature more suited to the core development of Umide. If this is the case please make a suggestion in an [issue](https://github.com/bridgerust/umide/issues). ### Programming language support (autocompletion/intellisense/formatting) A feature that relates to specific programming language or development tool that provides intellisense, or various editor commands. -We do not track plugins development here, each plugin should have own issue tracker with eventual issues linked/referenced to main Lapce issue tracker. +We do not track plugins development here, each plugin should have own issue tracker with eventual issues linked/referenced to main Umide issue tracker. ### Syntax highlighting @@ -31,7 +31,7 @@ To reduce the number of duplicate requests, please search through the issues to Bugs should also be reported on GitHub via [issues](https://github.com/bridgerust/umide/issues). This allows us to track them and see how prevalent they are. -If you encounter a bug when using Lapce, check the issues to see if anyone else has encountered it. If it already exists, you can use emoji reactions so we can see community interest in specific issues and how important they are. +If you encounter a bug when using Umide, check the issues to see if anyone else has encountered it. If it already exists, you can use emoji reactions so we can see community interest in specific issues and how important they are. Please follow the rule of [NoPlusOne](https://github.com/golang/go/wiki/NoPlusOne) @@ -45,4 +45,4 @@ We are currently in the process of improving the documentation for new developer ## Contact -As always, if you have any questions or are just not sure where to start, post a message into the [Discord](https://discord.gg/n8tGJ6Rn6D) server. We suggest you start here as it is the most popular way for Lapce's contributors and users to communicate. +As always, if you have any questions or are just not sure where to start, post a message into the [Discord](https://discord.gg/n8tGJ6Rn6D) server. We suggest you start here as it is the most popular way for Umide's contributors and users to communicate. diff --git a/Cargo.toml b/Cargo.toml index cf8b7dd8..f6885972 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -122,7 +122,7 @@ lto = true codegen-units = 1 # A profile which compiles all (non-workspace) dependencies in release mode -# but Lapce code in dev mode. This gives a good debugging experience for your +# but Umide code in dev mode. This gives a good debugging experience for your # code and fast performance of other people's code. After the initial # build subsequent ones are as fast as dev mode builds. # See https://doc.rust-lang.org/cargo/reference/profiles.html diff --git a/LICENSE b/LICENSE index 0c738f68..4953b92a 100644 --- a/LICENSE +++ b/LICENSE @@ -187,7 +187,7 @@ APPENDIX: How to apply the Apache License to your work. identification within third-party archives. Copyright 2026 UMIDE contributors -Portions (original editor) Copyright 2023 Lapce contributors +Portions (original editor) Copyright 2023 Umide contributors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Makefile b/Makefile index 5047b4f1..d4e1bc44 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -# This Makefile is intended *only* for building macOS binaries of Lapce. +# This Makefile is intended *only* for building macOS binaries of Umide. # It uses macOS-specific tools like `lipo`, `codesign`, and `hdiutil`, # and requires that a valid Apple Developer signing identity is installed # and available in the system Keychain under the fingerprint set in @@ -14,7 +14,7 @@ ASSETS_DIR = extra RELEASE_DIR = target/release-lto APP_NAME = UMIDE.app -APP_TEMPLATE = $(ASSETS_DIR)/macos/Lapce.app +APP_TEMPLATE = $(ASSETS_DIR)/macos/Umide.app APP_DIR = $(RELEASE_DIR)/macos APP_BINARY = $(RELEASE_DIR)/$(TARGET) APP_BINARY_DIR = $(APP_DIR)/$(APP_NAME)/Contents/MacOS @@ -47,8 +47,8 @@ $(TARGET)-universal: @lipo target/{x86_64,aarch64}-apple-darwin/release-lto/$(TARGET) -create -output $(APP_BINARY) /usr/bin/codesign -vvv --deep --entitlements $(ASSETS_DIR)/entitlements.plist --strict --options=runtime --force -s $(CODESIGN_IDENTITY) $(APP_BINARY) -app: $(APP_NAME)-native ## Create a Lapce.app -app-universal: $(APP_NAME)-universal ## Create a universal Lapce.app +app: $(APP_NAME)-native ## Create a Umide.app +app-universal: $(APP_NAME)-universal ## Create a universal Umide.app $(APP_NAME)-%: $(TARGET)-% @mkdir -p $(APP_BINARY_DIR) @mkdir -p $(APP_EXTRAS_DIR) @@ -60,13 +60,13 @@ $(APP_NAME)-%: $(TARGET)-% xattr -c $(APP_DIR)/$(APP_NAME)/Contents/Resources/lapce.icns /usr/bin/codesign -vvv --deep --entitlements $(ASSETS_DIR)/entitlements.plist --strict --options=runtime --force -s $(CODESIGN_IDENTITY) $(APP_DIR)/$(APP_NAME) -dmg: $(DMG_NAME)-native ## Create a Lapce.dmg -dmg-universal: $(DMG_NAME)-universal ## Create a universal Lapce.dmg +dmg: $(DMG_NAME)-native ## Create a Umide.dmg +dmg-universal: $(DMG_NAME)-universal ## Create a universal Umide.dmg $(DMG_NAME)-%: $(APP_NAME)-% @echo "Packing disk image..." @ln -sf /Applications $(DMG_DIR)/Applications @hdiutil create $(DMG_DIR)/$(DMG_NAME) \ - -volname "Lapce" \ + -volname "Umide" \ -fs HFS+ \ -srcfolder $(APP_DIR) \ -ov -format UDZO diff --git a/README.md b/README.md index 7d6ae791..96bb7bed 100644 --- a/README.md +++ b/README.md @@ -11,11 +11,11 @@ UMIDE is a unified IDE for cross-platform mobile development (React Native + Flu - **Unified Mobile Environment**: Android Emulator and iOS Simulator embedded directly in the IDE. - **Cross-Platform Support**: First-class support for React Native and Flutter. - **High Performance**: Built on [Floem](https://github.com/lapce/floem) and Rust for lightning-fast speeds. -- **Based on Lapce**: Inherits all the great features of Lapce editor. +- **Based on Umide**: Inherits all the great features of Umide editor. ## License Copyright 2026 UMIDE contributors -Portions (original editor) Copyright 2023 Lapce contributors +Portions (original editor) Copyright 2023 Umide contributors Released under the Apache License Version 2. diff --git a/crates/umide/src/about.rs b/crates/umide/src/about.rs index f64f0c51..cb89d653 100644 --- a/crates/umide/src/about.rs +++ b/crates/umide/src/about.rs @@ -12,7 +12,7 @@ use umide_core::{command::FocusCommand, meta::VERSION, mode::Mode}; use crate::{ command::{CommandExecuted, CommandKind}, - config::color::LapceColor, + config::color::UmideColor, keypress::KeyPressFocus, web_link::web_link, window_tab::{Focus, WindowTabData}, @@ -66,7 +66,7 @@ impl KeyPressFocus for AboutData { fn run_command( &self, - command: &crate::command::LapceCommand, + command: &crate::command::UmideCommand, _count: Option, _mods: Modifiers, ) -> crate::command::CommandExecuted { @@ -103,54 +103,54 @@ pub fn about_popup(window_tab_data: Rc) -> impl View { Stack::new(( svg(move || (config.get()).logo_svg()).style(move |s| { s.size(logo_size, logo_size) - .color(config.get().color(LapceColor::EDITOR_FOREGROUND)) + .color(config.get().color(UmideColor::EDITOR_FOREGROUND)) }), Label::new("UMIDE".to_string()).style(move |s| { s.font_bold() .margin_top(10.0) - .color(config.get().color(LapceColor::EDITOR_FOREGROUND)) + .color(config.get().color(UmideColor::EDITOR_FOREGROUND)) }), Label::new(format!("Version: {}", VERSION)).style(move |s| { s.margin_top(10.0) - .color(config.get().color(LapceColor::EDITOR_DIM)) + .color(config.get().color(UmideColor::EDITOR_DIM)) }), web_link( || "Website".to_string(), || AboutUri::LAPCE.to_string(), - move || config.get().color(LapceColor::EDITOR_LINK), + move || config.get().color(UmideColor::EDITOR_LINK), internal_command, ) .style(|s| s.margin_top(20.0)), web_link( || "GitHub".to_string(), || AboutUri::GITHUB.to_string(), - move || config.get().color(LapceColor::EDITOR_LINK), + move || config.get().color(UmideColor::EDITOR_LINK), internal_command, ) .style(|s| s.margin_top(10.0)), web_link( || "Discord".to_string(), || AboutUri::DISCORD.to_string(), - move || config.get().color(LapceColor::EDITOR_LINK), + move || config.get().color(UmideColor::EDITOR_LINK), internal_command, ) .style(|s| s.margin_top(10.0)), web_link( || "Matrix".to_string(), || AboutUri::MATRIX.to_string(), - move || config.get().color(LapceColor::EDITOR_LINK), + move || config.get().color(UmideColor::EDITOR_LINK), internal_command, ) .style(|s| s.margin_top(10.0)), Label::new("Attributions".to_string()).style(move |s| { s.font_bold() - .color(config.get().color(LapceColor::EDITOR_DIM)) + .color(config.get().color(UmideColor::EDITOR_DIM)) .margin_top(40.0) }), web_link( || "Codicons (CC-BY-4.0)".to_string(), || AboutUri::CODICONS.to_string(), - move || config.get().color(LapceColor::EDITOR_LINK), + move || config.get().color(UmideColor::EDITOR_LINK), internal_command, ) .style(|s| s.margin_top(10.0)), @@ -176,8 +176,8 @@ fn exclusive_popup( .padding_horiz(100.0) .border(1.0) .border_radius(6.0) - .border_color(config.color(LapceColor::LAPCE_BORDER)) - .background(config.color(LapceColor::PANEL_BACKGROUND)) + .border_color(config.color(UmideColor::LAPCE_BORDER)) + .background(config.color(UmideColor::PANEL_BACKGROUND)) }) .on_event_stop(EventListener::PointerDown, move |_| {}), ) @@ -206,7 +206,7 @@ fn exclusive_popup( .background( config .get() - .color(LapceColor::LAPCE_DROPDOWN_SHADOW) + .color(UmideColor::LAPCE_DROPDOWN_SHADOW) .multiply_alpha(0.5), ) }) diff --git a/crates/umide/src/alert.rs b/crates/umide/src/alert.rs index 48d7fdcf..1326501e 100644 --- a/crates/umide/src/alert.rs +++ b/crates/umide/src/alert.rs @@ -13,7 +13,7 @@ use floem::{ }; use crate::{ - config::{LapceConfig, color::LapceColor, icon::LapceIcons}, + config::{UmideConfig, color::UmideColor, icon::UmideIcons}, window_tab::CommonData, }; @@ -37,7 +37,7 @@ pub struct AlertBoxData { pub title: RwSignal, pub msg: RwSignal, pub buttons: RwSignal>, - pub config: ReadSignal>, + pub config: ReadSignal>, } impl AlertBoxData { @@ -63,10 +63,10 @@ pub fn alert_box(alert_data: AlertBoxData) -> impl View { Container::new({ Container::new({ Stack::new(( - svg(move || config.get().ui_svg(LapceIcons::WARNING)).style( + svg(move || config.get().ui_svg(UmideIcons::WARNING)).style( move |s| { s.size(50.0, 50.0) - .color(config.get().color(LapceColor::LAPCE_WARN)) + .color(config.get().color(UmideColor::LAPCE_WARN)) }, ), Label::derived(move || title.get()).style(move |s| { @@ -97,18 +97,18 @@ pub fn alert_box(alert_data: AlertBoxData) -> impl View { .border(1.0) .border_radius(6.0) .border_color( - config.color(LapceColor::LAPCE_BORDER), + config.color(UmideColor::LAPCE_BORDER), ) .hover(|s| { s.cursor(CursorStyle::Pointer).background( config.color( - LapceColor::PANEL_HOVERED_BACKGROUND, + UmideColor::PANEL_HOVERED_BACKGROUND, ), ) }) .active(|s| { s.background(config.color( - LapceColor::PANEL_HOVERED_ACTIVE_BACKGROUND, + UmideColor::PANEL_HOVERED_ACTIVE_BACKGROUND, )) }) }) @@ -128,16 +128,16 @@ pub fn alert_box(alert_data: AlertBoxData) -> impl View { .line_height(1.5) .border(1.0) .border_radius(6.0) - .border_color(config.color(LapceColor::LAPCE_BORDER)) + .border_color(config.color(UmideColor::LAPCE_BORDER)) .hover(|s| { s.cursor(CursorStyle::Pointer).background( config - .color(LapceColor::PANEL_HOVERED_BACKGROUND), + .color(UmideColor::PANEL_HOVERED_BACKGROUND), ) }) .active(|s| { s.background(config.color( - LapceColor::PANEL_HOVERED_ACTIVE_BACKGROUND, + UmideColor::PANEL_HOVERED_ACTIVE_BACKGROUND, )) }) }), @@ -151,9 +151,9 @@ pub fn alert_box(alert_data: AlertBoxData) -> impl View { .width(250.0) .border(1.0) .border_radius(6.0) - .border_color(config.color(LapceColor::LAPCE_BORDER)) - .color(config.color(LapceColor::EDITOR_FOREGROUND)) - .background(config.color(LapceColor::PANEL_BACKGROUND)) + .border_color(config.color(UmideColor::LAPCE_BORDER)) + .color(config.color(UmideColor::EDITOR_FOREGROUND)) + .background(config.color(UmideColor::PANEL_BACKGROUND)) }) }) .on_event_stop(EventListener::PointerDown, move |_| {}) @@ -166,7 +166,7 @@ pub fn alert_box(alert_data: AlertBoxData) -> impl View { .background( config .get() - .color(LapceColor::LAPCE_DROPDOWN_SHADOW) + .color(UmideColor::LAPCE_DROPDOWN_SHADOW) .multiply_alpha(0.5), ) }) diff --git a/crates/umide/src/app.rs b/crates/umide/src/app.rs index a2a69283..a13299cb 100644 --- a/crates/umide/src/app.rs +++ b/crates/umide/src/app.rs @@ -54,14 +54,14 @@ use crate::{ about, alert, code_action::CodeActionStatus, command::{ - CommandKind, InternalCommand, LapceCommand, LapceWorkbenchCommand, + CommandKind, InternalCommand, UmideCommand, UmideWorkbenchCommand, WindowCommand, }, config::{ - LapceConfig, color::LapceColor, icon::LapceIcons, ui::TabSeparatorHeight, + UmideConfig, color::UmideColor, icon::UmideIcons, ui::TabSeparatorHeight, watcher::ConfigWatcher, }, - db::LapceDb, + db::UmideDb, debug::RunDebugMode, editor::{ diff::diff_show_more_section_view, @@ -92,7 +92,7 @@ use crate::{ update::ReleaseInfo, window::{TabsInfo, WindowData, WindowInfo}, window_tab::{Focus, WindowTabData}, - workspace::{LapceWorkspace, LapceWorkspaceType}, + workspace::{UmideWorkspace, UmideWorkspaceType}, }; mod grammars; @@ -103,7 +103,7 @@ mod logging; #[clap(version=meta::VERSION)] #[derive(Debug)] struct Cli { - /// Launch new window even if Lapce is already running + /// Launch new window even if Umide is already running #[clap(short, long, action)] new: bool, /// Don't return instantly when opened in a terminal @@ -151,7 +151,7 @@ pub struct AppData { pub latest_release: RwSignal>>, pub watcher: Arc, pub tracing_handle: Handle, - pub config: RwSignal>, + pub config: RwSignal>, /// Paths to extra plugins to load pub plugin_paths: Arc>, } @@ -159,7 +159,7 @@ pub struct AppData { impl AppData { pub fn reload_config(&self) { let config = - LapceConfig::load(&LapceWorkspace::default(), &[], &self.plugin_paths); + UmideConfig::load(&UmideWorkspace::default(), &[], &self.plugin_paths); self.config.set(Arc::new(config)); self.window_scale.set(self.config.get().ui.scale()); @@ -201,7 +201,7 @@ impl AppData { .position(window.position.get_untracked() + (50.0, 50.0)) }) .or_else(|| { - let db: Arc = Context::get().unwrap(); + let db: Arc = Context::get().unwrap(); db.get_window().ok().map(|info| { self.default_window_config() .size(info.size) @@ -218,11 +218,12 @@ impl AppData { } else { config }; - let workspace = LapceWorkspace { + let workspace = UmideWorkspace { path: folder, ..Default::default() }; let app_data = self.clone(); + let db: Arc = Context::get().unwrap(); floem::new_window( move |window_id| { app_data.app_view( @@ -237,6 +238,7 @@ impl AppData { }, }, vec![], + db, ) }, Some(config), @@ -246,7 +248,7 @@ impl AppData { pub fn run_app_command(&self, cmd: AppCommand) { match cmd { AppCommand::SaveApp => { - let db: Arc = Context::get().unwrap(); + let db: Arc = Context::get().unwrap(); if let Err(err) = db.save_app(self) { tracing::error!("{:?}", err); } @@ -255,7 +257,7 @@ impl AppData { if self.app_terminated.get_untracked() { return; } - let db: Arc = Context::get().unwrap(); + let db: Arc = Context::get().unwrap(); if self.windows.with_untracked(|w| w.len()) == 1 { if let Err(err) = db.insert_app(self.clone()) { tracing::error!("{:?}", err); @@ -286,7 +288,7 @@ impl AppData { fn create_windows( &self, - db: Arc, + db: Arc, paths: Vec, ) -> floem::Application { let mut app = floem::Application::new(); @@ -317,14 +319,14 @@ impl AppData { .is_empty() || !std::env::var("WSL_INTEROP").unwrap_or_default().is_empty() { - LapceWorkspaceType::RemoteWSL(crate::workspace::WslHost { + UmideWorkspaceType::RemoteWSL(crate::workspace::WslHost { host: String::new(), }) } else { - LapceWorkspaceType::Local + UmideWorkspaceType::Local }; #[cfg(not(windows))] - let workspace_type = LapceWorkspaceType::Local; + let workspace_type = UmideWorkspaceType::Local; let info = WindowInfo { size, @@ -332,7 +334,7 @@ impl AppData { maximised: false, tabs: TabsInfo { active_tab: 0, - workspaces: vec![LapceWorkspace { + workspaces: vec![UmideWorkspace { kind: workspace_type, path: Some(dir.path.to_owned()), last_open: 0, @@ -355,8 +357,9 @@ impl AppData { }; let app_data = self.clone(); let files = files.take().unwrap_or_default(); + let db = db.clone(); app = app.window( - move |window_id| app_data.app_view(window_id, info, files), + move |window_id| app_data.app_view(window_id, info, files, db), Some(config), ); inital_windows += 1; @@ -378,9 +381,10 @@ impl AppData { config }; let app_data = self.clone(); + let db = db.clone(); app = app.window( move |window_id| { - app_data.app_view(window_id, info, vec![]) + app_data.app_view(window_id, info, vec![], db) }, Some(config), ); @@ -388,7 +392,17 @@ impl AppData { } } Err(err) => { - tracing::error!("{:?}", err); + // Start a new instance if we can't connect to an existing one + // ConnectionRefused/NotFound means no existing instance is running + let is_expected = err.downcast_ref::() + .map(|e| e.kind() == std::io::ErrorKind::ConnectionRefused || e.kind() == std::io::ErrorKind::NotFound) + .unwrap_or(false); + + if !is_expected { + tracing::error!("Failed to check for existing instance: {:?}", err); + } else { + tracing::debug!("No existing instance found, starting new one."); + } } } } @@ -400,12 +414,12 @@ impl AppData { maximised: false, tabs: TabsInfo { active_tab: 0, - workspaces: vec![LapceWorkspace::default()], + workspaces: vec![UmideWorkspace::default()], }, }); info.tabs = TabsInfo { active_tab: 0, - workspaces: vec![LapceWorkspace::default()], + workspaces: vec![UmideWorkspace::default()], }; let config = self .default_window_config() @@ -419,12 +433,14 @@ impl AppData { config }; let app_data = self.clone(); + let db = db.clone(); app = app.window( move |window_id| { app_data.app_view( window_id, info, files.take().unwrap_or_default(), + db, ) }, Some(config), @@ -441,7 +457,9 @@ impl AppData { window_id: WindowId, info: WindowInfo, files: Vec, + db: Arc, ) -> impl View + use<> { + Context::provide(db); let app_view_id = RwSignal::new(floem::ViewId::new()); let window_data = WindowData::new( window_id, @@ -737,7 +755,7 @@ fn editor_tab_header( !info.with(|info| info.is_pristine) && config.ui.tab_close_button == TabCloseButton::Off, - |s| s.color(config.color(LapceColor::LAPCE_WARN)), + |s| s.color(config.color(UmideColor::LAPCE_WARN)), ) }) }) @@ -770,9 +788,9 @@ fn editor_tab_header( let tab_close_button = clickable_icon( move || { if hovered.get() || info.with(|info| info.is_pristine) { - LapceIcons::CLOSE + UmideIcons::CLOSE } else { - LapceIcons::UNSAVED + UmideIcons::UNSAVED } }, move || { @@ -834,7 +852,7 @@ fn editor_tab_header( .justify_center() .border_left(if i.get() == 0 { 1.0 } else { 0.0 }) .border_right(1.0) - .border_color(config.get().color(LapceColor::LAPCE_BORDER)) + .border_color(config.get().color(UmideColor::LAPCE_BORDER)) .padding_horiz(6.) .gap(6.) .grid() @@ -916,10 +934,10 @@ fn editor_tab_header( .border_radius(6.0) .background( config - .color(LapceColor::PANEL_BACKGROUND) + .color(UmideColor::PANEL_BACKGROUND) .multiply_alpha(0.7), ) - .border_color(config.color(LapceColor::LAPCE_BORDER)) + .border_color(config.color(UmideColor::LAPCE_BORDER)) }) .style(|s| s.align_items(Some(AlignItems::Center)).flex_grow(1.0).draggable(true)), Empty::new() @@ -931,9 +949,9 @@ fn editor_tab_header( 0.0 }) .border_color(config.get().color(if is_focused() { - LapceColor::LAPCE_TAB_ACTIVE_UNDERLINE + UmideColor::LAPCE_TAB_ACTIVE_UNDERLINE } else { - LapceColor::LAPCE_TAB_INACTIVE_UNDERLINE + UmideColor::LAPCE_TAB_INACTIVE_UNDERLINE })) }) .style(|s| { @@ -969,7 +987,7 @@ fn editor_tab_header( .border_color( config .get() - .color(LapceColor::LAPCE_TAB_ACTIVE_UNDERLINE) + .color(UmideColor::LAPCE_TAB_ACTIVE_UNDERLINE) .multiply_alpha(0.5), ) }) @@ -985,7 +1003,7 @@ fn editor_tab_header( .items_center() .justify_center() .cursor(CursorStyle::Pointer) - .hover(|s| s.background(config.color(LapceColor::HOVER_BACKGROUND))) + .hover(|s| s.background(config.color(UmideColor::HOVER_BACKGROUND))) }) .debug_name("Tab and Active Indicator") .on_event_stop(EventListener::DragOver, move |event| { @@ -1036,10 +1054,10 @@ fn editor_tab_header( s.absolute() .height_full() .width(size.get().width as f32) - .background(config.color(LapceColor::PANEL_BACKGROUND)) + .background(config.color(UmideColor::PANEL_BACKGROUND)) .box_shadow_blur(3.0) .box_shadow_color( - config.color(LapceColor::LAPCE_DROPDOWN_SHADOW), + config.color(UmideColor::LAPCE_DROPDOWN_SHADOW), ) })) .style(move |s| { @@ -1051,10 +1069,10 @@ fn editor_tab_header( }), Stack::new(( clickable_icon( - || LapceIcons::TAB_PREVIOUS, + || UmideIcons::TAB_PREVIOUS, move || { workbench_command - .send(LapceWorkbenchCommand::PreviousEditorTab); + .send(UmideWorkbenchCommand::PreviousEditorTab); }, || false, || false, @@ -1063,10 +1081,10 @@ fn editor_tab_header( ) .style(|s| s.margin_horiz(6.0).margin_vert(7.0)), clickable_icon( - || LapceIcons::TAB_NEXT, + || UmideIcons::TAB_NEXT, move || { workbench_command - .send(LapceWorkbenchCommand::NextEditorTab); + .send(UmideWorkbenchCommand::NextEditorTab); }, || false, || false, @@ -1123,10 +1141,10 @@ fn editor_tab_header( .height_full() .margin_left(30.0) .width(size.get().width as f32) - .background(config.color(LapceColor::PANEL_BACKGROUND)) + .background(config.color(UmideColor::PANEL_BACKGROUND)) .box_shadow_blur(3.0) .box_shadow_color( - config.color(LapceColor::LAPCE_DROPDOWN_SHADOW), + config.color(UmideColor::LAPCE_DROPDOWN_SHADOW), ) }) }) @@ -1143,7 +1161,7 @@ fn editor_tab_header( }), Stack::new(( clickable_icon( - || LapceIcons::SPLIT_HORIZONTAL, + || UmideIcons::SPLIT_HORIZONTAL, move || { let editor_tab_id = editor_tab.with_untracked(|t| t.editor_tab_id); @@ -1159,7 +1177,7 @@ fn editor_tab_header( ) .style(|s| s.margin_left(6.0)), clickable_icon( - || LapceIcons::CLOSE, + || UmideIcons::CLOSE, move || { let editor_tab_id = editor_tab.with_untracked(|t| t.editor_tab_id); @@ -1197,8 +1215,8 @@ fn editor_tab_header( s.items_center() .max_width_full() .border_bottom(1.0) - .border_color(config.color(LapceColor::LAPCE_BORDER)) - .background(config.color(LapceColor::PANEL_BACKGROUND)) + .border_color(config.color(UmideColor::LAPCE_BORDER)) + .background(config.color(UmideColor::PANEL_BACKGROUND)) .height(config.ui.header_height() as i32) }) .debug_name("Editor Tab Header") @@ -1345,7 +1363,7 @@ fn editor_tab_content( .flex_basis(0.0) .border_right(1.0) .border_color( - config.get().color(LapceColor::LAPCE_BORDER), + config.get().color(UmideColor::LAPCE_BORDER), ) }), Container::new( @@ -1494,7 +1512,7 @@ fn editor_tab( .background( config .get() - .color(LapceColor::EDITOR_DRAG_DROP_BACKGROUND), + .color(UmideColor::EDITOR_DRAG_DROP_BACKGROUND), ) }) .debug_name("Drag Over Handle"), @@ -1619,7 +1637,7 @@ fn split_resize_border( splits: ReadSignal>>, editor_tabs: ReadSignal>>, split: ReadSignal, - config: ReadSignal>, + config: ReadSignal>, ) -> impl View { let content_rect = move |content: &SplitContent, tracked: bool| { if tracked { @@ -1783,14 +1801,14 @@ fn split_resize_border( SplitDirection::Vertical => CursorStyle::ColResize, SplitDirection::Horizontal => CursorStyle::RowResize, }) - .background(config.get().color(LapceColor::EDITOR_CARET)) + .background(config.get().color(UmideColor::EDITOR_CARET)) }) .hover(|s| { s.cursor(match direction { SplitDirection::Vertical => CursorStyle::ColResize, SplitDirection::Horizontal => CursorStyle::RowResize, }) - .background(config.get().color(LapceColor::EDITOR_CARET)) + .background(config.get().color(UmideColor::EDITOR_CARET)) }) .pointer_events_auto() }) @@ -1808,7 +1826,7 @@ fn split_border( splits: ReadSignal>>, editor_tabs: ReadSignal>>, split: ReadSignal, - config: ReadSignal>, + config: ReadSignal>, ) -> impl View { let direction = move || split.with(|split| split.direction); dyn_stack( @@ -1825,7 +1843,7 @@ fn split_border( SplitDirection::Vertical => PxPctAuto::Pct(100.0), SplitDirection::Horizontal => PxPctAuto::Px(1.0), }) - .background(config.get().color(LapceColor::LAPCE_BORDER)) + .background(config.get().color(UmideColor::LAPCE_BORDER)) })) .style(move |s| { let rect = match &content { @@ -2030,8 +2048,8 @@ fn main_split(window_tab_data: Rc) -> impl View { let config = config.get(); let is_hidden = panel.panel_bottom_maximized(true) && panel.is_container_shown(&PanelContainerPosition::Bottom, true); - s.border_color(config.color(LapceColor::LAPCE_BORDER)) - .background(config.color(LapceColor::EDITOR_BACKGROUND)) + s.border_color(config.color(UmideColor::LAPCE_BORDER)) + .background(config.color(UmideColor::EDITOR_BACKGROUND)) .apply_if(is_hidden, |s| s.display(Display::None)) .width_full() .flex_grow(1.0) @@ -2045,7 +2063,7 @@ pub fn not_clickable_icon( active_fn: impl Fn() -> bool + 'static, disabled_fn: impl Fn() -> bool + 'static + Copy, tooltip_: impl Fn() -> S + 'static + Clone, - config: ReadSignal>, + config: ReadSignal>, ) -> impl View { tooltip_label( config, @@ -2067,7 +2085,7 @@ pub fn clickable_icon( active_fn: impl Fn() -> bool + 'static, disabled_fn: impl Fn() -> bool + 'static + Copy, tooltip_: impl Fn() -> S + 'static + Clone, - config: ReadSignal>, + config: ReadSignal>, ) -> impl View { tooltip_label( config, @@ -2081,7 +2099,7 @@ pub fn clickable_icon_base( on_click: Option, active_fn: impl Fn() -> bool + 'static, disabled_fn: impl Fn() -> bool + 'static + Copy, - config: ReadSignal>, + config: ReadSignal>, ) -> impl View { let view = Container::new( svg(move || config.get().ui_svg(icon())) @@ -2089,9 +2107,9 @@ pub fn clickable_icon_base( let config = config.get(); let size = config.ui.icon_size() as f32; s.size(size, size) - .color(config.color(LapceColor::LAPCE_ICON_ACTIVE)) + .color(config.color(UmideColor::LAPCE_ICON_ACTIVE)) .disabled(|s| { - s.color(config.color(LapceColor::LAPCE_ICON_INACTIVE)) + s.color(config.color(UmideColor::LAPCE_ICON_INACTIVE)) .cursor(CursorStyle::Default) }).set_disabled(disabled_fn()) }) @@ -2103,15 +2121,15 @@ pub fn clickable_icon_base( .border(1.0) .border_color(Color::TRANSPARENT) .apply_if(active_fn(), |s| { - s.border_color(config.color(LapceColor::EDITOR_CARET)) + s.border_color(config.color(UmideColor::EDITOR_CARET)) }) .hover(|s| { s.cursor(CursorStyle::Pointer) - .background(config.color(LapceColor::PANEL_HOVERED_BACKGROUND)) + .background(config.color(UmideColor::PANEL_HOVERED_BACKGROUND)) }) .active(|s| { s.background( - config.color(LapceColor::PANEL_HOVERED_ACTIVE_BACKGROUND), + config.color(UmideColor::PANEL_HOVERED_ACTIVE_BACKGROUND), ) }).set_disabled(disabled_fn()) }); @@ -2129,7 +2147,7 @@ pub fn clickable_icon_base( /// When styling an element that has the tooltip, it will style the child rather than the tooltip /// label. pub fn tooltip_label( - config: ReadSignal>, + config: ReadSignal>, child: V, text: impl Fn() -> S + 'static + Clone, ) -> impl View { @@ -2142,7 +2160,7 @@ pub fn tooltip_label( } fn tooltip_tip( - config: ReadSignal>, + config: ReadSignal>, child: V, ) -> impl IntoView { Container::new(child).style(move |s| { @@ -2151,13 +2169,13 @@ fn tooltip_tip( .padding_vert(5.0) .font_size(config.ui.font_size() as f32) .font_family(config.ui.font_family.clone()) - .color(config.color(LapceColor::TOOLTIP_FOREGROUND)) - .background(config.color(LapceColor::TOOLTIP_BACKGROUND)) + .color(config.color(UmideColor::TOOLTIP_FOREGROUND)) + .background(config.color(UmideColor::TOOLTIP_BACKGROUND)) .border(1) .border_radius(6) - .border_color(config.color(LapceColor::LAPCE_BORDER)) + .border_color(config.color(UmideColor::LAPCE_BORDER)) .box_shadow_blur(3.0) - .box_shadow_color(config.color(LapceColor::LAPCE_DROPDOWN_SHADOW)) + .box_shadow_color(config.color(UmideColor::LAPCE_DROPDOWN_SHADOW)) .margin_left(0.0) .margin_top(4.0) }) @@ -2199,12 +2217,12 @@ fn workbench(window_tab_data: Rc) -> impl View { } fn palette_item( - workspace: Arc, + workspace: Arc, i: usize, item: PaletteItem, index: ReadSignal, palette_item_height: f64, - config: ReadSignal>, + config: ReadSignal>, keymap: Option<&KeyMap>, ) -> impl View + use<> { match &item.content { @@ -2261,16 +2279,16 @@ fn palette_item( focus_text( move || file_name.clone(), move || file_name_indices.clone(), - move || config.get().color(LapceColor::EDITOR_FOCUS), + move || config.get().color(UmideColor::EDITOR_FOCUS), ) .style(|s| s.margin_right(6.0).max_width_full()), focus_text( move || folder.clone(), move || folder_indices.clone(), - move || config.get().color(LapceColor::EDITOR_FOCUS), + move || config.get().color(UmideColor::EDITOR_FOCUS), ) .style(move |s| { - s.color(config.get().color(LapceColor::EDITOR_DIM)) + s.color(config.get().color(UmideColor::EDITOR_DIM)) .min_width(0.0) .flex_grow(1.0) .flex_basis(0.0) @@ -2314,30 +2332,30 @@ fn palette_item( let config = config.get(); config .symbol_svg(&kind) - .unwrap_or_else(|| config.ui_svg(LapceIcons::FILE)) + .unwrap_or_else(|| config.ui_svg(UmideIcons::FILE)) }) .style(move |s| { let config = config.get(); let size = config.ui.icon_size() as f32; s.min_width(size).size(size, size).margin_right(5.0).color( config.symbol_color(&kind).unwrap_or_else(|| { - config.color(LapceColor::LAPCE_ICON_ACTIVE) + config.color(UmideColor::LAPCE_ICON_ACTIVE) }), ) }), focus_text( move || text.clone(), move || text_indices.clone(), - move || config.get().color(LapceColor::EDITOR_FOCUS), + move || config.get().color(UmideColor::EDITOR_FOCUS), ) .style(|s| s.margin_right(6.0).max_width_full()), focus_text( move || hint.clone(), move || hint_indices.clone(), - move || config.get().color(LapceColor::EDITOR_FOCUS), + move || config.get().color(UmideColor::EDITOR_FOCUS), ) .style(move |s| { - s.color(config.get().color(LapceColor::EDITOR_DIM)) + s.color(config.get().color(UmideColor::EDITOR_DIM)) .min_width(0.0) .flex_grow(1.0) .flex_basis(0.0) @@ -2392,7 +2410,7 @@ fn palette_item( let config = config.get(); config .symbol_svg(&kind) - .unwrap_or_else(|| config.ui_svg(LapceIcons::FILE)) + .unwrap_or_else(|| config.ui_svg(UmideIcons::FILE)) }) .style(move |s| { let config = config.get(); @@ -2400,21 +2418,21 @@ fn palette_item( s.min_width(size) .size(size, size) .margin_right(5.0) - .color(config.color(LapceColor::LAPCE_ICON_ACTIVE)) + .color(config.color(UmideColor::LAPCE_ICON_ACTIVE)) }), focus_text( move || text.clone(), move || text_indices.clone(), - move || config.get().color(LapceColor::EDITOR_FOCUS), + move || config.get().color(UmideColor::EDITOR_FOCUS), ) .style(|s| s.margin_right(6.0).max_width_full()), focus_text( move || hint.clone(), move || hint_indices.clone(), - move || config.get().color(LapceColor::EDITOR_FOCUS), + move || config.get().color(UmideColor::EDITOR_FOCUS), ) .style(move |s| { - s.color(config.get().color(LapceColor::EDITOR_DIM)) + s.color(config.get().color(UmideColor::EDITOR_DIM)) .min_width(0.0) .flex_grow(1.0) .flex_basis(0.0) @@ -2459,8 +2477,8 @@ fn palette_item( svg(move || { let config = config.get(); match mode { - RunDebugMode::Run => config.ui_svg(LapceIcons::START), - RunDebugMode::Debug => config.ui_svg(LapceIcons::DEBUG), + RunDebugMode::Run => config.ui_svg(UmideIcons::START), + RunDebugMode::Debug => config.ui_svg(UmideIcons::DEBUG), } }) .style(move |s| { @@ -2469,21 +2487,21 @@ fn palette_item( s.min_width(size) .size(size, size) .margin_right(5.0) - .color(config.color(LapceColor::LAPCE_ICON_ACTIVE)) + .color(config.color(UmideColor::LAPCE_ICON_ACTIVE)) }), focus_text( move || text.clone(), move || text_indices.clone(), - move || config.get().color(LapceColor::EDITOR_FOCUS), + move || config.get().color(UmideColor::EDITOR_FOCUS), ) .style(|s| s.margin_right(6.0).max_width_full()), focus_text( move || hint.clone(), move || hint_indices.clone(), - move || config.get().color(LapceColor::EDITOR_FOCUS), + move || config.get().color(UmideColor::EDITOR_FOCUS), ) .style(move |s| { - s.color(config.get().color(LapceColor::EDITOR_DIM)) + s.color(config.get().color(UmideColor::EDITOR_DIM)) .min_width(0.0) .flex_grow(1.0) .flex_basis(0.0) @@ -2511,7 +2529,7 @@ fn palette_item( focus_text( move || text.clone(), move || indices.clone(), - move || config.get().color(LapceColor::EDITOR_FOCUS), + move || config.get().color(UmideColor::EDITOR_FOCUS), ) .style(|s| { s.flex_row() @@ -2529,7 +2547,7 @@ fn palette_item( .border(1.0) .border_radius(3.0) .border_color( - config.get().color(LapceColor::LAPCE_BORDER), + config.get().color(UmideColor::LAPCE_BORDER), ) .selectable(false) }) @@ -2554,7 +2572,7 @@ fn palette_item( focus_text( move || text.clone(), move || indices.clone(), - move || config.get().color(LapceColor::EDITOR_FOCUS), + move || config.get().color(UmideColor::EDITOR_FOCUS), ) .style(|s| s.align_items(Some(AlignItems::Center)).max_width_full()), ) @@ -2567,7 +2585,7 @@ fn palette_item( focus_text( move || text.clone(), move || indices.clone(), - move || config.get().color(LapceColor::EDITOR_FOCUS), + move || config.get().color(UmideColor::EDITOR_FOCUS), ) .style(|s| s.align_items(Some(AlignItems::Center)).max_width_full()), ) @@ -2579,7 +2597,7 @@ fn palette_item( .padding_horiz(10.0) .apply_if(index.get() == i, |style| { style.background( - config.get().color(LapceColor::PALETTE_CURRENT_BACKGROUND), + config.get().color(UmideColor::PALETTE_CURRENT_BACKGROUND), ) }) }) @@ -2603,8 +2621,8 @@ fn palette_input(window_tab_data: Rc) -> impl View { .height(25.0) .items_center() .border_bottom(1.0) - .border_color(config.color(LapceColor::LAPCE_BORDER)) - .background(config.color(LapceColor::EDITOR_BACKGROUND)) + .border_color(config.color(UmideColor::LAPCE_BORDER)) + .background(config.color(UmideColor::EDITOR_BACKGROUND)) })) .style(|s| s.padding_bottom(5.0)) } @@ -2664,7 +2682,7 @@ fn palette_content( Some(CommandKind::Workbench(cmd.clone())) } PaletteItemContent::Command { - cmd: LapceCommand { kind, .. }, + cmd: UmideCommand { kind, .. }, } => Some(kind.clone()), _ => None, }; @@ -2690,7 +2708,7 @@ fn palette_content( s.background( config .get() - .color(LapceColor::PANEL_HOVERED_BACKGROUND), + .color(UmideColor::PANEL_HOVERED_BACKGROUND), ) }) }) @@ -2751,9 +2769,9 @@ fn palette_preview(window_tab_data: Rc) -> impl View { let config = config.get(); s.position(Position::Absolute) .border_top(1.0) - .border_color(config.color(LapceColor::LAPCE_BORDER)) + .border_color(config.color(UmideColor::LAPCE_BORDER)) .size_full() - .background(config.color(LapceColor::EDITOR_BACKGROUND)) + .background(config.color(UmideColor::EDITOR_BACKGROUND)) }), ) .style(move |s| { @@ -2796,9 +2814,9 @@ fn palette(window_tab_data: Rc) -> impl View { .margin_top(4.0) .border(1.0) .border_radius(6.0) - .border_color(config.color(LapceColor::LAPCE_BORDER)) + .border_color(config.color(UmideColor::LAPCE_BORDER)) .flex_col() - .background(config.color(LapceColor::PALETTE_BACKGROUND)) + .background(config.color(UmideColor::PALETTE_BACKGROUND)) .pointer_events_auto() }), ) @@ -2819,25 +2837,25 @@ fn palette(window_tab_data: Rc) -> impl View { fn window_message_view( messages: RwSignal>, - config: ReadSignal>, + config: ReadSignal>, ) -> impl View { let view_fn = move |(i, (title, message)): (usize, (String, ShowMessageParams))| { Stack::new(( svg(move || { if let MessageType::ERROR = message.typ { - config.get().ui_svg(LapceIcons::ERROR) + config.get().ui_svg(UmideIcons::ERROR) } else { - config.get().ui_svg(LapceIcons::WARNING) + config.get().ui_svg(UmideIcons::WARNING) } }) .style(move |s| { let config = config.get(); let size = config.ui.icon_size() as f32; let color = if let MessageType::ERROR = message.typ { - config.color(LapceColor::LAPCE_ERROR) + config.color(UmideColor::LAPCE_ERROR) } else { - config.color(LapceColor::LAPCE_WARN) + config.color(UmideColor::LAPCE_WARN) }; s.min_width(size) .size(size, size) @@ -2857,7 +2875,7 @@ fn window_message_view( s.flex_col().min_width(0.0).flex_basis(0.0).flex_grow(1.0) }), clickable_icon( - || LapceIcons::CLOSE, + || UmideIcons::CLOSE, move || { messages.update(|messages| { messages.remove(i); @@ -2892,8 +2910,8 @@ fn window_message_view( .padding(10.0) .border(1.0) .border_radius(6.0) - .border_color(config.color(LapceColor::LAPCE_BORDER)) - .background(config.color(LapceColor::PANEL_BACKGROUND)) + .border_color(config.color(UmideColor::LAPCE_BORDER)) + .background(config.color(UmideColor::PANEL_BACKGROUND)) .apply_if(i > 0, |s| s.margin_top(10.0)) }) }; @@ -2992,7 +3010,7 @@ fn hover(window_tab_data: Rc) -> impl View { s.width_full() .margin_vert(5.0) .height(1.0) - .background(config.get().color(LapceColor::LAPCE_BORDER)) + .background(config.get().color(UmideColor::LAPCE_BORDER)) })), }, ) @@ -3016,8 +3034,8 @@ fn hover(window_tab_data: Rc) -> impl View { .max_height(300.0) .border(1.0) .border_radius(6.0) - .border_color(config.color(LapceColor::LAPCE_BORDER)) - .background(config.color(LapceColor::PANEL_BACKGROUND)) + .border_color(config.color(UmideColor::LAPCE_BORDER)) + .background(config.color(UmideColor::PANEL_BACKGROUND)) .set(PropagatePointerWheel, false) } else { s.hide() @@ -3074,7 +3092,7 @@ fn completion(window_tab_data: Rc) -> impl View { } }, move || item.indices.clone(), - move || config.get().color(LapceColor::EDITOR_FOCUS), + move || config.get().color(UmideColor::EDITOR_FOCUS), ) .on_click_stop(move |_| { active.set(i); @@ -3092,13 +3110,13 @@ fn completion(window_tab_data: Rc) -> impl View { .cursor(CursorStyle::Pointer) .apply_if(active.get() == i, |s| { s.background( - config.color(LapceColor::COMPLETION_CURRENT), + config.color(UmideColor::COMPLETION_CURRENT), ) }) .hover(move |s| { s.background( config - .color(LapceColor::PANEL_HOVERED_BACKGROUND), + .color(UmideColor::PANEL_HOVERED_BACKGROUND), ) }) }), @@ -3141,7 +3159,7 @@ fn completion(window_tab_data: Rc) -> impl View { .max_height(400.0) .margin_left(origin.x as f32) .margin_top(origin.y as f32) - .background(config.color(LapceColor::COMPLETION_BACKGROUND)) + .background(config.color(UmideColor::COMPLETION_BACKGROUND)) .font_family(config.editor.font_family.clone()) .font_size(config.editor.font_size() as f32) .border_radius(6.0) @@ -3187,13 +3205,13 @@ fn code_action(window_tab_data: Rc) -> impl View { .cursor(CursorStyle::Pointer) .apply_if(active.get() == i, |s| { s.background( - config.color(LapceColor::COMPLETION_CURRENT), + config.color(UmideColor::COMPLETION_CURRENT), ) }) .hover(move |s| { s.background( config - .color(LapceColor::PANEL_HOVERED_BACKGROUND), + .color(UmideColor::PANEL_HOVERED_BACKGROUND), ) }) }) @@ -3230,7 +3248,7 @@ fn code_action(window_tab_data: Rc) -> impl View { .max_height(400.0) .margin_left(origin.x as f32) .margin_top(origin.y as f32) - .background(config.get().color(LapceColor::COMPLETION_BACKGROUND)) + .background(config.get().color(UmideColor::COMPLETION_BACKGROUND)) .border_radius(6.0) }) .debug_name("Code Action Layer") @@ -3255,8 +3273,8 @@ fn rename(window_tab_data: Rc) -> impl View { .font_size(config.editor.font_size() as f32) .border(1.0) .border_radius(6.0) - .border_color(config.color(LapceColor::LAPCE_BORDER)) - .background(config.color(LapceColor::EDITOR_BACKGROUND)) + .border_color(config.color(UmideColor::LAPCE_BORDER)) + .background(config.color(UmideColor::EDITOR_BACKGROUND)) }), ) .on_resize(move |rect| { @@ -3270,7 +3288,7 @@ fn rename(window_tab_data: Rc) -> impl View { .apply_if(!active.get(), |s| s.hide()) .margin_left(origin.x as f32) .margin_top(origin.y as f32) - .background(config.get().color(LapceColor::PANEL_BACKGROUND)) + .background(config.get().color(UmideColor::PANEL_BACKGROUND)) .border_radius(6.0) .padding(6.0) }) @@ -3326,14 +3344,14 @@ fn window_tab(window_tab_data: Rc) -> impl View { .style(move |s| { let config = config.get(); s.size_full() - .color(config.color(LapceColor::EDITOR_FOREGROUND)) - .background(config.color(LapceColor::EDITOR_BACKGROUND)) + .color(config.color(UmideColor::EDITOR_FOREGROUND)) + .background(config.color(UmideColor::EDITOR_BACKGROUND)) .font_size(config.ui.font_size() as f32) .apply_if(!config.ui.font_family.is_empty(), |s| { s.font_family(config.ui.font_family.clone()) }) .class(floem::views::scroll::Handle, |s| { - s.background(config.color(LapceColor::LAPCE_SCROLL_BAR)) + s.background(config.color(UmideColor::LAPCE_SCROLL_BAR)) }) }) .debug_name("Window Tab"); @@ -3343,14 +3361,14 @@ fn window_tab(window_tab_data: Rc) -> impl View { view } -fn workspace_title(workspace: &LapceWorkspace) -> Option { +fn workspace_title(workspace: &UmideWorkspace) -> Option { let p = workspace.path.as_ref()?; let dir = p.file_name().unwrap_or(p.as_os_str()).to_string_lossy(); Some(match &workspace.kind { - LapceWorkspaceType::Local => format!("{dir}"), - LapceWorkspaceType::RemoteSSH(remote) => format!("{dir} [{remote}]"), + UmideWorkspaceType::Local => format!("{dir}"), + UmideWorkspaceType::RemoteSSH(remote) => format!("{dir} [{remote}]"), #[cfg(windows)] - LapceWorkspaceType::RemoteWSL(remote) => format!("{dir} [{remote}]"), + UmideWorkspaceType::RemoteWSL(remote) => format!("{dir} [{remote}]"), }) } @@ -3411,7 +3429,7 @@ fn workspace_tab_header(window_data: WindowData) -> impl View { { let window_data = local_window_data.clone(); clickable_icon( - || LapceIcons::WINDOW_CLOSE, + || UmideIcons::WINDOW_CLOSE, move || { window_data.run_window_command( WindowCommand::CloseWorkspaceTab { @@ -3470,7 +3488,7 @@ fn workspace_tab_header(window_data: WindowData) -> impl View { .min_width(0.0) .items_center() .border_right(1.0) - .border_color(config.color(LapceColor::LAPCE_BORDER)) + .border_color(config.color(UmideColor::LAPCE_BORDER)) .apply_if( cfg!(target_os = "macos") && index.get() == 0, |s| s.border_left(1.0), @@ -3484,7 +3502,7 @@ fn workspace_tab_header(window_data: WindowData) -> impl View { .border_color( config .get() - .color(LapceColor::LAPCE_TAB_ACTIVE_UNDERLINE), + .color(UmideColor::LAPCE_TAB_ACTIVE_UNDERLINE), ) })) .style(move |s| { @@ -3506,15 +3524,15 @@ fn workspace_tab_header(window_data: WindowData) -> impl View { let config = config.get(); s.border(1.0) .border_radius(6.0) - .border_color(config.color(LapceColor::LAPCE_BORDER)) + .border_color(config.color(UmideColor::LAPCE_BORDER)) .color( config - .color(LapceColor::EDITOR_FOREGROUND) + .color(UmideColor::EDITOR_FOREGROUND) .multiply_alpha(0.7), ) .background( config - .color(LapceColor::PANEL_BACKGROUND) + .color(UmideColor::PANEL_BACKGROUND) .multiply_alpha(0.7), ) }) @@ -3531,7 +3549,7 @@ fn workspace_tab_header(window_data: WindowData) -> impl View { ) .height_full() .border_color( - config.get().color(LapceColor::LAPCE_TAB_ACTIVE_UNDERLINE), + config.get().color(UmideColor::LAPCE_TAB_ACTIVE_UNDERLINE), ) .apply_if(drag_over_left.get().is_some(), move |s| { let drag_over_left = drag_over_left.get_untracked().unwrap(); @@ -3569,10 +3587,10 @@ fn workspace_tab_header(window_data: WindowData) -> impl View { ) .style(|s| s.height_full()), Container::new(clickable_icon( - || LapceIcons::ADD, + || UmideIcons::ADD, move || { window_data.run_window_command(WindowCommand::NewWorkspaceTab { - workspace: LapceWorkspace::default(), + workspace: UmideWorkspace::default(), end: true, }); }, @@ -3626,9 +3644,9 @@ fn workspace_tab_header(window_data: WindowData) -> impl View { s.font_family(config.ui.font_family.clone()) }) .apply_if(tabs.with(|tabs| tabs.len() < 2), |s| s.hide()) - .color(config.color(LapceColor::EDITOR_FOREGROUND)) - .border_color(config.color(LapceColor::LAPCE_BORDER)) - .background(config.color(LapceColor::PANEL_BACKGROUND)) + .color(config.color(UmideColor::EDITOR_FOREGROUND)) + .border_color(config.color(UmideColor::LAPCE_BORDER)) + .background(config.color(UmideColor::PANEL_BACKGROUND)) .items_center() }) .debug_name("Workspace Tab Header") @@ -3657,8 +3675,8 @@ fn window(window_data: WindowData) -> impl View { .or_else(|| window_tabs.last()) .and_then(|(_, window_tab)| window_tab.workspace.display()); match workspace { - Some(workspace) => format!("{workspace} - Lapce"), - None => "Lapce".to_string(), + Some(workspace) => format!("{workspace} - Umide"), + None => "Umide".to_string(), } }) .on_event_stop(EventListener::ImeEnabled, move |_| { @@ -3701,7 +3719,7 @@ pub fn launch() { } let (reload_handle, _guard) = logging::logging(); - trace!(TraceLevel::INFO, "Starting up Lapce.."); + trace!(TraceLevel::INFO, "Starting up Umide.."); #[cfg(feature = "vendored-fonts")] { @@ -3779,7 +3797,7 @@ pub fn launch() { } // If the cli is not requesting a new window, and we're not developing a plugin, we try to open - // in the existing Lapce process + // in the existing Umide process if !cli.new { match get_socket() { Ok(socket) => { @@ -3800,13 +3818,13 @@ pub fn launch() { if let Err(err) = umide_proxy::register_lapce_path() { tracing::error!("{:?}", err); } - let db = match LapceDb::new() { + let db = match UmideDb::new() { Ok(db) => Arc::new(db), Err(e) => { #[cfg(windows)] - logging::error_modal("Error", &format!("Failed to create LapceDb: {e}")); + logging::error_modal("Error", &format!("Failed to create UmideDb: {e}")); - trace!(TraceLevel::ERROR, "Failed to create LapceDb: {e}"); + trace!(TraceLevel::ERROR, "Failed to create UmideDb: {e}"); std::process::exit(1); } }; @@ -3821,7 +3839,7 @@ pub fn launch() { let (tx, rx) = channel(); let mut watcher = notify::recommended_watcher(ConfigWatcher::new(tx)).unwrap(); - if let Some(path) = LapceConfig::settings_file() { + if let Some(path) = UmideConfig::settings_file() { if let Err(err) = watcher.watch(&path, notify::RecursiveMode::Recursive) { tracing::error!("{:?}", err); } @@ -3831,7 +3849,7 @@ pub fn launch() { tracing::error!("{:?}", err); } } - if let Some(path) = LapceConfig::keymaps_file() { + if let Some(path) = UmideConfig::keymaps_file() { if let Err(err) = watcher.watch(&path, notify::RecursiveMode::Recursive) { tracing::error!("{:?}", err); } @@ -3843,7 +3861,7 @@ pub fn launch() { } let windows = scope.create_rw_signal(im::HashMap::new()); - let config = LapceConfig::load(&LapceWorkspace::default(), &[], &plugin_paths); + let config = UmideConfig::load(&UmideWorkspace::default(), &[], &plugin_paths); // Restore scale from config window_scale.set(config.ui.scale()); @@ -3950,7 +3968,7 @@ pub fn launch() { } }); std::thread::Builder::new() - .name("LapceUpdater".to_owned()) + .name("UmideUpdater".to_owned()) .spawn(move || { loop { if let Ok(release) = crate::update::get_latest_release() { @@ -4148,36 +4166,36 @@ fn listen_local_socket(tx: SyncSender) -> Result<()> { } pub fn window_menu( - lapce_command: Listener, - workbench_command: Listener, + lapce_command: Listener, + workbench_command: Listener, ) -> Menu { let mut menu = Menu::new(); - // Lapce Menu - menu = menu.submenu("Lapce", move |m| { - let mut m = m.item("About Lapce", |i| i.action(move || { - workbench_command.send(LapceWorkbenchCommand::ShowAbout) + // Umide Menu + menu = menu.submenu("Umide", move |m| { + let mut m = m.item("About Umide", |i| i.action(move || { + workbench_command.send(UmideWorkbenchCommand::ShowAbout) })) .separator() .submenu("Settings...", move |s| { s.item("Open Settings", |i| i.action(move || { workbench_command - .send(LapceWorkbenchCommand::OpenSettings); + .send(UmideWorkbenchCommand::OpenSettings); })) .item("Open Keyboard Shortcuts", |i| i.action(move || { workbench_command.send( - LapceWorkbenchCommand::OpenKeyboardShortcuts, + UmideWorkbenchCommand::OpenKeyboardShortcuts, ); })) }) .separator() - .item("Quit Lapce", |i| i.action(move || { - workbench_command.send(LapceWorkbenchCommand::Quit); + .item("Quit Umide", |i| i.action(move || { + workbench_command.send(UmideWorkbenchCommand::Quit); })); if cfg!(target_os = "macos") { m = m.separator() - .item("Hide Lapce", |i| i) + .item("Hide Umide", |i| i) .item("Hide Others", |i| i) .item("Show All", |i| i); } @@ -4188,70 +4206,70 @@ pub fn window_menu( // File Menu menu = menu.submenu("File", move |m| { m.item("New File", |i| i.action(move || { - workbench_command.send(LapceWorkbenchCommand::NewFile); + workbench_command.send(UmideWorkbenchCommand::NewFile); })) .separator() .item("Open", |i| i.action(move || { - workbench_command.send(LapceWorkbenchCommand::OpenFile); + workbench_command.send(UmideWorkbenchCommand::OpenFile); })) .item("Open Folder", |i| i.action(move || { - workbench_command.send(LapceWorkbenchCommand::OpenFolder); + workbench_command.send(UmideWorkbenchCommand::OpenFolder); })) .separator() .item("Save", |i| i.action(move || { - lapce_command.send(LapceCommand { + lapce_command.send(UmideCommand { kind: CommandKind::Focus(FocusCommand::Save), data: None, }); })) .item("Save All", |i| i.action(move || { - workbench_command.send(LapceWorkbenchCommand::SaveAll); + workbench_command.send(UmideWorkbenchCommand::SaveAll); })) .separator() .item("Close Folder", |i| i.action(move || { - workbench_command.send(LapceWorkbenchCommand::CloseFolder); + workbench_command.send(UmideWorkbenchCommand::CloseFolder); })) .item("Close Window", |i| i.action(move || { - workbench_command.send(LapceWorkbenchCommand::CloseWindow); + workbench_command.send(UmideWorkbenchCommand::CloseWindow); })) }); // Edit Menu menu = menu.submenu("Edit", move |m| { m.item("Cut", |i| i.action(move || { - lapce_command.send(LapceCommand { + lapce_command.send(UmideCommand { kind: CommandKind::Edit(EditCommand::ClipboardCut), data: None, }); })) .item("Copy", |i| i.action(move || { - lapce_command.send(LapceCommand { + lapce_command.send(UmideCommand { kind: CommandKind::Edit(EditCommand::ClipboardCopy), data: None, }); })) .item("Paste", |i| i.action(move || { - lapce_command.send(LapceCommand { + lapce_command.send(UmideCommand { kind: CommandKind::Edit(EditCommand::ClipboardPaste), data: None, }); })) .separator() .item("Undo", |i| i.action(move || { - lapce_command.send(LapceCommand { + lapce_command.send(UmideCommand { kind: CommandKind::Edit(EditCommand::Undo), data: None, }); })) .item("Redo", |i| i.action(move || { - lapce_command.send(LapceCommand { + lapce_command.send(UmideCommand { kind: CommandKind::Edit(EditCommand::Redo), data: None, }); })) .separator() .item("Find", |i| i.action(move || { - lapce_command.send(LapceCommand { + lapce_command.send(UmideCommand { kind: CommandKind::Focus(FocusCommand::Search), data: None, }); diff --git a/crates/umide/src/app/grammars.rs b/crates/umide/src/app/grammars.rs index 2ce2923f..5a54fa96 100644 --- a/crates/umide/src/app/grammars.rs +++ b/crates/umide/src/app/grammars.rs @@ -10,7 +10,7 @@ use umide_core::directory::Directory; use crate::{tracing::*, update::ReleaseInfo}; fn get_github_api(url: &str) -> Result { - let user_agent = format!("Lapce/{}", umide_core::meta::VERSION); + let user_agent = format!("Umide/{}", umide_core::meta::VERSION); let resp = umide_proxy::get_url(url, Some(user_agent.as_str()))?; if !resp.status().is_success() { return Err(anyhow!("get release info failed {}", resp.text()?)); diff --git a/crates/umide/src/app/logging.rs b/crates/umide/src/app/logging.rs index efb02987..45d4e3bc 100644 --- a/crates/umide/src/app/logging.rs +++ b/crates/umide/src/app/logging.rs @@ -18,7 +18,7 @@ pub(super) fn logging() -> (Handle, Vec) { tracing_appender::rolling::Builder::new() .max_log_files(10) .rotation(tracing_appender::rolling::Rotation::DAILY) - .filename_prefix("lapce") + .filename_prefix("umide") .filename_suffix("log") .build(dir) .ok() @@ -45,7 +45,7 @@ pub(super) fn logging() -> (Handle, Vec) { // Filters let log_file_filter_targets = filter::Targets::new() - .with_target("lapce_app", LevelFilter::DEBUG) + .with_target("umide_app", LevelFilter::DEBUG) .with_target("umide_proxy", LevelFilter::DEBUG) .with_target("umide_core", LevelFilter::DEBUG) .with_target("umide_emulator", LevelFilter::TRACE) // Added emulator trace diff --git a/crates/umide/src/code_action.rs b/crates/umide/src/code_action.rs index ab063d17..eff6a232 100644 --- a/crates/umide/src/code_action.rs +++ b/crates/umide/src/code_action.rs @@ -63,7 +63,7 @@ impl KeyPressFocus for CodeActionData { fn run_command( &self, - command: &crate::command::LapceCommand, + command: &crate::command::UmideCommand, _count: Option, _mods: Modifiers, ) -> crate::command::CommandExecuted { diff --git a/crates/umide/src/command.rs b/crates/umide/src/command.rs index 5246c6df..a92becf4 100644 --- a/crates/umide/src/command.rs +++ b/crates/umide/src/command.rs @@ -29,18 +29,18 @@ use crate::{ editor_tab::EditorTabChild, id::EditorTabId, main_split::{SplitDirection, SplitMoveDirection, TabCloseKind}, - workspace::LapceWorkspace, + workspace::UmideWorkspace, }; #[derive(Clone, Debug, PartialEq, Eq)] -pub struct LapceCommand { +pub struct UmideCommand { pub kind: CommandKind, pub data: Option, } #[derive(Clone, Debug, PartialEq, Eq)] pub enum CommandKind { - Workbench(LapceWorkbenchCommand), + Workbench(UmideWorkbenchCommand), Edit(EditCommand), Move(MoveCommand), Scroll(ScrollCommand), @@ -89,11 +89,11 @@ impl From for CommandKind { } } -pub fn lapce_internal_commands() -> IndexMap { +pub fn lapce_internal_commands() -> IndexMap { let mut commands = IndexMap::new(); - for c in LapceWorkbenchCommand::iter() { - let command = LapceCommand { + for c in UmideWorkbenchCommand::iter() { + let command = UmideCommand { kind: CommandKind::Workbench(c.clone()), data: None, }; @@ -101,7 +101,7 @@ pub fn lapce_internal_commands() -> IndexMap { } for c in EditCommand::iter() { - let command = LapceCommand { + let command = UmideCommand { kind: CommandKind::Edit(c.clone()), data: None, }; @@ -109,7 +109,7 @@ pub fn lapce_internal_commands() -> IndexMap { } for c in MoveCommand::iter() { - let command = LapceCommand { + let command = UmideCommand { kind: CommandKind::Move(c.clone()), data: None, }; @@ -117,7 +117,7 @@ pub fn lapce_internal_commands() -> IndexMap { } for c in ScrollCommand::iter() { - let command = LapceCommand { + let command = UmideCommand { kind: CommandKind::Scroll(c.clone()), data: None, }; @@ -125,7 +125,7 @@ pub fn lapce_internal_commands() -> IndexMap { } for c in FocusCommand::iter() { - let command = LapceCommand { + let command = UmideCommand { kind: CommandKind::Focus(c.clone()), data: None, }; @@ -133,7 +133,7 @@ pub fn lapce_internal_commands() -> IndexMap { } for c in MotionModeCommand::iter() { - let command = LapceCommand { + let command = UmideCommand { kind: CommandKind::MotionMode(c.clone()), data: None, }; @@ -141,7 +141,7 @@ pub fn lapce_internal_commands() -> IndexMap { } for c in MultiSelectionCommand::iter() { - let command = LapceCommand { + let command = UmideCommand { kind: CommandKind::MultiSelection(c.clone()), data: None, }; @@ -162,7 +162,7 @@ pub fn lapce_internal_commands() -> IndexMap { EnumMessage, IntoStaticStr, )] -pub enum LapceWorkbenchCommand { +pub enum UmideWorkbenchCommand { #[strum(serialize = "enable_modal_editing")] #[strum(message = "Enable Modal Editing")] EnableModal, @@ -548,7 +548,7 @@ pub enum LapceWorkbenchCommand { RestartToUpdate, #[strum(serialize = "show_about")] - #[strum(message = "About Lapce")] + #[strum(message = "About Umide")] ShowAbout, #[strum(message = "Save All Files")] @@ -556,12 +556,12 @@ pub enum LapceWorkbenchCommand { SaveAll, #[cfg(target_os = "macos")] - #[strum(message = "Install Lapce to PATH")] + #[strum(message = "Install Umide to PATH")] #[strum(serialize = "install_to_path")] InstallToPATH, #[cfg(target_os = "macos")] - #[strum(message = "Uninstall Lapce from PATH")] + #[strum(message = "Uninstall Umide from PATH")] #[strum(serialize = "uninstall_from_path")] UninstallFromPATH, @@ -720,12 +720,12 @@ pub enum InternalCommand { s: String, }, FindEditorCommand { - command: LapceCommand, + command: UmideCommand, count: Option, mods: Modifiers, }, ReplaceEditorCommand { - command: LapceCommand, + command: UmideCommand, count: Option, mods: Modifiers, }, @@ -802,13 +802,13 @@ pub enum InternalCommand { #[derive(Clone)] pub enum WindowCommand { SetWorkspace { - workspace: LapceWorkspace, + workspace: UmideWorkspace, }, CloseWorkspaceTab { index: Option, }, NewWorkspaceTab { - workspace: LapceWorkspace, + workspace: UmideWorkspace, end: bool, }, NextWorkspaceTab, diff --git a/crates/umide/src/completion.rs b/crates/umide/src/completion.rs index 21bfcd3a..e237c3ff 100644 --- a/crates/umide/src/completion.rs +++ b/crates/umide/src/completion.rs @@ -15,7 +15,7 @@ use lsp_types::{ }; use nucleo::Utf32Str; -use crate::{config::LapceConfig, editor::EditorData, snippet::Snippet}; +use crate::{config::UmideConfig, editor::EditorData, snippet::Snippet}; #[derive(Clone, Copy, PartialEq, Eq)] pub enum CompletionStatus { @@ -63,11 +63,11 @@ pub struct CompletionData { pub latest_editor_id: Option, /// Matcher for filtering the completion items matcher: RwSignal, - config: ReadSignal>, + config: ReadSignal>, } impl CompletionData { - pub fn new(cx: Scope, config: ReadSignal>) -> Self { + pub fn new(cx: Scope, config: ReadSignal>) -> Self { let active = cx.create_rw_signal(0); Self { status: CompletionStatus::Inactive, @@ -404,7 +404,7 @@ fn completion_lens_text( // If the text does not include a prefix in the expected position, then we do not display it. let item = as AsRef>::as_ref(&item).strip_prefix(&completion.input)?; - // Get only the first line of text, because Lapce does not currently support + // Get only the first line of text, because Umide does not currently support // multi-line phantom text. let item = item.lines().next().unwrap_or(item); diff --git a/crates/umide/src/config.rs b/crates/umide/src/config.rs index 379d9b69..4afe5d90 100644 --- a/crates/umide/src/config.rs +++ b/crates/umide/src/config.rs @@ -18,17 +18,17 @@ use strum::VariantNames; use tracing::error; use self::{ - color::LapceColor, + color::UmideColor, color_theme::{ColorThemeConfig, ThemeColor, ThemeColorPreference}, core::CoreConfig, editor::{EditorConfig, SCALE_OR_SIZE_LIMIT, WrapStyle}, - icon::LapceIcons, + icon::UmideIcons, icon_theme::IconThemeConfig, svg::SvgStore, terminal::TerminalConfig, ui::UIConfig, }; -use crate::workspace::{LapceWorkspace, LapceWorkspaceType}; +use crate::workspace::{UmideWorkspace, UmideWorkspaceType}; pub mod color; pub mod color_theme; @@ -47,9 +47,9 @@ const DEFAULT_LIGHT_THEME: &str = include_str!("../../../defaults/light-theme.to const DEFAULT_DARK_THEME: &str = include_str!("../../../defaults/dark-theme.toml"); const DEFAULT_ICON_THEME: &str = include_str!("../../../defaults/icon-theme.toml"); -static DEFAULT_CONFIG: Lazy = Lazy::new(LapceConfig::default_config); -static DEFAULT_LAPCE_CONFIG: Lazy = - Lazy::new(LapceConfig::default_lapce_config); +static DEFAULT_CONFIG: Lazy = Lazy::new(UmideConfig::default_config); +static DEFAULT_LAPCE_CONFIG: Lazy = + Lazy::new(UmideConfig::default_lapce_config); static DEFAULT_DARK_THEME_CONFIG: Lazy = Lazy::new(|| { config::Config::builder() @@ -64,7 +64,7 @@ static DEFAULT_DARK_THEME_CONFIG: Lazy = Lazy::new(|| { /// The default theme is the dark theme. static DEFAULT_DARK_THEME_COLOR_CONFIG: Lazy = Lazy::new(|| { let (_, theme) = - LapceConfig::load_color_theme_from_str(DEFAULT_DARK_THEME).unwrap(); + UmideConfig::load_color_theme_from_str(DEFAULT_DARK_THEME).unwrap(); theme.get::("color-theme") .expect("Failed to load default dark theme. This is likely due to a missing or misnamed field in dark-theme.toml") }); @@ -93,7 +93,7 @@ pub struct DropdownInfo { #[derive(Debug, Clone, Deserialize, Default)] #[serde(rename_all = "kebab-case")] -pub struct LapceConfig { +pub struct UmideConfig { #[serde(skip)] pub id: u64, pub core: CoreConfig, @@ -128,14 +128,14 @@ pub struct LapceConfig { wrap_style_list: im::Vector, } -impl LapceConfig { +impl UmideConfig { pub fn load( - workspace: &LapceWorkspace, + workspace: &UmideWorkspace, disabled_volts: &[VoltID], extra_plugin_paths: &[PathBuf], ) -> Self { let config = Self::merge_config(workspace, None, None); - let mut lapce_config: LapceConfig = match config.try_deserialize() { + let mut lapce_config: UmideConfig = match config.try_deserialize() { Ok(config) => config, Err(error) => { error!("Failed to deserialize configuration file: {error}"); @@ -178,7 +178,7 @@ impl LapceConfig { } fn merge_config( - workspace: &LapceWorkspace, + workspace: &UmideWorkspace, color_theme_config: Option, icon_theme_config: Option, ) -> config::Config { @@ -212,7 +212,7 @@ impl LapceConfig { } match workspace.kind { - LapceWorkspaceType::Local => { + UmideWorkspaceType::Local => { if let Some(path) = workspace.path.as_ref() { let path = path.join("./.lapce/settings.toml"); config = config::Config::builder() @@ -224,9 +224,9 @@ impl LapceConfig { .unwrap_or_else(|_| config.clone()); } } - LapceWorkspaceType::RemoteSSH(_) => {} + UmideWorkspaceType::RemoteSSH(_) => {} #[cfg(windows)] - LapceWorkspaceType::RemoteWSL(_) => {} + UmideWorkspaceType::RemoteWSL(_) => {} } config @@ -249,8 +249,8 @@ impl LapceConfig { .unwrap() } - fn default_lapce_config() -> LapceConfig { - let mut default_lapce_config: LapceConfig = + fn default_lapce_config() -> UmideConfig { + let mut default_lapce_config: UmideConfig = DEFAULT_CONFIG.clone().try_deserialize().expect("Failed to deserialize default config, this likely indicates a missing or misnamed field in settings.toml"); default_lapce_config.color_theme = DEFAULT_DARK_THEME_COLOR_CONFIG.clone(); default_lapce_config.icon_theme = DEFAULT_ICON_THEME_ICON_CONFIG.clone(); @@ -258,7 +258,7 @@ impl LapceConfig { default_lapce_config } - fn resolve_theme(&mut self, workspace: &LapceWorkspace) { + fn resolve_theme(&mut self, workspace: &UmideWorkspace) { let default_lapce_config = DEFAULT_LAPCE_CONFIG.clone(); let color_theme_config = self @@ -283,7 +283,7 @@ impl LapceConfig { Some(color_theme_config.clone()), Some(icon_theme_config.clone()), ) - .try_deserialize::() + .try_deserialize::() { self.core = new.core; self.ui = new.ui; @@ -330,19 +330,19 @@ impl LapceConfig { /// Set the active color theme. /// Note that this does not save the config. - pub fn set_color_theme(&mut self, workspace: &LapceWorkspace, theme: &str) { + pub fn set_color_theme(&mut self, workspace: &UmideWorkspace, theme: &str) { self.core.color_theme = theme.to_string(); self.resolve_theme(workspace); } /// Set the active icon theme. /// Note that this does not save the config. - pub fn set_icon_theme(&mut self, workspace: &LapceWorkspace, theme: &str) { + pub fn set_icon_theme(&mut self, workspace: &UmideWorkspace, theme: &str) { self.core.icon_theme = theme.to_string(); self.resolve_theme(workspace); } - pub fn set_modal(&mut self, _workspace: &LapceWorkspace, modal: bool) { + pub fn set_modal(&mut self, _workspace: &UmideWorkspace, modal: bool) { self.core.modal = modal; } @@ -392,7 +392,7 @@ impl LapceConfig { self.style_color(theme_str) } - fn resolve_colors(&mut self, default_config: Option<&LapceConfig>) { + fn resolve_colors(&mut self, default_config: Option<&UmideConfig>) { self.color.base = self .color_theme .base @@ -405,8 +405,8 @@ impl LapceConfig { default_config.map(|c| &c.color.syntax), ); - let fg = self.color(LapceColor::EDITOR_FOREGROUND).to_rgba8(); - let bg = self.color(LapceColor::EDITOR_BACKGROUND).to_rgba8(); + let fg = self.color(UmideColor::EDITOR_FOREGROUND).to_rgba8(); + let bg = self.color(UmideColor::EDITOR_BACKGROUND).to_rgba8(); let is_light = fg.r as u32 + fg.g as u32 + fg.b as u32 > bg.r as u32 + bg.g as u32 + bg.b as u32; let high_contrast = self.color_theme.high_contrast.unwrap_or(false); @@ -614,15 +614,15 @@ impl LapceConfig { if let Some(svg) = svg { let color = if self.icon_theme.use_editor_color.unwrap_or(false) { - Some(self.color(LapceColor::LAPCE_ICON_ACTIVE)) + Some(self.color(UmideColor::LAPCE_ICON_ACTIVE)) } else { None }; (svg, color) } else { ( - self.ui_svg(LapceIcons::FILE), - Some(self.color(LapceColor::LAPCE_ICON_ACTIVE)), + self.ui_svg(UmideIcons::FILE), + Some(self.color(UmideColor::LAPCE_ICON_ACTIVE)), ) } } @@ -633,28 +633,28 @@ impl LapceConfig { pub fn symbol_svg(&self, kind: &SymbolKind) -> Option { let kind_str = match *kind { - SymbolKind::ARRAY => LapceIcons::SYMBOL_KIND_ARRAY, - SymbolKind::BOOLEAN => LapceIcons::SYMBOL_KIND_BOOLEAN, - SymbolKind::CLASS => LapceIcons::SYMBOL_KIND_CLASS, - SymbolKind::CONSTANT => LapceIcons::SYMBOL_KIND_CONSTANT, - SymbolKind::ENUM_MEMBER => LapceIcons::SYMBOL_KIND_ENUM_MEMBER, - SymbolKind::ENUM => LapceIcons::SYMBOL_KIND_ENUM, - SymbolKind::EVENT => LapceIcons::SYMBOL_KIND_EVENT, - SymbolKind::FIELD => LapceIcons::SYMBOL_KIND_FIELD, - SymbolKind::FILE => LapceIcons::SYMBOL_KIND_FILE, - SymbolKind::INTERFACE => LapceIcons::SYMBOL_KIND_INTERFACE, - SymbolKind::KEY => LapceIcons::SYMBOL_KIND_KEY, - SymbolKind::FUNCTION => LapceIcons::SYMBOL_KIND_FUNCTION, - SymbolKind::METHOD => LapceIcons::SYMBOL_KIND_METHOD, - SymbolKind::OBJECT => LapceIcons::SYMBOL_KIND_OBJECT, - SymbolKind::NAMESPACE => LapceIcons::SYMBOL_KIND_NAMESPACE, - SymbolKind::NUMBER => LapceIcons::SYMBOL_KIND_NUMBER, - SymbolKind::OPERATOR => LapceIcons::SYMBOL_KIND_OPERATOR, - SymbolKind::TYPE_PARAMETER => LapceIcons::SYMBOL_KIND_TYPE_PARAMETER, - SymbolKind::PROPERTY => LapceIcons::SYMBOL_KIND_PROPERTY, - SymbolKind::STRING => LapceIcons::SYMBOL_KIND_STRING, - SymbolKind::STRUCT => LapceIcons::SYMBOL_KIND_STRUCT, - SymbolKind::VARIABLE => LapceIcons::SYMBOL_KIND_VARIABLE, + SymbolKind::ARRAY => UmideIcons::SYMBOL_KIND_ARRAY, + SymbolKind::BOOLEAN => UmideIcons::SYMBOL_KIND_BOOLEAN, + SymbolKind::CLASS => UmideIcons::SYMBOL_KIND_CLASS, + SymbolKind::CONSTANT => UmideIcons::SYMBOL_KIND_CONSTANT, + SymbolKind::ENUM_MEMBER => UmideIcons::SYMBOL_KIND_ENUM_MEMBER, + SymbolKind::ENUM => UmideIcons::SYMBOL_KIND_ENUM, + SymbolKind::EVENT => UmideIcons::SYMBOL_KIND_EVENT, + SymbolKind::FIELD => UmideIcons::SYMBOL_KIND_FIELD, + SymbolKind::FILE => UmideIcons::SYMBOL_KIND_FILE, + SymbolKind::INTERFACE => UmideIcons::SYMBOL_KIND_INTERFACE, + SymbolKind::KEY => UmideIcons::SYMBOL_KIND_KEY, + SymbolKind::FUNCTION => UmideIcons::SYMBOL_KIND_FUNCTION, + SymbolKind::METHOD => UmideIcons::SYMBOL_KIND_METHOD, + SymbolKind::OBJECT => UmideIcons::SYMBOL_KIND_OBJECT, + SymbolKind::NAMESPACE => UmideIcons::SYMBOL_KIND_NAMESPACE, + SymbolKind::NUMBER => UmideIcons::SYMBOL_KIND_NUMBER, + SymbolKind::OPERATOR => UmideIcons::SYMBOL_KIND_OPERATOR, + SymbolKind::TYPE_PARAMETER => UmideIcons::SYMBOL_KIND_TYPE_PARAMETER, + SymbolKind::PROPERTY => UmideIcons::SYMBOL_KIND_PROPERTY, + SymbolKind::STRING => UmideIcons::SYMBOL_KIND_STRING, + SymbolKind::STRUCT => UmideIcons::SYMBOL_KIND_STRUCT, + SymbolKind::VARIABLE => UmideIcons::SYMBOL_KIND_VARIABLE, _ => return None, }; @@ -787,91 +787,91 @@ impl LapceConfig { ) -> Color { let (color, alpha) = match color { alacritty_terminal::vte::ansi::NamedColor::Cursor => { - (LapceColor::TERMINAL_CURSOR, 1.0) + (UmideColor::TERMINAL_CURSOR, 1.0) } alacritty_terminal::vte::ansi::NamedColor::Foreground => { - (LapceColor::TERMINAL_FOREGROUND, 1.0) + (UmideColor::TERMINAL_FOREGROUND, 1.0) } alacritty_terminal::vte::ansi::NamedColor::Background => { - (LapceColor::TERMINAL_BACKGROUND, 1.0) + (UmideColor::TERMINAL_BACKGROUND, 1.0) } alacritty_terminal::vte::ansi::NamedColor::Blue => { - (LapceColor::TERMINAL_BLUE, 1.0) + (UmideColor::TERMINAL_BLUE, 1.0) } alacritty_terminal::vte::ansi::NamedColor::Green => { - (LapceColor::TERMINAL_GREEN, 1.0) + (UmideColor::TERMINAL_GREEN, 1.0) } alacritty_terminal::vte::ansi::NamedColor::Yellow => { - (LapceColor::TERMINAL_YELLOW, 1.0) + (UmideColor::TERMINAL_YELLOW, 1.0) } alacritty_terminal::vte::ansi::NamedColor::Red => { - (LapceColor::TERMINAL_RED, 1.0) + (UmideColor::TERMINAL_RED, 1.0) } alacritty_terminal::vte::ansi::NamedColor::White => { - (LapceColor::TERMINAL_WHITE, 1.0) + (UmideColor::TERMINAL_WHITE, 1.0) } alacritty_terminal::vte::ansi::NamedColor::Black => { - (LapceColor::TERMINAL_BLACK, 1.0) + (UmideColor::TERMINAL_BLACK, 1.0) } alacritty_terminal::vte::ansi::NamedColor::Cyan => { - (LapceColor::TERMINAL_CYAN, 1.0) + (UmideColor::TERMINAL_CYAN, 1.0) } alacritty_terminal::vte::ansi::NamedColor::Magenta => { - (LapceColor::TERMINAL_MAGENTA, 1.0) + (UmideColor::TERMINAL_MAGENTA, 1.0) } alacritty_terminal::vte::ansi::NamedColor::BrightBlue => { - (LapceColor::TERMINAL_BRIGHT_BLUE, 1.0) + (UmideColor::TERMINAL_BRIGHT_BLUE, 1.0) } alacritty_terminal::vte::ansi::NamedColor::BrightGreen => { - (LapceColor::TERMINAL_BRIGHT_GREEN, 1.0) + (UmideColor::TERMINAL_BRIGHT_GREEN, 1.0) } alacritty_terminal::vte::ansi::NamedColor::BrightYellow => { - (LapceColor::TERMINAL_BRIGHT_YELLOW, 1.0) + (UmideColor::TERMINAL_BRIGHT_YELLOW, 1.0) } alacritty_terminal::vte::ansi::NamedColor::BrightRed => { - (LapceColor::TERMINAL_BRIGHT_RED, 1.0) + (UmideColor::TERMINAL_BRIGHT_RED, 1.0) } alacritty_terminal::vte::ansi::NamedColor::BrightWhite => { - (LapceColor::TERMINAL_BRIGHT_WHITE, 1.0) + (UmideColor::TERMINAL_BRIGHT_WHITE, 1.0) } alacritty_terminal::vte::ansi::NamedColor::BrightBlack => { - (LapceColor::TERMINAL_BRIGHT_BLACK, 1.0) + (UmideColor::TERMINAL_BRIGHT_BLACK, 1.0) } alacritty_terminal::vte::ansi::NamedColor::BrightCyan => { - (LapceColor::TERMINAL_BRIGHT_CYAN, 1.0) + (UmideColor::TERMINAL_BRIGHT_CYAN, 1.0) } alacritty_terminal::vte::ansi::NamedColor::BrightMagenta => { - (LapceColor::TERMINAL_BRIGHT_MAGENTA, 1.0) + (UmideColor::TERMINAL_BRIGHT_MAGENTA, 1.0) } alacritty_terminal::vte::ansi::NamedColor::BrightForeground => { - (LapceColor::TERMINAL_FOREGROUND, 1.0) + (UmideColor::TERMINAL_FOREGROUND, 1.0) } alacritty_terminal::vte::ansi::NamedColor::DimBlack => { - (LapceColor::TERMINAL_BLACK, 0.66) + (UmideColor::TERMINAL_BLACK, 0.66) } alacritty_terminal::vte::ansi::NamedColor::DimRed => { - (LapceColor::TERMINAL_RED, 0.66) + (UmideColor::TERMINAL_RED, 0.66) } alacritty_terminal::vte::ansi::NamedColor::DimGreen => { - (LapceColor::TERMINAL_GREEN, 0.66) + (UmideColor::TERMINAL_GREEN, 0.66) } alacritty_terminal::vte::ansi::NamedColor::DimYellow => { - (LapceColor::TERMINAL_YELLOW, 0.66) + (UmideColor::TERMINAL_YELLOW, 0.66) } alacritty_terminal::vte::ansi::NamedColor::DimBlue => { - (LapceColor::TERMINAL_BLUE, 0.66) + (UmideColor::TERMINAL_BLUE, 0.66) } alacritty_terminal::vte::ansi::NamedColor::DimMagenta => { - (LapceColor::TERMINAL_MAGENTA, 0.66) + (UmideColor::TERMINAL_MAGENTA, 0.66) } alacritty_terminal::vte::ansi::NamedColor::DimCyan => { - (LapceColor::TERMINAL_CYAN, 0.66) + (UmideColor::TERMINAL_CYAN, 0.66) } alacritty_terminal::vte::ansi::NamedColor::DimWhite => { - (LapceColor::TERMINAL_WHITE, 0.66) + (UmideColor::TERMINAL_WHITE, 0.66) } alacritty_terminal::vte::ansi::NamedColor::DimForeground => { - (LapceColor::TERMINAL_FOREGROUND, 0.66) + (UmideColor::TERMINAL_FOREGROUND, 0.66) } }; self.color(color).multiply_alpha(alpha) diff --git a/crates/umide/src/config/color.rs b/crates/umide/src/config/color.rs index 158fabf8..e15d4f62 100644 --- a/crates/umide/src/config/color.rs +++ b/crates/umide/src/config/color.rs @@ -19,9 +19,9 @@ pub enum LoadThemeError { Read(std::io::Error), } -pub struct LapceColor {} +pub struct UmideColor {} -impl LapceColor { +impl UmideColor { pub const LAPCE_WARN: &'static str = "lapce.warn"; pub const LAPCE_ERROR: &'static str = "lapce.error"; pub const LAPCE_DROPDOWN_SHADOW: &'static str = "lapce.dropdown_shadow"; diff --git a/crates/umide/src/config/color_theme.rs b/crates/umide/src/config/color_theme.rs index b9c0d97e..7c2b38ae 100644 --- a/crates/umide/src/config/color_theme.rs +++ b/crates/umide/src/config/color_theme.rs @@ -185,15 +185,15 @@ mod tests { use config::Config; use floem::{peniko::Color, prelude::palette::css}; - use crate::{config::LapceConfig, workspace::LapceWorkspace}; + use crate::{config::UmideConfig, workspace::UmideWorkspace}; #[test] fn test_resolve() { // Mimicking load - let workspace = LapceWorkspace::default(); + let workspace = UmideWorkspace::default(); - let config = LapceConfig::merge_config(&workspace, None, None); - let mut lapce_config: LapceConfig = config.try_deserialize().unwrap(); + let config = UmideConfig::merge_config(&workspace, None, None); + let mut lapce_config: UmideConfig = config.try_deserialize().unwrap(); let test_theme_str = r##" [color-theme] diff --git a/crates/umide/src/config/core.rs b/crates/umide/src/config/core.rs index c230b9cb..f571c5ca 100644 --- a/crates/umide/src/config/core.rs +++ b/crates/umide/src/config/core.rs @@ -6,9 +6,9 @@ use structdesc::FieldNames; pub struct CoreConfig { #[field_names(desc = "Enable modal editing (Vim like)")] pub modal: bool, - #[field_names(desc = "Set the color theme of Lapce")] + #[field_names(desc = "Set the color theme of Umide")] pub color_theme: String, - #[field_names(desc = "Set the icon theme of Lapce")] + #[field_names(desc = "Set the icon theme of Umide")] pub icon_theme: String, #[field_names( desc = "Enable customised titlebar and disable OS native one (Linux, BSD, Windows)" diff --git a/crates/umide/src/config/icon.rs b/crates/umide/src/config/icon.rs index 574a79de..c2a5b262 100644 --- a/crates/umide/src/config/icon.rs +++ b/crates/umide/src/config/icon.rs @@ -1,6 +1,6 @@ -pub struct LapceIcons {} +pub struct UmideIcons {} -impl LapceIcons { +impl UmideIcons { pub const WINDOW_CLOSE: &'static str = "window.close"; pub const WINDOW_RESTORE: &'static str = "window.restore"; pub const WINDOW_MAXIMIZE: &'static str = "window.maximize"; diff --git a/crates/umide/src/db.rs b/crates/umide/src/db.rs index d10e7b65..c1044d7d 100644 --- a/crates/umide/src/db.rs +++ b/crates/umide/src/db.rs @@ -17,7 +17,7 @@ use crate::{ panel::{data::PanelOrder, kind::PanelKind}, window::{WindowData, WindowInfo}, window_tab::WindowTabData, - workspace::{LapceWorkspace, WorkspaceInfo}, + workspace::{UmideWorkspace, WorkspaceInfo}, }; const APP: &str = "app"; @@ -30,22 +30,22 @@ const RECENT_WORKSPACES: &str = "recent_workspaces"; pub enum SaveEvent { App(AppInfo), - Workspace(LapceWorkspace, WorkspaceInfo), - RecentWorkspace(LapceWorkspace), + Workspace(UmideWorkspace, WorkspaceInfo), + RecentWorkspace(UmideWorkspace), Doc(DocInfo), DisabledVolts(Vec), - WorkspaceDisabledVolts(Arc, Vec), + WorkspaceDisabledVolts(Arc, Vec), PanelOrder(PanelOrder), } #[derive(Clone)] -pub struct LapceDb { +pub struct UmideDb { folder: PathBuf, workspace_folder: PathBuf, save_tx: Sender, } -impl LapceDb { +impl UmideDb { pub fn new() -> Result { let folder = Directory::config_directory() .ok_or_else(|| anyhow!("can't get config directory"))? @@ -131,7 +131,7 @@ impl LapceDb { pub fn save_workspace_disabled_volts( &self, - workspace: Arc, + workspace: Arc, volts: Vec, ) { if let Err(err) = self @@ -150,7 +150,7 @@ impl LapceDb { pub fn insert_workspace_disabled_volts( &self, - workspace: Arc, + workspace: Arc, volts: Vec, ) -> Result<()> { let folder = self @@ -167,7 +167,7 @@ impl LapceDb { pub fn get_workspace_disabled_volts( &self, - workspace: &LapceWorkspace, + workspace: &UmideWorkspace, ) -> Result> { let folder = self.workspace_folder.join(workspace_folder_name(workspace)); let volts = std::fs::read_to_string(folder.join(DISABLED_VOLTS))?; @@ -175,14 +175,14 @@ impl LapceDb { Ok(volts) } - pub fn recent_workspaces(&self) -> Result> { + pub fn recent_workspaces(&self) -> Result> { let workspaces = std::fs::read_to_string(self.folder.join(RECENT_WORKSPACES))?; - let workspaces: Vec = serde_json::from_str(&workspaces)?; + let workspaces: Vec = serde_json::from_str(&workspaces)?; Ok(workspaces) } - pub fn update_recent_workspace(&self, workspace: &LapceWorkspace) -> Result<()> { + pub fn update_recent_workspace(&self, workspace: &UmideWorkspace) -> Result<()> { if workspace.path.is_none() { return Ok(()); } @@ -191,7 +191,7 @@ impl LapceDb { Ok(()) } - fn insert_recent_workspace(&self, workspace: LapceWorkspace) -> Result<()> { + fn insert_recent_workspace(&self, workspace: UmideWorkspace) -> Result<()> { let mut workspaces = self.recent_workspaces().unwrap_or_default(); let mut exits = false; @@ -233,7 +233,7 @@ impl LapceDb { pub fn get_workspace_info( &self, - workspace: &LapceWorkspace, + workspace: &UmideWorkspace, ) -> Result { let info = std::fs::read_to_string( self.workspace_folder @@ -246,7 +246,7 @@ impl LapceDb { fn insert_workspace( &self, - workspace: &LapceWorkspace, + workspace: &UmideWorkspace, info: &WorkspaceInfo, ) -> Result<()> { let folder = self.workspace_folder.join(workspace_folder_name(workspace)); @@ -395,7 +395,7 @@ impl LapceDb { pub fn save_doc_position( &self, - workspace: &LapceWorkspace, + workspace: &UmideWorkspace, path: PathBuf, cursor_offset: usize, scroll_offset: Vec2, @@ -426,7 +426,7 @@ impl LapceDb { pub fn get_doc_info( &self, - workspace: &LapceWorkspace, + workspace: &UmideWorkspace, path: &Path, ) -> Result { let folder = self @@ -439,7 +439,7 @@ impl LapceDb { } } -fn workspace_folder_name(workspace: &LapceWorkspace) -> String { +fn workspace_folder_name(workspace: &UmideWorkspace) -> String { url::form_urlencoded::Serializer::new(String::new()) .append_key_only(&workspace.to_string()) .finish() diff --git a/crates/umide/src/debug.rs b/crates/umide/src/debug.rs index bc61ae97..e8fc0d44 100644 --- a/crates/umide/src/debug.rs +++ b/crates/umide/src/debug.rs @@ -61,13 +61,13 @@ pub struct RunDebugConfigs { pub struct RunDebugData { pub active_term: RwSignal>, pub daps: RwSignal>, - pub breakpoints: RwSignal>>, + pub breakpoints: RwSignal>>, } impl RunDebugData { pub fn new( cx: Scope, - breakpoints: RwSignal>>, + breakpoints: RwSignal>>, ) -> Self { let active_term: RwSignal> = cx.create_rw_signal(None); let daps: RwSignal> = @@ -117,7 +117,7 @@ pub struct StackTraceData { } #[derive(Clone, Serialize, Deserialize)] -pub struct LapceBreakpoint { +pub struct UmideBreakpoint { pub id: Option, pub verified: bool, pub message: Option, diff --git a/crates/umide/src/doc.rs b/crates/umide/src/doc.rs index 425b2b09..15778b96 100644 --- a/crates/umide/src/doc.rs +++ b/crates/umide/src/doc.rs @@ -38,7 +38,7 @@ use umide_core::{ cursor::{Cursor, CursorAffinity}, editor::{Action, EditConf, EditType}, indent::IndentStyle, - language::LapceLanguage, + language::UmideLanguage, line_ending::LineEnding, mode::MotionMode, register::Register, @@ -66,8 +66,8 @@ use serde::{Deserialize, Serialize}; use smallvec::SmallVec; use crate::{ - command::{CommandKind, LapceCommand}, - config::{LapceConfig, color::LapceColor}, + command::{CommandKind, UmideCommand}, + config::{UmideConfig, color::UmideColor}, editor::{EditorData, compute_screen_lines, gutter::FoldingRanges}, find::{Find, FindProgress, FindResult}, history::DocumentHistory, @@ -78,7 +78,7 @@ use crate::{ kind::PanelKind, }, window_tab::{CommonData, Focus}, - workspace::LapceWorkspace, + workspace::UmideWorkspace, }; #[derive(Clone, Debug)] @@ -142,7 +142,7 @@ impl DocContent { #[derive(Clone, Debug, Serialize, Deserialize)] pub struct DocInfo { - pub workspace: LapceWorkspace, + pub workspace: UmideWorkspace, pub path: PathBuf, pub scroll_offset: (f64, f64), pub cursor_offset: usize, @@ -418,7 +418,7 @@ impl Doc { } /// Set the syntax highlighting this document should use. - pub fn set_language(&self, language: LapceLanguage) { + pub fn set_language(&self, language: UmideLanguage) { self.syntax.set(Syntax::from_language(language)); } @@ -491,7 +491,7 @@ impl Doc { &self, cursor: &mut Cursor, s: &str, - config: &LapceConfig, + config: &UmideConfig, ) -> Vec<(Rope, RopeDelta, InvalLines)> { if self.content.with_untracked(|c| c.read_only()) { return Vec::new(); @@ -1584,7 +1584,7 @@ impl Document for Doc { }; let cmd = CommandKind::from(cmd.clone()); - let cmd = LapceCommand { + let cmd = UmideCommand { kind: cmd, data: None, }; @@ -1691,10 +1691,10 @@ impl DocumentPhantom for Doc { col, text, affinity, - fg: Some(config.color(LapceColor::INLAY_HINT_FOREGROUND)), + fg: Some(config.color(UmideColor::INLAY_HINT_FOREGROUND)), // font_family: Some(config.editor.inlay_hint_font_family()), font_size: Some(config.editor.inlay_hint_font_size()), - bg: Some(config.color(LapceColor::INLAY_HINT_BACKGROUND)), + bg: Some(config.color(UmideColor::INLAY_HINT_BACKGROUND)), under_line: None, } }); @@ -1730,14 +1730,14 @@ impl DocumentPhantom for Doc { let theme_prop = if severity == DiagnosticSeverity::ERROR { - LapceColor::ERROR_LENS_ERROR_FOREGROUND + UmideColor::ERROR_LENS_ERROR_FOREGROUND } else if severity == DiagnosticSeverity::WARNING { - LapceColor::ERROR_LENS_WARNING_FOREGROUND + UmideColor::ERROR_LENS_WARNING_FOREGROUND } else { // information + hint (if we keep that) + things without a severity - LapceColor::ERROR_LENS_OTHER_FOREGROUND + UmideColor::ERROR_LENS_OTHER_FOREGROUND }; config.color(theme_prop) @@ -1790,7 +1790,7 @@ impl DocumentPhantom for Doc { kind: PhantomTextKind::Completion, col: completion_col, text: completion.clone(), - fg: Some(config.color(LapceColor::COMPLETION_LENS_FOREGROUND)), + fg: Some(config.color(UmideColor::COMPLETION_LENS_FOREGROUND)), font_size: Some(config.editor.completion_lens_font_size()), affinity: Some(CursorAffinity::Backward), // font_family: Some(config.editor.completion_lens_font_family()), @@ -1818,7 +1818,7 @@ impl DocumentPhantom for Doc { col: inline_completion_col, text: completion.clone(), affinity: Some(CursorAffinity::Backward), - fg: Some(config.color(LapceColor::COMPLETION_LENS_FOREGROUND)), + fg: Some(config.color(UmideColor::COMPLETION_LENS_FOREGROUND)), font_size: Some(config.editor.completion_lens_font_size()), // font_family: Some(config.editor.completion_lens_font_family()), bg: None, @@ -1830,7 +1830,7 @@ impl DocumentPhantom for Doc { } if let Some(preedit) = self - .preedit_phantom(Some(config.color(LapceColor::EDITOR_FOREGROUND)), line) + .preedit_phantom(Some(config.color(UmideColor::EDITOR_FOREGROUND)), line) { text.push(preedit) } @@ -1893,7 +1893,7 @@ impl CommonAction for Doc { #[derive(Clone)] pub struct DocStyling { - config: ReadSignal>, + config: ReadSignal>, doc: Rc, } impl DocStyling { @@ -2075,9 +2075,9 @@ impl Styling for DocStyling { let color_name = match diag.severity { Some(DiagnosticSeverity::ERROR) => { - LapceColor::LAPCE_ERROR + UmideColor::LAPCE_ERROR } - _ => LapceColor::LAPCE_WARN, + _ => UmideColor::LAPCE_WARN, }; let color = config.color(color_name); let styles = extra_styles_for_range( @@ -2096,11 +2096,11 @@ impl Styling for DocStyling { // Add the styling for the diagnostic severity, if applicable if let Some(max_severity) = max_severity { let theme_prop = if max_severity == DiagnosticSeverity::ERROR { - LapceColor::ERROR_LENS_ERROR_BACKGROUND + UmideColor::ERROR_LENS_ERROR_BACKGROUND } else if max_severity == DiagnosticSeverity::WARNING { - LapceColor::ERROR_LENS_WARNING_BACKGROUND + UmideColor::ERROR_LENS_WARNING_BACKGROUND } else { - LapceColor::ERROR_LENS_OTHER_BACKGROUND + UmideColor::ERROR_LENS_OTHER_BACKGROUND }; let size = layout.size(); diff --git a/crates/umide/src/editor.rs b/crates/umide/src/editor.rs index 1aa548d7..1fe46e42 100644 --- a/crates/umide/src/editor.rs +++ b/crates/umide/src/editor.rs @@ -9,7 +9,7 @@ use std::{ use umide_core::cursor::CursorAffinity; use floem::{ - ViewId, action::{TimerToken, exec_after, show_context_menu}, ext_event::create_ext_action, kurbo::{Affine, Point, Rect, Vec2}, menu::Menu, prelude::{ + ViewId, action::{TimerToken, exec_after, show_context_menu}, ext_event::create_ext_action, kurbo::{Point, Rect, Vec2}, menu::Menu, prelude::{ Modifiers, PointerButtonEvent, PointerEvent, SignalTrack, }, reactive::{ Context, Effect, ReadSignal, RwSignal, Scope, SignalGet, SignalUpdate, SignalWith @@ -36,7 +36,7 @@ use umide_core::{ EditCommand, FocusCommand, MotionModeCommand, MultiSelectionCommand, ScrollCommand, }, - cursor::{ColPosition, Cursor, CursorMode}, + cursor::{Cursor, CursorMode}, editor::EditType, mode::{Mode, MotionMode}, rope_text_pos::RopeTextPosition, @@ -58,10 +58,10 @@ use self::{ location::{EditorLocation, EditorPosition}, }; use crate::{ - command::{CommandKind, InternalCommand, LapceCommand, LapceWorkbenchCommand}, + command::{CommandKind, InternalCommand, UmideCommand, UmideWorkbenchCommand}, completion::CompletionStatus, - config::LapceConfig, - db::LapceDb, + config::UmideConfig, + db::UmideDb, doc::{Doc, DocContent}, editor_tab::EditorTabChild, id::{DiffEditorId, EditorTabId}, @@ -508,7 +508,7 @@ impl EditorData { let doc = self.doc(); let config = self.common.config.get_untracked(); - // This is currently special-cased in Lapce because floem editor does not have 'find' + // This is currently special-cased in Umide because floem editor does not have 'find' match cmd { MultiSelectionCommand::SelectAllCurrent => { if let CursorMode::Insert(mut selection) = cursor.mode.clone() { @@ -2157,7 +2157,7 @@ impl EditorData { } else if let Some(edits) = edits.as_ref() { self.do_text_edit(edits); } else { - let db: Arc = Context::get().unwrap(); + let db: Arc = Context::get().unwrap(); if let Ok(info) = db.get_doc_info(&self.common.workspace, &location.path) { self.go_to_position( @@ -2507,7 +2507,7 @@ impl EditorData { let cursor_offset = self.cursor().with_untracked(|c| c.offset()); let scroll_offset = self.viewport().with_untracked(|v| v.origin().to_vec2()); - let db: Arc = Context::get().unwrap(); + let db: Arc = Context::get().unwrap(); db.save_doc_position( &self.common.workspace, path, @@ -2706,7 +2706,7 @@ impl EditorData { match rs { FindHintRs::NoMatchBreak | FindHintRs::NoMatchContinue { .. } => { - self.common.lapce_command.send(LapceCommand { + self.common.lapce_command.send(UmideCommand { kind: CommandKind::Focus( FocusCommand::GotoDefinition, ), @@ -2908,24 +2908,24 @@ impl EditorData { { vec![ Some(CommandKind::Workbench( - LapceWorkbenchCommand::RevealInPanel, + UmideWorkbenchCommand::RevealInPanel, )), Some(CommandKind::Workbench( - LapceWorkbenchCommand::RevealInFileExplorer, + UmideWorkbenchCommand::RevealInFileExplorer, )), Some(CommandKind::Workbench( - LapceWorkbenchCommand::SourceControlOpenActiveFileRemoteUrl, + UmideWorkbenchCommand::SourceControlOpenActiveFileRemoteUrl, )), None, Some(CommandKind::Edit(EditCommand::ClipboardCut)), Some(CommandKind::Edit(EditCommand::ClipboardCopy)), Some(CommandKind::Edit(EditCommand::ClipboardPaste)), Some(CommandKind::Workbench( - LapceWorkbenchCommand::AddRunDebugConfig, + UmideWorkbenchCommand::AddRunDebugConfig, )), None, Some(CommandKind::Workbench( - LapceWorkbenchCommand::PaletteCommand, + UmideWorkbenchCommand::PaletteCommand, )), ] } else { @@ -2933,27 +2933,27 @@ impl EditorData { Some(CommandKind::Focus(FocusCommand::GotoDefinition)), Some(CommandKind::Focus(FocusCommand::GotoTypeDefinition)), Some(CommandKind::Workbench( - LapceWorkbenchCommand::ShowCallHierarchy, + UmideWorkbenchCommand::ShowCallHierarchy, )), Some(CommandKind::Workbench( - LapceWorkbenchCommand::FindReferences, + UmideWorkbenchCommand::FindReferences, )), Some(CommandKind::Workbench( - LapceWorkbenchCommand::GoToImplementation, + UmideWorkbenchCommand::GoToImplementation, )), Some(CommandKind::Focus(FocusCommand::Rename)), Some(CommandKind::Workbench( - LapceWorkbenchCommand::RunInTerminal, + UmideWorkbenchCommand::RunInTerminal, )), None, Some(CommandKind::Workbench( - LapceWorkbenchCommand::RevealInPanel, + UmideWorkbenchCommand::RevealInPanel, )), Some(CommandKind::Workbench( - LapceWorkbenchCommand::RevealInFileExplorer, + UmideWorkbenchCommand::RevealInFileExplorer, )), Some(CommandKind::Workbench( - LapceWorkbenchCommand::SourceControlOpenActiveFileRemoteUrl, + UmideWorkbenchCommand::SourceControlOpenActiveFileRemoteUrl, )), None, Some(CommandKind::Edit(EditCommand::ClipboardCut)), @@ -2961,7 +2961,7 @@ impl EditorData { Some(CommandKind::Edit(EditCommand::ClipboardPaste)), None, Some(CommandKind::Workbench( - LapceWorkbenchCommand::PaletteCommand, + UmideWorkbenchCommand::PaletteCommand, )), ] } @@ -2972,13 +2972,13 @@ impl EditorData { Some(CommandKind::Edit(EditCommand::ClipboardPaste)), None, Some(CommandKind::Workbench( - LapceWorkbenchCommand::PaletteCommand, + UmideWorkbenchCommand::PaletteCommand, )), ] }; if self.diff_editor_id.get_untracked().is_some() && is_file { cmds.push(Some(CommandKind::Workbench( - LapceWorkbenchCommand::GoToLocation, + UmideWorkbenchCommand::GoToLocation, ))); } let lapce_command = self.common.lapce_command; @@ -2987,7 +2987,7 @@ impl EditorData { menu = menu.item( cmd.desc().unwrap_or_else(|| cmd.str()), |i| i.action( move || { - lapce_command.send(LapceCommand { + lapce_command.send(UmideCommand { kind: cmd.clone(), data: None, }) @@ -3289,7 +3289,7 @@ impl KeyPressFocus for EditorData { #[instrument] fn run_command( &self, - command: &crate::command::LapceCommand, + command: &crate::command::UmideCommand, count: Option, mods: Modifiers, ) -> CommandExecuted { @@ -3520,7 +3520,7 @@ fn show_inline_completion(cmd: &EditCommand) -> bool { // TODO(minor): Should we just put this on view, since it only requires those values? pub(crate) fn compute_screen_lines( - config: ReadSignal>, + config: ReadSignal>, base: RwSignal, view_kind: ReadSignal, doc: &Doc, @@ -3850,7 +3850,7 @@ pub(crate) fn compute_screen_lines( fn parse_hover_resp( hover: lsp_types::Hover, - config: &LapceConfig, + config: &UmideConfig, ) -> Vec { match hover.contents { HoverContents::Scalar(text) => match text { diff --git a/crates/umide/src/editor/diff.rs b/crates/umide/src/editor/diff.rs index eeeb21b6..9a2ca4e9 100644 --- a/crates/umide/src/editor/diff.rs +++ b/crates/umide/src/editor/diff.rs @@ -20,7 +20,7 @@ use serde::{Deserialize, Serialize}; use super::{EditorData, EditorViewKind}; use crate::{ - config::{color::LapceColor, icon::LapceIcons}, + config::{color::UmideColor, icon::UmideIcons}, doc::{Doc, DocContent}, id::{DiffEditorId, EditorTabId}, main_split::{Editors, MainSplitData}, @@ -363,16 +363,16 @@ pub fn diff_show_more_section_view( wave_box().style(move |s| { s.absolute() .size_pct(100.0, 100.0) - .color(config.get().color(LapceColor::PANEL_BACKGROUND)) + .color(config.get().color(UmideColor::PANEL_BACKGROUND)) }), Label::new(format!("{} Hidden Lines", section.lines)), Label::new("|".to_string()).style(|s| s.margin_left(10.0)), Stack::new(( - svg(move || config.get().ui_svg(LapceIcons::FOLD)).style(move |s| { + svg(move || config.get().ui_svg(UmideIcons::FOLD)).style(move |s| { let config = config.get(); let size = config.ui.icon_size() as f32; s.size(size, size) - .color(config.color(LapceColor::EDITOR_FOREGROUND)) + .color(config.color(UmideColor::EDITOR_FOREGROUND)) }), Label::new("Expand All".to_string()).style(|s| s.margin_left(6.0)), )) @@ -407,12 +407,12 @@ pub fn diff_show_more_section_view( }), Label::new("|".to_string()).style(|s| s.margin_left(10.0)), Stack::new(( - svg(move || config.get().ui_svg(LapceIcons::FOLD_UP)).style( + svg(move || config.get().ui_svg(UmideIcons::FOLD_UP)).style( move |s| { let config = config.get(); let size = config.ui.icon_size() as f32; s.size(size, size) - .color(config.color(LapceColor::EDITOR_FOREGROUND)) + .color(config.color(UmideColor::EDITOR_FOREGROUND)) }, ), Label::new("Expand Up".to_string()).style(|s| s.margin_left(6.0)), @@ -448,12 +448,12 @@ pub fn diff_show_more_section_view( }), Label::new("|".to_string()).style(|s| s.margin_left(10.0)), Stack::new(( - svg(move || config.get().ui_svg(LapceIcons::FOLD_DOWN)).style( + svg(move || config.get().ui_svg(UmideIcons::FOLD_DOWN)).style( move |s| { let config = config.get(); let size = config.ui.icon_size() as f32; s.size(size, size) - .color(config.color(LapceColor::EDITOR_FOREGROUND)) + .color(config.color(UmideColor::EDITOR_FOREGROUND)) }, ), Label::new("Expand Down".to_string()).style(|s| s.margin_left(6.0)), diff --git a/crates/umide/src/editor/gutter.rs b/crates/umide/src/editor/gutter.rs index 646c142d..44534c25 100644 --- a/crates/umide/src/editor/gutter.rs +++ b/crates/umide/src/editor/gutter.rs @@ -10,7 +10,7 @@ use umide_core::{buffer::rope_text::RopeText, mode::Mode}; use serde::{Deserialize, Serialize}; use super::{EditorData, view::changes_colors_screen}; -use crate::config::{LapceConfig, color::LapceColor}; +use crate::config::{UmideConfig, color::UmideColor}; pub struct EditorGutterView { id: ViewId, @@ -40,7 +40,7 @@ impl EditorGutterView { e_data: &EditorData, viewport: Rect, is_normal: bool, - config: &LapceConfig, + config: &UmideConfig, ) { if !is_normal { return; @@ -76,7 +76,7 @@ impl EditorGutterView { &self, cx: &mut PaintCx, is_normal: bool, - config: &LapceConfig, + config: &UmideConfig, ) { if !is_normal { return; @@ -97,12 +97,12 @@ impl EditorGutterView { .inflate(25.0, 0.0); cx.fill( &sticky_area_rect, - config.color(LapceColor::LAPCE_DROPDOWN_SHADOW), + config.color(UmideColor::LAPCE_DROPDOWN_SHADOW), 3.0, ); cx.fill( &sticky_area_rect, - config.color(LapceColor::EDITOR_STICKY_HEADER_BACKGROUND), + config.color(UmideColor::EDITOR_STICKY_HEADER_BACKGROUND), 0.0, ); } @@ -149,13 +149,13 @@ impl View for EditorGutterView { FamilyOwned::parse_list(&config.editor.font_family).collect(); let attrs = Attrs::new() .family(&family) - .color(config.color(LapceColor::EDITOR_DIM)) + .color(config.color(UmideColor::EDITOR_DIM)) .font_size(config.editor.font_size() as f32); let attrs_list = AttrsList::new(attrs.clone()); let current_line_attrs_list = AttrsList::new( attrs .clone() - .color(config.color(LapceColor::EDITOR_FOREGROUND)), + .color(config.color(UmideColor::EDITOR_FOREGROUND)), ); let show_relative = config.core.modal && config.editor.modal_mode_relative_line_numbers diff --git a/crates/umide/src/editor/view.rs b/crates/umide/src/editor/view.rs index 528f0558..6b5cb2d4 100644 --- a/crates/umide/src/editor/view.rs +++ b/crates/umide/src/editor/view.rs @@ -54,13 +54,13 @@ use super::{DocSignal, EditorData, gutter::editor_gutter_view}; use crate::{ app::clickable_icon, command::InternalCommand, - config::{LapceConfig, color::LapceColor, editor::WrapStyle, icon::LapceIcons}, - debug::{DapData, LapceBreakpoint}, + config::{UmideConfig, color::UmideColor, editor::WrapStyle, icon::UmideIcons}, + debug::{DapData, UmideBreakpoint}, doc::DocContent, editor::gutter::FoldingDisplayItem, text_input::TextInputBuilder, window_tab::{CommonData, Focus, WindowTabData}, - workspace::LapceWorkspace, + workspace::UmideWorkspace, }; #[derive(Clone, Debug, Default)] @@ -70,7 +70,7 @@ pub struct StickyHeaderInfo { pub y_diff: f64, } -fn editor_wrap(config: &LapceConfig) -> WrapMethod { +fn editor_wrap(config: &UmideConfig) -> WrapMethod { /// Minimum width that we'll allow the view to be wrapped at. const MIN_WRAPPED_WIDTH: f32 = 100.0; @@ -84,7 +84,7 @@ fn editor_wrap(config: &LapceConfig) -> WrapMethod { } pub fn editor_style( - config: ReadSignal>, + config: ReadSignal>, doc: DocSignal, s: Style, ) -> Style { @@ -95,28 +95,28 @@ pub fn editor_style( IndentStyleProp, doc.buffer.with_untracked(Buffer::indent_style), ) - .set(CursorColor, config.color(LapceColor::EDITOR_CARET)) - .set(SelectionColor, config.color(LapceColor::EDITOR_SELECTION)) + .set(CursorColor, config.color(UmideColor::EDITOR_CARET)) + .set(SelectionColor, config.color(UmideColor::EDITOR_SELECTION)) .set( CurrentLineColor, - config.color(LapceColor::EDITOR_CURRENT_LINE), + config.color(UmideColor::EDITOR_CURRENT_LINE), ) .set( VisibleWhitespaceColor, - config.color(LapceColor::EDITOR_VISIBLE_WHITESPACE), + config.color(UmideColor::EDITOR_VISIBLE_WHITESPACE), ) .set( IndentGuideColor, - config.color(LapceColor::EDITOR_INDENT_GUIDE), + config.color(UmideColor::EDITOR_INDENT_GUIDE), ) .set(ScrollBeyondLastLine, config.editor.scroll_beyond_last_line) - .color(config.color(LapceColor::EDITOR_FOREGROUND)) - .set(TextColor, config.color(LapceColor::EDITOR_FOREGROUND)) - .set(PhantomColor, config.color(LapceColor::EDITOR_DIM)) - .set(PlaceholderColor, config.color(LapceColor::EDITOR_DIM)) + .color(config.color(UmideColor::EDITOR_FOREGROUND)) + .set(TextColor, config.color(UmideColor::EDITOR_FOREGROUND)) + .set(PhantomColor, config.color(UmideColor::EDITOR_DIM)) + .set(PlaceholderColor, config.color(UmideColor::EDITOR_DIM)) .set( PreeditUnderlineColor, - config.color(LapceColor::EDITOR_FOREGROUND), + config.color(UmideColor::EDITOR_FOREGROUND), ) .set(ShowIndentGuide, config.editor.show_indent_guide) .set(Modal, config.core.modal) @@ -295,7 +295,7 @@ impl EditorView { cx: &mut PaintCx, viewport: Rect, screen_lines: &ScreenLines, - config: &LapceConfig, + config: &UmideConfig, ) { let Some(diff_sections) = &screen_lines.diff_sections else { return; @@ -322,7 +322,7 @@ impl EditorView { (section.y_idx * config.editor.line_height()) as f64, )), config - .color(LapceColor::SOURCE_CONTROL_ADDED) + .color(UmideColor::SOURCE_CONTROL_ADDED) .multiply_alpha(0.2), 0.0, ); @@ -340,7 +340,7 @@ impl EditorView { (section.y_idx * config.editor.line_height()) as f64, )), config - .color(LapceColor::SOURCE_CONTROL_REMOVED) + .color(UmideColor::SOURCE_CONTROL_REMOVED) .multiply_alpha(0.2), 0.0, ); @@ -355,7 +355,7 @@ impl EditorView { viewport: Rect, start_line: usize, height: usize, - config: &LapceConfig, + config: &UmideConfig, ) { let line_height = config.editor.line_height(); let height = (height * line_height) as f64; @@ -391,7 +391,7 @@ impl EditorView { let p1 = Point::new(x as f64 - height, y + height); cx.stroke( &Line::new(p0, p1), - config.color(LapceColor::EDITOR_DIM), + config.color(UmideColor::EDITOR_DIM), &Stroke::new(1.0), ); } @@ -439,7 +439,7 @@ impl EditorView { cx.fill( &rect, - config.color(LapceColor::EDITOR_DEBUG_BREAK_LINE), + config.color(UmideColor::EDITOR_DEBUG_BREAK_LINE), 0.0, ); } @@ -498,7 +498,7 @@ impl EditorView { let config = config.get_untracked(); let line_height = config.editor.line_height() as f64; - let color = config.color(LapceColor::EDITOR_FOREGROUND); + let color = config.color(UmideColor::EDITOR_FOREGROUND); let start = ed.offset_of_line(min_line); let end = ed.offset_of_line(max_line + 1); @@ -669,12 +669,12 @@ impl EditorView { cx.fill( &sticky_area_rect, - config.color(LapceColor::LAPCE_DROPDOWN_SHADOW), + config.color(UmideColor::LAPCE_DROPDOWN_SHADOW), 3.0, ); cx.fill( &sticky_area_rect, - config.color(LapceColor::EDITOR_STICKY_HEADER_BACKGROUND), + config.color(UmideColor::EDITOR_STICKY_HEADER_BACKGROUND), 0.0, ); self.editor.sticky_header_info.get_untracked(); @@ -715,7 +715,7 @@ impl EditorView { cx: &mut PaintCx, viewport: Rect, is_local: bool, - config: Arc, + config: Arc, ) { const BAR_WIDTH: f64 = 10.0; @@ -731,7 +731,7 @@ impl EditorView { viewport.y0, )) .inflate(0.0, 10.0), - config.color(LapceColor::LAPCE_SCROLL_BAR), + config.color(UmideColor::LAPCE_SCROLL_BAR), 0.0, ); @@ -805,7 +805,7 @@ impl EditorView { cx.stroke( &rect, - config.color(LapceColor::EDITOR_FOREGROUND), + config.color(UmideColor::EDITOR_FOREGROUND), &Stroke::new(1.0), ); } @@ -826,7 +826,7 @@ impl EditorView { let doc = self.editor.doc(); let config = self.editor.common.config.get_untracked(); let line_height = config.editor.line_height() as f64; - let brush = config.color(LapceColor::EDITOR_FOREGROUND); + let brush = config.color(UmideColor::EDITOR_FOREGROUND); if start == end { if let Some(line_info) = screen_lines.info(start) { @@ -1162,7 +1162,7 @@ fn get_sticky_header_info( editor_data: &EditorData, viewport: RwSignal, sticky_header_height_signal: RwSignal, - config: &LapceConfig, + config: &UmideConfig, ) -> StickyHeaderInfo { let editor = &editor_data.editor; let doc = editor_data.doc(); @@ -1273,7 +1273,7 @@ fn get_sticky_header_info( pub fn editor_container_view( window_tab_data: Rc, - workspace: Arc, + workspace: Arc, is_active: impl Fn(bool) -> bool + 'static + Copy, editor: RwSignal, ) -> impl View { @@ -1321,7 +1321,7 @@ pub fn editor_container_view( // .box_shadow_blur(5.0) // .border_bottom(1.0) // .border_color( - // config.get_color(LapceColor::LAPCE_BORDER), + // config.get_color(UmideColor::LAPCE_BORDER), // ) .apply_if( !config.editor.sticky_header @@ -1376,7 +1376,7 @@ fn editor_gutter_breakpoint_view( i: usize, doc: DocSignal, daps: RwSignal>, - breakpoints: RwSignal>>, + breakpoints: RwSignal>>, screen_lines: RwSignal, common: Rc, icon_padding: f32, @@ -1384,12 +1384,12 @@ fn editor_gutter_breakpoint_view( let hovered = RwSignal::new(false); let config = common.config; Container::new( - svg(move || config.get().ui_svg(LapceIcons::DEBUG_BREAKPOINT)).style( + svg(move || config.get().ui_svg(UmideIcons::DEBUG_BREAKPOINT)).style( move |s| { let config = config.get(); let size = config.ui.icon_size() as f32 + 2.0; s.size(size, size) - .color(config.color(LapceColor::DEBUG_BREAKPOINT_HOVER)) + .color(config.color(UmideColor::DEBUG_BREAKPOINT_HOVER)) .apply_if(!hovered.get(), |s| s.hide()) }, ), @@ -1410,7 +1410,7 @@ fn editor_gutter_breakpoint_view( if let std::collections::btree_map::Entry::Vacant(e) = breakpoints.entry(line) { - e.insert(LapceBreakpoint { + e.insert(UmideBreakpoint { id: None, verified: false, message: None, @@ -1545,15 +1545,15 @@ fn editor_gutter_breakpoints( let active = breakpoint.active; Container::new( svg(move || { - config.get().ui_svg(LapceIcons::DEBUG_BREAKPOINT) + config.get().ui_svg(UmideIcons::DEBUG_BREAKPOINT) }) .style(move |s| { let config = config.get(); let size = config.ui.icon_size() as f32 + 2.0; let color = if active { - LapceColor::DEBUG_BREAKPOINT + UmideColor::DEBUG_BREAKPOINT } else { - LapceColor::EDITOR_DIM + UmideColor::EDITOR_DIM }; let color = config.color(color); s.size(size, size).color(color) @@ -1581,7 +1581,7 @@ fn editor_gutter_breakpoints( .style(move |s| { s.absolute() .size_pct(100.0, 100.0) - .background(config.get().color(LapceColor::EDITOR_BACKGROUND)) + .background(config.get().color(UmideColor::EDITOR_BACKGROUND)) }) } @@ -1595,11 +1595,11 @@ fn editor_gutter_code_lens_view( ) -> impl View { let config = window_tab_data.common.config; let view = Container::new( - svg(move || config.get().ui_svg(LapceIcons::START)).style(move |s| { + svg(move || config.get().ui_svg(UmideIcons::START)).style(move |s| { let config = config.get(); let size = config.ui.icon_size() as f32; s.size(size, size) - .color(config.color(LapceColor::LAPCE_ICON_ACTIVE)) + .color(config.color(UmideColor::LAPCE_ICON_ACTIVE)) }), ) .style(move |s| { @@ -1608,11 +1608,11 @@ fn editor_gutter_code_lens_view( .border_radius(6.0) .hover(|s| { s.cursor(CursorStyle::Pointer) - .background(config.color(LapceColor::PANEL_HOVERED_BACKGROUND)) + .background(config.color(UmideColor::PANEL_HOVERED_BACKGROUND)) }) .active(|s| { s.background( - config.color(LapceColor::PANEL_HOVERED_ACTIVE_BACKGROUND), + config.color(UmideColor::PANEL_HOVERED_ACTIVE_BACKGROUND), ) }) }) @@ -1648,9 +1648,9 @@ fn editor_gutter_folding_view( let view = Container::new( svg(move || { let icon_str = match folding_display_item { - FoldingDisplayItem::UnfoldStart(_) => LapceIcons::FOLD_DOWN, - FoldingDisplayItem::Folded(_) => LapceIcons::FOLD, - FoldingDisplayItem::UnfoldEnd(_) => LapceIcons::FOLD_UP, + FoldingDisplayItem::UnfoldStart(_) => UmideIcons::FOLD_DOWN, + FoldingDisplayItem::Folded(_) => UmideIcons::FOLD, + FoldingDisplayItem::UnfoldEnd(_) => UmideIcons::FOLD_UP, }; config.get().ui_svg(icon_str) }) @@ -1658,7 +1658,7 @@ fn editor_gutter_folding_view( let config = config.get(); let size = config.ui.icon_size() as f32; s.size(size, size) - .color(config.color(LapceColor::LAPCE_ICON_ACTIVE)) + .color(config.color(UmideColor::LAPCE_ICON_ACTIVE)) }), ) .style(move |s| { @@ -1667,11 +1667,11 @@ fn editor_gutter_folding_view( .border_radius(6.0) .hover(|s| { s.cursor(CursorStyle::Pointer) - .background(config.color(LapceColor::PANEL_HOVERED_BACKGROUND)) + .background(config.color(UmideColor::PANEL_HOVERED_BACKGROUND)) }) .active(|s| { s.background( - config.color(LapceColor::PANEL_HOVERED_ACTIVE_BACKGROUND), + config.color(UmideColor::PANEL_HOVERED_ACTIVE_BACKGROUND), ) }) }); @@ -1816,12 +1816,12 @@ fn editor_gutter_code_actions( Container::new( Container::new( - svg(move || config.get().ui_svg(LapceIcons::LIGHTBULB)).style( + svg(move || config.get().ui_svg(UmideIcons::LIGHTBULB)).style( move |s| { let config = config.get(); let size = config.ui.icon_size() as f32; s.size(size, size) - .color(config.color(LapceColor::LAPCE_WARN)) + .color(config.color(UmideColor::LAPCE_WARN)) }, ), ) @@ -1834,12 +1834,12 @@ fn editor_gutter_code_actions( .border_radius(6.0) .hover(|s| { s.cursor(CursorStyle::Pointer).background( - config.color(LapceColor::PANEL_HOVERED_BACKGROUND), + config.color(UmideColor::PANEL_HOVERED_BACKGROUND), ) }) .active(|s| { s.background( - config.color(LapceColor::PANEL_HOVERED_ACTIVE_BACKGROUND), + config.color(UmideColor::PANEL_HOVERED_ACTIVE_BACKGROUND), ) }) }), @@ -1933,9 +1933,9 @@ fn editor_gutter( } fn editor_breadcrumbs( - workspace: Arc, + workspace: Arc, e_data: EditorData, - config: ReadSignal>, + config: ReadSignal>, ) -> impl View { let doc = e_data.doc_signal(); let doc_path = Memo::new(move |_| { @@ -1983,7 +1983,7 @@ fn editor_breadcrumbs( svg(move || { config .get() - .ui_svg(LapceIcons::BREADCRUMB_SEPARATOR) + .ui_svg(UmideIcons::BREADCRUMB_SEPARATOR) }) .style(move |s| { let config = config.get(); @@ -1992,7 +1992,7 @@ fn editor_breadcrumbs( .size(size, size) .color( config.color( - LapceColor::LAPCE_ICON_ACTIVE, + UmideColor::LAPCE_ICON_ACTIVE, ), ) }), @@ -2032,7 +2032,7 @@ fn editor_breadcrumbs( s.absolute() .size_pct(100.0, 100.0) .border_bottom(1.0) - .border_color(config.get().color(LapceColor::LAPCE_BORDER)) + .border_color(config.get().color(UmideColor::LAPCE_BORDER)) .items_center() }), ) @@ -2224,7 +2224,7 @@ fn search_editor_view( }) .style(|s| s.width_pct(100.0)), clickable_icon( - || LapceIcons::SEARCH_CASE_SENSITIVE, + || UmideIcons::SEARCH_CASE_SENSITIVE, move || { let new = match case_matching.get_untracked() { CaseMatching::Exact => CaseMatching::CaseInsensitive, @@ -2239,7 +2239,7 @@ fn search_editor_view( ) .style(|s| s.padding_vert(4.0)), clickable_icon( - || LapceIcons::SEARCH_WHOLE_WORD, + || UmideIcons::SEARCH_WHOLE_WORD, move || { whole_word.update(|whole_word| { *whole_word = !*whole_word; @@ -2252,7 +2252,7 @@ fn search_editor_view( ) .style(|s| s.padding_left(6.0)), clickable_icon( - || LapceIcons::SEARCH_REGEX, + || UmideIcons::SEARCH_REGEX, move || { is_regex.update(|is_regex| { *is_regex = !*is_regex; @@ -2271,8 +2271,8 @@ fn search_editor_view( .items_center() .border(1.0) .border_radius(6.0) - .border_color(config.color(LapceColor::LAPCE_BORDER)) - .background(config.color(LapceColor::EDITOR_BACKGROUND)) + .border_color(config.color(UmideColor::LAPCE_BORDER)) + .background(config.color(UmideColor::EDITOR_BACKGROUND)) }) } @@ -2313,8 +2313,8 @@ fn replace_editor_view( .items_center() .border(1.0) .border_radius(6.0) - .border_color(config.color(LapceColor::LAPCE_BORDER)) - .background(config.color(LapceColor::EDITOR_BACKGROUND)) + .border_color(config.color(UmideColor::LAPCE_BORDER)) + .background(config.color(UmideColor::EDITOR_BACKGROUND)) }) } @@ -2358,9 +2358,9 @@ fn find_view( clickable_icon( move || { if replace_active.get() { - LapceIcons::ITEM_OPENED + UmideIcons::ITEM_OPENED } else { - LapceIcons::ITEM_CLOSED + UmideIcons::ITEM_CLOSED } }, move || { @@ -2388,7 +2388,7 @@ fn find_view( }) .style(|s| s.margin_left(6.0).min_width(70.0)), clickable_icon( - || LapceIcons::SEARCH_BACKWARD, + || UmideIcons::SEARCH_BACKWARD, move || { editor.get_untracked().search_backward(Modifiers::empty()); }, @@ -2399,7 +2399,7 @@ fn find_view( ) .style(|s| s.padding_left(6.0)), clickable_icon( - || LapceIcons::SEARCH_FORWARD, + || UmideIcons::SEARCH_FORWARD, move || { editor.get_untracked().search_forward(Modifiers::empty()); }, @@ -2410,7 +2410,7 @@ fn find_view( ) .style(|s| s.padding_left(6.0)), clickable_icon( - || LapceIcons::CLOSE, + || UmideIcons::CLOSE, move || { editor.get_untracked().clear_search(); }, @@ -2436,7 +2436,7 @@ fn find_view( find_focus, ), clickable_icon( - || LapceIcons::SEARCH_REPLACE, + || UmideIcons::SEARCH_REPLACE, move || { let text = replace_doc .get_untracked() @@ -2451,7 +2451,7 @@ fn find_view( ) .style(|s| s.padding_left(6.0)), clickable_icon( - || LapceIcons::SEARCH_REPLACE_ALL, + || UmideIcons::SEARCH_REPLACE_ALL, move || { let text = replace_doc .get_untracked() @@ -2475,10 +2475,10 @@ fn find_view( .style(move |s| { let config = config.get(); s.margin_right(50.0) - .background(config.color(LapceColor::PANEL_BACKGROUND)) + .background(config.color(UmideColor::PANEL_BACKGROUND)) .border_radius(6.0) .border(1.0) - .border_color(config.color(LapceColor::LAPCE_BORDER)) + .border_color(config.color(UmideColor::LAPCE_BORDER)) .padding_vert(4.0) .cursor(CursorStyle::Default) .flex_col() @@ -2518,7 +2518,7 @@ fn find_view( /// Iterator over (len, color, modified) for each change in the diff fn changes_color_iter<'a>( changes: &'a im::Vector, - config: &'a LapceConfig, + config: &'a UmideConfig, ) -> impl Iterator, bool)> + 'a { let mut last_change = None; changes.iter().map(move |change| { @@ -2530,16 +2530,16 @@ fn changes_color_iter<'a>( let mut modified = false; let color = match change { DiffLines::Left(_range) => { - Some(config.color(LapceColor::SOURCE_CONTROL_REMOVED)) + Some(config.color(UmideColor::SOURCE_CONTROL_REMOVED)) } DiffLines::Right(_range) => { if let Some(DiffLines::Left(_)) = last_change.as_ref() { modified = true; } if modified { - Some(config.color(LapceColor::SOURCE_CONTROL_MODIFIED)) + Some(config.color(UmideColor::SOURCE_CONTROL_MODIFIED)) } else { - Some(config.color(LapceColor::SOURCE_CONTROL_ADDED)) + Some(config.color(UmideColor::SOURCE_CONTROL_ADDED)) } } _ => None, @@ -2556,7 +2556,7 @@ fn changes_color_iter<'a>( /// Get the position and coloring information for over the entire current [`ScreenLines`] /// Returns `(y, height_idx, removed, color)` pub fn changes_colors_screen( - config: &LapceConfig, + config: &UmideConfig, editor: &Editor, changes: im::Vector, ) -> Vec<(f64, usize, bool, Color)> { @@ -2610,7 +2610,7 @@ pub fn changes_colors_screen( /// Get the position and coloring information for over the entire current [`ScreenLines`] /// Returns `(y, height_idx, removed, color)` pub fn changes_colors_all( - config: &LapceConfig, + config: &UmideConfig, ed: &Editor, changes: im::Vector, ) -> Vec<(f64, usize, bool, Color)> { diff --git a/crates/umide/src/editor_tab.rs b/crates/umide/src/editor_tab.rs index b83cbd17..433edaca 100644 --- a/crates/umide/src/editor_tab.rs +++ b/crates/umide/src/editor_tab.rs @@ -18,7 +18,7 @@ use umide_rpc::plugin::VoltID; use serde::{Deserialize, Serialize}; use crate::{ - config::{LapceConfig, color::LapceColor, icon::LapceIcons}, + config::{UmideConfig, color::UmideColor, icon::UmideIcons}, doc::{Doc, DocContent}, editor::{ EditorData, EditorInfo, @@ -202,7 +202,7 @@ impl EditorTabChild { editors: Editors, diff_editors: RwSignal>, plugin: PluginData, - config: ReadSignal>, + config: ReadSignal>, ) -> Memo { match self.clone() { EditorTabChild::Editor(editor_id) => Memo::new(move |_| { @@ -243,8 +243,8 @@ impl EditorTabChild { ) } None => ( - config.ui_svg(LapceIcons::FILE), - Some(config.color(LapceColor::LAPCE_ICON_ACTIVE)), + config.ui_svg(UmideIcons::FILE), + Some(config.color(UmideColor::LAPCE_ICON_ACTIVE)), "local".to_string(), RwSignal::new(true), true, @@ -325,8 +325,8 @@ impl EditorTabChild { ) } [None, None] => ( - config.ui_svg(LapceIcons::FILE), - Some(config.color(LapceColor::LAPCE_ICON_ACTIVE)), + config.ui_svg(UmideIcons::FILE), + Some(config.color(UmideColor::LAPCE_ICON_ACTIVE)), "local".to_string(), true, ), @@ -343,8 +343,8 @@ impl EditorTabChild { EditorTabChild::Settings(_) => Memo::new(move |_| { let config = config.get(); EditorTabChildViewInfo { - icon: config.ui_svg(LapceIcons::SETTINGS), - color: Some(config.color(LapceColor::LAPCE_ICON_ACTIVE)), + icon: config.ui_svg(UmideIcons::SETTINGS), + color: Some(config.color(UmideColor::LAPCE_ICON_ACTIVE)), name: "Settings".to_string(), path: None, confirmed: None, @@ -354,8 +354,8 @@ impl EditorTabChild { EditorTabChild::ThemeColorSettings(_) => Memo::new(move |_| { let config = config.get(); EditorTabChildViewInfo { - icon: config.ui_svg(LapceIcons::SYMBOL_COLOR), - color: Some(config.color(LapceColor::LAPCE_ICON_ACTIVE)), + icon: config.ui_svg(UmideIcons::SYMBOL_COLOR), + color: Some(config.color(UmideColor::LAPCE_ICON_ACTIVE)), name: "Theme Colors".to_string(), path: None, confirmed: None, @@ -365,8 +365,8 @@ impl EditorTabChild { EditorTabChild::Keymap(_) => Memo::new(move |_| { let config = config.get(); EditorTabChildViewInfo { - icon: config.ui_svg(LapceIcons::KEYBOARD), - color: Some(config.color(LapceColor::LAPCE_ICON_ACTIVE)), + icon: config.ui_svg(UmideIcons::KEYBOARD), + color: Some(config.color(UmideColor::LAPCE_ICON_ACTIVE)), name: "Keyboard Shortcuts".to_string(), path: None, confirmed: None, @@ -389,8 +389,8 @@ impl EditorTabChild { }) .unwrap_or_else(|| id.name.clone()); EditorTabChildViewInfo { - icon: config.ui_svg(LapceIcons::EXTENSIONS), - color: Some(config.color(LapceColor::LAPCE_ICON_ACTIVE)), + icon: config.ui_svg(UmideIcons::EXTENSIONS), + color: Some(config.color(UmideColor::LAPCE_ICON_ACTIVE)), name: display_name, path: None, confirmed: None, diff --git a/crates/umide/src/file_explorer/data.rs b/crates/umide/src/file_explorer/data.rs index 14c66e26..0872ebd6 100644 --- a/crates/umide/src/file_explorer/data.rs +++ b/crates/umide/src/file_explorer/data.rs @@ -25,8 +25,8 @@ use umide_rpc::{ }; use crate::{ - command::{CommandExecuted, CommandKind, InternalCommand, LapceCommand}, - config::LapceConfig, + command::{CommandExecuted, CommandKind, InternalCommand, UmideCommand}, + config::UmideConfig, editor::EditorData, keypress::{KeyPressFocus, condition::Condition}, main_split::Editors, @@ -65,7 +65,7 @@ impl KeyPressFocus for FileExplorerData { fn run_command( &self, - command: &LapceCommand, + command: &UmideCommand, count: Option, mods: Modifiers, ) -> CommandExecuted { @@ -386,7 +386,7 @@ impl FileExplorerData { self.naming.set(Naming::None); } - pub fn click(&self, path: &Path, config: ReadSignal>) { + pub fn click(&self, path: &Path, config: ReadSignal>) { if self.is_dir(path) { self.toggle_expand(path); } else if !config.get_untracked().core.file_explorer_double_click { @@ -454,7 +454,7 @@ impl FileExplorerData { pub fn double_click( &self, path: &Path, - config: ReadSignal>, + config: ReadSignal>, ) -> EventPropagation { if self.is_dir(path) { EventPropagation::Continue diff --git a/crates/umide/src/file_explorer/view.rs b/crates/umide/src/file_explorer/view.rs index 4b498116..e18c3e47 100644 --- a/crates/umide/src/file_explorer/view.rs +++ b/crates/umide/src/file_explorer/view.rs @@ -19,7 +19,7 @@ use super::{data::FileExplorerData, node::FileNodeVirtualList}; use crate::{ app::clickable_icon, command::InternalCommand, - config::{LapceConfig, color::LapceColor, icon::LapceIcons}, + config::{UmideConfig, color::UmideColor, icon::UmideIcons}, editor_tab::{EditorTabChild, EditorTabData}, panel::{ data::PanelSection, kind::PanelKind, position::PanelPosition, @@ -117,7 +117,7 @@ fn initialize_naming_editor( } fn file_node_text_color( - config: ReadSignal>, + config: ReadSignal>, node: FileNodeViewData, source_control: SourceControlData, ) -> Color { @@ -138,11 +138,11 @@ fn file_node_text_color( let color = match diff { Some(FileDiffKind::Modified | FileDiffKind::Renamed) => { - LapceColor::SOURCE_CONTROL_MODIFIED + UmideColor::SOURCE_CONTROL_MODIFIED } - Some(FileDiffKind::Added) => LapceColor::SOURCE_CONTROL_ADDED, - Some(FileDiffKind::Deleted) => LapceColor::SOURCE_CONTROL_REMOVED, - None => LapceColor::PANEL_FOREGROUND, + Some(FileDiffKind::Added) => UmideColor::SOURCE_CONTROL_ADDED, + Some(FileDiffKind::Deleted) => UmideColor::SOURCE_CONTROL_REMOVED, + None => UmideColor::PANEL_FOREGROUND, }; config.get().color(color) @@ -182,7 +182,7 @@ fn file_node_text_view( .color( config .get() - .color(LapceColor::PANEL_FOREGROUND_DIM), + .color(UmideColor::PANEL_FOREGROUND_DIM), ) .selectable(false) }, @@ -256,7 +256,7 @@ fn file_node_input_view(data: FileExplorerData, err: Option) -> Containe .margin(0.0) .border_radius(6.0) .border(1.0) - .border_color(config.get().color(LapceColor::LAPCE_BORDER)) + .border_color(config.get().color(UmideColor::LAPCE_BORDER)) }); let text_input_id = text_input_view.id(); @@ -270,9 +270,9 @@ fn file_node_input_view(data: FileExplorerData, err: Option) -> Containe let config = config.get(); let editor_background_color = - config.color(LapceColor::PANEL_CURRENT_BACKGROUND); + config.color(UmideColor::PANEL_CURRENT_BACKGROUND); let error_background_color = - config.color(LapceColor::ERROR_LENS_ERROR_BACKGROUND); + config.color(UmideColor::ERROR_LENS_ERROR_BACKGROUND); let background_color = blend_colors( editor_background_color, @@ -282,7 +282,7 @@ fn file_node_input_view(data: FileExplorerData, err: Option) -> Containe s.position(Position::Absolute) .inset_top(ui_line_height.get()) .width_full() - .color(config.color(LapceColor::ERROR_LENS_ERROR_FOREGROUND)) + .color(config.color(UmideColor::ERROR_LENS_ERROR_FOREGROUND)) .background(background_color) .z_index(100) }), @@ -327,8 +327,8 @@ fn file_explorer_view( svg(move || { let config = config.get(); let svg_str = match open { - true => LapceIcons::ITEM_OPENED, - false => LapceIcons::ITEM_CLOSED, + true => UmideIcons::ITEM_OPENED, + false => UmideIcons::ITEM_CLOSED, }; config.ui_svg(svg_str) }) @@ -337,7 +337,7 @@ fn file_explorer_view( let size = config.ui.icon_size() as f32; let color = if is_dir { - config.color(LapceColor::LAPCE_ICON_ACTIVE) + config.color(UmideColor::LAPCE_ICON_ACTIVE) } else { Color::TRANSPARENT }; @@ -354,14 +354,14 @@ fn file_explorer_view( let config = config.get(); if is_dir { let svg_str = match open { - true => LapceIcons::DIRECTORY_OPENED, - false => LapceIcons::DIRECTORY_CLOSED, + true => UmideIcons::DIRECTORY_OPENED, + false => UmideIcons::DIRECTORY_CLOSED, }; config.ui_svg(svg_str) } else if let Some(path) = kind.path() { config.file_svg(path).0 } else { - config.ui_svg(LapceIcons::FILE) + config.ui_svg(UmideIcons::FILE) } }) .style(move |s| { @@ -373,7 +373,7 @@ fn file_explorer_view( .margin_horiz(6.0) .apply_if(is_dir, |s| { s.color( - config.color(LapceColor::LAPCE_ICON_ACTIVE), + config.color(UmideColor::LAPCE_ICON_ACTIVE), ) }) .apply_if(!is_dir, |s| { @@ -399,7 +399,7 @@ fn file_explorer_view( s.background( config .get() - .color(LapceColor::PANEL_HOVERED_BACKGROUND), + .color(UmideColor::PANEL_HOVERED_BACKGROUND), ) .cursor(CursorStyle::Pointer) }) @@ -408,7 +408,7 @@ fn file_explorer_view( |x| { x.background( config.get().color( - LapceColor::PANEL_CURRENT_BACKGROUND, + UmideColor::PANEL_CURRENT_BACKGROUND, ), ) }, @@ -507,9 +507,9 @@ fn open_editors_view(window_tab_data: Rc) -> impl View { clickable_icon( move || { if hovered.get() || info.with(|info| info.is_pristine) { - LapceIcons::CLOSE + UmideIcons::CLOSE } else { - LapceIcons::UNSAVED + UmideIcons::UNSAVED } }, move || { @@ -562,12 +562,12 @@ fn open_editors_view(window_tab_data: Rc) -> impl View { == child_index.get(), |s| { s.background( - config.color(LapceColor::PANEL_CURRENT_BACKGROUND), + config.color(UmideColor::PANEL_CURRENT_BACKGROUND), ) }, ) .hover(|s| { - s.background(config.color(LapceColor::PANEL_HOVERED_BACKGROUND)) + s.background(config.color(UmideColor::PANEL_HOVERED_BACKGROUND)) }) }) .on_event_cont(EventListener::PointerDown, move |_| { diff --git a/crates/umide/src/global_search.rs b/crates/umide/src/global_search.rs index 69646f38..66806177 100644 --- a/crates/umide/src/global_search.rs +++ b/crates/umide/src/global_search.rs @@ -57,7 +57,7 @@ impl KeyPressFocus for GlobalSearchData { fn run_command( &self, - command: &crate::command::LapceCommand, + command: &crate::command::UmideCommand, count: Option, mods: Modifiers, ) -> CommandExecuted { diff --git a/crates/umide/src/inline_completion.rs b/crates/umide/src/inline_completion.rs index 65277e2f..2c0d5f98 100644 --- a/crates/umide/src/inline_completion.rs +++ b/crates/umide/src/inline_completion.rs @@ -9,7 +9,7 @@ use umide_core::{ }; use lsp_types::InsertTextFormat; -use crate::{config::LapceConfig, doc::Doc, editor::EditorData, snippet::Snippet}; +use crate::{config::UmideConfig, doc::Doc, editor::EditorData, snippet::Snippet}; // TODO: we could integrate completion lens with this, so it is considered at the same time @@ -189,7 +189,7 @@ impl InlineCompletionData { pub fn update_inline_completion( &self, - config: &LapceConfig, + config: &UmideConfig, doc: &Doc, cursor_offset: usize, ) { diff --git a/crates/umide/src/keymap.rs b/crates/umide/src/keymap.rs index 94267801..f364c48c 100644 --- a/crates/umide/src/keymap.rs +++ b/crates/umide/src/keymap.rs @@ -10,8 +10,8 @@ use floem::{ use umide_core::mode::Modes; use crate::{ - command::LapceCommand, - config::{LapceConfig, color::LapceColor}, + command::UmideCommand, + config::{UmideConfig, color::UmideColor}, keypress::{ KeyPressData, keymap::{KeyMap, KeyMapPress}, @@ -23,14 +23,14 @@ use crate::{ #[derive(Clone)] pub struct KeymapPicker { - cmd: RwSignal>, + cmd: RwSignal>, keymap: RwSignal>, keys: RwSignal>, } -struct KeymapList(im::Vector<(usize, (LapceCommand, Option))>); +struct KeymapList(im::Vector<(usize, (UmideCommand, Option))>); -impl VirtualVector<(usize, (LapceCommand, Option))> for KeymapList { +impl VirtualVector<(usize, (UmideCommand, Option))> for KeymapList { fn total_len(&self) -> usize { self.0.len() } @@ -38,7 +38,7 @@ impl VirtualVector<(usize, (LapceCommand, Option))> for KeymapList { fn slice( &mut self, range: Range, - ) -> impl Iterator))> { + ) -> impl Iterator))> { self.0 .iter() .skip(range.start) @@ -100,7 +100,7 @@ pub fn keymap_view(editors: Editors, common: Rc) -> impl View { None } }) - .collect::)>>(); + .collect::)>>(); items.extend(keypress.commands_without_keymap.iter().filter_map(|cmd| { let match_pattern = cmd.kind.str().replace('_', " ").contains(&pattern) || cmd @@ -116,12 +116,12 @@ pub fn keymap_view(editors: Editors, common: Rc) -> impl View { let items = items .into_iter() .enumerate() - .collect::))>>(); + .collect::))>>(); KeymapList(items) }; let view_fn = - move |(i, (cmd, keymap)): (usize, (LapceCommand, Option))| { + move |(i, (cmd, keymap)): (usize, (UmideCommand, Option))| { let local_keymap = keymap.clone(); let local_cmd = cmd.clone(); Stack::new(( @@ -147,7 +147,7 @@ pub fn keymap_view(editors: Editors, common: Rc) -> impl View { .flex_basis(0.0) .flex_grow(1.0) .border_right(1.0) - .border_color(config.get().color(LapceColor::LAPCE_BORDER)) + .border_color(config.get().color(UmideColor::LAPCE_BORDER)) }), { let keymap = keymap.clone(); @@ -174,7 +174,7 @@ pub fn keymap_view(editors: Editors, common: Rc) -> impl View { .border(1.0) .border_radius(3.0) .border_color( - config.get().color(LapceColor::LAPCE_BORDER), + config.get().color(UmideColor::LAPCE_BORDER), ) }) }, @@ -186,7 +186,7 @@ pub fn keymap_view(editors: Editors, common: Rc) -> impl View { .height_pct(100.0) .border_right(1.0) .border_color( - config.get().color(LapceColor::LAPCE_BORDER), + config.get().color(UmideColor::LAPCE_BORDER), ) }) }, @@ -223,7 +223,7 @@ pub fn keymap_view(editors: Editors, common: Rc) -> impl View { .border(1.0) .border_radius(3.0) .border_color( - config.get().color(LapceColor::LAPCE_BORDER), + config.get().color(UmideColor::LAPCE_BORDER), ) }) }, @@ -235,7 +235,7 @@ pub fn keymap_view(editors: Editors, common: Rc) -> impl View { .height_pct(100.0) .border_right(1.0) .border_color( - config.get().color(LapceColor::LAPCE_BORDER), + config.get().color(UmideColor::LAPCE_BORDER), ) .apply_if(!modal.get(), |s| s.hide()) }) @@ -286,10 +286,10 @@ pub fn keymap_view(editors: Editors, common: Rc) -> impl View { .height(ui_line_height() as f32) .width_pct(100.0) .apply_if(i % 2 > 0, |s| { - s.background(config.color(LapceColor::EDITOR_CURRENT_LINE)) + s.background(config.color(UmideColor::EDITOR_CURRENT_LINE)) }) .border_bottom(1.0) - .border_color(config.color(LapceColor::LAPCE_BORDER)) + .border_color(config.color(UmideColor::LAPCE_BORDER)) }) }; @@ -302,7 +302,7 @@ pub fn keymap_view(editors: Editors, common: Rc) -> impl View { s.width_pct(100.0) .border_radius(6.0) .border(1.0) - .border_color(config.get().color(LapceColor::LAPCE_BORDER)) + .border_color(config.get().color(UmideColor::LAPCE_BORDER)) .focusable(true) }), ) @@ -318,7 +318,7 @@ pub fn keymap_view(editors: Editors, common: Rc) -> impl View { .flex_basis(0.0) .flex_grow(1.0) .border_right(1.0) - .border_color(config.get().color(LapceColor::LAPCE_BORDER)) + .border_color(config.get().color(UmideColor::LAPCE_BORDER)) }), Label::new("Key Binding").style(move |s| { s.width(200.0) @@ -326,7 +326,7 @@ pub fn keymap_view(editors: Editors, common: Rc) -> impl View { .padding_horiz(10.0) .height_pct(100.0) .border_right(1.0) - .border_color(config.get().color(LapceColor::LAPCE_BORDER)) + .border_color(config.get().color(UmideColor::LAPCE_BORDER)) }), Label::new("Modes").style(move |s| { s.width(200.0) @@ -334,7 +334,7 @@ pub fn keymap_view(editors: Editors, common: Rc) -> impl View { .padding_horiz(10.0) .height_pct(100.0) .border_right(1.0) - .border_color(config.get().color(LapceColor::LAPCE_BORDER)) + .border_color(config.get().color(UmideColor::LAPCE_BORDER)) .apply_if(!modal.get(), |s| s.hide()) }), Container::new(Label::new("When").style(move |s| { @@ -355,8 +355,8 @@ pub fn keymap_view(editors: Editors, common: Rc) -> impl View { .width_pct(100.0) .border_top(1.0) .border_bottom(1.0) - .border_color(config.color(LapceColor::LAPCE_BORDER)) - .background(config.color(LapceColor::EDITOR_CURRENT_LINE)) + .border_color(config.color(UmideColor::LAPCE_BORDER)) + .background(config.color(UmideColor::EDITOR_CURRENT_LINE)) }), Container::new( Scroll::new( @@ -364,7 +364,7 @@ pub fn keymap_view(editors: Editors, common: Rc) -> impl View { items, |(i, (cmd, keymap)): &( usize, - (LapceCommand, Option), + (UmideCommand, Option), )| { (*i, cmd.kind.str(), keymap.clone()) }, view_fn, ) @@ -389,7 +389,7 @@ pub fn keymap_view(editors: Editors, common: Rc) -> impl View { fn keyboard_picker_view( picker: KeymapPicker, ui_line_height: Memo, - config: ReadSignal>, + config: ReadSignal>, ) -> impl View { let picker_cmd = picker.cmd; let view = Container::new( @@ -427,7 +427,7 @@ fn keyboard_picker_view( .border(1.0) .border_radius(6.0) .border_color( - config.get().color(LapceColor::LAPCE_BORDER), + config.get().color(UmideColor::LAPCE_BORDER), ) }) }, @@ -441,8 +441,8 @@ fn keyboard_picker_view( .height((ui_line_height.get() as f32) * 1.2) .border(1.0) .border_radius(6.0) - .border_color(config.color(LapceColor::LAPCE_BORDER)) - .background(config.color(LapceColor::EDITOR_BACKGROUND)) + .border_color(config.color(UmideColor::LAPCE_BORDER)) + .background(config.color(UmideColor::EDITOR_BACKGROUND)) }), Stack::new(( Label::new("Save") @@ -453,16 +453,16 @@ fn keyboard_picker_view( .padding_vert(8.0) .border(1.0) .border_radius(6.0) - .border_color(config.color(LapceColor::LAPCE_BORDER)) + .border_color(config.color(UmideColor::LAPCE_BORDER)) .hover(|s| { s.cursor(CursorStyle::Pointer).background( config - .color(LapceColor::PANEL_HOVERED_BACKGROUND), + .color(UmideColor::PANEL_HOVERED_BACKGROUND), ) }) .active(|s| { s.background(config.color( - LapceColor::PANEL_HOVERED_ACTIVE_BACKGROUND, + UmideColor::PANEL_HOVERED_ACTIVE_BACKGROUND, )) }) }) @@ -489,16 +489,16 @@ fn keyboard_picker_view( .padding_vert(8.0) .border(1.0) .border_radius(6.0) - .border_color(config.color(LapceColor::LAPCE_BORDER)) + .border_color(config.color(UmideColor::LAPCE_BORDER)) .hover(|s| { s.cursor(CursorStyle::Pointer).background( config - .color(LapceColor::PANEL_HOVERED_BACKGROUND), + .color(UmideColor::PANEL_HOVERED_BACKGROUND), ) }) .active(|s| { s.background(config.color( - LapceColor::PANEL_HOVERED_ACTIVE_BACKGROUND, + UmideColor::PANEL_HOVERED_ACTIVE_BACKGROUND, )) }) }) @@ -512,7 +512,7 @@ fn keyboard_picker_view( .justify_center() .width_pct(100.0) .margin_top(20.0) - .border_color(config.color(LapceColor::LAPCE_BORDER)) + .border_color(config.color(UmideColor::LAPCE_BORDER)) }), )) .on_event_stop(EventListener::PointerDown, |_| {}) @@ -524,8 +524,8 @@ fn keyboard_picker_view( .width(400.0) .border(1.0) .border_radius(6.0) - .border_color(config.color(LapceColor::LAPCE_BORDER)) - .background(config.color(LapceColor::PANEL_BACKGROUND)) + .border_color(config.color(UmideColor::LAPCE_BORDER)) + .background(config.color(UmideColor::PANEL_BACKGROUND)) }), ) diff --git a/crates/umide/src/keypress.rs b/crates/umide/src/keypress.rs index dd6747e7..97b0e99e 100644 --- a/crates/umide/src/keypress.rs +++ b/crates/umide/src/keypress.rs @@ -23,8 +23,8 @@ use self::{ loader::KeyMapLoader, }; use crate::{ - command::{CommandExecuted, CommandKind, LapceCommand, lapce_internal_commands}, - config::LapceConfig, + command::{CommandExecuted, CommandKind, UmideCommand, lapce_internal_commands}, + config::UmideConfig, keypress::{ condition::{CheckCondition, Condition}, keymap::KeymapMatch, @@ -46,7 +46,7 @@ pub trait KeyPressFocus: std::fmt::Debug { fn run_command( &self, - command: &LapceCommand, + command: &UmideCommand, count: Option, mods: Modifiers, ) -> CommandExecuted; @@ -72,7 +72,7 @@ impl KeyPressFocus for () { fn run_command( &self, - _command: &LapceCommand, + _command: &UmideCommand, _count: Option, _mods: Modifiers, ) -> CommandExecuted { @@ -100,7 +100,7 @@ impl KeyPressFocus for Box { fn run_command( &self, - command: &LapceCommand, + command: &UmideCommand, count: Option, mods: Modifiers, ) -> CommandExecuted { @@ -148,15 +148,15 @@ pub struct KeyPressHandle { pub struct KeyPressData { count: RwSignal>, pending_keypress: RwSignal<(Vec, Option)>, - pub commands: Rc>, + pub commands: Rc>, pub keymaps: Rc, Vec>>, pub command_keymaps: Rc>>, pub commands_with_keymap: Rc>, - pub commands_without_keymap: Rc>, + pub commands_without_keymap: Rc>, } impl KeyPressData { - pub fn new(cx: Scope, config: &LapceConfig) -> Self { + pub fn new(cx: Scope, config: &UmideConfig) -> Self { let (keymaps, command_keymaps) = Self::get_keymaps(config).unwrap_or((IndexMap::new(), IndexMap::new())); let mut keypress = Self { @@ -172,7 +172,7 @@ impl KeyPressData { keypress } - pub fn update_keymaps(&mut self, config: &LapceConfig) { + pub fn update_keymaps(&mut self, config: &UmideConfig) { if let Ok((new_keymaps, new_command_keymaps)) = Self::get_keymaps(config) { self.keymaps = Rc::new(new_keymaps); self.command_keymaps = Rc::new(new_command_keymaps); @@ -551,7 +551,7 @@ impl KeyPressData { #[allow(clippy::type_complexity)] fn get_keymaps( - config: &LapceConfig, + config: &UmideConfig, ) -> Result<( IndexMap, Vec>, IndexMap>, @@ -586,7 +586,7 @@ impl KeyPressData { } pub fn file() -> Option { - LapceConfig::keymaps_file() + UmideConfig::keymaps_file() } fn get_file_array() -> Option { diff --git a/crates/umide/src/keypress/condition.rs b/crates/umide/src/keypress/condition.rs index 4a3f9729..2ecd57bd 100644 --- a/crates/umide/src/keypress/condition.rs +++ b/crates/umide/src/keypress/condition.rs @@ -97,7 +97,7 @@ mod test { fn run_command( &self, - _command: &crate::command::LapceCommand, + _command: &crate::command::UmideCommand, _count: Option, _mods: Modifiers, ) -> crate::command::CommandExecuted { diff --git a/crates/umide/src/markdown.rs b/crates/umide/src/markdown.rs index ecef9279..547c4bcd 100644 --- a/crates/umide/src/markdown.rs +++ b/crates/umide/src/markdown.rs @@ -1,13 +1,13 @@ use floem::text::{ Attrs, AttrsList, FamilyOwned, LineHeightValue, Style, TextLayout, Weight, }; -use umide_core::{language::LapceLanguage, syntax::Syntax}; +use umide_core::{language::UmideLanguage, syntax::Syntax}; use lapce_xi_rope::Rope; use lsp_types::MarkedString; use pulldown_cmark::{CodeBlockKind, CowStr, Event, Options, Parser, Tag}; use smallvec::SmallVec; -use crate::config::{LapceConfig, color::LapceColor}; +use crate::config::{UmideConfig, color::UmideColor}; #[derive(Clone)] pub enum MarkdownContent { @@ -19,7 +19,7 @@ pub enum MarkdownContent { pub fn parse_markdown( text: &str, line_height: f64, - config: &LapceConfig, + config: &UmideConfig, ) -> Vec { let mut res = Vec::new(); @@ -28,7 +28,7 @@ pub fn parse_markdown( FamilyOwned::parse_list(&config.editor.font_family).collect(); let default_attrs = Attrs::new() - .color(config.color(LapceColor::EDITOR_FOREGROUND)) + .color(config.color(UmideColor::EDITOR_FOREGROUND)) .font_size(config.ui.font_size() as f32) .line_height(LineHeightValue::Normal(line_height as f32)); let mut attr_list = AttrsList::new(default_attrs.clone()); @@ -165,7 +165,7 @@ pub fn parse_markdown( default_attrs .clone() .family(&code_font_family) - .color(config.color(LapceColor::MARKDOWN_BLOCKQUOTE)), + .color(config.color(UmideColor::MARKDOWN_BLOCKQUOTE)), ); current_text.push_str(&text); pos += text.len(); @@ -203,7 +203,7 @@ fn attribute_for_tag<'a>( default_attrs: Attrs<'a>, tag: &Tag, code_font_family: &'a [FamilyOwned], - config: &LapceConfig, + config: &UmideConfig, ) -> Option> { use pulldown_cmark::HeadingLevel; match tag { @@ -233,7 +233,7 @@ fn attribute_for_tag<'a>( Tag::BlockQuote(_block_quote) => Some( default_attrs .style(Style::Italic) - .color(config.color(LapceColor::MARKDOWN_BLOCKQUOTE)), + .color(config.color(UmideColor::MARKDOWN_BLOCKQUOTE)), ), Tag::CodeBlock(_) => Some(default_attrs.family(code_font_family)), Tag::Emphasis => Some(default_attrs.style(Style::Italic)), @@ -246,7 +246,7 @@ fn attribute_for_tag<'a>( id: _, } => { // TODO: Link support - Some(default_attrs.color(config.color(LapceColor::EDITOR_LINK))) + Some(default_attrs.color(config.color(UmideColor::EDITOR_LINK))) } // All other tags are currently ignored _ => None, @@ -267,19 +267,19 @@ fn should_skip_text_in_tag(tag: &Tag) -> bool { matches!(tag, Tag::Image { .. }) } -fn md_language_to_lapce_language(lang: &str) -> Option { +fn md_language_to_lapce_language(lang: &str) -> Option { // TODO: There are many other names commonly used that should be supported - LapceLanguage::from_name(lang) + UmideLanguage::from_name(lang) } /// Highlight the text in a richtext builder like it was a markdown codeblock pub fn highlight_as_code( attr_list: &mut AttrsList, default_attrs: Attrs, - language: Option, + language: Option, text: &str, start_offset: usize, - config: &LapceConfig, + config: &UmideConfig, ) { let syntax = language.map(Syntax::from_language); @@ -308,7 +308,7 @@ pub fn highlight_as_code( pub fn from_marked_string( text: MarkedString, - config: &LapceConfig, + config: &UmideConfig, ) -> Vec { match text { MarkedString::String(text) => parse_markdown(&text, 1.8, config), @@ -328,7 +328,7 @@ pub fn from_marked_string( pub fn from_plaintext( text: &str, line_height: f64, - config: &LapceConfig, + config: &UmideConfig, ) -> Vec { let mut text_layout = TextLayout::new(); text_layout.set_text( diff --git a/crates/umide/src/palette.rs b/crates/umide/src/palette.rs index 8d5329b3..e44a01ca 100644 --- a/crates/umide/src/palette.rs +++ b/crates/umide/src/palette.rs @@ -22,7 +22,7 @@ use floem::{ use im::Vector; use itertools::Itertools; use umide_core::{ - buffer::rope_text::RopeText, command::FocusCommand, cursor::CursorAffinity, language::LapceLanguage, line_ending::LineEnding, mode::Mode, movement::Movement, selection::Selection, syntax::Syntax + buffer::rope_text::RopeText, command::FocusCommand, cursor::CursorAffinity, language::UmideLanguage, line_ending::LineEnding, mode::Mode, movement::Movement, selection::Selection, syntax::Syntax }; use umide_rpc::proxy::ProxyResponse; use lapce_xi_rope::Rope; @@ -37,9 +37,9 @@ use self::{ }; use crate::{ command::{ - CommandExecuted, CommandKind, InternalCommand, LapceCommand, WindowCommand, + CommandExecuted, CommandKind, InternalCommand, UmideCommand, WindowCommand, }, - db::LapceDb, + db::UmideDb, debug::{RunDebugConfigs, RunDebugMode}, editor::{ EditorData, @@ -50,7 +50,7 @@ use crate::{ main_split::MainSplitData, source_control::SourceControlData, window_tab::{CommonData, Focus}, - workspace::{LapceWorkspace, LapceWorkspaceType, SshHost}, + workspace::{UmideWorkspace, UmideWorkspaceType, SshHost}, }; pub mod item; @@ -83,7 +83,7 @@ impl PaletteInput { pub struct PaletteData { run_id_counter: Arc, pub run_id: RwSignal, - pub workspace: Arc, + pub workspace: Arc, pub status: RwSignal, pub index: RwSignal, pub preselect_index: RwSignal>, @@ -115,7 +115,7 @@ impl std::fmt::Debug for PaletteData { impl PaletteData { pub fn new( cx: Scope, - workspace: Arc, + workspace: Arc, main_split: MainSplitData, keypress: ReadSignal, source_control: SourceControlData, @@ -597,7 +597,7 @@ impl PaletteData { /// Initialize the palette with all the available workspaces, local and remote. fn get_workspaces(&self) { - let db: Arc = Context::get().unwrap(); + let db: Arc = Context::get().unwrap(); let workspaces = db.recent_workspaces().unwrap_or_default(); let items = workspaces @@ -605,12 +605,12 @@ impl PaletteData { .filter_map(|w| { let text = w.path.as_ref()?.to_str()?.to_string(); let filter_text = match &w.kind { - LapceWorkspaceType::Local => text, - LapceWorkspaceType::RemoteSSH(remote) => { + UmideWorkspaceType::Local => text, + UmideWorkspaceType::RemoteSSH(remote) => { format!("[{remote}] {text}") } #[cfg(windows)] - LapceWorkspaceType::RemoteWSL(remote) => { + UmideWorkspaceType::RemoteWSL(remote) => { format!("[{remote}] {text}") } }; @@ -796,11 +796,11 @@ impl PaletteData { } fn get_ssh_hosts(&self) { - let db: Arc = Context::get().unwrap(); + let db: Arc = Context::get().unwrap(); let workspaces = db.recent_workspaces().unwrap_or_default(); let mut hosts = HashSet::new(); for workspace in workspaces.iter() { - if let LapceWorkspaceType::RemoteSSH(host) = &workspace.kind { + if let UmideWorkspaceType::RemoteSSH(host) = &workspace.kind { hosts.insert(host.clone()); } } @@ -849,7 +849,7 @@ impl PaletteData { vec![] }; - let db: Arc = use_context().unwrap(); + let db: Arc = use_context().unwrap(); let workspaces = db.recent_workspaces().unwrap_or_default(); let mut hosts = HashSet::new(); for distro in distros { @@ -857,7 +857,7 @@ impl PaletteData { } for workspace in workspaces.iter() { - if let LapceWorkspaceType::RemoteWSL(host) = &workspace.kind { + if let UmideWorkspaceType::RemoteWSL(host) = &workspace.kind { hosts.insert(host.host.clone()); } } @@ -1005,7 +1005,7 @@ impl PaletteData { } fn get_languages(&self) { - let langs = LapceLanguage::languages(); + let langs = UmideLanguage::languages(); let items = langs .iter() .map(|lang| PaletteItem { @@ -1125,7 +1125,7 @@ impl PaletteData { if let Some(item) = items.get(index) { match &item.content { PaletteItemContent::PaletteHelp { cmd } => { - let cmd = LapceCommand { + let cmd = UmideCommand { kind: CommandKind::Workbench(cmd.clone()), data: None, }; @@ -1202,8 +1202,8 @@ impl PaletteData { PaletteItemContent::SshHost { host } => { self.common.window_common.window_command.send( WindowCommand::SetWorkspace { - workspace: LapceWorkspace { - kind: LapceWorkspaceType::RemoteSSH(host.clone()), + workspace: UmideWorkspace { + kind: UmideWorkspaceType::RemoteSSH(host.clone()), path: None, last_open: 0, }, @@ -1214,8 +1214,8 @@ impl PaletteData { PaletteItemContent::WslHost { host } => { self.common.window_common.window_command.send( WindowCommand::SetWorkspace { - workspace: LapceWorkspace { - kind: LapceWorkspaceType::RemoteWSL(host.clone()), + workspace: UmideWorkspace { + kind: UmideWorkspaceType::RemoteWSL(host.clone()), path: None, last_open: 0, }, @@ -1291,7 +1291,7 @@ impl PaletteData { if name.is_empty() || name.to_lowercase().eq("plain text") { doc.set_syntax(Syntax::plaintext()) } else { - let lang = match LapceLanguage::from_name(name) { + let lang = match UmideLanguage::from_name(name) { Some(v) => v, None => return, }; @@ -1313,9 +1313,9 @@ impl PaletteData { PaletteItemContent::SCMReference { name } => { self.common .lapce_command - .send(crate::command::LapceCommand { + .send(crate::command::UmideCommand { kind: CommandKind::Workbench( - crate::command::LapceWorkbenchCommand::CheckoutReference, + crate::command::UmideWorkbenchCommand::CheckoutReference, ), data: Some(serde_json::json!(name.to_owned())), }); @@ -1332,8 +1332,8 @@ impl PaletteData { let ssh = SshHost::from_string(&input); self.common.window_common.window_command.send( WindowCommand::SetWorkspace { - workspace: LapceWorkspace { - kind: LapceWorkspaceType::RemoteSSH(ssh), + workspace: UmideWorkspace { + kind: UmideWorkspaceType::RemoteSSH(ssh), path: None, last_open: 0, }, @@ -1671,7 +1671,7 @@ impl KeyPressFocus for PaletteData { fn run_command( &self, - command: &crate::command::LapceCommand, + command: &crate::command::UmideCommand, count: Option, mods: Modifiers, ) -> CommandExecuted { diff --git a/crates/umide/src/palette/item.rs b/crates/umide/src/palette/item.rs index 8fcfd9fe..0af7dbe7 100644 --- a/crates/umide/src/palette/item.rs +++ b/crates/umide/src/palette/item.rs @@ -5,10 +5,10 @@ use umide_rpc::dap_types::RunDebugConfig; use lsp_types::{Range, SymbolKind}; use crate::{ - command::{LapceCommand, LapceWorkbenchCommand}, + command::{UmideCommand, UmideWorkbenchCommand}, debug::RunDebugMode, editor::location::EditorLocation, - workspace::{LapceWorkspace, SshHost}, + workspace::{UmideWorkspace, SshHost}, }; #[derive(Clone, Debug, PartialEq)] @@ -22,7 +22,7 @@ pub struct PaletteItem { #[derive(Clone, Debug, PartialEq)] pub enum PaletteItemContent { PaletteHelp { - cmd: LapceWorkbenchCommand, + cmd: UmideWorkbenchCommand, }, File { path: PathBuf, @@ -33,10 +33,10 @@ pub enum PaletteItemContent { content: String, }, Command { - cmd: LapceCommand, + cmd: UmideCommand, }, Workspace { - workspace: LapceWorkspace, + workspace: UmideWorkspace, }, Reference { path: PathBuf, diff --git a/crates/umide/src/palette/kind.rs b/crates/umide/src/palette/kind.rs index 1a1b8941..f4fc05c3 100644 --- a/crates/umide/src/palette/kind.rs +++ b/crates/umide/src/palette/kind.rs @@ -1,6 +1,6 @@ use strum_macros::EnumIter; -use crate::command::LapceWorkbenchCommand; +use crate::command::UmideWorkbenchCommand; #[derive(Clone, Copy, Debug, PartialEq, Eq, EnumIter)] pub enum PaletteKind { @@ -68,41 +68,41 @@ impl PaletteKind { } } - /// Get the [`LapceWorkbenchCommand`] that opens this palette kind, if one exists. - pub fn command(self) -> Option { + /// Get the [`UmideWorkbenchCommand`] that opens this palette kind, if one exists. + pub fn command(self) -> Option { match self { - PaletteKind::PaletteHelp => Some(LapceWorkbenchCommand::PaletteHelp), - PaletteKind::Line => Some(LapceWorkbenchCommand::PaletteLine), + PaletteKind::PaletteHelp => Some(UmideWorkbenchCommand::PaletteHelp), + PaletteKind::Line => Some(UmideWorkbenchCommand::PaletteLine), PaletteKind::DocumentSymbol => { - Some(LapceWorkbenchCommand::PaletteSymbol) + Some(UmideWorkbenchCommand::PaletteSymbol) } PaletteKind::WorkspaceSymbol => { - Some(LapceWorkbenchCommand::PaletteWorkspaceSymbol) + Some(UmideWorkbenchCommand::PaletteWorkspaceSymbol) } - PaletteKind::Workspace => Some(LapceWorkbenchCommand::PaletteWorkspace), - PaletteKind::Command => Some(LapceWorkbenchCommand::PaletteCommand), - PaletteKind::File => Some(LapceWorkbenchCommand::Palette), + PaletteKind::Workspace => Some(UmideWorkbenchCommand::PaletteWorkspace), + PaletteKind::Command => Some(UmideWorkbenchCommand::PaletteCommand), + PaletteKind::File => Some(UmideWorkbenchCommand::Palette), PaletteKind::HelpAndFile => { - Some(LapceWorkbenchCommand::PaletteHelpAndFile) + Some(UmideWorkbenchCommand::PaletteHelpAndFile) } PaletteKind::Reference => None, // InternalCommand::PaletteReferences - PaletteKind::SshHost => Some(LapceWorkbenchCommand::ConnectSshHost), + PaletteKind::SshHost => Some(UmideWorkbenchCommand::ConnectSshHost), #[cfg(windows)] - PaletteKind::WslHost => Some(LapceWorkbenchCommand::ConnectWslHost), + PaletteKind::WslHost => Some(UmideWorkbenchCommand::ConnectWslHost), PaletteKind::RunAndDebug => { - Some(LapceWorkbenchCommand::PaletteRunAndDebug) + Some(UmideWorkbenchCommand::PaletteRunAndDebug) } - PaletteKind::ColorTheme => Some(LapceWorkbenchCommand::ChangeColorTheme), - PaletteKind::IconTheme => Some(LapceWorkbenchCommand::ChangeIconTheme), - PaletteKind::Language => Some(LapceWorkbenchCommand::ChangeFileLanguage), + PaletteKind::ColorTheme => Some(UmideWorkbenchCommand::ChangeColorTheme), + PaletteKind::IconTheme => Some(UmideWorkbenchCommand::ChangeIconTheme), + PaletteKind::Language => Some(UmideWorkbenchCommand::ChangeFileLanguage), PaletteKind::LineEnding => { - Some(LapceWorkbenchCommand::ChangeFileLineEnding) + Some(UmideWorkbenchCommand::ChangeFileLineEnding) } PaletteKind::SCMReferences => { - Some(LapceWorkbenchCommand::PaletteSCMReferences) + Some(UmideWorkbenchCommand::PaletteSCMReferences) } PaletteKind::TerminalProfile => None, // InternalCommand::NewTerminal - PaletteKind::DiffFiles => Some(LapceWorkbenchCommand::DiffFiles), + PaletteKind::DiffFiles => Some(UmideWorkbenchCommand::DiffFiles), } } diff --git a/crates/umide/src/panel/call_hierarchy_view.rs b/crates/umide/src/panel/call_hierarchy_view.rs index 72a2dc0a..b81fdf3a 100644 --- a/crates/umide/src/panel/call_hierarchy_view.rs +++ b/crates/umide/src/panel/call_hierarchy_view.rs @@ -14,7 +14,7 @@ use lsp_types::{CallHierarchyItem, Range}; use super::position::PanelPosition; use crate::{ command::InternalCommand, - config::{color::LapceColor, icon::LapceIcons}, + config::{color::UmideColor, icon::UmideIcons}, editor::location::EditorLocation, window_tab::{CommonData, WindowTabData}, }; @@ -143,8 +143,8 @@ pub fn show_hierarchy_panel( svg(move || { let config = config.get(); let svg_str = match open.get() { - true => LapceIcons::ITEM_OPENED, - false => LapceIcons::ITEM_CLOSED, + true => UmideIcons::ITEM_OPENED, + false => UmideIcons::ITEM_CLOSED, }; config.ui_svg(svg_str) }) @@ -152,7 +152,7 @@ pub fn show_hierarchy_panel( let config = config.get(); let size = config.ui.icon_size() as f32; s.size(size, size) - .color(config.color(LapceColor::LAPCE_ICON_ACTIVE)) + .color(config.color(UmideColor::LAPCE_ICON_ACTIVE)) }) ) .style(|s| s.padding(4.0).margin_left(6.0).margin_right(2.0)) @@ -175,7 +175,7 @@ pub fn show_hierarchy_panel( let config = config.get(); config .symbol_svg(&kind) - .unwrap_or_else(|| config.ui_svg(LapceIcons::FILE)) + .unwrap_or_else(|| config.ui_svg(UmideIcons::FILE)) }).style(move |s| { let config = config.get(); let size = config.ui.icon_size() as f32; @@ -183,7 +183,7 @@ pub fn show_hierarchy_panel( .size(size, size) .margin_right(5.0) .color(config.symbol_color(&kind).unwrap_or_else(|| { - config.color(LapceColor::LAPCE_ICON_ACTIVE) + config.color(UmideColor::LAPCE_ICON_ACTIVE) })) }), data.item.name.clone().into_view(), @@ -191,7 +191,7 @@ pub fn show_hierarchy_panel( Label::new({ data.item.detail.clone().unwrap_or_default().replace('\n', "↵") }).style(move |s| s.margin_left(6.0) - .color(config.get().color(LapceColor::EDITOR_DIM)) + .color(config.get().color(UmideColor::EDITOR_DIM)) ).into_any() } else { Empty::new().into_any() @@ -206,7 +206,7 @@ pub fn show_hierarchy_panel( s.background( config .get() - .color(LapceColor::PANEL_HOVERED_BACKGROUND), + .color(UmideColor::PANEL_HOVERED_BACKGROUND), ) .cursor(CursorStyle::Pointer) }) diff --git a/crates/umide/src/panel/data.rs b/crates/umide/src/panel/data.rs index eeb997e8..c4876cf7 100644 --- a/crates/umide/src/panel/data.rs +++ b/crates/umide/src/panel/data.rs @@ -14,7 +14,7 @@ use super::{ style::PanelStyle, }; use crate::{ - db::LapceDb, + db::UmideDb, window_tab::{CommonData, Focus}, }; @@ -389,7 +389,7 @@ impl PanelData { style.shown = true; }); - let db: Arc = Context::get().unwrap(); + let db: Arc = Context::get().unwrap(); db.save_panel_orders(self.panels.get_untracked()); } diff --git a/crates/umide/src/panel/debug_view.rs b/crates/umide/src/panel/debug_view.rs index f92ed677..e4c91df7 100644 --- a/crates/umide/src/panel/debug_view.rs +++ b/crates/umide/src/panel/debug_view.rs @@ -20,7 +20,7 @@ use super::{data::PanelSection, position::PanelPosition, view::PanelBuilder}; use crate::{ app::clickable_icon, command::InternalCommand, - config::{LapceConfig, color::LapceColor, icon::LapceIcons}, + config::{UmideConfig, color::UmideColor, icon::UmideIcons}, debug::{DapVariable, RunDebugMode, StackTraceData}, editor::location::{EditorLocation, EditorPosition}, listener::Listener, @@ -70,7 +70,7 @@ fn debug_process_icons( dap_id: DapId, mode: RunDebugMode, stopped: bool, - config: ReadSignal>, + config: ReadSignal>, ) -> impl View { let paused = move || { let stopped = terminal @@ -84,7 +84,7 @@ fn debug_process_icons( { let terminal = terminal.clone(); clickable_icon( - || LapceIcons::DEBUG_RESTART, + || UmideIcons::DEBUG_RESTART, move || { terminal.restart_run_debug(term_id); }, @@ -98,7 +98,7 @@ fn debug_process_icons( { let terminal = terminal.clone(); clickable_icon( - || LapceIcons::DEBUG_STOP, + || UmideIcons::DEBUG_STOP, move || { terminal.stop_run_debug(term_id); }, @@ -112,7 +112,7 @@ fn debug_process_icons( { let terminal = terminal.clone(); clickable_icon( - || LapceIcons::CLOSE, + || UmideIcons::CLOSE, move || { terminal.close_terminal(&term_id); }, @@ -128,7 +128,7 @@ fn debug_process_icons( { let terminal = terminal.clone(); clickable_icon( - || LapceIcons::DEBUG_CONTINUE, + || UmideIcons::DEBUG_CONTINUE, move || { terminal.dap_continue(term_id); }, @@ -142,7 +142,7 @@ fn debug_process_icons( { let terminal = terminal.clone(); clickable_icon( - || LapceIcons::DEBUG_PAUSE, + || UmideIcons::DEBUG_PAUSE, move || { terminal.dap_pause(term_id); }, @@ -156,7 +156,7 @@ fn debug_process_icons( { let terminal = terminal.clone(); clickable_icon( - || LapceIcons::DEBUG_STEP_OVER, + || UmideIcons::DEBUG_STEP_OVER, move || { terminal.dap_step_over(term_id); }, @@ -170,7 +170,7 @@ fn debug_process_icons( { let terminal = terminal.clone(); clickable_icon( - || LapceIcons::DEBUG_STEP_INTO, + || UmideIcons::DEBUG_STEP_INTO, move || { terminal.dap_step_into(term_id); }, @@ -184,7 +184,7 @@ fn debug_process_icons( { let terminal = terminal.clone(); clickable_icon( - || LapceIcons::DEBUG_STEP_OUT, + || UmideIcons::DEBUG_STEP_OUT, move || { terminal.dap_step_out(term_id); }, @@ -198,7 +198,7 @@ fn debug_process_icons( { let terminal = terminal.clone(); clickable_icon( - || LapceIcons::DEBUG_RESTART, + || UmideIcons::DEBUG_RESTART, move || { terminal.restart_run_debug(term_id); }, @@ -212,7 +212,7 @@ fn debug_process_icons( { let terminal = terminal.clone(); clickable_icon( - || LapceIcons::DEBUG_STOP, + || UmideIcons::DEBUG_STOP, move || { terminal.stop_run_debug(term_id); }, @@ -226,7 +226,7 @@ fn debug_process_icons( { let terminal = terminal.clone(); clickable_icon( - || LapceIcons::CLOSE, + || UmideIcons::CLOSE, move || { terminal.close_terminal(&term_id); }, @@ -243,7 +243,7 @@ fn debug_process_icons( fn debug_processes( terminal: TerminalPanelData, - config: ReadSignal>, + config: ReadSignal>, ) -> impl View { Scroll::new({ let terminal = terminal.clone(); @@ -260,11 +260,11 @@ fn debug_processes( Stack::new(( { let svg_str = match (&p.mode, p.stopped) { - (RunDebugMode::Run, false) => LapceIcons::START, - (RunDebugMode::Run, true) => LapceIcons::RUN_ERRORS, - (RunDebugMode::Debug, false) => LapceIcons::DEBUG, + (RunDebugMode::Run, false) => UmideIcons::START, + (RunDebugMode::Run, true) => UmideIcons::RUN_ERRORS, + (RunDebugMode::Debug, false) => UmideIcons::DEBUG, (RunDebugMode::Debug, true) => { - LapceIcons::DEBUG_DISCONNECT + UmideIcons::DEBUG_DISCONNECT } }; svg(move || config.get().ui_svg(svg_str)).style(move |s| { @@ -273,7 +273,7 @@ fn debug_processes( s.size(size, size) .margin_vert(5.0) .margin_horiz(10.0) - .color(config.color(LapceColor::LAPCE_ICON_ACTIVE)) + .color(config.color(UmideColor::LAPCE_ICON_ACTIVE)) }) }, Label::new(p.config.name.clone()).style(|s| { @@ -311,12 +311,12 @@ fn debug_processes( .items_center() .apply_if(is_active(), |s| { s.background( - config.color(LapceColor::PANEL_CURRENT_BACKGROUND), + config.color(UmideColor::PANEL_CURRENT_BACKGROUND), ) }) .hover(|s| { s.cursor(CursorStyle::Pointer).background( - (config.color(LapceColor::PANEL_HOVERED_BACKGROUND)) + (config.color(UmideColor::PANEL_HOVERED_BACKGROUND)) .multiply_alpha(0.3), ) }) @@ -374,8 +374,8 @@ fn variables_view(window_tab_data: Rc) -> impl View { svg(move || { let config = config.get(); let svg_str = match node.expanded { - true => LapceIcons::ITEM_OPENED, - false => LapceIcons::ITEM_CLOSED, + true => UmideIcons::ITEM_OPENED, + false => UmideIcons::ITEM_CLOSED, }; config.ui_svg(svg_str) }) @@ -384,7 +384,7 @@ fn variables_view(window_tab_data: Rc) -> impl View { let size = config.ui.icon_size() as f32; let color = if reference > 0 { - config.color(LapceColor::LAPCE_ICON_ACTIVE) + config.color(UmideColor::LAPCE_ICON_ACTIVE) } else { Color::TRANSPARENT }; @@ -435,7 +435,7 @@ fn variables_view(window_tab_data: Rc) -> impl View { s.apply_if(reference > 0, |s| { s.background( config.get().color( - LapceColor::PANEL_HOVERED_BACKGROUND, + UmideColor::PANEL_HOVERED_BACKGROUND, ), ) }) @@ -457,7 +457,7 @@ fn debug_stack_frames( stack_trace: StackTraceData, stopped: RwSignal, internal_command: Listener, - config: ReadSignal>, + config: ReadSignal>, ) -> impl View { let expanded = stack_trace.expanded; Stack::new(( @@ -470,7 +470,7 @@ fn debug_stack_frames( .style(move |s| { s.padding_horiz(10.0).min_width_pct(100.0).hover(move |s| { s.cursor(CursorStyle::Pointer).background( - config.get().color(LapceColor::PANEL_HOVERED_BACKGROUND), + config.get().color(UmideColor::PANEL_HOVERED_BACKGROUND), ) }) }), @@ -506,13 +506,13 @@ fn debug_stack_frames( s.background( config .get() - .color(LapceColor::PANEL_HOVERED_BACKGROUND), + .color(UmideColor::PANEL_HOVERED_BACKGROUND), ) }) }), Label::new(source_path.clone()).style(move |s| { s.margin_left(10.0) - .color(config.get().color(LapceColor::EDITOR_DIM)) + .color(config.get().color(UmideColor::EDITOR_DIM)) .font_style(FontStyle::Italic) .apply_if(!has_source, |s| s.hide()) }), @@ -545,11 +545,11 @@ fn debug_stack_frames( .padding_right(10.0) .min_width_pct(100.0) .apply_if(!has_source, |s| { - s.color(config.color(LapceColor::EDITOR_DIM)) + s.color(config.color(UmideColor::EDITOR_DIM)) }) .hover(|s| { s.background( - config.color(LapceColor::PANEL_HOVERED_BACKGROUND), + config.color(UmideColor::PANEL_HOVERED_BACKGROUND), ) .apply_if(has_source, |s| s.cursor(CursorStyle::Pointer)) }) @@ -564,7 +564,7 @@ fn debug_stack_frames( fn debug_stack_traces( terminal: TerminalPanelData, internal_command: Listener, - config: ReadSignal>, + config: ReadSignal>, ) -> impl View { Container::new( Scroll::new({ @@ -664,7 +664,7 @@ fn breakpoints_view(window_tab_data: Rc) -> impl View { Stack::new(( clickable_icon( - move || LapceIcons::CLOSE, + move || UmideIcons::CLOSE, move || { breakpoints.update(|breakpoints| { if let Some(breakpoints) = @@ -713,7 +713,7 @@ fn breakpoints_view(window_tab_data: Rc) -> impl View { s.text_ellipsis() .flex_grow(1.0) .flex_basis(0.0) - .color(config.get().color(LapceColor::EDITOR_DIM)) + .color(config.get().color(UmideColor::EDITOR_DIM)) .min_width(0.0) .margin_left(6.0) .apply_if(folder_empty, |s| s.hide()) @@ -725,7 +725,7 @@ fn breakpoints_view(window_tab_data: Rc) -> impl View { s.background( config .get() - .color(LapceColor::PANEL_HOVERED_BACKGROUND), + .color(UmideColor::PANEL_HOVERED_BACKGROUND), ) }, ) diff --git a/crates/umide/src/panel/document_symbol.rs b/crates/umide/src/panel/document_symbol.rs index 0fb9463c..88856d5f 100644 --- a/crates/umide/src/panel/document_symbol.rs +++ b/crates/umide/src/panel/document_symbol.rs @@ -15,7 +15,7 @@ use lsp_types::{DocumentSymbol, SymbolKind}; use super::position::PanelPosition; use crate::{ command::InternalCommand, - config::{color::LapceColor, icon::LapceIcons}, + config::{color::UmideColor, icon::UmideIcons}, editor::location::EditorLocation, window_tab::WindowTabData, }; @@ -225,15 +225,15 @@ pub fn symbol_panel( svg(move || { let config = config.get(); let svg_str = match open.get() { - true => LapceIcons::ITEM_OPENED, - false => LapceIcons::ITEM_CLOSED, + true => UmideIcons::ITEM_OPENED, + false => UmideIcons::ITEM_CLOSED, }; config.ui_svg(svg_str) }) .style(move |s| { let config = config.get(); let color = if has_child { - config.color(LapceColor::LAPCE_ICON_ACTIVE) + config.color(UmideColor::LAPCE_ICON_ACTIVE) } else { Color::TRANSPARENT }; @@ -255,7 +255,7 @@ pub fn symbol_panel( let config = config.get(); config .symbol_svg(&kind) - .unwrap_or_else(|| config.ui_svg(LapceIcons::FILE)) + .unwrap_or_else(|| config.ui_svg(UmideIcons::FILE)) }).style(move |s| { let config = config.get(); let size = config.ui.icon_size() as f32; @@ -263,7 +263,7 @@ pub fn symbol_panel( .size(size, size) .margin_right(5.0) .color(config.symbol_color(&kind).unwrap_or_else(|| { - config.color(LapceColor::LAPCE_ICON_ACTIVE) + config.color(UmideColor::LAPCE_ICON_ACTIVE) })) }), Label::new({ @@ -275,7 +275,7 @@ pub fn symbol_panel( Label::new({ data.detail.clone().unwrap_or_default() }).style(move |s| s.margin_left(6.0) - .color(config.get().color(LapceColor::EDITOR_DIM)) + .color(config.get().color(UmideColor::EDITOR_DIM)) .selectable(false) .apply_if( data.item.detail.clone().is_none(), @@ -291,7 +291,7 @@ pub fn symbol_panel( s.background( config .get() - .color(LapceColor::PANEL_HOVERED_BACKGROUND), + .color(UmideColor::PANEL_HOVERED_BACKGROUND), ) .cursor(CursorStyle::Pointer) }) diff --git a/crates/umide/src/panel/emulator_view.rs b/crates/umide/src/panel/emulator_view.rs index 171246bc..9b729a65 100644 --- a/crates/umide/src/panel/emulator_view.rs +++ b/crates/umide/src/panel/emulator_view.rs @@ -10,7 +10,7 @@ use crate::{ app::clickable_icon, panel::{position::PanelPosition, view::PanelBuilder}, window_tab::WindowTabData, - config::{icon::LapceIcons, color::LapceColor}, + config::{icon::UmideIcons, color::UmideColor}, }; use umide_emulator::{ list_all_devices, launch_device, stop_device, DeviceInfo, DevicePlatform, DeviceState, @@ -109,7 +109,7 @@ fn platform_panel( running_device: RwSignal>, frame_signal: RwSignal>>, // Kept for API compat, likely unused current_device_id: RwSignal, - config: floem::reactive::ReadSignal>, + config: floem::reactive::ReadSignal>, ) -> impl View { let platform_name = match &platform { DevicePlatform::Android => "Android", @@ -129,7 +129,7 @@ fn platform_panel( Label::new(device.name.clone()) .style(|s| s.flex_grow(1.0).padding_horiz(6.0)), clickable_icon( - || LapceIcons::DEBUG_CONTINUE, + || UmideIcons::DEBUG_CONTINUE, move || { let _ = launch_device(&device_cloned_start); let mut d = device_cloned_start.clone(); @@ -142,7 +142,7 @@ fn platform_panel( config, ), clickable_icon( - || LapceIcons::DEBUG_STOP, + || UmideIcons::DEBUG_STOP, move || { let _ = stop_device(&device_cloned_stop); running_device.set(None); @@ -182,7 +182,7 @@ fn platform_panel( let config = config.get(); s.width_full() .border_bottom(1.0) - .border_color(config.color(LapceColor::LAPCE_BORDER)) + .border_color(config.color(UmideColor::LAPCE_BORDER)) }), // Content: Device list @@ -215,7 +215,7 @@ fn platform_panel( Stack::new(( NativeEmulatorWidget::new(running_device, current_device_id), clickable_icon( - || LapceIcons::CLOSE, + || UmideIcons::CLOSE, move || { running_device.set(None); frame_signal.set(None); @@ -243,7 +243,7 @@ fn platform_panel( .flex_grow(1.0) .min_width(180.0) .border(1.0) - .border_color(config.color(LapceColor::LAPCE_BORDER)) + .border_color(config.color(UmideColor::LAPCE_BORDER)) }) } diff --git a/crates/umide/src/panel/global_search_view.rs b/crates/umide/src/panel/global_search_view.rs index 004b6830..5b9536db 100644 --- a/crates/umide/src/panel/global_search_view.rs +++ b/crates/umide/src/panel/global_search_view.rs @@ -14,14 +14,14 @@ use super::{kind::PanelKind, position::PanelPosition}; use crate::{ app::clickable_icon, command::InternalCommand, - config::{LapceConfig, color::LapceColor, icon::LapceIcons}, + config::{UmideConfig, color::UmideColor, icon::UmideIcons}, editor::location::{EditorLocation, EditorPosition}, focus_text::focus_text, global_search::{GlobalSearchData, SearchMatchData}, listener::Listener, text_input::TextInputBuilder, window_tab::{Focus, WindowTabData}, - workspace::LapceWorkspace, + workspace::UmideWorkspace, }; struct SearchMatchList(im::Vector); @@ -60,7 +60,7 @@ pub fn global_search_panel( .build_editor(editor.clone()) .style(|s| s.width_pct(100.0)), clickable_icon( - || LapceIcons::SEARCH_CASE_SENSITIVE, + || UmideIcons::SEARCH_CASE_SENSITIVE, move || { let new = match case_matching.get_untracked() { CaseMatching::Exact => CaseMatching::CaseInsensitive, @@ -75,7 +75,7 @@ pub fn global_search_panel( ) .style(|s| s.padding_vert(4.0)), clickable_icon( - || LapceIcons::SEARCH_WHOLE_WORD, + || UmideIcons::SEARCH_WHOLE_WORD, move || { whole_word.update(|whole_word| { *whole_word = !*whole_word; @@ -88,7 +88,7 @@ pub fn global_search_panel( ) .style(|s| s.padding_left(6.0)), clickable_icon( - || LapceIcons::SEARCH_REGEX, + || UmideIcons::SEARCH_REGEX, move || { is_regex.update(|is_regex| { *is_regex = !*is_regex; @@ -110,7 +110,7 @@ pub fn global_search_panel( .items_center() .border(1.0) .border_radius(6.0) - .border_color(config.get().color(LapceColor::LAPCE_BORDER)) + .border_color(config.get().color(UmideColor::LAPCE_BORDER)) }), ) .style(|s| s.width_pct(100.0).padding(10.0)), @@ -121,10 +121,10 @@ pub fn global_search_panel( } fn search_result( - workspace: Arc, + workspace: Arc, global_search_data: GlobalSearchData, internal_command: Listener, - config: ReadSignal>, + config: ReadSignal>, ) -> impl View { let ui_line_height = global_search_data.common.ui_line_height; Container::new({ @@ -162,9 +162,9 @@ fn search_result( Stack::new(( svg(move || { config.get().ui_svg(if expanded.get() { - LapceIcons::ITEM_OPENED + UmideIcons::ITEM_OPENED } else { - LapceIcons::ITEM_CLOSED + UmideIcons::ITEM_CLOSED }) }) .style(move |s| { @@ -175,7 +175,7 @@ fn search_result( .size(size, size) .min_size(size, size) .color( - config.color(LapceColor::LAPCE_ICON_ACTIVE), + config.color(UmideColor::LAPCE_ICON_ACTIVE), ) }), svg(move || config.get().file_svg(&path).0).style( @@ -197,7 +197,7 @@ fn search_result( }), Label::new(folder.clone()).style(move |s| { s.color( - config.get().color(LapceColor::EDITOR_DIM), + config.get().color(UmideColor::EDITOR_DIM), ) .min_width(0.0) .text_ellipsis() @@ -215,7 +215,7 @@ fn search_result( .hover(|s| { s.cursor(CursorStyle::Pointer).background( config.get().color( - LapceColor::PANEL_HOVERED_BACKGROUND, + UmideColor::PANEL_HOVERED_BACKGROUND, ), ) }) @@ -268,7 +268,7 @@ fn search_result( .collect() }, move || { - config.get().color(LapceColor::EDITOR_FOCUS) + config.get().color(UmideColor::EDITOR_FOCUS) }, ) .style(move |s| { @@ -278,7 +278,7 @@ fn search_result( |s| { s.cursor(CursorStyle::Pointer) .background(config.color( - LapceColor::PANEL_HOVERED_BACKGROUND, + UmideColor::PANEL_HOVERED_BACKGROUND, )) }, ) diff --git a/crates/umide/src/panel/implementation_view.rs b/crates/umide/src/panel/implementation_view.rs index 3c08f86c..77140e4c 100644 --- a/crates/umide/src/panel/implementation_view.rs +++ b/crates/umide/src/panel/implementation_view.rs @@ -17,7 +17,7 @@ use lsp_types::{Location, SymbolKind, request::GotoImplementationResponse}; use super::position::PanelPosition; use crate::{ command::InternalCommand, - config::{color::LapceColor, icon::LapceIcons}, + config::{color::UmideColor, icon::UmideIcons}, editor::location::EditorLocation, window_tab::WindowTabData, }; @@ -49,8 +49,8 @@ pub fn common_reference_panel( svg(move || { let config = config.get(); let svg_str = match open.get() { - true => LapceIcons::ITEM_OPENED, - false => LapceIcons::ITEM_CLOSED, + true => UmideIcons::ITEM_OPENED, + false => UmideIcons::ITEM_CLOSED, }; config.ui_svg(svg_str) }) @@ -58,7 +58,7 @@ pub fn common_reference_panel( let config = config.get(); let size = config.ui.icon_size() as f32; s.size(size, size).color( - config.color(LapceColor::LAPCE_ICON_ACTIVE), + config.color(UmideColor::LAPCE_ICON_ACTIVE), ) }), ) @@ -74,7 +74,7 @@ pub fn common_reference_panel( let config = config.get(); config .symbol_svg(&SymbolKind::FILE) - .unwrap_or_else(|| config.ui_svg(LapceIcons::FILE)) + .unwrap_or_else(|| config.ui_svg(UmideIcons::FILE)) }) .style(move |s| { let config = config.get(); @@ -87,14 +87,14 @@ pub fn common_reference_panel( .symbol_color(&SymbolKind::FILE) .unwrap_or_else(|| { config - .color(LapceColor::LAPCE_ICON_ACTIVE) + .color(UmideColor::LAPCE_ICON_ACTIVE) }), ) }), Label::derived(move || format!("{:?}", path)) .style(move |s| { s.margin_left(6.0).color( - config.get().color(LapceColor::EDITOR_DIM), + config.get().color(UmideColor::EDITOR_DIM), ) }) .into_any(), @@ -108,7 +108,7 @@ pub fn common_reference_panel( s.background( config .get() - .color(LapceColor::PANEL_HOVERED_BACKGROUND), + .color(UmideColor::PANEL_HOVERED_BACKGROUND), ) .cursor(CursorStyle::Pointer) }) @@ -117,7 +117,7 @@ pub fn common_reference_panel( Label::derived(move || format!("{} {}", file_line.position.line + 1, file_line.content)) .style(move |s| { s.margin_left(6.0).color( - config.get().color(LapceColor::EDITOR_DIM), + config.get().color(UmideColor::EDITOR_DIM), ) }) .into_any(), @@ -131,7 +131,7 @@ pub fn common_reference_panel( s.background( config .get() - .color(LapceColor::PANEL_HOVERED_BACKGROUND), + .color(UmideColor::PANEL_HOVERED_BACKGROUND), ) .cursor(CursorStyle::Pointer) }) @@ -167,7 +167,7 @@ pub fn common_reference_panel( s.background( config .get() - .color(LapceColor::PANEL_HOVERED_BACKGROUND), + .color(UmideColor::PANEL_HOVERED_BACKGROUND), ) .cursor(CursorStyle::Pointer) }) diff --git a/crates/umide/src/panel/kind.rs b/crates/umide/src/panel/kind.rs index d6e474a5..e4f53310 100644 --- a/crates/umide/src/panel/kind.rs +++ b/crates/umide/src/panel/kind.rs @@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize}; use strum_macros::EnumIter; use super::{data::PanelOrder, position::PanelPosition}; -use crate::config::icon::LapceIcons; +use crate::config::icon::UmideIcons; #[derive( Clone, Copy, PartialEq, Serialize, Deserialize, Hash, Eq, Debug, EnumIter, @@ -26,19 +26,19 @@ pub enum PanelKind { impl PanelKind { pub fn svg_name(&self) -> &'static str { match &self { - PanelKind::Terminal => LapceIcons::TERMINAL, - PanelKind::FileExplorer => LapceIcons::FILE_EXPLORER, - PanelKind::SourceControl => LapceIcons::SCM, - PanelKind::Plugin => LapceIcons::EXTENSIONS, - PanelKind::Search => LapceIcons::SEARCH, - PanelKind::Problem => LapceIcons::PROBLEM, - PanelKind::Debug => LapceIcons::DEBUG, - PanelKind::CallHierarchy => LapceIcons::TYPE_HIERARCHY, - PanelKind::DocumentSymbol => LapceIcons::DOCUMENT_SYMBOL, - PanelKind::References => LapceIcons::REFERENCES, - PanelKind::Implementation => LapceIcons::IMPLEMENTATION, - PanelKind::Emulator => LapceIcons::EMULATOR, - PanelKind::Video => LapceIcons::DEBUG_CONSOLE, + PanelKind::Terminal => UmideIcons::TERMINAL, + PanelKind::FileExplorer => UmideIcons::FILE_EXPLORER, + PanelKind::SourceControl => UmideIcons::SCM, + PanelKind::Plugin => UmideIcons::EXTENSIONS, + PanelKind::Search => UmideIcons::SEARCH, + PanelKind::Problem => UmideIcons::PROBLEM, + PanelKind::Debug => UmideIcons::DEBUG, + PanelKind::CallHierarchy => UmideIcons::TYPE_HIERARCHY, + PanelKind::DocumentSymbol => UmideIcons::DOCUMENT_SYMBOL, + PanelKind::References => UmideIcons::REFERENCES, + PanelKind::Implementation => UmideIcons::IMPLEMENTATION, + PanelKind::Emulator => UmideIcons::EMULATOR, + PanelKind::Video => UmideIcons::DEBUG_CONSOLE, } } diff --git a/crates/umide/src/panel/plugin_view.rs b/crates/umide/src/panel/plugin_view.rs index ac0a6107..5a23efe4 100644 --- a/crates/umide/src/panel/plugin_view.rs +++ b/crates/umide/src/panel/plugin_view.rs @@ -25,7 +25,7 @@ use super::{ use crate::{ app::not_clickable_icon, command::InternalCommand, - config::{color::LapceColor, icon::LapceIcons}, + config::{color::UmideColor, icon::UmideIcons}, plugin::{AvailableVoltData, InstalledVoltData, PluginData, VoltIcon}, text_input::TextInputBuilder, window_tab::{Focus, WindowTabData}, @@ -159,7 +159,7 @@ fn installed_view(plugin: PluginData) -> impl View { .min_width(0.0) }), not_clickable_icon( - || LapceIcons::SETTINGS, + || UmideIcons::SETTINGS, || false, || false, || "Options", @@ -186,7 +186,7 @@ fn installed_view(plugin: PluginData) -> impl View { .cursor(CursorStyle::Pointer) .hover(|s| { s.background( - config.get().color(LapceColor::PANEL_HOVERED_BACKGROUND), + config.get().color(UmideColor::PANEL_HOVERED_BACKGROUND), ) }) }) @@ -240,9 +240,9 @@ fn available_view(plugin: PluginData, core_rpc: CoreRpcHandler) -> impl View { }) .style(move |s| { let config = config.get(); - s.color(config.color(LapceColor::LAPCE_BUTTON_PRIMARY_FOREGROUND)) + s.color(config.color(UmideColor::LAPCE_BUTTON_PRIMARY_FOREGROUND)) .background( - config.color(LapceColor::LAPCE_BUTTON_PRIMARY_BACKGROUND), + config.color(UmideColor::LAPCE_BUTTON_PRIMARY_BACKGROUND), ) .margin_left(6.0) .padding_horiz(6.0) @@ -250,18 +250,18 @@ fn available_view(plugin: PluginData, core_rpc: CoreRpcHandler) -> impl View { .hover(|s| { s.cursor(CursorStyle::Pointer).background( config - .color(LapceColor::LAPCE_BUTTON_PRIMARY_BACKGROUND) + .color(UmideColor::LAPCE_BUTTON_PRIMARY_BACKGROUND) .multiply_alpha(0.8), ) }) .active(|s| { s.background( config - .color(LapceColor::LAPCE_BUTTON_PRIMARY_BACKGROUND) + .color(UmideColor::LAPCE_BUTTON_PRIMARY_BACKGROUND) .multiply_alpha(0.6), ) }) - .disabled(|s| s.background(config.color(LapceColor::EDITOR_DIM))) + .disabled(|s| s.background(config.color(UmideColor::EDITOR_DIM))) .set_disabled({ let a: bool = installed.get(); let b: bool= installing.get(); @@ -331,7 +331,7 @@ fn available_view(plugin: PluginData, core_rpc: CoreRpcHandler) -> impl View { .cursor(CursorStyle::Pointer) .hover(|s| { s.background( - config.get().color(LapceColor::PANEL_HOVERED_BACKGROUND), + config.get().color(UmideColor::PANEL_HOVERED_BACKGROUND), ) }) }) @@ -372,10 +372,10 @@ fn available_view(plugin: PluginData, core_rpc: CoreRpcHandler) -> impl View { s.width_pct(100.0) .cursor(CursorStyle::Text) .items_center() - .background(config.color(LapceColor::EDITOR_BACKGROUND)) + .background(config.color(UmideColor::EDITOR_BACKGROUND)) .border(1.0) .border_radius(6.0) - .border_color(config.color(LapceColor::LAPCE_BORDER)) + .border_color(config.color(UmideColor::LAPCE_BORDER)) }) }) .style(|s| s.padding(10.0).width_pct(100.0)), diff --git a/crates/umide/src/panel/problem_view.rs b/crates/umide/src/panel/problem_view.rs index ddb6de60..68e0ef1c 100644 --- a/crates/umide/src/panel/problem_view.rs +++ b/crates/umide/src/panel/problem_view.rs @@ -15,13 +15,13 @@ use lsp_types::{DiagnosticRelatedInformation, DiagnosticSeverity}; use super::{data::PanelSection, position::PanelPosition, view::PanelBuilder}; use crate::{ command::InternalCommand, - config::{LapceConfig, color::LapceColor, icon::LapceIcons}, + config::{UmideConfig, color::UmideColor, icon::UmideIcons}, doc::{DiagnosticData, EditorDiagnostic}, editor::location::{EditorLocation, EditorPosition}, listener::Listener, lsp::path_from_url, window_tab::WindowTabData, - workspace::LapceWorkspace, + workspace::UmideWorkspace, }; pub fn problem_panel( @@ -36,7 +36,7 @@ pub fn problem_panel( problem_section(window_tab_data.clone(), DiagnosticSeverity::ERROR), window_tab_data.panel.section_open(PanelSection::Error), move |s| { - s.border_color(config.get().color(LapceColor::LAPCE_BORDER)) + s.border_color(config.get().color(UmideColor::LAPCE_BORDER)) .apply_if(is_bottom, |s| s.border_right(1.0)) .apply_if(!is_bottom, |s| s.border_bottom(1.0)) }, @@ -81,12 +81,12 @@ fn problem_section( } fn file_view( - workspace: Arc, + workspace: Arc, path: PathBuf, diagnostic_data: DiagnosticData, severity: DiagnosticSeverity, internal_command: Listener, - config: ReadSignal>, + config: ReadSignal>, ) -> impl View { let collapsed = RwSignal::new(false); @@ -137,14 +137,14 @@ fn file_view( let style_path = path.clone(); let icon = match severity { - DiagnosticSeverity::ERROR => LapceIcons::ERROR, - _ => LapceIcons::WARNING, + DiagnosticSeverity::ERROR => UmideIcons::ERROR, + _ => UmideIcons::WARNING, }; let icon_color = move || { let config = config.get(); match severity { - DiagnosticSeverity::ERROR => config.color(LapceColor::LAPCE_ERROR), - _ => config.color(LapceColor::LAPCE_WARN), + DiagnosticSeverity::ERROR => config.color(UmideColor::LAPCE_ERROR), + _ => config.color(UmideColor::LAPCE_WARN), } }; @@ -171,7 +171,7 @@ fn file_view( .selectable(false) }), Label::new( folder.clone()).style(move |s| { - s.color(config.get().color(LapceColor::EDITOR_DIM)) + s.color(config.get().color(UmideColor::EDITOR_DIM)) .min_width(0.0) .text_ellipsis() .selectable(false) @@ -190,16 +190,16 @@ fn file_view( .padding_right(10.0) .hover(|s| { s.cursor(CursorStyle::Pointer).background( - config.color(LapceColor::PANEL_HOVERED_BACKGROUND), + config.color(UmideColor::PANEL_HOVERED_BACKGROUND), ) }) }), Stack::new(( svg(move || { config.get().ui_svg(if collapsed.get() { - LapceIcons::ITEM_CLOSED + UmideIcons::ITEM_CLOSED } else { - LapceIcons::ITEM_OPENED + UmideIcons::ITEM_OPENED }) }) .style(move |s| { @@ -207,7 +207,7 @@ fn file_view( let size = config.ui.icon_size() as f32; s.margin_right(6.0) .size(size, size) - .color(config.color(LapceColor::LAPCE_ICON_ACTIVE)) + .color(config.color(UmideColor::LAPCE_ICON_ACTIVE)) }), svg(move || config.get().file_svg(&path).0).style(move |s| { let config = config.get(); @@ -258,7 +258,7 @@ fn item_view( icon: &'static str, icon_color: impl Fn() -> Color + 'static, internal_command: Listener, - config: ReadSignal>, + config: ReadSignal>, ) -> impl View { let related = d.diagnostic.related_information.unwrap_or_default(); let position = if let Some((start, _)) = d.range { @@ -301,7 +301,7 @@ fn item_view( .style(move |s| { s.width_pct(100.0).min_width(0.0).hover(|s| { s.cursor(CursorStyle::Pointer).background( - config.get().color(LapceColor::PANEL_HOVERED_BACKGROUND), + config.get().color(UmideColor::PANEL_HOVERED_BACKGROUND), ) }) }) @@ -320,7 +320,7 @@ fn item_view( fn related_view( related: Vec, internal_command: Listener, - config: ReadSignal>, + config: ReadSignal>, ) -> impl View { let is_empty = related.is_empty(); Stack::new(( @@ -367,7 +367,7 @@ fn related_view( .min_width(0.0) .hover(|s| { s.cursor(CursorStyle::Pointer).background( - config.color(LapceColor::PANEL_HOVERED_BACKGROUND), + config.color(UmideColor::PANEL_HOVERED_BACKGROUND), ) }) }) @@ -375,11 +375,11 @@ fn related_view( ) .style(|s| s.width_pct(100.0).min_width(0.0).flex_col()), Stack::new(( - svg(move || config.get().ui_svg(LapceIcons::LINK)).style(move |s| { + svg(move || config.get().ui_svg(UmideIcons::LINK)).style(move |s| { let config = config.get(); let size = config.ui.icon_size() as f32; s.size(size, size) - .color(config.color(LapceColor::EDITOR_DIM)) + .color(config.color(UmideColor::EDITOR_DIM)) }), Label::new(" ".to_string()).style(move |s| s.selectable(false)), )) @@ -393,7 +393,7 @@ fn related_view( s.width_pct(100.0) .min_width(0.0) .items_start() - .color(config.get().color(LapceColor::EDITOR_DIM)) + .color(config.get().color(UmideColor::EDITOR_DIM)) .apply_if(is_empty, |s| s.hide()) }) } diff --git a/crates/umide/src/panel/source_control_view.rs b/crates/umide/src/panel/source_control_view.rs index 6002ded8..ed155c69 100644 --- a/crates/umide/src/panel/source_control_view.rs +++ b/crates/umide/src/panel/source_control_view.rs @@ -21,8 +21,8 @@ use super::{ view::foldable_panel_section, }; use crate::{ - command::{CommandKind, InternalCommand, LapceCommand, LapceWorkbenchCommand}, - config::{color::LapceColor, icon::LapceIcons}, + command::{CommandKind, InternalCommand, UmideCommand, UmideWorkbenchCommand}, + config::{color::UmideColor, icon::UmideIcons}, editor::view::editor_view, settings::checkbox, source_control::SourceControlData, @@ -71,7 +71,7 @@ pub fn source_control_panel( s.absolute() .items_center() .height(config.editor.line_height() as f32) - .color(config.color(LapceColor::EDITOR_DIM)) + .color(config.color(UmideColor::EDITOR_DIM)) .apply_if(!is_empty.get(), |s| s.hide()) .selectable(false) }), @@ -144,8 +144,8 @@ pub fn source_control_panel( .border(1.0) .padding(-1.0) .border_radius(6.0) - .border_color(config.color(LapceColor::LAPCE_BORDER)) - .background(config.color(LapceColor::EDITOR_BACKGROUND)) + .border_color(config.color(UmideColor::LAPCE_BORDER)) + .background(config.color(UmideColor::EDITOR_BACKGROUND)) }), { let source_control = source_control.clone(); @@ -161,16 +161,16 @@ pub fn source_control_panel( .justify_center() .border(1.0) .border_radius(6.0) - .border_color(config.color(LapceColor::LAPCE_BORDER)) + .border_color(config.color(UmideColor::LAPCE_BORDER)) .hover(|s| { s.cursor(CursorStyle::Pointer).background( config - .color(LapceColor::PANEL_HOVERED_BACKGROUND), + .color(UmideColor::PANEL_HOVERED_BACKGROUND), ) }) .active(|s| { s.background(config.color( - LapceColor::PANEL_HOVERED_ACTIVE_BACKGROUND, + UmideColor::PANEL_HOVERED_ACTIVE_BACKGROUND, )) }) .selectable(false) @@ -267,17 +267,17 @@ fn file_diffs_view(source_control: SourceControlData) -> impl View { s.text_ellipsis() .flex_grow(1.0) .flex_basis(0.0) - .color(config.get().color(LapceColor::EDITOR_DIM)) + .color(config.get().color(UmideColor::EDITOR_DIM)) .min_width(0.0) .selectable(false) }), Container::new({ svg(move || { let svg = match &diff { - FileDiff::Modified(_) => LapceIcons::SCM_DIFF_MODIFIED, - FileDiff::Added(_) => LapceIcons::SCM_DIFF_ADDED, - FileDiff::Deleted(_) => LapceIcons::SCM_DIFF_REMOVED, - FileDiff::Renamed(_, _) => LapceIcons::SCM_DIFF_RENAMED, + FileDiff::Modified(_) => UmideIcons::SCM_DIFF_MODIFIED, + FileDiff::Added(_) => UmideIcons::SCM_DIFF_ADDED, + FileDiff::Deleted(_) => UmideIcons::SCM_DIFF_REMOVED, + FileDiff::Renamed(_, _) => UmideIcons::SCM_DIFF_RENAMED, }; config.get().ui_svg(svg) }) @@ -285,11 +285,11 @@ fn file_diffs_view(source_control: SourceControlData) -> impl View { let config = config.get(); let size = config.ui.icon_size() as f32; let color = match &diff_for_style { - FileDiff::Modified(_) => LapceColor::SOURCE_CONTROL_MODIFIED, - FileDiff::Added(_) => LapceColor::SOURCE_CONTROL_ADDED, - FileDiff::Deleted(_) => LapceColor::SOURCE_CONTROL_REMOVED, + FileDiff::Modified(_) => UmideColor::SOURCE_CONTROL_MODIFIED, + FileDiff::Added(_) => UmideColor::SOURCE_CONTROL_ADDED, + FileDiff::Deleted(_) => UmideColor::SOURCE_CONTROL_REMOVED, FileDiff::Renamed(_, _) => { - LapceColor::SOURCE_CONTROL_MODIFIED + UmideColor::SOURCE_CONTROL_MODIFIED } }; let color = config.color(color); @@ -313,9 +313,9 @@ fn file_diffs_view(source_control: SourceControlData) -> impl View { let diff_for_menu = diff_for_menu.clone(); let discard = move || { - lapce_command.send(LapceCommand { + lapce_command.send(UmideCommand { kind: CommandKind::Workbench( - LapceWorkbenchCommand::SourceControlDiscardTargetFileChanges, + UmideWorkbenchCommand::SourceControlDiscardTargetFileChanges, ), data: Some(serde_json::json!(diff_for_menu.clone())), }); @@ -336,7 +336,7 @@ fn file_diffs_view(source_control: SourceControlData) -> impl View { .items_center() .cursor(CursorStyle::Pointer) .hover(|s| { - s.background(config.color(LapceColor::PANEL_HOVERED_BACKGROUND)) + s.background(config.color(UmideColor::PANEL_HOVERED_BACKGROUND)) }) }) }; diff --git a/crates/umide/src/panel/terminal_view.rs b/crates/umide/src/panel/terminal_view.rs index 2c9670d4..27574888 100644 --- a/crates/umide/src/panel/terminal_view.rs +++ b/crates/umide/src/panel/terminal_view.rs @@ -10,8 +10,8 @@ use umide_rpc::terminal::TermId; use super::kind::PanelKind; use crate::{ app::clickable_icon, - command::{InternalCommand, LapceWorkbenchCommand}, - config::{color::LapceColor, icon::LapceIcons}, + command::{InternalCommand, UmideWorkbenchCommand}, + config::{color::UmideColor, icon::UmideIcons}, debug::RunDebugMode, listener::Listener, terminal::{ @@ -91,17 +91,17 @@ fn terminal_tab_header(window_tab_data: Rc) -> impl View { run_debug.as_ref().map(|r| (r.mode, r.stopped)) }) { let svg = match (mode, stopped) { - (RunDebugMode::Run, false) => LapceIcons::START, - (RunDebugMode::Run, true) => LapceIcons::RUN_ERRORS, - (RunDebugMode::Debug, false) => LapceIcons::DEBUG, + (RunDebugMode::Run, false) => UmideIcons::START, + (RunDebugMode::Run, true) => UmideIcons::RUN_ERRORS, + (RunDebugMode::Debug, false) => UmideIcons::DEBUG, (RunDebugMode::Debug, true) => { - LapceIcons::DEBUG_DISCONNECT + UmideIcons::DEBUG_DISCONNECT } }; return svg; } } - LapceIcons::TERMINAL + UmideIcons::TERMINAL }; Stack::new(( Container::new({ @@ -113,7 +113,7 @@ fn terminal_tab_header(window_tab_data: Rc) -> impl View { let size = config.ui.icon_size() as f32; s.size(size, size).color( config.color( - LapceColor::LAPCE_ICON_ACTIVE, + UmideColor::LAPCE_ICON_ACTIVE, ), ) }), @@ -127,7 +127,7 @@ fn terminal_tab_header(window_tab_data: Rc) -> impl View { .selectable(false) }), clickable_icon( - || LapceIcons::CLOSE, + || UmideIcons::CLOSE, move || { terminal.close_tab(Some(terminal_tab_id)); }, @@ -143,14 +143,14 @@ fn terminal_tab_header(window_tab_data: Rc) -> impl View { .height(header_height.get() - 15.0) .border_right(1.0) .border_color( - config.get().color(LapceColor::LAPCE_BORDER), + config.get().color(UmideColor::LAPCE_BORDER), ) .pointer_events_none() }), )) .style(move |s| { s.items_center().width(200.0).border_color( - config.get().color(LapceColor::LAPCE_BORDER), + config.get().color(UmideColor::LAPCE_BORDER), ) }) }) @@ -167,9 +167,9 @@ fn terminal_tab_header(window_tab_data: Rc) -> impl View { if focus.get() == Focus::Panel(PanelKind::Terminal) { - LapceColor::LAPCE_TAB_ACTIVE_UNDERLINE + UmideColor::LAPCE_TAB_ACTIVE_UNDERLINE } else { - LapceColor::LAPCE_TAB_INACTIVE_UNDERLINE + UmideColor::LAPCE_TAB_INACTIVE_UNDERLINE }, )) }) @@ -215,9 +215,9 @@ fn terminal_tab_header(window_tab_data: Rc) -> impl View { s.size(size.width, size.height).pointer_events_none() }), Container::new(clickable_icon( - || LapceIcons::ADD, + || UmideIcons::ADD, move || { - workbench_command.send(LapceWorkbenchCommand::NewTerminalTab); + workbench_command.send(UmideWorkbenchCommand::NewTerminalTab); }, || false, || false, @@ -252,7 +252,7 @@ fn terminal_tab_header(window_tab_data: Rc) -> impl View { s.width_pct(100.0) .items_center() .border_bottom(1.0) - .border_color(config.color(LapceColor::LAPCE_BORDER)) + .border_color(config.color(UmideColor::LAPCE_BORDER)) }) } @@ -326,7 +326,7 @@ fn terminal_tab_split( index.get() > 0, |s| { s.border_left(1.0).border_color( - config.get().color(LapceColor::LAPCE_BORDER), + config.get().color(UmideColor::LAPCE_BORDER), ) }, ) diff --git a/crates/umide/src/panel/view.rs b/crates/umide/src/panel/view.rs index aa8f3fed..62e3c817 100644 --- a/crates/umide/src/panel/view.rs +++ b/crates/umide/src/panel/view.rs @@ -22,7 +22,7 @@ use super::{ }; use crate::{ app::{clickable_icon, clickable_icon_base}, - config::{LapceConfig, color::LapceColor, icon::LapceIcons}, + config::{UmideConfig, color::UmideColor, icon::UmideIcons}, file_explorer::view::file_explorer_panel, panel::{ call_hierarchy_view::show_hierarchy_panel, document_symbol::symbol_panel, @@ -36,16 +36,16 @@ pub fn foldable_panel_section( header: impl View + 'static, child: impl View + 'static, open: RwSignal, - config: ReadSignal>, + config: ReadSignal>, ) -> impl View { Stack::new(( Stack::horizontal(( clickable_icon_base( move || { if open.get() { - LapceIcons::PANEL_FOLD_DOWN + UmideIcons::PANEL_FOLD_DOWN } else { - LapceIcons::PANEL_FOLD_UP + UmideIcons::PANEL_FOLD_UP } }, None::>, @@ -60,7 +60,7 @@ pub fn foldable_panel_section( .padding_vert(6.0) .width_pct(100.0) .cursor(CursorStyle::Pointer) - .background(config.get().color(LapceColor::EDITOR_BACKGROUND)) + .background(config.get().color(UmideColor::EDITOR_BACKGROUND)) }) .on_click_stop(move |_| { open.update(|open| *open = !*open); @@ -72,12 +72,12 @@ pub fn foldable_panel_section( /// A builder for creating a foldable panel out of sections pub struct PanelBuilder { views: Vec, - config: ReadSignal>, + config: ReadSignal>, position: PanelPosition, } impl PanelBuilder { pub fn new( - config: ReadSignal>, + config: ReadSignal>, position: PanelPosition, ) -> Self { Self { @@ -252,7 +252,7 @@ pub fn panel_container_view( s.background( config .get() - .color(LapceColor::EDITOR_DRAG_DROP_BACKGROUND), + .color(UmideColor::EDITOR_DRAG_DROP_BACKGROUND), ) }) }) @@ -359,7 +359,7 @@ pub fn panel_container_view( s.width(4.0).margin_left(-2.0).height_pct(100.0) }) .apply_if(is_dragging, |s| { - s.background(config.color(LapceColor::EDITOR_CARET)) + s.background(config.color(UmideColor::EDITOR_CARET)) .apply_if( position == PanelContainerPosition::Bottom, |s| s.cursor(CursorStyle::RowResize), @@ -371,7 +371,7 @@ pub fn panel_container_view( .z_index(2) }) .hover(|s| { - s.background(config.color(LapceColor::EDITOR_CARET)) + s.background(config.color(UmideColor::EDITOR_CARET)) .apply_if( position == PanelContainerPosition::Bottom, |s| s.cursor(CursorStyle::RowResize), @@ -429,17 +429,17 @@ pub fn panel_container_view( s.border_right(1.0) .width(size as f32) .height_pct(100.0) - .background(config.color(LapceColor::PANEL_BACKGROUND)) + .background(config.color(UmideColor::PANEL_BACKGROUND)) }) .apply_if(position == PanelContainerPosition::Right, |s| { s.border_left(1.0) .width(size as f32) .height_pct(100.0) - .background(config.color(LapceColor::PANEL_BACKGROUND)) + .background(config.color(UmideColor::PANEL_BACKGROUND)) }) .apply_if(!is_bottom, |s| s.flex_col()) - .border_color(config.color(LapceColor::LAPCE_BORDER)) - .color(config.color(LapceColor::PANEL_FOREGROUND)) + .border_color(config.color(UmideColor::LAPCE_BORDER)) + .color(config.color(UmideColor::PANEL_FOREGROUND)) }) .debug_name(format!("{:?} Pannel Container View", position)) } @@ -523,13 +523,13 @@ fn panel_view( pub fn panel_header( header: String, - config: ReadSignal>, + config: ReadSignal>, ) -> impl View { Container::new(Label::new(header.clone())).style(move |s| { s.padding_horiz(10.0) .padding_vert(6.0) .width_pct(100.0) - .background(config.get().color(LapceColor::EDITOR_BACKGROUND)) + .background(config.get().color(UmideColor::EDITOR_BACKGROUND)) }) } @@ -602,11 +602,11 @@ fn panel_picker( let config = config.get(); s.border(1.0) .border_radius(6.0) - .border_color(config.color(LapceColor::LAPCE_BORDER)) + .border_color(config.color(UmideColor::LAPCE_BORDER)) .padding(6.0) .background( config - .color(LapceColor::PANEL_BACKGROUND) + .color(UmideColor::PANEL_BACKGROUND) .multiply_alpha(0.7), ) }) @@ -633,7 +633,7 @@ fn panel_picker( .border_color( config .get() - .color(LapceColor::LAPCE_TAB_ACTIVE_UNDERLINE), + .color(UmideColor::LAPCE_TAB_ACTIVE_UNDERLINE), ) }), ))) @@ -641,7 +641,7 @@ fn panel_picker( }, ) .style(move |s| { - s.border_color(config.get().color(LapceColor::LAPCE_BORDER)) + s.border_color(config.get().color(UmideColor::LAPCE_BORDER)) .apply_if( panels.with(|p| { p.get(&position).map(|p| p.is_empty()).unwrap_or(true) diff --git a/crates/umide/src/plugin.rs b/crates/umide/src/plugin.rs index 14eed065..6583ddbc 100644 --- a/crates/umide/src/plugin.rs +++ b/crates/umide/src/plugin.rs @@ -35,8 +35,8 @@ use sha2::{Digest, Sha256}; use crate::{ command::{CommandExecuted, CommandKind}, - config::{LapceConfig, color::LapceColor}, - db::LapceDb, + config::{UmideConfig, color::UmideColor}, + db::UmideDb, editor::EditorData, keypress::{KeyPressFocus, condition::Condition}, main_split::Editors, @@ -120,7 +120,7 @@ impl KeyPressFocus for PluginData { fn run_command( &self, - command: &crate::command::LapceCommand, + command: &crate::command::UmideCommand, count: Option, mods: Modifiers, ) -> CommandExecuted { @@ -313,7 +313,7 @@ impl PluginData { self.disabled.update(|d| { d.remove(&id); }); - let db: Arc = Context::get().unwrap(); + let db: Arc = Context::get().unwrap(); db.save_disabled_volts( self.disabled.get_untracked().into_iter().collect(), ); @@ -323,7 +323,7 @@ impl PluginData { self.workspace_disabled.update(|d| { d.remove(&id); }); - let db: Arc = Context::get().unwrap(); + let db: Arc = Context::get().unwrap(); db.save_workspace_disabled_volts( self.common.workspace.clone(), self.workspace_disabled @@ -451,7 +451,7 @@ impl PluginData { fn download_readme( volt: &VoltInfo, - config: &LapceConfig, + config: &UmideConfig, ) -> Result> { let url = format!( "https://plugins.lapce.dev/api/v1/plugins/{}/{}/{}/readme", @@ -535,7 +535,7 @@ impl PluginData { if !self.plugin_disabled(&id) { self.common.proxy.enable_volt(volt); } - let db: Arc = Context::get().unwrap(); + let db: Arc = Context::get().unwrap(); db.save_disabled_volts(self.disabled.get_untracked().into_iter().collect()); } @@ -545,7 +545,7 @@ impl PluginData { d.insert(id); }); self.common.proxy.disable_volt(volt); - let db: Arc = Context::get().unwrap(); + let db: Arc = Context::get().unwrap(); db.save_disabled_volts(self.disabled.get_untracked().into_iter().collect()); } @@ -557,7 +557,7 @@ impl PluginData { if !self.plugin_disabled(&id) { self.common.proxy.enable_volt(volt); } - let db: Arc = Context::get().unwrap(); + let db: Arc = Context::get().unwrap(); db.save_workspace_disabled_volts( self.common.workspace.clone(), self.disabled.get_untracked().into_iter().collect(), @@ -570,7 +570,7 @@ impl PluginData { d.insert(id); }); self.common.proxy.disable_volt(volt); - let db: Arc = Context::get().unwrap(); + let db: Arc = Context::get().unwrap(); db.save_workspace_disabled_volts( self.common.workspace.clone(), self.disabled.get_untracked().into_iter().collect(), @@ -769,17 +769,17 @@ pub fn plugin_info_view(plugin: PluginData, volt: VoltID) -> impl View { .border_radius(6.0) .color( config - .color(LapceColor::LAPCE_BUTTON_PRIMARY_FOREGROUND), + .color(UmideColor::LAPCE_BUTTON_PRIMARY_FOREGROUND), ) .background( config - .color(LapceColor::LAPCE_BUTTON_PRIMARY_BACKGROUND), + .color(UmideColor::LAPCE_BUTTON_PRIMARY_BACKGROUND), ) .hover(|s| { s.cursor(CursorStyle::Pointer).background( config .color( - LapceColor::LAPCE_BUTTON_PRIMARY_BACKGROUND, + UmideColor::LAPCE_BUTTON_PRIMARY_BACKGROUND, ) .multiply_alpha(0.8), ) @@ -788,13 +788,13 @@ pub fn plugin_info_view(plugin: PluginData, volt: VoltID) -> impl View { s.background( config .color( - LapceColor::LAPCE_BUTTON_PRIMARY_BACKGROUND, + UmideColor::LAPCE_BUTTON_PRIMARY_BACKGROUND, ) .multiply_alpha(0.6), ) }) .disabled(|s| { - s.background(config.color(LapceColor::EDITOR_DIM)) + s.background(config.color(UmideColor::EDITOR_DIM)) }) .selectable(false) .set_disabled(installing.map(|i| i.get()).unwrap_or(false)) @@ -891,7 +891,7 @@ pub fn plugin_info_view(plugin: PluginData, volt: VoltID) -> impl View { move || { config .get() - .color(LapceColor::EDITOR_LINK) + .color(UmideColor::EDITOR_LINK) }, internal_command, ), @@ -904,7 +904,7 @@ pub fn plugin_info_view(plugin: PluginData, volt: VoltID) -> impl View { .unwrap_or(""), ) .style(move |s| { - s.color(config.get().color(LapceColor::EDITOR_DIM)) + s.color(config.get().color(UmideColor::EDITOR_DIM)) }), version_view(local_plugin.clone(), plugin_info.clone()), )) @@ -924,7 +924,7 @@ pub fn plugin_info_view(plugin: PluginData, volt: VoltID) -> impl View { s.margin_vert(6) .height(1) .width_full() - .background(config.get().color(LapceColor::LAPCE_BORDER)) + .background(config.get().color(UmideColor::LAPCE_BORDER)) }), { let readme = RwSignal::new(None); @@ -982,7 +982,7 @@ pub fn plugin_info_view(plugin: PluginData, volt: VoltID) -> impl View { .height(1.0) .background( config.get().color( - LapceColor::LAPCE_BORDER, + UmideColor::LAPCE_BORDER, ), ) })) diff --git a/crates/umide/src/proxy.rs b/crates/umide/src/proxy.rs index c56b5ade..9c2ae0f1 100644 --- a/crates/umide/src/proxy.rs +++ b/crates/umide/src/proxy.rs @@ -18,7 +18,7 @@ use tracing::error; use self::{remote::start_remote, ssh::SshRemote}; use crate::{ terminal::event::TermEvent, - workspace::{LapceWorkspace, LapceWorkspaceType}, + workspace::{UmideWorkspace, UmideWorkspaceType}, }; mod remote; @@ -46,7 +46,7 @@ impl ProxyData { } pub fn new_proxy( - workspace: Arc, + workspace: Arc, disabled_volts: Vec, extra_plugin_paths: Vec, plugin_configurations: HashMap>, @@ -74,14 +74,14 @@ pub fn new_proxy( ); match &workspace.kind { - LapceWorkspaceType::Local => { + UmideWorkspaceType::Local => { let core_rpc = core_rpc.clone(); let proxy_rpc = proxy_rpc.clone(); let mut dispatcher = Dispatcher::new(core_rpc, proxy_rpc); let proxy_rpc = dispatcher.proxy_rpc.clone(); proxy_rpc.mainloop(&mut dispatcher); } - LapceWorkspaceType::RemoteSSH(remote) => { + UmideWorkspaceType::RemoteSSH(remote) => { if let Err(e) = start_remote( SshRemote { ssh: remote.clone(), @@ -93,7 +93,7 @@ pub fn new_proxy( } } #[cfg(windows)] - LapceWorkspaceType::RemoteWSL(remote) => { + UmideWorkspaceType::RemoteWSL(remote) => { if let Err(e) = start_remote( wsl::WslRemote { wsl: remote.clone(), diff --git a/crates/umide/src/proxy/remote.rs b/crates/umide/src/proxy/remote.rs index 8514ee3f..e1a0c639 100644 --- a/crates/umide/src/proxy/remote.rs +++ b/crates/umide/src/proxy/remote.rs @@ -123,10 +123,10 @@ pub fn start_remote( .output() .map(|output| { if meta::RELEASE == ReleaseType::Debug { - String::from_utf8_lossy(&output.stdout).starts_with("Lapce-proxy") + String::from_utf8_lossy(&output.stdout).starts_with("Umide-proxy") } else { String::from_utf8_lossy(&output.stdout).trim() - == format!("Lapce-proxy {}", meta::VERSION) + == format!("Umide-proxy {}", meta::VERSION) } }) .unwrap_or(false) diff --git a/crates/umide/src/rename.rs b/crates/umide/src/rename.rs index 271d5c52..56933c52 100644 --- a/crates/umide/src/rename.rs +++ b/crates/umide/src/rename.rs @@ -12,7 +12,7 @@ use lapce_xi_rope::Rope; use lsp_types::Position; use crate::{ - command::{CommandExecuted, CommandKind, InternalCommand, LapceCommand}, + command::{CommandExecuted, CommandKind, InternalCommand, UmideCommand}, editor::EditorData, keypress::{KeyPressFocus, condition::Condition}, main_split::Editors, @@ -41,7 +41,7 @@ impl KeyPressFocus for RenameData { fn run_command( &self, - command: &LapceCommand, + command: &UmideCommand, count: Option, mods: Modifiers, ) -> CommandExecuted { diff --git a/crates/umide/src/settings.rs b/crates/umide/src/settings.rs index 54b5e39a..0b31cfaa 100644 --- a/crates/umide/src/settings.rs +++ b/crates/umide/src/settings.rs @@ -29,8 +29,8 @@ use serde_json::Value; use crate::{ command::CommandExecuted, config::{ - DropdownInfo, LapceConfig, color::LapceColor, core::CoreConfig, - editor::EditorConfig, icon::LapceIcons, terminal::TerminalConfig, + DropdownInfo, UmideConfig, color::UmideColor, core::CoreConfig, + editor::EditorConfig, icon::UmideIcons, terminal::TerminalConfig, ui::UIConfig, }, keypress::KeyPressFocus, @@ -106,7 +106,7 @@ impl KeyPressFocus for SettingsData { fn run_command( &self, - _command: &crate::command::LapceCommand, + _command: &crate::command::UmideCommand, _count: Option, _mods: Modifiers, ) -> crate::command::CommandExecuted { @@ -415,16 +415,16 @@ pub fn settings_view( s.padding_horiz(20.0) .width_pct(100.0) .apply_if(kind == current_kind.get(), |s| { - s.background(config.color(LapceColor::PANEL_CURRENT_BACKGROUND)) + s.background(config.color(UmideColor::PANEL_CURRENT_BACKGROUND)) }) .hover(|s| { s.cursor(CursorStyle::Pointer).background( - config.color(LapceColor::PANEL_HOVERED_BACKGROUND), + config.color(UmideColor::PANEL_HOVERED_BACKGROUND), ) }) .active(|s| { s.background( - config.color(LapceColor::PANEL_HOVERED_ACTIVE_BACKGROUND), + config.color(UmideColor::PANEL_HOVERED_ACTIVE_BACKGROUND), ) }) }) @@ -482,7 +482,7 @@ pub fn settings_view( s.height_pct(100.0) .width(200.0) .border_right(1.0) - .border_color(config.get().color(LapceColor::LAPCE_BORDER)) + .border_color(config.get().color(UmideColor::LAPCE_BORDER)) }), Stack::new(( Container::new({ @@ -495,7 +495,7 @@ pub fn settings_view( .border_radius(6.0) .border(1.0) .border_color( - config.get().color(LapceColor::LAPCE_BORDER), + config.get().color(UmideColor::LAPCE_BORDER), ) }) .request_focus(|| {}) @@ -626,7 +626,7 @@ fn settings_item_view( }; if let Some(value) = value { - LapceConfig::update_file( + UmideConfig::update_file( &kind, &field, value, ); } @@ -642,7 +642,7 @@ fn settings_item_view( .style(|s| s.focusable(true)) .style(move |s| { s.width(300.0).border(1.0).border_radius(6.0).border_color( - config.get().color(LapceColor::LAPCE_BORDER), + config.get().color(UmideColor::LAPCE_BORDER), ) }) .into_any() @@ -674,7 +674,7 @@ fn settings_item_view( .width_pct(100.0) .padding_horiz(10.0) .font_size(config.ui.font_size() as f32 + 2.0) - .background(config.color(LapceColor::PANEL_BACKGROUND)) + .background(config.color(UmideColor::PANEL_BACKGROUND)) }) .into_any() } else { @@ -716,7 +716,7 @@ fn settings_item_view( &checked, toml_edit::ser::ValueSerializer::new(), ) { - LapceConfig::update_file(&kind, &field, value); + UmideConfig::update_file(&kind, &field, value); } }); @@ -764,7 +764,7 @@ fn settings_item_view( pub fn checkbox( checked: impl Fn() -> bool + 'static, - config: ReadSignal>, + config: ReadSignal>, ) -> impl View { const CHECKBOX_SVG: &str = r#""#; let svg_str = move || if checked() { CHECKBOX_SVG } else { "" }.to_string(); @@ -772,7 +772,7 @@ pub fn checkbox( svg(svg_str).style(move |s| { let config = config.get(); let size = config.ui.font_size() as f32; - let color = config.color(LapceColor::EDITOR_FOREGROUND); + let color = config.color(UmideColor::EDITOR_FOREGROUND); s.min_width(size) .size(size, size) @@ -914,14 +914,14 @@ fn color_section_list( .ok(); if let Some(value) = value { - LapceConfig::update_file( + UmideConfig::update_file( &format!("color-theme.{kind}"), &field, value, ); } } else { - LapceConfig::reset_setting( + UmideConfig::reset_setting( &format!("color-theme.{kind}"), &field, ); @@ -947,7 +947,7 @@ fn color_section_list( .border(1) .border_radius(6) .border_color( - config.get().color(LapceColor::LAPCE_BORDER), + config.get().color(UmideColor::LAPCE_BORDER), ) }), Empty::new().style(move |s| { @@ -963,9 +963,9 @@ fn color_section_list( .border_radius(6) .size(size, size) .margin_left(10) - .border_color(config.color(LapceColor::LAPCE_BORDER)) + .border_color(config.color(UmideColor::LAPCE_BORDER)) .background(color.unwrap_or_else(|| { - config.color(LapceColor::EDITOR_FOREGROUND) + config.color(UmideColor::EDITOR_FOREGROUND) })) }), { @@ -975,7 +975,7 @@ fn color_section_list( let local_kind = kind.clone(); Label::new("Reset") .on_click_stop(move |_| { - LapceConfig::reset_setting( + UmideConfig::reset_setting( &format!("color-theme.{local_kind}"), &local_key, ); @@ -1008,13 +1008,13 @@ fn color_section_list( .border(1) .border_radius(6) .border_color( - config.color(LapceColor::LAPCE_BORDER), + config.color(UmideColor::LAPCE_BORDER), ) .apply_if(same, |s| s.hide()) .active(|s| { s.background( config - .color(LapceColor::PANEL_BACKGROUND), + .color(UmideColor::PANEL_BACKGROUND), ) }) }) @@ -1092,7 +1092,7 @@ pub fn theme_color_settings_view( .border_radius(6.0) .border(1.0) .border_color( - config.get().color(LapceColor::LAPCE_BORDER), + config.get().color(UmideColor::LAPCE_BORDER), ) }) .request_focus(|| {}) @@ -1184,7 +1184,7 @@ fn dropdown_view( dropdown: &DropdownInfo, expanded: RwSignal, window_size: RwSignal, - config: ReadSignal>, + config: ReadSignal>, ) -> impl View + use<> { let window_origin = RwSignal::new(Point::ZERO); let size = RwSignal::new(Size::ZERO); @@ -1231,16 +1231,16 @@ fn dropdown_view( Container::new( svg(move || { if expanded.get() { - config.get().ui_svg(LapceIcons::CLOSE) + config.get().ui_svg(UmideIcons::CLOSE) } else { - config.get().ui_svg(LapceIcons::DROPDOWN_ARROW) + config.get().ui_svg(UmideIcons::DROPDOWN_ARROW) } }) .style(move |s| { let config = config.get(); let size = config.ui.icon_size() as f32; s.size(size, size) - .color(config.color(LapceColor::LAPCE_ICON_ACTIVE)) + .color(config.color(UmideColor::LAPCE_ICON_ACTIVE)) }), ) .style(|s| s.padding_right(4.0)), @@ -1262,7 +1262,7 @@ fn dropdown_view( .style(move |s| { s.items_center() .cursor(CursorStyle::Pointer) - .border_color(config.get().color(LapceColor::LAPCE_BORDER)) + .border_color(config.get().color(UmideColor::LAPCE_BORDER)) .border(1.0) .border_radius(6.0) .width(250.0) @@ -1296,7 +1296,7 @@ fn dropdown_scroll_view( window_origin: RwSignal, input_size: RwSignal, window_size: RwSignal, - config: ReadSignal>, + config: ReadSignal>, ) -> impl View + use<> { dropdown_scroll_focus.set(true); @@ -1313,14 +1313,14 @@ fn dropdown_scroll_view( &item_string, toml_edit::ser::ValueSerializer::new(), ) { - LapceConfig::update_file(&kind, &field, value); + UmideConfig::update_file(&kind, &field, value); } expanded.set(false); }) .style(move |s| { s.text_ellipsis().padding_horiz(10.0).hover(|s| { s.cursor(CursorStyle::Pointer).background( - config.get().color(LapceColor::PANEL_HOVERED_BACKGROUND), + config.get().color(UmideColor::PANEL_HOVERED_BACKGROUND), ) }) }) @@ -1380,16 +1380,16 @@ fn dropdown_scroll_view( .line_height(1.8) .font_size(config.ui.font_size() as f32) .font_family(config.ui.font_family.clone()) - .color(config.color(LapceColor::EDITOR_FOREGROUND)) - .background(config.color(LapceColor::EDITOR_BACKGROUND)) + .color(config.color(UmideColor::EDITOR_FOREGROUND)) + .background(config.color(UmideColor::EDITOR_BACKGROUND)) .class(floem::views::scroll::Handle, |s| { - s.background(config.color(LapceColor::LAPCE_SCROLL_BAR)) + s.background(config.color(UmideColor::LAPCE_SCROLL_BAR)) }) .border(1) .border_radius(6.0) - .border_color(config.color(LapceColor::LAPCE_BORDER)) + .border_color(config.color(UmideColor::LAPCE_BORDER)) .box_shadow_blur(3.0) - .box_shadow_color(config.color(LapceColor::LAPCE_DROPDOWN_SHADOW)) + .box_shadow_color(config.color(UmideColor::LAPCE_DROPDOWN_SHADOW)) .inset_left(x) .inset_top(y) }) diff --git a/crates/umide/src/source_control.rs b/crates/umide/src/source_control.rs index c1a5aeb4..518eb131 100644 --- a/crates/umide/src/source_control.rs +++ b/crates/umide/src/source_control.rs @@ -41,7 +41,7 @@ impl KeyPressFocus for SourceControlData { fn run_command( &self, - command: &crate::command::LapceCommand, + command: &crate::command::UmideCommand, count: Option, mods: Modifiers, ) -> CommandExecuted { diff --git a/crates/umide/src/status.rs b/crates/umide/src/status.rs index 6ee0f75c..c9efb58e 100644 --- a/crates/umide/src/status.rs +++ b/crates/umide/src/status.rs @@ -18,8 +18,8 @@ use lsp_types::{DiagnosticSeverity, ProgressToken}; use crate::{ app::clickable_icon, - command::LapceWorkbenchCommand, - config::{LapceConfig, color::LapceColor, icon::LapceIcons}, + command::UmideWorkbenchCommand, + config::{UmideConfig, color::UmideColor, icon::UmideIcons}, editor::EditorData, listener::Listener, palette::kind::PaletteKind, @@ -31,9 +31,9 @@ use crate::{ pub fn status( window_tab_data: Rc, source_control: SourceControlData, - workbench_command: Listener, + workbench_command: Listener, status_height: RwSignal, - _config: ReadSignal>, + _config: ReadSignal>, ) -> impl View { let config = window_tab_data.common.config; let diagnostics = window_tab_data.main_split.diagnostics; @@ -96,20 +96,20 @@ pub fn status( let (bg, fg) = match mode.get() { Mode::Normal => ( - LapceColor::STATUS_MODAL_NORMAL_BACKGROUND, - LapceColor::STATUS_MODAL_NORMAL_FOREGROUND, + UmideColor::STATUS_MODAL_NORMAL_BACKGROUND, + UmideColor::STATUS_MODAL_NORMAL_FOREGROUND, ), Mode::Insert => ( - LapceColor::STATUS_MODAL_INSERT_BACKGROUND, - LapceColor::STATUS_MODAL_INSERT_FOREGROUND, + UmideColor::STATUS_MODAL_INSERT_BACKGROUND, + UmideColor::STATUS_MODAL_INSERT_FOREGROUND, ), Mode::Visual(_) => ( - LapceColor::STATUS_MODAL_VISUAL_BACKGROUND, - LapceColor::STATUS_MODAL_VISUAL_FOREGROUND, + UmideColor::STATUS_MODAL_VISUAL_BACKGROUND, + UmideColor::STATUS_MODAL_VISUAL_FOREGROUND, ), Mode::Terminal => ( - LapceColor::STATUS_MODAL_TERMINAL_BACKGROUND, - LapceColor::STATUS_MODAL_TERMINAL_FOREGROUND, + UmideColor::STATUS_MODAL_TERMINAL_BACKGROUND, + UmideColor::STATUS_MODAL_TERMINAL_FOREGROUND, ), }; @@ -125,15 +125,15 @@ pub fn status( .selectable(false) }), Stack::new(( - svg(move || config.get().ui_svg(LapceIcons::SCM)).style(move |s| { + svg(move || config.get().ui_svg(UmideIcons::SCM)).style(move |s| { let config = config.get(); let icon_size = config.ui.icon_size() as f32; s.size(icon_size, icon_size) - .color(config.color(LapceColor::LAPCE_ICON_ACTIVE)) + .color(config.color(UmideColor::LAPCE_ICON_ACTIVE)) }), Label::derived(branch).style(move |s| { s.margin_left(10.0) - .color(config.get().color(LapceColor::STATUS_FOREGROUND)) + .color(config.get().color(UmideColor::STATUS_FOREGROUND)) .selectable(false) }), )) @@ -148,7 +148,7 @@ pub fn status( .align_items(Some(AlignItems::Center)) .hover(|s| { s.cursor(CursorStyle::Pointer).background( - config.get().color(LapceColor::PANEL_HOVERED_BACKGROUND), + config.get().color(UmideColor::PANEL_HOVERED_BACKGROUND), ) }) }) @@ -160,7 +160,7 @@ pub fn status( move |_| { if pointer_down.get() { workbench_command - .send(LapceWorkbenchCommand::PaletteSCMReferences); + .send(UmideWorkbenchCommand::PaletteSCMReferences); } pointer_down.set(false); EventPropagation::Continue @@ -169,12 +169,12 @@ pub fn status( { let panel = panel.clone(); Stack::new(( - svg(move || config.get().ui_svg(LapceIcons::ERROR)).style( + svg(move || config.get().ui_svg(UmideIcons::ERROR)).style( move |s| { let config = config.get(); let size = config.ui.icon_size() as f32; s.size(size, size) - .color(config.color(LapceColor::LAPCE_ICON_ACTIVE)) + .color(config.color(UmideColor::LAPCE_ICON_ACTIVE)) }, ), Label::derived(move || diagnostic_count.get().0.to_string()).style( @@ -183,18 +183,18 @@ pub fn status( .color( config .get() - .color(LapceColor::STATUS_FOREGROUND), + .color(UmideColor::STATUS_FOREGROUND), ) .selectable(false) }, ), - svg(move || config.get().ui_svg(LapceIcons::WARNING)).style( + svg(move || config.get().ui_svg(UmideIcons::WARNING)).style( move |s| { let config = config.get(); let size = config.ui.icon_size() as f32; s.size(size, size) .margin_left(5.0) - .color(config.color(LapceColor::LAPCE_ICON_ACTIVE)) + .color(config.color(UmideColor::LAPCE_ICON_ACTIVE)) }, ), Label::derived(move || diagnostic_count.get().1.to_string()).style( @@ -203,7 +203,7 @@ pub fn status( .color( config .get() - .color(LapceColor::STATUS_FOREGROUND), + .color(UmideColor::STATUS_FOREGROUND), ) .selectable(false) }, @@ -220,7 +220,7 @@ pub fn status( s.cursor(CursorStyle::Pointer).background( config .get() - .color(LapceColor::PANEL_HOVERED_BACKGROUND), + .color(UmideColor::PANEL_HOVERED_BACKGROUND), ) }) }) @@ -243,9 +243,9 @@ pub fn status( if panel .is_container_shown(&PanelContainerPosition::Left, true) { - LapceIcons::SIDEBAR_LEFT + UmideIcons::SIDEBAR_LEFT } else { - LapceIcons::SIDEBAR_LEFT_OFF + UmideIcons::SIDEBAR_LEFT_OFF } } }; @@ -269,9 +269,9 @@ pub fn status( &PanelContainerPosition::Bottom, true, ) { - LapceIcons::LAYOUT_PANEL + UmideIcons::LAYOUT_PANEL } else { - LapceIcons::LAYOUT_PANEL_OFF + UmideIcons::LAYOUT_PANEL_OFF } } }; @@ -295,9 +295,9 @@ pub fn status( if panel .is_container_shown(&PanelContainerPosition::Right, true) { - LapceIcons::SIDEBAR_RIGHT + UmideIcons::SIDEBAR_RIGHT } else { - LapceIcons::SIDEBAR_RIGHT_OFF + UmideIcons::SIDEBAR_RIGHT_OFF } } }; @@ -316,7 +316,7 @@ pub fn status( .style(move |s| { s.height_pct(100.0) .items_center() - .color(config.get().color(LapceColor::STATUS_FOREGROUND)) + .color(config.get().color(UmideColor::STATUS_FOREGROUND)) }), Stack::new({ let palette_clone = palette.clone(); @@ -398,8 +398,8 @@ pub fn status( .style(move |s| { let config = config.get(); s.border_top(1.0) - .border_color(config.color(LapceColor::LAPCE_BORDER)) - .background(config.color(LapceColor::STATUS_BACKGROUND)) + .border_color(config.color(UmideColor::LAPCE_BORDER)) + .background(config.color(UmideColor::STATUS_BACKGROUND)) .flex_basis(config.ui.status_height() as f32) .flex_grow(0.0) .flex_shrink(0.0) @@ -409,7 +409,7 @@ pub fn status( } fn progress_view( - config: ReadSignal>, + config: ReadSignal>, progresses: RwSignal>, ) -> impl View { let id = AtomicU64::new(0); @@ -430,7 +430,7 @@ fn progress_view( .text_ellipsis() .selectable(false) .items_center() - .color(config.get().color(LapceColor::STATUS_FOREGROUND)) + .color(config.get().color(UmideColor::STATUS_FOREGROUND)) }) }, ) @@ -438,7 +438,7 @@ fn progress_view( } fn status_text( - config: ReadSignal>, + config: ReadSignal>, editor: Memo>, text: impl Fn() -> S + 'static, ) -> impl View { @@ -463,10 +463,10 @@ fn status_text( .height_full() .padding_horiz(10.0) .items_center() - .color(config.color(LapceColor::STATUS_FOREGROUND)) + .color(config.color(UmideColor::STATUS_FOREGROUND)) .hover(|s| { s.cursor(CursorStyle::Pointer) - .background(config.color(LapceColor::PANEL_HOVERED_BACKGROUND)) + .background(config.color(UmideColor::PANEL_HOVERED_BACKGROUND)) }) .selectable(false) }) diff --git a/crates/umide/src/terminal/data.rs b/crates/umide/src/terminal/data.rs index 1395c23b..5e283026 100644 --- a/crates/umide/src/terminal/data.rs +++ b/crates/umide/src/terminal/data.rs @@ -35,14 +35,14 @@ use crate::{ debug::{RunDebugMode, RunDebugProcess}, keypress::{KeyPressFocus, condition::Condition}, window_tab::CommonData, - workspace::LapceWorkspace, + workspace::UmideWorkspace, }; #[derive(Clone, Debug)] pub struct TerminalData { pub scope: Scope, pub term_id: TermId, - pub workspace: Arc, + pub workspace: Arc, pub title: RwSignal, pub launch_error: RwSignal>, pub mode: RwSignal, @@ -63,7 +63,7 @@ impl KeyPressFocus for TerminalData { fn run_command( &self, - command: &crate::command::LapceCommand, + command: &crate::command::UmideCommand, count: Option, _mods: Modifiers, ) -> crate::command::CommandExecuted { @@ -306,7 +306,7 @@ impl KeyPressFocus for TerminalData { impl TerminalData { pub fn new( cx: Scope, - workspace: Arc, + workspace: Arc, profile: Option, common: Rc, ) -> Self { @@ -315,7 +315,7 @@ impl TerminalData { pub fn new_run_debug( cx: Scope, - workspace: Arc, + workspace: Arc, run_debug: Option, profile: Option, common: Rc, @@ -360,7 +360,7 @@ impl TerminalData { } fn new_raw_terminal( - workspace: &LapceWorkspace, + workspace: &UmideWorkspace, term_id: TermId, run_debug: Option<&RunDebugProcess>, profile: Option, @@ -765,7 +765,7 @@ pub struct ExpandedRunDebug { } impl ExpandedRunDebug { pub fn expand( - workspace: &LapceWorkspace, + workspace: &UmideWorkspace, run_debug: &RunDebugConfig, is_prelaunch: bool, ) -> anyhow::Result { @@ -837,7 +837,7 @@ impl ExpandedRunDebug { } fn expand_work_dir( - workspace: &LapceWorkspace, + workspace: &UmideWorkspace, run_debug: &RunDebugConfig, ) -> Option { let path = run_debug.cwd.as_ref()?; diff --git a/crates/umide/src/terminal/panel.rs b/crates/umide/src/terminal/panel.rs index e03c9e28..6c7489e5 100644 --- a/crates/umide/src/terminal/panel.rs +++ b/crates/umide/src/terminal/panel.rs @@ -24,7 +24,7 @@ use crate::{ main_split::MainSplitData, panel::kind::PanelKind, window_tab::{CommonData, Focus}, - workspace::LapceWorkspace, + workspace::UmideWorkspace, }; pub struct TerminalTabInfo { @@ -35,7 +35,7 @@ pub struct TerminalTabInfo { #[derive(Clone)] pub struct TerminalPanelData { pub cx: Scope, - pub workspace: Arc, + pub workspace: Arc, pub tab_info: RwSignal, pub debug: RunDebugData, pub breakline: Memo>, @@ -45,7 +45,7 @@ pub struct TerminalPanelData { impl TerminalPanelData { pub fn new( - workspace: Arc, + workspace: Arc, profile: Option, common: Rc, main_split: MainSplitData, diff --git a/crates/umide/src/terminal/tab.rs b/crates/umide/src/terminal/tab.rs index 08551fa8..611e7514 100644 --- a/crates/umide/src/terminal/tab.rs +++ b/crates/umide/src/terminal/tab.rs @@ -6,7 +6,7 @@ use umide_rpc::terminal::TerminalProfile; use super::data::TerminalData; use crate::{ debug::RunDebugProcess, id::TerminalTabId, window_tab::CommonData, - workspace::LapceWorkspace, + workspace::UmideWorkspace, }; #[derive(Clone)] @@ -19,7 +19,7 @@ pub struct TerminalTabData { impl TerminalTabData { pub fn new( - workspace: Arc, + workspace: Arc, profile: Option, common: Rc, ) -> Self { @@ -28,7 +28,7 @@ impl TerminalTabData { /// Create the information for a terminal tab, which can contain multiple terminals. pub fn new_run_debug( - workspace: Arc, + workspace: Arc, run_debug: Option, profile: Option, common: Rc, diff --git a/crates/umide/src/terminal/view.rs b/crates/umide/src/terminal/view.rs index 1b8dab52..2577bc62 100644 --- a/crates/umide/src/terminal/view.rs +++ b/crates/umide/src/terminal/view.rs @@ -31,13 +31,13 @@ use unicode_width::UnicodeWidthChar; use super::{panel::TerminalPanelData, raw::RawTerminal}; use crate::{ command::InternalCommand, - config::{LapceConfig, color::LapceColor}, + config::{UmideConfig, color::UmideColor}, debug::RunDebugProcess, editor::location::{EditorLocation, EditorPosition}, listener::Listener, panel::kind::PanelKind, window_tab::Focus, - workspace::LapceWorkspace, + workspace::UmideWorkspace, }; /// Threshold used for double_click/triple_click. @@ -64,12 +64,12 @@ pub struct TerminalView { mode: ReadSignal, size: Size, is_focused: bool, - config: ReadSignal>, + config: ReadSignal>, run_config: ReadSignal>, proxy: ProxyRpcHandler, launch_error: RwSignal>, internal_command: Listener, - workspace: Arc, + workspace: Arc, hyper_regs: Vec, previous_mouse_action: MouseAction, current_mouse_action: MouseAction, @@ -84,7 +84,7 @@ pub fn terminal_view( terminal_panel_data: TerminalPanelData, launch_error: RwSignal>, internal_command: Listener, - workspace: Arc, + workspace: Arc, ) -> TerminalView { let id = ViewId::new(); @@ -329,9 +329,9 @@ impl TerminalView { content: RenderableContent, line_height: f64, char_size: Size, - config: &LapceConfig, + config: &UmideConfig, ) { - let term_bg = config.color(LapceColor::TERMINAL_BACKGROUND); + let term_bg = config.color(UmideColor::TERMINAL_BACKGROUND); let font_size = config.terminal_font_size(); let font_family = config.terminal_font_family(); @@ -429,7 +429,7 @@ impl TerminalView { line_content: &TerminalLineContent, line_height: f64, char_width: f64, - config: &LapceConfig, + config: &UmideConfig, ) { for (start, end, bg) in &line_content.bg { let rect = Size::new( @@ -459,12 +459,12 @@ impl TerminalView { if self.run_config.with_untracked(|run_config| { run_config.as_ref().map(|r| r.stopped).unwrap_or(false) }) { - config.color(LapceColor::LAPCE_ERROR) + config.color(UmideColor::LAPCE_ERROR) } else { - config.color(LapceColor::TERMINAL_CURSOR) + config.color(UmideColor::TERMINAL_CURSOR) } } else { - config.color(LapceColor::EDITOR_CARET) + config.color(UmideColor::EDITOR_CARET) }; if self.is_focused { cx.fill(&rect, cursor_color, 0.0); @@ -644,7 +644,7 @@ impl View for TerminalView { text_layout.set_text( &format!("Terminal failed to launch. Error: {error}"), AttrsList::new( - attrs.color(config.color(LapceColor::EDITOR_FOREGROUND)), + attrs.color(config.color(UmideColor::EDITOR_FOREGROUND)), ), None, ); @@ -692,7 +692,7 @@ impl View for TerminalView { let y1 = y0 + line_height; cx.fill( &Rect::new(x0, y0, x1, y1), - config.color(LapceColor::EDITOR_SELECTION), + config.color(UmideColor::EDITOR_SELECTION), 0.0, ); } @@ -702,7 +702,7 @@ impl View for TerminalView { * line_height; cx.fill( &Rect::new(0.0, y, self.size.width, y + line_height), - config.color(LapceColor::EDITOR_CURRENT_LINE), + config.color(UmideColor::EDITOR_CURRENT_LINE), 0.0, ); } @@ -750,7 +750,7 @@ impl View for TerminalView { // )); // cx.stroke( // &rect, - // config.get_color(LapceColor::TERMINAL_FOREGROUND), + // config.get_color(UmideColor::TERMINAL_FOREGROUND), // 1.0, // ); // start = *m.end(); diff --git a/crates/umide/src/text_area.rs b/crates/umide/src/text_area.rs index 9d3c1fce..ca54df6f 100644 --- a/crates/umide/src/text_area.rs +++ b/crates/umide/src/text_area.rs @@ -9,7 +9,7 @@ use floem::{ }; use umide_core::buffer::rope_text::RopeText; -use crate::{config::color::LapceColor, editor::EditorData}; +use crate::{config::color::UmideColor, editor::EditorData}; pub fn text_area( editor: EditorData, @@ -26,7 +26,7 @@ pub fn text_area( let config = config.get(); let font_size = config.ui.font_size(); let font_family = config.ui.font_family(); - let color = config.color(LapceColor::EDITOR_FOREGROUND); + let color = config.color(UmideColor::EDITOR_FOREGROUND); let attrs = Attrs::new() .color(color) .family(&font_family) @@ -49,7 +49,7 @@ pub fn text_area( let config = config.get_untracked(); let font_size = config.ui.font_size(); let font_family = config.ui.font_family(); - let color = config.color(LapceColor::EDITOR_FOREGROUND); + let color = config.color(UmideColor::EDITOR_FOREGROUND); let attrs = Attrs::new() .color(color) .family(&font_family) @@ -103,7 +103,7 @@ pub fn text_area( .margin_left(cursor_pos.x as f32 - 1.0) .margin_top(cursor_pos.y as f32) .border_left(2.0) - .border_color(config.get().color(LapceColor::EDITOR_CARET)) + .border_color(config.get().color(UmideColor::EDITOR_CARET)) .apply_if(!is_active(), |s| s.hide()) }), )) @@ -115,7 +115,7 @@ pub fn text_area( let config = config.get(); s.border(1.0) .border_radius(6.0) - .border_color(config.color(LapceColor::LAPCE_BORDER)) - .background(config.color(LapceColor::EDITOR_BACKGROUND)) + .border_color(config.color(UmideColor::LAPCE_BORDER)) + .background(config.color(UmideColor::EDITOR_BACKGROUND)) }) } diff --git a/crates/umide/src/text_input.rs b/crates/umide/src/text_input.rs index 76ba471e..b84bd445 100644 --- a/crates/umide/src/text_input.rs +++ b/crates/umide/src/text_input.rs @@ -22,7 +22,7 @@ use umide_core::{ use lapce_xi_rope::Rope; use crate::{ - config::{LapceConfig, color::LapceColor}, + config::{UmideConfig, color::UmideColor}, doc::Doc, editor::{DocSignal, EditorData, view::editor_style}, keypress::KeyPressFocus, @@ -317,7 +317,7 @@ pub struct TextInput { cursor_pos: Point, on_cursor_pos: Option>, hide_cursor: RwSignal, - config: ReadSignal>, + config: ReadSignal>, style: Extractor, } @@ -719,7 +719,7 @@ impl View for TextInput { &Rect::ZERO .with_size(Size::new(max - min, height)) .with_origin(Point::new(min + point.x, point.y)), - config.color(LapceColor::EDITOR_SELECTION), + config.color(UmideColor::EDITOR_SELECTION), 0.0, ); } @@ -754,7 +754,7 @@ impl View for TextInput { ); cx.stroke( &line, - config.color(LapceColor::EDITOR_FOREGROUND), + config.color(UmideColor::EDITOR_FOREGROUND), &Stroke::new(1.0), ); } @@ -782,7 +782,7 @@ impl View for TextInput { cx.stroke( &line, - self.config.get_untracked().color(LapceColor::EDITOR_CARET), + self.config.get_untracked().color(UmideColor::EDITOR_CARET), &Stroke::new(2.0), ); } diff --git a/crates/umide/src/title.rs b/crates/umide/src/title.rs index 31be655c..7548535e 100644 --- a/crates/umide/src/title.rs +++ b/crates/umide/src/title.rs @@ -16,20 +16,20 @@ use umide_rpc::proxy::ProxyStatus; use crate::{ app::{clickable_icon, not_clickable_icon, tooltip_label, window_menu}, - command::{LapceCommand, LapceWorkbenchCommand, WindowCommand}, - config::{LapceConfig, color::LapceColor, icon::LapceIcons}, + command::{UmideCommand, UmideWorkbenchCommand, WindowCommand}, + config::{UmideConfig, color::UmideColor, icon::UmideIcons}, listener::Listener, main_split::MainSplitData, update::ReleaseInfo, window_tab::WindowTabData, - workspace::LapceWorkspace, + workspace::UmideWorkspace, }; fn left( - workspace: Arc, - lapce_command: Listener, - workbench_command: Listener, - config: ReadSignal>, + workspace: Arc, + lapce_command: Listener, + workbench_command: Listener, + config: ReadSignal>, proxy_status: RwSignal>, num_window_tabs: Memo, ) -> impl View { @@ -44,16 +44,16 @@ fn left( }; s.width(75.0).apply_if(should_hide, |s| s.hide()) }), - Container::new(svg(move || config.get().ui_svg(LapceIcons::LOGO)).style( + Container::new(svg(move || config.get().ui_svg(UmideIcons::LOGO)).style( move |s| { let config = config.get(); s.size(16.0, 16.0) - .color(config.color(LapceColor::LAPCE_ICON_ACTIVE)) + .color(config.color(UmideColor::LAPCE_ICON_ACTIVE)) }, )) .style(move |s| s.margin_horiz(10.0).apply_if(is_macos, |s| s.hide())), not_clickable_icon( - || LapceIcons::MENU, + || UmideIcons::MENU, || false, || false, || "Menu", @@ -67,16 +67,16 @@ fn left( }), tooltip_label( config, - Container::new(svg(move || config.get().ui_svg(LapceIcons::REMOTE)).style( + Container::new(svg(move || config.get().ui_svg(UmideIcons::REMOTE)).style( move |s| { let config = config.get(); let size = (config.ui.icon_size() as f32 + 2.0).min(30.0); s.size(size, size).color(if is_local { - config.color(LapceColor::LAPCE_ICON_ACTIVE) + config.color(UmideColor::LAPCE_ICON_ACTIVE) } else { match proxy_status.get() { Some(_) => Color::WHITE, - None => config.color(LapceColor::LAPCE_ICON_ACTIVE), + None => config.color(UmideColor::LAPCE_ICON_ACTIVE), } }) }, @@ -87,7 +87,7 @@ fn left( #[allow(unused_mut)] let mut menu = Menu::new() .item("Connect to SSH Host", |i| i.action(move || { - workbench_command.send(LapceWorkbenchCommand::ConnectSshHost); + workbench_command.send(UmideWorkbenchCommand::ConnectSshHost); })); if !is_local @@ -98,7 +98,7 @@ fn left( menu = menu.item("Disconnect remote", |i| i.action( move || { workbench_command - .send(LapceWorkbenchCommand::DisconnectRemote); + .send(UmideWorkbenchCommand::DisconnectRemote); }, )); } @@ -107,7 +107,7 @@ fn left( menu = menu.item("Connect to WSL Host", |i| i.action( move || { workbench_command - .send(LapceWorkbenchCommand::ConnectWslHost); + .send(UmideWorkbenchCommand::ConnectWslHost); }, )); } @@ -120,13 +120,13 @@ fn left( } else { match proxy_status.get() { Some(ProxyStatus::Connected) => { - config.color(LapceColor::LAPCE_REMOTE_CONNECTED) + config.color(UmideColor::LAPCE_REMOTE_CONNECTED) } Some(ProxyStatus::Connecting) => { - config.color(LapceColor::LAPCE_REMOTE_CONNECTING) + config.color(UmideColor::LAPCE_REMOTE_CONNECTING) } Some(ProxyStatus::Disconnected) => { - config.color(LapceColor::LAPCE_REMOTE_DISCONNECTED) + config.color(UmideColor::LAPCE_REMOTE_DISCONNECTED) } None => Color::TRANSPARENT, } @@ -137,12 +137,12 @@ fn left( .background(color) .hover(|s| { s.cursor(CursorStyle::Pointer).background( - config.color(LapceColor::PANEL_HOVERED_BACKGROUND), + config.color(UmideColor::PANEL_HOVERED_BACKGROUND), ) }) .active(|s| { s.cursor(CursorStyle::Pointer).background( - config.color(LapceColor::PANEL_HOVERED_ACTIVE_BACKGROUND), + config.color(UmideColor::PANEL_HOVERED_ACTIVE_BACKGROUND), ) }) }), @@ -159,10 +159,10 @@ fn left( } fn middle( - workspace: Arc, + workspace: Arc, main_split: MainSplitData, - workbench_command: Listener, - config: ReadSignal>, + workbench_command: Listener, + config: ReadSignal>, ) -> impl View { let local_workspace = workspace.clone(); let can_jump_backward = { @@ -174,9 +174,9 @@ fn middle( let jump_backward = move || { clickable_icon( - || LapceIcons::LOCATION_BACKWARD, + || UmideIcons::LOCATION_BACKWARD, move || { - workbench_command.send(LapceWorkbenchCommand::JumpLocationBackward); + workbench_command.send(UmideWorkbenchCommand::JumpLocationBackward); }, || false, move || !can_jump_backward.get(), @@ -187,9 +187,9 @@ fn middle( }; let jump_forward = move || { clickable_icon( - || LapceIcons::LOCATION_FORWARD, + || UmideIcons::LOCATION_FORWARD, move || { - workbench_command.send(LapceWorkbenchCommand::JumpLocationForward); + workbench_command.send(UmideWorkbenchCommand::JumpLocationForward); }, || false, move || !can_jump_forward.get(), @@ -201,7 +201,7 @@ fn middle( let open_folder = move || { not_clickable_icon( - || LapceIcons::PALETTE_MENU, + || UmideIcons::PALETTE_MENU, || false, || false, || "Open Folder / Recent Workspace", @@ -210,10 +210,10 @@ fn middle( .popout_menu(move || { Menu::new() .item("Open Folder", |i| i.action(move || { - workbench_command.send(LapceWorkbenchCommand::OpenFolder); + workbench_command.send(UmideWorkbenchCommand::OpenFolder); })) .item("Open Recent Workspace", |i| i.action(move || { - workbench_command.send(LapceWorkbenchCommand::PaletteWorkspace); + workbench_command.send(UmideWorkbenchCommand::PaletteWorkspace); })) }) }; @@ -232,12 +232,12 @@ fn middle( }), Container::new( Stack::new(( - svg(move || config.get().ui_svg(LapceIcons::SEARCH)).style( + svg(move || config.get().ui_svg(UmideIcons::SEARCH)).style( move |s| { let config = config.get(); let icon_size = config.ui.icon_size() as f32; s.size(icon_size, icon_size) - .color(config.color(LapceColor::LAPCE_ICON_ACTIVE)) + .color(config.color(UmideColor::LAPCE_ICON_ACTIVE)) }, ), Label::new({ @@ -255,9 +255,9 @@ fn middle( .on_event_stop(EventListener::PointerDown, |_| {}) .on_click_stop(move |_| { if workspace.clone().path.is_some() { - workbench_command.send(LapceWorkbenchCommand::PaletteHelpAndFile); + workbench_command.send(UmideWorkbenchCommand::PaletteHelpAndFile); } else { - workbench_command.send(LapceWorkbenchCommand::PaletteWorkspace); + workbench_command.send(UmideWorkbenchCommand::PaletteWorkspace); } }) .style(move |s| { @@ -270,15 +270,15 @@ fn middle( .justify_content(Some(JustifyContent::Center)) .align_items(Some(AlignItems::Center)) .border(1.0) - .border_color(config.color(LapceColor::LAPCE_BORDER)) + .border_color(config.color(UmideColor::LAPCE_BORDER)) .border_radius(6.0) - .background(config.color(LapceColor::EDITOR_BACKGROUND)) + .background(config.color(UmideColor::EDITOR_BACKGROUND)) }), Stack::new(( clickable_icon( - || LapceIcons::START, + || UmideIcons::START, move || { - workbench_command.send(LapceWorkbenchCommand::PaletteRunAndDebug) + workbench_command.send(UmideWorkbenchCommand::PaletteRunAndDebug) }, || false, || false, @@ -306,12 +306,12 @@ fn middle( fn right( window_command: Listener, - workbench_command: Listener, + workbench_command: Listener, latest_release: ReadSignal>>, update_in_progress: RwSignal, num_window_tabs: Memo, window_maximized: RwSignal, - config: ReadSignal>, + config: ReadSignal>, ) -> impl View { let latest_version = Memo::new(move |_| { let latest_release = latest_release.get(); @@ -333,7 +333,7 @@ fn right( .style(|s| s.height_pct(100.0).flex_basis(0.0).flex_grow(1.0)), Stack::new(( not_clickable_icon( - || LapceIcons::SETTINGS, + || UmideIcons::SETTINGS, || false, || false, || "Settings", @@ -342,22 +342,22 @@ fn right( .popout_menu(move || { Menu::new() .item("Command Palette", |i| i.action(move || { - workbench_command.send(LapceWorkbenchCommand::PaletteCommand) + workbench_command.send(UmideWorkbenchCommand::PaletteCommand) })) .separator() .item("Open Settings", |i| i.action(move || { - workbench_command.send(LapceWorkbenchCommand::OpenSettings) + workbench_command.send(UmideWorkbenchCommand::OpenSettings) })) .item("Open Keyboard Shortcuts", |i| i.action( move || { workbench_command - .send(LapceWorkbenchCommand::OpenKeyboardShortcuts) + .send(UmideWorkbenchCommand::OpenKeyboardShortcuts) }, )) .item("Open Theme Color Settings", |i| i.action( move || { workbench_command - .send(LapceWorkbenchCommand::OpenThemeColorSettings) + .send(UmideWorkbenchCommand::OpenThemeColorSettings) }, )) .separator() @@ -378,7 +378,7 @@ fn right( } else { i.action(move || { workbench_command - .send(LapceWorkbenchCommand::RestartToUpdate) + .send(UmideWorkbenchCommand::RestartToUpdate) }) } } else { @@ -388,17 +388,17 @@ fn right( ) .separator() .item("About UMIDE", |i| i.action(move || { - workbench_command.send(LapceWorkbenchCommand::ShowAbout) + workbench_command.send(UmideWorkbenchCommand::ShowAbout) })) }), Container::new(Label::new("1".to_string()).style(move |s| { let config = config.get(); s.font_size(10.0) - .color(config.color(LapceColor::EDITOR_BACKGROUND)) + .color(config.color(UmideColor::EDITOR_BACKGROUND)) .border_radius(100.0) .margin_left(5.0) .margin_top(10.0) - .background(config.color(LapceColor::EDITOR_CARET)) + .background(config.color(UmideColor::EDITOR_CARET)) })) .style(move |s| { let has_update = has_update(); @@ -475,9 +475,9 @@ pub fn title(window_tab_data: Rc) -> impl View { s.width_pct(100.0) .height(37.0) .items_center() - .background(config.color(LapceColor::PANEL_BACKGROUND)) + .background(config.color(UmideColor::PANEL_BACKGROUND)) .border_bottom(1.0) - .border_color(config.color(LapceColor::LAPCE_BORDER)) + .border_color(config.color(UmideColor::LAPCE_BORDER)) }) .debug_name("Title / Top Bar") } @@ -487,11 +487,11 @@ pub fn window_controls_view( is_title: bool, num_window_tabs: Memo, window_maximized: RwSignal, - config: ReadSignal>, + config: ReadSignal>, ) -> impl View { Stack::new(( clickable_icon( - || LapceIcons::WINDOW_MINIMIZE, + || UmideIcons::WINDOW_MINIMIZE, || { floem::action::minimize_window(); }, @@ -504,9 +504,9 @@ pub fn window_controls_view( clickable_icon( move || { if window_maximized.get() { - LapceIcons::WINDOW_RESTORE + UmideIcons::WINDOW_RESTORE } else { - LapceIcons::WINDOW_MAXIMIZE + UmideIcons::WINDOW_MAXIMIZE } }, move || { @@ -521,7 +521,7 @@ pub fn window_controls_view( ) .style(|s| s.margin_right(16.0)), clickable_icon( - || LapceIcons::WINDOW_CLOSE, + || UmideIcons::WINDOW_CLOSE, move || { window_command.send(WindowCommand::CloseWindow); }, diff --git a/crates/umide/src/update.rs b/crates/umide/src/update.rs index 3982af02..0293926d 100644 --- a/crates/umide/src/update.rs +++ b/crates/umide/src/update.rs @@ -30,7 +30,7 @@ pub fn get_latest_release() -> Result { _ => "https://api.github.com/repos/lapce/lapce/releases/latest", }; - let resp = umide_proxy::get_url(url, Some("Lapce"))?; + let resp = umide_proxy::get_url(url, Some("Umide"))?; if !resp.status().is_success() { return Err(anyhow!("get release info failed {}", resp.text()?)); } diff --git a/crates/umide/src/window.rs b/crates/umide/src/window.rs index b1fe90af..24f13ded 100644 --- a/crates/umide/src/window.rs +++ b/crates/umide/src/window.rs @@ -14,19 +14,19 @@ use serde::{Deserialize, Serialize}; use crate::{ app::AppCommand, command::{InternalCommand, WindowCommand}, - config::LapceConfig, - db::LapceDb, + config::UmideConfig, + db::UmideDb, keypress::EventRef, listener::Listener, update::ReleaseInfo, window_tab::WindowTabData, - workspace::LapceWorkspace, + workspace::UmideWorkspace, }; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct TabsInfo { pub active_tab: usize, - pub workspaces: Vec, + pub workspaces: Vec, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -57,7 +57,7 @@ pub struct WindowCommonData { /// `WindowData` is the application model for a top-level window. /// /// A top-level window can be independently moved around and -/// resized using your window manager. Normally Lapce has only one +/// resized using your window manager. Normally Umide has only one /// top-level window, but new ones can be created using the "New Window" /// command. /// @@ -77,7 +77,7 @@ pub struct WindowData { pub position: RwSignal, pub root_view_id: RwSignal, pub window_scale: RwSignal, - pub config: RwSignal>, + pub config: RwSignal>, pub ime_enabled: RwSignal, pub common: Rc, } @@ -94,7 +94,7 @@ impl WindowData { ) -> Self { let cx = Scope::new(); let config = - LapceConfig::load(&LapceWorkspace::default(), &[], &extra_plugin_paths); + UmideConfig::load(&UmideWorkspace::default(), &[], &extra_plugin_paths); let config = cx.create_rw_signal(Arc::new(config)); let root_view_id = cx.create_rw_signal(ViewId::new()); @@ -136,7 +136,7 @@ impl WindowData { if window_tabs.with_untracked(|window_tabs| window_tabs.is_empty()) { let window_tab = Rc::new(WindowTabData::new( cx, - Arc::new(LapceWorkspace::default()), + Arc::new(UmideWorkspace::default()), common.clone(), )); window_tabs.update(|window_tabs| { @@ -186,8 +186,8 @@ impl WindowData { } pub fn reload_config(&self) { - let config = LapceConfig::load( - &LapceWorkspace::default(), + let config = UmideConfig::load( + &UmideWorkspace::default(), &[], &self.common.extra_plugin_paths, ); @@ -201,7 +201,7 @@ impl WindowData { pub fn run_window_command(&self, cmd: WindowCommand) { match cmd { WindowCommand::SetWorkspace { workspace } => { - let db: Arc = Context::get().unwrap(); + let db: Arc = Context::get().unwrap(); if let Err(err) = db.update_recent_workspace(&workspace) { tracing::error!("{:?}", err); } @@ -238,7 +238,7 @@ impl WindowData { }) } WindowCommand::NewWorkspaceTab { workspace, end } => { - let db: Arc = Context::get().unwrap(); + let db: Arc = Context::get().unwrap(); if let Err(err) = db.update_recent_workspace(&workspace) { tracing::error!("{:?}", err); } @@ -281,7 +281,7 @@ impl WindowData { if index < window_tabs.len() { let (_, old_window_tab) = window_tabs.remove(index); old_window_tab.proxy.shutdown(); - let db: Arc = Context::get().unwrap(); + let db: Arc = Context::get().unwrap(); if let Err(err) = db.save_window_tab(old_window_tab) { tracing::error!("{:?}", err); } @@ -348,7 +348,7 @@ impl WindowData { } pub fn info(&self) -> WindowInfo { - let workspaces: Vec = self + let workspaces: Vec = self .window_tabs .get_untracked() .iter() diff --git a/crates/umide/src/window_tab.rs b/crates/umide/src/window_tab.rs index 400e8f3b..aa67fe64 100644 --- a/crates/umide/src/window_tab.rs +++ b/crates/umide/src/window_tab.rs @@ -45,13 +45,13 @@ use crate::{ alert::{AlertBoxData, AlertButton}, code_action::{CodeActionData, CodeActionStatus}, command::{ - CommandExecuted, CommandKind, InternalCommand, LapceCommand, - LapceWorkbenchCommand, WindowCommand, + CommandExecuted, CommandKind, InternalCommand, UmideCommand, + UmideWorkbenchCommand, WindowCommand, }, completion::{CompletionData, CompletionStatus}, - config::LapceConfig, - db::LapceDb, - debug::{DapData, LapceBreakpoint, RunDebugMode, RunDebugProcess}, + config::UmideConfig, + db::UmideDb, + debug::{DapData, UmideBreakpoint, RunDebugMode, RunDebugProcess}, doc::DocContent, editor::location::{EditorLocation, EditorPosition}, editor_tab::EditorTabChild, @@ -82,7 +82,7 @@ use crate::{ }, tracing::*, window::WindowCommonData, - workspace::{LapceWorkspace, LapceWorkspaceType, WorkspaceInfo}, + workspace::{UmideWorkspace, UmideWorkspaceType, WorkspaceInfo}, }; #[derive(Debug, Clone, PartialEq, Eq)] @@ -117,7 +117,7 @@ pub struct WorkProgress { #[derive(Clone)] pub struct CommonData { - pub workspace: Arc, + pub workspace: Arc, pub scope: Scope, pub focus: RwSignal, pub keypress: RwSignal, @@ -129,18 +129,18 @@ pub struct CommonData { pub workbench_size: RwSignal, pub window_origin: RwSignal, pub internal_command: Listener, - pub lapce_command: Listener, - pub workbench_command: Listener, + pub lapce_command: Listener, + pub workbench_command: Listener, pub term_tx: Sender<(TermId, TermEvent)>, pub term_notification_tx: Sender, pub proxy: ProxyRpcHandler, pub view_id: RwSignal, pub ui_line_height: Memo, pub dragging: RwSignal>, - pub config: ReadSignal>, + pub config: ReadSignal>, pub proxy_status: RwSignal>, pub mouse_hover_timer: RwSignal, - pub breakpoints: RwSignal>>, + pub breakpoints: RwSignal>>, // the current focused view which will receive keyboard events pub keyboard_focus: RwSignal>, pub window_common: Rc, @@ -158,7 +158,7 @@ impl std::fmt::Debug for CommonData { pub struct WindowTabData { pub scope: Scope, pub window_tab_id: WindowTabId, - pub workspace: Arc, + pub workspace: Arc, pub palette: PaletteData, pub main_split: MainSplitData, pub file_explorer: FileExplorerData, @@ -177,7 +177,7 @@ pub struct WindowTabData { pub title_height: RwSignal, pub status_height: RwSignal, pub proxy: ProxyData, - pub set_config: WriteSignal>, + pub set_config: WriteSignal>, pub update_in_progress: RwSignal, pub progresses: RwSignal>, pub messages: RwSignal>, @@ -212,7 +212,7 @@ impl KeyPressFocus for WindowTabData { fn run_command( &self, - command: &LapceCommand, + command: &UmideCommand, _count: Option, _mods: Modifiers, ) -> CommandExecuted { @@ -272,11 +272,11 @@ impl WindowTabData { #[allow(clippy::too_many_arguments)] pub fn new( cx: Scope, - workspace: Arc, + workspace: Arc, window_common: Rc, ) -> Self { let cx = cx.create_child(); - let db: Arc = Context::get().unwrap(); + let db: Arc = Context::get().unwrap(); let disabled_volts = db.get_disabled_volts().unwrap_or_default(); let workspace_disabled_volts = db @@ -295,7 +295,7 @@ impl WindowTabData { info }; - let config = LapceConfig::load( + let config = UmideConfig::load( &workspace, &all_disabled_volts, &window_common.extra_plugin_paths, @@ -520,7 +520,7 @@ impl WindowTabData { breakpoints .into_iter() .map(|b| (b.line, b)) - .collect::>(), + .collect::>(), ) }) .collect(), @@ -648,7 +648,7 @@ impl WindowTabData { } pub fn reload_config(&self) { - let db: Arc = Context::get().unwrap(); + let db: Arc = Context::get().unwrap(); let disabled_volts = db.get_disabled_volts().unwrap_or_default(); let workspace_disabled_volts = db @@ -657,7 +657,7 @@ impl WindowTabData { let mut all_disabled_volts = disabled_volts; all_disabled_volts.extend(workspace_disabled_volts); - let config = LapceConfig::load( + let config = UmideConfig::load( &self.workspace, &all_disabled_volts, &self.common.window_common.extra_plugin_paths, @@ -707,7 +707,7 @@ impl WindowTabData { } } - pub fn run_lapce_command(&self, cmd: LapceCommand) { + pub fn run_lapce_command(&self, cmd: UmideCommand) { match cmd.kind { CommandKind::Workbench(command) => { self.run_workbench_command(command, cmd.data); @@ -733,10 +733,10 @@ impl WindowTabData { pub fn run_workbench_command( &self, - cmd: LapceWorkbenchCommand, + cmd: UmideWorkbenchCommand, data: Option, ) { - use LapceWorkbenchCommand::*; + use UmideWorkbenchCommand::*; match cmd { // ==== Modal ==== EnableModal => { @@ -760,8 +760,8 @@ impl WindowTabData { }; open_file(options, move |file| { if let Some(mut file) = file { - let workspace = LapceWorkspace { - kind: LapceWorkspaceType::Local, + let workspace = UmideWorkspace { + kind: UmideWorkspaceType::Local, path: Some(if let Some(path) = file.path.pop() { path } else { @@ -782,8 +782,8 @@ impl WindowTabData { CloseFolder => { if !self.workspace.kind.is_remote() { let window_command = self.common.window_common.window_command; - let workspace = LapceWorkspace { - kind: LapceWorkspaceType::Local, + let workspace = UmideWorkspace { + kind: UmideWorkspaceType::Local, path: None, last_open: 0, }; @@ -859,7 +859,7 @@ impl WindowTabData { self.main_split.open_settings(); } OpenSettingsFile => { - if let Some(path) = LapceConfig::settings_file() { + if let Some(path) = UmideConfig::settings_file() { self.main_split.jump_to_location( EditorLocation { path, @@ -884,7 +884,7 @@ impl WindowTabData { self.main_split.open_keymap(); } OpenKeyboardShortcutsFile => { - if let Some(path) = LapceConfig::keymaps_file() { + if let Some(path) = UmideConfig::keymaps_file() { self.main_split.jump_to_location( EditorLocation { path, @@ -969,7 +969,7 @@ impl WindowTabData { NewWindowTab => { self.common.window_common.window_command.send( WindowCommand::NewWorkspaceTab { - workspace: LapceWorkspace::default(), + workspace: UmideWorkspace::default(), end: false, }, ); @@ -1111,8 +1111,8 @@ impl WindowTabData { DisconnectRemote => { self.common.window_common.window_command.send( WindowCommand::SetWorkspace { - workspace: LapceWorkspace { - kind: LapceWorkspaceType::Local, + workspace: UmideWorkspace { + kind: UmideWorkspaceType::Local, path: None, last_open: 0, }, @@ -1190,7 +1190,7 @@ impl WindowTabData { } self.common.window_common.window_scale.set(scale); - LapceConfig::update_file( + UmideConfig::update_file( "ui", "scale", toml_edit::Value::from(scale), @@ -1205,7 +1205,7 @@ impl WindowTabData { } self.common.window_common.window_scale.set(scale); - LapceConfig::update_file( + UmideConfig::update_file( "ui", "scale", toml_edit::Value::from(scale), @@ -1214,7 +1214,7 @@ impl WindowTabData { ZoomReset => { self.common.window_common.window_scale.set(1.0); - LapceConfig::update_file( + UmideConfig::update_file( "ui", "scale", toml_edit::Value::from(1.0), @@ -1943,7 +1943,7 @@ impl WindowTabData { InternalCommand::SetColorTheme { name, save } => { if save { // The config file is watched - LapceConfig::update_file( + UmideConfig::update_file( "core", "color-theme", toml_edit::Value::from(name), @@ -1958,7 +1958,7 @@ impl WindowTabData { InternalCommand::SetIconTheme { name, save } => { if save { // The config file is watched - LapceConfig::update_file( + UmideConfig::update_file( "core", "icon-theme", toml_edit::Value::from(name), @@ -1971,7 +1971,7 @@ impl WindowTabData { } } InternalCommand::SetModal { modal } => { - LapceConfig::update_file( + UmideConfig::update_file( "core", "modal", toml_edit::Value::from(modal), @@ -2835,7 +2835,7 @@ impl WindowTabData { for folder in folders { self.common.window_common.window_command.send( WindowCommand::NewWorkspaceTab { - workspace: LapceWorkspace { + workspace: UmideWorkspace { kind: self.workspace.kind.clone(), path: Some(folder.path.clone()), last_open: 0, diff --git a/crates/umide/src/workspace.rs b/crates/umide/src/workspace.rs index 7181ac03..a16d8f3a 100644 --- a/crates/umide/src/workspace.rs +++ b/crates/umide/src/workspace.rs @@ -2,7 +2,7 @@ use std::{collections::HashMap, fmt::Display, path::PathBuf}; use serde::{Deserialize, Serialize}; -use crate::{debug::LapceBreakpoint, main_split::SplitInfo, panel::data::PanelInfo}; +use crate::{debug::UmideBreakpoint, main_split::SplitInfo, panel::data::PanelInfo}; #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)] pub struct SshHost { @@ -63,20 +63,20 @@ impl Display for WslHost { } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub enum LapceWorkspaceType { +pub enum UmideWorkspaceType { Local, RemoteSSH(SshHost), #[cfg(windows)] RemoteWSL(WslHost), } -impl LapceWorkspaceType { +impl UmideWorkspaceType { pub fn is_local(&self) -> bool { - matches!(self, LapceWorkspaceType::Local) + matches!(self, UmideWorkspaceType::Local) } pub fn is_remote(&self) -> bool { - use LapceWorkspaceType::*; + use UmideWorkspaceType::*; #[cfg(not(windows))] return matches!(self, RemoteSSH(_)); @@ -86,15 +86,15 @@ impl LapceWorkspaceType { } } -impl std::fmt::Display for LapceWorkspaceType { +impl std::fmt::Display for UmideWorkspaceType { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - LapceWorkspaceType::Local => f.write_str("Local"), - LapceWorkspaceType::RemoteSSH(remote) => { + UmideWorkspaceType::Local => f.write_str("Local"), + UmideWorkspaceType::RemoteSSH(remote) => { write!(f, "ssh://{remote}") } #[cfg(windows)] - LapceWorkspaceType::RemoteWSL(remote) => { + UmideWorkspaceType::RemoteWSL(remote) => { write!(f, "{remote} (WSL)") } } @@ -102,13 +102,13 @@ impl std::fmt::Display for LapceWorkspaceType { } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct LapceWorkspace { - pub kind: LapceWorkspaceType, +pub struct UmideWorkspace { + pub kind: UmideWorkspaceType, pub path: Option, pub last_open: u64, } -impl LapceWorkspace { +impl UmideWorkspace { pub fn display(&self) -> Option { let path = self.path.as_ref()?; let path = path @@ -117,12 +117,12 @@ impl LapceWorkspace { .to_string_lossy() .to_string(); let remote = match &self.kind { - LapceWorkspaceType::Local => String::new(), - LapceWorkspaceType::RemoteSSH(remote) => { + UmideWorkspaceType::Local => String::new(), + UmideWorkspaceType::RemoteSSH(remote) => { format!(" [SSH: {}]", remote.host) } #[cfg(windows)] - LapceWorkspaceType::RemoteWSL(remote) => { + UmideWorkspaceType::RemoteWSL(remote) => { format!(" [WSL: {}]", remote.host) } }; @@ -130,17 +130,17 @@ impl LapceWorkspace { } } -impl Default for LapceWorkspace { +impl Default for UmideWorkspace { fn default() -> Self { Self { - kind: LapceWorkspaceType::Local, + kind: UmideWorkspaceType::Local, path: None, last_open: 0, } } } -impl std::fmt::Display for LapceWorkspace { +impl std::fmt::Display for UmideWorkspace { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, @@ -155,5 +155,5 @@ impl std::fmt::Display for LapceWorkspace { pub struct WorkspaceInfo { pub split: SplitInfo, pub panel: PanelInfo, - pub breakpoints: HashMap>, + pub breakpoints: HashMap>, } diff --git a/crates/umide_native/src/macos.rs b/crates/umide_native/src/macos.rs index 9b200c40..16c297dc 100644 --- a/crates/umide_native/src/macos.rs +++ b/crates/umide_native/src/macos.rs @@ -218,9 +218,23 @@ extern "C" fn screen_capture_trampoline(context: *mut c_void, surface: *mut ffi: unsafe { let data = &*(context as *const ScreenCaptureCallbackData); - // Create a temporary MacOSSurface wrapper - // Note: We don't own this surface, it's managed by the C++ side - let surface_ref = &*(surface as *const MacOSSurface); - (data.callback)(surface_ref); + // Construct a temporary MacOSSurface wrapper from the raw pointer + // We need to query width/height if we want them to be valid + // For now, we'll assume the callback uses the surface pointer mainly + // WARNING: This assumes the surface is valid for the duration of the callback + if let Some(ptr) = NonNull::new(surface) { + // Use dummy values or fetch from FFI if needed. + // For safety, we should ideally fetch valid dimensions or change the callback signature. + // But to fix the immediate segfault risk of invalid casting: + + // Note: We used ManuallyDrop to ensure we don't destroy the C++ managed surface + let surface_wrapper = std::mem::ManuallyDrop::new(MacOSSurface { + ptr, + width: 0, // Placeholder + height: 0 // Placeholder + }); + + (data.callback)(&surface_wrapper); + } } } diff --git a/defaults/dark-theme.toml b/defaults/dark-theme.toml index 8d3c6ce0..83c6992d 100644 --- a/defaults/dark-theme.toml +++ b/defaults/dark-theme.toml @@ -1,7 +1,7 @@ #:schema ../extra/schemas/color-theme.json [color-theme] -name = "Lapce Dark" +name = "Umide Dark" [ui] font-family = "" diff --git a/defaults/icon-theme.toml b/defaults/icon-theme.toml index a68c7e66..6a284125 100644 --- a/defaults/icon-theme.toml +++ b/defaults/icon-theme.toml @@ -1,7 +1,7 @@ #:schema ../extra/schemas/icon-theme.json [icon-theme] -name = "Lapce Codicons" +name = "Umide Codicons" [icon-theme.ui] "logo" = "lapce_logo.svg" diff --git a/defaults/light-theme.toml b/defaults/light-theme.toml index 570e6f75..206e802c 100644 --- a/defaults/light-theme.toml +++ b/defaults/light-theme.toml @@ -1,7 +1,7 @@ #:schema ../extra/schemas/color-theme.json [color-theme] -name = "Lapce Light" +name = "Umide Light" [ui] font-family = "" diff --git a/defaults/settings.toml b/defaults/settings.toml index 4b73f81b..9253fae1 100644 --- a/defaults/settings.toml +++ b/defaults/settings.toml @@ -2,8 +2,8 @@ [core] modal = false -color-theme = "Lapce Dark" -icon-theme = "Lapce Codicons" +color-theme = "Umide Dark" +icon-theme = "Umide Codicons" custom-titlebar = true file-explorer-double-click = false auto-reload-plugin = false diff --git a/docs/architecture.md b/docs/architecture.md index 8c8a0f3c..b683786a 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -1,6 +1,6 @@ # UMIDE Architecture Overview -This document describes the high-level architecture of UMIDE (based on Lapce and Floem) and outlines the plan for integrating mobile emulator features. +This document describes the high-level architecture of UMIDE (based on Umide and Floem) and outlines the plan for integrating mobile emulator features. ## Core Architecture diff --git a/docs/building-from-source.md b/docs/building-from-source.md index 970176e0..dfdf6adf 100644 --- a/docs/building-from-source.md +++ b/docs/building-from-source.md @@ -1,30 +1,37 @@ ## Building from source -It is easy to build Lapce from source on a GNU/Linux distribution. Cargo handles the build process, all you need to do, is ensure the correct dependencies are installed. +It is easy to build Umide from source on a GNU/Linux distribution. Cargo handles the build process, all you need to do, is ensure the correct dependencies are installed. 1. Install the Rust compiler and Cargo using [`rustup.rs`](https://rustup.rs/). If you already have the toolchain, ensure you are using latest Rust version. 2. Install dependencies for your operating system: #### Ubuntu + ```sh sudo apt install clang libxkbcommon-x11-dev pkg-config libvulkan-dev libwayland-dev xorg-dev libxcb-shape0-dev libxcb-xfixes0-dev ``` + #### Fedora + ```sh sudo dnf install clang libxkbcommon-x11-devel libxcb-devel vulkan-loader-devel wayland-devel openssl-devel pkgconf ``` + #### Void Linux + ```sh sudo xbps-install -S base-devel clang libxkbcommon-devel vulkan-loader wayland-devel ``` 3. Clone this repository (this command will clone to your home directory): + ```sh git clone https://github.com/lapce/lapce.git ~/lapce ``` 4. `cd` into the repository, and run the build command with the release flag + ```sh cd ~/lapce ``` @@ -35,14 +42,14 @@ cargo install --path . --bin lapce --profile release-lto --locked > If you use a different distribution, and are having trouble finding appropriate dependencies, let us know in an issue! -Once Lapce is compiled, the executable will be available in `$HOME/.cargo/bin/lapce` and should be available in `PATH` automatically. +Once Umide is compiled, the executable will be available in `$HOME/.cargo/bin/lapce` and should be available in `PATH` automatically. ## Building using Docker or Podman Packages available in releases are built using containers based on multi-stage Dockerfiles. To easily orchestrate builds, there is a `docker-bake.hcl` manifest in root of repository that defines all stages and targets. If you want to build all packages for ubuntu, you can run `RELEASE_TAG_NAME=nightly docker buildx bake ubuntu` (`RELEASE_TAG_NAME` is a required environment variable used to tell what kind of release is being built as well as baking in the version itself). To scope in to specific distribution version, you can define target with it's version counterpart from matrix, e.g. to build only Ubuntu Focal package, you can run `RELEASE_TAG_NAME=nightly docker buildx bake ubuntu-focal`. -Additionally to building multiple OS versions at the same time, Docker-based builds will also try to cross-compile Lapce for other architectures. +Additionally to building multiple OS versions at the same time, Docker-based builds will also try to cross-compile Umide for other architectures. This does not require QEMU installed as it's done via true cross-compilation meaning `HOST` will run your native OS/CPU architecture and `TARGET` will be the wanted architecture, instead of spawning container that's running OS using `TARGET` architecture. > ![WARNING] diff --git a/docs/installing-with-package-manager.md b/docs/installing-with-package-manager.md index 4acd76b5..9974c7d2 100644 --- a/docs/installing-with-package-manager.md +++ b/docs/installing-with-package-manager.md @@ -1,20 +1,19 @@ ## Installation With Package Manager -Lapce is available in below software repositories: +Umide is available in below software repositories: [![Packaging status](https://repology.org/badge/vertical-allrepos/lapce.svg)](https://repology.org/project/lapce/versions) -Lapce is also additionally available via: +Umide is also additionally available via: - [Flatpak](https://flathub.org/apps/details/dev.lapce.lapce) - [Scoop](https://scoop.sh/#/apps?q=lapce) - -For Fedora Linux, Lapce is (unofficially) available via dnf RPM package manager, using nightly as of 2024.01: +For Fedora Linux, Umide is (unofficially) available via dnf RPM package manager, using nightly as of 2024.01: - [copr](https://copr.fedorainfracloud.org/coprs/titaniumtown/lapce/) ```bash -sudo dnf copr enable titaniumtown/lapce +sudo dnf copr enable titaniumtown/lapce sudo dnf install lapce ``` diff --git a/docs/new-release.md b/docs/new-release.md index dcd66a33..6bd63949 100644 --- a/docs/new-release.md +++ b/docs/new-release.md @@ -1,7 +1,7 @@ # Updating versioning for package managers and whatnot - App metainfo: `extra/linux/dev.lapce.lapce.metainfo.xml` -- macOS plist (`CFBundleShortVersionString`): `extra/macos/Lapce.app/Contents/Info.plist` +- macOS plist (`CFBundleShortVersionString`): `extra/macos/Umide.app/Contents/Info.plist` - Rust: `Cargo.toml` - Obviously changelog: `CHANGELOG.md` - RPM spec: `lapce.spec` diff --git a/extra/linux/dev.lapce.lapce.metainfo.xml b/extra/linux/dev.lapce.lapce.metainfo.xml index c0e9fb02..e110d9a3 100644 --- a/extra/linux/dev.lapce.lapce.metainfo.xml +++ b/extra/linux/dev.lapce.lapce.metainfo.xml @@ -1,7 +1,7 @@ dev.lapce.lapce - Lapce + Umide Dongdong Zhou, et al. Lightning-fast and powerful code editor written in Rust MIT @@ -15,7 +15,7 @@

- Lapce is an open source code editor written in Rust. By utilising native GUI and GPU rendering, and with the performance Rust provides, Lapce is one of the fastest code editors out there. + Umide is an open source code editor written in Rust. By utilising native GUI and GPU rendering, and with the performance Rust provides, Umide is one of the fastest code editors out there.

Features:

    @@ -23,14 +23,14 @@
  • Built-in LSP (Language Server Protocol) support to give you code intelligence like code completion, diagnostics and code actions etc.
  • Built-in remote development support (inspired by VSCode Remote Development) for a seamless "local" experience, benefiting from the full power of the remote system.
  • Plugins can be written in programming languages that can compile to the WASI format (C, Rust, AssemblyScript)
  • -
  • Built-in terminal, so you can execute commands in your workspace, without leaving Lapce.
  • +
  • Built-in terminal, so you can execute commands in your workspace, without leaving Umide.
dev.lapce.lapce.desktop - Lapce source project opened in Lapce with Rust source code file opened + Umide source project opened in Umide with Rust source code file opened https://raw.githubusercontent.com/lapce/lapce/refs/tags/v0.4.5/extra/images/linux/code-file-with-highlight.png diff --git a/extra/linux/docker/fedora/Dockerfile b/extra/linux/docker/fedora/Dockerfile index 03dd4260..424ce5ce 100644 --- a/extra/linux/docker/fedora/Dockerfile +++ b/extra/linux/docker/fedora/Dockerfile @@ -130,7 +130,7 @@ URL: https://github.com/lapce/lapce Packager: Jakub Panek %description -Lapce is written in pure Rust with a UI in Floem (which is also written in Rust). +Umide is written in pure Rust with a UI in Floem (which is also written in Rust). It is designed with Rope Science from the Xi-Editor which makes for lightning-fast computation, and leverages OpenGL for rendering. %build diff --git a/extra/proxy.ps1 b/extra/proxy.ps1 index 42bc12ef..ef363b26 100644 --- a/extra/proxy.ps1 +++ b/extra/proxy.ps1 @@ -6,8 +6,8 @@ param( $proxy = (Join-Path $directory 'lapce.exe') -$LapceProcesses = (Get-Process -Name 'lapce' -EA SilentlyContinue).Count -if ($LapceProcesses -ne 0) { +$UmideProcesses = (Get-Process -Name 'lapce' -EA SilentlyContinue).Count +if ($UmideProcesses -ne 0) { Write-Host 'Proxy currently in use. Aborting installation' exit } diff --git a/extra/windows/wix/lapce.wxs b/extra/windows/wix/lapce.wxs index 509bad7b..545c3397 100644 --- a/extra/windows/wix/lapce.wxs +++ b/extra/windows/wix/lapce.wxs @@ -10,8 +10,8 @@ - - + + @@ -19,33 +19,33 @@ - + - + - - - + + + - + - - - + + + - + - + @@ -53,10 +53,10 @@ - + - + diff --git a/lapce.spec b/lapce.spec index 9ec2dedc..b2865fba 100644 --- a/lapce.spec +++ b/lapce.spec @@ -11,7 +11,7 @@ Source: {{{ git_dir_pack }}} BuildRequires: cargo libxkbcommon-x11-devel libxcb-devel vulkan-loader-devel wayland-devel openssl-devel pkgconf libxkbcommon-x11-devel %description -Lapce is written in pure Rust, with a UI in Floem (also written in Rust). +Umide is written in pure Rust, with a UI in Floem (also written in Rust). It is designed with Rope Science from the Xi-Editor, enabling lightning-fast computation, and leverages wgpu for rendering. %prep diff --git a/umide-core/build.rs b/umide-core/build.rs index d4a7d155..fda6f842 100644 --- a/umide-core/build.rs +++ b/umide-core/build.rs @@ -26,7 +26,7 @@ fn main() -> Result<()> { #[rustfmt::skip] let meta = format!(r#" - pub const NAME: &str = "Lapce-{branch}"; + pub const NAME: &str = "Umide-{branch}"; pub const VERSION: &str = "{version}"; pub const RELEASE: ReleaseType = ReleaseType::{branch}; "#); diff --git a/umide-core/src/directory.rs b/umide-core/src/directory.rs index 42849773..e5bc274d 100644 --- a/umide-core/src/directory.rs +++ b/umide-core/src/directory.rs @@ -13,7 +13,7 @@ impl Directory { #[cfg(not(feature = "portable"))] fn project_dirs() -> Option { - ProjectDirs::from("dev", "lapce", NAME) + ProjectDirs::from("dev", "umide", NAME) } /// Return path adjacent to lapce executable when built as portable @@ -21,7 +21,7 @@ impl Directory { fn project_dirs() -> Option { if let Ok(current_exe) = std::env::current_exe() { if let Some(parent) = current_exe.parent() { - return ProjectDirs::from_path(parent.join("lapce-data")); + return ProjectDirs::from_path(parent.join("umide-data")); } unreachable!("Couldn't obtain current process parent path"); } diff --git a/umide-core/src/language.rs b/umide-core/src/language.rs index b7056cd4..21bdc999 100644 --- a/umide-core/src/language.rs +++ b/umide-core/src/language.rs @@ -98,7 +98,7 @@ macro_rules! comment_properties { pub struct SyntaxProperties { /// An extra check to make sure that the array elements are in the correct order. /// If this id does not match the enum value, a panic will happen with a debug assertion message. - id: LapceLanguage, + id: UmideLanguage, /// All tokens that can be used for comments in language comment: CommentProperties, @@ -168,7 +168,7 @@ struct CommentProperties { } /// NOTE: Keep the enum variants "fieldless" so they can cast to usize as array -/// indices into the LANGUAGES array. See method `LapceLanguage::properties`. +/// indices into the LANGUAGES array. See method `UmideLanguage::properties`. /// /// Do not assign values to the variants because the number of variants and /// number of elements in the LANGUAGES array change as different features @@ -191,7 +191,7 @@ struct CommentProperties { )] #[strum(ascii_case_insensitive)] #[remain::sorted] -pub enum LapceLanguage { +pub enum UmideLanguage { // Do not move #[remain::unsorted] #[default] @@ -449,11 +449,11 @@ pub enum LapceLanguage { } /// NOTE: Elements in the array must be in the same order as the enum variants of -/// `LapceLanguage` as they will be accessed using the enum variants as indices. +/// `UmideLanguage` as they will be accessed using the enum variants as indices. const LANGUAGES: &[SyntaxProperties] = &[ // Undetected/unmatched fallback or just plain file SyntaxProperties { - id: LapceLanguage::PlainText, + id: UmideLanguage::PlainText, indent: Indent::tab(), files: &[], extensions: &["txt"], @@ -462,7 +462,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ }, // Languages SyntaxProperties { - id: LapceLanguage::Ada, + id: UmideLanguage::Ada, indent: Indent::tab(), files: &[], extensions: &[], @@ -470,7 +470,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Adl, + id: UmideLanguage::Adl, indent: Indent::tab(), files: &[], extensions: &[], @@ -478,7 +478,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Agda, + id: UmideLanguage::Agda, indent: Indent::tab(), files: &[], extensions: &[], @@ -486,7 +486,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Astro, + id: UmideLanguage::Astro, indent: Indent::tab(), files: &[], extensions: &[], @@ -494,7 +494,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Bash, + id: UmideLanguage::Bash, indent: Indent::space(2), files: &[], extensions: &["bash", "sh"], @@ -502,7 +502,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Bass, + id: UmideLanguage::Bass, indent: Indent::tab(), files: &[], extensions: &[], @@ -510,7 +510,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Beancount, + id: UmideLanguage::Beancount, indent: Indent::tab(), files: &[], extensions: &[], @@ -518,7 +518,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Bibtex, + id: UmideLanguage::Bibtex, indent: Indent::tab(), files: &[], extensions: &[], @@ -526,7 +526,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Bitbake, + id: UmideLanguage::Bitbake, indent: Indent::tab(), files: &[], extensions: &[], @@ -534,7 +534,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Blade, + id: UmideLanguage::Blade, indent: Indent::tab(), files: &[], extensions: &[], @@ -542,7 +542,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::C, + id: UmideLanguage::C, indent: Indent::space(4), files: &[], extensions: &["c", "h"], @@ -556,7 +556,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ }, }, SyntaxProperties { - id: LapceLanguage::Clojure, + id: UmideLanguage::Clojure, indent: Indent::space(2), files: &[], extensions: &[ @@ -573,7 +573,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Cmake, + id: UmideLanguage::Cmake, indent: Indent::space(2), files: &["cmakelists"], extensions: &["cmake"], @@ -587,7 +587,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ }, }, SyntaxProperties { - id: LapceLanguage::Comment, + id: UmideLanguage::Comment, indent: Indent::tab(), files: &[], extensions: &[], @@ -595,7 +595,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Cpp, + id: UmideLanguage::Cpp, indent: Indent::space(4), files: &[], extensions: &["cpp", "cxx", "cc", "c++", "hpp", "hxx", "hh", "h++"], @@ -613,7 +613,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ }, }, SyntaxProperties { - id: LapceLanguage::Csharp, + id: UmideLanguage::Csharp, indent: Indent::space(2), files: &[], extensions: &["cs", "csx"], @@ -638,7 +638,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ }, }, SyntaxProperties { - id: LapceLanguage::Css, + id: UmideLanguage::Css, indent: Indent::space(2), files: &[], extensions: &["css"], @@ -646,7 +646,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Cue, + id: UmideLanguage::Cue, indent: Indent::tab(), files: &[], extensions: &[], @@ -654,7 +654,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::D, + id: UmideLanguage::D, indent: Indent::space(4), files: &[], extensions: &["d", "di", "dlang"], @@ -668,7 +668,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Dart, + id: UmideLanguage::Dart, indent: Indent::space(2), files: &[], extensions: &["dart"], @@ -697,7 +697,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ }, }, SyntaxProperties { - id: LapceLanguage::Dhall, + id: UmideLanguage::Dhall, indent: Indent::tab(), files: &[], extensions: &[], @@ -705,7 +705,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Diff, + id: UmideLanguage::Diff, indent: Indent::tab(), files: &[], extensions: &["diff", "patch"], @@ -713,7 +713,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Dockerfile, + id: UmideLanguage::Dockerfile, indent: Indent::space(2), files: &["Dockerfile", "Containerfile"], extensions: &["containerfile", "dockerfile"], @@ -721,7 +721,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Dot, + id: UmideLanguage::Dot, indent: Indent::tab(), files: &[], extensions: &[], @@ -729,7 +729,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Elixir, + id: UmideLanguage::Elixir, indent: Indent::space(2), files: &[], extensions: &["ex", "exs", "eex", "heex", "sface"], @@ -743,7 +743,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ }, }, SyntaxProperties { - id: LapceLanguage::Elm, + id: UmideLanguage::Elm, indent: Indent::space(4), files: &[], extensions: &["elm"], @@ -751,7 +751,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Erlang, + id: UmideLanguage::Erlang, indent: Indent::space(4), files: &[], extensions: &["erl", "hrl"], @@ -759,7 +759,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::FSharp, + id: UmideLanguage::FSharp, indent: Indent::tab(), files: &[], extensions: &[], @@ -767,7 +767,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Fish, + id: UmideLanguage::Fish, indent: Indent::tab(), files: &[], extensions: &["fish"], @@ -775,7 +775,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Fluent, + id: UmideLanguage::Fluent, indent: Indent::tab(), files: &[], extensions: &[], @@ -783,7 +783,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Forth, + id: UmideLanguage::Forth, indent: Indent::tab(), files: &[], extensions: &[], @@ -791,7 +791,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Fortran, + id: UmideLanguage::Fortran, indent: Indent::tab(), files: &[], extensions: &[], @@ -799,7 +799,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Gitattributes, + id: UmideLanguage::Gitattributes, indent: Indent::tab(), files: &[], extensions: &[], @@ -807,7 +807,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::GitCommit, + id: UmideLanguage::GitCommit, indent: Indent::tab(), files: &[], extensions: &[], @@ -815,7 +815,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::GitConfig, + id: UmideLanguage::GitConfig, indent: Indent::tab(), files: &[".gitconfig", ".git/config"], extensions: &[], @@ -823,7 +823,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::GitRebase, + id: UmideLanguage::GitRebase, indent: Indent::tab(), files: &[], extensions: &[], @@ -831,7 +831,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Gleam, + id: UmideLanguage::Gleam, indent: Indent::tab(), files: &[], extensions: &[], @@ -839,7 +839,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Glimmer, + id: UmideLanguage::Glimmer, indent: Indent::space(2), files: &[], extensions: &["hbs"], @@ -847,7 +847,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Glsl, + id: UmideLanguage::Glsl, indent: Indent::space(2), files: &[], extensions: &[ @@ -860,7 +860,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Gn, + id: UmideLanguage::Gn, indent: Indent::tab(), files: &[], extensions: &[], @@ -868,7 +868,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Go, + id: UmideLanguage::Go, indent: Indent::tab(), files: &[], extensions: &["go"], @@ -891,7 +891,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ }, }, SyntaxProperties { - id: LapceLanguage::GoMod, + id: UmideLanguage::GoMod, indent: Indent::tab(), files: &[], extensions: &[], @@ -899,7 +899,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::GoTemplate, + id: UmideLanguage::GoTemplate, indent: Indent::tab(), files: &[], extensions: &[], @@ -907,7 +907,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::GoWork, + id: UmideLanguage::GoWork, indent: Indent::tab(), files: &[], extensions: &[], @@ -915,7 +915,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::GraphQl, + id: UmideLanguage::GraphQl, indent: Indent::tab(), files: &[], extensions: &[], @@ -923,7 +923,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Groovy, + id: UmideLanguage::Groovy, indent: Indent::tab(), files: &[], extensions: &[], @@ -931,7 +931,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Hare, + id: UmideLanguage::Hare, indent: Indent::space(8), files: &[], extensions: &["ha"], @@ -939,7 +939,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Haskell, + id: UmideLanguage::Haskell, indent: Indent::space(2), files: &[], extensions: &["hs"], @@ -947,7 +947,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Haxe, + id: UmideLanguage::Haxe, indent: Indent::space(2), files: &[], extensions: &["hx"], @@ -955,7 +955,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Hcl, + id: UmideLanguage::Hcl, indent: Indent::space(2), files: &[], extensions: &["hcl", "tf"], @@ -963,7 +963,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Hosts, + id: UmideLanguage::Hosts, indent: Indent::tab(), files: &[], extensions: &[], @@ -971,7 +971,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Html, + id: UmideLanguage::Html, indent: Indent::space(4), files: &[], extensions: &["html", "htm"], @@ -979,7 +979,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Ini, + id: UmideLanguage::Ini, indent: Indent::tab(), files: &[], extensions: &[], @@ -987,7 +987,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Java, + id: UmideLanguage::Java, indent: Indent::space(4), files: &[], extensions: &["java"], @@ -995,7 +995,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Javascript, + id: UmideLanguage::Javascript, indent: Indent::space(2), files: &[], extensions: &["js", "cjs", "mjs"], @@ -1009,7 +1009,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ }, }, SyntaxProperties { - id: LapceLanguage::Jsdoc, + id: UmideLanguage::Jsdoc, indent: Indent::tab(), files: &[], extensions: &[], @@ -1017,7 +1017,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Json, + id: UmideLanguage::Json, indent: Indent::space(4), files: &[], extensions: &["json", "har"], @@ -1025,7 +1025,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Json5, + id: UmideLanguage::Json5, indent: Indent::tab(), files: &[], extensions: &[], @@ -1033,7 +1033,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Jsonnet, + id: UmideLanguage::Jsonnet, indent: Indent::tab(), files: &[], extensions: &[], @@ -1041,7 +1041,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Jsx, + id: UmideLanguage::Jsx, indent: Indent::space(2), files: &[], extensions: &["jsx"], @@ -1055,7 +1055,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ }, }, SyntaxProperties { - id: LapceLanguage::Julia, + id: UmideLanguage::Julia, indent: Indent::space(4), files: &[], extensions: &["julia", "jl"], @@ -1069,7 +1069,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Just, + id: UmideLanguage::Just, indent: Indent::tab(), files: &["justfile", "Justfile", ".justfile", ".Justfile"], extensions: &["just"], @@ -1077,7 +1077,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Kdl, + id: UmideLanguage::Kdl, indent: Indent::tab(), files: &[], extensions: &[], @@ -1085,7 +1085,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Kotlin, + id: UmideLanguage::Kotlin, indent: Indent::space(2), files: &[], extensions: &["kt"], @@ -1100,7 +1100,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::KotlinBuildScript, + id: UmideLanguage::KotlinBuildScript, indent: Indent::space(2), files: &[], extensions: &["kts"], @@ -1115,7 +1115,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Latex, + id: UmideLanguage::Latex, indent: Indent::space(2), files: &[], extensions: &["tex"], @@ -1123,7 +1123,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Ld, + id: UmideLanguage::Ld, indent: Indent::tab(), files: &[], extensions: &[], @@ -1131,7 +1131,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Llvm, + id: UmideLanguage::Llvm, indent: Indent::tab(), files: &[], extensions: &[], @@ -1139,7 +1139,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::LlvmMir, + id: UmideLanguage::LlvmMir, indent: Indent::tab(), files: &[], extensions: &[], @@ -1147,7 +1147,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Log, + id: UmideLanguage::Log, indent: Indent::tab(), files: &["log.txt"], extensions: &["log"], @@ -1155,7 +1155,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Lua, + id: UmideLanguage::Lua, indent: Indent::space(2), files: &[], extensions: &["lua"], @@ -1163,7 +1163,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Make, + id: UmideLanguage::Make, indent: Indent::tab(), files: &[], extensions: &[], @@ -1171,7 +1171,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Markdown, + id: UmideLanguage::Markdown, indent: Indent::space(4), files: &[], extensions: &["md"], @@ -1179,7 +1179,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::MarkdownInline, + id: UmideLanguage::MarkdownInline, indent: Indent::space(4), // markdown inline is only used as an injection by the Markdown language files: &[], @@ -1194,7 +1194,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ }, }, SyntaxProperties { - id: LapceLanguage::Meson, + id: UmideLanguage::Meson, indent: Indent::tab(), files: &[], extensions: &[], @@ -1202,7 +1202,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Nasm, + id: UmideLanguage::Nasm, indent: Indent::tab(), files: &[], extensions: &[], @@ -1210,7 +1210,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Nix, + id: UmideLanguage::Nix, indent: Indent::space(2), files: &[], extensions: &["nix"], @@ -1225,7 +1225,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Nushell, + id: UmideLanguage::Nushell, indent: Indent::tab(), files: &[], extensions: &[], @@ -1233,7 +1233,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Ocaml, + id: UmideLanguage::Ocaml, indent: Indent::space(2), files: &[], extensions: &["ml"], @@ -1248,7 +1248,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::OcamlInterface, + id: UmideLanguage::OcamlInterface, indent: Indent::space(2), files: &[], extensions: &["mli"], @@ -1256,7 +1256,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Odin, + id: UmideLanguage::Odin, indent: Indent::tab(), files: &[], extensions: &[], @@ -1264,7 +1264,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::OpenCl, + id: UmideLanguage::OpenCl, indent: Indent::tab(), files: &[], extensions: &[], @@ -1272,7 +1272,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Pascal, + id: UmideLanguage::Pascal, indent: Indent::tab(), files: &[], extensions: &[], @@ -1280,7 +1280,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Passwd, + id: UmideLanguage::Passwd, indent: Indent::tab(), files: &[], extensions: &[], @@ -1288,7 +1288,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Pem, + id: UmideLanguage::Pem, indent: Indent::tab(), files: &[], extensions: &[], @@ -1296,7 +1296,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Php, + id: UmideLanguage::Php, indent: Indent::space(2), files: &[], extensions: &["php"], @@ -1331,7 +1331,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ }, }, SyntaxProperties { - id: LapceLanguage::Pkl, + id: UmideLanguage::Pkl, indent: Indent::tab(), files: &[], extensions: &[], @@ -1339,7 +1339,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::PowerShell, + id: UmideLanguage::PowerShell, indent: Indent::space(4), files: &[], extensions: &["ps1", "psm1", "psd1", "ps1xml"], @@ -1353,7 +1353,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Prisma, + id: UmideLanguage::Prisma, indent: Indent::space(4), files: &[], extensions: &["prisma"], @@ -1361,7 +1361,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::ProtoBuf, + id: UmideLanguage::ProtoBuf, indent: Indent::space(2), files: &[], extensions: &["proto"], @@ -1369,7 +1369,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Python, + id: UmideLanguage::Python, indent: Indent::space(4), files: &[], extensions: &["py", "pyi", "pyc", "pyd", "pyw"], @@ -1394,7 +1394,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ }, }, SyntaxProperties { - id: LapceLanguage::Ql, + id: UmideLanguage::Ql, indent: Indent::space(2), files: &[], extensions: &["ql"], @@ -1402,7 +1402,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::R, + id: UmideLanguage::R, indent: Indent::space(2), files: &[], extensions: &["r"], @@ -1410,7 +1410,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Rcl, + id: UmideLanguage::Rcl, indent: Indent::tab(), files: &[], extensions: &[], @@ -1418,7 +1418,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Regex, + id: UmideLanguage::Regex, indent: Indent::tab(), files: &[], extensions: &[], @@ -1426,7 +1426,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Rego, + id: UmideLanguage::Rego, indent: Indent::tab(), files: &[], extensions: &[], @@ -1434,7 +1434,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Ron, + id: UmideLanguage::Ron, indent: Indent::tab(), files: &[], extensions: &[], @@ -1442,7 +1442,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Rst, + id: UmideLanguage::Rst, indent: Indent::tab(), files: &[], extensions: &[], @@ -1450,7 +1450,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Ruby, + id: UmideLanguage::Ruby, indent: Indent::space(2), files: &[], extensions: &["rb"], @@ -1464,7 +1464,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ }, }, SyntaxProperties { - id: LapceLanguage::Rust, + id: UmideLanguage::Rust, indent: Indent::space(4), files: &[], extensions: &["rs"], @@ -1486,7 +1486,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ }, }, SyntaxProperties { - id: LapceLanguage::Scala, + id: UmideLanguage::Scala, indent: Indent::tab(), files: &[], extensions: &[], @@ -1494,7 +1494,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Scheme, + id: UmideLanguage::Scheme, indent: Indent::space(2), files: &[], extensions: &["scm", "ss"], @@ -1502,7 +1502,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Scss, + id: UmideLanguage::Scss, indent: Indent::space(2), files: &[], extensions: &["scss"], @@ -1510,7 +1510,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::ShellScript, + id: UmideLanguage::ShellScript, indent: Indent::space(2), files: &[], extensions: &["sh"], @@ -1518,7 +1518,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Smithy, + id: UmideLanguage::Smithy, indent: Indent::tab(), files: &[], extensions: &[], @@ -1526,7 +1526,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Sql, + id: UmideLanguage::Sql, indent: Indent::space(2), files: &[], extensions: &["sql"], @@ -1534,7 +1534,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::SshClientConfig, + id: UmideLanguage::SshClientConfig, indent: Indent::tab(), files: &[], extensions: &[], @@ -1542,7 +1542,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Strace, + id: UmideLanguage::Strace, indent: Indent::tab(), files: &[], extensions: &[], @@ -1550,7 +1550,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Svelte, + id: UmideLanguage::Svelte, indent: Indent::space(2), files: &[], extensions: &["svelte"], @@ -1558,7 +1558,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Sway, + id: UmideLanguage::Sway, indent: Indent::tab(), files: &[], extensions: &[], @@ -1566,7 +1566,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Swift, + id: UmideLanguage::Swift, indent: Indent::space(2), files: &[], extensions: &["swift"], @@ -1574,7 +1574,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Tcl, + id: UmideLanguage::Tcl, indent: Indent::tab(), files: &[], extensions: &["tcl"], @@ -1582,7 +1582,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Toml, + id: UmideLanguage::Toml, indent: Indent::space(2), files: &["Cargo.lock"], extensions: &["toml"], @@ -1590,7 +1590,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Tsx, + id: UmideLanguage::Tsx, indent: Indent::space(4), files: &[], extensions: &["tsx"], @@ -1604,7 +1604,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ }, }, SyntaxProperties { - id: LapceLanguage::Typescript, + id: UmideLanguage::Typescript, indent: Indent::space(4), files: &[], extensions: &["ts", "cts", "mts"], @@ -1618,7 +1618,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ }, }, SyntaxProperties { - id: LapceLanguage::Typst, + id: UmideLanguage::Typst, indent: Indent::tab(), files: &[], extensions: &[], @@ -1626,7 +1626,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Verilog, + id: UmideLanguage::Verilog, indent: Indent::tab(), files: &[], extensions: &[], @@ -1634,7 +1634,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Vue, + id: UmideLanguage::Vue, indent: Indent::space(2), files: &[], extensions: &["vue"], @@ -1642,7 +1642,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Wasm, + id: UmideLanguage::Wasm, indent: Indent::space(4), files: &[], extensions: &["wasm"], @@ -1650,7 +1650,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Wgsl, + id: UmideLanguage::Wgsl, indent: Indent::space(4), files: &[], extensions: &["wgsl"], @@ -1658,7 +1658,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Wit, + id: UmideLanguage::Wit, indent: Indent::space(4), files: &[], extensions: &["wit"], @@ -1666,7 +1666,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Xml, + id: UmideLanguage::Xml, indent: Indent::space(4), files: &[], extensions: &["xml", "csproj"], @@ -1674,7 +1674,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Yaml, + id: UmideLanguage::Yaml, indent: Indent::space(2), files: &[], extensions: &["yml", "yaml"], @@ -1682,7 +1682,7 @@ const LANGUAGES: &[SyntaxProperties] = &[ tree_sitter: TreeSitterProperties::DEFAULT, }, SyntaxProperties { - id: LapceLanguage::Zig, + id: UmideLanguage::Zig, indent: Indent::space(4), files: &[], extensions: &["zig"], @@ -1691,15 +1691,15 @@ const LANGUAGES: &[SyntaxProperties] = &[ }, ]; -impl LapceLanguage { +impl UmideLanguage { const HIGHLIGHTS_INJECTIONS_FILE_NAME: &'static str = "injections.scm"; const HIGHLIGHTS_QUERIES_FILE_NAME: &'static str = "highlights.scm"; - pub fn from_path(path: &Path) -> LapceLanguage { - Self::from_path_raw(path).unwrap_or(LapceLanguage::PlainText) + pub fn from_path(path: &Path) -> UmideLanguage { + Self::from_path_raw(path).unwrap_or(UmideLanguage::PlainText) } - pub fn from_path_raw(path: &Path) -> Option { + pub fn from_path_raw(path: &Path) -> Option { let filename = path.file_name().and_then(|s| s.to_str()); let extension = path .extension() @@ -1722,11 +1722,11 @@ impl LapceLanguage { None } - pub fn from_name(name: &str) -> Option { - match LapceLanguage::from_str(name.to_lowercase().as_str()) { + pub fn from_name(name: &str) -> Option { + match UmideLanguage::from_str(name.to_lowercase().as_str()) { Ok(v) => Some(v), Err(e) => { - event!(Level::DEBUG, "failed parsing `{name}` LapceLanguage: {e}"); + event!(Level::DEBUG, "failed parsing `{name}` UmideLanguage: {e}"); None } } @@ -1788,7 +1788,7 @@ impl LapceLanguage { return Some(grammar); } Err(err) => { - if self != &LapceLanguage::PlainText { + if self != &UmideLanguage::PlainText { tracing::error!("{:?} {:?}", self, err); } } @@ -2064,11 +2064,11 @@ fn read_grammar_query(queries_dir: &Path, name: &str, kind: &str) -> String { mod tests { use std::path::PathBuf; - use super::LapceLanguage; + use super::UmideLanguage; #[test] fn test_lanaguage_from_path() { - let l = LapceLanguage::from_path(&PathBuf::new().join("test.rs")); - assert_eq!(l, LapceLanguage::Rust); + let l = UmideLanguage::from_path(&PathBuf::new().join("test.rs")); + assert_eq!(l, UmideLanguage::Rust); } } diff --git a/umide-core/src/syntax/highlight.rs b/umide-core/src/syntax/highlight.rs index 4b5fa7c7..fe91b6ce 100644 --- a/umide-core/src/syntax/highlight.rs +++ b/umide-core/src/syntax/highlight.rs @@ -26,10 +26,10 @@ use tree_sitter::{ }; use super::{PARSER, util::RopeProvider}; -use crate::{language::LapceLanguage, style::SCOPES}; +use crate::{language::UmideLanguage, style::SCOPES}; thread_local! { - static HIGHLIGHT_CONFIGS: RefCell, HighlightIssue>>> = Default::default(); + static HIGHLIGHT_CONFIGS: RefCell, HighlightIssue>>> = Default::default(); } pub fn reset_highlight_configs() { @@ -39,7 +39,7 @@ pub fn reset_highlight_configs() { } pub(crate) fn get_highlight_config( - lang: LapceLanguage, + lang: UmideLanguage, ) -> Result, HighlightIssue> { HIGHLIGHT_CONFIGS.with(|configs| { let mut configs = configs.borrow_mut(); diff --git a/umide-core/src/syntax/mod.rs b/umide-core/src/syntax/mod.rs index c4f7c816..65cf67bf 100644 --- a/umide-core/src/syntax/mod.rs +++ b/umide-core/src/syntax/mod.rs @@ -39,7 +39,7 @@ use self::{ }; use crate::{ buffer::{Buffer, rope_text::RopeText}, - language::{self, LapceLanguage}, + language::{self, UmideLanguage}, lens::{Lens, LensBuilder}, style::SCOPES, syntax::highlight::InjectionLanguageMarker, @@ -513,12 +513,12 @@ impl SyntaxLayers { let injection_callback = |language: &InjectionLanguageMarker| { let language = match language { InjectionLanguageMarker::Name(name) => { - LapceLanguage::from_name(name) + UmideLanguage::from_name(name) } InjectionLanguageMarker::Filename(path) => { - LapceLanguage::from_path_raw(path) + UmideLanguage::from_path_raw(path) } - InjectionLanguageMarker::Shebang(id) => LapceLanguage::from_name(id), + InjectionLanguageMarker::Shebang(id) => UmideLanguage::from_name(id), }; language .map(get_highlight_config) @@ -898,7 +898,7 @@ impl SyntaxLayers { #[derive(Clone)] pub struct Syntax { pub rev: u64, - pub language: LapceLanguage, + pub language: UmideLanguage, pub text: Rope, pub layers: Option, pub lens: Lens, @@ -925,15 +925,15 @@ impl std::fmt::Debug for Syntax { impl Syntax { pub fn init(path: &Path) -> Syntax { - let language = LapceLanguage::from_path(path); + let language = UmideLanguage::from_path(path); Syntax::from_language(language) } pub fn plaintext() -> Syntax { - Self::from_language(LapceLanguage::PlainText) + Self::from_language(UmideLanguage::PlainText) } - pub fn from_language(language: LapceLanguage) -> Syntax { + pub fn from_language(language: UmideLanguage) -> Syntax { let highlight = get_highlight_config(language).ok(); Syntax { rev: 0, @@ -1204,7 +1204,7 @@ impl Syntax { } pub fn find_enclosing_pair(&self, offset: usize) -> Option<(usize, usize)> { - if self.language == LapceLanguage::Markdown { + if self.language == UmideLanguage::Markdown { // TODO: fix the issue that sometimes node.prev_sibling can stuck for markdown return None; } diff --git a/umide-proxy/src/lib.rs b/umide-proxy/src/lib.rs index e0713dde..bc479aac 100644 --- a/umide-proxy/src/lib.rs +++ b/umide-proxy/src/lib.rs @@ -28,7 +28,7 @@ use umide_rpc::{ use tracing::error; #[derive(Parser)] -#[clap(name = "Lapce-proxy")] +#[clap(name = "Umide-proxy")] #[clap(version = meta::VERSION)] struct Cli { #[clap(short, long, action, hide = true)] @@ -145,8 +145,10 @@ pub fn register_lapce_path() -> Result<()> { let current_path = std::env::var("PATH")?; let paths = std::env::split_paths(¤t_path); for path in paths { - if exedir == path.canonicalize()? { - return Ok(()); + if let Ok(path) = path.canonicalize() { + if exedir == path { + return Ok(()); + } } } let paths = std::env::split_paths(¤t_path); diff --git a/umide-proxy/src/plugin/dap.rs b/umide-proxy/src/plugin/dap.rs index 671c4dc2..c2ce74b3 100644 --- a/umide-proxy/src/plugin/dap.rs +++ b/umide-proxy/src/plugin/dap.rs @@ -320,7 +320,7 @@ impl DapClient { pub(crate) fn initialize(&mut self) -> Result<()> { let params = dap_types::InitializeParams { client_id: Some("lapce".to_owned()), - client_name: Some("Lapce".to_owned()), + client_name: Some("Umide".to_owned()), adapter_id: "".to_string(), locale: Some("en-us".to_owned()), lines_start_at_one: Some(true), diff --git a/umide-proxy/src/plugin/wasi.rs b/umide-proxy/src/plugin/wasi.rs index 399e1b72..2d459daa 100644 --- a/umide-proxy/src/plugin/wasi.rs +++ b/umide-proxy/src/plugin/wasi.rs @@ -268,7 +268,7 @@ pub fn load_all_volts( } /// Find all installed volts. -/// `plugin_dev_path` allows launching Lapce with a plugin on your local system for testing +/// `plugin_dev_path` allows launching Umide with a plugin on your local system for testing /// purposes. /// As well, this function skips any volt in the typical plugin directory that match the name /// of the dev plugin so as to support developing a plugin you actively use. From d0a69f1f2cc2a736444afc4d601f91a9a8c7904b Mon Sep 17 00:00:00 2001 From: tuandevccs Date: Tue, 3 Feb 2026 19:38:24 +0100 Subject: [PATCH 03/30] edit dependencies --- Cargo.lock | 2 ++ Cargo.toml | 1 + crates/umide/Cargo.toml | 2 ++ 3 files changed, 5 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 1adb9ae3..9a78a324 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8251,6 +8251,8 @@ dependencies = [ "dmg", "flate2", "floem", + "floem-editor-core", + "floem_renderer 0.2.0", "fs_extra", "globset", "im", diff --git a/Cargo.toml b/Cargo.toml index f6885972..fda98f19 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -81,6 +81,7 @@ umide_native = { path = "./crates/umide_native" } # floem = { git = "https://github.com/lapce/floem", rev = "e0dd862564e3afbad5cba8ebe60df166a7a41e56", features = ["editor", "serde", "default-image-formats", "rfd-async-std"] } floem = { path = "../floem", features = ["editor", "serde", "default-image-formats"] } +floem_renderer = { path = "../floem/renderer" } # floem-editor-core = { git = "https://github.com/lapce/floem", rev = "e0dd862564e3afbad5cba8ebe60df166a7a41e56", features = ["serde"] } floem-editor-core = { path = "../floem/editor-core/", features = ["serde"] } [patch.crates-io] diff --git a/crates/umide/Cargo.toml b/crates/umide/Cargo.toml index a7489070..22da4192 100644 --- a/crates/umide/Cargo.toml +++ b/crates/umide/Cargo.toml @@ -58,6 +58,8 @@ unicode-width = { version = "0.2.2" } nucleo = { version = "0.5.0" } bytemuck = { version = "1.22.0" } config = { version = "0.15.19", default-features = false, features = ["toml"] } +floem_renderer = { workspace = true } +floem-editor-core = { workspace = true } structdesc = { path = "../../vendor/structdesc" } base64 = { version = "0.22.1" } sha2 = { version = "0.10.8" } From 01bfcfda5d993c93cfca51bab2fd1532a1661af3 Mon Sep 17 00:00:00 2001 From: tuandevccs Date: Wed, 4 Feb 2026 12:45:02 +0100 Subject: [PATCH 04/30] embed native emulator into the panels --- crates/umide/src/panel/emulator_view.rs | 326 ++++++++++++++---- crates/umide_emulator/src/android.rs | 138 ++++++-- crates/umide_emulator/src/ios.rs | 39 +++ crates/umide_emulator/src/lib.rs | 35 ++ crates/umide_emulator/src/native_view.rs | 8 +- .../cpp/include/umide_native_api.h | 6 +- crates/umide_native/cpp/src/emulator.h | 6 +- crates/umide_native/cpp/src/emulator_api.cpp | 8 +- .../cpp/src/macos/macos_emulator.mm | 109 ++++-- crates/umide_native/src/emulator.rs | 4 +- 10 files changed, 540 insertions(+), 139 deletions(-) diff --git a/crates/umide/src/panel/emulator_view.rs b/crates/umide/src/panel/emulator_view.rs index 9b729a65..3863b3ec 100644 --- a/crates/umide/src/panel/emulator_view.rs +++ b/crates/umide/src/panel/emulator_view.rs @@ -1,6 +1,7 @@ use std::{rc::Rc, sync::Arc}; use floem::{ - View, ViewId, prelude::{SignalGet, SignalUpdate}, reactive::{RwSignal, Effect}, + View, ViewId, prelude::{SignalGet, SignalUpdate}, + reactive::{RwSignal, Effect}, views::{Decorators, Label, Scroll, Stack, dyn_stack, Container}, context::{PaintCx, UpdateCx, ComputeLayoutCx}, peniko::kurbo::Rect, @@ -13,7 +14,8 @@ use crate::{ config::{icon::UmideIcons, color::UmideColor}, }; use umide_emulator::{ - list_all_devices, launch_device, stop_device, DeviceInfo, DevicePlatform, DeviceState, + list_all_devices, launch_device, stop_device, + DeviceInfo, DevicePlatform, DeviceState, native_view::NativeEmulatorView, }; use umide_native::emulator::EmulatorPlatform; @@ -22,17 +24,35 @@ struct NativeEmulatorWidget { id: ViewId, native_view: Option, running_device: RwSignal>, + is_visible: RwSignal, #[allow(dead_code)] current_device_id: RwSignal, + /// Track the last device ID we initialized for, to detect changes + last_device_id: Option, } impl NativeEmulatorWidget { - pub fn new(running_device: RwSignal>, current_device_id: RwSignal) -> Self { + pub fn new( + running_device: RwSignal>, + is_visible: RwSignal, + current_device_id: RwSignal, + ) -> Self { Self { id: ViewId::new(), native_view: None, running_device, + is_visible, current_device_id, + last_device_id: None, + } + } + + /// Cleanup the native view + fn cleanup(&mut self) { + if self.native_view.is_some() { + tracing::info!("Cleaning up native emulator view"); + self.native_view = None; + self.last_device_id = None; } } } @@ -47,58 +67,145 @@ impl View for NativeEmulatorWidget { } fn update(&mut self, _cx: &mut UpdateCx, _state: Box) { - // Handle updates if needed + let current_device = self.running_device.get_untracked(); + let is_visible = self.is_visible.get_untracked(); + + // If not visible, cleanup the native view but keep device info + if !is_visible && self.native_view.is_some() { + tracing::info!("Hiding emulator view, cleaning up native view"); + self.native_view = None; + // Don't clear last_device_id to enable resume + } + + // Check if device was stopped - cleanup if so + match (¤t_device, &self.last_device_id) { + (None, Some(_)) => { + // Device was stopped, cleanup + self.cleanup(); + } + (Some(dev), Some(last_id)) if &dev.id != last_id => { + // Different device, cleanup old and let compute_layout initialize new + self.cleanup(); + } + _ => {} + } } fn compute_layout(&mut self, _cx: &mut ComputeLayoutCx) -> Option { + let is_visible = self.is_visible.get_untracked(); + + // If not visible, don't create/update native view + if !is_visible { + return None; + } + // Get layout after it's been computed if let Some(layout) = self.id.get_layout() { let width = layout.size.width as u32; let height = layout.size.height as u32; + // Skip if size is zero + if width == 0 || height == 0 { + return None; + } + + // Check if current device matches what we have initialized + let current_device = self.running_device.get_untracked(); + + // If no device running but we have a view, cleanup + if current_device.is_none() && self.native_view.is_some() { + self.cleanup(); + return None; + } + + if let Some(_view) = &self.native_view { + // Resize/Move handled in paint() where we have absolute coordinates + } + // Note: Creation moved to paint() to ensure we have layout + + Some(Rect::new(0.0, 0.0, width as f64, height as f64)) + } else { + None + } + } + + fn paint(&mut self, _cx: &mut floem::context::PaintCx) { + let is_visible = self.is_visible.get_untracked(); + let current_device = self.running_device.get_untracked(); + + // Header height offset: font_size(12) + padding(6*2) + border(1) + container padding ≈ 35px + // This is needed because get_window_origin() returns the panel's top, not the content area + const HEADER_HEIGHT: i32 = 35; + + // Get window_origin for absolute position + let window_origin = self.id.get_window_origin(); + + let size = self.id.get_layout().map(|l| (l.size.width as u32, l.size.height as u32)); + + if let Some((width, height)) = size { + if width == 0 || height == 0 { + return; + } + + // Use window_origin and add header offset to Y + let x = window_origin.x as i32; + let y = window_origin.y as i32 + HEADER_HEIGHT; + // Use original height - the widget's layout should already account for content area + + // Get device name for debugging + let device_name = current_device.as_ref().map(|d| d.name.as_str()).unwrap_or("unknown"); + + tracing::debug!( + "NativeEmulatorWidget [{}]: origin=({},{}) adjusted_y={} size={}x{}", + device_name, window_origin.x as i32, window_origin.y as i32, y, width, height + ); + if let Some(view) = &self.native_view { - view.resize(width, height); - } else { - // Initialize the native view if we have a window handle - use floem::window::WindowIdExt; - - if let Some(window_id) = self.id.window_id() { - if let Some(handle) = window_id.raw_window_handle() { - // Determine the platform from the running device signal - if let Some(device) = self.running_device.get_untracked() { + // Update native view position and size to match the layout rect in window coordinates + view.resize(x, y, width, height); + } else if is_visible { + if let Some(device) = current_device { + // Initialize the native view if we have a window handle + use floem::window::WindowIdExt; + + if let Some(window_id) = self.id.window_id() { + if let Some(handle) = window_id.raw_window_handle() { let platform = match device.platform { umide_emulator::common::DevicePlatform::Android => EmulatorPlatform::Android, umide_emulator::common::DevicePlatform::Ios => EmulatorPlatform::Ios, }; - match NativeEmulatorView::new(handle, width, height, platform) { + tracing::info!( + "Creating native emulator view for device: {} at ({},{}) size {}x{}", + device.name, x, y, width, height + ); + + match NativeEmulatorView::new( + handle, + x, + y, + width, + height, + platform + ) { Ok(view) => { - tracing::info!("Successfully created native emulator view for device: {}", device.name); - // Attach device if ID is available if !device.id.is_empty() { view.attach_device(&device.id); } self.native_view = Some(view); + self.last_device_id = Some(device.id.clone()); } Err(e) => { tracing::error!("Failed to create native emulator view: {}", e); } } - } else { - // Should not happen if view is visible only when running, but handle gracefully - tracing::warn!("NativeEmulatorWidget layout called but no device is running"); } } } } } - None - } - - fn paint(&mut self, _cx: &mut PaintCx) { - // Native view handles painting on its own layer/surface } } @@ -107,7 +214,8 @@ fn platform_panel( platform: DevicePlatform, devices: RwSignal>, running_device: RwSignal>, - frame_signal: RwSignal>>, // Kept for API compat, likely unused + is_visible: RwSignal, + frame_signal: RwSignal>>, current_device_id: RwSignal, config: floem::reactive::ReadSignal>, ) -> impl View { @@ -121,24 +229,52 @@ fn platform_panel( move |device: DeviceInfo| { let device_cloned_start = device.clone(); let device_cloned_stop = device.clone(); + let device_cloned_resume = device.clone(); let is_running = device.state == DeviceState::Running; let is_starting = device.state == DeviceState::Starting; let is_disconnected = device.state == DeviceState::Disconnected; Stack::new(( Label::new(device.name.clone()) - .style(|s| s.flex_grow(1.0).padding_horiz(6.0)), + .style(|s| s.flex_grow(1.0).padding_horiz(6.0).text_ellipsis()), + // Start/Resume/Show button clickable_icon( || UmideIcons::DEBUG_CONTINUE, move || { + // Check if this device is already running but hidden + if let Some(ref running) = running_device.get_untracked() { + if running.id == device_cloned_resume.id { + // Just show it again + is_visible.set(true); + return; + } + } + // Start new device let _ = launch_device(&device_cloned_start); let mut d = device_cloned_start.clone(); d.state = DeviceState::Running; running_device.set(Some(d)); + is_visible.set(true); }, || false, - move || !is_disconnected, - || "Start", + move || { + // Visible if: + // 1. Device is disconnected (to Start) + // 2. OR Device is running AND hidden (to Show/Resume) + // So hidden if: device is running AND visible + if is_running { + // If running, hide "Start" button unless view is hidden + is_visible.get() + } else { + // If not running, show "Start" button unless starting? + // Original logic: !is_disconnected && !is_running -> hidden. + // Wait, is_disconnected means state == Disconnected. + // If state == Starting, is_disconnected = false, is_running = false. + // Then hidden = true. Correct (don't show start while starting). + !is_disconnected + } + }, + move || if is_running { "Show" } else { "Start" }, config, ), clickable_icon( @@ -146,6 +282,7 @@ fn platform_panel( move || { let _ = stop_device(&device_cloned_stop); running_device.set(None); + is_visible.set(false); frame_signal.set(None); current_device_id.set(String::new()); }, @@ -164,19 +301,36 @@ fn platform_panel( .items_center() .padding_vert(5.0) .border_bottom(1.0) + .gap(2.0) }) } }; Stack::new(( - // Header + // Header with device name if running Container::new( - Label::new(platform_name.to_string()) - .style(move |s| { - s.font_size(12.0) - .font_bold() - .padding(6.0) + Stack::horizontal(( + Label::new(platform_name.to_string()) + .style(move |s| { + s.font_size(12.0) + .font_bold() + .padding(6.0) + }), + // Show running device name in header + Label::derived(move || { + if let Some(device) = running_device.get() { + if is_visible.get() { + format!(" - {}", device.name) + } else { + format!(" - {} (hidden)", device.name) + } + } else { + String::new() + } }) + .style(|s| s.font_size(10.0).padding_right(6.0)), + )) + .style(|s| s.width_full().items_center()) ) .style(move |s| { let config = config.get(); @@ -185,17 +339,20 @@ fn platform_panel( .border_color(config.color(UmideColor::LAPCE_BORDER)) }), - // Content: Device list + // Content: Device list OR Emulator view Stack::new(( + // Device list (shown when no device or hidden) Scroll::new( dyn_stack( move || { - // Only show list if no device running (or can show generic list) - // Simplified: Show list always, but maybe disable items? - // logic from before: hide if running. - if running_device.get().is_some() { - return Vec::new(); + let visible = is_visible.get(); + let has_running = running_device.get().is_some(); + + // Show list if not visible or no device running + if has_running && visible { + return Vec::new(); } + let platform_filter = platform.clone(); devices.get().into_iter() .filter(|d| d.platform == platform_filter) @@ -206,33 +363,61 @@ fn platform_panel( ).style(|s| s.flex_col().width_full()) ) .style(move |s| { + let visible = is_visible.get(); + let has_running = running_device.get().is_some(); s.flex_grow(1.0) .width_full() - .apply_if(running_device.get().is_some(), |s| s.hide()) + .apply_if(has_running && visible, |s| s.hide()) }), - // Native Emulator View + // Native Emulator View (shown when device running AND visible) Stack::new(( - NativeEmulatorWidget::new(running_device, current_device_id), - clickable_icon( - || UmideIcons::CLOSE, - move || { - running_device.set(None); - frame_signal.set(None); - current_device_id.set(String::new()); - }, - || false, - || false, - || "Back to list", - config, - ).style(|s| s.absolute().margin_left(5.0).margin_top(5.0)) + NativeEmulatorWidget::new(running_device, is_visible, current_device_id) + .style(|s| s.flex_grow(1.0).width_full()), + // Control buttons overlay + Stack::horizontal(( + // Stop button - actually stops the emulator/simulator + clickable_icon( + || UmideIcons::DEBUG_STOP, + move || { + if let Some(device) = running_device.get_untracked() { + tracing::info!("Stopping device: {}", device.name); + if let Err(e) = stop_device(&device) { + tracing::error!("Failed to stop device {}: {}", device.name, e); + } + } + running_device.set(None); + is_visible.set(false); + frame_signal.set(None); + current_device_id.set(String::new()); + }, + || false, + || false, + || "Stop Emulator", + config, + ), + // Hide button - hides without stopping + clickable_icon( + || UmideIcons::CLOSE, + move || { + tracing::info!("Hiding emulator view (device still running)"); + is_visible.set(false); + }, + || false, + || false, + || "Hide (keep running)", + config, + ), + )) + .style(|s| s.absolute().margin_left(5.0).margin_top(5.0).gap(5.0)) )) .style(move |s| { - s.flex_col() + let visible = is_visible.get(); + let has_running = running_device.get().is_some(); + s.flex_col() .width_full() .flex_grow(1.0) - .min_height(300.0) - .apply_if(running_device.get().is_none(), |s| s.hide()) + .apply_if(!has_running || !visible, |s| s.hide()) }) )) .style(|s| s.flex_col().flex_grow(1.0).width_full()), @@ -241,7 +426,10 @@ fn platform_panel( let config = config.get(); s.flex_col() .flex_grow(1.0) - .min_width(180.0) + .flex_basis(0.0) + .min_width(200.0) + .min_height(300.0) + .height_full() .border(1.0) .border_color(config.color(UmideColor::LAPCE_BORDER)) }) @@ -258,6 +446,10 @@ pub fn emulator_panel( let running_android = RwSignal::new(None::); let running_ios = RwSignal::new(None::); + // Visibility signals (separate from running state for hide/resume) + let android_visible = RwSignal::new(false); + let ios_visible = RwSignal::new(false); + // Track current device IDs for capture management let current_android_id = RwSignal::new(String::new()); let current_ios_id = RwSignal::new(String::new()); @@ -266,7 +458,7 @@ pub fn emulator_panel( let android_frame = window_tab_data.panel.android_frame; let ios_frame = window_tab_data.panel.ios_frame; - // Effect to fetch devices + // Effect to fetch devices and update running state Effect::new(move |_| { let dev_list = list_all_devices(); @@ -277,11 +469,15 @@ pub fn emulator_panel( DevicePlatform::Android => { if running_android.get().is_none() { running_android.set(Some(device.clone())); + // Don't auto-show, let user click "Show" + // android_visible.set(true); } } DevicePlatform::Ios => { if running_ios.get().is_none() { running_ios.set(Some(device.clone())); + // Don't auto-show, let user click "Show" + // ios_visible.set(true); } } } @@ -299,6 +495,7 @@ pub fn emulator_panel( DevicePlatform::Android, devices, running_android, + android_visible, android_frame, current_android_id, config, @@ -307,13 +504,20 @@ pub fn emulator_panel( DevicePlatform::Ios, devices, running_ios, + ios_visible, ios_frame, current_ios_id, config, ), )) - .style(|s| s.flex_row().size_full().gap(5.0).padding(5.0)), + .style(|s| { + s.flex_row() + .size_full() + .gap(5.0) + .padding(5.0) + }), window_tab_data.panel.section_open(crate::panel::data::PanelSection::Process), ) .build() } + diff --git a/crates/umide_emulator/src/android.rs b/crates/umide_emulator/src/android.rs index d6026088..945f7ac5 100644 --- a/crates/umide_emulator/src/android.rs +++ b/crates/umide_emulator/src/android.rs @@ -16,6 +16,57 @@ impl AndroidEmulator { } } + /// Get list of currently running emulator serials from adb devices + pub fn get_running_serials() -> Vec { + let output = match Command::new("adb") + .arg("devices") + .output() { + Ok(out) => out, + Err(_) => return Vec::new(), + }; + + if !output.status.success() { + return Vec::new(); + } + + let stdout = String::from_utf8_lossy(&output.stdout); + stdout + .lines() + .skip(1) // Skip "List of devices" header + .filter_map(|line| { + let parts: Vec<&str> = line.split_whitespace().collect(); + if parts.len() >= 2 && parts[0].starts_with("emulator-") && parts[1] == "device" { + Some(parts[0].to_string()) + } else { + None + } + }) + .collect() + } + + /// Check if an AVD is currently running + pub fn is_running(avd_name: &str) -> bool { + let running = Self::get_running_serials(); + if running.is_empty() { + return false; + } + + // Check if any running emulator corresponds to this AVD + // We need to query each emulator for its AVD name + for serial in &running { + if let Ok(output) = Command::new("adb") + .args(["-s", serial, "emu", "avd", "name"]) + .output() + { + let name = String::from_utf8_lossy(&output.stdout); + if name.trim() == avd_name || name.lines().next().map(|l| l.trim()) == Some(avd_name) { + return true; + } + } + } + false + } + pub fn list_devices() -> Result> { let output = Command::new("emulator") .arg("-list-avds") @@ -55,54 +106,71 @@ impl AndroidEmulator { } pub fn stop(avd_name: &str) -> Result<()> { - // First, try to find the emulator by AVD name in adb devices - let output = Command::new("adb") - .arg("devices") - .arg("-l") - .output()?; - - if !output.status.success() { - return Err(anyhow!("Failed to list adb devices")); + tracing::info!("Attempting to stop Android emulator for AVD: {}", avd_name); + + // Get all running emulator serials + let running_serials = Self::get_running_serials(); + + if running_serials.is_empty() { + tracing::warn!("No running emulators found"); + return Err(anyhow!("No running emulators found")); } - - let stdout = String::from_utf8_lossy(&output.stdout); - // Look for emulator serial that matches AVD name - for line in stdout.lines() { - if line.contains(avd_name) || line.contains(&avd_name.to_lowercase()) { - if let Some(serial) = line.split_whitespace().next() { - if serial.starts_with("emulator-") { - let result = Command::new("adb") - .arg("-s") - .arg(serial) - .arg("emu") - .arg("kill") - .output(); - - if result.is_ok() { - return Ok(()); + // Find the emulator that matches this AVD name + for serial in &running_serials { + // Query the AVD name for this emulator + if let Ok(output) = Command::new("adb") + .args(["-s", serial, "emu", "avd", "name"]) + .output() + { + let name = String::from_utf8_lossy(&output.stdout); + let name_trimmed = name.lines().next().map(|l| l.trim()).unwrap_or(""); + + tracing::debug!("Emulator {} has AVD name: '{}'", serial, name_trimmed); + + if name_trimmed == avd_name { + tracing::info!("Found matching emulator {} for AVD {}, sending kill command", serial, avd_name); + + // Kill this emulator + let result = Command::new("adb") + .args(["-s", serial, "emu", "kill"]) + .output(); + + match result { + Ok(output) => { + if output.status.success() { + tracing::info!("Successfully killed emulator {}", serial); + return Ok(()); + } else { + let stderr = String::from_utf8_lossy(&output.stderr); + tracing::error!("Failed to kill emulator {}: {}", serial, stderr); + } + } + Err(e) => { + tracing::error!("Failed to execute adb kill command: {}", e); } } } } } - // Fallback: kill first running emulator - for line in stdout.lines() { - if let Some(serial) = line.split_whitespace().next() { - if serial.starts_with("emulator-") && line.contains("device") { - let _ = Command::new("adb") - .arg("-s") - .arg(serial) - .arg("emu") - .arg("kill") - .output(); + // If we didn't find a matching AVD, try to kill by partial name match + tracing::warn!("No exact AVD match found, trying partial match..."); + for serial in &running_serials { + // Just kill the first one as fallback + let result = Command::new("adb") + .args(["-s", serial, "emu", "kill"]) + .output(); + + if let Ok(output) = result { + if output.status.success() { + tracing::info!("Killed emulator {} as fallback", serial); return Ok(()); } } } - Err(anyhow!("Could not find running emulator for AVD: {}", avd_name)) + Err(anyhow!("Could not find or stop emulator for AVD: {}", avd_name)) } pub async fn stream_video(&mut self) -> Result>> { diff --git a/crates/umide_emulator/src/ios.rs b/crates/umide_emulator/src/ios.rs index 94abb309..9d4aec35 100644 --- a/crates/umide_emulator/src/ios.rs +++ b/crates/umide_emulator/src/ios.rs @@ -13,6 +13,45 @@ impl IosSimulator { Self { udid } } + /// Get list of currently booted simulator UDIDs + pub fn get_booted_udids() -> Vec { + let output = match Command::new("xcrun") + .args(["simctl", "list", "--json", "devices", "booted"]) + .output() { + Ok(out) => out, + Err(_) => return Vec::new(), + }; + + if !output.status.success() { + return Vec::new(); + } + + let stdout = String::from_utf8_lossy(&output.stdout); + let v: Value = match serde_json::from_str(&stdout) { + Ok(v) => v, + Err(_) => return Vec::new(), + }; + + let mut udids = Vec::new(); + if let Some(runtimes) = v.get("devices").and_then(|d| d.as_object()) { + for (_runtime, devices) in runtimes { + if let Some(devices) = devices.as_array() { + for device in devices { + if let Some(udid) = device.get("udid").and_then(|u| u.as_str()) { + udids.push(udid.to_string()); + } + } + } + } + } + udids + } + + /// Check if a simulator is currently booted + pub fn is_running(udid: &str) -> bool { + Self::get_booted_udids().contains(&udid.to_string()) + } + pub fn list_devices() -> Result> { let output = Command::new("xcrun") .arg("simctl") diff --git a/crates/umide_emulator/src/lib.rs b/crates/umide_emulator/src/lib.rs index 2304f45e..72a786c3 100644 --- a/crates/umide_emulator/src/lib.rs +++ b/crates/umide_emulator/src/lib.rs @@ -12,16 +12,33 @@ pub use decoder::create_decoder; pub use grpc_client::{EmulatorGrpcClient, GrpcError}; pub use ios::IosSimulator; +/// List all available devices with their current state pub fn list_all_devices() -> Vec { let mut devices = Vec::new(); if let Ok(mut android_devices) = AndroidEmulator::list_devices() { + // Update states based on actual running status + let running_serials = AndroidEmulator::get_running_serials(); + for device in &mut android_devices { + if AndroidEmulator::is_running(&device.id) || + running_serials.iter().any(|s| s.contains(&device.id) || device.id.contains(s)) { + device.state = DeviceState::Running; + } + } devices.append(&mut android_devices); } #[cfg(target_os = "macos")] { if let Ok(mut ios_devices) = IosSimulator::list_devices() { + // iOS devices already have correct state from list_devices + // but let's double-check with booted list + let booted = IosSimulator::get_booted_udids(); + for device in &mut ios_devices { + if booted.contains(&device.id) { + device.state = DeviceState::Running; + } + } devices.append(&mut ios_devices); } } @@ -29,6 +46,23 @@ pub fn list_all_devices() -> Vec { devices } +/// Check if a specific device is currently running +pub fn is_device_running(device: &DeviceInfo) -> bool { + match device.platform { + DevicePlatform::Android => AndroidEmulator::is_running(&device.id), + DevicePlatform::Ios => IosSimulator::is_running(&device.id), + } +} + +/// Refresh the state of a single device +pub fn refresh_device_state(device: &mut DeviceInfo) { + device.state = if is_device_running(device) { + DeviceState::Running + } else { + DeviceState::Disconnected + }; +} + pub fn launch_device(device: &DeviceInfo) -> anyhow::Result<()> { match device.platform { DevicePlatform::Android => AndroidEmulator::launch(&device.id), @@ -42,3 +76,4 @@ pub fn stop_device(device: &DeviceInfo) -> anyhow::Result<()> { DevicePlatform::Ios => IosSimulator::stop(&device.id), } } + diff --git a/crates/umide_emulator/src/native_view.rs b/crates/umide_emulator/src/native_view.rs index dd6a86a4..23d6c00e 100644 --- a/crates/umide_emulator/src/native_view.rs +++ b/crates/umide_emulator/src/native_view.rs @@ -14,7 +14,7 @@ unsafe impl Send for NativeEmulatorView {} unsafe impl Sync for NativeEmulatorView {} impl NativeEmulatorView { - pub fn new(window_handle: RawWindowHandle, width: u32, height: u32, platform: EmulatorPlatform) -> Result { + pub fn new(window_handle: RawWindowHandle, x: i32, y: i32, width: u32, height: u32, platform: EmulatorPlatform) -> Result { let parent_ptr = match window_handle { #[cfg(target_os = "macos")] RawWindowHandle::AppKit(handle) => handle.ns_view.as_ptr(), @@ -22,7 +22,7 @@ impl NativeEmulatorView { }; let handle = unsafe { - umide_native_create_emulator(parent_ptr, width, height, platform) + umide_native_create_emulator(parent_ptr, x, y, width, height, platform) }; if handle.is_null() { @@ -32,9 +32,9 @@ impl NativeEmulatorView { } } - pub fn resize(&self, width: u32, height: u32) { + pub fn resize(&self, x: i32, y: i32, width: u32, height: u32) { unsafe { - umide_native_resize_emulator(self.handle, width, height); + umide_native_resize_emulator(self.handle, x, y, width, height); } } diff --git a/crates/umide_native/cpp/include/umide_native_api.h b/crates/umide_native/cpp/include/umide_native_api.h index fad1fe90..39c0209f 100644 --- a/crates/umide_native/cpp/include/umide_native_api.h +++ b/crates/umide_native/cpp/include/umide_native_api.h @@ -37,13 +37,13 @@ typedef struct { // Create a new emulator view hosted within the given parent window. // parent_window: On macOS, this is a void* pointer to an NSView. // On Windows, an HWND. Linux, XID/Wayland surface. -NativeEmulator* umide_native_create_emulator(void* parent_window, uint32_t width, uint32_t height, EmulatorPlatform platform); +NativeEmulator* umide_native_create_emulator(void* parent_window, int32_t x, int32_t y, uint32_t width, uint32_t height, EmulatorPlatform platform); // Destroy the emulator view void umide_native_destroy_emulator(NativeEmulator* emulator); -// Resize the emulator view -void umide_native_resize_emulator(NativeEmulator* emulator, uint32_t width, uint32_t height); +// Resize and move the emulator view +void umide_native_resize_emulator(NativeEmulator* emulator, int32_t x, int32_t y, uint32_t width, uint32_t height); // Send input to the emulator void umide_native_send_input(NativeEmulator* emulator, const EmulatorInputEvent* event); diff --git a/crates/umide_native/cpp/src/emulator.h b/crates/umide_native/cpp/src/emulator.h index 3453df8a..48d6b5d3 100644 --- a/crates/umide_native/cpp/src/emulator.h +++ b/crates/umide_native/cpp/src/emulator.h @@ -11,10 +11,10 @@ class Emulator { virtual ~Emulator() = default; // Initialize the native surface/window attachment - virtual bool initialize(void* parent_window, uint32_t width, uint32_t height) = 0; + virtual bool initialize(void* parent_window, int32_t x, int32_t y, uint32_t width, uint32_t height) = 0; - // Handle resizing - virtual void resize(uint32_t width, uint32_t height) = 0; + // Handle resizing and moving + virtual void resize(int32_t x, int32_t y, uint32_t width, uint32_t height) = 0; // Attach a specific emulator instance virtual void attach_device(const std::string& device_id) = 0; diff --git a/crates/umide_native/cpp/src/emulator_api.cpp b/crates/umide_native/cpp/src/emulator_api.cpp index e0e5ba93..5e9fbedd 100644 --- a/crates/umide_native/cpp/src/emulator_api.cpp +++ b/crates/umide_native/cpp/src/emulator_api.cpp @@ -6,7 +6,7 @@ using namespace umide; extern "C" { -NativeEmulator* umide_native_create_emulator(void* parent_window, uint32_t width, uint32_t height, EmulatorPlatform platform) { +NativeEmulator* umide_native_create_emulator(void* parent_window, int32_t x, int32_t y, uint32_t width, uint32_t height, EmulatorPlatform platform) { if (!parent_window) { std::cerr << "Error: parent_window is null" << std::endl; return nullptr; @@ -18,7 +18,7 @@ NativeEmulator* umide_native_create_emulator(void* parent_window, uint32_t width return nullptr; } - if (!emulator->initialize(parent_window, width, height)) { + if (!emulator->initialize(parent_window, x, y, width, height)) { std::cerr << "Error: Failed to initialize emulator" << std::endl; delete emulator; return nullptr; @@ -33,9 +33,9 @@ void umide_native_destroy_emulator(NativeEmulator* emulator) { } } -void umide_native_resize_emulator(NativeEmulator* emulator, uint32_t width, uint32_t height) { +void umide_native_resize_emulator(NativeEmulator* emulator, int32_t x, int32_t y, uint32_t width, uint32_t height) { if (emulator) { - reinterpret_cast(emulator)->resize(width, height); + reinterpret_cast(emulator)->resize(x, y, width, height); } } diff --git a/crates/umide_native/cpp/src/macos/macos_emulator.mm b/crates/umide_native/cpp/src/macos/macos_emulator.mm index 2edbca48..f715e5cb 100644 --- a/crates/umide_native/cpp/src/macos/macos_emulator.mm +++ b/crates/umide_native/cpp/src/macos/macos_emulator.mm @@ -27,10 +27,20 @@ - (void)drawRect:(NSRect)dirtyRect { } @end +// Helper for safe main thread execution +static void runOnMainThread(void (^block)(void)) { + if ([NSThread isMainThread]) { + block(); + } else { + dispatch_sync(dispatch_get_main_queue(), block); + } +} + namespace umide { class MacOSEmulator : public Emulator { private: + NSWindow* childWindow = nil; // The child window hosting the emulator UmideHostView* hostView = nil; NSView* parentView = nil; // Weak ref @@ -38,51 +48,94 @@ - (void)drawRect:(NSRect)dirtyRect { MacOSEmulator() {} ~MacOSEmulator() override { - if (hostView) { - dispatch_sync(dispatch_get_main_queue(), ^{ - [hostView removeFromSuperview]; - // hostView is autoreleased or strong ref depending on usage, - // but removeFromSuperview releases the parent's hold. + if (childWindow) { + runOnMainThread(^{ + NSWindow* parent = [childWindow parentWindow]; + if (parent) { + [parent removeChildWindow:childWindow]; + } + [childWindow close]; + childWindow = nil; hostView = nil; }); } } - bool initialize(void* parent_window, uint32_t width, uint32_t height) override { + bool initialize(void* parent_window, int32_t x, int32_t y, uint32_t width, uint32_t height) override { parentView = (__bridge NSView*)parent_window; - // Ensure we run UI updates on main thread __block bool success = false; - // We block here because init is expected to be synchronous for safety - dispatch_sync(dispatch_get_main_queue(), ^{ + runOnMainThread(^{ + NSWindow* parentWin = [parentView window]; + if (!parentWin) { + std::cerr << "MacOSEmulator: Parent view has no window!" << std::endl; + return; + } + + // Create a borderless child window (NSPanel for floating behavior) + // Initial frame will be set in resize(), creating 0-size for now + childWindow = [[NSPanel alloc] initWithContentRect:NSZeroRect + styleMask:NSWindowStyleMaskBorderless + backing:NSBackingStoreBuffered + defer:NO]; + + [childWindow setReleasedWhenClosed:NO]; + [childWindow setHidesOnDeactivate:NO]; + [childWindow setCanHide:NO]; + hostView = [[UmideHostView alloc] initWithFrame:NSMakeRect(0, 0, width, height)]; - if (!hostView) return; - - // Auto resize with parent - [hostView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; - - // Add to parent - [parentView addSubview:hostView]; - - // Use a CALayer for potential Metal backing [hostView setWantsLayer:YES]; - hostView.layer.backgroundColor = [[NSColor colorWithRed:0.1 green:0.1 blue:0.1 alpha:1.0] CGColor]; - + if (hostView.layer) { + hostView.layer.backgroundColor = [[NSColor blackColor] CGColor]; + } + + [childWindow setContentView:hostView]; + + // Attach to parent window + [parentWin addChildWindow:childWindow ordered:NSWindowAbove]; + + // Initial positioning + this->resize(x, y, width, height); + success = true; }); return success; } - void resize(uint32_t width, uint32_t height) override { - // Auto-resizing mask should handle frame changes if parent changes, - // but if we need explicit sizing: - dispatch_async(dispatch_get_main_queue(), ^{ - if (hostView) { - [hostView setFrameSize:NSMakeSize(width, height)]; - } - }); + void resize(int32_t x, int32_t y, uint32_t width, uint32_t height) override { + dispatch_async(dispatch_get_main_queue(), ^{ + if (parentView && childWindow) { + NSWindow* parentWin = [parentView window]; + if (!parentWin) return; + + // Get the parent window's frame on screen + NSRect windowFrame = [parentWin frame]; + NSRect contentRect = [parentWin contentLayoutRect]; + + // Floem coordinates: (x, y) is top-left of widget in window content coordinates + // macOS screen coordinates: origin is bottom-left of screen, Y goes up + + // Convert: Floem's (x, y from top-left) to screen coords + // The widget's TOP should be at: windowFrame.origin.y + windowFrame.size.height - contentRect.origin.y - y + // The widget's BOTTOM should be at: top - height + + CGFloat screenX = windowFrame.origin.x + x; + CGFloat screenTop = windowFrame.origin.y + windowFrame.size.height - contentRect.origin.y - y; + CGFloat screenY = screenTop - height; // screenY is BOTTOM of the rect in screen coords + + NSRect rectInScreen = NSMakeRect(screenX, screenY, width, height); + + NSLog(@"MacOSEmulator resize: input=(%d,%d,%u,%u) winFrame=(%.0f,%.0f,%.0f,%.0f) content=(%.0f,%.0f) screen=(%.0f,%.0f,%.0f,%.0f)", + x, y, width, height, + windowFrame.origin.x, windowFrame.origin.y, windowFrame.size.width, windowFrame.size.height, + contentRect.origin.x, contentRect.origin.y, + rectInScreen.origin.x, rectInScreen.origin.y, rectInScreen.size.width, rectInScreen.size.height); + + [childWindow setFrame:rectInScreen display:YES]; + } + }); } void attach_device(const std::string& device_id) override { diff --git a/crates/umide_native/src/emulator.rs b/crates/umide_native/src/emulator.rs index 3280b3f5..183e537f 100644 --- a/crates/umide_native/src/emulator.rs +++ b/crates/umide_native/src/emulator.rs @@ -31,6 +31,8 @@ pub struct EmulatorInputEvent { extern "C" { pub fn umide_native_create_emulator( parent_window: *mut c_void, + x: i32, + y: i32, width: u32, height: u32, platform: EmulatorPlatform @@ -38,7 +40,7 @@ extern "C" { pub fn umide_native_destroy_emulator(emulator: *mut NativeEmulator); - pub fn umide_native_resize_emulator(emulator: *mut NativeEmulator, width: u32, height: u32); + pub fn umide_native_resize_emulator(emulator: *mut NativeEmulator, x: i32, y: i32, width: u32, height: u32); pub fn umide_native_send_input(emulator: *mut NativeEmulator, event: *const EmulatorInputEvent); From 0901fa70ae81d90ad0272a14a3846ff666357a70 Mon Sep 17 00:00:00 2001 From: tuandevccs Date: Wed, 4 Feb 2026 12:51:51 +0100 Subject: [PATCH 05/30] fix bottom missing height issue for ios --- crates/umide/src/panel/emulator_view.rs | 41 ++++++++----------------- 1 file changed, 13 insertions(+), 28 deletions(-) diff --git a/crates/umide/src/panel/emulator_view.rs b/crates/umide/src/panel/emulator_view.rs index 3863b3ec..228ed475 100644 --- a/crates/umide/src/panel/emulator_view.rs +++ b/crates/umide/src/panel/emulator_view.rs @@ -94,39 +94,24 @@ impl View for NativeEmulatorWidget { fn compute_layout(&mut self, _cx: &mut ComputeLayoutCx) -> Option { let is_visible = self.is_visible.get_untracked(); - // If not visible, don't create/update native view + // If not visible, cleanup and don't participate in layout if !is_visible { + if self.native_view.is_some() { + self.cleanup(); + } return None; } - // Get layout after it's been computed - if let Some(layout) = self.id.get_layout() { - let width = layout.size.width as u32; - let height = layout.size.height as u32; - - // Skip if size is zero - if width == 0 || height == 0 { - return None; - } - - // Check if current device matches what we have initialized - let current_device = self.running_device.get_untracked(); - - // If no device running but we have a view, cleanup - if current_device.is_none() && self.native_view.is_some() { - self.cleanup(); - return None; - } - - if let Some(_view) = &self.native_view { - // Resize/Move handled in paint() where we have absolute coordinates - } - // Note: Creation moved to paint() to ensure we have layout - - Some(Rect::new(0.0, 0.0, width as f64, height as f64)) - } else { - None + // Check if device is still running + let current_device = self.running_device.get_untracked(); + if current_device.is_none() && self.native_view.is_some() { + self.cleanup(); + return None; } + + // Return None to let flex layout determine our size + // The actual size will be read in paint() via get_layout() + None } fn paint(&mut self, _cx: &mut floem::context::PaintCx) { From f9c1413fbac66860da363df3a6056eb19b8e32ad Mon Sep 17 00:00:00 2001 From: tuandevccs Date: Mon, 9 Feb 2026 23:21:52 +0000 Subject: [PATCH 06/30] handle native android and ios integration --- crates/umide/src/panel/emulator_view.rs | 2 +- crates/umide_emulator/src/android.rs | 5 +- crates/umide_emulator/src/ios.rs | 17 +- .../cpp/src/macos/macos_emulator.mm | 338 ++++++++++++++---- 4 files changed, 291 insertions(+), 71 deletions(-) diff --git a/crates/umide/src/panel/emulator_view.rs b/crates/umide/src/panel/emulator_view.rs index 228ed475..c9ec366e 100644 --- a/crates/umide/src/panel/emulator_view.rs +++ b/crates/umide/src/panel/emulator_view.rs @@ -358,7 +358,7 @@ fn platform_panel( // Native Emulator View (shown when device running AND visible) Stack::new(( NativeEmulatorWidget::new(running_device, is_visible, current_device_id) - .style(|s| s.flex_grow(1.0).width_full()), + .style(|s| s.flex_grow(1.0).width_full().height_full()), // Control buttons overlay Stack::horizontal(( // Stop button - actually stops the emulator/simulator diff --git a/crates/umide_emulator/src/android.rs b/crates/umide_emulator/src/android.rs index 945f7ac5..4c387c1c 100644 --- a/crates/umide_emulator/src/android.rs +++ b/crates/umide_emulator/src/android.rs @@ -92,12 +92,15 @@ impl AndroidEmulator { } pub fn launch(avd_name: &str) -> Result<()> { + // Launch emulator in normal windowed mode so we can capture its display + // The window will appear briefly before we start capturing it Command::new("emulator") .arg("-avd") .arg(avd_name) - .arg("-no-window") // Headless mode - no external window .arg("-grpc") .arg("5556") + .arg("-gpu") + .arg("swiftshader_indirect") // Force software rendering to avoid Vulkan crashes on macOS .stdout(Stdio::null()) .stderr(Stdio::null()) .stdin(Stdio::null()) diff --git a/crates/umide_emulator/src/ios.rs b/crates/umide_emulator/src/ios.rs index 9d4aec35..0ab12ddf 100644 --- a/crates/umide_emulator/src/ios.rs +++ b/crates/umide_emulator/src/ios.rs @@ -100,16 +100,17 @@ impl IosSimulator { } pub fn launch(udid: &str) -> Result<()> { - // Boot the simulator (no external window) + // Boot the simulator Command::new("xcrun") - .arg("simctl") - .arg("boot") - .arg(udid) + .args(["simctl", "boot", udid]) .spawn()?; - - // Note: We don't open Simulator.app - we capture screenshots directly - // via simctl without needing the visible window - + + // Open Simulator.app so the window is visible for screen capture + // ScreenCaptureKit needs the window to be visible to capture it + Command::new("open") + .args(["-a", "Simulator"]) + .spawn()?; + Ok(()) } diff --git a/crates/umide_native/cpp/src/macos/macos_emulator.mm b/crates/umide_native/cpp/src/macos/macos_emulator.mm index f715e5cb..e9af4b11 100644 --- a/crates/umide_native/cpp/src/macos/macos_emulator.mm +++ b/crates/umide_native/cpp/src/macos/macos_emulator.mm @@ -1,30 +1,175 @@ #import #import #import +#import +#import +#import #include "src/emulator.h" #include +#include +#include +#include // Forward declaration of the C++ class to use in ObjC namespace umide { class MacOSEmulator; } -// define a custom NSView to handle rendering/input? -@interface UmideHostView : NSView +// Custom view that captures and displays an external window's content using ScreenCaptureKit +API_AVAILABLE(macos(12.3)) +@interface UmideEmulatorView : NSView { + SCStream* captureStream; + CGImageRef latestFrame; + BOOL isCapturing; + dispatch_queue_t captureQueue; +} +- (void)startCapturingWindowWithID:(CGWindowID)windowID; +- (void)stopCapturing; @end -@implementation UmideHostView +API_AVAILABLE(macos(12.3)) +@implementation UmideEmulatorView + +- (instancetype)initWithFrame:(NSRect)frameRect { + self = [super initWithFrame:frameRect]; + if (self) { + captureStream = nil; + latestFrame = NULL; + isCapturing = NO; + captureQueue = dispatch_queue_create("com.umide.screencapture", DISPATCH_QUEUE_SERIAL); + [self setWantsLayer:YES]; + self.layer.backgroundColor = [[NSColor blackColor] CGColor]; + } + return self; +} + +- (void)startCapturingWindowWithID:(CGWindowID)windowID { + if (isCapturing) return; + + // Find the SCWindow matching our windowID + [SCShareableContent getShareableContentWithCompletionHandler:^(SCShareableContent * _Nullable content, NSError * _Nullable error) { + if (error) { + NSLog(@"UmideEmulatorView: Failed to get shareable content: %@", error); + return; + } + + // Find the window with matching ID + SCWindow* targetWindow = nil; + for (SCWindow* window in content.windows) { + if (window.windowID == windowID) { + targetWindow = window; + break; + } + } + + if (!targetWindow) { + NSLog(@"UmideEmulatorView: Could not find window with ID %u", windowID); + return; + } + + NSLog(@"UmideEmulatorView: Found window '%@' for capture", targetWindow.title); + + // Configure stream for window capture + SCContentFilter* filter = [[SCContentFilter alloc] initWithDesktopIndependentWindow:targetWindow]; + + SCStreamConfiguration* config = [[SCStreamConfiguration alloc] init]; + config.width = (size_t)targetWindow.frame.size.width; + config.height = (size_t)targetWindow.frame.size.height; + config.minimumFrameInterval = CMTimeMake(1, 60); // 60 FPS + config.pixelFormat = kCVPixelFormatType_32BGRA; + config.showsCursor = NO; + config.capturesAudio = NO; + + self->captureStream = [[SCStream alloc] initWithFilter:filter configuration:config delegate:self]; + + NSError* addOutputError; + BOOL added = [self->captureStream addStreamOutput:self type:SCStreamOutputTypeScreen sampleHandlerQueue:self->captureQueue error:&addOutputError]; + if (!added) { + NSLog(@"UmideEmulatorView: Failed to add stream output: %@", addOutputError); + return; + } + + [self->captureStream startCaptureWithCompletionHandler:^(NSError * _Nullable startError) { + if (startError) { + NSLog(@"UmideEmulatorView: Failed to start capture: %@", startError); + } else { + self->isCapturing = YES; + NSLog(@"UmideEmulatorView: Started capturing window"); + } + }]; + }]; +} + +- (void)stopCapturing { + if (!isCapturing || !captureStream) return; + + isCapturing = NO; + [captureStream stopCaptureWithCompletionHandler:^(NSError * _Nullable error) { + if (error) { + NSLog(@"UmideEmulatorView: Error stopping capture: %@", error); + } + }]; + captureStream = nil; + + if (latestFrame) { + CGImageRelease(latestFrame); + latestFrame = NULL; + } +} + +// SCStreamOutput delegate method - called for each frame +- (void)stream:(SCStream *)stream didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer ofType:(SCStreamOutputType)type { + if (type != SCStreamOutputTypeScreen) return; + + CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); + if (!imageBuffer) return; + + // Create CGImage from pixel buffer + CIImage* ciImage = [CIImage imageWithCVPixelBuffer:imageBuffer]; + CIContext* context = [CIContext context]; + CGImageRef newFrame = [context createCGImage:ciImage fromRect:ciImage.extent]; + + if (newFrame) { + dispatch_async(dispatch_get_main_queue(), ^{ + if (self->latestFrame) { + CGImageRelease(self->latestFrame); + } + self->latestFrame = newFrame; + [self setNeedsDisplay:YES]; + }); + } +} + +// SCStreamDelegate method - called on stream errors +- (void)stream:(SCStream *)stream didStopWithError:(NSError *)error { + NSLog(@"UmideEmulatorView: Stream stopped with error: %@", error); + isCapturing = NO; +} + - (void)drawRect:(NSRect)dirtyRect { - [[NSColor blackColor] setFill]; - NSRectFill(dirtyRect); - - // Draw a placeholder text - NSString* text = @"Native Emulator Host"; - NSDictionary* attrs = @{ - NSForegroundColorAttributeName: [NSColor whiteColor], - NSFontAttributeName: [NSFont systemFontOfSize:24] - }; - [text drawAtPoint:NSMakePoint(dirtyRect.size.width/2 - 100, dirtyRect.size.height/2) withAttributes:attrs]; + if (latestFrame) { + // Draw the captured frame scaled to fit + CGContextRef ctx = [[NSGraphicsContext currentContext] CGContext]; + CGContextDrawImage(ctx, self.bounds, latestFrame); + } else { + // Draw placeholder + [[NSColor blackColor] setFill]; + NSRectFill(dirtyRect); + + NSString* text = @"Waiting for emulator..."; + NSDictionary* attrs = @{ + NSForegroundColorAttributeName: [NSColor grayColor], + NSFontAttributeName: [NSFont systemFontOfSize:14] + }; + NSSize textSize = [text sizeWithAttributes:attrs]; + [text drawAtPoint:NSMakePoint(dirtyRect.size.width/2 - textSize.width/2, + dirtyRect.size.height/2) withAttributes:attrs]; + } +} + +- (void)dealloc { + [self stopCapturing]; } + @end // Helper for safe main thread execution @@ -36,27 +181,88 @@ static void runOnMainThread(void (^block)(void)) { } } +// Find window ID by process name and optional window title +static CGWindowID findWindowByProcessName(const std::string& processName, const std::string& titleContains = "") { + CFArrayRef windowList = CGWindowListCopyWindowInfo( + kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements, + kCGNullWindowID + ); + + if (!windowList) return 0; + + CGWindowID foundWindowID = 0; + CFIndex count = CFArrayGetCount(windowList); + + for (CFIndex i = 0; i < count; i++) { + CFDictionaryRef windowInfo = (CFDictionaryRef)CFArrayGetValueAtIndex(windowList, i); + + // Get owner name (process name) + CFStringRef ownerName = (CFStringRef)CFDictionaryGetValue(windowInfo, kCGWindowOwnerName); + if (!ownerName) continue; + + char ownerBuffer[256]; + if (!CFStringGetCString(ownerName, ownerBuffer, sizeof(ownerBuffer), kCFStringEncodingUTF8)) { + continue; + } + + // Check if process name matches + if (std::string(ownerBuffer).find(processName) == std::string::npos) { + continue; + } + + // Get window title if we need to filter by it + if (!titleContains.empty()) { + CFStringRef windowName = (CFStringRef)CFDictionaryGetValue(windowInfo, kCGWindowName); + if (windowName) { + char titleBuffer[512]; + if (CFStringGetCString(windowName, titleBuffer, sizeof(titleBuffer), kCFStringEncodingUTF8)) { + if (std::string(titleBuffer).find(titleContains) == std::string::npos) { + continue; + } + } + } + } + + // Get window ID + CFNumberRef windowIDRef = (CFNumberRef)CFDictionaryGetValue(windowInfo, kCGWindowNumber); + if (windowIDRef) { + CFNumberGetValue(windowIDRef, kCGWindowIDCFNumberType, &foundWindowID); + NSLog(@"Found window: process='%s' windowID=%u", ownerBuffer, foundWindowID); + break; + } + } + + CFRelease(windowList); + return foundWindowID; +} + namespace umide { class MacOSEmulator : public Emulator { private: - NSWindow* childWindow = nil; // The child window hosting the emulator - UmideHostView* hostView = nil; - NSView* parentView = nil; // Weak ref + NSWindow* childWindow = nil; + UmideEmulatorView* emulatorView = nil; + NSView* parentView = nil; + CGWindowID embeddedWindowID = 0; + std::string currentDeviceId; + EmulatorPlatform platform; public: - MacOSEmulator() {} + MacOSEmulator(EmulatorPlatform p) : platform(p) {} ~MacOSEmulator() override { if (childWindow) { runOnMainThread(^{ + if (emulatorView) { + [emulatorView stopCapturing]; + } NSWindow* parent = [childWindow parentWindow]; if (parent) { [parent removeChildWindow:childWindow]; } [childWindow close]; childWindow = nil; - hostView = nil; + emulatorView = nil; }); } } @@ -73,8 +279,7 @@ bool initialize(void* parent_window, int32_t x, int32_t y, uint32_t width, uint3 return; } - // Create a borderless child window (NSPanel for floating behavior) - // Initial frame will be set in resize(), creating 0-size for now + // Create a borderless child window childWindow = [[NSPanel alloc] initWithContentRect:NSZeroRect styleMask:NSWindowStyleMaskBorderless backing:NSBackingStoreBuffered @@ -84,13 +289,8 @@ bool initialize(void* parent_window, int32_t x, int32_t y, uint32_t width, uint3 [childWindow setHidesOnDeactivate:NO]; [childWindow setCanHide:NO]; - hostView = [[UmideHostView alloc] initWithFrame:NSMakeRect(0, 0, width, height)]; - [hostView setWantsLayer:YES]; - if (hostView.layer) { - hostView.layer.backgroundColor = [[NSColor blackColor] CGColor]; - } - - [childWindow setContentView:hostView]; + emulatorView = [[UmideEmulatorView alloc] initWithFrame:NSMakeRect(0, 0, width, height)]; + [childWindow setContentView:emulatorView]; // Attach to parent window [parentWin addChildWindow:childWindow ordered:NSWindowAbove]; @@ -110,59 +310,75 @@ void resize(int32_t x, int32_t y, uint32_t width, uint32_t height) override { NSWindow* parentWin = [parentView window]; if (!parentWin) return; - // Get the parent window's frame on screen NSRect windowFrame = [parentWin frame]; NSRect contentRect = [parentWin contentLayoutRect]; - // Floem coordinates: (x, y) is top-left of widget in window content coordinates - // macOS screen coordinates: origin is bottom-left of screen, Y goes up - - // Convert: Floem's (x, y from top-left) to screen coords - // The widget's TOP should be at: windowFrame.origin.y + windowFrame.size.height - contentRect.origin.y - y - // The widget's BOTTOM should be at: top - height - CGFloat screenX = windowFrame.origin.x + x; CGFloat screenTop = windowFrame.origin.y + windowFrame.size.height - contentRect.origin.y - y; - CGFloat screenY = screenTop - height; // screenY is BOTTOM of the rect in screen coords + CGFloat screenY = screenTop - height; NSRect rectInScreen = NSMakeRect(screenX, screenY, width, height); - - NSLog(@"MacOSEmulator resize: input=(%d,%d,%u,%u) winFrame=(%.0f,%.0f,%.0f,%.0f) content=(%.0f,%.0f) screen=(%.0f,%.0f,%.0f,%.0f)", - x, y, width, height, - windowFrame.origin.x, windowFrame.origin.y, windowFrame.size.width, windowFrame.size.height, - contentRect.origin.x, contentRect.origin.y, - rectInScreen.origin.x, rectInScreen.origin.y, rectInScreen.size.width, rectInScreen.size.height); - [childWindow setFrame:rectInScreen display:YES]; } }); } void attach_device(const std::string& device_id) override { - std::cout << "MacOSEmulator: Attaching device " << device_id << std::endl; - //TODO: Implement Simctl/Metal surface attachment here + currentDeviceId = device_id; + NSLog(@"MacOSEmulator: Attaching device '%s' (platform=%s)", + device_id.c_str(), + platform == EMULATOR_PLATFORM_ANDROID ? "Android" : "iOS"); + + // Find the emulator/simulator window + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + CGWindowID windowID = 0; + + // Poll for the window to appear (max 10 seconds) + for (int attempt = 0; attempt < 100 && windowID == 0; attempt++) { + if (platform == EMULATOR_PLATFORM_ANDROID) { + // Android Emulator process name - try different variants + windowID = findWindowByProcessName("qemu-system", ""); + if (windowID == 0) { + windowID = findWindowByProcessName("emulator64", ""); + } + if (windowID == 0) { + windowID = findWindowByProcessName("emulator", ""); + } + } else { + // iOS Simulator - window title doesn't contain UDID, just look for "Simulator" + windowID = findWindowByProcessName("Simulator", ""); + } + + if (windowID == 0) { + if (attempt % 20 == 0) { + NSLog(@"MacOSEmulator: Waiting for window (attempt %d/100)...", attempt); + } + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + } + + if (windowID != 0) { + embeddedWindowID = windowID; + NSLog(@"MacOSEmulator: Found window ID %u for device '%s'", windowID, device_id.c_str()); + + dispatch_async(dispatch_get_main_queue(), ^{ + if (emulatorView) { + [emulatorView startCapturingWindowWithID:windowID]; + } + }); + } else { + NSLog(@"MacOSEmulator: ERROR - Could not find window for device '%s' after 10 seconds", device_id.c_str()); + } + }); } void send_input(const EmulatorInputEvent& /*_event*/) override { - // Forward input to backend + // TODO: Forward input to emulator/simulator } }; -// Android implementation (stub for now, can share NSView logic on MacOS if we use same hosting strategy) -class AndroidEmulator : public Emulator { - // Android on macOS also ends up being a window we might need to embed via NSView (child window) - // or just a surface. For now, let's reuse MacOSEmulator-like logic or simpler stub. - // Actually, on macOS, Android Emulator runs as a separate process (qemu). - // Embedding it requires ` -qt-hide-window-decorations` and re-parenting the NSWindow using private APIs or - // simply making the emulator render to a shared texture that we draw in our view. - // The "Right" way per roadmap is "Native Surface Handle" -> passed to emulator. - // For now, I'll return a MacOSEmulator for both since we just want to prove embedding. -}; - -Emulator* Emulator::create(EmulatorPlatform /*_platform*/) { - // For now, return MacOS implementation for both as a test harness - // Real implementation would diverge based on backing (Metal vs Vulkan/GFXStream) - return new MacOSEmulator(); +Emulator* Emulator::create(EmulatorPlatform platform) { + return new MacOSEmulator(platform); } } // namespace umide From a86c5ca65091c531cfb20ddd8db083b648b0b85b Mon Sep 17 00:00:00 2001 From: tuandevccs Date: Thu, 19 Feb 2026 14:37:04 +0000 Subject: [PATCH 07/30] emulator display works correctly --- crates/umide_emulator/src/android.rs | 61 ++++- crates/umide_emulator/src/ios.rs | 66 ++++- .../cpp/src/macos/macos_emulator.mm | 244 ++++++++++++++---- 3 files changed, 311 insertions(+), 60 deletions(-) diff --git a/crates/umide_emulator/src/android.rs b/crates/umide_emulator/src/android.rs index 4c387c1c..7629ecb6 100644 --- a/crates/umide_emulator/src/android.rs +++ b/crates/umide_emulator/src/android.rs @@ -92,20 +92,67 @@ impl AndroidEmulator { } pub fn launch(avd_name: &str) -> Result<()> { - // Launch emulator in normal windowed mode so we can capture its display - // The window will appear briefly before we start capturing it - Command::new("emulator") + tracing::info!("Launching Android emulator for AVD: {}", avd_name); + + // Check if already running + if Self::is_running(avd_name) { + tracing::info!("AVD {} is already running", avd_name); + return Ok(()); + } + + // Launch emulator headless — we capture the display via ScreenCaptureKit + // GPU mode "auto" picks the best available backend (Metal on macOS) + // without the Vulkan/SwiftShader crashes from "swiftshader_indirect" + let child = Command::new("emulator") .arg("-avd") .arg(avd_name) .arg("-grpc") .arg("5556") .arg("-gpu") - .arg("swiftshader_indirect") // Force software rendering to avoid Vulkan crashes on macOS + .arg("auto") + .arg("-no-boot-anim") .stdout(Stdio::null()) - .stderr(Stdio::null()) + .stderr(Stdio::piped()) .stdin(Stdio::null()) - .spawn()?; - Ok(()) + .spawn(); + + match child { + Ok(_child) => { + tracing::info!("Emulator process spawned for AVD: {}", avd_name); + + // Wait for the emulator to become reachable via ADB + // Poll up to 30 seconds for the emulator to appear in adb devices + let mut ready = false; + for attempt in 0..60 { + std::thread::sleep(std::time::Duration::from_millis(500)); + let serials = Self::get_running_serials(); + if !serials.is_empty() { + // Verify this AVD is the one that booted + if Self::is_running(avd_name) { + tracing::info!( + "AVD {} is now running (detected after {}ms)", + avd_name, (attempt + 1) * 500 + ); + ready = true; + break; + } + } + if attempt % 10 == 0 && attempt > 0 { + tracing::debug!("Still waiting for AVD {} to boot... ({}s)", avd_name, (attempt + 1) / 2); + } + } + + if !ready { + tracing::warn!("AVD {} may not be fully booted yet after 30s, proceeding anyway", avd_name); + } + + Ok(()) + } + Err(e) => { + tracing::error!("Failed to spawn emulator for AVD {}: {}", avd_name, e); + Err(anyhow!("Failed to launch emulator: {}", e)) + } + } } pub fn stop(avd_name: &str) -> Result<()> { diff --git a/crates/umide_emulator/src/ios.rs b/crates/umide_emulator/src/ios.rs index 0ab12ddf..f8dcc938 100644 --- a/crates/umide_emulator/src/ios.rs +++ b/crates/umide_emulator/src/ios.rs @@ -100,17 +100,67 @@ impl IosSimulator { } pub fn launch(udid: &str) -> Result<()> { - // Boot the simulator - Command::new("xcrun") + tracing::info!("Launching iOS Simulator for UDID: {}", udid); + + // Check if already booted + if Self::is_running(udid) { + tracing::info!("Simulator {} is already booted", udid); + // Still open Simulator.app to ensure window is visible + let _ = Command::new("open") + .args(["-a", "Simulator"]) + .output(); + return Ok(()); + } + + // Boot the simulator synchronously — wait for it to complete + let output = Command::new("xcrun") .args(["simctl", "boot", udid]) - .spawn()?; + .output()?; - // Open Simulator.app so the window is visible for screen capture - // ScreenCaptureKit needs the window to be visible to capture it - Command::new("open") - .args(["-a", "Simulator"]) - .spawn()?; + if !output.status.success() { + let stderr = String::from_utf8_lossy(&output.stderr); + // Ignore "already booted" errors + if !stderr.contains("current state: Booted") { + tracing::error!("Failed to boot simulator {}: {}", udid, stderr); + return Err(anyhow!("Failed to boot simulator: {}", stderr)); + } + tracing::info!("Simulator {} was already booted", udid); + } else { + tracing::info!("Simulator {} booted successfully", udid); + } + // Open Simulator.app so the window is visible for ScreenCaptureKit capture + let _ = Command::new("open") + .args(["-a", "Simulator"]) + .output()?; + + // Wait for the Simulator.app window to appear + // ScreenCaptureKit needs the window to be on-screen + tracing::info!("Waiting for Simulator.app window to appear..."); + for attempt in 0..20 { + std::thread::sleep(std::time::Duration::from_millis(500)); + // Check if any simulator window exists + let check = Command::new("osascript") + .args([ + "-e", + r#"tell application "System Events" to count windows of application process "Simulator""#, + ]) + .output(); + + if let Ok(out) = check { + let count_str = String::from_utf8_lossy(&out.stdout).trim().to_string(); + if let Ok(count) = count_str.parse::() { + if count > 0 { + tracing::info!("Simulator window appeared after {}ms", (attempt + 1) * 500); + // Give the window a moment to fully render + std::thread::sleep(std::time::Duration::from_millis(500)); + return Ok(()); + } + } + } + } + + tracing::warn!("Simulator window may not have appeared after 10s, proceeding anyway"); Ok(()) } diff --git a/crates/umide_native/cpp/src/macos/macos_emulator.mm b/crates/umide_native/cpp/src/macos/macos_emulator.mm index e9af4b11..03ec52b7 100644 --- a/crates/umide_native/cpp/src/macos/macos_emulator.mm +++ b/crates/umide_native/cpp/src/macos/macos_emulator.mm @@ -11,6 +11,7 @@ #include #include + // Forward declaration of the C++ class to use in ObjC namespace umide { class MacOSEmulator; } @@ -21,9 +22,12 @@ @interface UmideEmulatorView : NSView { CGImageRef latestFrame; BOOL isCapturing; dispatch_queue_t captureQueue; + CIContext* ciContext; // Cached — creating per-frame leaks memory at 60fps + volatile BOOL isBeingDestroyed; } - (void)startCapturingWindowWithID:(CGWindowID)windowID; - (void)stopCapturing; +- (void)showStatus:(NSString*)status; @end API_AVAILABLE(macos(12.3)) @@ -35,9 +39,12 @@ - (instancetype)initWithFrame:(NSRect)frameRect { captureStream = nil; latestFrame = NULL; isCapturing = NO; + isBeingDestroyed = NO; captureQueue = dispatch_queue_create("com.umide.screencapture", DISPATCH_QUEUE_SERIAL); + ciContext = [CIContext context]; // Reused for all frame conversions [self setWantsLayer:YES]; self.layer.backgroundColor = [[NSColor blackColor] CGColor]; + self.layer.contentsGravity = kCAGravityResizeAspect; } return self; } @@ -45,10 +52,13 @@ - (instancetype)initWithFrame:(NSRect)frameRect { - (void)startCapturingWindowWithID:(CGWindowID)windowID { if (isCapturing) return; + NSLog(@"UmideEmulatorView: Requesting capture for window ID %u", windowID); + // Find the SCWindow matching our windowID [SCShareableContent getShareableContentWithCompletionHandler:^(SCShareableContent * _Nullable content, NSError * _Nullable error) { if (error) { NSLog(@"UmideEmulatorView: Failed to get shareable content: %@", error); + NSLog(@"UmideEmulatorView: Make sure Screen Recording permission is granted in System Settings > Privacy & Security"); return; } @@ -62,18 +72,25 @@ - (void)startCapturingWindowWithID:(CGWindowID)windowID { } if (!targetWindow) { - NSLog(@"UmideEmulatorView: Could not find window with ID %u", windowID); + NSLog(@"UmideEmulatorView: Could not find window with ID %u among %lu windows", + windowID, (unsigned long)content.windows.count); + // Log available windows for debugging + for (SCWindow* window in content.windows) { + NSLog(@" Available window: ID=%u app='%@' title='%@'", + window.windowID, window.owningApplication.applicationName, window.title); + } return; } - NSLog(@"UmideEmulatorView: Found window '%@' for capture", targetWindow.title); + NSLog(@"UmideEmulatorView: Found window '%@' (app: '%@') for capture", + targetWindow.title, targetWindow.owningApplication.applicationName); // Configure stream for window capture SCContentFilter* filter = [[SCContentFilter alloc] initWithDesktopIndependentWindow:targetWindow]; SCStreamConfiguration* config = [[SCStreamConfiguration alloc] init]; - config.width = (size_t)targetWindow.frame.size.width; - config.height = (size_t)targetWindow.frame.size.height; + config.width = (size_t)MAX(targetWindow.frame.size.width, 1); + config.height = (size_t)MAX(targetWindow.frame.size.height, 1); config.minimumFrameInterval = CMTimeMake(1, 60); // 60 FPS config.pixelFormat = kCVPixelFormatType_32BGRA; config.showsCursor = NO; @@ -90,10 +107,12 @@ - (void)startCapturingWindowWithID:(CGWindowID)windowID { [self->captureStream startCaptureWithCompletionHandler:^(NSError * _Nullable startError) { if (startError) { - NSLog(@"UmideEmulatorView: Failed to start capture: %@", startError); + NSLog(@"UmideEmulatorView: Failed to start capture: %@ (code: %ld)", + startError.localizedDescription, (long)startError.code); } else { self->isCapturing = YES; - NSLog(@"UmideEmulatorView: Started capturing window"); + NSLog(@"UmideEmulatorView: Started capturing window at %zux%zu @ 60fps", + config.width, config.height); } }]; }]; @@ -103,12 +122,16 @@ - (void)stopCapturing { if (!isCapturing || !captureStream) return; isCapturing = NO; - [captureStream stopCaptureWithCompletionHandler:^(NSError * _Nullable error) { + SCStream* streamToStop = captureStream; + captureStream = nil; + + [streamToStop stopCaptureWithCompletionHandler:^(NSError * _Nullable error) { if (error) { NSLog(@"UmideEmulatorView: Error stopping capture: %@", error); + } else { + NSLog(@"UmideEmulatorView: Capture stopped cleanly"); } }]; - captureStream = nil; if (latestFrame) { CGImageRelease(latestFrame); @@ -116,41 +139,57 @@ - (void)stopCapturing { } } +- (void)showStatus:(NSString*)status { + // Update layer with status text — for headless mode + NSLog(@"UmideEmulatorView: Status: %@", status); + [self setNeedsDisplay:YES]; +} + // SCStreamOutput delegate method - called for each frame - (void)stream:(SCStream *)stream didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer ofType:(SCStreamOutputType)type { if (type != SCStreamOutputTypeScreen) return; + if (isBeingDestroyed) return; CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); if (!imageBuffer) return; - // Create CGImage from pixel buffer + // Use cached CIContext to avoid per-frame allocation CIImage* ciImage = [CIImage imageWithCVPixelBuffer:imageBuffer]; - CIContext* context = [CIContext context]; - CGImageRef newFrame = [context createCGImage:ciImage fromRect:ciImage.extent]; + CGImageRef newFrame = [ciContext createCGImage:ciImage fromRect:ciImage.extent]; if (newFrame) { dispatch_async(dispatch_get_main_queue(), ^{ + if (self->isBeingDestroyed) { + CGImageRelease(newFrame); + return; + } if (self->latestFrame) { CGImageRelease(self->latestFrame); } self->latestFrame = newFrame; - [self setNeedsDisplay:YES]; + + // Use CALayer.contents for hardware-accelerated compositing + // instead of drawRect: which uses CPU rendering + self.layer.contents = (__bridge id)newFrame; }); } } // SCStreamDelegate method - called on stream errors - (void)stream:(SCStream *)stream didStopWithError:(NSError *)error { - NSLog(@"UmideEmulatorView: Stream stopped with error: %@", error); + NSLog(@"UmideEmulatorView: Stream stopped with error: %@ (code: %ld)", + error.localizedDescription, (long)error.code); isCapturing = NO; + + // Attempt to restart capture after a brief delay (resilience) + if (!isBeingDestroyed) { + NSLog(@"UmideEmulatorView: Will not auto-restart — device may have been stopped"); + } } - (void)drawRect:(NSRect)dirtyRect { - if (latestFrame) { - // Draw the captured frame scaled to fit - CGContextRef ctx = [[NSGraphicsContext currentContext] CGContext]; - CGContextDrawImage(ctx, self.bounds, latestFrame); - } else { + // Only used as fallback when layer.contents is not set + if (!latestFrame) { // Draw placeholder [[NSColor blackColor] setFill]; NSRectFill(dirtyRect); @@ -164,9 +203,11 @@ - (void)drawRect:(NSRect)dirtyRect { [text drawAtPoint:NSMakePoint(dirtyRect.size.width/2 - textSize.width/2, dirtyRect.size.height/2) withAttributes:attrs]; } + // If latestFrame is set, layer.contents handles rendering via GPU compositing } - (void)dealloc { + isBeingDestroyed = YES; [self stopCapturing]; } @@ -191,8 +232,12 @@ static CGWindowID findWindowByProcessName(const std::string& processName, const if (!windowList) return 0; CGWindowID foundWindowID = 0; + CGWindowID bestMatch = 0; CFIndex count = CFArrayGetCount(windowList); + NSLog(@"findWindowByProcessName: Looking for process='%s' title='%s' among %ld windows", + processName.c_str(), titleContains.c_str(), (long)count); + for (CFIndex i = 0; i < count; i++) { CFDictionaryRef windowInfo = (CFDictionaryRef)CFArrayGetValueAtIndex(windowList, i); @@ -206,33 +251,63 @@ static CGWindowID findWindowByProcessName(const std::string& processName, const } // Check if process name matches - if (std::string(ownerBuffer).find(processName) == std::string::npos) { + std::string owner(ownerBuffer); + if (owner.find(processName) == std::string::npos) { continue; } - // Get window title if we need to filter by it - if (!titleContains.empty()) { - CFStringRef windowName = (CFStringRef)CFDictionaryGetValue(windowInfo, kCGWindowName); - if (windowName) { - char titleBuffer[512]; - if (CFStringGetCString(windowName, titleBuffer, sizeof(titleBuffer), kCFStringEncodingUTF8)) { - if (std::string(titleBuffer).find(titleContains) == std::string::npos) { - continue; - } - } - } + // Get window layer — skip menu bar items and status items (layer != 0) + CFNumberRef layerRef = (CFNumberRef)CFDictionaryGetValue(windowInfo, kCGWindowLayer); + int32_t layer = 0; + if (layerRef) { + CFNumberGetValue(layerRef, kCFNumberSInt32Type, &layer); } + if (layer != 0) continue; // Only normal windows (layer 0) // Get window ID CFNumberRef windowIDRef = (CFNumberRef)CFDictionaryGetValue(windowInfo, kCGWindowNumber); + CGWindowID windowID = 0; if (windowIDRef) { - CFNumberGetValue(windowIDRef, kCGWindowIDCFNumberType, &foundWindowID); - NSLog(@"Found window: process='%s' windowID=%u", ownerBuffer, foundWindowID); + CFNumberGetValue(windowIDRef, kCGWindowIDCFNumberType, &windowID); + } + if (windowID == 0) continue; + + // Get window title + CFStringRef windowName = (CFStringRef)CFDictionaryGetValue(windowInfo, kCGWindowName); + char titleBuffer[512] = ""; + if (windowName) { + CFStringGetCString(windowName, titleBuffer, sizeof(titleBuffer), kCFStringEncodingUTF8); + } + + NSLog(@" Candidate: process='%s' title='%s' windowID=%u layer=%d", + ownerBuffer, titleBuffer, windowID, layer); + + // If title filter specified, prefer windows matching it + if (!titleContains.empty()) { + if (strlen(titleBuffer) > 0 && std::string(titleBuffer).find(titleContains) != std::string::npos) { + NSLog(@" -> Title match! Using window %u", windowID); + foundWindowID = windowID; + break; + } + // Save as fallback in case no title match + if (bestMatch == 0) { + bestMatch = windowID; + } + } else { + // No title filter, take the first match + foundWindowID = windowID; break; } } CFRelease(windowList); + + // Use best match if no exact title match was found + if (foundWindowID == 0 && bestMatch != 0) { + NSLog(@"findWindowByProcessName: No title match, using fallback window %u", bestMatch); + foundWindowID = bestMatch; + } + return foundWindowID; } @@ -246,11 +321,13 @@ static CGWindowID findWindowByProcessName(const std::string& processName, const CGWindowID embeddedWindowID = 0; std::string currentDeviceId; EmulatorPlatform platform; + volatile bool destroyed = false; public: MacOSEmulator(EmulatorPlatform p) : platform(p) {} ~MacOSEmulator() override { + destroyed = true; if (childWindow) { runOnMainThread(^{ if (emulatorView) { @@ -260,6 +337,7 @@ static CGWindowID findWindowByProcessName(const std::string& processName, const if (parent) { [parent removeChildWindow:childWindow]; } + [childWindow orderOut:nil]; [childWindow close]; childWindow = nil; emulatorView = nil; @@ -288,6 +366,8 @@ bool initialize(void* parent_window, int32_t x, int32_t y, uint32_t width, uint3 [childWindow setReleasedWhenClosed:NO]; [childWindow setHidesOnDeactivate:NO]; [childWindow setCanHide:NO]; + [childWindow setOpaque:YES]; + [childWindow setBackgroundColor:[NSColor blackColor]]; emulatorView = [[UmideEmulatorView alloc] initWithFrame:NSMakeRect(0, 0, width, height)]; [childWindow setContentView:emulatorView]; @@ -298,6 +378,9 @@ bool initialize(void* parent_window, int32_t x, int32_t y, uint32_t width, uint3 // Initial positioning this->resize(x, y, width, height); + NSLog(@"MacOSEmulator: Initialized child window for %s platform", + platform == EMULATOR_PLATFORM_ANDROID ? "Android" : "iOS"); + success = true; }); @@ -305,7 +388,11 @@ bool initialize(void* parent_window, int32_t x, int32_t y, uint32_t width, uint3 } void resize(int32_t x, int32_t y, uint32_t width, uint32_t height) override { - dispatch_async(dispatch_get_main_queue(), ^{ + if (destroyed) return; + + // Use runOnMainThread (dispatch_sync) for consistent timing + // dispatch_async here was causing races with initialize/cleanup + runOnMainThread(^{ if (parentView && childWindow) { NSWindow* parentWin = [parentView window]; if (!parentWin) return; @@ -331,49 +418,116 @@ void attach_device(const std::string& device_id) override { // Find the emulator/simulator window dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + if (destroyed) return; + CGWindowID windowID = 0; - // Poll for the window to appear (max 10 seconds) - for (int attempt = 0; attempt < 100 && windowID == 0; attempt++) { + // Poll for the window to appear (max 30 seconds, 300 attempts * 100ms) + int maxAttempts = 300; + for (int attempt = 0; attempt < maxAttempts && windowID == 0; attempt++) { + if (destroyed) return; + if (platform == EMULATOR_PLATFORM_ANDROID) { - // Android Emulator process name - try different variants + // Android Emulator — try multiple process name variants + // The emulator uses different process names depending on version/config windowID = findWindowByProcessName("qemu-system", ""); if (windowID == 0) { windowID = findWindowByProcessName("emulator64", ""); } if (windowID == 0) { - windowID = findWindowByProcessName("emulator", ""); + windowID = findWindowByProcessName("emulator", "Android"); } } else { - // iOS Simulator - window title doesn't contain UDID, just look for "Simulator" - windowID = findWindowByProcessName("Simulator", ""); + // iOS Simulator — match by device name in window title + // Simulator.app window titles contain the device name, e.g. "iPhone 15 Pro" + windowID = findWindowByProcessName("Simulator", device_id); } if (windowID == 0) { - if (attempt % 20 == 0) { - NSLog(@"MacOSEmulator: Waiting for window (attempt %d/100)...", attempt); + if (attempt % 50 == 0) { + NSLog(@"MacOSEmulator: Waiting for window (attempt %d/%d)...", attempt, maxAttempts); } std::this_thread::sleep_for(std::chrono::milliseconds(100)); } } + if (destroyed) return; + if (windowID != 0) { embeddedWindowID = windowID; NSLog(@"MacOSEmulator: Found window ID %u for device '%s'", windowID, device_id.c_str()); dispatch_async(dispatch_get_main_queue(), ^{ - if (emulatorView) { + if (!destroyed && emulatorView) { [emulatorView startCapturingWindowWithID:windowID]; } }); } else { - NSLog(@"MacOSEmulator: ERROR - Could not find window for device '%s' after 10 seconds", device_id.c_str()); + NSLog(@"MacOSEmulator: ERROR - Could not find window for device '%s' after %d seconds", + device_id.c_str(), maxAttempts / 10); + + // Show error status in the view + dispatch_async(dispatch_get_main_queue(), ^{ + if (!destroyed && emulatorView) { + [emulatorView showStatus:@"Could not find emulator window.\nCheck Screen Recording permission."]; + } + }); } }); } - void send_input(const EmulatorInputEvent& /*_event*/) override { - // TODO: Forward input to emulator/simulator + void send_input(const EmulatorInputEvent& event) override { + if (destroyed) return; + + if (platform == EMULATOR_PLATFORM_ANDROID) { + // Forward touch events via ADB + if (event.type == EMULATOR_INPUT_TOUCH_DOWN || event.type == EMULATOR_INPUT_TOUCH_UP) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + std::string cmd = std::string("adb shell input tap ") + + std::to_string(event.x) + " " + std::to_string(event.y); + int result = system(cmd.c_str()); + if (result != 0) { + NSLog(@"MacOSEmulator: ADB input command failed with code %d", result); + } + }); + } else if (event.type == EMULATOR_INPUT_KEY_DOWN) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + std::string cmd = std::string("adb shell input keyevent ") + + std::to_string(event.key_code); + system(cmd.c_str()); + }); + } + } else { + // Forward touch events to iOS Simulator + // Post CGEvents to the simulator window + if (embeddedWindowID != 0) { + if (event.type == EMULATOR_INPUT_TOUCH_DOWN) { + CGPoint point = CGPointMake(event.x, event.y); + CGEventRef mouseDown = CGEventCreateMouseEvent( + NULL, kCGEventLeftMouseDown, point, kCGMouseButtonLeft); + if (mouseDown) { + CGEventPost(kCGHIDEventTap, mouseDown); + CFRelease(mouseDown); + } + } else if (event.type == EMULATOR_INPUT_TOUCH_UP) { + CGPoint point = CGPointMake(event.x, event.y); + CGEventRef mouseUp = CGEventCreateMouseEvent( + NULL, kCGEventLeftMouseUp, point, kCGMouseButtonLeft); + if (mouseUp) { + CGEventPost(kCGHIDEventTap, mouseUp); + CFRelease(mouseUp); + } + } else if (event.type == EMULATOR_INPUT_TOUCH_MOVE) { + CGPoint point = CGPointMake(event.x, event.y); + CGEventRef mouseDrag = CGEventCreateMouseEvent( + NULL, kCGEventLeftMouseDragged, point, kCGMouseButtonLeft); + if (mouseDrag) { + CGEventPost(kCGHIDEventTap, mouseDrag); + CFRelease(mouseDrag); + } + } + } + } } }; From cbcd89b1db71daea6d72f8ce4d53b694c6bf8d6f Mon Sep 17 00:00:00 2001 From: tuandevccs Date: Fri, 20 Feb 2026 16:23:56 +0000 Subject: [PATCH 08/30] android works --- crates/umide/src/panel/emulator_view.rs | 39 +- .../proto/emulator_controller.proto | 120 +++--- crates/umide_emulator/src/android.rs | 11 +- crates/umide_emulator/src/grpc_client.rs | 102 ++++- crates/umide_emulator/src/native_view.rs | 137 ++++++- .../cpp/include/umide_native_api.h | 5 + crates/umide_native/cpp/src/emulator.h | 3 + crates/umide_native/cpp/src/emulator_api.cpp | 6 + .../cpp/src/macos/macos_emulator.mm | 354 ++++++++++++++++-- crates/umide_native/src/emulator.rs | 3 + 10 files changed, 640 insertions(+), 140 deletions(-) diff --git a/crates/umide/src/panel/emulator_view.rs b/crates/umide/src/panel/emulator_view.rs index c9ec366e..1e97aae5 100644 --- a/crates/umide/src/panel/emulator_view.rs +++ b/crates/umide/src/panel/emulator_view.rs @@ -3,7 +3,7 @@ use floem::{ View, ViewId, prelude::{SignalGet, SignalUpdate}, reactive::{RwSignal, Effect}, views::{Decorators, Label, Scroll, Stack, dyn_stack, Container}, - context::{PaintCx, UpdateCx, ComputeLayoutCx}, + context::{UpdateCx, ComputeLayoutCx}, peniko::kurbo::Rect, }; @@ -16,7 +16,8 @@ use crate::{ use umide_emulator::{ list_all_devices, launch_device, stop_device, DeviceInfo, DevicePlatform, DeviceState, - native_view::NativeEmulatorView, + native_view::NativeEmulatorView, + decoder::DecodedFrame, }; use umide_native::emulator::EmulatorPlatform; @@ -29,6 +30,9 @@ struct NativeEmulatorWidget { current_device_id: RwSignal, /// Track the last device ID we initialized for, to detect changes last_device_id: Option, + /// Floem frame signal (for panel data, not used for rendering directly) + #[allow(dead_code)] + frame_signal: RwSignal>>, } impl NativeEmulatorWidget { @@ -36,6 +40,7 @@ impl NativeEmulatorWidget { running_device: RwSignal>, is_visible: RwSignal, current_device_id: RwSignal, + frame_signal: RwSignal>>, ) -> Self { Self { id: ViewId::new(), @@ -44,6 +49,7 @@ impl NativeEmulatorWidget { is_visible, current_device_id, last_device_id: None, + frame_signal, } } @@ -70,21 +76,16 @@ impl View for NativeEmulatorWidget { let current_device = self.running_device.get_untracked(); let is_visible = self.is_visible.get_untracked(); - // If not visible, cleanup the native view but keep device info if !is_visible && self.native_view.is_some() { tracing::info!("Hiding emulator view, cleaning up native view"); self.native_view = None; - // Don't clear last_device_id to enable resume } - // Check if device was stopped - cleanup if so match (¤t_device, &self.last_device_id) { (None, Some(_)) => { - // Device was stopped, cleanup self.cleanup(); } (Some(dev), Some(last_id)) if &dev.id != last_id => { - // Different device, cleanup old and let compute_layout initialize new self.cleanup(); } _ => {} @@ -94,7 +95,6 @@ impl View for NativeEmulatorWidget { fn compute_layout(&mut self, _cx: &mut ComputeLayoutCx) -> Option { let is_visible = self.is_visible.get_untracked(); - // If not visible, cleanup and don't participate in layout if !is_visible { if self.native_view.is_some() { self.cleanup(); @@ -102,15 +102,12 @@ impl View for NativeEmulatorWidget { return None; } - // Check if device is still running let current_device = self.running_device.get_untracked(); if current_device.is_none() && self.native_view.is_some() { self.cleanup(); return None; } - // Return None to let flex layout determine our size - // The actual size will be read in paint() via get_layout() None } @@ -118,13 +115,8 @@ impl View for NativeEmulatorWidget { let is_visible = self.is_visible.get_untracked(); let current_device = self.running_device.get_untracked(); - // Header height offset: font_size(12) + padding(6*2) + border(1) + container padding ≈ 35px - // This is needed because get_window_origin() returns the panel's top, not the content area const HEADER_HEIGHT: i32 = 35; - - // Get window_origin for absolute position let window_origin = self.id.get_window_origin(); - let size = self.id.get_layout().map(|l| (l.size.width as u32, l.size.height as u32)); if let Some((width, height)) = size { @@ -132,12 +124,8 @@ impl View for NativeEmulatorWidget { return; } - // Use window_origin and add header offset to Y let x = window_origin.x as i32; let y = window_origin.y as i32 + HEADER_HEIGHT; - // Use original height - the widget's layout should already account for content area - - // Get device name for debugging let device_name = current_device.as_ref().map(|d| d.name.as_str()).unwrap_or("unknown"); tracing::debug!( @@ -146,11 +134,9 @@ impl View for NativeEmulatorWidget { ); if let Some(view) = &self.native_view { - // Update native view position and size to match the layout rect in window coordinates view.resize(x, y, width, height); } else if is_visible { if let Some(device) = current_device { - // Initialize the native view if we have a window handle use floem::window::WindowIdExt; if let Some(window_id) = self.id.window_id() { @@ -174,11 +160,16 @@ impl View for NativeEmulatorWidget { platform ) { Ok(view) => { - // Attach device if ID is available if !device.id.is_empty() { view.attach_device(&device.id); } + // Android: start gRPC frame streaming (headless, no window) + // iOS: uses ScreenCaptureKit via attach_device (no gRPC needed) + if view.is_android() { + view.start_grpc_stream("http://localhost:8554"); + } + self.native_view = Some(view); self.last_device_id = Some(device.id.clone()); } @@ -357,7 +348,7 @@ fn platform_panel( // Native Emulator View (shown when device running AND visible) Stack::new(( - NativeEmulatorWidget::new(running_device, is_visible, current_device_id) + NativeEmulatorWidget::new(running_device, is_visible, current_device_id, frame_signal) .style(|s| s.flex_grow(1.0).width_full().height_full()), // Control buttons overlay Stack::horizontal(( diff --git a/crates/umide_emulator/proto/emulator_controller.proto b/crates/umide_emulator/proto/emulator_controller.proto index 73f96794..9f40ed97 100644 --- a/crates/umide_emulator/proto/emulator_controller.proto +++ b/crates/umide_emulator/proto/emulator_controller.proto @@ -1,80 +1,97 @@ // Android Emulator gRPC Protocol -// Based on AOSP android/android-grpc/android/emulation/control/emulator_controller.proto -// Simplified version with screenshot streaming and touch input +// Based on AOSP emulator_controller.proto (field numbers must match exactly) +// https://android.googlesource.com/platform/prebuilts/android-emulator syntax = "proto3"; package android.emulation.control; +import "google/protobuf/empty.proto"; + option java_multiple_files = true; option java_package = "com.android.emulator.control"; // The EmulatorController service provides methods to control the emulator service EmulatorController { // Stream a series of screenshots from the emulator - // This will return a new frame whenever the emulated device produces one rpc streamScreenshot(ImageFormat) returns (stream Image) {} // Get a single screenshot from the emulator rpc getScreenshot(ImageFormat) returns (Image) {} // Send a touch event to the emulator - rpc sendTouch(TouchEvent) returns (Empty) {} + rpc sendTouch(TouchEvent) returns (google.protobuf.Empty) {} // Send a key event to the emulator - rpc sendKey(KeyboardEvent) returns (Empty) {} + rpc sendKey(KeyboardEvent) returns (google.protobuf.Empty) {} // Get the status of the emulator - rpc getStatus(Empty) returns (EmulatorStatus) {} + rpc getStatus(google.protobuf.Empty) returns (EmulatorStatus) {} } -// Empty message for methods that don't need parameters -message Empty {} +// Rotation information for the device display +message Rotation { + enum SkinRotation { + PORTRAIT = 0; + LANDSCAPE = 1; + REVERSE_PORTRAIT = 2; + REVERSE_LANDSCAPE = 3; + } + SkinRotation rotation = 1; +} // Image format specification for screenshots +// Field numbers MUST match AOSP emulator_controller.proto exactly message ImageFormat { - // Format of the image enum ImgFormat { PNG = 0; - RGB888 = 1; - RGBA8888 = 2; + RGBA8888 = 1; // 4 bytes per pixel + RGB888 = 2; // 3 bytes per pixel } + // The (desired) format of the resulting bytes ImgFormat format = 1; - // Optional width/height for resized images - // If not specified, uses native resolution - uint32 width = 2; - uint32 height = 3; + // [Output Only] The rotation of the image + Rotation rotation = 2; + + // The (desired) width of the image (0 = native resolution) + uint32 width = 3; + + // The (desired) height of the image (0 = native resolution) + uint32 height = 4; + + // The display id (0 = main display) + uint32 display = 5; } // The screenshot image returned by the emulator message Image { - // Image format + // Image format (contains actual width/height in AOSP) ImageFormat format = 1; - // Width of the image in pixels + // Deprecated in AOSP but still present for backwards compat uint32 width = 2; - - // Height of the image in pixels uint32 height = 3; - // The actual image data (raw bytes) + // The actual image data (raw bytes, bottom-up, left-to-right) bytes image = 4; - // Sequence number for frame ordering + // Monotonically increasing sequence number uint32 seq = 5; - // Timestamp in microseconds + // Unix timestamp in microseconds when frame was generated uint64 timestampUs = 6; } -// Touch event types +// Touch event containing a list of touch contacts message TouchEvent { - // List of touches (supports multi-touch) repeated Touch touches = 1; + // Display where the touch occurred (0 = main display) + int32 display = 2; } +// A single touch contact point message Touch { // X coordinate in device pixels int32 x = 1; @@ -82,45 +99,46 @@ message Touch { // Y coordinate in device pixels int32 y = 2; - // Touch identifier for multi-touch + // Touch identifier for multi-touch tracking int32 identifier = 3; - // Pressure (0-1) - float pressure = 4; + // Pressure: non-zero when touching, 0 to release. + // Must send pressure=0 to release a touch identifier! + int32 pressure = 4; - // Touch type - enum TouchType { - DOWN = 0; - UP = 1; - MOVE = 2; - } - TouchType type = 5; + // Optional touch major axis + int32 touch_major = 5; + + // Optional touch minor axis + int32 touch_minor = 6; } // Keyboard event message KeyboardEvent { - // Key code - int32 keycode = 1; + enum KeyCodeType { + Usb = 0; + Evdev = 1; + XKB = 2; + Win = 3; + Mac = 4; + } - // Event type enum KeyEventType { - DOWN = 0; - UP = 1; + keydown = 0; + keyup = 1; + keypress = 2; } - KeyEventType type = 2; + + KeyCodeType codeType = 1; + KeyEventType eventType = 2; + int32 keyCode = 3; + string key = 4; + string text = 5; } // Emulator status information message EmulatorStatus { - // Whether the emulator is running - bool running = 1; - - // The AVD name - string avd_name = 2; - - // Display width - uint32 width = 3; - - // Display height - uint32 height = 4; + string version = 1; + uint64 uptime = 2; + bool booted = 3; } diff --git a/crates/umide_emulator/src/android.rs b/crates/umide_emulator/src/android.rs index 7629ecb6..79ec9673 100644 --- a/crates/umide_emulator/src/android.rs +++ b/crates/umide_emulator/src/android.rs @@ -100,17 +100,20 @@ impl AndroidEmulator { return Ok(()); } - // Launch emulator headless — we capture the display via ScreenCaptureKit + // Launch emulator headless — no window, frames arrive via gRPC streaming // GPU mode "auto" picks the best available backend (Metal on macOS) - // without the Vulkan/SwiftShader crashes from "swiftshader_indirect" + // -no-window: run headless, no macOS window (we render via gRPC frames) + // -grpc 8554: expose gRPC endpoint for frame streaming and input let child = Command::new("emulator") .arg("-avd") .arg(avd_name) - .arg("-grpc") - .arg("5556") .arg("-gpu") .arg("auto") .arg("-no-boot-anim") + .arg("-no-skin") + .arg("-no-window") // Headless: no desktop window, frames via gRPC + .arg("-grpc") + .arg("8554") // gRPC endpoint for streamScreenshot + sendTouch .stdout(Stdio::null()) .stderr(Stdio::piped()) .stdin(Stdio::null()) diff --git a/crates/umide_emulator/src/grpc_client.rs b/crates/umide_emulator/src/grpc_client.rs index 75424b0f..6184e79c 100644 --- a/crates/umide_emulator/src/grpc_client.rs +++ b/crates/umide_emulator/src/grpc_client.rs @@ -17,7 +17,6 @@ use emulator_proto::{ emulator_controller_client::EmulatorControllerClient, ImageFormat, Image, TouchEvent, Touch, image_format::ImgFormat, - touch::TouchType, }; use crate::decoder::{DecodedFrame, GpuFrame}; @@ -49,24 +48,53 @@ impl EmulatorGrpcClient { .await .map_err(|e| GrpcError::ConnectionFailed(e.to_string()))?; - let client = EmulatorControllerClient::new(channel); + // Raw RGBA frames at device resolution can be large (1080x2400x4 = ~10MB) + // Default tonic limit is 4MB — increase to 50MB + let client = EmulatorControllerClient::new(channel) + .max_decoding_message_size(50 * 1024 * 1024); info!("Connected to Android emulator gRPC"); Ok(Self { client }) } - /// Connect to default emulator endpoint (localhost:5556) + /// Connect to default emulator endpoint (localhost:8554) pub async fn connect_default() -> Result { - Self::connect("http://localhost:5556").await + Self::connect("http://localhost:8554").await + } + + /// Connect with retry and exponential backoff. + /// The emulator takes time to boot and expose gRPC, so we retry patiently. + pub async fn connect_with_retry(endpoint: &str, max_duration: std::time::Duration) -> Result { + let start = std::time::Instant::now(); + let mut delay = std::time::Duration::from_millis(200); + let max_delay = std::time::Duration::from_secs(2); + + loop { + match Self::connect(endpoint).await { + Ok(client) => return Ok(client), + Err(e) => { + if start.elapsed() >= max_duration { + return Err(GrpcError::ConnectionFailed(format!( + "Failed to connect after {:?}: {}", max_duration, e + ))); + } + warn!("gRPC connection failed (retrying in {:?}): {}", delay, e); + tokio::time::sleep(delay).await; + delay = (delay * 2).min(max_delay); + } + } + } } /// Get a single screenshot pub async fn get_screenshot(&mut self) -> Result { let format = ImageFormat { format: ImgFormat::Rgba8888 as i32, - width: 0, // Native resolution + rotation: None, + width: 0, // Native resolution height: 0, + display: 0, // Main display }; let response = self.client @@ -86,8 +114,10 @@ impl EmulatorGrpcClient { ) -> Result<(), GrpcError> { let format = ImageFormat { format: ImgFormat::Rgba8888 as i32, - width: 0, + rotation: None, + width: 0, // Native resolution height: 0, + display: 0, }; info!("Starting screenshot stream..."); @@ -130,17 +160,44 @@ impl EmulatorGrpcClient { } /// Send a touch event to the emulator - pub async fn send_touch(&mut self, x: i32, y: i32, touch_type: TouchType) -> Result<(), GrpcError> { + /// pressure > 0 means touching, pressure = 0 means release + pub async fn send_touch_down(&mut self, x: i32, y: i32) -> Result<(), GrpcError> { let touch = Touch { x, y, identifier: 0, - pressure: 1.0, - r#type: touch_type as i32, + pressure: 1, // Non-zero = touching + touch_major: 0, + touch_minor: 0, }; let event = TouchEvent { touches: vec![touch], + display: 0, + }; + + self.client + .send_touch(event) + .await + .map_err(|e| GrpcError::StreamError(e.to_string()))?; + + Ok(()) + } + + /// Release a touch at coordinates (pressure = 0) + pub async fn send_touch_up(&mut self, x: i32, y: i32) -> Result<(), GrpcError> { + let touch = Touch { + x, + y, + identifier: 0, + pressure: 0, // 0 = release + touch_major: 0, + touch_minor: 0, + }; + + let event = TouchEvent { + touches: vec![touch], + display: 0, }; self.client @@ -153,29 +210,42 @@ impl EmulatorGrpcClient { /// Send a tap (down + up) at coordinates pub async fn tap(&mut self, x: i32, y: i32) -> Result<(), GrpcError> { - self.send_touch(x, y, TouchType::Down).await?; + self.send_touch_down(x, y).await?; tokio::time::sleep(std::time::Duration::from_millis(50)).await; - self.send_touch(x, y, TouchType::Up).await?; + self.send_touch_up(x, y).await?; Ok(()) } /// Convert gRPC Image to DecodedFrame fn image_to_frame(&self, image: Image) -> Result { - let width = image.width; - let height = image.height; + // AOSP: width/height can be in Image (deprecated) or Image.format + // Try format first, fall back to deprecated fields + let (width, height) = if let Some(ref fmt) = image.format { + let w = if fmt.width > 0 { fmt.width } else { image.width }; + let h = if fmt.height > 0 { fmt.height } else { image.height }; + (w, h) + } else { + (image.width, image.height) + }; + let data = image.image; if data.is_empty() { return Err(GrpcError::DecodeError("Empty image data".to_string())); } + if width == 0 || height == 0 { + return Err(GrpcError::DecodeError(format!( + "Invalid dimensions: {}x{}", width, height + ))); + } + // Image data should be RGBA8888 let expected_size = (width * height * 4) as usize; if data.len() != expected_size { return Err(GrpcError::DecodeError(format!( - "Image size mismatch: expected {} bytes, got {}", - expected_size, - data.len() + "Image size mismatch: expected {} ({}x{}x4), got {}", + expected_size, width, height, data.len() ))); } diff --git a/crates/umide_emulator/src/native_view.rs b/crates/umide_emulator/src/native_view.rs index 23d6c00e..3a5f01e7 100644 --- a/crates/umide_emulator/src/native_view.rs +++ b/crates/umide_emulator/src/native_view.rs @@ -1,13 +1,18 @@ -use std::ffi::{CString}; -use raw_window_handle::{RawWindowHandle}; +use std::ffi::CString; +use std::sync::Arc; +use std::sync::atomic::{AtomicBool, Ordering}; +use raw_window_handle::RawWindowHandle; use umide_native::emulator::{ umide_native_create_emulator, umide_native_destroy_emulator, umide_native_resize_emulator, - umide_native_send_input, umide_native_attach_device, + umide_native_send_input, umide_native_attach_device, umide_native_push_frame, NativeEmulator, EmulatorPlatform, EmulatorInputEvent }; pub struct NativeEmulatorView { handle: *mut NativeEmulator, + is_android: bool, + /// Cancellation flag for the gRPC streaming task + stream_cancel: Arc, } unsafe impl Send for NativeEmulatorView {} @@ -28,7 +33,11 @@ impl NativeEmulatorView { if handle.is_null() { Err("Failed to create native emulator instance".to_string()) } else { - Ok(Self { handle }) + Ok(Self { + handle, + is_android: matches!(platform, EmulatorPlatform::Android), + stream_cancel: Arc::new(AtomicBool::new(false)), + }) } } @@ -50,10 +59,130 @@ impl NativeEmulatorView { umide_native_send_input(self.handle, &event); } } + + /// Push RGBA frame data for display (used by gRPC streaming for Android) + pub fn push_frame(&self, rgba_data: &[u8], width: u32, height: u32) { + unsafe { + umide_native_push_frame(self.handle, rgba_data.as_ptr(), width, height); + } + } + + /// Start gRPC frame streaming for Android emulator. + /// Spawns a background async task that connects to the emulator's gRPC endpoint + /// and continuously pushes frames to the native view. + pub fn start_grpc_stream(&self, grpc_endpoint: &str) { + if !self.is_android { + tracing::warn!("gRPC streaming is only for Android emulators"); + return; + } + + // Cancel any existing stream + self.stream_cancel.store(true, Ordering::SeqCst); + let cancel = Arc::new(AtomicBool::new(false)); + // We can't update self.stream_cancel here since &self is immutable, + // but the old cancel flag is set to true, so old tasks will stop. + + let endpoint = grpc_endpoint.to_string(); + // Cast to usize to cross thread boundary — usize is Send, *mut is not + let handle_addr = self.handle as usize; + let cancel_flag = cancel.clone(); + + // Spawn the streaming task on a background thread with its own tokio runtime + std::thread::spawn(move || { + let rt = match tokio::runtime::Runtime::new() { + Ok(rt) => rt, + Err(e) => { + tracing::error!("Failed to create tokio runtime for gRPC stream: {}", e); + return; + } + }; + + rt.block_on(async move { + use crate::grpc_client::EmulatorGrpcClient; + use tokio::sync::mpsc; + + tracing::info!("Android gRPC stream: connecting to {}...", endpoint); + + // Connect with retry (up to 60 seconds for emulator boot) + let mut client = match EmulatorGrpcClient::connect_with_retry( + &endpoint, + std::time::Duration::from_secs(60), + ).await { + Ok(c) => { + tracing::info!("Android gRPC stream: connected!"); + c + } + Err(e) => { + tracing::error!("Android gRPC stream: failed to connect: {}", e); + return; + } + }; + + if cancel_flag.load(Ordering::SeqCst) { + tracing::info!("Android gRPC stream: cancelled before streaming started"); + return; + } + + // Start streaming frames + let (tx, mut rx) = mpsc::channel(2); // Small buffer to avoid latency + + // Spawn the gRPC stream reader + let stream_cancel = cancel_flag.clone(); + tokio::spawn(async move { + if let Err(e) = client.stream_screenshots(tx).await { + if !stream_cancel.load(Ordering::SeqCst) { + tracing::error!("Android gRPC stream error: {}", e); + } + } + }); + + // Push frames to native view + while let Some(frame) = rx.recv().await { + if cancel_flag.load(Ordering::SeqCst) { + tracing::info!("Android gRPC stream: cancelled"); + break; + } + + if let Some(rgba_data) = frame.to_rgba() { + // Safety: handle_addr is valid as long as NativeEmulatorView exists + // The cancel flag ensures we stop before the view is destroyed + let ptr = handle_addr as *mut NativeEmulator; + unsafe { + umide_native_push_frame( + ptr, + rgba_data.as_ptr(), + frame.width, + frame.height, + ); + } + } + } + + tracing::info!("Android gRPC stream: ended"); + }); + }); + + // Note: We store the cancel flag via interior mutability pattern + // The old stream_cancel is already set to true + } + + /// Stop the gRPC streaming task + pub fn stop_stream(&self) { + self.stream_cancel.store(true, Ordering::SeqCst); + } + + /// Check if this is an Android emulator + pub fn is_android(&self) -> bool { + self.is_android + } } impl Drop for NativeEmulatorView { fn drop(&mut self) { + // Cancel any running stream first + self.stream_cancel.store(true, Ordering::SeqCst); + // Give the stream thread a moment to notice cancellation + std::thread::sleep(std::time::Duration::from_millis(50)); unsafe { umide_native_destroy_emulator(self.handle); } diff --git a/crates/umide_native/cpp/include/umide_native_api.h b/crates/umide_native/cpp/include/umide_native_api.h index 39c0209f..7e3dd2a2 100644 --- a/crates/umide_native/cpp/include/umide_native_api.h +++ b/crates/umide_native/cpp/include/umide_native_api.h @@ -52,6 +52,11 @@ void umide_native_send_input(NativeEmulator* emulator, const EmulatorInputEvent* // device_id: serial for ADB, UDID for iOS void umide_native_attach_device(NativeEmulator* emulator, const char* device_id); +// Push an RGBA frame for display (used by gRPC streaming for Android) +// rgba_data: pointer to RGBA8888 pixel data +// width/height: dimensions in pixels +void umide_native_push_frame(NativeEmulator* emulator, const uint8_t* rgba_data, uint32_t width, uint32_t height); + #ifdef __cplusplus } #endif diff --git a/crates/umide_native/cpp/src/emulator.h b/crates/umide_native/cpp/src/emulator.h index 48d6b5d3..024fc4f4 100644 --- a/crates/umide_native/cpp/src/emulator.h +++ b/crates/umide_native/cpp/src/emulator.h @@ -22,6 +22,9 @@ class Emulator { // Handle input virtual void send_input(const EmulatorInputEvent& event) = 0; + // Push an RGBA frame for display (used by gRPC streaming for Android) + virtual void push_frame(const uint8_t* rgba_data, uint32_t width, uint32_t height) = 0; + // Factory method static Emulator* create(EmulatorPlatform platform); }; diff --git a/crates/umide_native/cpp/src/emulator_api.cpp b/crates/umide_native/cpp/src/emulator_api.cpp index 5e9fbedd..5184b1f4 100644 --- a/crates/umide_native/cpp/src/emulator_api.cpp +++ b/crates/umide_native/cpp/src/emulator_api.cpp @@ -51,4 +51,10 @@ void umide_native_attach_device(NativeEmulator* emulator, const char* device_id) } } +void umide_native_push_frame(NativeEmulator* emulator, const uint8_t* rgba_data, uint32_t width, uint32_t height) { + if (emulator && rgba_data && width > 0 && height > 0) { + reinterpret_cast(emulator)->push_frame(rgba_data, width, height); + } +} + } // extern "C" diff --git a/crates/umide_native/cpp/src/macos/macos_emulator.mm b/crates/umide_native/cpp/src/macos/macos_emulator.mm index 03ec52b7..6c30304b 100644 --- a/crates/umide_native/cpp/src/macos/macos_emulator.mm +++ b/crates/umide_native/cpp/src/macos/macos_emulator.mm @@ -15,6 +15,9 @@ // Forward declaration of the C++ class to use in ObjC namespace umide { class MacOSEmulator; } +// Input callback type: platform, eventType (0=down,1=move,2=up), x, y +typedef void (^UmideInputCallback)(int eventType, int x, int y); + // Custom view that captures and displays an external window's content using ScreenCaptureKit API_AVAILABLE(macos(12.3)) @interface UmideEmulatorView : NSView { @@ -22,12 +25,17 @@ @interface UmideEmulatorView : NSView { CGImageRef latestFrame; BOOL isCapturing; dispatch_queue_t captureQueue; - CIContext* ciContext; // Cached — creating per-frame leaks memory at 60fps + CIContext* ciContext; volatile BOOL isBeingDestroyed; + // Track the captured image dimensions for coordinate mapping + CGFloat capturedWidth; + CGFloat capturedHeight; } +@property (nonatomic, copy) UmideInputCallback inputCallback; - (void)startCapturingWindowWithID:(CGWindowID)windowID; - (void)stopCapturing; - (void)showStatus:(NSString*)status; +- (void)pushFrameWithData:(const uint8_t*)rgbaData width:(uint32_t)width height:(uint32_t)height; @end API_AVAILABLE(macos(12.3)) @@ -40,11 +48,14 @@ - (instancetype)initWithFrame:(NSRect)frameRect { latestFrame = NULL; isCapturing = NO; isBeingDestroyed = NO; + capturedWidth = 0; + capturedHeight = 0; captureQueue = dispatch_queue_create("com.umide.screencapture", DISPATCH_QUEUE_SERIAL); - ciContext = [CIContext context]; // Reused for all frame conversions + ciContext = [CIContext context]; [self setWantsLayer:YES]; self.layer.backgroundColor = [[NSColor blackColor] CGColor]; - self.layer.contentsGravity = kCAGravityResizeAspect; + // Auto-resize with the window — without this, the view stays at initial size + self.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; } return self; } @@ -74,7 +85,6 @@ - (void)startCapturingWindowWithID:(CGWindowID)windowID { if (!targetWindow) { NSLog(@"UmideEmulatorView: Could not find window with ID %u among %lu windows", windowID, (unsigned long)content.windows.count); - // Log available windows for debugging for (SCWindow* window in content.windows) { NSLog(@" Available window: ID=%u app='%@' title='%@'", window.windowID, window.owningApplication.applicationName, window.title); @@ -82,15 +92,27 @@ - (void)startCapturingWindowWithID:(CGWindowID)windowID { return; } - NSLog(@"UmideEmulatorView: Found window '%@' (app: '%@') for capture", - targetWindow.title, targetWindow.owningApplication.applicationName); + NSLog(@"UmideEmulatorView: Found window '%@' (app: '%@') size=%.0fx%.0f for capture", + targetWindow.title, targetWindow.owningApplication.applicationName, + targetWindow.frame.size.width, targetWindow.frame.size.height); // Configure stream for window capture SCContentFilter* filter = [[SCContentFilter alloc] initWithDesktopIndependentWindow:targetWindow]; SCStreamConfiguration* config = [[SCStreamConfiguration alloc] init]; - config.width = (size_t)MAX(targetWindow.frame.size.width, 1); - config.height = (size_t)MAX(targetWindow.frame.size.height, 1); + // Capture at high resolution for sharp emulator output. + // ScreenCaptureKit can render the window content at higher-than-screen + // resolution, which is critical for Android emulators that render internally + // at device resolution (e.g. 1080x2400) but display in a smaller window. + // We use 4x the window's point size to capture as much detail as possible, + // then drawRect scales down with high-quality interpolation for a crisp result. + CGFloat retinaScale = [[NSScreen mainScreen] backingScaleFactor]; + CGFloat captureScale = MAX(retinaScale, 2.0) * 2.0; // Typically 4x on Retina + config.width = (size_t)MAX(targetWindow.frame.size.width * captureScale, 1); + config.height = (size_t)MAX(targetWindow.frame.size.height * captureScale, 1); + NSLog(@"UmideEmulatorView: Capture resolution: %zux%zu (%.0fx%.0f pts @ %.0fx)", + config.width, config.height, + targetWindow.frame.size.width, targetWindow.frame.size.height, captureScale); config.minimumFrameInterval = CMTimeMake(1, 60); // 60 FPS config.pixelFormat = kCVPixelFormatType_32BGRA; config.showsCursor = NO; @@ -140,7 +162,6 @@ - (void)stopCapturing { } - (void)showStatus:(NSString*)status { - // Update layer with status text — for headless mode NSLog(@"UmideEmulatorView: Status: %@", status); [self setNeedsDisplay:YES]; } @@ -158,6 +179,9 @@ - (void)stream:(SCStream *)stream didOutputSampleBuffer:(CMSampleBufferRef)sampl CGImageRef newFrame = [ciContext createCGImage:ciImage fromRect:ciImage.extent]; if (newFrame) { + CGFloat imgW = (CGFloat)CGImageGetWidth(newFrame); + CGFloat imgH = (CGFloat)CGImageGetHeight(newFrame); + dispatch_async(dispatch_get_main_queue(), ^{ if (self->isBeingDestroyed) { CGImageRelease(newFrame); @@ -167,10 +191,9 @@ - (void)stream:(SCStream *)stream didOutputSampleBuffer:(CMSampleBufferRef)sampl CGImageRelease(self->latestFrame); } self->latestFrame = newFrame; - - // Use CALayer.contents for hardware-accelerated compositing - // instead of drawRect: which uses CPU rendering - self.layer.contents = (__bridge id)newFrame; + self->capturedWidth = imgW; + self->capturedHeight = imgH; + [self setNeedsDisplay:YES]; }); } } @@ -181,15 +204,126 @@ - (void)stream:(SCStream *)stream didStopWithError:(NSError *)error { error.localizedDescription, (long)error.code); isCapturing = NO; - // Attempt to restart capture after a brief delay (resilience) if (!isBeingDestroyed) { NSLog(@"UmideEmulatorView: Will not auto-restart — device may have been stopped"); } } +// Calculate the aspect-fit drawing rect for the current frame +- (NSRect)aspectFitRect { + if (capturedWidth <= 0 || capturedHeight <= 0) return self.bounds; + + NSRect bounds = self.bounds; + CGFloat scaleX = bounds.size.width / capturedWidth; + CGFloat scaleY = bounds.size.height / capturedHeight; + CGFloat scale = MIN(scaleX, scaleY); + + CGFloat drawW = capturedWidth * scale; + CGFloat drawH = capturedHeight * scale; + CGFloat drawX = (bounds.size.width - drawW) / 2.0; + CGFloat drawY = (bounds.size.height - drawH) / 2.0; + + return NSMakeRect(drawX, drawY, drawW, drawH); +} + +// Map a view point to emulator coordinates (0..capturedWidth, 0..capturedHeight) +- (NSPoint)viewPointToEmulatorPoint:(NSPoint)viewPoint { + NSRect drawRect = [self aspectFitRect]; + if (drawRect.size.width <= 0 || drawRect.size.height <= 0) return NSMakePoint(-1, -1); + + // Map from view-space draw rect to image-space + CGFloat relX = (viewPoint.x - drawRect.origin.x) / drawRect.size.width; + CGFloat relY = (viewPoint.y - drawRect.origin.y) / drawRect.size.height; + + // Clamp to valid range + if (relX < 0 || relX > 1 || relY < 0 || relY > 1) return NSMakePoint(-1, -1); + + // NSView is bottom-up, emulator is top-down — flip Y + CGFloat emuX = relX * capturedWidth; + CGFloat emuY = (1.0 - relY) * capturedHeight; + + return NSMakePoint(emuX, emuY); +} + +// Mouse event handling for interaction +- (BOOL)acceptsFirstResponder { + return YES; +} + +- (BOOL)acceptsFirstMouse:(NSEvent *)event { + return YES; +} + +- (void)mouseDown:(NSEvent *)event { + NSPoint viewPoint = [self convertPoint:[event locationInWindow] fromView:nil]; + NSPoint emuPoint = [self viewPointToEmulatorPoint:viewPoint]; + if (emuPoint.x >= 0 && self.inputCallback) { + self.inputCallback(0, (int)emuPoint.x, (int)emuPoint.y); + } +} + +- (void)mouseDragged:(NSEvent *)event { + NSPoint viewPoint = [self convertPoint:[event locationInWindow] fromView:nil]; + NSPoint emuPoint = [self viewPointToEmulatorPoint:viewPoint]; + if (emuPoint.x >= 0 && self.inputCallback) { + self.inputCallback(1, (int)emuPoint.x, (int)emuPoint.y); + } +} + +- (void)mouseUp:(NSEvent *)event { + NSPoint viewPoint = [self convertPoint:[event locationInWindow] fromView:nil]; + NSPoint emuPoint = [self viewPointToEmulatorPoint:viewPoint]; + if (emuPoint.x >= 0 && self.inputCallback) { + self.inputCallback(2, (int)emuPoint.x, (int)emuPoint.y); + } +} + +- (void)scrollWheel:(NSEvent *)event { + NSPoint viewPoint = [self convertPoint:[event locationInWindow] fromView:nil]; + NSPoint emuPoint = [self viewPointToEmulatorPoint:viewPoint]; + if (emuPoint.x >= 0 && self.inputCallback) { + // Event type 3 = scroll, pass deltaY as the y coordinate + int deltaY = (int)([event scrollingDeltaY] * 3); // Amplify for emulator + self.inputCallback(3, (int)emuPoint.x, deltaY); + } +} + - (void)drawRect:(NSRect)dirtyRect { - // Only used as fallback when layer.contents is not set - if (!latestFrame) { + NSRect bounds = self.bounds; + + if (latestFrame && bounds.size.width > 0 && bounds.size.height > 0) { + // Aspect-fit: preserve the emulator's aspect ratio, center in view + // This prevents stretching a 9:19 phone display into a wider panel + CGFloat imgW = capturedWidth; + CGFloat imgH = capturedHeight; + + if (imgW > 0 && imgH > 0) { + CGFloat viewW = bounds.size.width; + CGFloat viewH = bounds.size.height; + + // Image aspect ratio (pixels cancel out, ratio is scale-invariant) + CGFloat imgAspect = imgW / imgH; + CGFloat viewAspect = viewW / viewH; + + CGFloat drawW, drawH; + if (imgAspect > viewAspect) { + // Image is wider than view — fit width, letterbox top/bottom + drawW = viewW; + drawH = viewW / imgAspect; + } else { + // Image is taller than view — fit height, pillarbox left/right + drawH = viewH; + drawW = viewH * imgAspect; + } + + CGFloat drawX = (viewW - drawW) / 2.0; + CGFloat drawY = (viewH - drawH) / 2.0; + + CGContextRef ctx = [[NSGraphicsContext currentContext] CGContext]; + CGContextSetInterpolationQuality(ctx, kCGInterpolationHigh); + CGContextDrawImage(ctx, CGRectMake(drawX, drawY, drawW, drawH), latestFrame); + } + } else { // Draw placeholder [[NSColor blackColor] setFill]; NSRectFill(dirtyRect); @@ -200,10 +334,9 @@ - (void)drawRect:(NSRect)dirtyRect { NSFontAttributeName: [NSFont systemFontOfSize:14] }; NSSize textSize = [text sizeWithAttributes:attrs]; - [text drawAtPoint:NSMakePoint(dirtyRect.size.width/2 - textSize.width/2, - dirtyRect.size.height/2) withAttributes:attrs]; + [text drawAtPoint:NSMakePoint(bounds.size.width/2 - textSize.width/2, + bounds.size.height/2) withAttributes:attrs]; } - // If latestFrame is set, layer.contents handles rendering via GPU compositing } - (void)dealloc { @@ -211,6 +344,60 @@ - (void)dealloc { [self stopCapturing]; } +// Push RGBA frame data from gRPC (Android native resolution) +- (void)pushFrameWithData:(const uint8_t*)rgbaData width:(uint32_t)width height:(uint32_t)height { + if (!rgbaData || width == 0 || height == 0) return; + if (isBeingDestroyed) return; + + // Create CGImage from RGBA data + size_t bytesPerRow = width * 4; + size_t dataSize = bytesPerRow * height; + + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + CFDataRef cfData = CFDataCreate(NULL, rgbaData, dataSize); + CGDataProviderRef provider = CGDataProviderCreateWithCFData(cfData); + + CGImageRef newFrame = CGImageCreate( + width, height, + 8, // bits per component + 32, // bits per pixel + bytesPerRow, + colorSpace, + kCGBitmapByteOrderDefault | kCGImageAlphaLast, // RGBA + provider, + NULL, // decode + false, // shouldInterpolate + kCGRenderingIntentDefault + ); + + CGDataProviderRelease(provider); + CFRelease(cfData); + CGColorSpaceRelease(colorSpace); + + if (newFrame) { + // Must update UI on main thread + if ([NSThread isMainThread]) { + if (latestFrame) CGImageRelease(latestFrame); + latestFrame = newFrame; + capturedWidth = width; + capturedHeight = height; + [self setNeedsDisplay:YES]; + } else { + dispatch_async(dispatch_get_main_queue(), ^{ + if (self->isBeingDestroyed) { + CGImageRelease(newFrame); + return; + } + if (self->latestFrame) CGImageRelease(self->latestFrame); + self->latestFrame = newFrame; + self->capturedWidth = width; + self->capturedHeight = height; + [self setNeedsDisplay:YES]; + }); + } + } +} + @end // Helper for safe main thread execution @@ -370,8 +557,62 @@ bool initialize(void* parent_window, int32_t x, int32_t y, uint32_t width, uint3 [childWindow setBackgroundColor:[NSColor blackColor]]; emulatorView = [[UmideEmulatorView alloc] initWithFrame:NSMakeRect(0, 0, width, height)]; + + // Wire up input callback to forward mouse events to emulator/simulator + EmulatorPlatform plat = this->platform; + std::string devId = this->currentDeviceId; + CGWindowID* embeddedWinPtr = &this->embeddedWindowID; + emulatorView.inputCallback = ^(int eventType, int emuX, int emuY) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + if (plat == EMULATOR_PLATFORM_ANDROID) { + if (eventType == 0 || eventType == 2) { // tap + std::string cmd = std::string("adb shell input tap ") + + std::to_string(emuX) + " " + std::to_string(emuY); + system(cmd.c_str()); + } else if (eventType == 3) { // scroll + // emuY here is deltaY from scrollWheel + int startY = 500; // middle of screen + int endY = startY - emuY * 5; // scroll distance + std::string cmd = std::string("adb shell input swipe ") + + std::to_string(emuX) + " " + std::to_string(startY) + " " + + std::to_string(emuX) + " " + std::to_string(endY) + " 100"; + system(cmd.c_str()); + } + } else { + // iOS Simulator — post CGEvents + if (eventType == 3) { // scroll + CGEventRef scrollEvent = CGEventCreateScrollWheelEvent( + NULL, kCGScrollEventUnitPixel, 1, emuY); + if (scrollEvent) { + CGEventPost(kCGHIDEventTap, scrollEvent); + CFRelease(scrollEvent); + } + } else { + CGWindowID winID = *embeddedWinPtr; + if (winID != 0) { + CGPoint point = CGPointMake(emuX, emuY); + CGEventType type; + if (eventType == 0) type = kCGEventLeftMouseDown; + else if (eventType == 2) type = kCGEventLeftMouseUp; + else type = kCGEventLeftMouseDragged; + + CGEventRef mouseEvent = CGEventCreateMouseEvent( + NULL, type, point, kCGMouseButtonLeft); + if (mouseEvent) { + CGEventPost(kCGHIDEventTap, mouseEvent); + CFRelease(mouseEvent); + } + } + } + } + }); + }; + [childWindow setContentView:emulatorView]; + // Make the child window accept mouse events for interaction + [childWindow setIgnoresMouseEvents:NO]; + // Attach to parent window [parentWin addChildWindow:childWindow ordered:NSWindowAbove]; @@ -390,8 +631,6 @@ bool initialize(void* parent_window, int32_t x, int32_t y, uint32_t width, uint3 void resize(int32_t x, int32_t y, uint32_t width, uint32_t height) override { if (destroyed) return; - // Use runOnMainThread (dispatch_sync) for consistent timing - // dispatch_async here was causing races with initialize/cleanup runOnMainThread(^{ if (parentView && childWindow) { NSWindow* parentWin = [parentView window]; @@ -406,6 +645,17 @@ void resize(int32_t x, int32_t y, uint32_t width, uint32_t height) override { NSRect rectInScreen = NSMakeRect(screenX, screenY, width, height); [childWindow setFrame:rectInScreen display:YES]; + + // CRITICAL: Explicitly update the content view's frame + // The NSPanel starts at NSZeroRect, so autoresizingMask from 0x0 stays 0x0 + // We must manually set the view frame to match the window's content area + if (emulatorView) { + NSRect contentBounds = [[childWindow contentView] superview].bounds; + [emulatorView setFrame:NSMakeRect(0, 0, width, height)]; + NSLog(@"MacOSEmulator::resize: window=%dx%d view=%dx%d", + (int)width, (int)height, + (int)emulatorView.frame.size.width, (int)emulatorView.frame.size.height); + } } }); } @@ -416,7 +666,21 @@ void attach_device(const std::string& device_id) override { device_id.c_str(), platform == EMULATOR_PLATFORM_ANDROID ? "Android" : "iOS"); - // Find the emulator/simulator window + if (platform == EMULATOR_PLATFORM_ANDROID) { + // Android: emulator runs headless (-no-window), frames arrive via gRPC pushFrame. + // No window to find, no ScreenCaptureKit, no AppleScript. + // The Rust side handles gRPC connection and frame streaming. + NSLog(@"MacOSEmulator: Android device attached (headless mode, frames via gRPC)"); + + dispatch_async(dispatch_get_main_queue(), ^{ + if (!destroyed && emulatorView) { + [emulatorView showStatus:@"Connecting to Android emulator..."]; + } + }); + return; + } + + // iOS Simulator: Find the simulator window and capture via ScreenCaptureKit dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ if (destroyed) return; @@ -427,25 +691,13 @@ void attach_device(const std::string& device_id) override { for (int attempt = 0; attempt < maxAttempts && windowID == 0; attempt++) { if (destroyed) return; - if (platform == EMULATOR_PLATFORM_ANDROID) { - // Android Emulator — try multiple process name variants - // The emulator uses different process names depending on version/config - windowID = findWindowByProcessName("qemu-system", ""); - if (windowID == 0) { - windowID = findWindowByProcessName("emulator64", ""); - } - if (windowID == 0) { - windowID = findWindowByProcessName("emulator", "Android"); - } - } else { - // iOS Simulator — match by device name in window title - // Simulator.app window titles contain the device name, e.g. "iPhone 15 Pro" - windowID = findWindowByProcessName("Simulator", device_id); - } + // iOS Simulator — match by device name in window title + // Simulator.app window titles contain the device name, e.g. "iPhone 15 Pro" + windowID = findWindowByProcessName("Simulator", device_id); if (windowID == 0) { if (attempt % 50 == 0) { - NSLog(@"MacOSEmulator: Waiting for window (attempt %d/%d)...", attempt, maxAttempts); + NSLog(@"MacOSEmulator: Waiting for Simulator window (attempt %d/%d)...", attempt, maxAttempts); } std::this_thread::sleep_for(std::chrono::milliseconds(100)); } @@ -455,21 +707,24 @@ void attach_device(const std::string& device_id) override { if (windowID != 0) { embeddedWindowID = windowID; - NSLog(@"MacOSEmulator: Found window ID %u for device '%s'", windowID, device_id.c_str()); + NSLog(@"MacOSEmulator: Found Simulator window ID %u for device '%s'", windowID, device_id.c_str()); + // iOS: start capture directly dispatch_async(dispatch_get_main_queue(), ^{ if (!destroyed && emulatorView) { [emulatorView startCapturingWindowWithID:windowID]; + NSLog(@"MacOSEmulator: Capture started, view bounds=%.0fx%.0f", + emulatorView.bounds.size.width, emulatorView.bounds.size.height); } }); } else { - NSLog(@"MacOSEmulator: ERROR - Could not find window for device '%s' after %d seconds", + NSLog(@"MacOSEmulator: ERROR - Could not find Simulator window for device '%s' after %d seconds", device_id.c_str(), maxAttempts / 10); // Show error status in the view dispatch_async(dispatch_get_main_queue(), ^{ if (!destroyed && emulatorView) { - [emulatorView showStatus:@"Could not find emulator window.\nCheck Screen Recording permission."]; + [emulatorView showStatus:@"Could not find Simulator window.\nCheck Screen Recording permission."]; } }); } @@ -529,6 +784,23 @@ void send_input(const EmulatorInputEvent& event) override { } } } + + void push_frame(const uint8_t* rgba_data, uint32_t width, uint32_t height) override { + if (destroyed) return; + + // Copy data — dispatch_async outlives the caller's buffer + size_t dataSize = (size_t)width * height * 4; + uint8_t* dataCopy = (uint8_t*)malloc(dataSize); + if (!dataCopy) return; + memcpy(dataCopy, rgba_data, dataSize); + + dispatch_async(dispatch_get_main_queue(), ^{ + if (!destroyed && emulatorView) { + [emulatorView pushFrameWithData:dataCopy width:width height:height]; + } + free(dataCopy); + }); + } }; Emulator* Emulator::create(EmulatorPlatform platform) { diff --git a/crates/umide_native/src/emulator.rs b/crates/umide_native/src/emulator.rs index 183e537f..33eaaaea 100644 --- a/crates/umide_native/src/emulator.rs +++ b/crates/umide_native/src/emulator.rs @@ -6,6 +6,7 @@ pub struct NativeEmulator { } #[repr(C)] +#[derive(Copy, Clone)] pub enum EmulatorPlatform { Android = 0, Ios = 1, @@ -45,4 +46,6 @@ extern "C" { pub fn umide_native_send_input(emulator: *mut NativeEmulator, event: *const EmulatorInputEvent); pub fn umide_native_attach_device(emulator: *mut NativeEmulator, device_id: *const i8); + + pub fn umide_native_push_frame(emulator: *mut NativeEmulator, rgba_data: *const u8, width: u32, height: u32); } From 0bd748b7a75f21b5d2268ac155a1895b593928d7 Mon Sep 17 00:00:00 2001 From: tuandevccs Date: Fri, 20 Feb 2026 17:21:20 +0000 Subject: [PATCH 09/30] menu appears --- crates/umide/src/panel/emulator_view.rs | 119 +++++++++++++-- crates/umide_emulator/src/common.rs | 2 +- crates/umide_emulator/src/grpc_client.rs | 40 +++++ crates/umide_emulator/src/native_view.rs | 144 +++++++++++++++--- .../cpp/src/macos/macos_emulator.mm | 60 +++++++- 5 files changed, 329 insertions(+), 36 deletions(-) diff --git a/crates/umide/src/panel/emulator_view.rs b/crates/umide/src/panel/emulator_view.rs index 1e97aae5..6c98f8b2 100644 --- a/crates/umide/src/panel/emulator_view.rs +++ b/crates/umide/src/panel/emulator_view.rs @@ -115,7 +115,6 @@ impl View for NativeEmulatorWidget { let is_visible = self.is_visible.get_untracked(); let current_device = self.running_device.get_untracked(); - const HEADER_HEIGHT: i32 = 35; let window_origin = self.id.get_window_origin(); let size = self.id.get_layout().map(|l| (l.size.width as u32, l.size.height as u32)); @@ -124,13 +123,15 @@ impl View for NativeEmulatorWidget { return; } + // Use the widget's own layout position — Floem already accounts for + // the toolbar, header, and sidebar in the layout tree let x = window_origin.x as i32; - let y = window_origin.y as i32 + HEADER_HEIGHT; + let y = window_origin.y as i32; let device_name = current_device.as_ref().map(|d| d.name.as_str()).unwrap_or("unknown"); tracing::debug!( - "NativeEmulatorWidget [{}]: origin=({},{}) adjusted_y={} size={}x{}", - device_name, window_origin.x as i32, window_origin.y as i32, y, width, height + "NativeEmulatorWidget [{}]: origin=({},{}) size={}x{}", + device_name, x, y, width, height ); if let Some(view) = &self.native_view { @@ -159,7 +160,7 @@ impl View for NativeEmulatorWidget { height, platform ) { - Ok(view) => { + Ok(mut view) => { if !device.id.is_empty() { view.attach_device(&device.id); } @@ -329,9 +330,8 @@ fn platform_panel( return Vec::new(); } - let platform_filter = platform.clone(); devices.get().into_iter() - .filter(|d| d.platform == platform_filter) + .filter(|d| d.platform == platform) .collect::>() }, |d| format!("{}-{}", d.id, d.state as u32), @@ -348,11 +348,9 @@ fn platform_panel( // Native Emulator View (shown when device running AND visible) Stack::new(( - NativeEmulatorWidget::new(running_device, is_visible, current_device_id, frame_signal) - .style(|s| s.flex_grow(1.0).width_full().height_full()), - // Control buttons overlay + // Control toolbar at top Stack::horizontal(( - // Stop button - actually stops the emulator/simulator + // Stop button clickable_icon( || UmideIcons::DEBUG_STOP, move || { @@ -369,10 +367,12 @@ fn platform_panel( }, || false, || false, - || "Stop Emulator", + || "Stop", config, ), - // Hide button - hides without stopping + Label::new("Stop") + .style(|s| s.font_size(10.0).margin_right(8.0)), + // Hide button clickable_icon( || UmideIcons::CLOSE, move || { @@ -381,11 +381,31 @@ fn platform_panel( }, || false, || false, - || "Hide (keep running)", + || "Hide", config, ), + Label::new("Hide") + .style(|s| s.font_size(10.0)), )) - .style(|s| s.absolute().margin_left(5.0).margin_top(5.0).gap(5.0)) + .style(move |s| { + let config_val = config.get(); + s.width_full() + .items_center() + .padding_vert(3.0) + .padding_horiz(6.0) + .gap(3.0) + .border_bottom(1.0) + .border_color(config_val.color(UmideColor::LAPCE_BORDER)) + }), + // Emulator display + sidebar + Stack::horizontal(( + // Emulator display + NativeEmulatorWidget::new(running_device, is_visible, current_device_id, frame_signal) + .style(|s| s.flex_grow(1.0).width_full().height_full()), + // Android sidebar controls (only shown for Android) + android_sidebar(platform, config), + )) + .style(|s| s.flex_grow(1.0).width_full().height_full()), )) .style(move |s| { let visible = is_visible.get(); @@ -411,6 +431,75 @@ fn platform_panel( }) } +/// Helper to create a sidebar button that sends an ADB keyevent +fn adb_button( + label: &'static str, + _tooltip: &'static str, + keyevent: i32, + config: floem::reactive::ReadSignal>, +) -> impl View { + let label_text = label.to_string(); + Stack::new(( + Label::new(label_text) + .style(|s| s.font_size(14.0)), + )) + .on_click_stop(move |_| { + std::thread::spawn(move || { + let cmd = format!("adb shell input keyevent {}", keyevent); + let _ = std::process::Command::new("sh") + .arg("-c") + .arg(&cmd) + .output(); + }); + }) + .style(move |s| { + let config_val = config.get(); + s.width(28.0) + .height(28.0) + .items_center() + .justify_center() + .border_radius(4.0) + .cursor(floem::style::CursorStyle::Pointer) + .border(1.0) + .border_color(config_val.color(UmideColor::LAPCE_BORDER)) + .hover(|s| s.background(floem::peniko::Color::from_rgba8(255, 255, 255, 20))) + }) +} + +/// Android emulator sidebar with hardware control buttons +fn android_sidebar( + platform: DevicePlatform, + config: floem::reactive::ReadSignal>, +) -> impl View { + let is_android = matches!(platform, DevicePlatform::Android); + + Stack::new(( + // Home button (keyevent 3) + adb_button("🏠", "Home", 3, config), + // Back button (keyevent 4) + adb_button("◀", "Back", 4, config), + // Overview/Recents button (keyevent 187) + adb_button("▦", "Overview", 187, config), + // Separator + Label::new("").style(|s| s.height(8.0)), + // Volume Up (keyevent 24) + adb_button("🔊", "Vol+", 24, config), + // Volume Down (keyevent 25) + adb_button("🔉", "Vol-", 25, config), + // Separator + Label::new("").style(|s| s.height(8.0)), + // Power button (keyevent 26) + adb_button("⏻", "Power", 26, config), + )) + .style(move |s| { + s.flex_col() + .items_center() + .gap(4.0) + .padding(4.0) + .apply_if(!is_android, |s| s.hide()) + }) +} + pub fn emulator_panel( window_tab_data: Rc, position: PanelPosition, diff --git a/crates/umide_emulator/src/common.rs b/crates/umide_emulator/src/common.rs index 64dfdab0..64be583e 100644 --- a/crates/umide_emulator/src/common.rs +++ b/crates/umide_emulator/src/common.rs @@ -2,7 +2,7 @@ use anyhow::Result; use async_trait::async_trait; use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] pub enum DevicePlatform { Android, Ios, diff --git a/crates/umide_emulator/src/grpc_client.rs b/crates/umide_emulator/src/grpc_client.rs index 6184e79c..984f165c 100644 --- a/crates/umide_emulator/src/grpc_client.rs +++ b/crates/umide_emulator/src/grpc_client.rs @@ -216,6 +216,46 @@ impl EmulatorGrpcClient { Ok(()) } + /// Send a key event using a key string (e.g. "GoHome", "GoBack", "Power", "AppSwitch") + pub async fn send_key(&mut self, key: &str) -> Result<(), GrpcError> { + use emulator_proto::{KeyboardEvent, keyboard_event::{KeyEventType, KeyCodeType}}; + + let event = KeyboardEvent { + code_type: KeyCodeType::Evdev as i32, + event_type: KeyEventType::Keypress as i32, + key_code: 0, + key: key.to_string(), + text: String::new(), + }; + + self.client + .send_key(event) + .await + .map_err(|e| GrpcError::StreamError(e.to_string()))?; + + Ok(()) + } + + /// Send a key event using an Evdev keycode (e.g. 115=Vol+, 114=Vol-) + pub async fn send_key_code(&mut self, code: i32) -> Result<(), GrpcError> { + use emulator_proto::{KeyboardEvent, keyboard_event::{KeyEventType, KeyCodeType}}; + + let event = KeyboardEvent { + code_type: KeyCodeType::Evdev as i32, + event_type: KeyEventType::Keypress as i32, + key_code: code, + key: String::new(), + text: String::new(), + }; + + self.client + .send_key(event) + .await + .map_err(|e| GrpcError::StreamError(e.to_string()))?; + + Ok(()) + } + /// Convert gRPC Image to DecodedFrame fn image_to_frame(&self, image: Image) -> Result { // AOSP: width/height can be in Image (deprecated) or Image.format diff --git a/crates/umide_emulator/src/native_view.rs b/crates/umide_emulator/src/native_view.rs index 3a5f01e7..3d2275dd 100644 --- a/crates/umide_emulator/src/native_view.rs +++ b/crates/umide_emulator/src/native_view.rs @@ -8,11 +8,22 @@ use umide_native::emulator::{ NativeEmulator, EmulatorPlatform, EmulatorInputEvent }; +/// Commands to send to the gRPC command client +enum GrpcCommand { + Key(String), + KeyCode(i32), + TouchDown(i32, i32), + TouchMove(i32, i32), + TouchUp(i32, i32), +} + pub struct NativeEmulatorView { handle: *mut NativeEmulator, is_android: bool, /// Cancellation flag for the gRPC streaming task stream_cancel: Arc, + /// Channel to send commands to the gRPC command client + grpc_cmd_tx: Option>, } unsafe impl Send for NativeEmulatorView {} @@ -37,6 +48,7 @@ impl NativeEmulatorView { handle, is_android: matches!(platform, EmulatorPlatform::Android), stream_cancel: Arc::new(AtomicBool::new(false)), + grpc_cmd_tx: None, }) } } @@ -67,10 +79,45 @@ impl NativeEmulatorView { } } + /// Send a key event to the Android emulator via gRPC (e.g. "GoHome", "GoBack", "Power") + pub fn send_key(&self, key: &str) { + if let Some(tx) = &self.grpc_cmd_tx { + let _ = tx.send(GrpcCommand::Key(key.to_string())); + } + } + + /// Send a key code to the Android emulator via gRPC (e.g. 115=Vol+, 114=Vol-) + pub fn send_key_code(&self, code: i32) { + if let Some(tx) = &self.grpc_cmd_tx { + let _ = tx.send(GrpcCommand::KeyCode(code)); + } + } + + /// Send a touch down event to the Android emulator via gRPC + pub fn send_touch_down(&self, x: i32, y: i32) { + if let Some(tx) = &self.grpc_cmd_tx { + let _ = tx.send(GrpcCommand::TouchDown(x, y)); + } + } + + /// Send a touch move event to the Android emulator via gRPC + pub fn send_touch_move(&self, x: i32, y: i32) { + if let Some(tx) = &self.grpc_cmd_tx { + let _ = tx.send(GrpcCommand::TouchMove(x, y)); + } + } + + /// Send a touch up event to the Android emulator via gRPC + pub fn send_touch_up(&self, x: i32, y: i32) { + if let Some(tx) = &self.grpc_cmd_tx { + let _ = tx.send(GrpcCommand::TouchUp(x, y)); + } + } + /// Start gRPC frame streaming for Android emulator. - /// Spawns a background async task that connects to the emulator's gRPC endpoint - /// and continuously pushes frames to the native view. - pub fn start_grpc_stream(&self, grpc_endpoint: &str) { + /// Uses TWO separate gRPC clients: one for streaming frames, one for commands. + /// This avoids the deadlock where stream_screenshots holds a mutex forever. + pub fn start_grpc_stream(&mut self, grpc_endpoint: &str) { if !self.is_android { tracing::warn!("gRPC streaming is only for Android emulators"); return; @@ -79,14 +126,16 @@ impl NativeEmulatorView { // Cancel any existing stream self.stream_cancel.store(true, Ordering::SeqCst); let cancel = Arc::new(AtomicBool::new(false)); - // We can't update self.stream_cancel here since &self is immutable, - // but the old cancel flag is set to true, so old tasks will stop. + self.stream_cancel = cancel.clone(); let endpoint = grpc_endpoint.to_string(); - // Cast to usize to cross thread boundary — usize is Send, *mut is not let handle_addr = self.handle as usize; let cancel_flag = cancel.clone(); + // Create a sync channel for commands (key presses, touch events) + let (cmd_tx, cmd_rx) = std::sync::mpsc::channel::(); + self.grpc_cmd_tx = Some(cmd_tx); + // Spawn the streaming task on a background thread with its own tokio runtime std::thread::spawn(move || { let rt = match tokio::runtime::Runtime::new() { @@ -103,17 +152,17 @@ impl NativeEmulatorView { tracing::info!("Android gRPC stream: connecting to {}...", endpoint); - // Connect with retry (up to 60 seconds for emulator boot) - let mut client = match EmulatorGrpcClient::connect_with_retry( + // Connect STREAMING client with retry + let mut stream_client = match EmulatorGrpcClient::connect_with_retry( &endpoint, std::time::Duration::from_secs(60), ).await { Ok(c) => { - tracing::info!("Android gRPC stream: connected!"); + tracing::info!("Android gRPC stream: streaming client connected!"); c } Err(e) => { - tracing::error!("Android gRPC stream: failed to connect: {}", e); + tracing::error!("Android gRPC stream: failed to connect streaming client: {}", e); return; } }; @@ -123,13 +172,73 @@ impl NativeEmulatorView { return; } - // Start streaming frames - let (tx, mut rx) = mpsc::channel(2); // Small buffer to avoid latency + // Connect COMMAND client (separate connection, no lock contention) + let cmd_endpoint = endpoint.clone(); + let cmd_cancel = cancel_flag.clone(); + tokio::spawn(async move { + let mut cmd_client = match EmulatorGrpcClient::connect_with_retry( + &cmd_endpoint, + std::time::Duration::from_secs(10), + ).await { + Ok(c) => { + tracing::info!("Android gRPC: command client connected!"); + c + } + Err(e) => { + tracing::error!("Android gRPC: failed to connect command client: {}", e); + return; + } + }; - // Spawn the gRPC stream reader + loop { + if cmd_cancel.load(Ordering::SeqCst) { + break; + } + match cmd_rx.try_recv() { + Ok(cmd) => { + match cmd { + GrpcCommand::Key(key) => { + if let Err(e) = cmd_client.send_key(&key).await { + tracing::warn!("gRPC send_key error: {}", e); + } + } + GrpcCommand::KeyCode(code) => { + if let Err(e) = cmd_client.send_key_code(code).await { + tracing::warn!("gRPC send_key_code error: {}", e); + } + } + GrpcCommand::TouchDown(x, y) => { + if let Err(e) = cmd_client.send_touch_down(x, y).await { + tracing::warn!("gRPC touch_down error: {}", e); + } + } + GrpcCommand::TouchMove(x, y) => { + if let Err(e) = cmd_client.send_touch_down(x, y).await { + tracing::warn!("gRPC touch_move error: {}", e); + } + } + GrpcCommand::TouchUp(x, y) => { + if let Err(e) = cmd_client.send_touch_up(x, y).await { + tracing::warn!("gRPC touch_up error: {}", e); + } + } + } + } + Err(std::sync::mpsc::TryRecvError::Empty) => { + tokio::time::sleep(std::time::Duration::from_millis(10)).await; + } + Err(std::sync::mpsc::TryRecvError::Disconnected) => { + break; + } + } + } + }); + + // Start streaming frames (this runs until cancelled or error) + let (tx, mut rx) = mpsc::channel(2); let stream_cancel = cancel_flag.clone(); tokio::spawn(async move { - if let Err(e) = client.stream_screenshots(tx).await { + if let Err(e) = stream_client.stream_screenshots(tx).await { if !stream_cancel.load(Ordering::SeqCst) { tracing::error!("Android gRPC stream error: {}", e); } @@ -144,8 +253,6 @@ impl NativeEmulatorView { } if let Some(rgba_data) = frame.to_rgba() { - // Safety: handle_addr is valid as long as NativeEmulatorView exists - // The cancel flag ensures we stop before the view is destroyed let ptr = handle_addr as *mut NativeEmulator; unsafe { umide_native_push_frame( @@ -161,9 +268,6 @@ impl NativeEmulatorView { tracing::info!("Android gRPC stream: ended"); }); }); - - // Note: We store the cancel flag via interior mutability pattern - // The old stream_cancel is already set to true } /// Stop the gRPC streaming task @@ -181,6 +285,8 @@ impl Drop for NativeEmulatorView { fn drop(&mut self) { // Cancel any running stream first self.stream_cancel.store(true, Ordering::SeqCst); + // Drop the command channel + self.grpc_cmd_tx = None; // Give the stream thread a moment to notice cancellation std::thread::sleep(std::time::Duration::from_millis(50)); unsafe { diff --git a/crates/umide_native/cpp/src/macos/macos_emulator.mm b/crates/umide_native/cpp/src/macos/macos_emulator.mm index 6c30304b..4d20e869 100644 --- a/crates/umide_native/cpp/src/macos/macos_emulator.mm +++ b/crates/umide_native/cpp/src/macos/macos_emulator.mm @@ -709,7 +709,49 @@ void attach_device(const std::string& device_id) override { embeddedWindowID = windowID; NSLog(@"MacOSEmulator: Found Simulator window ID %u for device '%s'", windowID, device_id.c_str()); - // iOS: start capture directly + // Get the Simulator's PID from the window info for AppleScript + pid_t simPid = 0; + CFArrayRef windowList = CGWindowListCopyWindowInfo(kCGWindowListOptionAll, kCGNullWindowID); + if (windowList) { + for (CFIndex i = 0; i < CFArrayGetCount(windowList); i++) { + CFDictionaryRef info = (CFDictionaryRef)CFArrayGetValueAtIndex(windowList, i); + CFNumberRef winIDRef = (CFNumberRef)CFDictionaryGetValue(info, kCGWindowNumber); + CGWindowID wid = 0; + if (winIDRef) CFNumberGetValue(winIDRef, kCGWindowIDCFNumberType, &wid); + if (wid == windowID) { + CFNumberRef pidRef = (CFNumberRef)CFDictionaryGetValue(info, kCGWindowOwnerPID); + if (pidRef) CFNumberGetValue(pidRef, kCFNumberIntType, &simPid); + break; + } + } + CFRelease(windowList); + } + + // Resize Simulator window for better capture resolution + if (simPid > 0) { + NSString* resizeScript = [NSString stringWithFormat: + @"tell application \"System Events\"\n" + @" set simProc to first process whose unix id is %d\n" + @" tell simProc\n" + @" set position of window 1 to {50, 50}\n" + @" set size of window 1 to {400, 860}\n" + @" end tell\n" + @"end tell", simPid]; + + NSAppleScript* script = [[NSAppleScript alloc] initWithSource:resizeScript]; + NSDictionary* errorDict = nil; + [script executeAndReturnError:&errorDict]; + if (errorDict) { + NSLog(@"MacOSEmulator: AppleScript resize warning: %@", errorDict); + } else { + NSLog(@"MacOSEmulator: Resized Simulator window to 400x860"); + } + + // Wait for Simulator to re-render at new size + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } + + // Start capture dispatch_async(dispatch_get_main_queue(), ^{ if (!destroyed && emulatorView) { [emulatorView startCapturingWindowWithID:windowID]; @@ -717,6 +759,22 @@ void attach_device(const std::string& device_id) override { emulatorView.bounds.size.width, emulatorView.bounds.size.height); } }); + + // Move Simulator window off-screen after capture starts + if (simPid > 0) { + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + NSString* moveScript = [NSString stringWithFormat: + @"tell application \"System Events\"\n" + @" set simProc to first process whose unix id is %d\n" + @" tell simProc\n" + @" set position of window 1 to {-2000, 0}\n" + @" end tell\n" + @"end tell", simPid]; + + NSAppleScript* moveScriptObj = [[NSAppleScript alloc] initWithSource:moveScript]; + [moveScriptObj executeAndReturnError:nil]; + NSLog(@"MacOSEmulator: Moved Simulator window off-screen"); + } } else { NSLog(@"MacOSEmulator: ERROR - Could not find Simulator window for device '%s' after %d seconds", device_id.c_str(), maxAttempts / 10); From 05bf392325eb80a54858166e309fb6b20444d78d Mon Sep 17 00:00:00 2001 From: tuandevccs Date: Fri, 20 Feb 2026 20:23:41 +0000 Subject: [PATCH 10/30] buttons work --- crates/umide/src/panel/emulator_view.rs | 172 +++++++++--------- crates/umide_emulator/src/grpc_client.rs | 24 +++ crates/umide_emulator/src/native_view.rs | 87 ++++++++- .../cpp/include/umide_native_api.h | 7 + crates/umide_native/cpp/src/emulator.h | 3 + crates/umide_native/cpp/src/emulator_api.cpp | 6 + .../cpp/src/macos/macos_emulator.mm | 59 ++---- crates/umide_native/src/emulator.rs | 5 + 8 files changed, 228 insertions(+), 135 deletions(-) diff --git a/crates/umide/src/panel/emulator_view.rs b/crates/umide/src/panel/emulator_view.rs index 6c98f8b2..77e95fcc 100644 --- a/crates/umide/src/panel/emulator_view.rs +++ b/crates/umide/src/panel/emulator_view.rs @@ -284,7 +284,7 @@ fn platform_panel( }; Stack::new(( - // Header with device name if running + // Header with device name (ABOVE native view so always visible) Container::new( Stack::horizontal(( Label::new(platform_name.to_string()) @@ -305,7 +305,7 @@ fn platform_panel( String::new() } }) - .style(|s| s.font_size(10.0).padding_right(6.0)), + .style(|s| s.font_size(10.0).flex_grow(1.0).padding_right(6.0)), )) .style(|s| s.width_full().items_center()) ) @@ -346,73 +346,20 @@ fn platform_panel( .apply_if(has_running && visible, |s| s.hide()) }), - // Native Emulator View (shown when device running AND visible) - Stack::new(( - // Control toolbar at top - Stack::horizontal(( - // Stop button - clickable_icon( - || UmideIcons::DEBUG_STOP, - move || { - if let Some(device) = running_device.get_untracked() { - tracing::info!("Stopping device: {}", device.name); - if let Err(e) = stop_device(&device) { - tracing::error!("Failed to stop device {}: {}", device.name, e); - } - } - running_device.set(None); - is_visible.set(false); - frame_signal.set(None); - current_device_id.set(String::new()); - }, - || false, - || false, - || "Stop", - config, - ), - Label::new("Stop") - .style(|s| s.font_size(10.0).margin_right(8.0)), - // Hide button - clickable_icon( - || UmideIcons::CLOSE, - move || { - tracing::info!("Hiding emulator view (device still running)"); - is_visible.set(false); - }, - || false, - || false, - || "Hide", - config, - ), - Label::new("Hide") - .style(|s| s.font_size(10.0)), - )) - .style(move |s| { - let config_val = config.get(); - s.width_full() - .items_center() - .padding_vert(3.0) - .padding_horiz(6.0) - .gap(3.0) - .border_bottom(1.0) - .border_color(config_val.color(UmideColor::LAPCE_BORDER)) - }), - // Emulator display + sidebar - Stack::horizontal(( - // Emulator display - NativeEmulatorWidget::new(running_device, is_visible, current_device_id, frame_signal) - .style(|s| s.flex_grow(1.0).width_full().height_full()), - // Android sidebar controls (only shown for Android) - android_sidebar(platform, config), - )) - .style(|s| s.flex_grow(1.0).width_full().height_full()), + // Native Emulator View + Sidebar (shown when device running AND visible) + Stack::horizontal(( + // Emulator display + NativeEmulatorWidget::new(running_device, is_visible, current_device_id, frame_signal) + .style(|s| s.flex_grow(1.0).width_full().height_full()), + // Emulator sidebar controls + emulator_sidebar(platform, running_device, is_visible, frame_signal, current_device_id, config), )) .style(move |s| { let visible = is_visible.get(); let has_running = running_device.get().is_some(); - s.flex_col() + s.flex_grow(1.0) .width_full() - .flex_grow(1.0) + .height_full() .apply_if(!has_running || !visible, |s| s.hide()) }) )) @@ -466,37 +413,94 @@ fn adb_button( }) } -/// Android emulator sidebar with hardware control buttons -fn android_sidebar( +/// Emulator sidebar with control buttons (Stop/Hide for all, hardware buttons for Android) +fn emulator_sidebar( platform: DevicePlatform, + running_device: RwSignal>, + is_visible: RwSignal, + frame_signal: RwSignal>>, + current_device_id: RwSignal, config: floem::reactive::ReadSignal>, ) -> impl View { let is_android = matches!(platform, DevicePlatform::Android); Stack::new(( - // Home button (keyevent 3) - adb_button("🏠", "Home", 3, config), - // Back button (keyevent 4) - adb_button("◀", "Back", 4, config), - // Overview/Recents button (keyevent 187) - adb_button("▦", "Overview", 187, config), - // Separator - Label::new("").style(|s| s.height(8.0)), - // Volume Up (keyevent 24) - adb_button("🔊", "Vol+", 24, config), - // Volume Down (keyevent 25) - adb_button("🔉", "Vol-", 25, config), - // Separator - Label::new("").style(|s| s.height(8.0)), - // Power button (keyevent 26) - adb_button("⏻", "Power", 26, config), + // Generic controls (both platforms) + Stack::new(( + // Stop button + clickable_icon( + || UmideIcons::DEBUG_STOP, + move || { + if let Some(device) = running_device.get_untracked() { + tracing::info!("Stopping device: {}", device.name); + if let Err(e) = stop_device(&device) { + tracing::error!("Failed to stop device {}: {}", device.name, e); + } + } + running_device.set(None); + is_visible.set(false); + frame_signal.set(None); + current_device_id.set(String::new()); + }, + || false, + || false, + || "Stop", + config, + ), + Label::new("Stop").style(|s| s.font_size(10.0)), + // Separator + Label::new("").style(|s| s.height(8.0)), + // Hide button + clickable_icon( + || UmideIcons::CLOSE, + move || { + tracing::info!("Hiding emulator view (device still running)"); + is_visible.set(false); + }, + || false, + || false, + || "Hide", + config, + ), + Label::new("Hide").style(|s| s.font_size(10.0)), + // Separator + Label::new("").style(|s| s.height(8.0)), + )) + .style(|s| s.flex_col().items_center().gap(2.0)), + + // Android hardware controls + Stack::new(( + // Home button (keyevent 3) + adb_button("🏠", "Home", 3, config), + // Back button (keyevent 4) + adb_button("◀", "Back", 4, config), + // Overview/Recents button (keyevent 187) + adb_button("▦", "Overview", 187, config), + // Separator + Label::new("").style(|s| s.height(8.0)), + // Volume Up (keyevent 24) + adb_button("🔊", "Vol+", 24, config), + // Volume Down (keyevent 25) + adb_button("🔉", "Vol-", 25, config), + // Separator + Label::new("").style(|s| s.height(8.0)), + // Power button (keyevent 26) + adb_button("⏻", "Power", 26, config), + )) + .style(move |s| { + s.flex_col() + .items_center() + .gap(4.0) + .apply_if(!is_android, |s| s.hide()) + }) )) .style(move |s| { + let config_val = config.get(); s.flex_col() .items_center() - .gap(4.0) .padding(4.0) - .apply_if(!is_android, |s| s.hide()) + .border_left(1.0) + .border_color(config_val.color(UmideColor::LAPCE_BORDER)) }) } diff --git a/crates/umide_emulator/src/grpc_client.rs b/crates/umide_emulator/src/grpc_client.rs index 984f165c..1e55de19 100644 --- a/crates/umide_emulator/src/grpc_client.rs +++ b/crates/umide_emulator/src/grpc_client.rs @@ -183,6 +183,30 @@ impl EmulatorGrpcClient { Ok(()) } + + /// Move a touch to new coordinates (pressure = 1) + pub async fn send_touch_move(&mut self, x: i32, y: i32) -> Result<(), GrpcError> { + let touch = Touch { + x, + y, + identifier: 0, + pressure: 1, // Non-zero = touching + touch_major: 0, + touch_minor: 0, + }; + + let event = TouchEvent { + touches: vec![touch], + display: 0, + }; + + self.client + .send_touch(event) + .await + .map_err(|e| GrpcError::StreamError(e.to_string()))?; + + Ok(()) + } /// Release a touch at coordinates (pressure = 0) pub async fn send_touch_up(&mut self, x: i32, y: i32) -> Result<(), GrpcError> { diff --git a/crates/umide_emulator/src/native_view.rs b/crates/umide_emulator/src/native_view.rs index 3d2275dd..6a6e62b2 100644 --- a/crates/umide_emulator/src/native_view.rs +++ b/crates/umide_emulator/src/native_view.rs @@ -1,11 +1,11 @@ -use std::ffi::CString; +use std::ffi::{CString, c_void}; use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; use raw_window_handle::RawWindowHandle; use umide_native::emulator::{ umide_native_create_emulator, umide_native_destroy_emulator, umide_native_resize_emulator, umide_native_send_input, umide_native_attach_device, umide_native_push_frame, - NativeEmulator, EmulatorPlatform, EmulatorInputEvent + umide_native_set_input_callback, NativeEmulator, EmulatorPlatform, EmulatorInputEvent, EmulatorInputType }; /// Commands to send to the gRPC command client @@ -15,6 +15,48 @@ enum GrpcCommand { TouchDown(i32, i32), TouchMove(i32, i32), TouchUp(i32, i32), + Scroll(i32, i32), +} + +/// Context passed to the C++ callback +struct CallbackCtx { + is_android: bool, + handle: *mut NativeEmulator, + grpc_cmd_tx: Option>, +} + +extern "C" fn input_callback(event_type: i32, x: i32, y: i32, user_data: *mut c_void) { + if user_data.is_null() { return; } + let ctx = unsafe { &*(user_data as *mut CallbackCtx) }; + + if ctx.is_android { + if let Some(tx) = &ctx.grpc_cmd_tx { + let cmd = match event_type { + 0 => GrpcCommand::TouchDown(x, y), + 1 => GrpcCommand::TouchMove(x, y), + 2 => GrpcCommand::TouchUp(x, y), + 3 => GrpcCommand::Scroll(x, y), // y is deltaY + _ => return, + }; + let _ = tx.send(cmd); + } + } else { + // iOS: send event directly back to C++ `send_input` handler where CGEventPost happens + let ev_type = match event_type { + 0 => EmulatorInputType::TouchDown, + 1 => EmulatorInputType::TouchMove, + 2 => EmulatorInputType::TouchUp, + 3 => EmulatorInputType::Scroll, + _ => return, + }; + let ev = EmulatorInputEvent { + event_type: ev_type, + x, + y, + key_code: 0, + }; + unsafe { umide_native_send_input(ctx.handle, &ev); } + } } pub struct NativeEmulatorView { @@ -24,6 +66,8 @@ pub struct NativeEmulatorView { stream_cancel: Arc, /// Channel to send commands to the gRPC command client grpc_cmd_tx: Option>, + /// Pointer to the callback context (so we can drop it) + callback_ctx: *mut CallbackCtx, } unsafe impl Send for NativeEmulatorView {} @@ -44,11 +88,26 @@ impl NativeEmulatorView { if handle.is_null() { Err("Failed to create native emulator instance".to_string()) } else { + let is_android = matches!(platform, EmulatorPlatform::Android); + let (grpc_cmd_tx, _) = std::sync::mpsc::channel::(); // placeholder, replaced in start_grpc_stream + + let ctx = Box::new(CallbackCtx { + is_android, + handle, + grpc_cmd_tx: None, + }); + let ctx_ptr = Box::into_raw(ctx); + + unsafe { + umide_native_set_input_callback(handle, Some(input_callback), ctx_ptr as *mut c_void); + } + Ok(Self { handle, - is_android: matches!(platform, EmulatorPlatform::Android), + is_android, stream_cancel: Arc::new(AtomicBool::new(false)), grpc_cmd_tx: None, + callback_ctx: ctx_ptr, }) } } @@ -134,7 +193,15 @@ impl NativeEmulatorView { // Create a sync channel for commands (key presses, touch events) let (cmd_tx, cmd_rx) = std::sync::mpsc::channel::(); - self.grpc_cmd_tx = Some(cmd_tx); + self.grpc_cmd_tx = Some(cmd_tx.clone()); + + // Update the callback context so the C++ callback can send to this channel + unsafe { + if !self.callback_ctx.is_null() { + let ctx = &mut *self.callback_ctx; + ctx.grpc_cmd_tx = Some(cmd_tx); + } + } // Spawn the streaming task on a background thread with its own tokio runtime std::thread::spawn(move || { @@ -222,6 +289,15 @@ impl NativeEmulatorView { tracing::warn!("gRPC touch_up error: {}", e); } } + GrpcCommand::Scroll(x, delta_y) => { + let start_y = 500; + let end_y = start_y - delta_y * 5; + let _ = cmd_client.send_touch_down(x, start_y).await; + tokio::time::sleep(std::time::Duration::from_millis(15)).await; + let _ = cmd_client.send_touch_move(x, end_y).await; + tokio::time::sleep(std::time::Duration::from_millis(15)).await; + let _ = cmd_client.send_touch_up(x, end_y).await; + } } } Err(std::sync::mpsc::TryRecvError::Empty) => { @@ -290,6 +366,9 @@ impl Drop for NativeEmulatorView { // Give the stream thread a moment to notice cancellation std::thread::sleep(std::time::Duration::from_millis(50)); unsafe { + if !self.callback_ctx.is_null() { + let _ = Box::from_raw(self.callback_ctx); + } umide_native_destroy_emulator(self.handle); } } diff --git a/crates/umide_native/cpp/include/umide_native_api.h b/crates/umide_native/cpp/include/umide_native_api.h index 7e3dd2a2..e6cd65f6 100644 --- a/crates/umide_native/cpp/include/umide_native_api.h +++ b/crates/umide_native/cpp/include/umide_native_api.h @@ -24,6 +24,7 @@ typedef enum { EMULATOR_INPUT_TOUCH_UP = 2, EMULATOR_INPUT_KEY_DOWN = 3, EMULATOR_INPUT_KEY_UP = 4, + EMULATOR_INPUT_SCROLL = 5, } EmulatorInputType; typedef struct { @@ -57,6 +58,12 @@ void umide_native_attach_device(NativeEmulator* emulator, const char* device_id) // width/height: dimensions in pixels void umide_native_push_frame(NativeEmulator* emulator, const uint8_t* rgba_data, uint32_t width, uint32_t height); +// Input callback definition: event_type, x, y, user_data +typedef void (*EmulatorInputCallback)(int32_t event_type, int32_t x, int32_t y, void* user_data); + +// Set input callback to route touch/mouse/scroll events back to Rust +void umide_native_set_input_callback(NativeEmulator* emulator, EmulatorInputCallback callback, void* user_data); + #ifdef __cplusplus } #endif diff --git a/crates/umide_native/cpp/src/emulator.h b/crates/umide_native/cpp/src/emulator.h index 024fc4f4..1b5899ca 100644 --- a/crates/umide_native/cpp/src/emulator.h +++ b/crates/umide_native/cpp/src/emulator.h @@ -25,6 +25,9 @@ class Emulator { // Push an RGBA frame for display (used by gRPC streaming for Android) virtual void push_frame(const uint8_t* rgba_data, uint32_t width, uint32_t height) = 0; + // Set input callback to route native NSView events back to Rust + virtual void set_input_callback(void (*callback)(int32_t, int32_t, int32_t, void*), void* user_data) = 0; + // Factory method static Emulator* create(EmulatorPlatform platform); }; diff --git a/crates/umide_native/cpp/src/emulator_api.cpp b/crates/umide_native/cpp/src/emulator_api.cpp index 5184b1f4..a9349bee 100644 --- a/crates/umide_native/cpp/src/emulator_api.cpp +++ b/crates/umide_native/cpp/src/emulator_api.cpp @@ -57,4 +57,10 @@ void umide_native_push_frame(NativeEmulator* emulator, const uint8_t* rgba_data, } } +void umide_native_set_input_callback(NativeEmulator* emulator, EmulatorInputCallback callback, void* user_data) { + if (emulator) { + reinterpret_cast(emulator)->set_input_callback(callback, user_data); + } +} + } // extern "C" diff --git a/crates/umide_native/cpp/src/macos/macos_emulator.mm b/crates/umide_native/cpp/src/macos/macos_emulator.mm index 4d20e869..69b5e418 100644 --- a/crates/umide_native/cpp/src/macos/macos_emulator.mm +++ b/crates/umide_native/cpp/src/macos/macos_emulator.mm @@ -532,6 +532,9 @@ static CGWindowID findWindowByProcessName(const std::string& processName, const } } + void (*inputCallbackFn)(int32_t, int32_t, int32_t, void*) = nullptr; + void* inputCallbackUserData = nullptr; + bool initialize(void* parent_window, int32_t x, int32_t y, uint32_t width, uint32_t height) override { parentView = (__bridge NSView*)parent_window; @@ -558,54 +561,11 @@ bool initialize(void* parent_window, int32_t x, int32_t y, uint32_t width, uint3 emulatorView = [[UmideEmulatorView alloc] initWithFrame:NSMakeRect(0, 0, width, height)]; - // Wire up input callback to forward mouse events to emulator/simulator - EmulatorPlatform plat = this->platform; - std::string devId = this->currentDeviceId; - CGWindowID* embeddedWinPtr = &this->embeddedWindowID; + // Wire up input callback to forward mouse events to Rust emulatorView.inputCallback = ^(int eventType, int emuX, int emuY) { - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - if (plat == EMULATOR_PLATFORM_ANDROID) { - if (eventType == 0 || eventType == 2) { // tap - std::string cmd = std::string("adb shell input tap ") + - std::to_string(emuX) + " " + std::to_string(emuY); - system(cmd.c_str()); - } else if (eventType == 3) { // scroll - // emuY here is deltaY from scrollWheel - int startY = 500; // middle of screen - int endY = startY - emuY * 5; // scroll distance - std::string cmd = std::string("adb shell input swipe ") + - std::to_string(emuX) + " " + std::to_string(startY) + " " + - std::to_string(emuX) + " " + std::to_string(endY) + " 100"; - system(cmd.c_str()); - } - } else { - // iOS Simulator — post CGEvents - if (eventType == 3) { // scroll - CGEventRef scrollEvent = CGEventCreateScrollWheelEvent( - NULL, kCGScrollEventUnitPixel, 1, emuY); - if (scrollEvent) { - CGEventPost(kCGHIDEventTap, scrollEvent); - CFRelease(scrollEvent); - } - } else { - CGWindowID winID = *embeddedWinPtr; - if (winID != 0) { - CGPoint point = CGPointMake(emuX, emuY); - CGEventType type; - if (eventType == 0) type = kCGEventLeftMouseDown; - else if (eventType == 2) type = kCGEventLeftMouseUp; - else type = kCGEventLeftMouseDragged; - - CGEventRef mouseEvent = CGEventCreateMouseEvent( - NULL, type, point, kCGMouseButtonLeft); - if (mouseEvent) { - CGEventPost(kCGHIDEventTap, mouseEvent); - CFRelease(mouseEvent); - } - } - } - } - }); + if (this->inputCallbackFn) { + this->inputCallbackFn(eventType, emuX, emuY, this->inputCallbackUserData); + } }; [childWindow setContentView:emulatorView]; @@ -628,6 +588,11 @@ bool initialize(void* parent_window, int32_t x, int32_t y, uint32_t width, uint3 return success; } + void set_input_callback(void (*callback)(int32_t, int32_t, int32_t, void*), void* user_data) override { + inputCallbackFn = callback; + inputCallbackUserData = user_data; + } + void resize(int32_t x, int32_t y, uint32_t width, uint32_t height) override { if (destroyed) return; diff --git a/crates/umide_native/src/emulator.rs b/crates/umide_native/src/emulator.rs index 33eaaaea..72a0769f 100644 --- a/crates/umide_native/src/emulator.rs +++ b/crates/umide_native/src/emulator.rs @@ -19,6 +19,7 @@ pub enum EmulatorInputType { TouchUp = 2, KeyDown = 3, KeyUp = 4, + Scroll = 5, } #[repr(C)] @@ -29,6 +30,8 @@ pub struct EmulatorInputEvent { pub key_code: i32, } +pub type EmulatorInputCallback = Option; + extern "C" { pub fn umide_native_create_emulator( parent_window: *mut c_void, @@ -45,6 +48,8 @@ extern "C" { pub fn umide_native_send_input(emulator: *mut NativeEmulator, event: *const EmulatorInputEvent); + pub fn umide_native_set_input_callback(emulator: *mut NativeEmulator, callback: EmulatorInputCallback, user_data: *mut c_void); + pub fn umide_native_attach_device(emulator: *mut NativeEmulator, device_id: *const i8); pub fn umide_native_push_frame(emulator: *mut NativeEmulator, rgba_data: *const u8, width: u32, height: u32); From 7e79bffdd415b0b4e7f67f8acb5ac14ad2d3d1f0 Mon Sep 17 00:00:00 2001 From: dev-josias Date: Sat, 21 Feb 2026 11:21:23 +0000 Subject: [PATCH 11/30] android and ios now working --- crates/umide/src/panel/emulator_view.rs | 35 +++- crates/umide_emulator/src/native_view.rs | 15 +- crates/umide_native/cpp/src/emulator.h | 7 + crates/umide_native/cpp/src/emulator_api.cpp | 12 ++ .../cpp/src/macos/macos_emulator.mm | 183 +++++------------- crates/umide_native/src/emulator.rs | 4 + test_bezel.scpt | 13 ++ test_sc | Bin 0 -> 33544 bytes test_sc.m | 7 + 9 files changed, 136 insertions(+), 140 deletions(-) create mode 100644 test_bezel.scpt create mode 100755 test_sc create mode 100644 test_sc.m diff --git a/crates/umide/src/panel/emulator_view.rs b/crates/umide/src/panel/emulator_view.rs index 77e95fcc..4c97b7ca 100644 --- a/crates/umide/src/panel/emulator_view.rs +++ b/crates/umide/src/panel/emulator_view.rs @@ -115,6 +115,14 @@ impl View for NativeEmulatorWidget { let is_visible = self.is_visible.get_untracked(); let current_device = self.running_device.get_untracked(); + // Cleanup if hidden or no device + if !is_visible || current_device.is_none() { + if self.native_view.is_some() { + self.cleanup(); + } + return; + } + let window_origin = self.id.get_window_origin(); let size = self.id.get_layout().map(|l| (l.size.width as u32, l.size.height as u32)); @@ -136,6 +144,7 @@ impl View for NativeEmulatorWidget { if let Some(view) = &self.native_view { view.resize(x, y, width, height); + view.show(); } else if is_visible { if let Some(device) = current_device { use floem::window::WindowIdExt; @@ -347,13 +356,25 @@ fn platform_panel( }), // Native Emulator View + Sidebar (shown when device running AND visible) - Stack::horizontal(( - // Emulator display - NativeEmulatorWidget::new(running_device, is_visible, current_device_id, frame_signal) - .style(|s| s.flex_grow(1.0).width_full().height_full()), - // Emulator sidebar controls - emulator_sidebar(platform, running_device, is_visible, frame_signal, current_device_id, config), - )) + Stack::horizontal({ + let native_widget = NativeEmulatorWidget::new(running_device, is_visible, current_device_id, frame_signal); + let widget_id = native_widget.id(); + + // Effect to force a repaint when signals change + Effect::new(move |_| { + let _ = is_visible.get(); + let _ = running_device.get(); + widget_id.request_paint(); + }); + + ( + // Emulator display + native_widget + .style(|s| s.flex_grow(1.0).width_full().height_full()), + // Emulator sidebar controls + emulator_sidebar(platform, running_device, is_visible, frame_signal, current_device_id, config), + ) + }) .style(move |s| { let visible = is_visible.get(); let has_running = running_device.get().is_some(); diff --git a/crates/umide_emulator/src/native_view.rs b/crates/umide_emulator/src/native_view.rs index 6a6e62b2..1281127b 100644 --- a/crates/umide_emulator/src/native_view.rs +++ b/crates/umide_emulator/src/native_view.rs @@ -5,6 +5,7 @@ use raw_window_handle::RawWindowHandle; use umide_native::emulator::{ umide_native_create_emulator, umide_native_destroy_emulator, umide_native_resize_emulator, umide_native_send_input, umide_native_attach_device, umide_native_push_frame, + umide_native_show_emulator, umide_native_hide_emulator, umide_native_set_input_callback, NativeEmulator, EmulatorPlatform, EmulatorInputEvent, EmulatorInputType }; @@ -89,7 +90,7 @@ impl NativeEmulatorView { Err("Failed to create native emulator instance".to_string()) } else { let is_android = matches!(platform, EmulatorPlatform::Android); - let (grpc_cmd_tx, _) = std::sync::mpsc::channel::(); // placeholder, replaced in start_grpc_stream + let (_grpc_cmd_tx, _) = std::sync::mpsc::channel::(); // placeholder, replaced in start_grpc_stream let ctx = Box::new(CallbackCtx { is_android, @@ -138,6 +139,18 @@ impl NativeEmulatorView { } } + pub fn show(&self) { + unsafe { + umide_native_show_emulator(self.handle); + } + } + + pub fn hide(&self) { + unsafe { + umide_native_hide_emulator(self.handle); + } + } + /// Send a key event to the Android emulator via gRPC (e.g. "GoHome", "GoBack", "Power") pub fn send_key(&self, key: &str) { if let Some(tx) = &self.grpc_cmd_tx { diff --git a/crates/umide_native/cpp/src/emulator.h b/crates/umide_native/cpp/src/emulator.h index 1b5899ca..736cfbb5 100644 --- a/crates/umide_native/cpp/src/emulator.h +++ b/crates/umide_native/cpp/src/emulator.h @@ -19,9 +19,16 @@ class Emulator { // Attach a specific emulator instance virtual void attach_device(const std::string& device_id) = 0; + // Show the emulator + virtual void show() = 0; + + // Hide the emulator + virtual void hide() = 0; + // Handle input virtual void send_input(const EmulatorInputEvent& event) = 0; + // Push an RGBA frame for display (used by gRPC streaming for Android) virtual void push_frame(const uint8_t* rgba_data, uint32_t width, uint32_t height) = 0; diff --git a/crates/umide_native/cpp/src/emulator_api.cpp b/crates/umide_native/cpp/src/emulator_api.cpp index a9349bee..602b35cd 100644 --- a/crates/umide_native/cpp/src/emulator_api.cpp +++ b/crates/umide_native/cpp/src/emulator_api.cpp @@ -45,6 +45,18 @@ void umide_native_send_input(NativeEmulator* emulator, const EmulatorInputEvent* } } +void umide_native_show_emulator(NativeEmulator* emulator) { + if (emulator) { + reinterpret_cast(emulator)->show(); + } +} + +void umide_native_hide_emulator(NativeEmulator* emulator) { + if (emulator) { + reinterpret_cast(emulator)->hide(); + } +} + void umide_native_attach_device(NativeEmulator* emulator, const char* device_id) { if (emulator && device_id) { reinterpret_cast(emulator)->attach_device(std::string(device_id)); diff --git a/crates/umide_native/cpp/src/macos/macos_emulator.mm b/crates/umide_native/cpp/src/macos/macos_emulator.mm index 69b5e418..eaea43ba 100644 --- a/crates/umide_native/cpp/src/macos/macos_emulator.mm +++ b/crates/umide_native/cpp/src/macos/macos_emulator.mm @@ -54,8 +54,8 @@ - (instancetype)initWithFrame:(NSRect)frameRect { ciContext = [CIContext context]; [self setWantsLayer:YES]; self.layer.backgroundColor = [[NSColor blackColor] CGColor]; - // Auto-resize with the window — without this, the view stays at initial size - self.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; + // Ensure CoreAnimation scales the video frames automatically while maintaining aspect ratio + self.layer.contentsGravity = kCAGravityResizeAspect; } return self; } @@ -100,24 +100,18 @@ - (void)startCapturingWindowWithID:(CGWindowID)windowID { SCContentFilter* filter = [[SCContentFilter alloc] initWithDesktopIndependentWindow:targetWindow]; SCStreamConfiguration* config = [[SCStreamConfiguration alloc] init]; - // Capture at high resolution for sharp emulator output. - // ScreenCaptureKit can render the window content at higher-than-screen - // resolution, which is critical for Android emulators that render internally - // at device resolution (e.g. 1080x2400) but display in a smaller window. - // We use 4x the window's point size to capture as much detail as possible, - // then drawRect scales down with high-quality interpolation for a crisp result. - CGFloat retinaScale = [[NSScreen mainScreen] backingScaleFactor]; - CGFloat captureScale = MAX(retinaScale, 2.0) * 2.0; // Typically 4x on Retina - config.width = (size_t)MAX(targetWindow.frame.size.width * captureScale, 1); - config.height = (size_t)MAX(targetWindow.frame.size.height * captureScale, 1); - NSLog(@"UmideEmulatorView: Capture resolution: %zux%zu (%.0fx%.0f pts @ %.0fx)", - config.width, config.height, - targetWindow.frame.size.width, targetWindow.frame.size.height, captureScale); + config.width = (size_t)MAX(targetWindow.frame.size.width, 1); + config.height = (size_t)MAX(targetWindow.frame.size.height, 1); config.minimumFrameInterval = CMTimeMake(1, 60); // 60 FPS config.pixelFormat = kCVPixelFormatType_32BGRA; config.showsCursor = NO; config.capturesAudio = NO; + // Remove massive macOS window drop shadow from the capture if supported (macOS 14+) + if ([config respondsToSelector:NSSelectorFromString(@"setIgnoreShadowsSingleWindow:")]) { + [config setValue:@YES forKey:@"ignoreShadowsSingleWindow"]; + } + self->captureStream = [[SCStream alloc] initWithFilter:filter configuration:config delegate:self]; NSError* addOutputError; @@ -193,7 +187,10 @@ - (void)stream:(SCStream *)stream didOutputSampleBuffer:(CMSampleBufferRef)sampl self->latestFrame = newFrame; self->capturedWidth = imgW; self->capturedHeight = imgH; - [self setNeedsDisplay:YES]; + + // Render directly through the layer tree instead of relying on drawRect: + // This grants hardware-accelerated kCAGravityResizeAspect perfect fit + self.layer.contents = (__bridge id)self->latestFrame; }); } } @@ -288,56 +285,7 @@ - (void)scrollWheel:(NSEvent *)event { } } -- (void)drawRect:(NSRect)dirtyRect { - NSRect bounds = self.bounds; - - if (latestFrame && bounds.size.width > 0 && bounds.size.height > 0) { - // Aspect-fit: preserve the emulator's aspect ratio, center in view - // This prevents stretching a 9:19 phone display into a wider panel - CGFloat imgW = capturedWidth; - CGFloat imgH = capturedHeight; - - if (imgW > 0 && imgH > 0) { - CGFloat viewW = bounds.size.width; - CGFloat viewH = bounds.size.height; - - // Image aspect ratio (pixels cancel out, ratio is scale-invariant) - CGFloat imgAspect = imgW / imgH; - CGFloat viewAspect = viewW / viewH; - - CGFloat drawW, drawH; - if (imgAspect > viewAspect) { - // Image is wider than view — fit width, letterbox top/bottom - drawW = viewW; - drawH = viewW / imgAspect; - } else { - // Image is taller than view — fit height, pillarbox left/right - drawH = viewH; - drawW = viewH * imgAspect; - } - - CGFloat drawX = (viewW - drawW) / 2.0; - CGFloat drawY = (viewH - drawH) / 2.0; - - CGContextRef ctx = [[NSGraphicsContext currentContext] CGContext]; - CGContextSetInterpolationQuality(ctx, kCGInterpolationHigh); - CGContextDrawImage(ctx, CGRectMake(drawX, drawY, drawW, drawH), latestFrame); - } - } else { - // Draw placeholder - [[NSColor blackColor] setFill]; - NSRectFill(dirtyRect); - - NSString* text = @"Waiting for emulator..."; - NSDictionary* attrs = @{ - NSForegroundColorAttributeName: [NSColor grayColor], - NSFontAttributeName: [NSFont systemFontOfSize:14] - }; - NSSize textSize = [text sizeWithAttributes:attrs]; - [text drawAtPoint:NSMakePoint(bounds.size.width/2 - textSize.width/2, - bounds.size.height/2) withAttributes:attrs]; - } -} +// Removed manual drawRect: - replaced by CALayer rendering - (void)dealloc { isBeingDestroyed = YES; @@ -381,7 +329,9 @@ - (void)pushFrameWithData:(const uint8_t*)rgbaData width:(uint32_t)width height: latestFrame = newFrame; capturedWidth = width; capturedHeight = height; - [self setNeedsDisplay:YES]; + + // Render directly through the layer tree instead of relying on drawRect: + self.layer.contents = (__bridge id)self->latestFrame; } else { dispatch_async(dispatch_get_main_queue(), ^{ if (self->isBeingDestroyed) { @@ -392,7 +342,9 @@ - (void)pushFrameWithData:(const uint8_t*)rgbaData width:(uint32_t)width height: self->latestFrame = newFrame; self->capturedWidth = width; self->capturedHeight = height; - [self setNeedsDisplay:YES]; + + // Render directly through the layer tree instead of relying on drawRect: + self.layer.contents = (__bridge id)self->latestFrame; }); } } @@ -509,6 +461,8 @@ static CGWindowID findWindowByProcessName(const std::string& processName, const std::string currentDeviceId; EmulatorPlatform platform; volatile bool destroyed = false; + uint32_t viewWidth = 400; + uint32_t viewHeight = 860; public: MacOSEmulator(EmulatorPlatform p) : platform(p) {} @@ -547,8 +501,16 @@ bool initialize(void* parent_window, int32_t x, int32_t y, uint32_t width, uint3 return; } - // Create a borderless child window - childWindow = [[NSPanel alloc] initWithContentRect:NSZeroRect + // Calculate exact screen coordinates for initialization to avoid 0x0 bugs + NSRect windowFrame = [parentWin frame]; + NSRect contentRect = [parentWin contentLayoutRect]; + CGFloat screenX = windowFrame.origin.x + x; + CGFloat screenTop = windowFrame.origin.y + windowFrame.size.height - contentRect.origin.y - y; + CGFloat screenY = screenTop - height; + NSRect initialChildFrame = NSMakeRect(screenX, screenY, width, height); + + // Create a borderless child window sized precisely + childWindow = [[NSPanel alloc] initWithContentRect:initialChildFrame styleMask:NSWindowStyleMaskBorderless backing:NSBackingStoreBuffered defer:NO]; @@ -611,11 +573,13 @@ void resize(int32_t x, int32_t y, uint32_t width, uint32_t height) override { NSRect rectInScreen = NSMakeRect(screenX, screenY, width, height); [childWindow setFrame:rectInScreen display:YES]; + viewWidth = width; + viewHeight = height; + // CRITICAL: Explicitly update the content view's frame // The NSPanel starts at NSZeroRect, so autoresizingMask from 0x0 stays 0x0 // We must manually set the view frame to match the window's content area if (emulatorView) { - NSRect contentBounds = [[childWindow contentView] superview].bounds; [emulatorView setFrame:NSMakeRect(0, 0, width, height)]; NSLog(@"MacOSEmulator::resize: window=%dx%d view=%dx%d", (int)width, (int)height, @@ -674,72 +638,11 @@ void attach_device(const std::string& device_id) override { embeddedWindowID = windowID; NSLog(@"MacOSEmulator: Found Simulator window ID %u for device '%s'", windowID, device_id.c_str()); - // Get the Simulator's PID from the window info for AppleScript - pid_t simPid = 0; - CFArrayRef windowList = CGWindowListCopyWindowInfo(kCGWindowListOptionAll, kCGNullWindowID); - if (windowList) { - for (CFIndex i = 0; i < CFArrayGetCount(windowList); i++) { - CFDictionaryRef info = (CFDictionaryRef)CFArrayGetValueAtIndex(windowList, i); - CFNumberRef winIDRef = (CFNumberRef)CFDictionaryGetValue(info, kCGWindowNumber); - CGWindowID wid = 0; - if (winIDRef) CFNumberGetValue(winIDRef, kCGWindowIDCFNumberType, &wid); - if (wid == windowID) { - CFNumberRef pidRef = (CFNumberRef)CFDictionaryGetValue(info, kCGWindowOwnerPID); - if (pidRef) CFNumberGetValue(pidRef, kCFNumberIntType, &simPid); - break; - } - } - CFRelease(windowList); - } - - // Resize Simulator window for better capture resolution - if (simPid > 0) { - NSString* resizeScript = [NSString stringWithFormat: - @"tell application \"System Events\"\n" - @" set simProc to first process whose unix id is %d\n" - @" tell simProc\n" - @" set position of window 1 to {50, 50}\n" - @" set size of window 1 to {400, 860}\n" - @" end tell\n" - @"end tell", simPid]; - - NSAppleScript* script = [[NSAppleScript alloc] initWithSource:resizeScript]; - NSDictionary* errorDict = nil; - [script executeAndReturnError:&errorDict]; - if (errorDict) { - NSLog(@"MacOSEmulator: AppleScript resize warning: %@", errorDict); - } else { - NSLog(@"MacOSEmulator: Resized Simulator window to 400x860"); - } - - // Wait for Simulator to re-render at new size - std::this_thread::sleep_for(std::chrono::milliseconds(500)); - } - - // Start capture dispatch_async(dispatch_get_main_queue(), ^{ if (!destroyed && emulatorView) { [emulatorView startCapturingWindowWithID:windowID]; - NSLog(@"MacOSEmulator: Capture started, view bounds=%.0fx%.0f", - emulatorView.bounds.size.width, emulatorView.bounds.size.height); } }); - - // Move Simulator window off-screen after capture starts - if (simPid > 0) { - std::this_thread::sleep_for(std::chrono::milliseconds(1000)); - NSString* moveScript = [NSString stringWithFormat: - @"tell application \"System Events\"\n" - @" set simProc to first process whose unix id is %d\n" - @" tell simProc\n" - @" set position of window 1 to {-2000, 0}\n" - @" end tell\n" - @"end tell", simPid]; - - NSAppleScript* moveScriptObj = [[NSAppleScript alloc] initWithSource:moveScript]; - [moveScriptObj executeAndReturnError:nil]; - NSLog(@"MacOSEmulator: Moved Simulator window off-screen"); - } } else { NSLog(@"MacOSEmulator: ERROR - Could not find Simulator window for device '%s' after %d seconds", device_id.c_str(), maxAttempts / 10); @@ -808,6 +711,22 @@ void send_input(const EmulatorInputEvent& event) override { } } + void show() override { + runOnMainThread(^{ + if (childWindow) { + [childWindow orderFront:nil]; + } + }); + } + + void hide() override { + runOnMainThread(^{ + if (childWindow) { + [childWindow orderOut:nil]; + } + }); + } + void push_frame(const uint8_t* rgba_data, uint32_t width, uint32_t height) override { if (destroyed) return; diff --git a/crates/umide_native/src/emulator.rs b/crates/umide_native/src/emulator.rs index 72a0769f..9d404881 100644 --- a/crates/umide_native/src/emulator.rs +++ b/crates/umide_native/src/emulator.rs @@ -53,4 +53,8 @@ extern "C" { pub fn umide_native_attach_device(emulator: *mut NativeEmulator, device_id: *const i8); pub fn umide_native_push_frame(emulator: *mut NativeEmulator, rgba_data: *const u8, width: u32, height: u32); + + pub fn umide_native_show_emulator(emulator: *mut NativeEmulator); + + pub fn umide_native_hide_emulator(emulator: *mut NativeEmulator); } diff --git a/test_bezel.scpt b/test_bezel.scpt new file mode 100644 index 00000000..0ee68512 --- /dev/null +++ b/test_bezel.scpt @@ -0,0 +1,13 @@ +tell application "System Events" + tell process "Simulator" + if exists menu item "Show Device Bezels" of menu "Window" of menu bar 1 then + set bezelItem to menu item "Show Device Bezels" of menu "Window" of menu bar 1 + if value of attribute "AXMenuItemMarkChar" of bezelItem is not missing value then + click bezelItem + return "Bezels disabled" + else + return "Bezels already disabled" + end if + end if + end tell +end tell diff --git a/test_sc b/test_sc new file mode 100755 index 0000000000000000000000000000000000000000..cb9dba96f895e4bbf81b8a7843cf3602df849946 GIT binary patch literal 33544 zcmeI5U1(fY5Xa|kwly_rchOjCRI*C(qm*n~1%u|{Zno)XXhJvGAjs(^xk+!E-3@o| z(!>PZPy&{|q)@8`Es77?QYnaH@}LF-r6N|NP(eW|C`Lu-ONA8DI&(iZcek|x3*y6n zVD33H=bV{2zjHQk;e2)N&+D~B8nJ{}>sTLOK{P=z?h)P3x}8<2&cwF1=iBylh__sv z#pSM>EQ!<16P4;}>+UKacGm0VKJsiXg+!~oVWn(i*!B!=D&r0DWQo_}O%Yr6Rgy3j zOMUJrmA4B$`I4(L-dQgmGjc@iV7zKCoV|U7>r+bISts@n!@Di2SQC6h}ash1r7*FOpqAxKQdnIe|oR!M; z9OzYMCOu%tRx9g^@_LzH%_<`Ha{F}eS^JLNyV|zw@b5^mVxMe_RC^afas=yoim2%9 zp-42zV^4baB->4FOAYH-FR&e!{y34GMGb2wYfxmauR(vXU(M_NyBYMaVI#&W_aa`% zTk%1&C*C(Q*vGcW1FTZVFWTPGx-U0%omhB#n(qB*Vl(?Td39`yO|l#sR`R*{3>McP3S`J&{VO^(vK2*_M&c zBy-t*bD&^3&wi8phJ1Q(Fvl;+XHDmQdQH(i5>g7OqAPcEPi6KiW7y~|*oN9~r27nu zR%Oy=mR6H9!Ji({(fCj-XRG zFx1h#;>OqqV=qp8|MAi7M>f85r{ilzk9-q*^YvMMou(aq_l3oi&;H)2t#5v%CN=y==#6LoO8xq(I +#import + +int main() { + SCStreamConfiguration *cfg = [[SCStreamConfiguration alloc] init]; + return 0; +} From 217665e6b755227e96d7d67187cf04ce8dabee68 Mon Sep 17 00:00:00 2001 From: dev-josias Date: Sat, 21 Feb 2026 11:58:16 +0000 Subject: [PATCH 12/30] fixed android sizing issue --- crates/umide/src/panel/emulator_view.rs | 46 +++++++++++++------ .../cpp/src/macos/macos_emulator.mm | 16 +++++-- 2 files changed, 43 insertions(+), 19 deletions(-) diff --git a/crates/umide/src/panel/emulator_view.rs b/crates/umide/src/panel/emulator_view.rs index 4c97b7ca..fbe024df 100644 --- a/crates/umide/src/panel/emulator_view.rs +++ b/crates/umide/src/panel/emulator_view.rs @@ -72,23 +72,33 @@ impl View for NativeEmulatorWidget { "NativeEmulatorWidget".into() } - fn update(&mut self, _cx: &mut UpdateCx, _state: Box) { + fn update(&mut self, _cx: &mut floem::context::UpdateCx, _state: Box) { let current_device = self.running_device.get_untracked(); let is_visible = self.is_visible.get_untracked(); - if !is_visible && self.native_view.is_some() { - tracing::info!("Hiding emulator view, cleaning up native view"); - self.native_view = None; + let mut should_cleanup = false; + + if !is_visible || current_device.is_none() { + should_cleanup = true; + } else if let Some(ref dev) = current_device { + if let Some(ref last_id) = self.last_device_id { + if dev.id != *last_id { + should_cleanup = true; + } + } } - - match (¤t_device, &self.last_device_id) { - (None, Some(_)) => { + + if should_cleanup { + if self.native_view.is_some() { + if let Some(ref view) = self.native_view { + view.hide(); + } self.cleanup(); } - (Some(dev), Some(last_id)) if &dev.id != last_id => { - self.cleanup(); + } else if is_visible { + if let Some(ref view) = self.native_view { + view.show(); } - _ => {} } } @@ -118,6 +128,9 @@ impl View for NativeEmulatorWidget { // Cleanup if hidden or no device if !is_visible || current_device.is_none() { if self.native_view.is_some() { + if let Some(ref view) = self.native_view { + view.hide(); + } self.cleanup(); } return; @@ -352,6 +365,8 @@ fn platform_panel( let has_running = running_device.get().is_some(); s.flex_grow(1.0) .width_full() + .min_width(0.0) + .min_height(0.0) .apply_if(has_running && visible, |s| s.hide()) }), @@ -360,10 +375,11 @@ fn platform_panel( let native_widget = NativeEmulatorWidget::new(running_device, is_visible, current_device_id, frame_signal); let widget_id = native_widget.id(); - // Effect to force a repaint when signals change + // Effect to force an update when signals change Effect::new(move |_| { let _ = is_visible.get(); let _ = running_device.get(); + widget_id.update_state(()); widget_id.request_paint(); }); @@ -381,18 +397,20 @@ fn platform_panel( s.flex_grow(1.0) .width_full() .height_full() + .min_width(0.0) + .min_height(0.0) .apply_if(!has_running || !visible, |s| s.hide()) }) )) - .style(|s| s.flex_col().flex_grow(1.0).width_full()), + .style(|s| s.flex_col().flex_grow(1.0).width_full().height_full().min_width(0.0).min_height(0.0)), )) .style(move |s| { let config = config.get(); s.flex_col() .flex_grow(1.0) .flex_basis(0.0) - .min_width(200.0) - .min_height(300.0) + .min_width(0.0) + .min_height(0.0) .height_full() .border(1.0) .border_color(config.color(UmideColor::LAPCE_BORDER)) diff --git a/crates/umide_native/cpp/src/macos/macos_emulator.mm b/crates/umide_native/cpp/src/macos/macos_emulator.mm index eaea43ba..7a382e7d 100644 --- a/crates/umide_native/cpp/src/macos/macos_emulator.mm +++ b/crates/umide_native/cpp/src/macos/macos_emulator.mm @@ -568,21 +568,27 @@ void resize(int32_t x, int32_t y, uint32_t width, uint32_t height) override { CGFloat screenX = windowFrame.origin.x + x; CGFloat screenTop = windowFrame.origin.y + windowFrame.size.height - contentRect.origin.y - y; - CGFloat screenY = screenTop - height; - NSRect rectInScreen = NSMakeRect(screenX, screenY, width, height); + // CLAMP : ne jamais dépasser le bas de la fenêtre parente + CGFloat parentBottom = windowFrame.origin.y; + CGFloat maxHeight = screenTop - parentBottom; + CGFloat clampedHeight = MIN((CGFloat)height, maxHeight); + + CGFloat screenY = screenTop - clampedHeight; + + NSRect rectInScreen = NSMakeRect(screenX, screenY, width, clampedHeight); [childWindow setFrame:rectInScreen display:YES]; viewWidth = width; - viewHeight = height; + viewHeight = height; // Keep original requested dimensions for logical sizing if needed later // CRITICAL: Explicitly update the content view's frame // The NSPanel starts at NSZeroRect, so autoresizingMask from 0x0 stays 0x0 // We must manually set the view frame to match the window's content area if (emulatorView) { - [emulatorView setFrame:NSMakeRect(0, 0, width, height)]; + [emulatorView setFrame:NSMakeRect(0, 0, width, clampedHeight)]; NSLog(@"MacOSEmulator::resize: window=%dx%d view=%dx%d", - (int)width, (int)height, + (int)width, (int)clampedHeight, (int)emulatorView.frame.size.width, (int)emulatorView.frame.size.height); } } From 19d293dff7c9c753c865c8fcf26e147618030752 Mon Sep 17 00:00:00 2001 From: dev-josias Date: Sat, 21 Feb 2026 12:11:21 +0000 Subject: [PATCH 13/30] add android/ios switch --- crates/umide/src/panel/emulator_view.rs | 89 ++++++++++++++++++------- 1 file changed, 64 insertions(+), 25 deletions(-) diff --git a/crates/umide/src/panel/emulator_view.rs b/crates/umide/src/panel/emulator_view.rs index fbe024df..bb23a397 100644 --- a/crates/umide/src/panel/emulator_view.rs +++ b/crates/umide/src/panel/emulator_view.rs @@ -595,35 +595,74 @@ pub fn emulator_panel( devices.set(dev_list); }); + let android_panel_visible = RwSignal::new(true); + let ios_panel_visible = RwSignal::new(cfg!(target_os = "macos")); + let show_ios_ui = cfg!(target_os = "macos"); + + let toggle_btn = move |label: &'static str, visible_sig: RwSignal| { + Label::derived(move || { + if visible_sig.get() { + format!("☑ {}", label) + } else { + format!("☐ {}", label) + } + }) + .on_click_stop(move |_| { + visible_sig.update(|v| *v = !*v); + }) + .style(move |s| { + s.cursor(floem::style::CursorStyle::Pointer) + .padding_right(15.0) + .font_size(12.0) + .apply_if(label == "iOS" && !show_ios_ui, |s| s.hide()) + }) + }; + + let toggle_bar = Stack::horizontal(( + toggle_btn("Android", android_panel_visible), + toggle_btn("iOS", ios_panel_visible), + )) + .style(move |s| { + let config_val = config.get(); + s.width_full() + .padding(5.0) + .border_bottom(1.0) + .border_color(config_val.color(UmideColor::LAPCE_BORDER)) + }); + PanelBuilder::new(config, position) .add( "Emulators", - Stack::horizontal(( - platform_panel( - DevicePlatform::Android, - devices, - running_android, - android_visible, - android_frame, - current_android_id, - config, - ), - platform_panel( - DevicePlatform::Ios, - devices, - running_ios, - ios_visible, - ios_frame, - current_ios_id, - config, - ), + Stack::new(( + toggle_bar, + Stack::horizontal(( + platform_panel( + DevicePlatform::Android, + devices, + running_android, + android_visible, + android_frame, + current_android_id, + config, + ).style(move |s| s.apply_if(!android_panel_visible.get(), |s| s.hide())), + platform_panel( + DevicePlatform::Ios, + devices, + running_ios, + ios_visible, + ios_frame, + current_ios_id, + config, + ).style(move |s| s.apply_if(!ios_panel_visible.get() || !show_ios_ui, |s| s.hide())), + )) + .style(|s| { + s.flex_row() + .size_full() + .gap(5.0) + .padding(5.0) + }), )) - .style(|s| { - s.flex_row() - .size_full() - .gap(5.0) - .padding(5.0) - }), + .style(|s| s.flex_col().size_full()), window_tab_data.panel.section_open(crate::panel::data::PanelSection::Process), ) .build() From 28af9bbdcb9191cc0b3593cd42c3e9a2ac5a3191 Mon Sep 17 00:00:00 2001 From: dev-josias Date: Sat, 21 Feb 2026 13:49:16 +0000 Subject: [PATCH 14/30] add sidebar buttons and screenshot --- crates/umide/src/panel/emulator_view.rs | 91 ++++++++++++------- crates/umide_emulator/src/native_view.rs | 45 ++++++++- .../cpp/src/macos/macos_emulator.mm | 88 +++++++++++++----- 3 files changed, 164 insertions(+), 60 deletions(-) diff --git a/crates/umide/src/panel/emulator_view.rs b/crates/umide/src/panel/emulator_view.rs index bb23a397..227005a8 100644 --- a/crates/umide/src/panel/emulator_view.rs +++ b/crates/umide/src/panel/emulator_view.rs @@ -23,7 +23,7 @@ use umide_native::emulator::EmulatorPlatform; struct NativeEmulatorWidget { id: ViewId, - native_view: Option, + native_view: Rc>>, running_device: RwSignal>, is_visible: RwSignal, #[allow(dead_code)] @@ -44,7 +44,7 @@ impl NativeEmulatorWidget { ) -> Self { Self { id: ViewId::new(), - native_view: None, + native_view: Rc::new(std::cell::RefCell::new(None)), running_device, is_visible, current_device_id, @@ -55,9 +55,10 @@ impl NativeEmulatorWidget { /// Cleanup the native view fn cleanup(&mut self) { - if self.native_view.is_some() { + let mut view_lock = self.native_view.borrow_mut(); + if view_lock.is_some() { tracing::info!("Cleaning up native emulator view"); - self.native_view = None; + *view_lock = None; self.last_device_id = None; } } @@ -89,14 +90,15 @@ impl View for NativeEmulatorWidget { } if should_cleanup { - if self.native_view.is_some() { - if let Some(ref view) = self.native_view { + let has_view = self.native_view.borrow().is_some(); + if has_view { + if let Some(ref view) = *self.native_view.borrow() { view.hide(); } self.cleanup(); } } else if is_visible { - if let Some(ref view) = self.native_view { + if let Some(ref view) = *self.native_view.borrow() { view.show(); } } @@ -106,14 +108,14 @@ impl View for NativeEmulatorWidget { let is_visible = self.is_visible.get_untracked(); if !is_visible { - if self.native_view.is_some() { + if self.native_view.borrow().is_some() { self.cleanup(); } return None; } let current_device = self.running_device.get_untracked(); - if current_device.is_none() && self.native_view.is_some() { + if current_device.is_none() && self.native_view.borrow().is_some() { self.cleanup(); return None; } @@ -127,8 +129,9 @@ impl View for NativeEmulatorWidget { // Cleanup if hidden or no device if !is_visible || current_device.is_none() { - if self.native_view.is_some() { - if let Some(ref view) = self.native_view { + let has_view = self.native_view.borrow().is_some(); + if has_view { + if let Some(ref view) = *self.native_view.borrow() { view.hide(); } self.cleanup(); @@ -155,9 +158,12 @@ impl View for NativeEmulatorWidget { device_name, x, y, width, height ); - if let Some(view) = &self.native_view { - view.resize(x, y, width, height); - view.show(); + let has_view = self.native_view.borrow().is_some(); + if has_view { + if let Some(view) = &*self.native_view.borrow() { + view.resize(x, y, width, height); + view.show(); + } } else if is_visible { if let Some(device) = current_device { use floem::window::WindowIdExt; @@ -193,7 +199,7 @@ impl View for NativeEmulatorWidget { view.start_grpc_stream("http://localhost:8554"); } - self.native_view = Some(view); + *self.native_view.borrow_mut() = Some(view); self.last_device_id = Some(device.id.clone()); } Err(e) => { @@ -244,6 +250,7 @@ fn platform_panel( if let Some(ref running) = running_device.get_untracked() { if running.id == device_cloned_resume.id { // Just show it again + current_device_id.set(device_cloned_resume.id.clone()); is_visible.set(true); return; } @@ -253,6 +260,7 @@ fn platform_panel( let mut d = device_cloned_start.clone(); d.state = DeviceState::Running; running_device.set(Some(d)); + current_device_id.set(device_cloned_start.id.clone()); is_visible.set(true); }, || false, @@ -375,6 +383,8 @@ fn platform_panel( let native_widget = NativeEmulatorWidget::new(running_device, is_visible, current_device_id, frame_signal); let widget_id = native_widget.id(); + + // Effect to force an update when signals change Effect::new(move |_| { let _ = is_visible.get(); @@ -417,11 +427,12 @@ fn platform_panel( }) } -/// Helper to create a sidebar button that sends an ADB keyevent -fn adb_button( +/// Helper to create a sidebar button that executes an arbitrary shell command +fn action_button( label: &'static str, _tooltip: &'static str, - keyevent: i32, + device_id: RwSignal, + cmd_builder: impl Fn(String) -> String + 'static + Send + Sync, config: floem::reactive::ReadSignal>, ) -> impl View { let label_text = label.to_string(); @@ -430,9 +441,14 @@ fn adb_button( .style(|s| s.font_size(14.0)), )) .on_click_stop(move |_| { + let id = device_id.get_untracked(); + if id.is_empty() { return; } + + let cmd = cmd_builder(id); std::thread::spawn(move || { - let cmd = format!("adb shell input keyevent {}", keyevent); + let env_path = std::env::var("PATH").unwrap_or_default(); let _ = std::process::Command::new("sh") + .env("PATH", format!("/opt/homebrew/bin:/usr/local/bin:{}", env_path)) .arg("-c") .arg(&cmd) .output(); @@ -509,28 +525,35 @@ fn emulator_sidebar( // Android hardware controls Stack::new(( - // Home button (keyevent 3) - adb_button("🏠", "Home", 3, config), - // Back button (keyevent 4) - adb_button("◀", "Back", 4, config), - // Overview/Recents button (keyevent 187) - adb_button("▦", "Overview", 187, config), - // Separator + action_button("🏠", "Home", current_device_id, |_id| "adb shell input keyevent 3".to_string(), config), + action_button("◀", "Back", current_device_id, |_id| "adb shell input keyevent 4".to_string(), config), + action_button("▦", "Overview", current_device_id, |_id| "adb shell input keyevent 187".to_string(), config), Label::new("").style(|s| s.height(8.0)), - // Volume Up (keyevent 24) - adb_button("🔊", "Vol+", 24, config), - // Volume Down (keyevent 25) - adb_button("🔉", "Vol-", 25, config), - // Separator + action_button("🔊", "Vol+", current_device_id, |_id| "adb shell input keyevent 24".to_string(), config), + action_button("🔉", "Vol-", current_device_id, |_id| "adb shell input keyevent 25".to_string(), config), Label::new("").style(|s| s.height(8.0)), - // Power button (keyevent 26) - adb_button("⏻", "Power", 26, config), + action_button("⏻", "Power", current_device_id, |_id| "adb shell input keyevent 26".to_string(), config), + Label::new("").style(|s| s.height(8.0)), + action_button("📷", "Screenshot", current_device_id, |_id| "adb exec-out screencap -p > ~/Desktop/umide_screenshot_$(date +%s).png".to_string(), config), )) .style(move |s| { s.flex_col() .items_center() .gap(4.0) .apply_if(!is_android, |s| s.hide()) + }), + + // iOS hardware controls + Stack::new(( + action_button("🏠", "Home", current_device_id, |id| format!("idb ui button --udid {} HOME", id), config), + Label::new("").style(|s| s.height(8.0)), + action_button("📷", "Screenshot", current_device_id, |id| format!("idb screenshot --udid {} ~/Desktop/umide_screenshot_$(date +%s).png", id), config), + )) + .style(move |s| { + s.flex_col() + .items_center() + .gap(4.0) + .apply_if(is_android, |s| s.hide()) // Hide if android }) )) .style(move |s| { @@ -577,6 +600,7 @@ pub fn emulator_panel( DevicePlatform::Android => { if running_android.get().is_none() { running_android.set(Some(device.clone())); + current_android_id.set(device.id.clone()); // Don't auto-show, let user click "Show" // android_visible.set(true); } @@ -584,6 +608,7 @@ pub fn emulator_panel( DevicePlatform::Ios => { if running_ios.get().is_none() { running_ios.set(Some(device.clone())); + current_ios_id.set(device.id.clone()); // Don't auto-show, let user click "Show" // ios_visible.set(true); } diff --git a/crates/umide_emulator/src/native_view.rs b/crates/umide_emulator/src/native_view.rs index 1281127b..0711faed 100644 --- a/crates/umide_emulator/src/native_view.rs +++ b/crates/umide_emulator/src/native_view.rs @@ -124,14 +124,49 @@ impl NativeEmulatorView { unsafe { umide_native_attach_device(self.handle, c_str.as_ptr()); } - } - pub fn send_input(&self, event: EmulatorInputEvent) { - unsafe { - umide_native_send_input(self.handle, &event); + if !self.is_android { + self.ensure_idb_installed(); } } + /// Silently checks and installs `idb` via Homebrew and pip if it is missing on the host. + /// This is strictly required for iOS interactability (taps/swipes). + fn ensure_idb_installed(&self) { + std::thread::spawn(move || { + // Check if idb exists + let output = std::process::Command::new("which") + .arg("idb") + .output(); + + let needs_install = match output { + Ok(out) => !out.status.success() || out.stdout.is_empty(), + Err(_) => true, + }; + + if needs_install { + tracing::info!("'idb' not found. Auto-installing iOS interaction dependencies..."); + + // 1. Install idb-companion via brew + let _ = std::process::Command::new("brew") + .args(["tap", "facebook/fb"]) + .output(); + let _ = std::process::Command::new("brew") + .args(["install", "idb-companion"]) + .output(); + + // 2. Install fb-idb via pip3 + let _ = std::process::Command::new("pip3") + .args(["install", "fb-idb"]) + .output(); + + tracing::info!("Finished installing iOS idb dependencies."); + } + }); + } + + + /// Push RGBA frame data for display (used by gRPC streaming for Android) pub fn push_frame(&self, rgba_data: &[u8], width: u32, height: u32) { unsafe { @@ -368,6 +403,8 @@ impl NativeEmulatorView { pub fn is_android(&self) -> bool { self.is_android } + + } impl Drop for NativeEmulatorView { diff --git a/crates/umide_native/cpp/src/macos/macos_emulator.mm b/crates/umide_native/cpp/src/macos/macos_emulator.mm index 7a382e7d..c840d8ea 100644 --- a/crates/umide_native/cpp/src/macos/macos_emulator.mm +++ b/crates/umide_native/cpp/src/macos/macos_emulator.mm @@ -28,6 +28,7 @@ @interface UmideEmulatorView : NSView { CIContext* ciContext; volatile BOOL isBeingDestroyed; // Track the captured image dimensions for coordinate mapping +@public CGFloat capturedWidth; CGFloat capturedHeight; } @@ -464,6 +465,11 @@ static CGWindowID findWindowByProcessName(const std::string& processName, const uint32_t viewWidth = 400; uint32_t viewHeight = 860; + // State tracking for iOS idb touches + int lastTouchX = 0; + int lastTouchY = 0; + std::chrono::steady_clock::time_point lastMoveTime; + public: MacOSEmulator(EmulatorPlatform p) : platform(p) {} @@ -685,33 +691,69 @@ void send_input(const EmulatorInputEvent& event) override { }); } } else { - // Forward touch events to iOS Simulator - // Post CGEvents to the simulator window - if (embeddedWindowID != 0) { + // Forward touch events to iOS Simulator using idb + if (embeddedWindowID != 0 && emulatorView != nil) { + + // Convert simulator capture pixels into idb logical points (assume 3.0x retina scale) + int mappedX = (int)(event.x / 3.0f); + int mappedY = (int)(event.y / 3.0f); + if (event.type == EMULATOR_INPUT_TOUCH_DOWN) { - CGPoint point = CGPointMake(event.x, event.y); - CGEventRef mouseDown = CGEventCreateMouseEvent( - NULL, kCGEventLeftMouseDown, point, kCGMouseButtonLeft); - if (mouseDown) { - CGEventPost(kCGHIDEventTap, mouseDown); - CFRelease(mouseDown); - } + lastTouchX = mappedX; + lastTouchY = mappedY; } else if (event.type == EMULATOR_INPUT_TOUCH_UP) { - CGPoint point = CGPointMake(event.x, event.y); - CGEventRef mouseUp = CGEventCreateMouseEvent( - NULL, kCGEventLeftMouseUp, point, kCGMouseButtonLeft); - if (mouseUp) { - CGEventPost(kCGHIDEventTap, mouseUp); - CFRelease(mouseUp); + int startX = lastTouchX; + int startY = lastTouchY; + int endX = mappedX; + int endY = mappedY; + std::string udid = currentDeviceId; + + int dx = abs(endX - startX); + int dy = abs(endY - startY); + + if (dx < 10 && dy < 10) { + // It's a tap + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + NSLog(@"MacOSEmulator: Sending idb tap to x=%d y=%d", endX, endY); + NSString* cmd = [NSString stringWithFormat:@"idb ui tap --udid %s %d %d", udid.c_str(), endX, endY]; + int result = system([cmd UTF8String]); + if (result != 0) { + NSLog(@"MacOSEmulator: idb tap command failed with code %d", result); + } + }); + } else { + // It's a swipe + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + NSLog(@"MacOSEmulator: Sending idb swipe from x=%d y=%d to x=%d y=%d", startX, startY, endX, endY); + NSString* cmd = [NSString stringWithFormat:@"idb ui swipe --udid %s --duration 0.2 %d %d %d %d", udid.c_str(), startX, startY, endX, endY]; + system([cmd UTF8String]); + }); } } else if (event.type == EMULATOR_INPUT_TOUCH_MOVE) { - CGPoint point = CGPointMake(event.x, event.y); - CGEventRef mouseDrag = CGEventCreateMouseEvent( - NULL, kCGEventLeftMouseDragged, point, kCGMouseButtonLeft); - if (mouseDrag) { - CGEventPost(kCGHIDEventTap, mouseDrag); - CFRelease(mouseDrag); - } + // Empty tracking block; we batch swipe invocations to fire cleanly out of TOUCH_UP instead. + } else if (event.type == EMULATOR_INPUT_SCROLL) { + auto now = std::chrono::steady_clock::now(); + auto elapsed = std::chrono::duration_cast(now - lastMoveTime).count(); + + if (elapsed < 100) return; // scroll throttle + lastMoveTime = now; + + int deltaY = event.y; + + // Synthetic swipe originating from center of iOS simulator bounds + int centerX = emulatorView->capturedWidth > 0 ? (emulatorView->capturedWidth / 2) / 3 : 200; + int centerY = emulatorView->capturedHeight > 0 ? (emulatorView->capturedHeight / 2) / 3 : 400; + + int startX = centerX; + int startY = centerY; + int endX = startX; + int endY = startY - (deltaY * 20); // scroll direction translation + + std::string udid = currentDeviceId; + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + NSString* cmd = [NSString stringWithFormat:@"idb ui swipe --udid %s --duration 0.1 %d %d %d %d", udid.c_str(), startX, startY, endX, endY]; + system([cmd UTF8String]); + }); } } } From 9d21398c3f533a79b94821e1256be1fac25aad61 Mon Sep 17 00:00:00 2001 From: dev-josias Date: Tue, 3 Mar 2026 05:23:16 +0000 Subject: [PATCH 15/30] ci: simplify release workflow for first tagged release --- .github/workflows/release.yml | 439 ++++++++++++---------------------- 1 file changed, 152 insertions(+), 287 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 43661717..8c3b6e38 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,373 +1,238 @@ name: Release on: - schedule: - - cron: 0 0 * * * + push: + tags: + - "v*" workflow_dispatch: inputs: tag_name: - description: "Tag name for release" - required: false - default: nightly - push: - tags: ["v[0-9]+.[0-9]+.[0-9]+*"] + description: "Release tag (for example: v1.0.0)" + required: true pull_request: paths: - # trigger release workflow only if this file changed - - .github/workflows/release.yml + - ".github/workflows/release.yml" concurrency: group: ${{ github.ref }}-${{ github.workflow }} cancel-in-progress: ${{ github.event_name == 'pull_request' }} env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} CARGO_TERM_COLOR: always + CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse + FLOEM_REPOSITORY: https://github.com/lapce/floem + FLOEM_REV: e0dd862564e3afbad5cba8ebe60df166a7a41e56 jobs: - tagname: + meta: runs-on: ubuntu-latest outputs: - tag_name: ${{ steps.tag.outputs.tag }} + tag_name: ${{ steps.meta.outputs.tag_name }} + prerelease: ${{ steps.meta.outputs.prerelease }} steps: - - id: vars + - id: meta shell: bash - run: echo "sha_short=${GITHUB_SHA::7}" | tee -a $GITHUB_OUTPUT - - - if: github.event_name == 'workflow_dispatch' - run: echo "TAG_NAME=${{ github.event.inputs.tag_name }}" | tee -a $GITHUB_ENV - - - if: github.event_name == 'schedule' || github.event_name == 'pull_request' - run: echo 'TAG_NAME=nightly-${{ steps.vars.outputs.sha_short }}' | tee -a $GITHUB_ENV - - - if: github.event_name == 'push' run: | - TAG_NAME=${{ github.ref }} - echo "TAG_NAME=${TAG_NAME#refs/tags/}" | tee -a $GITHUB_ENV - - - id: tag - run: echo "tag=$TAG_NAME" | tee -a $GITHUB_OUTPUT - - windows: - runs-on: windows-latest - needs: tagname - env: - RELEASE_TAG_NAME: ${{ needs.tagname.outputs.tag_name }} - - defaults: - run: - shell: bash - - steps: - - uses: actions/checkout@v4 - - - name: Update rust - run: rustup update --no-self-update - - - name: Fetch dependencies - run: cargo fetch --locked - - - name: Build - run: cargo build --frozen --profile release-lto + if [[ "${{ github.event_name }}" == "push" ]]; then + TAG_NAME="${GITHUB_REF_NAME}" + elif [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then + TAG_NAME="${{ github.event.inputs.tag_name }}" + else + TAG_NAME="dry-run-${GITHUB_SHA::7}" + fi - - name: Crate msi installer - run: | - candle.exe -arch "x64" -ext WixUIExtension -ext WixUtilExtension \ - -out "./lapce.wixobj" "extra/windows/wix/lapce.wxs" + if [[ -z "${TAG_NAME}" ]]; then + echo "tag_name input is required for workflow_dispatch" + exit 1 + fi - light.exe -ext WixUIExtension -ext WixUtilExtension \ - -out "./Umide-windows.msi" -sice:ICE61 -sice:ICE91 \ - "./lapce.wixobj" + PRERELEASE=false + if [[ "${TAG_NAME}" == *-* ]]; then + PRERELEASE=true + fi - - name: Create portable - shell: pwsh - run: | - cargo build --profile release-lto --features lapce-app/portable - Compress-Archive ./target/release-lto/lapce.exe ./Umide-windows-portable.zip - - - name: Create lapce-proxy archive - shell: pwsh - run: | - $file = [System.IO.File]::Open((Join-Path $PWD '.\target\release-lto\lapce-proxy.exe'), [System.IO.FileMode]::Open) - $archive = [System.IO.File]::Create((Join-Path $PWD '.\lapce-proxy-windows-x86_64.gz')) - $compressor = [System.IO.Compression.GZipStream]::new($archive, [System.IO.Compression.CompressionMode]::Compress) - $file.CopyTo($compressor) - Start-Sleep -Seconds 10 - $compressor.close() - - - uses: actions/upload-artifact@v4 - with: - name: lapce-windows - path: | - ./lapce-proxy-windows-*.gz - ./Umide-windows-portable.zip - ./Umide-windows.msi - retention-days: 1 + echo "tag_name=${TAG_NAME}" | tee -a "$GITHUB_OUTPUT" + echo "prerelease=${PRERELEASE}" | tee -a "$GITHUB_OUTPUT" linux: + name: Build Linux runs-on: ubuntu-latest - needs: tagname - env: - RELEASE_TAG_NAME: ${{ needs.tagname.outputs.tag_name }} + needs: meta steps: - uses: actions/checkout@v4 - - name: Build deb packages - run: | - docker buildx create --driver=docker-container --use - docker buildx bake --pull ubuntu-focal-binary - - - name: Gzip - run: | - mkdir Umide - cp ./target/linux_amd64/lapce Umide/ - tar -zcvf ./lapce-linux-amd64.tar.gz Umide - - rm -rf Umide - mkdir Umide - cp ./target/linux_arm64/lapce Umide/ - tar -zcvf ./lapce-linux-arm64.tar.gz Umide + - name: Install Linux build dependencies + run: sudo make ubuntu-deps - - name: Fetch dependencies - run: cargo fetch --locked - - - name: Vendor dependencies + - name: Prepare floem dependency run: | - cargo vendor --frozen > ./vendor-config.toml - mv ./vendor-config.toml ./vendor/ - tar -zcf vendor.tar.gz ./vendor/ + rm -rf ../floem + git clone "${FLOEM_REPOSITORY}" ../floem + git -C ../floem checkout "${FLOEM_REV}" - - uses: actions/upload-artifact@v4 - with: - name: lapce-linux - path: | - ./lapce-linux-*.tar.gz - ./vendor.tar.gz - retention-days: 1 + - name: Update toolchain + run: rustup update --no-self-update - deb: - runs-on: ubuntu-latest - needs: tagname - env: - RELEASE_TAG_NAME: ${{ needs.tagname.outputs.tag_name }} - strategy: - fail-fast: false - matrix: - include: - - os-name: debian - os-version: bookworm - - os-name: debian - os-version: bullseye - - os-name: ubuntu - os-version: jammy - - os-name: ubuntu - os-version: noble - - os-name: ubuntu - os-version: plucky - steps: - - uses: actions/checkout@v4 + - name: Cache Rust dependencies + uses: Swatinem/rust-cache@v2 - - name: Build deb packages + - name: Build binaries + run: cargo build --locked --profile release-lto --bin umide --bin umide-proxy + + - name: Package artifacts + shell: bash run: | - docker buildx create --driver=docker-container --use - docker buildx bake --pull ${{ matrix.os-name }}-${{ matrix.os-version }}-package + cp ./target/release-lto/umide ./umide-linux-x86_64 + cp ./target/release-lto/umide-proxy ./umide-proxy-linux-x86_64 + tar -czf ./umide-linux-x86_64.tar.gz ./umide-linux-x86_64 + gzip -c ./umide-proxy-linux-x86_64 > ./umide-proxy-linux-x86_64.gz - uses: actions/upload-artifact@v4 with: - name: lapce-${{ matrix.os-name }}-${{ matrix.os-version }} + name: release-linux path: | - ./target/linux_*/* - retention-days: 1 + ./umide-linux-x86_64.tar.gz + ./umide-proxy-linux-x86_64.gz + retention-days: 7 - rpm: - runs-on: ubuntu-latest - needs: tagname - env: - RELEASE_TAG_NAME: ${{ needs.tagname.outputs.tag_name }} - strategy: - fail-fast: false - matrix: - include: - - os-name: fedora - os-version: 41 - - os-name: fedora - os-version: 42 - # - os-name: fedora - # os-version: rawhide + windows: + name: Build Windows + runs-on: windows-latest + needs: meta + defaults: + run: + shell: pwsh steps: - uses: actions/checkout@v4 - - name: Build rpm packages + - name: Prepare floem dependency run: | - docker buildx create --driver=docker-container --use - docker buildx bake --pull ${{ matrix.os-name }}-${{ matrix.os-version }}-package + if (Test-Path ../floem) { Remove-Item -Path ../floem -Recurse -Force } + git clone "${env:FLOEM_REPOSITORY}" ../floem + git -C ../floem checkout "${env:FLOEM_REV}" - - uses: actions/upload-artifact@v4 - with: - name: lapce-${{ matrix.os-name }}-${{ matrix.os-version }} - path: | - ./target/* - retention-days: 1 + - name: Update toolchain + run: rustup update --no-self-update - lapce-proxy: - runs-on: ubuntu-latest - needs: tagname - env: - RELEASE_TAG_NAME: ${{ needs.tagname.outputs.tag_name }} - strategy: - fail-fast: false - matrix: - include: - - os-name: alpine - os-version: "" # uses latest - steps: - - uses: actions/checkout@v4 + - name: Cache Rust dependencies + uses: Swatinem/rust-cache@v2 - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 + - name: Build binaries + run: cargo build --locked --profile release-lto --bin umide --bin umide-proxy - - name: Build lapce-proxy binary + - name: Package artifacts run: | - docker buildx create --driver=docker-container --use - docker buildx bake --pull ${{ matrix.os-name }}-${{ matrix.os-version }} + Compress-Archive -Path .\target\release-lto\umide.exe -DestinationPath .\umide-windows-x86_64.zip -Force - - name: Gzip - run: | - gzip -c ./target/linux_amd64/lapce-proxy > ./lapce-proxy-linux-x86_64.gz - gzip -c ./target/linux_arm64/lapce-proxy > ./lapce-proxy-linux-aarch64.gz + $source = Join-Path $PWD '.\target\release-lto\umide-proxy.exe' + $target = Join-Path $PWD '.\umide-proxy-windows-x86_64.gz' + $inStream = [System.IO.File]::OpenRead($source) + $outStream = [System.IO.File]::Create($target) + $gzipStream = New-Object System.IO.Compression.GzipStream($outStream, [System.IO.Compression.CompressionLevel]::Optimal) + $inStream.CopyTo($gzipStream) + $gzipStream.Dispose() + $inStream.Dispose() + $outStream.Dispose() - uses: actions/upload-artifact@v4 with: - name: lapce-proxy-linux + name: release-windows path: | - ./lapce-proxy-linux-*.gz - retention-days: 1 + ./umide-windows-x86_64.zip + ./umide-proxy-windows-x86_64.gz + retention-days: 7 macos: + name: Build macOS runs-on: macos-14 - needs: tagname - env: - RELEASE_TAG_NAME: ${{ needs.tagname.outputs.tag_name }} - - NOTARIZE_USERNAME: ${{ secrets.NOTARIZE_USERNAME }} - NOTARIZE_PASSWORD: ${{ secrets.NOTARIZE_PASSWORD }} - + needs: meta steps: - uses: actions/checkout@v4 - - name: Install ARM target - run: rustup update && rustup target add x86_64-apple-darwin - - - name: Import Certificate - uses: Apple-Actions/import-codesign-certs@v3 - with: - p12-file-base64: ${{ secrets.MACOS_CERTIFICATE }} - p12-password: ${{ secrets.MACOS_CERTIFICATE_PWD }} - - - name: Select newer Xcode for building + - name: Prepare floem dependency + shell: bash run: | - sudo xcode-select -s /Applications/Xcode_15.4.app/Contents/Developer + rm -rf ../floem + git clone "${FLOEM_REPOSITORY}" ../floem + git -C ../floem checkout "${FLOEM_REV}" - - name: Fetch dependencies - run: cargo fetch --locked + - name: Update toolchain and install targets + run: | + rustup update --no-self-update + rustup target add x86_64-apple-darwin aarch64-apple-darwin - - name: Make DMG - run: make dmg-universal + - name: Cache Rust dependencies + uses: Swatinem/rust-cache@v2 - - name: Rename + - name: Build binaries run: | - cp ./target/release-lto/macos/Umide.dmg ./target/release-lto/macos/Umide-macos.dmg + cargo build --locked --profile release-lto --target x86_64-apple-darwin --bin umide --bin umide-proxy + cargo build --locked --profile release-lto --target aarch64-apple-darwin --bin umide --bin umide-proxy - - name: Gzip lapce-proxy + - name: Build universal artifacts + shell: bash run: | - gzip -c ./target/x86_64-apple-darwin/release-lto/lapce-proxy > ./target/release-lto/macos/lapce-proxy-darwin-x86_64.gz - gzip -c ./target/aarch64-apple-darwin/release-lto/lapce-proxy > ./target/release-lto/macos/lapce-proxy-darwin-aarch64.gz + lipo -create \ + ./target/x86_64-apple-darwin/release-lto/umide \ + ./target/aarch64-apple-darwin/release-lto/umide \ + -output ./umide-macos-universal - - name: Notarize Release Build - uses: lando/notarize-action@v2 - with: - product-path: "./target/release-lto/macos/Umide-macos.dmg" - appstore-connect-username: ${{ secrets.NOTARIZE_USERNAME }} - appstore-connect-password: ${{ secrets.NOTARIZE_PASSWORD }} - appstore-connect-team-id: CYSGAZFR8D - primary-bundle-id: "io.lapce" - verbose: true - - - name: "Staple Release Build" - uses: lapce/xcode-staple@062485d6eeafe841c18a412f012e80f49e23c517 - with: - product-path: "./target/release-lto/macos/Umide-macos.dmg" + lipo -create \ + ./target/x86_64-apple-darwin/release-lto/umide-proxy \ + ./target/aarch64-apple-darwin/release-lto/umide-proxy \ + -output ./umide-proxy-macos-universal + + tar -czf ./umide-macos-universal.tar.gz ./umide-macos-universal + gzip -c ./umide-proxy-macos-universal > ./umide-proxy-macos-universal.gz - uses: actions/upload-artifact@v4 with: - name: lapce-macos + name: release-macos path: | - ./target/release-lto/macos/lapce-proxy-darwin-*.gz - ./target/release-lto/macos/Umide-macos.dmg - retention-days: 3 + ./umide-macos-universal.tar.gz + ./umide-proxy-macos-universal.gz + retention-days: 7 publish: + name: Publish GitHub Release + if: github.event_name != 'pull_request' + runs-on: ubuntu-latest needs: + - meta - linux - - lapce-proxy - - deb - - rpm - windows - macos - runs-on: ubuntu-latest - env: - GH_REPO: ${{ github.repository }} - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} permissions: contents: write + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TAG_NAME: ${{ needs.meta.outputs.tag_name }} + PRERELEASE: ${{ needs.meta.outputs.prerelease }} steps: - # Must perform checkout first, since it deletes the target directory - # before running, and would therefore delete the downloaded artifacts - - uses: actions/checkout@v4 - - uses: actions/download-artifact@v4 - - if: github.event_name == 'workflow_dispatch' - run: echo "TAG_NAME=${{ github.event.inputs.tag_name }}" | tee -a $GITHUB_ENV - - - if: github.event_name == 'schedule' - run: echo 'TAG_NAME=nightly' | tee -a $GITHUB_ENV - - - if: github.event_name == 'push' - run: | - TAG_NAME=${{ github.ref }} - echo "TAG_NAME=${TAG_NAME#refs/tags/}" | tee -a $GITHUB_ENV - - - if: env.TAG_NAME == 'nightly' - run: | - { - echo 'SUBJECT=Umide development build' - echo 'PRERELEASE=--prerelease' - } | tee -a $GITHUB_ENV - - - if: env.TAG_NAME == 'nightly' && github.event_name != 'pull_request' - name: Re-Tag nightly - run: | - gh release delete nightly --yes || true - git push origin :nightly || true - - - if: env.TAG_NAME != 'nightly' - run: | - { - echo 'SUBJECT=Umide release build' - echo 'PRERELEASE=' - } | tee -a $GITHUB_ENV - - - name: Publish release - if: github.event_name != 'pull_request' - env: - DEBUG: api + - name: Create or update release + shell: bash run: | - gh release create $TAG_NAME $PRERELEASE --title "$TAG_NAME" --target $GITHUB_SHA \ - lapce-macos/* \ - lapce-linux/* \ - lapce-debian*/*/* \ - lapce-ubuntu*/*/* \ - lapce-fedora*/* \ - lapce-proxy-linux/* \ - lapce-windows/* + if gh release view "${TAG_NAME}" >/dev/null 2>&1; then + gh release upload "${TAG_NAME}" \ + ./release-linux/* \ + ./release-windows/* \ + ./release-macos/* \ + --clobber + exit 0 + fi + + RELEASE_ARGS=() + if [[ "${PRERELEASE}" == "true" ]]; then + RELEASE_ARGS+=(--prerelease) + fi + + gh release create "${TAG_NAME}" \ + --target "${GITHUB_SHA}" \ + --title "${TAG_NAME}" \ + --generate-notes \ + "${RELEASE_ARGS[@]}" \ + ./release-linux/* \ + ./release-windows/* \ + ./release-macos/* From 6ef3f21ca322f59f6249d18b258ab30f948388b4 Mon Sep 17 00:00:00 2001 From: dev-josias Date: Tue, 3 Mar 2026 05:51:46 +0000 Subject: [PATCH 16/30] ci: fetch vendor path dependencies in release builds --- .github/workflows/release.yml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8c3b6e38..eaa9bcc0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -22,6 +22,8 @@ env: CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse FLOEM_REPOSITORY: https://github.com/lapce/floem FLOEM_REV: e0dd862564e3afbad5cba8ebe60df166a7a41e56 + LAPCE_SOURCE_REPOSITORY: https://github.com/lapce/lapce + LAPCE_SOURCE_TAG: v0.4.6 jobs: meta: @@ -70,6 +72,15 @@ jobs: git clone "${FLOEM_REPOSITORY}" ../floem git -C ../floem checkout "${FLOEM_REV}" + - name: Prepare vendor dependencies + run: | + rm -rf ../lapce-src + git clone --depth 1 --branch "${LAPCE_SOURCE_TAG}" "${LAPCE_SOURCE_REPOSITORY}" ../lapce-src + mkdir -p ./vendor + cp -R ../lapce-src/vendor/structdesc ./vendor/structdesc + cp -R ../lapce-src/vendor/lsp-types ./vendor/lsp-types + cp -R ../lapce-src/vendor/psp-types ./vendor/psp-types + - name: Update toolchain run: rustup update --no-self-update @@ -111,6 +122,15 @@ jobs: git clone "${env:FLOEM_REPOSITORY}" ../floem git -C ../floem checkout "${env:FLOEM_REV}" + - name: Prepare vendor dependencies + run: | + if (Test-Path ../lapce-src) { Remove-Item -Path ../lapce-src -Recurse -Force } + git clone --depth 1 --branch "${env:LAPCE_SOURCE_TAG}" "${env:LAPCE_SOURCE_REPOSITORY}" ../lapce-src + New-Item -ItemType Directory -Path .\vendor -Force | Out-Null + Copy-Item -Path ..\lapce-src\vendor\structdesc -Destination .\vendor\structdesc -Recurse -Force + Copy-Item -Path ..\lapce-src\vendor\lsp-types -Destination .\vendor\lsp-types -Recurse -Force + Copy-Item -Path ..\lapce-src\vendor\psp-types -Destination .\vendor\psp-types -Recurse -Force + - name: Update toolchain run: rustup update --no-self-update @@ -156,6 +176,16 @@ jobs: git clone "${FLOEM_REPOSITORY}" ../floem git -C ../floem checkout "${FLOEM_REV}" + - name: Prepare vendor dependencies + shell: bash + run: | + rm -rf ../lapce-src + git clone --depth 1 --branch "${LAPCE_SOURCE_TAG}" "${LAPCE_SOURCE_REPOSITORY}" ../lapce-src + mkdir -p ./vendor + cp -R ../lapce-src/vendor/structdesc ./vendor/structdesc + cp -R ../lapce-src/vendor/lsp-types ./vendor/lsp-types + cp -R ../lapce-src/vendor/psp-types ./vendor/psp-types + - name: Update toolchain and install targets run: | rustup update --no-self-update From 4e4b55aead364c7db417c52f852cdf0af5947487 Mon Sep 17 00:00:00 2001 From: dev-josias Date: Tue, 3 Mar 2026 05:54:15 +0000 Subject: [PATCH 17/30] ci: track vendor crates required by path dependencies --- .github/workflows/release.yml | 30 - .gitignore | 8 +- vendor/lsp-types/.clog.toml | 6 + vendor/lsp-types/.github/workflows/rust.yml | 40 + vendor/lsp-types/.gitignore | 5 + vendor/lsp-types/CHANGELOG.md | 319 ++ vendor/lsp-types/Cargo.toml | 28 + vendor/lsp-types/LICENSE | 22 + vendor/lsp-types/README.md | 18 + vendor/lsp-types/release.sh | 15 + vendor/lsp-types/release.toml | 1 + vendor/lsp-types/src/call_hierarchy.rs | 127 + vendor/lsp-types/src/code_action.rs | 395 +++ vendor/lsp-types/src/code_lens.rs | 66 + vendor/lsp-types/src/color.rs | 122 + vendor/lsp-types/src/completion.rs | 616 ++++ vendor/lsp-types/src/document_diagnostic.rs | 269 ++ vendor/lsp-types/src/document_highlight.rs | 51 + vendor/lsp-types/src/document_link.rs | 67 + vendor/lsp-types/src/document_symbols.rs | 134 + vendor/lsp-types/src/error_codes.rs | 54 + vendor/lsp-types/src/file_operations.rs | 213 ++ vendor/lsp-types/src/folding_range.rs | 145 + vendor/lsp-types/src/formatting.rs | 153 + vendor/lsp-types/src/hover.rs | 86 + vendor/lsp-types/src/inlay_hint.rs | 281 ++ vendor/lsp-types/src/inline_completion.rs | 162 + vendor/lsp-types/src/inline_value.rs | 217 ++ vendor/lsp-types/src/lib.rs | 2880 ++++++++++++++++++ vendor/lsp-types/src/linked_editing.rs | 61 + vendor/lsp-types/src/lsif.rs | 336 ++ vendor/lsp-types/src/moniker.rs | 92 + vendor/lsp-types/src/notification.rs | 361 +++ vendor/lsp-types/src/progress.rs | 135 + vendor/lsp-types/src/references.rs | 30 + vendor/lsp-types/src/rename.rs | 88 + vendor/lsp-types/src/request.rs | 1068 +++++++ vendor/lsp-types/src/selection_range.rs | 86 + vendor/lsp-types/src/semantic_tokens.rs | 734 +++++ vendor/lsp-types/src/signature_help.rs | 207 ++ vendor/lsp-types/src/trace.rs | 77 + vendor/lsp-types/src/type_hierarchy.rs | 90 + vendor/lsp-types/src/window.rs | 177 ++ vendor/lsp-types/src/workspace_diagnostic.rs | 149 + vendor/lsp-types/src/workspace_folders.rs | 49 + vendor/lsp-types/src/workspace_symbols.rs | 105 + vendor/lsp-types/tests/lsif.rs | 18 + vendor/lsp-types/tests/tsc-unix.lsif | 135 + vendor/psp-types/.gitignore | 2 + vendor/psp-types/Cargo.toml | 11 + vendor/psp-types/README.md | 1 + vendor/psp-types/src/lib.rs | 114 + vendor/structdesc/.gitignore | 2 + vendor/structdesc/.taplo.toml | 13 + vendor/structdesc/Cargo.toml | 14 + vendor/structdesc/LICENCE | 21 + vendor/structdesc/src/lib.rs | 128 + 57 files changed, 10803 insertions(+), 31 deletions(-) create mode 100644 vendor/lsp-types/.clog.toml create mode 100644 vendor/lsp-types/.github/workflows/rust.yml create mode 100644 vendor/lsp-types/.gitignore create mode 100644 vendor/lsp-types/CHANGELOG.md create mode 100644 vendor/lsp-types/Cargo.toml create mode 100644 vendor/lsp-types/LICENSE create mode 100644 vendor/lsp-types/README.md create mode 100755 vendor/lsp-types/release.sh create mode 100644 vendor/lsp-types/release.toml create mode 100644 vendor/lsp-types/src/call_hierarchy.rs create mode 100644 vendor/lsp-types/src/code_action.rs create mode 100644 vendor/lsp-types/src/code_lens.rs create mode 100644 vendor/lsp-types/src/color.rs create mode 100644 vendor/lsp-types/src/completion.rs create mode 100644 vendor/lsp-types/src/document_diagnostic.rs create mode 100644 vendor/lsp-types/src/document_highlight.rs create mode 100644 vendor/lsp-types/src/document_link.rs create mode 100644 vendor/lsp-types/src/document_symbols.rs create mode 100644 vendor/lsp-types/src/error_codes.rs create mode 100644 vendor/lsp-types/src/file_operations.rs create mode 100644 vendor/lsp-types/src/folding_range.rs create mode 100644 vendor/lsp-types/src/formatting.rs create mode 100644 vendor/lsp-types/src/hover.rs create mode 100644 vendor/lsp-types/src/inlay_hint.rs create mode 100644 vendor/lsp-types/src/inline_completion.rs create mode 100644 vendor/lsp-types/src/inline_value.rs create mode 100644 vendor/lsp-types/src/lib.rs create mode 100644 vendor/lsp-types/src/linked_editing.rs create mode 100644 vendor/lsp-types/src/lsif.rs create mode 100644 vendor/lsp-types/src/moniker.rs create mode 100644 vendor/lsp-types/src/notification.rs create mode 100644 vendor/lsp-types/src/progress.rs create mode 100644 vendor/lsp-types/src/references.rs create mode 100644 vendor/lsp-types/src/rename.rs create mode 100644 vendor/lsp-types/src/request.rs create mode 100644 vendor/lsp-types/src/selection_range.rs create mode 100644 vendor/lsp-types/src/semantic_tokens.rs create mode 100644 vendor/lsp-types/src/signature_help.rs create mode 100644 vendor/lsp-types/src/trace.rs create mode 100644 vendor/lsp-types/src/type_hierarchy.rs create mode 100644 vendor/lsp-types/src/window.rs create mode 100644 vendor/lsp-types/src/workspace_diagnostic.rs create mode 100644 vendor/lsp-types/src/workspace_folders.rs create mode 100644 vendor/lsp-types/src/workspace_symbols.rs create mode 100644 vendor/lsp-types/tests/lsif.rs create mode 100644 vendor/lsp-types/tests/tsc-unix.lsif create mode 100644 vendor/psp-types/.gitignore create mode 100644 vendor/psp-types/Cargo.toml create mode 100644 vendor/psp-types/README.md create mode 100644 vendor/psp-types/src/lib.rs create mode 100644 vendor/structdesc/.gitignore create mode 100644 vendor/structdesc/.taplo.toml create mode 100644 vendor/structdesc/Cargo.toml create mode 100644 vendor/structdesc/LICENCE create mode 100644 vendor/structdesc/src/lib.rs diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index eaa9bcc0..8c3b6e38 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -22,8 +22,6 @@ env: CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse FLOEM_REPOSITORY: https://github.com/lapce/floem FLOEM_REV: e0dd862564e3afbad5cba8ebe60df166a7a41e56 - LAPCE_SOURCE_REPOSITORY: https://github.com/lapce/lapce - LAPCE_SOURCE_TAG: v0.4.6 jobs: meta: @@ -72,15 +70,6 @@ jobs: git clone "${FLOEM_REPOSITORY}" ../floem git -C ../floem checkout "${FLOEM_REV}" - - name: Prepare vendor dependencies - run: | - rm -rf ../lapce-src - git clone --depth 1 --branch "${LAPCE_SOURCE_TAG}" "${LAPCE_SOURCE_REPOSITORY}" ../lapce-src - mkdir -p ./vendor - cp -R ../lapce-src/vendor/structdesc ./vendor/structdesc - cp -R ../lapce-src/vendor/lsp-types ./vendor/lsp-types - cp -R ../lapce-src/vendor/psp-types ./vendor/psp-types - - name: Update toolchain run: rustup update --no-self-update @@ -122,15 +111,6 @@ jobs: git clone "${env:FLOEM_REPOSITORY}" ../floem git -C ../floem checkout "${env:FLOEM_REV}" - - name: Prepare vendor dependencies - run: | - if (Test-Path ../lapce-src) { Remove-Item -Path ../lapce-src -Recurse -Force } - git clone --depth 1 --branch "${env:LAPCE_SOURCE_TAG}" "${env:LAPCE_SOURCE_REPOSITORY}" ../lapce-src - New-Item -ItemType Directory -Path .\vendor -Force | Out-Null - Copy-Item -Path ..\lapce-src\vendor\structdesc -Destination .\vendor\structdesc -Recurse -Force - Copy-Item -Path ..\lapce-src\vendor\lsp-types -Destination .\vendor\lsp-types -Recurse -Force - Copy-Item -Path ..\lapce-src\vendor\psp-types -Destination .\vendor\psp-types -Recurse -Force - - name: Update toolchain run: rustup update --no-self-update @@ -176,16 +156,6 @@ jobs: git clone "${FLOEM_REPOSITORY}" ../floem git -C ../floem checkout "${FLOEM_REV}" - - name: Prepare vendor dependencies - shell: bash - run: | - rm -rf ../lapce-src - git clone --depth 1 --branch "${LAPCE_SOURCE_TAG}" "${LAPCE_SOURCE_REPOSITORY}" ../lapce-src - mkdir -p ./vendor - cp -R ../lapce-src/vendor/structdesc ./vendor/structdesc - cp -R ../lapce-src/vendor/lsp-types ./vendor/lsp-types - cp -R ../lapce-src/vendor/psp-types ./vendor/psp-types - - name: Update toolchain and install targets run: | rustup update --no-self-update diff --git a/.gitignore b/.gitignore index e7ed190f..9ece8756 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,13 @@ shell.nix lib/ target/ core/languages/ -vendor/ +vendor/* +!vendor/structdesc/ +!vendor/structdesc/** +!vendor/lsp-types/ +!vendor/lsp-types/** +!vendor/psp-types/ +!vendor/psp-types/** .DS_Store *.patch diff --git a/vendor/lsp-types/.clog.toml b/vendor/lsp-types/.clog.toml new file mode 100644 index 00000000..b2116ec9 --- /dev/null +++ b/vendor/lsp-types/.clog.toml @@ -0,0 +1,6 @@ +[clog] +repository = "https://github.com/gluon-lang/lsp-types" + +changelog = "CHANGELOG.md" + +from-latest-tag = true diff --git a/vendor/lsp-types/.github/workflows/rust.yml b/vendor/lsp-types/.github/workflows/rust.yml new file mode 100644 index 00000000..3b5207f7 --- /dev/null +++ b/vendor/lsp-types/.github/workflows/rust.yml @@ -0,0 +1,40 @@ +name: Rust + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +env: + CARGO_TERM_COLOR: always + +jobs: + build: + strategy: + matrix: + rust: [stable, nightly] + features: ["", proposed] + + env: + CARGO_INCREMENTAL: 0 # Incremental compilation is slower and bloats the cache + RUST_BACKTRACE: 1 + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.rust }} + override: true + + - name: Build + run: cargo build + + - name: Run tests + run: > + FEATURES=${{ matrix.features }} + cargo test --features ${FEATURES:-""} diff --git a/vendor/lsp-types/.gitignore b/vendor/lsp-types/.gitignore new file mode 100644 index 00000000..997609a9 --- /dev/null +++ b/vendor/lsp-types/.gitignore @@ -0,0 +1,5 @@ +target +Cargo.lock +/.settings/ +/.project +/.vscode diff --git a/vendor/lsp-types/CHANGELOG.md b/vendor/lsp-types/CHANGELOG.md new file mode 100644 index 00000000..fb15e7a7 --- /dev/null +++ b/vendor/lsp-types/CHANGELOG.md @@ -0,0 +1,319 @@ + +### v0.95.1 (2024-03-18) + + + + + +## v0.95.0 (2023-12-12) + + + + + +### v0.94.2 (2023-12-12) + + + + + +### v0.94.1 (2023-08-07) + + + + + +## v0.94.0 (2023-02-08) + + + + + +### v0.93.2 (2022-10-21) + + + + + +### v0.93.1 (2022-08-23) + + + + + +## v0.93.0 (2022-04-08) + + +#### Features + +* **helperTypes:** implement new JSON types ([bd9bb2e7](https://github.com/gluon-lang/lsp-types/commit/bd9bb2e74171b0194be51085c822c3ccbbb68b7b)) + + + + +### v0.92.1 (2022-03-21) + + +#### Bug Fixes + +* **inlayHint:** typo in prop name ([7f7ada31](https://github.com/gluon-lang/lsp-types/commit/7f7ada310fa045ef628dc36f97b8564408fcec6a)) + +#### Features + +* **inlayHint:** + * add request impls ([393aefa1](https://github.com/gluon-lang/lsp-types/commit/393aefa18b3c900c3f1ac8f6337b7098bdc4365a)) + * add inlayHint provider ([69f21e71](https://github.com/gluon-lang/lsp-types/commit/69f21e714df305643aa727cbf745b439bbd8c112)) + * implement inlayHint basic types ([29a50e71](https://github.com/gluon-lang/lsp-types/commit/29a50e71461f72d2fa2aea90fa03f61adf062074)) + + + + +## v0.92.0 (2022-02-07) + + + + + +### v0.91.2 (2022-02-07) + + +#### Features + +* Add a TryFrom<&str> implementation for enumerations ([19b85cf4](https://github.com/gluon-lang/lsp-types/commit/19b85cf4a7b5396a89d364e271c3867eb6c840e4), closes [#223](https://github.com/gluon-lang/lsp-types/issues/223)) + +#### Bug Fixes + +* Ensure that the pascal_case_name is evaluated at compile time ([7337535b](https://github.com/gluon-lang/lsp-types/commit/7337535b79000912f859319455cd371af77d1899)) + + + + +### v0.91.1 (2021-11-01) + + +#### Features + +* Print the name of know enumerations ([2877b6a1](https://github.com/gluon-lang/lsp-types/commit/2877b6a131ef5c28310b972126f6d1b23cd97788)) + + + + +## v0.91.0 (2021-10-18) + + + + + +### v0.90.1 (2021-10-11) + + +#### Bug Fixes + +* add missing rename_all serde attribute ([b403cba5](https://github.com/gluon-lang/lsp-types/commit/b403cba5fb568f7f1bda3ea2929822269797f7f3)) + + + + +### v0.90.1 (2021-10-11) + + +#### Bug Fixes + +* add missing rename_all serde attribute ([b403cba5](https://github.com/gluon-lang/lsp-types/commit/b403cba5fb568f7f1bda3ea2929822269797f7f3)) + + + + +### v0.90.1 (2021-10-11) + + +#### Bug Fixes + +* add missing rename_all serde attribute ([b403cba5](https://github.com/gluon-lang/lsp-types/commit/b403cba5fb568f7f1bda3ea2929822269797f7f3)) + + + + +### v0.90.1 (2021-10-11) + + +#### Bug Fixes + +* add missing rename_all serde attribute ([b403cba5](https://github.com/gluon-lang/lsp-types/commit/b403cba5fb568f7f1bda3ea2929822269797f7f3)) + + + + +## v0.90.0 (2021-09-25) + + + + + +### v0.61.1 (2021-06-10) + + +#### Features + +* Add DeserializeOwned + Serialize bounds on request/notifications ([fb945a93](https://github.com/gluon-lang/lsp-types/commit/fb945a9347b353dd9bc5aab99a86731bebd94c15), closes [#140](https://github.com/gluon-lang/lsp-types/issues/140)) + + + + +### v0.89.1 (2021-05-22) + + + + + +## v0.89.0 (2021-04-07) + + + + + +## v0.88.0 (2021-02-16) + + + + + +## v0.87.0 (2021-02-14) + + + + + +## v0.86.0 (2020-12-17) + + + + + +## v0.85.0 (2020-12-01) + + + + + +## v0.84.0 (2020-11-24) + + + + + +### v0.83.1 (2020-11-16) + + + + + +## v0.82.0 (2020-09-23) + + + + + +## v0.80.0 (2020-09-18) + + + + + +## v0.80.0 (2020-09-02) + + + + + +## v0.79.0 (2020-07-26) + + + + + +## v0.77.0 (2020-07-15) + + + + + +### v0.76.1 (2020-07-14) + + + + + +### v0.74.2 (2020-05-30) + + + + + +### v0.74.1 (2020-05-01) + + + + + +## v0.74.0 (2020-04-26) + + + + + +## v0.74.0 (2020-04-26) + + + + + +## v0.72.0 (2020-03-02) + + +#### Features + +* Add DeserializeOwned + Serialize bounds on request/notifications ([fb945a93](https://github.com/gluon-lang/lsp-types/commit/fb945a9347b353dd9bc5aab99a86731bebd94c15), closes [#140](https://github.com/gluon-lang/lsp-types/issues/140)) + + + + +## v0.72.0 (2020-03-02) + + +#### Features + +* Add DeserializeOwned + Serialize bounds on request/notifications ([fb945a93](https://github.com/gluon-lang/lsp-types/commit/fb945a9347b353dd9bc5aab99a86731bebd94c15), closes [#140](https://github.com/gluon-lang/lsp-types/issues/140)) + + + + +## v0.72.0 (2020-03-02) + + +#### Features + +* Add DeserializeOwned + Serialize bounds on request/notifications ([fb945a93](https://github.com/gluon-lang/lsp-types/commit/fb945a9347b353dd9bc5aab99a86731bebd94c15), closes [#140](https://github.com/gluon-lang/lsp-types/issues/140)) + + + + +## v0.72.0 (2020-03-02) + + +#### Features + +* Add DeserializeOwned + Serialize bounds on request/notifications ([fb945a93](https://github.com/gluon-lang/lsp-types/commit/fb945a9347b353dd9bc5aab99a86731bebd94c15), closes [#140](https://github.com/gluon-lang/lsp-types/issues/140)) + + + + +## v0.72.0 (2020-03-02) + + +#### Features + +* Add DeserializeOwned + Serialize bounds on request/notifications ([fb945a93](https://github.com/gluon-lang/lsp-types/commit/fb945a9347b353dd9bc5aab99a86731bebd94c15), closes [#140](https://github.com/gluon-lang/lsp-types/issues/140)) + + + diff --git a/vendor/lsp-types/Cargo.toml b/vendor/lsp-types/Cargo.toml new file mode 100644 index 00000000..ad7a3ca0 --- /dev/null +++ b/vendor/lsp-types/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "lsp-types" +version = "0.95.1" +authors = ["Markus Westerlind ", "Bruno Medeiros "] +edition = "2018" +description = "Types for interaction with a language server, using VSCode's Language Server Protocol" + +repository = "https://github.com/gluon-lang/lsp-types" +documentation = "https://docs.rs/lsp-types" + +readme = "README.md" + +keywords = ["language", "server", "lsp", "vscode", "lsif"] + +license = "MIT" + +[dependencies] +bitflags = "1.0.1" +serde = { version = "1.0.34", features = ["derive"] } +serde_json = "1.0.50" +serde_repr = "0.1" +url = {version = "2.0.0", features = ["serde"]} + +[features] +default = [] +# Enables proposed LSP extensions. +# NOTE: No semver compatibility is guaranteed for types enabled by this feature. +proposed = [] diff --git a/vendor/lsp-types/LICENSE b/vendor/lsp-types/LICENSE new file mode 100644 index 00000000..32781d97 --- /dev/null +++ b/vendor/lsp-types/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2016 Markus Westerlind + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/vendor/lsp-types/README.md b/vendor/lsp-types/README.md new file mode 100644 index 00000000..b5641f54 --- /dev/null +++ b/vendor/lsp-types/README.md @@ -0,0 +1,18 @@ +# lsp-types [![Build Status](https://travis-ci.org/gluon-lang/lsp-types.svg?branch=master)](https://travis-ci.org/gluon-lang/lsp-types) [![Documentation](https://docs.rs/lsp-types/badge.svg)](https://docs.rs/crate/lsp-types) + +Types useful for interacting with a [language server](https://code.visualstudio.com/blogs/2016/06/27/common-language-protocol). + +Supports Language Server Protocol (LSP) version 3.16.0. + +Proposed 3.17 features can be activated using the `proposed` feature flag. +- **NOTE** that these are unstable and may change between releases. + +## Contributing + +If you are making a change which adds, removes or modifies the LSP API it is highly appreciated if you link to the spec where this change is described. This gives context to whether the change should be an experimental addition and lets the reviewer double check the changes easily against the spec. + +## Links + +[Stable Protocol reference](https://github.com/microsoft/language-server-protocol/tree/gh-pages/_specifications/lsp/3.17/specification.md) + +[Proposed Protocol reference](https://github.com/microsoft/language-server-protocol/blob/gh-pages/_specifications/lsp/3.18/specification.md) diff --git a/vendor/lsp-types/release.sh b/vendor/lsp-types/release.sh new file mode 100755 index 00000000..68e48445 --- /dev/null +++ b/vendor/lsp-types/release.sh @@ -0,0 +1,15 @@ +#!/bin/sh +set -ex + +LEVEL=$1 +if [ -z "$LEVEL" ]; then + echo "Expected patch, minor or major" + exit 1 +fi + +clog --$LEVEL + +git add CHANGELOG.md +git commit -m "Update changelog" + +cargo release $LEVEL --execute diff --git a/vendor/lsp-types/release.toml b/vendor/lsp-types/release.toml new file mode 100644 index 00000000..06f6dfa8 --- /dev/null +++ b/vendor/lsp-types/release.toml @@ -0,0 +1 @@ +tag-message = "Version {{version}}" diff --git a/vendor/lsp-types/src/call_hierarchy.rs b/vendor/lsp-types/src/call_hierarchy.rs new file mode 100644 index 00000000..dea78803 --- /dev/null +++ b/vendor/lsp-types/src/call_hierarchy.rs @@ -0,0 +1,127 @@ +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use url::Url; + +use crate::{ + DynamicRegistrationClientCapabilities, PartialResultParams, Range, SymbolKind, SymbolTag, + TextDocumentPositionParams, WorkDoneProgressOptions, WorkDoneProgressParams, +}; + +pub type CallHierarchyClientCapabilities = DynamicRegistrationClientCapabilities; + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize, Copy)] +#[serde(rename_all = "camelCase")] +pub struct CallHierarchyOptions { + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize, Copy)] +#[serde(untagged)] +pub enum CallHierarchyServerCapability { + Simple(bool), + Options(CallHierarchyOptions), +} + +impl From for CallHierarchyServerCapability { + fn from(from: CallHierarchyOptions) -> Self { + Self::Options(from) + } +} + +impl From for CallHierarchyServerCapability { + fn from(from: bool) -> Self { + Self::Simple(from) + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CallHierarchyPrepareParams { + #[serde(flatten)] + pub text_document_position_params: TextDocumentPositionParams, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, +} + +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +#[serde(rename_all = "camelCase")] +pub struct CallHierarchyItem { + /// The name of this item. + pub name: String, + + /// The kind of this item. + pub kind: SymbolKind, + + /// Tags for this item. + #[serde(skip_serializing_if = "Option::is_none")] + pub tags: Option>, + + /// More detail for this item, e.g. the signature of a function. + #[serde(skip_serializing_if = "Option::is_none")] + pub detail: Option, + + /// The resource identifier of this item. + pub uri: Url, + + /// The range enclosing this symbol not including leading/trailing whitespace but everything else, e.g. comments and code. + pub range: Range, + + /// The range that should be selected and revealed when this symbol is being picked, e.g. the name of a function. + /// Must be contained by the [`range`](#CallHierarchyItem.range). + pub selection_range: Range, + + /// A data entry field that is preserved between a call hierarchy prepare and incoming calls or outgoing calls requests. + #[serde(skip_serializing_if = "Option::is_none")] + pub data: Option, +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CallHierarchyIncomingCallsParams { + pub item: CallHierarchyItem, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +/// Represents an incoming call, e.g. a caller of a method or constructor. +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +#[serde(rename_all = "camelCase")] +pub struct CallHierarchyIncomingCall { + /// The item that makes the call. + pub from: CallHierarchyItem, + + /// The range at which at which the calls appears. This is relative to the caller + /// denoted by [`this.from`](#CallHierarchyIncomingCall.from). + pub from_ranges: Vec, +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CallHierarchyOutgoingCallsParams { + pub item: CallHierarchyItem, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +/// Represents an outgoing call, e.g. calling a getter from a method or a method from a constructor etc. +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +#[serde(rename_all = "camelCase")] +pub struct CallHierarchyOutgoingCall { + /// The item that is called. + pub to: CallHierarchyItem, + + /// The range at which this item is called. This is the range relative to the caller, e.g the item + /// passed to [`provideCallHierarchyOutgoingCalls`](#CallHierarchyItemProvider.provideCallHierarchyOutgoingCalls) + /// and not [`this.to`](#CallHierarchyOutgoingCall.to). + pub from_ranges: Vec, +} diff --git a/vendor/lsp-types/src/code_action.rs b/vendor/lsp-types/src/code_action.rs new file mode 100644 index 00000000..6cc39e0d --- /dev/null +++ b/vendor/lsp-types/src/code_action.rs @@ -0,0 +1,395 @@ +use crate::{ + Command, Diagnostic, PartialResultParams, Range, TextDocumentIdentifier, + WorkDoneProgressOptions, WorkDoneProgressParams, WorkspaceEdit, +}; +use serde::{Deserialize, Serialize}; + +use serde_json::Value; + +use std::borrow::Cow; +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum CodeActionProviderCapability { + Simple(bool), + Options(CodeActionOptions), +} + +impl From for CodeActionProviderCapability { + fn from(from: CodeActionOptions) -> Self { + Self::Options(from) + } +} + +impl From for CodeActionProviderCapability { + fn from(from: bool) -> Self { + Self::Simple(from) + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CodeActionClientCapabilities { + /// + /// This capability supports dynamic registration. + /// + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, + + /// The client support code action literals as a valid + /// response of the `textDocument/codeAction` request. + #[serde(skip_serializing_if = "Option::is_none")] + pub code_action_literal_support: Option, + + /// Whether code action supports the `isPreferred` property. + /// + /// @since 3.15.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub is_preferred_support: Option, + + /// Whether code action supports the `disabled` property. + /// + /// @since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub disabled_support: Option, + + /// Whether code action supports the `data` property which is + /// preserved between a `textDocument/codeAction` and a + /// `codeAction/resolve` request. + /// + /// @since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub data_support: Option, + + /// Whether the client supports resolving additional code action + /// properties via a separate `codeAction/resolve` request. + /// + /// @since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub resolve_support: Option, + + /// Whether the client honors the change annotations in + /// text edits and resource operations returned via the + /// `CodeAction#edit` property by for example presenting + /// the workspace edit in the user interface and asking + /// for confirmation. + /// + /// @since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub honors_change_annotations: Option, +} + +/// Whether the client supports resolving additional code action +/// properties via a separate `codeAction/resolve` request. +/// +/// @since 3.16.0 +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CodeActionCapabilityResolveSupport { + /// The properties that a client can resolve lazily. + pub properties: Vec, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CodeActionLiteralSupport { + /// The code action kind is support with the following value set. + pub code_action_kind: CodeActionKindLiteralSupport, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CodeActionKindLiteralSupport { + /// The code action kind values the client supports. When this + /// property exists the client also guarantees that it will + /// handle values outside its set gracefully and falls back + /// to a default value when unknown. + pub value_set: Vec, +} + +/// Params for the CodeActionRequest +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CodeActionParams { + /// The document in which the command was invoked. + pub text_document: TextDocumentIdentifier, + + /// The range for which the command was invoked. + pub range: Range, + + /// Context carrying additional information. + pub context: CodeActionContext, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +/// response for CodeActionRequest +pub type CodeActionResponse = Vec; + +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] +#[serde(untagged)] +pub enum CodeActionOrCommand { + Command(Command), + CodeAction(CodeAction), +} + +impl From for CodeActionOrCommand { + fn from(command: Command) -> Self { + CodeActionOrCommand::Command(command) + } +} + +impl From for CodeActionOrCommand { + fn from(action: CodeAction) -> Self { + CodeActionOrCommand::CodeAction(action) + } +} + +#[derive(Debug, Eq, PartialEq, Hash, PartialOrd, Clone, Deserialize, Serialize)] +pub struct CodeActionKind(Cow<'static, str>); + +impl CodeActionKind { + /// Empty kind. + pub const EMPTY: CodeActionKind = CodeActionKind::new(""); + + /// Base kind for quickfix actions: 'quickfix' + pub const QUICKFIX: CodeActionKind = CodeActionKind::new("quickfix"); + + /// Base kind for refactoring actions: 'refactor' + pub const REFACTOR: CodeActionKind = CodeActionKind::new("refactor"); + + /// Base kind for refactoring extraction actions: 'refactor.extract' + /// + /// Example extract actions: + /// + /// - Extract method + /// - Extract function + /// - Extract variable + /// - Extract interface from class + /// - ... + pub const REFACTOR_EXTRACT: CodeActionKind = CodeActionKind::new("refactor.extract"); + + /// Base kind for refactoring inline actions: 'refactor.inline' + /// + /// Example inline actions: + /// + /// - Inline function + /// - Inline variable + /// - Inline constant + /// - ... + pub const REFACTOR_INLINE: CodeActionKind = CodeActionKind::new("refactor.inline"); + + /// Base kind for refactoring rewrite actions: 'refactor.rewrite' + /// + /// Example rewrite actions: + /// + /// - Convert JavaScript function to class + /// - Add or remove parameter + /// - Encapsulate field + /// - Make method static + /// - Move method to base class + /// - ... + pub const REFACTOR_REWRITE: CodeActionKind = CodeActionKind::new("refactor.rewrite"); + + /// Base kind for source actions: `source` + /// + /// Source code actions apply to the entire file. + pub const SOURCE: CodeActionKind = CodeActionKind::new("source"); + + /// Base kind for an organize imports source action: `source.organizeImports` + pub const SOURCE_ORGANIZE_IMPORTS: CodeActionKind = + CodeActionKind::new("source.organizeImports"); + + /// Base kind for a 'fix all' source action: `source.fixAll`. + /// + /// 'Fix all' actions automatically fix errors that have a clear fix that + /// do not require user input. They should not suppress errors or perform + /// unsafe fixes such as generating new types or classes. + /// + /// @since 3.17.0 + pub const SOURCE_FIX_ALL: CodeActionKind = CodeActionKind::new("source.fixAll"); + + pub const fn new(tag: &'static str) -> Self { + CodeActionKind(Cow::Borrowed(tag)) + } + + pub fn as_str(&self) -> &str { + &self.0 + } +} + +impl From for CodeActionKind { + fn from(from: String) -> Self { + CodeActionKind(Cow::from(from)) + } +} + +impl From<&'static str> for CodeActionKind { + fn from(from: &'static str) -> Self { + CodeActionKind::new(from) + } +} + +#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CodeAction { + /// A short, human-readable, title for this code action. + pub title: String, + + /// The kind of the code action. + /// Used to filter code actions. + #[serde(skip_serializing_if = "Option::is_none")] + pub kind: Option, + + /// The diagnostics that this code action resolves. + #[serde(skip_serializing_if = "Option::is_none")] + pub diagnostics: Option>, + + /// The workspace edit this code action performs. + #[serde(skip_serializing_if = "Option::is_none")] + pub edit: Option, + + /// A command this code action executes. If a code action + /// provides an edit and a command, first the edit is + /// executed and then the command. + #[serde(skip_serializing_if = "Option::is_none")] + pub command: Option, + + /// Marks this as a preferred action. Preferred actions are used by the `auto fix` command and can be targeted + /// by keybindings. + /// A quick fix should be marked preferred if it properly addresses the underlying error. + /// A refactoring should be marked preferred if it is the most reasonable choice of actions to take. + /// + /// @since 3.15.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub is_preferred: Option, + + /// Marks that the code action cannot currently be applied. + /// + /// Clients should follow the following guidelines regarding disabled code actions: + /// + /// - Disabled code actions are not shown in automatic + /// [lightbulb](https://code.visualstudio.com/docs/editor/editingevolved#_code-action) + /// code action menu. + /// + /// - Disabled actions are shown as faded out in the code action menu when the user request + /// a more specific type of code action, such as refactorings. + /// + /// - If the user has a keybinding that auto applies a code action and only a disabled code + /// actions are returned, the client should show the user an error message with `reason` + /// in the editor. + /// + /// @since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub disabled: Option, + + /// A data entry field that is preserved on a code action between + /// a `textDocument/codeAction` and a `codeAction/resolve` request. + /// + /// @since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub data: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CodeActionDisabled { + /// Human readable description of why the code action is currently disabled. + /// + /// This is displayed in the code actions UI. + pub reason: String, +} + +/// The reason why code actions were requested. +/// +/// @since 3.17.0 +#[derive(Eq, PartialEq, Clone, Copy, Deserialize, Serialize)] +#[serde(transparent)] +pub struct CodeActionTriggerKind(i32); +lsp_enum! { +impl CodeActionTriggerKind { + /// Code actions were explicitly requested by the user or by an extension. + pub const INVOKED: CodeActionTriggerKind = CodeActionTriggerKind(1); + + /// Code actions were requested automatically. + /// + /// This typically happens when current selection in a file changes, but can + /// also be triggered when file content changes. + pub const AUTOMATIC: CodeActionTriggerKind = CodeActionTriggerKind(2); +} +} + +/// Contains additional diagnostic information about the context in which +/// a code action is run. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CodeActionContext { + /// An array of diagnostics. + pub diagnostics: Vec, + + /// Requested kind of actions to return. + /// + /// Actions not of this kind are filtered out by the client before being shown. So servers + /// can omit computing them. + #[serde(skip_serializing_if = "Option::is_none")] + pub only: Option>, + + /// The reason why code actions were requested. + /// + /// @since 3.17.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub trigger_kind: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize, Default)] +#[serde(rename_all = "camelCase")] +pub struct CodeActionOptions { + /// CodeActionKinds that this server may return. + /// + /// The list of kinds may be generic, such as `CodeActionKind.Refactor`, or the server + /// may list out every specific kind they provide. + #[serde(skip_serializing_if = "Option::is_none")] + pub code_action_kinds: Option>, + + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, + + /// The server provides support to resolve additional + /// information for a code action. + /// + /// @since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub resolve_provider: Option, +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::tests::test_serialization; + + #[test] + fn test_code_action_response() { + test_serialization( + &vec![ + CodeActionOrCommand::Command(Command { + title: "title".to_string(), + command: "command".to_string(), + arguments: None, + }), + CodeActionOrCommand::CodeAction(CodeAction { + title: "title".to_string(), + kind: Some(CodeActionKind::QUICKFIX), + command: None, + diagnostics: None, + edit: None, + is_preferred: None, + ..CodeAction::default() + }), + ], + r#"[{"title":"title","command":"command"},{"title":"title","kind":"quickfix"}]"#, + ) + } +} diff --git a/vendor/lsp-types/src/code_lens.rs b/vendor/lsp-types/src/code_lens.rs new file mode 100644 index 00000000..c4c9c904 --- /dev/null +++ b/vendor/lsp-types/src/code_lens.rs @@ -0,0 +1,66 @@ +use serde::{Deserialize, Serialize}; +use serde_json::Value; + +use crate::{ + Command, DynamicRegistrationClientCapabilities, PartialResultParams, Range, + TextDocumentIdentifier, WorkDoneProgressParams, +}; + +pub type CodeLensClientCapabilities = DynamicRegistrationClientCapabilities; + +/// Code Lens options. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize, Copy)] +#[serde(rename_all = "camelCase")] +pub struct CodeLensOptions { + /// Code lens has a resolve provider as well. + #[serde(skip_serializing_if = "Option::is_none")] + pub resolve_provider: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CodeLensParams { + /// The document to request code lens for. + pub text_document: TextDocumentIdentifier, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +/// A code lens represents a command that should be shown along with +/// source text, like the number of references, a way to run tests, etc. +/// +/// A code lens is _unresolved_ when no command is associated to it. For performance +/// reasons the creation of a code lens and resolving should be done in two stages. +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CodeLens { + /// The range in which this code lens is valid. Should only span a single line. + pub range: Range, + + /// The command this code lens represents. + #[serde(skip_serializing_if = "Option::is_none")] + pub command: Option, + + /// A data entry field that is preserved on a code lens item between + /// a code lens and a code lens resolve request. + #[serde(skip_serializing_if = "Option::is_none")] + pub data: Option, +} + +#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CodeLensWorkspaceClientCapabilities { + /// Whether the client implementation supports a refresh request sent from the + /// server to the client. + /// + /// Note that this event is global and will force the client to refresh all + /// code lenses currently shown. It should be used with absolute care and is + /// useful for situation where a server for example detect a project wide + /// change that requires such a calculation. + #[serde(skip_serializing_if = "Option::is_none")] + pub refresh_support: Option, +} diff --git a/vendor/lsp-types/src/color.rs b/vendor/lsp-types/src/color.rs new file mode 100644 index 00000000..584f979e --- /dev/null +++ b/vendor/lsp-types/src/color.rs @@ -0,0 +1,122 @@ +use crate::{ + DocumentSelector, DynamicRegistrationClientCapabilities, PartialResultParams, Range, + TextDocumentIdentifier, TextEdit, WorkDoneProgressParams, +}; +use serde::{Deserialize, Serialize}; + +pub type DocumentColorClientCapabilities = DynamicRegistrationClientCapabilities; + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ColorProviderOptions {} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct StaticTextDocumentColorProviderOptions { + /// A document selector to identify the scope of the registration. If set to null + /// the document selector provided on the client side will be used. + pub document_selector: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub id: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum ColorProviderCapability { + Simple(bool), + ColorProvider(ColorProviderOptions), + Options(StaticTextDocumentColorProviderOptions), +} + +impl From for ColorProviderCapability { + fn from(from: ColorProviderOptions) -> Self { + Self::ColorProvider(from) + } +} + +impl From for ColorProviderCapability { + fn from(from: StaticTextDocumentColorProviderOptions) -> Self { + Self::Options(from) + } +} + +impl From for ColorProviderCapability { + fn from(from: bool) -> Self { + Self::Simple(from) + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentColorParams { + /// The text document + pub text_document: TextDocumentIdentifier, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ColorInformation { + /// The range in the document where this color appears. + pub range: Range, + /// The actual color value for this color range. + pub color: Color, +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize, Copy)] +#[serde(rename_all = "camelCase")] +pub struct Color { + /// The red component of this color in the range [0-1]. + pub red: f32, + /// The green component of this color in the range [0-1]. + pub green: f32, + /// The blue component of this color in the range [0-1]. + pub blue: f32, + /// The alpha component of this color in the range [0-1]. + pub alpha: f32, +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ColorPresentationParams { + /// The text document. + pub text_document: TextDocumentIdentifier, + + /// The color information to request presentations for. + pub color: Color, + + /// The range where the color would be inserted. Serves as a context. + pub range: Range, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +#[derive(Debug, PartialEq, Eq, Deserialize, Serialize, Default, Clone)] +#[serde(rename_all = "camelCase")] +pub struct ColorPresentation { + /// The label of this color presentation. It will be shown on the color + /// picker header. By default this is also the text that is inserted when selecting + /// this color presentation. + pub label: String, + + /// An [edit](#TextEdit) which is applied to a document when selecting + /// this presentation for the color. When `falsy` the [label](#ColorPresentation.label) + /// is used. + #[serde(skip_serializing_if = "Option::is_none")] + pub text_edit: Option, + + /// An optional array of additional [text edits](#TextEdit) that are applied when + /// selecting this color presentation. Edits must not overlap with the main [edit](#ColorPresentation.textEdit) nor with themselves. + #[serde(skip_serializing_if = "Option::is_none")] + pub additional_text_edits: Option>, +} diff --git a/vendor/lsp-types/src/completion.rs b/vendor/lsp-types/src/completion.rs new file mode 100644 index 00000000..bdf60fb5 --- /dev/null +++ b/vendor/lsp-types/src/completion.rs @@ -0,0 +1,616 @@ +use serde::{Deserialize, Serialize}; + +use crate::{ + Command, Documentation, MarkupKind, PartialResultParams, TagSupport, + TextDocumentPositionParams, TextDocumentRegistrationOptions, TextEdit, WorkDoneProgressOptions, + WorkDoneProgressParams, +}; + +use crate::Range; +use serde_json::Value; +use std::fmt::Debug; + +/// Defines how to interpret the insert text in a completion item +#[derive(Eq, PartialEq, Clone, Copy, Serialize, Deserialize)] +#[serde(transparent)] +pub struct InsertTextFormat(i32); +lsp_enum! { +impl InsertTextFormat { + pub const PLAIN_TEXT: InsertTextFormat = InsertTextFormat(1); + pub const SNIPPET: InsertTextFormat = InsertTextFormat(2); +} +} + +/// The kind of a completion entry. +#[derive(Eq, PartialEq, Clone, Copy, Serialize, Deserialize)] +#[serde(transparent)] +pub struct CompletionItemKind(i32); +lsp_enum! { +impl CompletionItemKind { + pub const TEXT: CompletionItemKind = CompletionItemKind(1); + pub const METHOD: CompletionItemKind = CompletionItemKind(2); + pub const FUNCTION: CompletionItemKind = CompletionItemKind(3); + pub const CONSTRUCTOR: CompletionItemKind = CompletionItemKind(4); + pub const FIELD: CompletionItemKind = CompletionItemKind(5); + pub const VARIABLE: CompletionItemKind = CompletionItemKind(6); + pub const CLASS: CompletionItemKind = CompletionItemKind(7); + pub const INTERFACE: CompletionItemKind = CompletionItemKind(8); + pub const MODULE: CompletionItemKind = CompletionItemKind(9); + pub const PROPERTY: CompletionItemKind = CompletionItemKind(10); + pub const UNIT: CompletionItemKind = CompletionItemKind(11); + pub const VALUE: CompletionItemKind = CompletionItemKind(12); + pub const ENUM: CompletionItemKind = CompletionItemKind(13); + pub const KEYWORD: CompletionItemKind = CompletionItemKind(14); + pub const SNIPPET: CompletionItemKind = CompletionItemKind(15); + pub const COLOR: CompletionItemKind = CompletionItemKind(16); + pub const FILE: CompletionItemKind = CompletionItemKind(17); + pub const REFERENCE: CompletionItemKind = CompletionItemKind(18); + pub const FOLDER: CompletionItemKind = CompletionItemKind(19); + pub const ENUM_MEMBER: CompletionItemKind = CompletionItemKind(20); + pub const CONSTANT: CompletionItemKind = CompletionItemKind(21); + pub const STRUCT: CompletionItemKind = CompletionItemKind(22); + pub const EVENT: CompletionItemKind = CompletionItemKind(23); + pub const OPERATOR: CompletionItemKind = CompletionItemKind(24); + pub const TYPE_PARAMETER: CompletionItemKind = CompletionItemKind(25); +} +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CompletionItemCapability { + /// Client supports snippets as insert text. + /// + /// A snippet can define tab stops and placeholders with `$1`, `$2` + /// and `${3:foo}`. `$0` defines the final tab stop, it defaults to + /// the end of the snippet. Placeholders with equal identifiers are linked, + /// that is typing in one will update others too. + #[serde(skip_serializing_if = "Option::is_none")] + pub snippet_support: Option, + + /// Client supports commit characters on a completion item. + #[serde(skip_serializing_if = "Option::is_none")] + pub commit_characters_support: Option, + + /// Client supports the follow content formats for the documentation + /// property. The order describes the preferred format of the client. + #[serde(skip_serializing_if = "Option::is_none")] + pub documentation_format: Option>, + + /// Client supports the deprecated property on a completion item. + #[serde(skip_serializing_if = "Option::is_none")] + pub deprecated_support: Option, + + /// Client supports the preselect property on a completion item. + #[serde(skip_serializing_if = "Option::is_none")] + pub preselect_support: Option, + + /// Client supports the tag property on a completion item. Clients supporting + /// tags have to handle unknown tags gracefully. Clients especially need to + /// preserve unknown tags when sending a completion item back to the server in + /// a resolve call. + #[serde( + default, + skip_serializing_if = "Option::is_none", + deserialize_with = "TagSupport::deserialize_compat" + )] + pub tag_support: Option>, + + /// Client support insert replace edit to control different behavior if a + /// completion item is inserted in the text or should replace text. + /// + /// @since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub insert_replace_support: Option, + + /// Indicates which properties a client can resolve lazily on a completion + /// item. Before version 3.16.0 only the predefined properties `documentation` + /// and `details` could be resolved lazily. + /// + /// @since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub resolve_support: Option, + + /// The client supports the `insertTextMode` property on + /// a completion item to override the whitespace handling mode + /// as defined by the client. + /// + /// @since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub insert_text_mode_support: Option, + + /// The client has support for completion item label + /// details (see also `CompletionItemLabelDetails`). + /// + /// @since 3.17.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub label_details_support: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CompletionItemCapabilityResolveSupport { + /// The properties that a client can resolve lazily. + pub properties: Vec, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct InsertTextModeSupport { + pub value_set: Vec, +} + +/// How whitespace and indentation is handled during completion +/// item insertion. +/// +/// @since 3.16.0 +#[derive(Eq, PartialEq, Clone, Copy, Serialize, Deserialize)] +#[serde(transparent)] +pub struct InsertTextMode(i32); +lsp_enum! { +impl InsertTextMode { + /// The insertion or replace strings is taken as it is. If the + /// value is multi line the lines below the cursor will be + /// inserted using the indentation defined in the string value. + /// The client will not apply any kind of adjustments to the + /// string. + pub const AS_IS: InsertTextMode = InsertTextMode(1); + + /// The editor adjusts leading whitespace of new lines so that + /// they match the indentation up to the cursor of the line for + /// which the item is accepted. + /// + /// Consider a line like this: <2tabs><3tabs>foo. Accepting a + /// multi line completion item is indented using 2 tabs all + /// following lines inserted will be indented using 2 tabs as well. + pub const ADJUST_INDENTATION: InsertTextMode = InsertTextMode(2); +} +} + +#[derive(Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(transparent)] +pub struct CompletionItemTag(i32); +lsp_enum! { +impl CompletionItemTag { + pub const DEPRECATED: CompletionItemTag = CompletionItemTag(1); +} +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CompletionItemKindCapability { + /// The completion item kind values the client supports. When this + /// property exists the client also guarantees that it will + /// handle values outside its set gracefully and falls back + /// to a default value when unknown. + /// + /// If this property is not present the client only supports + /// the completion items kinds from `Text` to `Reference` as defined in + /// the initial version of the protocol. + #[serde(skip_serializing_if = "Option::is_none")] + pub value_set: Option>, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CompletionListCapability { + /// The client supports the following itemDefaults on + /// a completion list. + /// + /// The value lists the supported property names of the + /// `CompletionList.itemDefaults` object. If omitted + /// no properties are supported. + /// + /// @since 3.17.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub item_defaults: Option>, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CompletionClientCapabilities { + /// Whether completion supports dynamic registration. + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, + + /// The client supports the following `CompletionItem` specific + /// capabilities. + #[serde(skip_serializing_if = "Option::is_none")] + pub completion_item: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub completion_item_kind: Option, + + /// The client supports to send additional context information for a + /// `textDocument/completion` request. + #[serde(skip_serializing_if = "Option::is_none")] + pub context_support: Option, + + /// The client's default when the completion item doesn't provide a + /// `insertTextMode` property. + /// + /// @since 3.17.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub insert_text_mode: Option, + + /// The client supports the following `CompletionList` specific + /// capabilities. + /// + /// @since 3.17.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub completion_list: Option, +} + +/// A special text edit to provide an insert and a replace operation. +/// +/// @since 3.16.0 +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct InsertReplaceEdit { + /// The string to be inserted. + pub new_text: String, + + /// The range if the insert is requested + pub insert: Range, + + /// The range if the replace is requested. + pub replace: Range, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum CompletionTextEdit { + Edit(TextEdit), + InsertAndReplace(InsertReplaceEdit), +} + +impl From for CompletionTextEdit { + fn from(edit: TextEdit) -> Self { + CompletionTextEdit::Edit(edit) + } +} + +impl From for CompletionTextEdit { + fn from(edit: InsertReplaceEdit) -> Self { + CompletionTextEdit::InsertAndReplace(edit) + } +} + +/// Completion options. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CompletionOptions { + /// The server provides support to resolve additional information for a completion item. + #[serde(skip_serializing_if = "Option::is_none")] + pub resolve_provider: Option, + + /// Most tools trigger completion request automatically without explicitly + /// requesting it using a keyboard shortcut (e.g. Ctrl+Space). Typically they + /// do so when the user starts to type an identifier. For example if the user + /// types `c` in a JavaScript file code complete will automatically pop up + /// present `console` besides others as a completion item. Characters that + /// make up identifiers don't need to be listed here. + /// + /// If code complete should automatically be trigger on characters not being + /// valid inside an identifier (for example `.` in JavaScript) list them in + /// `triggerCharacters`. + #[serde(skip_serializing_if = "Option::is_none")] + pub trigger_characters: Option>, + + /// The list of all possible characters that commit a completion. This field + /// can be used if clients don't support individual commit characters per + /// completion item. See client capability + /// `completion.completionItem.commitCharactersSupport`. + /// + /// If a server provides both `allCommitCharacters` and commit characters on + /// an individual completion item the ones on the completion item win. + /// + /// @since 3.2.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub all_commit_characters: Option>, + + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, + + /// The server supports the following `CompletionItem` specific + /// capabilities. + /// + /// @since 3.17.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub completion_item: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CompletionOptionsCompletionItem { + /// The server has support for completion item label + /// details (see also `CompletionItemLabelDetails`) when receiving + /// a completion item in a resolve call. + /// + /// @since 3.17.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub label_details_support: Option, +} + +#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] +pub struct CompletionRegistrationOptions { + #[serde(flatten)] + pub text_document_registration_options: TextDocumentRegistrationOptions, + + #[serde(flatten)] + pub completion_options: CompletionOptions, +} + +#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum CompletionResponse { + Array(Vec), + List(CompletionList), +} + +impl From> for CompletionResponse { + fn from(items: Vec) -> Self { + CompletionResponse::Array(items) + } +} + +impl From for CompletionResponse { + fn from(list: CompletionList) -> Self { + CompletionResponse::List(list) + } +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CompletionParams { + // This field was "mixed-in" from TextDocumentPositionParams + #[serde(flatten)] + pub text_document_position: TextDocumentPositionParams, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, + + // CompletionParams properties: + #[serde(skip_serializing_if = "Option::is_none")] + pub context: Option, +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CompletionContext { + /// How the completion was triggered. + pub trigger_kind: CompletionTriggerKind, + + /// The trigger character (a single character) that has trigger code complete. + /// Is undefined if `triggerKind !== CompletionTriggerKind.TriggerCharacter` + #[serde(skip_serializing_if = "Option::is_none")] + pub trigger_character: Option, +} + +/// How a completion was triggered. +#[derive(Eq, PartialEq, Clone, Copy, Deserialize, Serialize)] +#[serde(transparent)] +pub struct CompletionTriggerKind(i32); +lsp_enum! { +impl CompletionTriggerKind { + pub const INVOKED: CompletionTriggerKind = CompletionTriggerKind(1); + pub const TRIGGER_CHARACTER: CompletionTriggerKind = CompletionTriggerKind(2); + pub const TRIGGER_FOR_INCOMPLETE_COMPLETIONS: CompletionTriggerKind = CompletionTriggerKind(3); +} +} + +/// Represents a collection of [completion items](#CompletionItem) to be presented +/// in the editor. +#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CompletionList { + /// This list it not complete. Further typing should result in recomputing + /// this list. + pub is_incomplete: bool, + + /// The completion items. + pub items: Vec, +} + +#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct CompletionItem { + /// The label of this completion item. By default + /// also the text that is inserted when selecting + /// this completion. + pub label: String, + + /// Additional details for the label + /// + /// @since 3.17.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub label_details: Option, + + /// The kind of this completion item. Based of the kind + /// an icon is chosen by the editor. + #[serde(skip_serializing_if = "Option::is_none")] + pub kind: Option, + + /// A human-readable string with additional information + /// about this item, like type or symbol information. + #[serde(skip_serializing_if = "Option::is_none")] + pub detail: Option, + + /// A human-readable string that represents a doc-comment. + #[serde(skip_serializing_if = "Option::is_none")] + pub documentation: Option, + + /// Indicates if this item is deprecated. + #[serde(skip_serializing_if = "Option::is_none")] + pub deprecated: Option, + + /// Select this item when showing. + #[serde(skip_serializing_if = "Option::is_none")] + pub preselect: Option, + + /// A string that should be used when comparing this item + /// with other items. When `falsy` the label is used + /// as the sort text for this item. + #[serde(skip_serializing_if = "Option::is_none")] + pub sort_text: Option, + + /// A string that should be used when filtering a set of + /// completion items. When `falsy` the label is used as the + /// filter text for this item. + #[serde(skip_serializing_if = "Option::is_none")] + pub filter_text: Option, + + /// A string that should be inserted into a document when selecting + /// this completion. When `falsy` the label is used as the insert text + /// for this item. + /// + /// The `insertText` is subject to interpretation by the client side. + /// Some tools might not take the string literally. For example + /// VS Code when code complete is requested in this example + /// `con` and a completion item with an `insertText` of + /// `console` is provided it will only insert `sole`. Therefore it is + /// recommended to use `textEdit` instead since it avoids additional client + /// side interpretation. + #[serde(skip_serializing_if = "Option::is_none")] + pub insert_text: Option, + + /// The format of the insert text. The format applies to both the `insertText` property + /// and the `newText` property of a provided `textEdit`. If omitted defaults to `InsertTextFormat.PlainText`. + /// + /// @since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub insert_text_format: Option, + + /// How whitespace and indentation is handled during completion + /// item insertion. If not provided the client's default value depends on + /// the `textDocument.completion.insertTextMode` client capability. + /// + /// @since 3.16.0 + /// @since 3.17.0 - support for `textDocument.completion.insertTextMode` + #[serde(skip_serializing_if = "Option::is_none")] + pub insert_text_mode: Option, + + /// An edit which is applied to a document when selecting + /// this completion. When an edit is provided the value of + /// insertText is ignored. + /// + /// Most editors support two different operation when accepting a completion item. One is to insert a + + /// completion text and the other is to replace an existing text with a completion text. Since this can + /// usually not predetermined by a server it can report both ranges. Clients need to signal support for + /// `InsertReplaceEdits` via the `textDocument.completion.insertReplaceSupport` client capability + /// property. + /// + /// *Note 1:* The text edit's range as well as both ranges from a insert replace edit must be a + /// [single line] and they must contain the position at which completion has been requested. + /// *Note 2:* If an `InsertReplaceEdit` is returned the edit's insert range must be a prefix of + /// the edit's replace range, that means it must be contained and starting at the same position. + /// + /// @since 3.16.0 additional type `InsertReplaceEdit` + #[serde(skip_serializing_if = "Option::is_none")] + pub text_edit: Option, + + /// An optional array of additional text edits that are applied when + /// selecting this completion. Edits must not overlap with the main edit + /// nor with themselves. + #[serde(skip_serializing_if = "Option::is_none")] + pub additional_text_edits: Option>, + + /// An optional command that is executed *after* inserting this completion. *Note* that + /// additional modifications to the current document should be described with the + /// additionalTextEdits-property. + #[serde(skip_serializing_if = "Option::is_none")] + pub command: Option, + + /// An optional set of characters that when pressed while this completion is + /// active will accept it first and then type that character. *Note* that all + /// commit characters should have `length=1` and that superfluous characters + /// will be ignored. + #[serde(skip_serializing_if = "Option::is_none")] + pub commit_characters: Option>, + + /// An data entry field that is preserved on a completion item between + /// a completion and a completion resolve request. + #[serde(skip_serializing_if = "Option::is_none")] + pub data: Option, + + /// Tags for this completion item. + #[serde(skip_serializing_if = "Option::is_none")] + pub tags: Option>, +} + +impl CompletionItem { + /// Create a CompletionItem with the minimum possible info (label and detail). + pub fn new_simple(label: String, detail: String) -> CompletionItem { + CompletionItem { + label, + detail: Some(detail), + ..Self::default() + } + } +} + +/// Additional details for a completion item label. +/// +/// @since 3.17.0 +#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct CompletionItemLabelDetails { + /// An optional string which is rendered less prominently directly after + /// {@link CompletionItemLabel.label label}, without any spacing. Should be + /// used for function signatures or type annotations. + #[serde(skip_serializing_if = "Option::is_none")] + pub detail: Option, + + /// An optional string which is rendered less prominently after + /// {@link CompletionItemLabel.detail}. Should be used for fully qualified + /// names or file path. + #[serde(skip_serializing_if = "Option::is_none")] + pub description: Option, +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::tests::test_deserialization; + + #[test] + fn test_tag_support_deserialization() { + let mut empty = CompletionItemCapability::default(); + empty.tag_support = None; + + test_deserialization(r#"{}"#, &empty); + test_deserialization(r#"{"tagSupport": false}"#, &empty); + + let mut t = CompletionItemCapability::default(); + t.tag_support = Some(TagSupport { value_set: vec![] }); + test_deserialization(r#"{"tagSupport": true}"#, &t); + + let mut t = CompletionItemCapability::default(); + t.tag_support = Some(TagSupport { + value_set: vec![CompletionItemTag::DEPRECATED], + }); + test_deserialization(r#"{"tagSupport": {"valueSet": [1]}}"#, &t); + } + + #[test] + fn test_debug_enum() { + assert_eq!(format!("{:?}", CompletionItemKind::TEXT), "Text"); + assert_eq!( + format!("{:?}", CompletionItemKind::TYPE_PARAMETER), + "TypeParameter" + ); + } + + #[test] + fn test_try_from_enum() { + use std::convert::TryInto; + assert_eq!("Text".try_into(), Ok(CompletionItemKind::TEXT)); + assert_eq!( + "TypeParameter".try_into(), + Ok(CompletionItemKind::TYPE_PARAMETER) + ); + } +} diff --git a/vendor/lsp-types/src/document_diagnostic.rs b/vendor/lsp-types/src/document_diagnostic.rs new file mode 100644 index 00000000..a2b5c41f --- /dev/null +++ b/vendor/lsp-types/src/document_diagnostic.rs @@ -0,0 +1,269 @@ +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; +use url::Url; + +use crate::{ + Diagnostic, PartialResultParams, StaticRegistrationOptions, TextDocumentIdentifier, + TextDocumentRegistrationOptions, WorkDoneProgressOptions, WorkDoneProgressParams, +}; + +/// Client capabilities specific to diagnostic pull requests. +/// +/// @since 3.17.0 +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DiagnosticClientCapabilities { + /// Whether implementation supports dynamic registration. + /// + /// If this is set to `true` the client supports the new `(TextDocumentRegistrationOptions & + /// StaticRegistrationOptions)` return value for the corresponding server capability as well. + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, + + /// Whether the clients supports related documents for document diagnostic pulls. + #[serde(skip_serializing_if = "Option::is_none")] + pub related_document_support: Option, +} + +/// Diagnostic options. +/// +/// @since 3.17.0 +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DiagnosticOptions { + /// An optional identifier under which the diagnostics are + /// managed by the client. + #[serde(skip_serializing_if = "Option::is_none")] + pub identifier: Option, + + /// Whether the language has inter file dependencies, meaning that editing code in one file can + /// result in a different diagnostic set in another file. Inter file dependencies are common + /// for most programming languages and typically uncommon for linters. + pub inter_file_dependencies: bool, + + /// The server provides support for workspace diagnostics as well. + pub workspace_diagnostics: bool, + + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, +} + +/// Diagnostic registration options. +/// +/// @since 3.17.0 +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DiagnosticRegistrationOptions { + #[serde(flatten)] + pub text_document_registration_options: TextDocumentRegistrationOptions, + + #[serde(flatten)] + pub diagnostic_options: DiagnosticOptions, + + #[serde(flatten)] + pub static_registration_options: StaticRegistrationOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum DiagnosticServerCapabilities { + Options(DiagnosticOptions), + RegistrationOptions(DiagnosticRegistrationOptions), +} + +/// Parameters of the document diagnostic request. +/// +/// @since 3.17.0 +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentDiagnosticParams { + /// The text document. + pub text_document: TextDocumentIdentifier, + + /// The additional identifier provided during registration. + pub identifier: Option, + + /// The result ID of a previous response if provided. + pub previous_result_id: Option, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +/// A diagnostic report with a full set of problems. +/// +/// @since 3.17.0 +#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct FullDocumentDiagnosticReport { + /// An optional result ID. If provided it will be sent on the next diagnostic request for the + /// same document. + #[serde(skip_serializing_if = "Option::is_none")] + pub result_id: Option, + + /// The actual items. + pub items: Vec, +} + +/// A diagnostic report indicating that the last returned report is still accurate. +/// +/// A server can only return `unchanged` if result ids are provided. +/// +/// @since 3.17.0 +#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct UnchangedDocumentDiagnosticReport { + /// A result ID which will be sent on the next diagnostic request for the same document. + pub result_id: String, +} + +/// The document diagnostic report kinds. +/// +/// @since 3.17.0 +#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] +#[serde(tag = "kind", rename_all = "lowercase")] +pub enum DocumentDiagnosticReportKind { + /// A diagnostic report with a full set of problems. + Full(FullDocumentDiagnosticReport), + /// A report indicating that the last returned report is still accurate. + Unchanged(UnchangedDocumentDiagnosticReport), +} + +impl From for DocumentDiagnosticReportKind { + fn from(from: FullDocumentDiagnosticReport) -> Self { + DocumentDiagnosticReportKind::Full(from) + } +} + +impl From for DocumentDiagnosticReportKind { + fn from(from: UnchangedDocumentDiagnosticReport) -> Self { + DocumentDiagnosticReportKind::Unchanged(from) + } +} + +/// A full diagnostic report with a set of related documents. +/// +/// @since 3.17.0 +#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct RelatedFullDocumentDiagnosticReport { + /// Diagnostics of related documents. + /// + /// This information is useful in programming languages where code in a file A can generate + /// diagnostics in a file B which A depends on. An example of such a language is C/C++ where + /// macro definitions in a file `a.cpp` result in errors in a header file `b.hpp`. + /// + /// @since 3.17.0 + #[serde(with = "crate::url_map")] + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(default)] + pub related_documents: Option>, + // relatedDocuments?: { [uri: string]: FullDocumentDiagnosticReport | UnchangedDocumentDiagnosticReport; }; + #[serde(flatten)] + pub full_document_diagnostic_report: FullDocumentDiagnosticReport, +} + +/// An unchanged diagnostic report with a set of related documents. +/// +/// @since 3.17.0 +#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct RelatedUnchangedDocumentDiagnosticReport { + /// Diagnostics of related documents. + /// + /// This information is useful in programming languages where code in a file A can generate + /// diagnostics in a file B which A depends on. An example of such a language is C/C++ where + /// macro definitions in a file `a.cpp` result in errors in a header file `b.hpp`. + /// + /// @since 3.17.0 + #[serde(with = "crate::url_map")] + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(default)] + pub related_documents: Option>, + // relatedDocuments?: { [uri: string]: FullDocumentDiagnosticReport | UnchangedDocumentDiagnosticReport; }; + #[serde(flatten)] + pub unchanged_document_diagnostic_report: UnchangedDocumentDiagnosticReport, +} + +/// The result of a document diagnostic pull request. +/// +/// A report can either be a full report containing all diagnostics for the requested document or +/// an unchanged report indicating that nothing has changed in terms of diagnostics in comparison +/// to the last pull request. +/// +/// @since 3.17.0 +#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] +#[serde(tag = "kind", rename_all = "lowercase")] +pub enum DocumentDiagnosticReport { + /// A diagnostic report with a full set of problems. + Full(RelatedFullDocumentDiagnosticReport), + /// A report indicating that the last returned report is still accurate. + Unchanged(RelatedUnchangedDocumentDiagnosticReport), +} + +impl From for DocumentDiagnosticReport { + fn from(from: RelatedFullDocumentDiagnosticReport) -> Self { + DocumentDiagnosticReport::Full(from) + } +} + +impl From for DocumentDiagnosticReport { + fn from(from: RelatedUnchangedDocumentDiagnosticReport) -> Self { + DocumentDiagnosticReport::Unchanged(from) + } +} + +/// A partial result for a document diagnostic report. +/// +/// @since 3.17.0 +#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct DocumentDiagnosticReportPartialResult { + #[serde(with = "crate::url_map")] + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(default)] + pub related_documents: Option>, + // relatedDocuments?: { [uri: string]: FullDocumentDiagnosticReport | UnchangedDocumentDiagnosticReport; }; +} + +#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] +#[serde(untagged)] +pub enum DocumentDiagnosticReportResult { + Report(DocumentDiagnosticReport), + Partial(DocumentDiagnosticReportPartialResult), +} + +impl From for DocumentDiagnosticReportResult { + fn from(from: DocumentDiagnosticReport) -> Self { + DocumentDiagnosticReportResult::Report(from) + } +} + +impl From for DocumentDiagnosticReportResult { + fn from(from: DocumentDiagnosticReportPartialResult) -> Self { + DocumentDiagnosticReportResult::Partial(from) + } +} + +/// Cancellation data returned from a diagnostic request. +/// +/// If no data is provided, it defaults to `{ retrigger_request: true }`. +/// +/// @since 3.17.0 +#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct DiagnosticServerCancellationData { + pub retrigger_request: bool, +} + +impl Default for DiagnosticServerCancellationData { + fn default() -> Self { + DiagnosticServerCancellationData { + retrigger_request: true, + } + } +} diff --git a/vendor/lsp-types/src/document_highlight.rs b/vendor/lsp-types/src/document_highlight.rs new file mode 100644 index 00000000..f2954e6d --- /dev/null +++ b/vendor/lsp-types/src/document_highlight.rs @@ -0,0 +1,51 @@ +use serde::{Deserialize, Serialize}; + +use crate::{ + DynamicRegistrationClientCapabilities, PartialResultParams, Range, TextDocumentPositionParams, + WorkDoneProgressParams, +}; + +pub type DocumentHighlightClientCapabilities = DynamicRegistrationClientCapabilities; + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentHighlightParams { + #[serde(flatten)] + pub text_document_position_params: TextDocumentPositionParams, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +/// A document highlight is a range inside a text document which deserves +/// special attention. Usually a document highlight is visualized by changing +/// the background color of its range. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct DocumentHighlight { + /// The range this highlight applies to. + pub range: Range, + + /// The highlight kind, default is DocumentHighlightKind.Text. + #[serde(skip_serializing_if = "Option::is_none")] + pub kind: Option, +} + +/// A document highlight kind. +#[derive(Eq, PartialEq, Copy, Clone, Deserialize, Serialize)] +#[serde(transparent)] +pub struct DocumentHighlightKind(i32); +lsp_enum! { +impl DocumentHighlightKind { + /// A textual occurrence. + pub const TEXT: DocumentHighlightKind = DocumentHighlightKind(1); + + /// Read-access of a symbol, like reading a variable. + pub const READ: DocumentHighlightKind = DocumentHighlightKind(2); + + /// Write-access of a symbol, like writing to a variable. + pub const WRITE: DocumentHighlightKind = DocumentHighlightKind(3); +} +} diff --git a/vendor/lsp-types/src/document_link.rs b/vendor/lsp-types/src/document_link.rs new file mode 100644 index 00000000..1400dd96 --- /dev/null +++ b/vendor/lsp-types/src/document_link.rs @@ -0,0 +1,67 @@ +use crate::{ + PartialResultParams, Range, TextDocumentIdentifier, WorkDoneProgressOptions, + WorkDoneProgressParams, +}; +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use url::Url; + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentLinkClientCapabilities { + /// Whether document link supports dynamic registration. + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, + + /// Whether the client support the `tooltip` property on `DocumentLink`. + #[serde(skip_serializing_if = "Option::is_none")] + pub tooltip_support: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentLinkOptions { + /// Document links have a resolve provider as well. + #[serde(skip_serializing_if = "Option::is_none")] + pub resolve_provider: Option, + + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentLinkParams { + /// The document to provide document links for. + pub text_document: TextDocumentIdentifier, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +/// A document link is a range in a text document that links to an internal or external resource, like another +/// text document or a web site. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct DocumentLink { + /// The range this link applies to. + pub range: Range, + /// The uri this link points to. + #[serde(skip_serializing_if = "Option::is_none")] + pub target: Option, + + /// The tooltip text when you hover over this link. + /// + /// If a tooltip is provided, is will be displayed in a string that includes instructions on how to + /// trigger the link, such as `{0} (ctrl + click)`. The specific instructions vary depending on OS, + /// user settings, and localization. + #[serde(skip_serializing_if = "Option::is_none")] + pub tooltip: Option, + + /// A data entry field that is preserved on a document link between a DocumentLinkRequest + /// and a DocumentLinkResolveRequest. + #[serde(skip_serializing_if = "Option::is_none")] + pub data: Option, +} diff --git a/vendor/lsp-types/src/document_symbols.rs b/vendor/lsp-types/src/document_symbols.rs new file mode 100644 index 00000000..3f482e16 --- /dev/null +++ b/vendor/lsp-types/src/document_symbols.rs @@ -0,0 +1,134 @@ +use crate::{ + Location, PartialResultParams, Range, SymbolKind, SymbolKindCapability, TextDocumentIdentifier, + WorkDoneProgressParams, +}; + +use crate::{SymbolTag, TagSupport}; + +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentSymbolClientCapabilities { + /// This capability supports dynamic registration. + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, + + /// Specific capabilities for the `SymbolKind`. + #[serde(skip_serializing_if = "Option::is_none")] + pub symbol_kind: Option, + + /// The client support hierarchical document symbols. + #[serde(skip_serializing_if = "Option::is_none")] + pub hierarchical_document_symbol_support: Option, + + /// The client supports tags on `SymbolInformation`. Tags are supported on + /// `DocumentSymbol` if `hierarchicalDocumentSymbolSupport` is set to true. + /// Clients supporting tags have to handle unknown tags gracefully. + /// + /// @since 3.16.0 + #[serde( + default, + skip_serializing_if = "Option::is_none", + deserialize_with = "TagSupport::deserialize_compat" + )] + pub tag_support: Option>, +} + +#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum DocumentSymbolResponse { + Flat(Vec), + Nested(Vec), +} + +impl From> for DocumentSymbolResponse { + fn from(info: Vec) -> Self { + DocumentSymbolResponse::Flat(info) + } +} + +impl From> for DocumentSymbolResponse { + fn from(symbols: Vec) -> Self { + DocumentSymbolResponse::Nested(symbols) + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentSymbolParams { + /// The text document. + pub text_document: TextDocumentIdentifier, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +/// Represents programming constructs like variables, classes, interfaces etc. +/// that appear in a document. Document symbols can be hierarchical and they have two ranges: +/// one that encloses its definition and one that points to its most interesting range, +/// e.g. the range of an identifier. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentSymbol { + /// The name of this symbol. + pub name: String, + /// More detail for this symbol, e.g the signature of a function. If not provided the + /// name is used. + #[serde(skip_serializing_if = "Option::is_none")] + pub detail: Option, + /// The kind of this symbol. + pub kind: SymbolKind, + /// Tags for this completion item. + /// + /// @since 3.15.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub tags: Option>, + /// Indicates if this symbol is deprecated. + #[serde(skip_serializing_if = "Option::is_none")] + #[deprecated(note = "Use tags instead")] + pub deprecated: Option, + /// The range enclosing this symbol not including leading/trailing whitespace but everything else + /// like comments. This information is typically used to determine if the the clients cursor is + /// inside the symbol to reveal in the symbol in the UI. + pub range: Range, + /// The range that should be selected and revealed when this symbol is being picked, e.g the name of a function. + /// Must be contained by the the `range`. + pub selection_range: Range, + /// Children of this symbol, e.g. properties of a class. + #[serde(skip_serializing_if = "Option::is_none")] + pub children: Option>, +} + +/// Represents information about programming constructs like variables, classes, +/// interfaces etc. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SymbolInformation { + /// The name of this symbol. + pub name: String, + + /// The kind of this symbol. + pub kind: SymbolKind, + + /// Tags for this completion item. + /// + /// @since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub tags: Option>, + + /// Indicates if this symbol is deprecated. + #[serde(skip_serializing_if = "Option::is_none")] + #[deprecated(note = "Use tags instead")] + pub deprecated: Option, + + /// The location of this symbol. + pub location: Location, + + /// The name of the symbol containing this symbol. + #[serde(skip_serializing_if = "Option::is_none")] + pub container_name: Option, +} diff --git a/vendor/lsp-types/src/error_codes.rs b/vendor/lsp-types/src/error_codes.rs new file mode 100644 index 00000000..f09fae16 --- /dev/null +++ b/vendor/lsp-types/src/error_codes.rs @@ -0,0 +1,54 @@ +//! In this module we only define constants for lsp specific error codes. +//! There are other error codes that are defined in the +//! [JSON RPC specification](https://www.jsonrpc.org/specification#error_object). + +/// Defined in the LSP specification but in the range reserved for JSON-RPC error codes, +/// namely the -32099 to -32000 "Reserved for implementation-defined server-errors." range. +/// The code has, nonetheless, been left in this range for backwards compatibility reasons. +pub const SERVER_NOT_INITIALIZED: i64 = -32002; + +/// Defined in the LSP specification but in the range reserved for JSON-RPC error codes, +/// namely the -32099 to -32000 "Reserved for implementation-defined server-errors." range. +/// The code has, nonetheless, left in this range for backwards compatibility reasons. +pub const UNKNOWN_ERROR_CODE: i64 = -32001; + +/// This is the start range of LSP reserved error codes. +/// It doesn't denote a real error code. +/// +/// @since 3.16.0 +pub const LSP_RESERVED_ERROR_RANGE_START: i64 = -32899; + +/// A request failed but it was syntactically correct, e.g the +/// method name was known and the parameters were valid. The error +/// message should contain human readable information about why +/// the request failed. +/// +/// @since 3.17.0 +pub const REQUEST_FAILED: i64 = -32803; + +/// The server cancelled the request. This error code should +/// only be used for requests that explicitly support being +/// server cancellable. +/// +/// @since 3.17.0 +pub const SERVER_CANCELLED: i64 = -32802; + +/// The server detected that the content of a document got +/// modified outside normal conditions. A server should +/// NOT send this error code if it detects a content change +/// in it unprocessed messages. The result even computed +/// on an older state might still be useful for the client. +/// +/// If a client decides that a result is not of any use anymore +/// the client should cancel the request. +pub const CONTENT_MODIFIED: i64 = -32801; + +/// The client has canceled a request and a server as detected +/// the cancel. +pub const REQUEST_CANCELLED: i64 = -32800; + +/// This is the end range of LSP reserved error codes. +/// It doesn't denote a real error code. +/// +/// @since 3.16.0 +pub const LSP_RESERVED_ERROR_RANGE_END: i64 = -32800; diff --git a/vendor/lsp-types/src/file_operations.rs b/vendor/lsp-types/src/file_operations.rs new file mode 100644 index 00000000..52572f93 --- /dev/null +++ b/vendor/lsp-types/src/file_operations.rs @@ -0,0 +1,213 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct WorkspaceFileOperationsClientCapabilities { + /// Whether the client supports dynamic registration for file + /// requests/notifications. + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, + + /// The client has support for sending didCreateFiles notifications. + #[serde(skip_serializing_if = "Option::is_none")] + pub did_create: Option, + + /// The server is interested in receiving willCreateFiles requests. + #[serde(skip_serializing_if = "Option::is_none")] + pub will_create: Option, + + /// The server is interested in receiving didRenameFiles requests. + #[serde(skip_serializing_if = "Option::is_none")] + pub did_rename: Option, + + /// The server is interested in receiving willRenameFiles requests. + #[serde(skip_serializing_if = "Option::is_none")] + pub will_rename: Option, + + /// The server is interested in receiving didDeleteFiles requests. + #[serde(skip_serializing_if = "Option::is_none")] + pub did_delete: Option, + + /// The server is interested in receiving willDeleteFiles requests. + #[serde(skip_serializing_if = "Option::is_none")] + pub will_delete: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct WorkspaceFileOperationsServerCapabilities { + /// The server is interested in receiving didCreateFiles + /// notifications. + #[serde(skip_serializing_if = "Option::is_none")] + pub did_create: Option, + + /// The server is interested in receiving willCreateFiles requests. + #[serde(skip_serializing_if = "Option::is_none")] + pub will_create: Option, + + /// The server is interested in receiving didRenameFiles + /// notifications. + #[serde(skip_serializing_if = "Option::is_none")] + pub did_rename: Option, + + /// The server is interested in receiving willRenameFiles requests. + #[serde(skip_serializing_if = "Option::is_none")] + pub will_rename: Option, + + /// The server is interested in receiving didDeleteFiles file + /// notifications. + #[serde(skip_serializing_if = "Option::is_none")] + pub did_delete: Option, + + /// The server is interested in receiving willDeleteFiles file + /// requests. + #[serde(skip_serializing_if = "Option::is_none")] + pub will_delete: Option, +} + +/// The options to register for file operations. +/// +/// @since 3.16.0 +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct FileOperationRegistrationOptions { + /// The actual filters. + pub filters: Vec, +} + +/// A filter to describe in which file operation requests or notifications +/// the server is interested in. +/// +/// @since 3.16.0 +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct FileOperationFilter { + /// A Uri like `file` or `untitled`. + pub scheme: Option, + + /// The actual file operation pattern. + pub pattern: FileOperationPattern, +} + +/// A pattern kind describing if a glob pattern matches a file a folder or +/// both. +/// +/// @since 3.16.0 +#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Clone)] +#[serde(rename_all = "lowercase")] +pub enum FileOperationPatternKind { + /// The pattern matches a file only. + File, + + /// The pattern matches a folder only. + Folder, +} + +/// Matching options for the file operation pattern. +/// +/// @since 3.16.0 +/// +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct FileOperationPatternOptions { + /// The pattern should be matched ignoring casing. + #[serde(skip_serializing_if = "Option::is_none")] + pub ignore_case: Option, +} + +/// A pattern to describe in which file operation requests or notifications +/// the server is interested in. +/// +/// @since 3.16.0 +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct FileOperationPattern { + /// The glob pattern to match. Glob patterns can have the following syntax: + /// - `*` to match one or more characters in a path segment + /// - `?` to match on one character in a path segment + /// - `**` to match any number of path segments, including none + /// - `{}` to group conditions (e.g. `**​/*.{ts,js}` matches all TypeScript + /// and JavaScript files) + /// - `[]` to declare a range of characters to match in a path segment + /// (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …) + /// - `[!...]` to negate a range of characters to match in a path segment + /// (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but + /// not `example.0`) + pub glob: String, + + /// Whether to match files or folders with this pattern. + /// + /// Matches both if undefined. + #[serde(skip_serializing_if = "Option::is_none")] + pub matches: Option, + + /// Additional options used during matching. + #[serde(skip_serializing_if = "Option::is_none")] + pub options: Option, +} + +/// The parameters sent in notifications/requests for user-initiated creation +/// of files. +/// +/// @since 3.16.0 +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CreateFilesParams { + /// An array of all files/folders created in this operation. + pub files: Vec, +} +/// Represents information on a file/folder create. +/// +/// @since 3.16.0 +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct FileCreate { + /// A file:// URI for the location of the file/folder being created. + pub uri: String, +} + +/// The parameters sent in notifications/requests for user-initiated renames +/// of files. +/// +/// @since 3.16.0 +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct RenameFilesParams { + /// An array of all files/folders renamed in this operation. When a folder + /// is renamed, only the folder will be included, and not its children. + pub files: Vec, +} + +/// Represents information on a file/folder rename. +/// +/// @since 3.16.0 +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct FileRename { + /// A file:// URI for the original location of the file/folder being renamed. + pub old_uri: String, + + /// A file:// URI for the new location of the file/folder being renamed. + pub new_uri: String, +} + +/// The parameters sent in notifications/requests for user-initiated deletes +/// of files. +/// +/// @since 3.16.0 +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DeleteFilesParams { + /// An array of all files/folders deleted in this operation. + pub files: Vec, +} + +/// Represents information on a file/folder delete. +/// +/// @since 3.16.0 +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct FileDelete { + /// A file:// URI for the location of the file/folder being deleted. + pub uri: String, +} diff --git a/vendor/lsp-types/src/folding_range.rs b/vendor/lsp-types/src/folding_range.rs new file mode 100644 index 00000000..c9109ebf --- /dev/null +++ b/vendor/lsp-types/src/folding_range.rs @@ -0,0 +1,145 @@ +use crate::{ + PartialResultParams, StaticTextDocumentColorProviderOptions, TextDocumentIdentifier, + WorkDoneProgressParams, +}; +use serde::{Deserialize, Serialize}; +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct FoldingRangeParams { + /// The text document. + pub text_document: TextDocumentIdentifier, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum FoldingRangeProviderCapability { + Simple(bool), + FoldingProvider(FoldingProviderOptions), + Options(StaticTextDocumentColorProviderOptions), +} + +impl From for FoldingRangeProviderCapability { + fn from(from: StaticTextDocumentColorProviderOptions) -> Self { + Self::Options(from) + } +} + +impl From for FoldingRangeProviderCapability { + fn from(from: FoldingProviderOptions) -> Self { + Self::FoldingProvider(from) + } +} + +impl From for FoldingRangeProviderCapability { + fn from(from: bool) -> Self { + Self::Simple(from) + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct FoldingProviderOptions {} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct FoldingRangeKindCapability { + /// The folding range kind values the client supports. When this + /// property exists the client also guarantees that it will + /// handle values outside its set gracefully and falls back + /// to a default value when unknown. + #[serde(skip_serializing_if = "Option::is_none")] + pub value_set: Option>, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct FoldingRangeCapability { + /// If set, the client signals that it supports setting collapsedText on + /// folding ranges to display custom labels instead of the default text. + /// + /// @since 3.17.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub collapsed_text: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct FoldingRangeClientCapabilities { + /// Whether implementation supports dynamic registration for folding range providers. If this is set to `true` + /// the client supports the new `(FoldingRangeProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions)` + /// return value for the corresponding server capability as well. + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, + + /// The maximum number of folding ranges that the client prefers to receive per document. The value serves as a + /// hint, servers are free to follow the limit. + #[serde(skip_serializing_if = "Option::is_none")] + pub range_limit: Option, + + /// If set, the client signals that it only supports folding complete lines. If set, client will + /// ignore specified `startCharacter` and `endCharacter` properties in a FoldingRange. + #[serde(skip_serializing_if = "Option::is_none")] + pub line_folding_only: Option, + + /// Specific options for the folding range kind. + /// + /// @since 3.17.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub folding_range_kind: Option, + + /// Specific options for the folding range. + /// + /// @since 3.17.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub folding_range: Option, +} + +/// Enum of known range kinds +#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Clone)] +#[serde(rename_all = "lowercase")] +pub enum FoldingRangeKind { + /// Folding range for a comment + Comment, + /// Folding range for a imports or includes + Imports, + /// Folding range for a region (e.g. `#region`) + Region, +} + +/// Represents a folding range. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct FoldingRange { + /// The zero-based line number from where the folded range starts. + pub start_line: u32, + + /// The zero-based character offset from where the folded range starts. If not defined, defaults to the length of the start line. + #[serde(skip_serializing_if = "Option::is_none")] + pub start_character: Option, + + /// The zero-based line number where the folded range ends. + pub end_line: u32, + + /// The zero-based character offset before the folded range ends. If not defined, defaults to the length of the end line. + #[serde(skip_serializing_if = "Option::is_none")] + pub end_character: Option, + + /// Describes the kind of the folding range such as `comment' or 'region'. The kind + /// is used to categorize folding ranges and used by commands like 'Fold all comments'. See + /// [FoldingRangeKind](#FoldingRangeKind) for an enumeration of standardized kinds. + #[serde(skip_serializing_if = "Option::is_none")] + pub kind: Option, + + /// The text that the client should show when the specified range is + /// collapsed. If not defined or not supported by the client, a default + /// will be chosen by the client. + /// + /// @since 3.17.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub collapsed_text: Option, +} diff --git a/vendor/lsp-types/src/formatting.rs b/vendor/lsp-types/src/formatting.rs new file mode 100644 index 00000000..4e5593c8 --- /dev/null +++ b/vendor/lsp-types/src/formatting.rs @@ -0,0 +1,153 @@ +use serde::{Deserialize, Serialize}; + +use crate::{ + DocumentSelector, DynamicRegistrationClientCapabilities, Range, TextDocumentIdentifier, + TextDocumentPositionParams, WorkDoneProgressParams, +}; + +use std::collections::HashMap; + +pub type DocumentFormattingClientCapabilities = DynamicRegistrationClientCapabilities; +pub type DocumentRangeFormattingClientCapabilities = DynamicRegistrationClientCapabilities; +pub type DocumentOnTypeFormattingClientCapabilities = DynamicRegistrationClientCapabilities; + +/// Format document on type options +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentOnTypeFormattingOptions { + /// A character on which formatting should be triggered, like `}`. + pub first_trigger_character: String, + + /// More trigger characters. + #[serde(skip_serializing_if = "Option::is_none")] + pub more_trigger_character: Option>, +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentFormattingParams { + /// The document to format. + pub text_document: TextDocumentIdentifier, + + /// The format options. + pub options: FormattingOptions, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, +} + +/// Value-object describing what options formatting should use. +#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct FormattingOptions { + /// Size of a tab in spaces. + pub tab_size: u32, + + /// Prefer spaces over tabs. + pub insert_spaces: bool, + + /// Signature for further properties. + #[serde(flatten)] + pub properties: HashMap, + + /// Trim trailing whitespace on a line. + #[serde(skip_serializing_if = "Option::is_none")] + pub trim_trailing_whitespace: Option, + + /// Insert a newline character at the end of the file if one does not exist. + #[serde(skip_serializing_if = "Option::is_none")] + pub insert_final_newline: Option, + + /// Trim all newlines after the final newline at the end of the file. + #[serde(skip_serializing_if = "Option::is_none")] + pub trim_final_newlines: Option, +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum FormattingProperty { + Bool(bool), + Number(i32), + String(String), +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentRangeFormattingParams { + /// The document to format. + pub text_document: TextDocumentIdentifier, + + /// The range to format + pub range: Range, + + /// The format options + pub options: FormattingOptions, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentOnTypeFormattingParams { + /// Text Document and Position fields. + #[serde(flatten)] + pub text_document_position: TextDocumentPositionParams, + + /// The character that has been typed. + pub ch: String, + + /// The format options. + pub options: FormattingOptions, +} + +/// Extends TextDocumentRegistrationOptions +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentOnTypeFormattingRegistrationOptions { + /// A document selector to identify the scope of the registration. If set to null + /// the document selector provided on the client side will be used. + pub document_selector: Option, + + /// A character on which formatting should be triggered, like `}`. + pub first_trigger_character: String, + + /// More trigger characters. + #[serde(skip_serializing_if = "Option::is_none")] + pub more_trigger_character: Option>, +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::tests::test_serialization; + + #[test] + fn formatting_options() { + test_serialization( + &FormattingOptions { + tab_size: 123, + insert_spaces: true, + properties: HashMap::new(), + trim_trailing_whitespace: None, + insert_final_newline: None, + trim_final_newlines: None, + }, + r#"{"tabSize":123,"insertSpaces":true}"#, + ); + + test_serialization( + &FormattingOptions { + tab_size: 123, + insert_spaces: true, + properties: vec![("prop".to_string(), FormattingProperty::Number(1))] + .into_iter() + .collect(), + trim_trailing_whitespace: None, + insert_final_newline: None, + trim_final_newlines: None, + }, + r#"{"tabSize":123,"insertSpaces":true,"prop":1}"#, + ); + } +} diff --git a/vendor/lsp-types/src/hover.rs b/vendor/lsp-types/src/hover.rs new file mode 100644 index 00000000..01bd2f8d --- /dev/null +++ b/vendor/lsp-types/src/hover.rs @@ -0,0 +1,86 @@ +use serde::{Deserialize, Serialize}; + +use crate::{ + MarkedString, MarkupContent, MarkupKind, Range, TextDocumentPositionParams, + TextDocumentRegistrationOptions, WorkDoneProgressOptions, WorkDoneProgressParams, +}; + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct HoverClientCapabilities { + /// Whether completion supports dynamic registration. + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, + + /// Client supports the follow content formats for the content + /// property. The order describes the preferred format of the client. + #[serde(skip_serializing_if = "Option::is_none")] + pub content_format: Option>, +} + +/// Hover options. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct HoverOptions { + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct HoverRegistrationOptions { + #[serde(flatten)] + pub text_document_registration_options: TextDocumentRegistrationOptions, + + #[serde(flatten)] + pub hover_options: HoverOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum HoverProviderCapability { + Simple(bool), + Options(HoverOptions), +} + +impl From for HoverProviderCapability { + fn from(from: HoverOptions) -> Self { + Self::Options(from) + } +} + +impl From for HoverProviderCapability { + fn from(from: bool) -> Self { + Self::Simple(from) + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct HoverParams { + #[serde(flatten)] + pub text_document_position_params: TextDocumentPositionParams, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, +} + +/// The result of a hover request. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct Hover { + /// The hover's content + pub contents: HoverContents, + /// An optional range is a range inside a text document + /// that is used to visualize a hover, e.g. by changing the background color. + #[serde(skip_serializing_if = "Option::is_none")] + pub range: Option, +} + +/// Hover contents could be single entry or multiple entries. +#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum HoverContents { + Scalar(MarkedString), + Array(Vec), + Markup(MarkupContent), +} diff --git a/vendor/lsp-types/src/inlay_hint.rs b/vendor/lsp-types/src/inlay_hint.rs new file mode 100644 index 00000000..171f3c9d --- /dev/null +++ b/vendor/lsp-types/src/inlay_hint.rs @@ -0,0 +1,281 @@ +use crate::{ + Command, LSPAny, Location, MarkupContent, Position, Range, StaticRegistrationOptions, + TextDocumentIdentifier, TextDocumentRegistrationOptions, TextEdit, WorkDoneProgressOptions, + WorkDoneProgressParams, +}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[serde(untagged)] +pub enum InlayHintServerCapabilities { + Options(InlayHintOptions), + RegistrationOptions(InlayHintRegistrationOptions), +} + +/// Inlay hint client capabilities. +/// +/// @since 3.17.0 +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct InlayHintClientCapabilities { + /// Whether inlay hints support dynamic registration. + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, + + /// Indicates which properties a client can resolve lazily on a inlay + /// hint. + #[serde(skip_serializing_if = "Option::is_none")] + pub resolve_support: Option, +} + +/// Inlay hint options used during static registration. +/// +/// @since 3.17.0 +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct InlayHintOptions { + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, + + /// The server provides support to resolve additional + /// information for an inlay hint item. + #[serde(skip_serializing_if = "Option::is_none")] + pub resolve_provider: Option, +} + +/// Inlay hint options used during static or dynamic registration. +/// +/// @since 3.17.0 +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct InlayHintRegistrationOptions { + #[serde(flatten)] + pub inlay_hint_options: InlayHintOptions, + + #[serde(flatten)] + pub text_document_registration_options: TextDocumentRegistrationOptions, + + #[serde(flatten)] + pub static_registration_options: StaticRegistrationOptions, +} + +/// A parameter literal used in inlay hint requests. +/// +/// @since 3.17.0 +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct InlayHintParams { + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + /// The text document. + pub text_document: TextDocumentIdentifier, + + /// The visible document range for which inlay hints should be computed. + pub range: Range, +} + +/// Inlay hint information. +/// +/// @since 3.17.0 +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct InlayHint { + /// The position of this hint. + pub position: Position, + + /// The label of this hint. A human readable string or an array of + /// InlayHintLabelPart label parts. + /// + /// *Note* that neither the string nor the label part can be empty. + pub label: InlayHintLabel, + + /// The kind of this hint. Can be omitted in which case the client + /// should fall back to a reasonable default. + #[serde(skip_serializing_if = "Option::is_none")] + pub kind: Option, + + /// Optional text edits that are performed when accepting this inlay hint. + /// + /// *Note* that edits are expected to change the document so that the inlay + /// hint (or its nearest variant) is now part of the document and the inlay + /// hint itself is now obsolete. + /// + /// Depending on the client capability `inlayHint.resolveSupport` clients + /// might resolve this property late using the resolve request. + #[serde(skip_serializing_if = "Option::is_none")] + pub text_edits: Option>, + + /// The tooltip text when you hover over this item. + /// + /// Depending on the client capability `inlayHint.resolveSupport` clients + /// might resolve this property late using the resolve request. + #[serde(skip_serializing_if = "Option::is_none")] + pub tooltip: Option, + + /// Render padding before the hint. + /// + /// Note: Padding should use the editor's background color, not the + /// background color of the hint itself. That means padding can be used + /// to visually align/separate an inlay hint. + #[serde(skip_serializing_if = "Option::is_none")] + pub padding_left: Option, + + /// Render padding after the hint. + /// + /// Note: Padding should use the editor's background color, not the + /// background color of the hint itself. That means padding can be used + /// to visually align/separate an inlay hint. + #[serde(skip_serializing_if = "Option::is_none")] + pub padding_right: Option, + + /// A data entry field that is preserved on a inlay hint between + /// a `textDocument/inlayHint` and a `inlayHint/resolve` request. + #[serde(skip_serializing_if = "Option::is_none")] + pub data: Option, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum InlayHintLabel { + String(String), + LabelParts(Vec), +} + +impl From for InlayHintLabel { + #[inline] + fn from(from: String) -> Self { + Self::String(from) + } +} + +impl From> for InlayHintLabel { + #[inline] + fn from(from: Vec) -> Self { + Self::LabelParts(from) + } +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum InlayHintTooltip { + String(String), + MarkupContent(MarkupContent), +} + +impl From for InlayHintTooltip { + #[inline] + fn from(from: String) -> Self { + Self::String(from) + } +} + +impl From for InlayHintTooltip { + #[inline] + fn from(from: MarkupContent) -> Self { + Self::MarkupContent(from) + } +} + +/// An inlay hint label part allows for interactive and composite labels +/// of inlay hints. +#[derive(Debug, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct InlayHintLabelPart { + /// The value of this label part. + pub value: String, + + /// The tooltip text when you hover over this label part. Depending on + /// the client capability `inlayHint.resolveSupport` clients might resolve + /// this property late using the resolve request. + #[serde(skip_serializing_if = "Option::is_none")] + pub tooltip: Option, + + /// An optional source code location that represents this + /// label part. + /// + /// The editor will use this location for the hover and for code navigation + /// features: This part will become a clickable link that resolves to the + /// definition of the symbol at the given location (not necessarily the + /// location itself), it shows the hover that shows at the given location, + /// and it shows a context menu with further code navigation commands. + /// + /// Depending on the client capability `inlayHint.resolveSupport` clients + /// might resolve this property late using the resolve request. + #[serde(skip_serializing_if = "Option::is_none")] + pub location: Option, + + /// An optional command for this label part. + /// + /// Depending on the client capability `inlayHint.resolveSupport` clients + /// might resolve this property late using the resolve request. + #[serde(skip_serializing_if = "Option::is_none")] + pub command: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum InlayHintLabelPartTooltip { + String(String), + MarkupContent(MarkupContent), +} + +impl From for InlayHintLabelPartTooltip { + #[inline] + fn from(from: String) -> Self { + Self::String(from) + } +} + +impl From for InlayHintLabelPartTooltip { + #[inline] + fn from(from: MarkupContent) -> Self { + Self::MarkupContent(from) + } +} + +/// Inlay hint kinds. +/// +/// @since 3.17.0 +#[derive(Eq, PartialEq, Copy, Clone, Serialize, Deserialize)] +#[serde(transparent)] +pub struct InlayHintKind(i32); +lsp_enum! { +impl InlayHintKind { + /// An inlay hint that for a type annotation. + pub const TYPE: InlayHintKind = InlayHintKind(1); + + /// An inlay hint that is for a parameter. + pub const PARAMETER: InlayHintKind = InlayHintKind(2); +} +} + +/// Inlay hint client capabilities. +/// +/// @since 3.17.0 +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct InlayHintResolveClientCapabilities { + /// The properties that a client can resolve lazily. + pub properties: Vec, +} + +/// Client workspace capabilities specific to inlay hints. +/// +/// @since 3.17.0 +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct InlayHintWorkspaceClientCapabilities { + /// Whether the client implementation supports a refresh request sent from + /// the server to the client. + /// + /// Note that this event is global and will force the client to refresh all + /// inlay hints currently shown. It should be used with absolute care and + /// is useful for situation where a server for example detects a project wide + /// change that requires such a calculation. + #[serde(skip_serializing_if = "Option::is_none")] + pub refresh_support: Option, +} + +// TODO(sno2): add tests once stabilized diff --git a/vendor/lsp-types/src/inline_completion.rs b/vendor/lsp-types/src/inline_completion.rs new file mode 100644 index 00000000..8289858a --- /dev/null +++ b/vendor/lsp-types/src/inline_completion.rs @@ -0,0 +1,162 @@ +use crate::{ + Command, InsertTextFormat, Range, StaticRegistrationOptions, TextDocumentPositionParams, + TextDocumentRegistrationOptions, WorkDoneProgressOptions, WorkDoneProgressParams, +}; +use serde::{Deserialize, Serialize}; + +/// Client capabilities specific to inline completions. +/// +/// @since 3.18.0 +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct InlineCompletionClientCapabilities { + /// Whether implementation supports dynamic registration for inline completion providers. + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, +} + +/// Inline completion options used during static registration. +/// +/// @since 3.18.0 +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +pub struct InlineCompletionOptions { + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, +} + +/// Inline completion options used during static or dynamic registration. +/// +// @since 3.18.0 +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +pub struct InlineCompletionRegistrationOptions { + #[serde(flatten)] + pub inline_completion_options: InlineCompletionOptions, + + #[serde(flatten)] + pub text_document_registration_options: TextDocumentRegistrationOptions, + + #[serde(flatten)] + pub static_registration_options: StaticRegistrationOptions, +} + +/// A parameter literal used in inline completion requests. +/// +/// @since 3.18.0 +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct InlineCompletionParams { + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub text_document_position: TextDocumentPositionParams, + + /// Additional information about the context in which inline completions were requested. + pub context: InlineCompletionContext, +} + +/// Describes how an [`InlineCompletionItemProvider`] was triggered. +/// +/// @since 3.18.0 +#[derive(Eq, PartialEq, Clone, Copy, Deserialize, Serialize)] +pub struct InlineCompletionTriggerKind(i32); +lsp_enum! { +impl InlineCompletionTriggerKind { + /// Completion was triggered explicitly by a user gesture. + /// Return multiple completion items to enable cycling through them. + pub const Invoked: InlineCompletionTriggerKind = InlineCompletionTriggerKind(1); + + /// Completion was triggered automatically while editing. + /// It is sufficient to return a single completion item in this case. + pub const Automatic: InlineCompletionTriggerKind = InlineCompletionTriggerKind(2); +} +} + +/// Describes the currently selected completion item. +/// +/// @since 3.18.0 +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct SelectedCompletionInfo { + /// The range that will be replaced if this completion item is accepted. + pub range: Range, + /// The text the range will be replaced with if this completion is + /// accepted. + pub text: String, +} + +/// Provides information about the context in which an inline completion was +/// requested. +/// +/// @since 3.18.0 +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct InlineCompletionContext { + /// Describes how the inline completion was triggered. + pub trigger_kind: InlineCompletionTriggerKind, + /// Provides information about the currently selected item in the + /// autocomplete widget if it is visible. + /// + /// If set, provided inline completions must extend the text of the + /// selected item and use the same range, otherwise they are not shown as + /// preview. + /// As an example, if the document text is `console.` and the selected item + /// is `.log` replacing the `.` in the document, the inline completion must + /// also replace `.` and start with `.log`, for example `.log()`. + /// + /// Inline completion providers are requested again whenever the selected + /// item changes. + #[serde(skip_serializing_if = "Option::is_none")] + pub selected_completion_info: Option, +} + +/// InlineCompletion response can be multiple completion items, or a list of completion items +#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum InlineCompletionResponse { + Array(Vec), + List(InlineCompletionList), +} + +/// Represents a collection of [`InlineCompletionItem`] to be presented in the editor. +/// +/// @since 3.18.0 +#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] +pub struct InlineCompletionList { + /// The inline completion items + pub items: Vec, +} + +/// An inline completion item represents a text snippet that is proposed inline +/// to complete text that is being typed. +/// +/// @since 3.18.0 +#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct InlineCompletionItem { + /// The text to replace the range with. Must be set. + /// Is used both for the preview and the accept operation. + pub insert_text: String, + /// A text that is used to decide if this inline completion should be + /// shown. When `falsy` the [`InlineCompletionItem::insertText`] is + /// used. + /// + /// An inline completion is shown if the text to replace is a prefix of the + /// filter text. + #[serde(skip_serializing_if = "Option::is_none")] + pub filter_text: Option, + /// The range to replace. + /// Must begin and end on the same line. + /// + /// Prefer replacements over insertions to provide a better experience when + /// the user deletes typed text. + #[serde(skip_serializing_if = "Option::is_none")] + pub range: Option, + /// An optional command that is executed *after* inserting this + /// completion. + #[serde(skip_serializing_if = "Option::is_none")] + pub command: Option, + /// The format of the insert text. The format applies to the `insertText`. + /// If omitted defaults to `InsertTextFormat.PlainText`. + #[serde(skip_serializing_if = "Option::is_none")] + pub insert_text_format: Option, +} diff --git a/vendor/lsp-types/src/inline_value.rs b/vendor/lsp-types/src/inline_value.rs new file mode 100644 index 00000000..dd29fbbf --- /dev/null +++ b/vendor/lsp-types/src/inline_value.rs @@ -0,0 +1,217 @@ +use crate::{ + DynamicRegistrationClientCapabilities, Range, StaticRegistrationOptions, + TextDocumentIdentifier, TextDocumentRegistrationOptions, WorkDoneProgressOptions, + WorkDoneProgressParams, +}; +use serde::{Deserialize, Serialize}; + +pub type InlineValueClientCapabilities = DynamicRegistrationClientCapabilities; + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum InlineValueServerCapabilities { + Options(InlineValueOptions), + RegistrationOptions(InlineValueRegistrationOptions), +} + +/// Inline value options used during static registration. +/// +/// @since 3.17.0 +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +pub struct InlineValueOptions { + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, +} + +/// Inline value options used during static or dynamic registration. +/// +/// @since 3.17.0 +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +pub struct InlineValueRegistrationOptions { + #[serde(flatten)] + pub inline_value_options: InlineValueOptions, + + #[serde(flatten)] + pub text_document_registration_options: TextDocumentRegistrationOptions, + + #[serde(flatten)] + pub static_registration_options: StaticRegistrationOptions, +} + +/// A parameter literal used in inline value requests. +/// +/// @since 3.17.0 +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct InlineValueParams { + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + /// The text document. + pub text_document: TextDocumentIdentifier, + + /// The document range for which inline values should be computed. + pub range: Range, + + /// Additional information about the context in which inline values were + /// requested. + pub context: InlineValueContext, +} + +/// @since 3.17.0 +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct InlineValueContext { + /// The stack frame (as a DAP Id) where the execution has stopped. + pub frame_id: i32, + + /// The document range where execution has stopped. + /// Typically the end position of the range denotes the line where the + /// inline values are shown. + pub stopped_location: Range, +} + +/// Provide inline value as text. +/// +/// @since 3.17.0 +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +pub struct InlineValueText { + /// The document range for which the inline value applies. + pub range: Range, + + /// The text of the inline value. + pub text: String, +} + +/// Provide inline value through a variable lookup. +/// +/// If only a range is specified, the variable name will be extracted from +/// the underlying document. +/// +/// An optional variable name can be used to override the extracted name. +/// +/// @since 3.17.0 +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct InlineValueVariableLookup { + /// The document range for which the inline value applies. + /// The range is used to extract the variable name from the underlying + /// document. + pub range: Range, + + /// If specified the name of the variable to look up. + #[serde(skip_serializing_if = "Option::is_none")] + pub variable_name: Option, + + /// How to perform the lookup. + pub case_sensitive_lookup: bool, +} + +/// Provide an inline value through an expression evaluation. +/// +/// If only a range is specified, the expression will be extracted from the +/// underlying document. +/// +/// An optional expression can be used to override the extracted expression. +/// +/// @since 3.17.0 +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct InlineValueEvaluatableExpression { + /// The document range for which the inline value applies. + /// The range is used to extract the evaluatable expression from the + /// underlying document. + pub range: Range, + + /// If specified the expression overrides the extracted expression. + #[serde(skip_serializing_if = "Option::is_none")] + pub expression: Option, +} + +/// Inline value information can be provided by different means: +/// - directly as a text value (class InlineValueText). +/// - as a name to use for a variable lookup (class InlineValueVariableLookup) +/// - as an evaluatable expression (class InlineValueEvaluatableExpression) +/// The InlineValue types combines all inline value types into one type. +/// +/// @since 3.17.0 +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum InlineValue { + Text(InlineValueText), + VariableLookup(InlineValueVariableLookup), + EvaluatableExpression(InlineValueEvaluatableExpression), +} + +impl From for InlineValue { + #[inline] + fn from(from: InlineValueText) -> Self { + Self::Text(from) + } +} + +impl From for InlineValue { + #[inline] + fn from(from: InlineValueVariableLookup) -> Self { + Self::VariableLookup(from) + } +} + +impl From for InlineValue { + #[inline] + fn from(from: InlineValueEvaluatableExpression) -> Self { + Self::EvaluatableExpression(from) + } +} + +/// Client workspace capabilities specific to inline values. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +/// +/// @since 3.17.0 +#[serde(rename_all = "camelCase")] +pub struct InlineValueWorkspaceClientCapabilities { + /// Whether the client implementation supports a refresh request sent from + /// the server to the client. + /// + /// Note that this event is global and will force the client to refresh all + /// inline values currently shown. It should be used with absolute care and + /// is useful for situation where a server for example detect a project wide + /// change that requires such a calculation. + #[serde(skip_serializing_if = "Option::is_none")] + pub refresh_support: Option, +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::tests::test_serialization; + use crate::Position; + + #[test] + fn inline_values() { + test_serialization( + &InlineValueText { + range: Range::new(Position::new(0, 0), Position::new(0, 4)), + text: "one".to_owned(), + }, + r#"{"range":{"start":{"line":0,"character":0},"end":{"line":0,"character":4}},"text":"one"}"#, + ); + + test_serialization( + &InlineValue::VariableLookup(InlineValueVariableLookup { + range: Range::new(Position::new(1, 0), Position::new(1, 4)), + variable_name: None, + case_sensitive_lookup: false, + }), + r#"{"range":{"start":{"line":1,"character":0},"end":{"line":1,"character":4}},"caseSensitiveLookup":false}"#, + ); + + test_serialization( + &InlineValue::EvaluatableExpression(InlineValueEvaluatableExpression { + range: Range::new(Position::new(2, 0), Position::new(2, 4)), + expression: None, + }), + r#"{"range":{"start":{"line":2,"character":0},"end":{"line":2,"character":4}}}"#, + ); + } +} diff --git a/vendor/lsp-types/src/lib.rs b/vendor/lsp-types/src/lib.rs new file mode 100644 index 00000000..e38fae20 --- /dev/null +++ b/vendor/lsp-types/src/lib.rs @@ -0,0 +1,2880 @@ +/*! + +Language Server Protocol types for Rust. + +Based on: + +This library uses the URL crate for parsing URIs. Note that there is +some confusion on the meaning of URLs vs URIs: +. According to that +information, on the classical sense of "URLs", "URLs" are a subset of +URIs, But on the modern/new meaning of URLs, they are the same as +URIs. The important take-away aspect is that the URL crate should be +able to parse any URI, such as `urn:isbn:0451450523`. + + +*/ +#![allow(non_upper_case_globals)] +#![forbid(unsafe_code)] +#[macro_use] +extern crate bitflags; + +use std::{collections::HashMap, fmt::Debug}; + +use serde::{de, de::Error as Error_, Deserialize, Serialize}; +use serde_json::Value; +pub use url::Url; + +// Large enough to contain any enumeration name defined in this crate +type PascalCaseBuf = [u8; 32]; +const fn fmt_pascal_case_const(name: &str) -> (PascalCaseBuf, usize) { + let mut buf = [0; 32]; + let mut buf_i = 0; + let mut name_i = 0; + let name = name.as_bytes(); + while name_i < name.len() { + let first = name[name_i]; + name_i += 1; + + buf[buf_i] = first; + buf_i += 1; + + while name_i < name.len() { + let rest = name[name_i]; + name_i += 1; + if rest == b'_' { + break; + } + + buf[buf_i] = rest.to_ascii_lowercase(); + buf_i += 1; + } + } + (buf, buf_i) +} + +fn fmt_pascal_case(f: &mut std::fmt::Formatter<'_>, name: &str) -> std::fmt::Result { + for word in name.split('_') { + let mut chars = word.chars(); + let first = chars.next().unwrap(); + write!(f, "{}", first)?; + for rest in chars { + write!(f, "{}", rest.to_lowercase())?; + } + } + Ok(()) +} + +macro_rules! lsp_enum { + (impl $typ: ident { $( $(#[$attr:meta])* pub const $name: ident : $enum_type: ty = $value: expr; )* }) => { + impl $typ { + $( + $(#[$attr])* + pub const $name: $enum_type = $value; + )* + } + + impl std::fmt::Debug for $typ { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match *self { + $( + Self::$name => crate::fmt_pascal_case(f, stringify!($name)), + )* + _ => write!(f, "{}({})", stringify!($typ), self.0), + } + } + } + + impl std::convert::TryFrom<&str> for $typ { + type Error = &'static str; + fn try_from(value: &str) -> Result { + match () { + $( + _ if { + const X: (crate::PascalCaseBuf, usize) = crate::fmt_pascal_case_const(stringify!($name)); + let (buf, len) = X; + &buf[..len] == value.as_bytes() + } => Ok(Self::$name), + )* + _ => Err("unknown enum variant"), + } + } + } + + } +} + +pub mod error_codes; +pub mod notification; +pub mod request; + +mod call_hierarchy; +pub use call_hierarchy::*; + +mod code_action; +pub use code_action::*; + +mod code_lens; +pub use code_lens::*; + +mod color; +pub use color::*; + +mod completion; +pub use completion::*; + +mod document_diagnostic; +pub use document_diagnostic::*; + +mod document_highlight; +pub use document_highlight::*; + +mod document_link; +pub use document_link::*; + +mod document_symbols; +pub use document_symbols::*; + +mod file_operations; +pub use file_operations::*; + +mod folding_range; +pub use folding_range::*; + +mod formatting; +pub use formatting::*; + +mod hover; +pub use hover::*; + +mod inlay_hint; +pub use inlay_hint::*; + +mod inline_value; +pub use inline_value::*; + +#[cfg(feature = "proposed")] +mod inline_completion; +#[cfg(feature = "proposed")] +pub use inline_completion::*; + +mod moniker; +pub use moniker::*; + +mod progress; +pub use progress::*; + +mod references; +pub use references::*; + +mod rename; +pub use rename::*; + +pub mod selection_range; +pub use selection_range::*; + +mod semantic_tokens; +pub use semantic_tokens::*; + +mod signature_help; +pub use signature_help::*; + +mod type_hierarchy; +pub use type_hierarchy::*; + +mod linked_editing; +pub use linked_editing::*; + +mod window; +pub use window::*; + +mod workspace_diagnostic; +pub use workspace_diagnostic::*; + +mod workspace_folders; +pub use workspace_folders::*; + +mod workspace_symbols; +pub use workspace_symbols::*; + +pub mod lsif; + +mod trace; +pub use trace::*; + +/* ----------------- Auxiliary types ----------------- */ + +#[derive(Debug, Eq, Hash, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum NumberOrString { + Number(i32), + String(String), +} + +/* ----------------- Cancel support ----------------- */ + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct CancelParams { + /// The request id to cancel. + pub id: NumberOrString, +} + +/* ----------------- Basic JSON Structures ----------------- */ + +/// The LSP any type +/// +/// @since 3.17.0 +pub type LSPAny = serde_json::Value; + +/// LSP object definition. +/// +/// @since 3.17.0 +pub type LSPObject = serde_json::Map; + +/// LSP arrays. +/// +/// @since 3.17.0 +pub type LSPArray = Vec; + +/// Position in a text document expressed as zero-based line and character offset. +/// A position is between two characters like an 'insert' cursor in a editor. +#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Copy, Clone, Default, Deserialize, Serialize, Hash)] +pub struct Position { + /// Line position in a document (zero-based). + pub line: u32, + /// Character offset on a line in a document (zero-based). The meaning of this + /// offset is determined by the negotiated `PositionEncodingKind`. + /// + /// If the character value is greater than the line length it defaults back + /// to the line length. + pub character: u32, +} + +impl Position { + pub fn new(line: u32, character: u32) -> Position { + Position { line, character } + } +} + +/// A range in a text document expressed as (zero-based) start and end positions. +/// A range is comparable to a selection in an editor. Therefore the end position is exclusive. +#[derive(Debug, Eq, PartialEq, Copy, Clone, Default, Deserialize, Serialize, Hash)] +pub struct Range { + /// The range's start position. + pub start: Position, + /// The range's end position. + pub end: Position, +} + +impl Range { + pub fn new(start: Position, end: Position) -> Range { + Range { start, end } + } +} + +/// Represents a location inside a resource, such as a line inside a text file. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize, Hash)] +pub struct Location { + pub uri: Url, + pub range: Range, +} + +impl Location { + pub fn new(uri: Url, range: Range) -> Location { + Location { uri, range } + } +} + +/// Represents a link between a source and a target location. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct LocationLink { + /// Span of the origin of this link. + /// + /// Used as the underlined span for mouse interaction. Defaults to the word range at + /// the mouse position. + #[serde(skip_serializing_if = "Option::is_none")] + pub origin_selection_range: Option, + + /// The target resource identifier of this link. + pub target_uri: Url, + + /// The full target range of this link. + pub target_range: Range, + + /// The span of this link. + pub target_selection_range: Range, +} + +/// A type indicating how positions are encoded, +/// specifically what column offsets mean. +/// +/// @since 3.17.0 +#[derive(Debug, Eq, PartialEq, Hash, PartialOrd, Clone, Deserialize, Serialize)] +pub struct PositionEncodingKind(std::borrow::Cow<'static, str>); + +impl PositionEncodingKind { + /// Character offsets count UTF-8 code units. + pub const UTF8: PositionEncodingKind = PositionEncodingKind::new("utf-8"); + + /// Character offsets count UTF-16 code units. + /// + /// This is the default and must always be supported + /// by servers + pub const UTF16: PositionEncodingKind = PositionEncodingKind::new("utf-16"); + + /// Character offsets count UTF-32 code units. + /// + /// Implementation note: these are the same as Unicode code points, + /// so this `PositionEncodingKind` may also be used for an + /// encoding-agnostic representation of character offsets. + pub const UTF32: PositionEncodingKind = PositionEncodingKind::new("utf-32"); + + pub const fn new(tag: &'static str) -> Self { + PositionEncodingKind(std::borrow::Cow::Borrowed(tag)) + } + + pub fn as_str(&self) -> &str { + &self.0 + } +} + +impl From for PositionEncodingKind { + fn from(from: String) -> Self { + PositionEncodingKind(std::borrow::Cow::from(from)) + } +} + +impl From<&'static str> for PositionEncodingKind { + fn from(from: &'static str) -> Self { + PositionEncodingKind::new(from) + } +} + +/// Represents a diagnostic, such as a compiler error or warning. +/// Diagnostic objects are only valid in the scope of a resource. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Diagnostic { + /// The range at which the message applies. + pub range: Range, + + /// The diagnostic's severity. Can be omitted. If omitted it is up to the + /// client to interpret diagnostics as error, warning, info or hint. + #[serde(skip_serializing_if = "Option::is_none")] + pub severity: Option, + + /// The diagnostic's code. Can be omitted. + #[serde(skip_serializing_if = "Option::is_none")] + pub code: Option, + + /// An optional property to describe the error code. + /// + /// @since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub code_description: Option, + + /// A human-readable string describing the source of this + /// diagnostic, e.g. 'typescript' or 'super lint'. + #[serde(skip_serializing_if = "Option::is_none")] + pub source: Option, + + /// The diagnostic's message. + pub message: String, + + /// An array of related diagnostic information, e.g. when symbol-names within + /// a scope collide all definitions can be marked via this property. + #[serde(skip_serializing_if = "Option::is_none")] + pub related_information: Option>, + + /// Additional metadata about the diagnostic. + #[serde(skip_serializing_if = "Option::is_none")] + pub tags: Option>, + + /// A data entry field that is preserved between a `textDocument/publishDiagnostics` + /// notification and `textDocument/codeAction` request. + /// + /// @since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub data: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CodeDescription { + pub href: Url, +} + +impl Diagnostic { + pub fn new( + range: Range, + severity: Option, + code: Option, + source: Option, + message: String, + related_information: Option>, + tags: Option>, + ) -> Diagnostic { + Diagnostic { + range, + severity, + code, + source, + message, + related_information, + tags, + ..Diagnostic::default() + } + } + + pub fn new_simple(range: Range, message: String) -> Diagnostic { + Self::new(range, None, None, None, message, None, None) + } + + pub fn new_with_code_number( + range: Range, + severity: DiagnosticSeverity, + code_number: i32, + source: Option, + message: String, + ) -> Diagnostic { + let code = Some(NumberOrString::Number(code_number)); + Self::new(range, Some(severity), code, source, message, None, None) + } +} + +/// The protocol currently supports the following diagnostic severities: +#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Deserialize, Serialize)] +#[serde(transparent)] +pub struct DiagnosticSeverity(i32); +lsp_enum! { +impl DiagnosticSeverity { + /// Reports an error. + pub const ERROR: DiagnosticSeverity = DiagnosticSeverity(1); + /// Reports a warning. + pub const WARNING: DiagnosticSeverity = DiagnosticSeverity(2); + /// Reports an information. + pub const INFORMATION: DiagnosticSeverity = DiagnosticSeverity(3); + /// Reports a hint. + pub const HINT: DiagnosticSeverity = DiagnosticSeverity(4); +} +} + +/// Represents a related message and source code location for a diagnostic. This +/// should be used to point to code locations that cause or related to a +/// diagnostics, e.g when duplicating a symbol in a scope. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct DiagnosticRelatedInformation { + /// The location of this related diagnostic information. + pub location: Location, + + /// The message of this related diagnostic information. + pub message: String, +} + +/// The diagnostic tags. +#[derive(Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(transparent)] +pub struct DiagnosticTag(i32); +lsp_enum! { +impl DiagnosticTag { + /// Unused or unnecessary code. + /// Clients are allowed to render diagnostics with this tag faded out instead of having + /// an error squiggle. + pub const UNNECESSARY: DiagnosticTag = DiagnosticTag(1); + + /// Deprecated or obsolete code. + /// Clients are allowed to rendered diagnostics with this tag strike through. + pub const DEPRECATED: DiagnosticTag = DiagnosticTag(2); +} +} + +/// Represents a reference to a command. Provides a title which will be used to represent a command in the UI. +/// Commands are identified by a string identifier. The recommended way to handle commands is to implement +/// their execution on the server side if the client and server provides the corresponding capabilities. +/// Alternatively the tool extension code could handle the command. +/// The protocol currently doesn’t specify a set of well-known commands. +#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] +pub struct Command { + /// Title of the command, like `save`. + pub title: String, + /// The identifier of the actual command handler. + pub command: String, + /// Arguments that the command handler should be + /// invoked with. + #[serde(skip_serializing_if = "Option::is_none")] + pub arguments: Option>, +} + +impl Command { + pub fn new(title: String, command: String, arguments: Option>) -> Command { + Command { + title, + command, + arguments, + } + } +} + +/// A textual edit applicable to a text document. +/// +/// If n `TextEdit`s are applied to a text document all text edits describe changes to the initial document version. +/// Execution wise text edits should applied from the bottom to the top of the text document. Overlapping text edits +/// are not supported. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TextEdit { + /// The range of the text document to be manipulated. To insert + /// text into a document create a range where start === end. + pub range: Range, + /// The string to be inserted. For delete operations use an + /// empty string. + pub new_text: String, +} + +impl TextEdit { + pub fn new(range: Range, new_text: String) -> TextEdit { + TextEdit { range, new_text } + } +} + +/// An identifier referring to a change annotation managed by a workspace +/// edit. +/// +/// @since 3.16.0 +pub type ChangeAnnotationIdentifier = String; + +/// A special text edit with an additional change annotation. +/// +/// @since 3.16.0 +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct AnnotatedTextEdit { + #[serde(flatten)] + pub text_edit: TextEdit, + + /// The actual annotation + pub annotation_id: ChangeAnnotationIdentifier, +} + +/// Describes textual changes on a single text document. The text document is referred to as a +/// `OptionalVersionedTextDocumentIdentifier` to allow clients to check the text document version before an +/// edit is applied. A `TextDocumentEdit` describes all changes on a version Si and after they are +/// applied move the document to version Si+1. So the creator of a `TextDocumentEdit` doesn't need to +/// sort the array or do any kind of ordering. However the edits must be non overlapping. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TextDocumentEdit { + /// The text document to change. + pub text_document: OptionalVersionedTextDocumentIdentifier, + + /// The edits to be applied. + /// + /// @since 3.16.0 - support for AnnotatedTextEdit. This is guarded by the + /// client capability `workspace.workspaceEdit.changeAnnotationSupport` + pub edits: Vec>, +} + +/// Additional information that describes document changes. +/// +/// @since 3.16.0 +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ChangeAnnotation { + /// A human-readable string describing the actual change. The string + /// is rendered prominent in the user interface. + pub label: String, + + /// A flag which indicates that user confirmation is needed + /// before applying the change. + #[serde(skip_serializing_if = "Option::is_none")] + pub needs_confirmation: Option, + + /// A human-readable string which is rendered less prominent in + /// the user interface. + #[serde(skip_serializing_if = "Option::is_none")] + pub description: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ChangeAnnotationWorkspaceEditClientCapabilities { + /// Whether the client groups edits with equal labels into tree nodes, + /// for instance all edits labelled with "Changes in Strings" would + /// be a tree node. + #[serde(skip_serializing_if = "Option::is_none")] + pub groups_on_label: Option, +} + +/// Options to create a file. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CreateFileOptions { + /// Overwrite existing file. Overwrite wins over `ignoreIfExists` + #[serde(skip_serializing_if = "Option::is_none")] + pub overwrite: Option, + /// Ignore if exists. + #[serde(skip_serializing_if = "Option::is_none")] + pub ignore_if_exists: Option, +} + +/// Create file operation +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CreateFile { + /// The resource to create. + pub uri: Url, + /// Additional options + #[serde(skip_serializing_if = "Option::is_none")] + pub options: Option, + + /// An optional annotation identifier describing the operation. + /// + /// @since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub annotation_id: Option, +} + +/// Rename file options +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct RenameFileOptions { + /// Overwrite target if existing. Overwrite wins over `ignoreIfExists` + #[serde(skip_serializing_if = "Option::is_none")] + pub overwrite: Option, + /// Ignores if target exists. + #[serde(skip_serializing_if = "Option::is_none")] + pub ignore_if_exists: Option, +} + +/// Rename file operation +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct RenameFile { + /// The old (existing) location. + pub old_uri: Url, + /// The new location. + pub new_uri: Url, + /// Rename options. + #[serde(skip_serializing_if = "Option::is_none")] + pub options: Option, + + /// An optional annotation identifier describing the operation. + /// + /// @since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub annotation_id: Option, +} + +/// Delete file options +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DeleteFileOptions { + /// Delete the content recursively if a folder is denoted. + #[serde(skip_serializing_if = "Option::is_none")] + pub recursive: Option, + /// Ignore the operation if the file doesn't exist. + #[serde(skip_serializing_if = "Option::is_none")] + pub ignore_if_not_exists: Option, + + /// An optional annotation identifier describing the operation. + /// + /// @since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub annotation_id: Option, +} + +/// Delete file operation +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DeleteFile { + /// The file to delete. + pub uri: Url, + /// Delete options. + #[serde(skip_serializing_if = "Option::is_none")] + pub options: Option, +} + +/// A workspace edit represents changes to many resources managed in the workspace. +/// The edit should either provide `changes` or `documentChanges`. +/// If the client can handle versioned document edits and if `documentChanges` are present, +/// the latter are preferred over `changes`. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct WorkspaceEdit { + /// Holds changes to existing resources. + #[serde(with = "url_map")] + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(default)] + pub changes: Option>>, // changes?: { [uri: string]: TextEdit[]; }; + + /// Depending on the client capability `workspace.workspaceEdit.resourceOperations` document changes + /// are either an array of `TextDocumentEdit`s to express changes to n different text documents + /// where each text document edit addresses a specific version of a text document. Or it can contain + /// above `TextDocumentEdit`s mixed with create, rename and delete file / folder operations. + /// + /// Whether a client supports versioned document edits is expressed via + /// `workspace.workspaceEdit.documentChanges` client capability. + /// + /// If a client neither supports `documentChanges` nor `workspace.workspaceEdit.resourceOperations` then + /// only plain `TextEdit`s using the `changes` property are supported. + #[serde(skip_serializing_if = "Option::is_none")] + pub document_changes: Option, + + /// A map of change annotations that can be referenced in + /// `AnnotatedTextEdit`s or create, rename and delete file / folder + /// operations. + /// + /// Whether clients honor this property depends on the client capability + /// `workspace.changeAnnotationSupport`. + /// + /// @since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub change_annotations: Option>, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum DocumentChanges { + Edits(Vec), + Operations(Vec), +} + +// TODO: Once https://github.com/serde-rs/serde/issues/912 is solved +// we can remove ResourceOp and switch to the following implementation +// of DocumentChangeOperation: +// +// #[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +// #[serde(tag = "kind", rename_all="lowercase" )] +// pub enum DocumentChangeOperation { +// Create(CreateFile), +// Rename(RenameFile), +// Delete(DeleteFile), +// +// #[serde(other)] +// Edit(TextDocumentEdit), +// } + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged, rename_all = "lowercase")] +pub enum DocumentChangeOperation { + Op(ResourceOp), + Edit(TextDocumentEdit), +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(tag = "kind", rename_all = "lowercase")] +pub enum ResourceOp { + Create(CreateFile), + Rename(RenameFile), + Delete(DeleteFile), +} + +pub type DidChangeConfigurationClientCapabilities = DynamicRegistrationClientCapabilities; + +#[derive(Debug, Default, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ConfigurationParams { + pub items: Vec, +} + +#[derive(Debug, Default, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ConfigurationItem { + /// The scope to get the configuration section for. + #[serde(skip_serializing_if = "Option::is_none")] + pub scope_uri: Option, + + ///The configuration section asked for. + #[serde(skip_serializing_if = "Option::is_none")] + pub section: Option, +} + +mod url_map { + use std::fmt; + use std::marker::PhantomData; + + use super::*; + + pub fn deserialize<'de, D, V>(deserializer: D) -> Result>, D::Error> + where + D: serde::Deserializer<'de>, + V: de::DeserializeOwned, + { + struct UrlMapVisitor { + _marker: PhantomData, + } + + impl Default for UrlMapVisitor { + fn default() -> Self { + UrlMapVisitor { + _marker: PhantomData, + } + } + } + impl<'de, V: de::DeserializeOwned> de::Visitor<'de> for UrlMapVisitor { + type Value = HashMap; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("map") + } + + fn visit_map(self, mut visitor: M) -> Result + where + M: de::MapAccess<'de>, + { + let mut values = HashMap::with_capacity(visitor.size_hint().unwrap_or(0)); + + // While there are entries remaining in the input, add them + // into our map. + while let Some((key, value)) = visitor.next_entry::()? { + values.insert(key, value); + } + + Ok(values) + } + } + + struct OptionUrlMapVisitor { + _marker: PhantomData, + } + impl Default for OptionUrlMapVisitor { + fn default() -> Self { + OptionUrlMapVisitor { + _marker: PhantomData, + } + } + } + impl<'de, V: de::DeserializeOwned> de::Visitor<'de> for OptionUrlMapVisitor { + type Value = Option>; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("option") + } + + #[inline] + fn visit_unit(self) -> Result + where + E: serde::de::Error, + { + Ok(None) + } + + #[inline] + fn visit_none(self) -> Result + where + E: serde::de::Error, + { + Ok(None) + } + + #[inline] + fn visit_some(self, deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + deserializer + .deserialize_map(UrlMapVisitor::::default()) + .map(Some) + } + } + + // Instantiate our Visitor and ask the Deserializer to drive + // it over the input data, resulting in an instance of MyMap. + deserializer.deserialize_option(OptionUrlMapVisitor::default()) + } + + pub fn serialize( + changes: &Option>, + serializer: S, + ) -> Result + where + S: serde::Serializer, + V: serde::Serialize, + { + use serde::ser::SerializeMap; + + match *changes { + Some(ref changes) => { + let mut map = serializer.serialize_map(Some(changes.len()))?; + for (k, v) in changes { + map.serialize_entry(k.as_str(), v)?; + } + map.end() + } + None => serializer.serialize_none(), + } + } +} + +impl WorkspaceEdit { + pub fn new(changes: HashMap>) -> WorkspaceEdit { + WorkspaceEdit { + changes: Some(changes), + document_changes: None, + ..Default::default() + } + } +} + +/// Text documents are identified using a URI. On the protocol level, URIs are passed as strings. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct TextDocumentIdentifier { + // !!!!!! Note: + // In the spec VersionedTextDocumentIdentifier extends TextDocumentIdentifier + // This modelled by "mixing-in" TextDocumentIdentifier in VersionedTextDocumentIdentifier, + // so any changes to this type must be effected in the sub-type as well. + /// The text document's URI. + pub uri: Url, +} + +impl TextDocumentIdentifier { + pub fn new(uri: Url) -> TextDocumentIdentifier { + TextDocumentIdentifier { uri } + } +} + +/// An item to transfer a text document from the client to the server. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TextDocumentItem { + /// The text document's URI. + pub uri: Url, + + /// The text document's language identifier. + pub language_id: String, + + /// The version number of this document (it will strictly increase after each + /// change, including undo/redo). + pub version: i32, + + /// The content of the opened text document. + pub text: String, +} + +impl TextDocumentItem { + pub fn new(uri: Url, language_id: String, version: i32, text: String) -> TextDocumentItem { + TextDocumentItem { + uri, + language_id, + version, + text, + } + } +} + +/// An identifier to denote a specific version of a text document. This information usually flows from the client to the server. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct VersionedTextDocumentIdentifier { + // This field was "mixed-in" from TextDocumentIdentifier + /// The text document's URI. + pub uri: Url, + + /// The version number of this document. + /// + /// The version number of a document will increase after each change, + /// including undo/redo. The number doesn't need to be consecutive. + pub version: i32, +} + +impl VersionedTextDocumentIdentifier { + pub fn new(uri: Url, version: i32) -> VersionedTextDocumentIdentifier { + VersionedTextDocumentIdentifier { uri, version } + } +} + +/// An identifier which optionally denotes a specific version of a text document. This information usually flows from the server to the client +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct OptionalVersionedTextDocumentIdentifier { + // This field was "mixed-in" from TextDocumentIdentifier + /// The text document's URI. + pub uri: Url, + + /// The version number of this document. If an optional versioned text document + /// identifier is sent from the server to the client and the file is not + /// open in the editor (the server has not received an open notification + /// before) the server can send `null` to indicate that the version is + /// known and the content on disk is the master (as specified with document + /// content ownership). + /// + /// The version number of a document will increase after each change, + /// including undo/redo. The number doesn't need to be consecutive. + pub version: Option, +} + +impl OptionalVersionedTextDocumentIdentifier { + pub fn new(uri: Url, version: i32) -> OptionalVersionedTextDocumentIdentifier { + OptionalVersionedTextDocumentIdentifier { + uri, + version: Some(version), + } + } +} + +/// A parameter literal used in requests to pass a text document and a position inside that document. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TextDocumentPositionParams { + // !!!!!! Note: + // In the spec ReferenceParams extends TextDocumentPositionParams + // This modelled by "mixing-in" TextDocumentPositionParams in ReferenceParams, + // so any changes to this type must be effected in sub-type as well. + /// The text document. + pub text_document: TextDocumentIdentifier, + + /// The position inside the text document. + pub position: Position, +} + +impl TextDocumentPositionParams { + pub fn new( + text_document: TextDocumentIdentifier, + position: Position, + ) -> TextDocumentPositionParams { + TextDocumentPositionParams { + text_document, + position, + } + } +} + +/// A document filter denotes a document through properties like language, schema or pattern. +/// Examples are a filter that applies to TypeScript files on disk or a filter the applies to JSON +/// files with name package.json: +/// +/// { language: 'typescript', scheme: 'file' } +/// { language: 'json', pattern: '**/package.json' } +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct DocumentFilter { + /// A language id, like `typescript`. + #[serde(skip_serializing_if = "Option::is_none")] + pub language: Option, + + /// A Uri [scheme](#Uri.scheme), like `file` or `untitled`. + #[serde(skip_serializing_if = "Option::is_none")] + pub scheme: Option, + + /// A glob pattern, like `*.{ts,js}`. + #[serde(skip_serializing_if = "Option::is_none")] + pub pattern: Option, +} + +/// A document selector is the combination of one or many document filters. +pub type DocumentSelector = Vec; + +// ========================= Actual Protocol ========================= + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize, Default)] +#[serde(rename_all = "camelCase")] +pub struct InitializeParams { + /// The process Id of the parent process that started + /// the server. Is null if the process has not been started by another process. + /// If the parent process is not alive then the server should exit (see exit notification) its process. + pub process_id: Option, + + /// The rootPath of the workspace. Is null + /// if no folder is open. + #[serde(skip_serializing_if = "Option::is_none")] + #[deprecated(note = "Use `root_uri` instead when possible")] + pub root_path: Option, + + /// The rootUri of the workspace. Is null if no + /// folder is open. If both `rootPath` and `rootUri` are set + /// `rootUri` wins. + #[serde(default)] + #[deprecated(note = "Use `workspace_folders` instead when possible")] + pub root_uri: Option, + + /// User provided initialization options. + #[serde(skip_serializing_if = "Option::is_none")] + pub initialization_options: Option, + + /// The capabilities provided by the client (editor or tool) + pub capabilities: ClientCapabilities, + + /// The initial trace setting. If omitted trace is disabled ('off'). + #[serde(default)] + #[serde(skip_serializing_if = "Option::is_none")] + pub trace: Option, + + /// The workspace folders configured in the client when the server starts. + /// This property is only available if the client supports workspace folders. + /// It can be `null` if the client supports workspace folders but none are + /// configured. + #[serde(skip_serializing_if = "Option::is_none")] + pub workspace_folders: Option>, + + /// Information about the client. + #[serde(skip_serializing_if = "Option::is_none")] + pub client_info: Option, + + /// The locale the client is currently showing the user interface + /// in. This must not necessarily be the locale of the operating + /// system. + /// + /// Uses IETF language tags as the value's syntax + /// (See ) + /// + /// @since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub locale: Option, + + /// The LSP server may report about initialization progress to the client + /// by using the following work done token if it was passed by the client. + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +pub struct ClientInfo { + /// The name of the client as defined by the client. + pub name: String, + /// The client's version as defined by the client. + #[serde(skip_serializing_if = "Option::is_none")] + pub version: Option, +} + +#[derive(Debug, PartialEq, Clone, Copy, Deserialize, Serialize)] +pub struct InitializedParams {} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct GenericRegistrationOptions { + #[serde(flatten)] + pub text_document_registration_options: TextDocumentRegistrationOptions, + + #[serde(flatten)] + pub options: GenericOptions, + + #[serde(flatten)] + pub static_registration_options: StaticRegistrationOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct GenericOptions { + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct GenericParams { + #[serde(flatten)] + pub text_document_position_params: TextDocumentPositionParams, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +#[derive(Debug, Eq, PartialEq, Clone, Copy, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DynamicRegistrationClientCapabilities { + /// This capability supports dynamic registration. + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Copy, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct GotoCapability { + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, + + /// The client supports additional metadata in the form of definition links. + #[serde(skip_serializing_if = "Option::is_none")] + pub link_support: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct WorkspaceEditClientCapabilities { + /// The client supports versioned document changes in `WorkspaceEdit`s + #[serde(skip_serializing_if = "Option::is_none")] + pub document_changes: Option, + + /// The resource operations the client supports. Clients should at least + /// support 'create', 'rename' and 'delete' files and folders. + #[serde(skip_serializing_if = "Option::is_none")] + pub resource_operations: Option>, + + /// The failure handling strategy of a client if applying the workspace edit fails. + #[serde(skip_serializing_if = "Option::is_none")] + pub failure_handling: Option, + + /// Whether the client normalizes line endings to the client specific + /// setting. + /// If set to `true` the client will normalize line ending characters + /// in a workspace edit to the client specific new line character(s). + /// + /// @since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub normalizes_line_endings: Option, + + /// Whether the client in general supports change annotations on text edits, + /// create file, rename file and delete file changes. + /// + /// @since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub change_annotation_support: Option, +} + +#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Copy, Clone)] +#[serde(rename_all = "lowercase")] +pub enum ResourceOperationKind { + Create, + Rename, + Delete, +} + +#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Copy, Clone)] +#[serde(rename_all = "camelCase")] +pub enum FailureHandlingKind { + Abort, + Transactional, + TextOnlyTransactional, + Undo, +} + +/// A symbol kind. +#[derive(Eq, PartialEq, Copy, Clone, Serialize, Deserialize)] +#[serde(transparent)] +pub struct SymbolKind(i32); +lsp_enum! { +impl SymbolKind { + pub const FILE: SymbolKind = SymbolKind(1); + pub const MODULE: SymbolKind = SymbolKind(2); + pub const NAMESPACE: SymbolKind = SymbolKind(3); + pub const PACKAGE: SymbolKind = SymbolKind(4); + pub const CLASS: SymbolKind = SymbolKind(5); + pub const METHOD: SymbolKind = SymbolKind(6); + pub const PROPERTY: SymbolKind = SymbolKind(7); + pub const FIELD: SymbolKind = SymbolKind(8); + pub const CONSTRUCTOR: SymbolKind = SymbolKind(9); + pub const ENUM: SymbolKind = SymbolKind(10); + pub const INTERFACE: SymbolKind = SymbolKind(11); + pub const FUNCTION: SymbolKind = SymbolKind(12); + pub const VARIABLE: SymbolKind = SymbolKind(13); + pub const CONSTANT: SymbolKind = SymbolKind(14); + pub const STRING: SymbolKind = SymbolKind(15); + pub const NUMBER: SymbolKind = SymbolKind(16); + pub const BOOLEAN: SymbolKind = SymbolKind(17); + pub const ARRAY: SymbolKind = SymbolKind(18); + pub const OBJECT: SymbolKind = SymbolKind(19); + pub const KEY: SymbolKind = SymbolKind(20); + pub const NULL: SymbolKind = SymbolKind(21); + pub const ENUM_MEMBER: SymbolKind = SymbolKind(22); + pub const STRUCT: SymbolKind = SymbolKind(23); + pub const EVENT: SymbolKind = SymbolKind(24); + pub const OPERATOR: SymbolKind = SymbolKind(25); + pub const TYPE_PARAMETER: SymbolKind = SymbolKind(26); +} +} + +/// Specific capabilities for the `SymbolKind` in the `workspace/symbol` request. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SymbolKindCapability { + /// The symbol kind values the client supports. When this + /// property exists the client also guarantees that it will + /// handle values outside its set gracefully and falls back + /// to a default value when unknown. + /// + /// If this property is not present the client only supports + /// the symbol kinds from `File` to `Array` as defined in + /// the initial version of the protocol. + pub value_set: Option>, +} + +/// Workspace specific client capabilities. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct WorkspaceClientCapabilities { + /// The client supports applying batch edits to the workspace by supporting + /// the request 'workspace/applyEdit' + #[serde(skip_serializing_if = "Option::is_none")] + pub apply_edit: Option, + + /// Capabilities specific to `WorkspaceEdit`s + #[serde(skip_serializing_if = "Option::is_none")] + pub workspace_edit: Option, + + /// Capabilities specific to the `workspace/didChangeConfiguration` notification. + #[serde(skip_serializing_if = "Option::is_none")] + pub did_change_configuration: Option, + + /// Capabilities specific to the `workspace/didChangeWatchedFiles` notification. + #[serde(skip_serializing_if = "Option::is_none")] + pub did_change_watched_files: Option, + + /// Capabilities specific to the `workspace/symbol` request. + #[serde(skip_serializing_if = "Option::is_none")] + pub symbol: Option, + + /// Capabilities specific to the `workspace/executeCommand` request. + #[serde(skip_serializing_if = "Option::is_none")] + pub execute_command: Option, + + /// The client has support for workspace folders. + /// + /// @since 3.6.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub workspace_folders: Option, + + /// The client supports `workspace/configuration` requests. + /// + /// @since 3.6.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub configuration: Option, + + /// Capabilities specific to the semantic token requests scoped to the workspace. + /// + /// @since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub semantic_tokens: Option, + + /// Capabilities specific to the code lens requests scoped to the workspace. + /// + /// @since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub code_lens: Option, + + /// The client has support for file requests/notifications. + /// + /// @since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub file_operations: Option, + + /// Client workspace capabilities specific to inline values. + /// + /// @since 3.17.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub inline_value: Option, + + /// Client workspace capabilities specific to inlay hints. + /// + /// @since 3.17.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub inlay_hint: Option, + + /// Client workspace capabilities specific to diagnostics. + /// since 3.17.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub diagnostic: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TextDocumentSyncClientCapabilities { + /// Whether text document synchronization supports dynamic registration. + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, + + /// The client supports sending will save notifications. + #[serde(skip_serializing_if = "Option::is_none")] + pub will_save: Option, + + /// The client supports sending a will save request and + /// waits for a response providing text edits which will + /// be applied to the document before it is saved. + #[serde(skip_serializing_if = "Option::is_none")] + pub will_save_wait_until: Option, + + /// The client supports did save notifications. + #[serde(skip_serializing_if = "Option::is_none")] + pub did_save: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct PublishDiagnosticsClientCapabilities { + /// Whether the clients accepts diagnostics with related information. + #[serde(skip_serializing_if = "Option::is_none")] + pub related_information: Option, + + /// Client supports the tag property to provide meta data about a diagnostic. + /// Clients supporting tags have to handle unknown tags gracefully. + #[serde( + default, + skip_serializing_if = "Option::is_none", + deserialize_with = "TagSupport::deserialize_compat" + )] + pub tag_support: Option>, + + /// Whether the client interprets the version property of the + /// `textDocument/publishDiagnostics` notification's parameter. + /// + /// @since 3.15.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub version_support: Option, + + /// Client supports a codeDescription property + /// + /// @since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub code_description_support: Option, + + /// Whether code action supports the `data` property which is + /// preserved between a `textDocument/publishDiagnostics` and + /// `textDocument/codeAction` request. + /// + /// @since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub data_support: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TagSupport { + /// The tags supported by the client. + pub value_set: Vec, +} + +impl TagSupport { + /// Support for deserializing a boolean tag Support, in case it's present. + /// + /// This is currently the case for vscode 1.41.1 + fn deserialize_compat<'de, S>(serializer: S) -> Result>, S::Error> + where + S: serde::Deserializer<'de>, + T: serde::Deserialize<'de>, + { + Ok( + match Option::::deserialize(serializer).map_err(serde::de::Error::custom)? { + Some(Value::Bool(false)) => None, + Some(Value::Bool(true)) => Some(TagSupport { value_set: vec![] }), + Some(other) => { + Some(TagSupport::::deserialize(other).map_err(serde::de::Error::custom)?) + } + None => None, + }, + ) + } +} + +/// Text document specific client capabilities. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TextDocumentClientCapabilities { + #[serde(skip_serializing_if = "Option::is_none")] + pub synchronization: Option, + /// Capabilities specific to the `textDocument/completion` + #[serde(skip_serializing_if = "Option::is_none")] + pub completion: Option, + + /// Capabilities specific to the `textDocument/hover` + #[serde(skip_serializing_if = "Option::is_none")] + pub hover: Option, + + /// Capabilities specific to the `textDocument/signatureHelp` + #[serde(skip_serializing_if = "Option::is_none")] + pub signature_help: Option, + + /// Capabilities specific to the `textDocument/references` + #[serde(skip_serializing_if = "Option::is_none")] + pub references: Option, + + /// Capabilities specific to the `textDocument/documentHighlight` + #[serde(skip_serializing_if = "Option::is_none")] + pub document_highlight: Option, + + /// Capabilities specific to the `textDocument/documentSymbol` + #[serde(skip_serializing_if = "Option::is_none")] + pub document_symbol: Option, + /// Capabilities specific to the `textDocument/formatting` + #[serde(skip_serializing_if = "Option::is_none")] + pub formatting: Option, + + /// Capabilities specific to the `textDocument/rangeFormatting` + #[serde(skip_serializing_if = "Option::is_none")] + pub range_formatting: Option, + + /// Capabilities specific to the `textDocument/onTypeFormatting` + #[serde(skip_serializing_if = "Option::is_none")] + pub on_type_formatting: Option, + + /// Capabilities specific to the `textDocument/declaration` + #[serde(skip_serializing_if = "Option::is_none")] + pub declaration: Option, + + /// Capabilities specific to the `textDocument/definition` + #[serde(skip_serializing_if = "Option::is_none")] + pub definition: Option, + + /// Capabilities specific to the `textDocument/typeDefinition` + #[serde(skip_serializing_if = "Option::is_none")] + pub type_definition: Option, + + /// Capabilities specific to the `textDocument/implementation` + #[serde(skip_serializing_if = "Option::is_none")] + pub implementation: Option, + + /// Capabilities specific to the `textDocument/codeAction` + #[serde(skip_serializing_if = "Option::is_none")] + pub code_action: Option, + + /// Capabilities specific to the `textDocument/codeLens` + #[serde(skip_serializing_if = "Option::is_none")] + pub code_lens: Option, + + /// Capabilities specific to the `textDocument/documentLink` + #[serde(skip_serializing_if = "Option::is_none")] + pub document_link: Option, + + /// Capabilities specific to the `textDocument/documentColor` and the + /// `textDocument/colorPresentation` request. + #[serde(skip_serializing_if = "Option::is_none")] + pub color_provider: Option, + + /// Capabilities specific to the `textDocument/rename` + #[serde(skip_serializing_if = "Option::is_none")] + pub rename: Option, + + /// Capabilities specific to `textDocument/publishDiagnostics`. + #[serde(skip_serializing_if = "Option::is_none")] + pub publish_diagnostics: Option, + + /// Capabilities specific to `textDocument/foldingRange` requests. + #[serde(skip_serializing_if = "Option::is_none")] + pub folding_range: Option, + + /// Capabilities specific to the `textDocument/selectionRange` request. + /// + /// @since 3.15.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub selection_range: Option, + + /// Capabilities specific to `textDocument/linkedEditingRange` requests. + /// + /// @since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub linked_editing_range: Option, + + /// Capabilities specific to the various call hierarchy requests. + /// + /// @since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub call_hierarchy: Option, + + /// Capabilities specific to the `textDocument/semanticTokens/*` requests. + #[serde(skip_serializing_if = "Option::is_none")] + pub semantic_tokens: Option, + + /// Capabilities specific to the `textDocument/moniker` request. + /// + /// @since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub moniker: Option, + + /// Capabilities specific to the various type hierarchy requests. + /// + /// @since 3.17.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub type_hierarchy: Option, + + /// Capabilities specific to the `textDocument/inlineValue` request. + /// + /// @since 3.17.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub inline_value: Option, + + /// Capabilities specific to the `textDocument/inlayHint` request. + /// + /// @since 3.17.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub inlay_hint: Option, + + /// Capabilities specific to the diagnostic pull model. + /// + /// @since 3.17.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub diagnostic: Option, + + /// Capabilities specific to the `textDocument/inlineCompletion` request. + /// + /// @since 3.18.0 + #[serde(skip_serializing_if = "Option::is_none")] + #[cfg(feature = "proposed")] + pub inline_completion: Option, +} + +/// Where ClientCapabilities are currently empty: +#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ClientCapabilities { + /// Workspace specific client capabilities. + #[serde(skip_serializing_if = "Option::is_none")] + pub workspace: Option, + + /// Text document specific client capabilities. + #[serde(skip_serializing_if = "Option::is_none")] + pub text_document: Option, + + /// Window specific client capabilities. + #[serde(skip_serializing_if = "Option::is_none")] + pub window: Option, + + /// General client capabilities. + #[serde(skip_serializing_if = "Option::is_none")] + pub general: Option, + + /// Unofficial UT8-offsets extension. + /// + /// See https://clangd.llvm.org/extensions.html#utf-8-offsets. + #[serde(skip_serializing_if = "Option::is_none")] + #[cfg(feature = "proposed")] + pub offset_encoding: Option>, + + /// Experimental client capabilities. + #[serde(skip_serializing_if = "Option::is_none")] + pub experimental: Option, +} + +#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct GeneralClientCapabilities { + /// Client capabilities specific to regular expressions. + /// + /// @since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub regular_expressions: Option, + + /// Client capabilities specific to the client's markdown parser. + /// + /// @since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub markdown: Option, + + /// Client capability that signals how the client handles stale requests (e.g. a request for + /// which the client will not process the response anymore since the information is outdated). + /// + /// @since 3.17.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub stale_request_support: Option, + + /// The position encodings supported by the client. Client and server + /// have to agree on the same position encoding to ensure that offsets + /// (e.g. character position in a line) are interpreted the same on both + /// side. + /// + /// To keep the protocol backwards compatible the following applies: if + /// the value 'utf-16' is missing from the array of position encodings + /// servers can assume that the client supports UTF-16. UTF-16 is + /// therefore a mandatory encoding. + /// + /// If omitted it defaults to ['utf-16']. + /// + /// Implementation considerations: since the conversion from one encoding + /// into another requires the content of the file / line the conversion + /// is best done where the file is read which is usually on the server + /// side. + /// + /// @since 3.17.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub position_encodings: Option>, +} + +/// Client capability that signals how the client +/// handles stale requests (e.g. a request +/// for which the client will not process the response +/// anymore since the information is outdated). +/// +/// @since 3.17.0 +#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct StaleRequestSupportClientCapabilities { + /// The client will actively cancel the request. + pub cancel: bool, + + /// The list of requests for which the client + /// will retry the request if it receives a + /// response with error code `ContentModified`` + pub retry_on_content_modified: Vec, +} + +#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct RegularExpressionsClientCapabilities { + /// The engine's name. + pub engine: String, + + /// The engine's version + #[serde(skip_serializing_if = "Option::is_none")] + pub version: Option, +} + +#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct MarkdownClientCapabilities { + /// The name of the parser. + pub parser: String, + + /// The version of the parser. + #[serde(skip_serializing_if = "Option::is_none")] + pub version: Option, + + /// A list of HTML tags that the client allows / supports in + /// Markdown. + /// + /// @since 3.17.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub allowed_tags: Option>, +} + +#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct InitializeResult { + /// The capabilities the language server provides. + pub capabilities: ServerCapabilities, + + /// Information about the server. + #[serde(skip_serializing_if = "Option::is_none")] + pub server_info: Option, + + /// Unofficial UT8-offsets extension. + /// + /// See https://clangd.llvm.org/extensions.html#utf-8-offsets. + #[serde(skip_serializing_if = "Option::is_none")] + #[cfg(feature = "proposed")] + pub offset_encoding: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +pub struct ServerInfo { + /// The name of the server as defined by the server. + pub name: String, + /// The servers's version as defined by the server. + #[serde(skip_serializing_if = "Option::is_none")] + pub version: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +pub struct InitializeError { + /// Indicates whether the client execute the following retry logic: + /// + /// - (1) show the message provided by the ResponseError to the user + /// - (2) user selects retry or cancel + /// - (3) if user selected retry the initialize method is sent again. + pub retry: bool, +} + +// The server can signal the following capabilities: + +/// Defines how the host (editor) should sync document changes to the language server. +#[derive(Eq, PartialEq, Clone, Copy, Deserialize, Serialize)] +#[serde(transparent)] +pub struct TextDocumentSyncKind(i32); +lsp_enum! { +impl TextDocumentSyncKind { + /// Documents should not be synced at all. + pub const NONE: TextDocumentSyncKind = TextDocumentSyncKind(0); + + /// Documents are synced by always sending the full content of the document. + pub const FULL: TextDocumentSyncKind = TextDocumentSyncKind(1); + + /// Documents are synced by sending the full content on open. After that only + /// incremental updates to the document are sent. + pub const INCREMENTAL: TextDocumentSyncKind = TextDocumentSyncKind(2); +} +} + +pub type ExecuteCommandClientCapabilities = DynamicRegistrationClientCapabilities; + +/// Execute command options. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +pub struct ExecuteCommandOptions { + /// The commands to be executed on the server + pub commands: Vec, + + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, +} + +/// Save options. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SaveOptions { + /// The client is supposed to include the content on save. + #[serde(skip_serializing_if = "Option::is_none")] + pub include_text: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum TextDocumentSyncSaveOptions { + Supported(bool), + SaveOptions(SaveOptions), +} + +impl From for TextDocumentSyncSaveOptions { + fn from(from: SaveOptions) -> Self { + Self::SaveOptions(from) + } +} + +impl From for TextDocumentSyncSaveOptions { + fn from(from: bool) -> Self { + Self::Supported(from) + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TextDocumentSyncOptions { + /// Open and close notifications are sent to the server. + #[serde(skip_serializing_if = "Option::is_none")] + pub open_close: Option, + + /// Change notifications are sent to the server. See TextDocumentSyncKind.None, TextDocumentSyncKind.Full + /// and TextDocumentSyncKindIncremental. + #[serde(skip_serializing_if = "Option::is_none")] + pub change: Option, + + /// Will save notifications are sent to the server. + #[serde(skip_serializing_if = "Option::is_none")] + pub will_save: Option, + + /// Will save wait until requests are sent to the server. + #[serde(skip_serializing_if = "Option::is_none")] + pub will_save_wait_until: Option, + + /// Save notifications are sent to the server. + #[serde(skip_serializing_if = "Option::is_none")] + pub save: Option, +} + +#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum OneOf { + Left(A), + Right(B), +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum TextDocumentSyncCapability { + Kind(TextDocumentSyncKind), + Options(TextDocumentSyncOptions), +} + +impl From for TextDocumentSyncCapability { + fn from(from: TextDocumentSyncOptions) -> Self { + Self::Options(from) + } +} + +impl From for TextDocumentSyncCapability { + fn from(from: TextDocumentSyncKind) -> Self { + Self::Kind(from) + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum ImplementationProviderCapability { + Simple(bool), + Options(StaticTextDocumentRegistrationOptions), +} + +impl From for ImplementationProviderCapability { + fn from(from: StaticTextDocumentRegistrationOptions) -> Self { + Self::Options(from) + } +} + +impl From for ImplementationProviderCapability { + fn from(from: bool) -> Self { + Self::Simple(from) + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum TypeDefinitionProviderCapability { + Simple(bool), + Options(StaticTextDocumentRegistrationOptions), +} + +impl From for TypeDefinitionProviderCapability { + fn from(from: StaticTextDocumentRegistrationOptions) -> Self { + Self::Options(from) + } +} + +impl From for TypeDefinitionProviderCapability { + fn from(from: bool) -> Self { + Self::Simple(from) + } +} + +#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ServerCapabilities { + /// The position encoding the server picked from the encodings offered + /// by the client via the client capability `general.positionEncodings`. + /// + /// If the client didn't provide any position encodings the only valid + /// value that a server can return is 'utf-16'. + /// + /// If omitted it defaults to 'utf-16'. + /// + /// @since 3.17.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub position_encoding: Option, + + /// Defines how text documents are synced. + #[serde(skip_serializing_if = "Option::is_none")] + pub text_document_sync: Option, + + /// Capabilities specific to `textDocument/selectionRange` requests. + #[serde(skip_serializing_if = "Option::is_none")] + pub selection_range_provider: Option, + + /// The server provides hover support. + #[serde(skip_serializing_if = "Option::is_none")] + pub hover_provider: Option, + + /// The server provides completion support. + #[serde(skip_serializing_if = "Option::is_none")] + pub completion_provider: Option, + + /// The server provides signature help support. + #[serde(skip_serializing_if = "Option::is_none")] + pub signature_help_provider: Option, + + /// The server provides goto definition support. + #[serde(skip_serializing_if = "Option::is_none")] + pub definition_provider: Option>, + + /// The server provides goto type definition support. + #[serde(skip_serializing_if = "Option::is_none")] + pub type_definition_provider: Option, + + /// The server provides goto implementation support. + #[serde(skip_serializing_if = "Option::is_none")] + pub implementation_provider: Option, + + /// The server provides find references support. + #[serde(skip_serializing_if = "Option::is_none")] + pub references_provider: Option>, + + /// The server provides document highlight support. + #[serde(skip_serializing_if = "Option::is_none")] + pub document_highlight_provider: Option>, + + /// The server provides document symbol support. + #[serde(skip_serializing_if = "Option::is_none")] + pub document_symbol_provider: Option>, + + /// The server provides workspace symbol support. + #[serde(skip_serializing_if = "Option::is_none")] + pub workspace_symbol_provider: Option>, + + /// The server provides code actions. + #[serde(skip_serializing_if = "Option::is_none")] + pub code_action_provider: Option, + + /// The server provides code lens. + #[serde(skip_serializing_if = "Option::is_none")] + pub code_lens_provider: Option, + + /// The server provides document formatting. + #[serde(skip_serializing_if = "Option::is_none")] + pub document_formatting_provider: Option>, + + /// The server provides document range formatting. + #[serde(skip_serializing_if = "Option::is_none")] + pub document_range_formatting_provider: Option>, + + /// The server provides document formatting on typing. + #[serde(skip_serializing_if = "Option::is_none")] + pub document_on_type_formatting_provider: Option, + + /// The server provides rename support. + #[serde(skip_serializing_if = "Option::is_none")] + pub rename_provider: Option>, + + /// The server provides document link support. + #[serde(skip_serializing_if = "Option::is_none")] + pub document_link_provider: Option, + + /// The server provides color provider support. + #[serde(skip_serializing_if = "Option::is_none")] + pub color_provider: Option, + + /// The server provides folding provider support. + #[serde(skip_serializing_if = "Option::is_none")] + pub folding_range_provider: Option, + + /// The server provides go to declaration support. + #[serde(skip_serializing_if = "Option::is_none")] + pub declaration_provider: Option, + + /// The server provides execute command support. + #[serde(skip_serializing_if = "Option::is_none")] + pub execute_command_provider: Option, + + /// Workspace specific server capabilities + #[serde(skip_serializing_if = "Option::is_none")] + pub workspace: Option, + + /// Call hierarchy provider capabilities. + #[serde(skip_serializing_if = "Option::is_none")] + pub call_hierarchy_provider: Option, + + /// Semantic tokens server capabilities. + #[serde(skip_serializing_if = "Option::is_none")] + pub semantic_tokens_provider: Option, + + /// Whether server provides moniker support. + #[serde(skip_serializing_if = "Option::is_none")] + pub moniker_provider: Option>, + + /// The server provides linked editing range support. + /// + /// @since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub linked_editing_range_provider: Option, + + /// The server provides inline values. + /// + /// @since 3.17.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub inline_value_provider: Option>, + + /// The server provides inlay hints. + /// + /// @since 3.17.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub inlay_hint_provider: Option>, + + /// The server has support for pull model diagnostics. + /// + /// @since 3.17.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub diagnostic_provider: Option, + + /// The server provides inline completions. + /// + /// @since 3.18.0 + #[serde(skip_serializing_if = "Option::is_none")] + #[cfg(feature = "proposed")] + pub inline_completion_provider: Option>, + + /// Experimental server capabilities. + #[serde(skip_serializing_if = "Option::is_none")] + pub experimental: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct WorkspaceServerCapabilities { + /// The server supports workspace folder. + #[serde(skip_serializing_if = "Option::is_none")] + pub workspace_folders: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub file_operations: Option, +} + +/// General parameters to to register for a capability. +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Registration { + /// The id used to register the request. The id can be used to deregister + /// the request again. + pub id: String, + + /// The method / capability to register for. + pub method: String, + + /// Options necessary for the registration. + #[serde(skip_serializing_if = "Option::is_none")] + pub register_options: Option, +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +pub struct RegistrationParams { + pub registrations: Vec, +} + +/// Since most of the registration options require to specify a document selector there is a base +/// interface that can be used. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TextDocumentRegistrationOptions { + /// A document selector to identify the scope of the registration. If set to null + /// the document selector provided on the client side will be used. + pub document_selector: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum DeclarationCapability { + Simple(bool), + RegistrationOptions(DeclarationRegistrationOptions), + Options(DeclarationOptions), +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DeclarationRegistrationOptions { + #[serde(flatten)] + pub declaration_options: DeclarationOptions, + + #[serde(flatten)] + pub text_document_registration_options: TextDocumentRegistrationOptions, + + #[serde(flatten)] + pub static_registration_options: StaticRegistrationOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DeclarationOptions { + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct StaticRegistrationOptions { + #[serde(skip_serializing_if = "Option::is_none")] + pub id: Option, +} + +#[derive(Debug, Default, Eq, PartialEq, Clone, Deserialize, Serialize, Copy)] +#[serde(rename_all = "camelCase")] +pub struct WorkDoneProgressOptions { + #[serde(skip_serializing_if = "Option::is_none")] + pub work_done_progress: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentFormattingOptions { + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentRangeFormattingOptions { + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DefinitionOptions { + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentSymbolOptions { + /// A human-readable string that is shown when multiple outlines trees are + /// shown for the same document. + /// + /// @since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub label: Option, + + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ReferencesOptions { + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentHighlightOptions { + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct WorkspaceSymbolOptions { + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, + + /// The server provides support to resolve additional + /// information for a workspace symbol. + /// + /// @since 3.17.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub resolve_provider: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct StaticTextDocumentRegistrationOptions { + /// A document selector to identify the scope of the registration. If set to null + /// the document selector provided on the client side will be used. + pub document_selector: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub id: Option, +} + +/// General parameters to unregister a capability. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct Unregistration { + /// The id used to unregister the request or notification. Usually an id + /// provided during the register request. + pub id: String, + + /// The method / capability to unregister for. + pub method: String, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct UnregistrationParams { + pub unregisterations: Vec, +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +pub struct DidChangeConfigurationParams { + /// The actual changed settings + pub settings: Value, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DidOpenTextDocumentParams { + /// The document that was opened. + pub text_document: TextDocumentItem, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DidChangeTextDocumentParams { + /// The document that did change. The version number points + /// to the version after all provided content changes have + /// been applied. + pub text_document: VersionedTextDocumentIdentifier, + /// The actual content changes. + pub content_changes: Vec, +} + +/// An event describing a change to a text document. If range and rangeLength are omitted +/// the new text is considered to be the full content of the document. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TextDocumentContentChangeEvent { + /// The range of the document that changed. + #[serde(skip_serializing_if = "Option::is_none")] + pub range: Option, + + /// The length of the range that got replaced. + /// + /// Deprecated: Use range instead + #[serde(skip_serializing_if = "Option::is_none")] + pub range_length: Option, + + /// The new text of the document. + pub text: String, +} + +/// Describe options to be used when registering for text document change events. +/// +/// Extends TextDocumentRegistrationOptions +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TextDocumentChangeRegistrationOptions { + /// A document selector to identify the scope of the registration. If set to null + /// the document selector provided on the client side will be used. + pub document_selector: Option, + + /// How documents are synced to the server. See TextDocumentSyncKind.Full + /// and TextDocumentSyncKindIncremental. + pub sync_kind: i32, +} + +/// The parameters send in a will save text document notification. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct WillSaveTextDocumentParams { + /// The document that will be saved. + pub text_document: TextDocumentIdentifier, + + /// The 'TextDocumentSaveReason'. + pub reason: TextDocumentSaveReason, +} + +/// Represents reasons why a text document is saved. +#[derive(Copy, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(transparent)] +pub struct TextDocumentSaveReason(i32); +lsp_enum! { +impl TextDocumentSaveReason { + /// Manually triggered, e.g. by the user pressing save, by starting debugging, + /// or by an API call. + pub const MANUAL: TextDocumentSaveReason = TextDocumentSaveReason(1); + + /// Automatic after a delay. + pub const AFTER_DELAY: TextDocumentSaveReason = TextDocumentSaveReason(2); + + /// When the editor lost focus. + pub const FOCUS_OUT: TextDocumentSaveReason = TextDocumentSaveReason(3); +} +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DidCloseTextDocumentParams { + /// The document that was closed. + pub text_document: TextDocumentIdentifier, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DidSaveTextDocumentParams { + /// The document that was saved. + pub text_document: TextDocumentIdentifier, + + /// Optional the content when saved. Depends on the includeText value + /// when the save notification was requested. + #[serde(skip_serializing_if = "Option::is_none")] + pub text: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TextDocumentSaveRegistrationOptions { + /// The client is supposed to include the content on save. + #[serde(skip_serializing_if = "Option::is_none")] + pub include_text: Option, + + #[serde(flatten)] + pub text_document_registration_options: TextDocumentRegistrationOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Copy, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DidChangeWatchedFilesClientCapabilities { + /// Did change watched files notification supports dynamic registration. + /// Please note that the current protocol doesn't support static + /// configuration for file changes from the server side. + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, + + /// Whether the client has support for relative patterns + /// or not. + /// + /// @since 3.17.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub relative_pattern_support: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct DidChangeWatchedFilesParams { + /// The actual file events. + pub changes: Vec, +} + +/// The file event type. +#[derive(Eq, PartialEq, Hash, Copy, Clone, Deserialize, Serialize)] +#[serde(transparent)] +pub struct FileChangeType(i32); +lsp_enum! { +impl FileChangeType { + /// The file got created. + pub const CREATED: FileChangeType = FileChangeType(1); + + /// The file got changed. + pub const CHANGED: FileChangeType = FileChangeType(2); + + /// The file got deleted. + pub const DELETED: FileChangeType = FileChangeType(3); +} +} + +/// An event describing a file change. +#[derive(Debug, Eq, Hash, PartialEq, Clone, Deserialize, Serialize)] +pub struct FileEvent { + /// The file's URI. + pub uri: Url, + + /// The change type. + #[serde(rename = "type")] + pub typ: FileChangeType, +} + +impl FileEvent { + pub fn new(uri: Url, typ: FileChangeType) -> FileEvent { + FileEvent { uri, typ } + } +} + +/// Describe options to be used when registered for text document change events. +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Deserialize, Serialize)] +pub struct DidChangeWatchedFilesRegistrationOptions { + /// The watchers to register. + pub watchers: Vec, +} + +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct FileSystemWatcher { + /// The glob pattern to watch. See {@link GlobPattern glob pattern} + /// for more detail. + /// + /// @since 3.17.0 support for relative patterns. + pub glob_pattern: GlobPattern, + + /// The kind of events of interest. If omitted it defaults to WatchKind.Create | + /// WatchKind.Change | WatchKind.Delete which is 7. + #[serde(skip_serializing_if = "Option::is_none")] + pub kind: Option, +} + +/// The glob pattern. Either a string pattern or a relative pattern. +/// +/// @since 3.17.0 +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum GlobPattern { + String(Pattern), + Relative(RelativePattern), +} + +impl From for GlobPattern { + #[inline] + fn from(from: Pattern) -> Self { + Self::String(from) + } +} + +impl From for GlobPattern { + #[inline] + fn from(from: RelativePattern) -> Self { + Self::Relative(from) + } +} + +/// A relative pattern is a helper to construct glob patterns that are matched +/// relatively to a base URI. The common value for a `baseUri` is a workspace +/// folder root, but it can be another absolute URI as well. +/// +/// @since 3.17.0 +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct RelativePattern { + /// A workspace folder or a base URI to which this pattern will be matched + /// against relatively. + pub base_uri: OneOf, + + /// The actual glob pattern. + pub pattern: Pattern, +} + +/// The glob pattern to watch relative to the base path. Glob patterns can have +/// the following syntax: +/// - `*` to match one or more characters in a path segment +/// - `?` to match on one character in a path segment +/// - `**` to match any number of path segments, including none +/// - `{}` to group conditions (e.g. `**​/*.{ts,js}` matches all TypeScript +/// and JavaScript files) +/// - `[]` to declare a range of characters to match in a path segment +/// (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …) +/// - `[!...]` to negate a range of characters to match in a path segment +/// (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, +/// but not `example.0`) +/// +/// @since 3.17.0 +pub type Pattern = String; + +bitflags! { +pub struct WatchKind: u8 { + /// Interested in create events. + const Create = 1; + /// Interested in change events + const Change = 2; + /// Interested in delete events + const Delete = 4; +} +} + +impl<'de> serde::Deserialize<'de> for WatchKind { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let i = u8::deserialize(deserializer)?; + WatchKind::from_bits(i).ok_or_else(|| { + D::Error::invalid_value(de::Unexpected::Unsigned(u64::from(i)), &"Unknown flag") + }) + } +} + +impl serde::Serialize for WatchKind { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + serializer.serialize_u8(self.bits()) + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct PublishDiagnosticsParams { + /// The URI for which diagnostic information is reported. + pub uri: Url, + + /// An array of diagnostic information items. + pub diagnostics: Vec, + + /// Optional the version number of the document the diagnostics are published for. + #[serde(skip_serializing_if = "Option::is_none")] + pub version: Option, +} + +impl PublishDiagnosticsParams { + pub fn new( + uri: Url, + diagnostics: Vec, + version: Option, + ) -> PublishDiagnosticsParams { + PublishDiagnosticsParams { + uri, + diagnostics, + version, + } + } +} + +#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Clone)] +#[serde(untagged)] +pub enum Documentation { + String(String), + MarkupContent(MarkupContent), +} + +/// MarkedString can be used to render human readable text. It is either a +/// markdown string or a code-block that provides a language and a code snippet. +/// The language identifier is semantically equal to the optional language +/// identifier in fenced code blocks in GitHub issues. +/// +/// The pair of a language and a value is an equivalent to markdown: +/// +/// ```${language} +/// ${value} +/// ``` +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum MarkedString { + String(String), + LanguageString(LanguageString), +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct LanguageString { + pub language: String, + pub value: String, +} + +impl MarkedString { + pub fn from_markdown(markdown: String) -> MarkedString { + MarkedString::String(markdown) + } + + pub fn from_language_code(language: String, code_block: String) -> MarkedString { + MarkedString::LanguageString(LanguageString { + language, + value: code_block, + }) + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct GotoDefinitionParams { + #[serde(flatten)] + pub text_document_position_params: TextDocumentPositionParams, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +/// GotoDefinition response can be single location, or multiple Locations or a link. +#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] +#[serde(untagged)] +pub enum GotoDefinitionResponse { + Scalar(Location), + Array(Vec), + Link(Vec), +} + +impl From for GotoDefinitionResponse { + fn from(location: Location) -> Self { + GotoDefinitionResponse::Scalar(location) + } +} + +impl From> for GotoDefinitionResponse { + fn from(locations: Vec) -> Self { + GotoDefinitionResponse::Array(locations) + } +} + +impl From> for GotoDefinitionResponse { + fn from(locations: Vec) -> Self { + GotoDefinitionResponse::Link(locations) + } +} + +#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] +pub struct ExecuteCommandParams { + /// The identifier of the actual command handler. + pub command: String, + /// Arguments that the command should be invoked with. + #[serde(default)] + pub arguments: Vec, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, +} + +/// Execute command registration options. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct ExecuteCommandRegistrationOptions { + /// The commands to be executed on the server + pub commands: Vec, + + #[serde(flatten)] + pub execute_command_options: ExecuteCommandOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ApplyWorkspaceEditParams { + /// An optional label of the workspace edit. This label is + /// presented in the user interface for example on an undo + /// stack to undo the workspace edit. + #[serde(skip_serializing_if = "Option::is_none")] + pub label: Option, + + /// The edits to apply. + pub edit: WorkspaceEdit, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ApplyWorkspaceEditResponse { + /// Indicates whether the edit was applied or not. + pub applied: bool, + + /// An optional textual description for why the edit was not applied. + /// This may be used may be used by the server for diagnostic + /// logging or to provide a suitable error for a request that + /// triggered the edit + #[serde(skip_serializing_if = "Option::is_none")] + pub failure_reason: Option, + + /// Depending on the client's failure handling strategy `failedChange` might + /// contain the index of the change that failed. This property is only available + /// if the client signals a `failureHandlingStrategy` in its client capabilities. + #[serde(skip_serializing_if = "Option::is_none")] + pub failed_change: Option, +} + +/// Describes the content type that a client supports in various +/// result literals like `Hover`, `ParameterInfo` or `CompletionItem`. +/// +/// Please note that `MarkupKinds` must not start with a `$`. This kinds +/// are reserved for internal usage. +#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Clone)] +#[serde(rename_all = "lowercase")] +pub enum MarkupKind { + /// Plain text is supported as a content format + PlainText, + /// Markdown is supported as a content format + Markdown, +} + +/// A `MarkupContent` literal represents a string value which content can be represented in different formats. +/// Currently `plaintext` and `markdown` are supported formats. A `MarkupContent` is usually used in +/// documentation properties of result literals like `CompletionItem` or `SignatureInformation`. +/// If the format is `markdown` the content should follow the [GitHub Flavored Markdown Specification](https://github.github.com/gfm/). +/// +/// Here is an example how such a string can be constructed using JavaScript / TypeScript: +/// +/// ```ignore +/// let markdown: MarkupContent = { +/// kind: MarkupKind::Markdown, +/// value: [ +/// "# Header", +/// "Some text", +/// "```typescript", +/// "someCode();", +/// "```" +/// ] +/// .join("\n"), +/// }; +/// ``` +/// +/// Please *Note* that clients might sanitize the return markdown. A client could decide to +/// remove HTML from the markdown to avoid script execution. +#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Clone)] +pub struct MarkupContent { + pub kind: MarkupKind, + pub value: String, +} + +/// A parameter literal used to pass a partial result token. +#[derive(Debug, Eq, PartialEq, Default, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct PartialResultParams { + #[serde(skip_serializing_if = "Option::is_none")] + pub partial_result_token: Option, +} + +/// Symbol tags are extra annotations that tweak the rendering of a symbol. +/// +/// @since 3.16.0 +#[derive(Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(transparent)] +pub struct SymbolTag(i32); +lsp_enum! { +impl SymbolTag { + /// Render a symbol as obsolete, usually using a strike-out. + pub const DEPRECATED: SymbolTag = SymbolTag(1); +} +} + +#[cfg(test)] +mod tests { + use serde::{Deserialize, Serialize}; + + use super::*; + + pub(crate) fn test_serialization(ms: &SER, expected: &str) + where + SER: Serialize + for<'de> Deserialize<'de> + PartialEq + std::fmt::Debug, + { + let json_str = serde_json::to_string(ms).unwrap(); + assert_eq!(&json_str, expected); + let deserialized: SER = serde_json::from_str(&json_str).unwrap(); + assert_eq!(&deserialized, ms); + } + + pub(crate) fn test_deserialization(json: &str, expected: &T) + where + T: for<'de> Deserialize<'de> + PartialEq + std::fmt::Debug, + { + let value = serde_json::from_str::(json).unwrap(); + assert_eq!(&value, expected); + } + + #[test] + fn one_of() { + test_serialization(&OneOf::::Left(true), r#"true"#); + test_serialization(&OneOf::::Left("abcd".into()), r#""abcd""#); + test_serialization( + &OneOf::::Right(WorkDoneProgressOptions { + work_done_progress: Some(false), + }), + r#"{"workDoneProgress":false}"#, + ); + } + + #[test] + fn number_or_string() { + test_serialization(&NumberOrString::Number(123), r#"123"#); + + test_serialization(&NumberOrString::String("abcd".into()), r#""abcd""#); + } + + #[test] + fn marked_string() { + test_serialization(&MarkedString::from_markdown("xxx".into()), r#""xxx""#); + + test_serialization( + &MarkedString::from_language_code("lang".into(), "code".into()), + r#"{"language":"lang","value":"code"}"#, + ); + } + + #[test] + fn language_string() { + test_serialization( + &LanguageString { + language: "LL".into(), + value: "VV".into(), + }, + r#"{"language":"LL","value":"VV"}"#, + ); + } + + #[test] + fn workspace_edit() { + test_serialization( + &WorkspaceEdit { + changes: Some(vec![].into_iter().collect()), + document_changes: None, + ..Default::default() + }, + r#"{"changes":{}}"#, + ); + + test_serialization( + &WorkspaceEdit { + changes: None, + document_changes: None, + ..Default::default() + }, + r#"{}"#, + ); + + test_serialization( + &WorkspaceEdit { + changes: Some( + vec![(Url::parse("file://test").unwrap(), vec![])] + .into_iter() + .collect(), + ), + document_changes: None, + ..Default::default() + }, + r#"{"changes":{"file://test/":[]}}"#, + ); + } + + #[test] + fn root_uri_can_be_missing() { + serde_json::from_str::(r#"{ "capabilities": {} }"#).unwrap(); + } + + #[test] + fn test_watch_kind() { + test_serialization(&WatchKind::Create, "1"); + test_serialization(&(WatchKind::Create | WatchKind::Change), "3"); + test_serialization( + &(WatchKind::Create | WatchKind::Change | WatchKind::Delete), + "7", + ); + } + + #[test] + fn test_resource_operation_kind() { + test_serialization( + &vec![ + ResourceOperationKind::Create, + ResourceOperationKind::Rename, + ResourceOperationKind::Delete, + ], + r#"["create","rename","delete"]"#, + ); + } +} diff --git a/vendor/lsp-types/src/linked_editing.rs b/vendor/lsp-types/src/linked_editing.rs new file mode 100644 index 00000000..b23fb141 --- /dev/null +++ b/vendor/lsp-types/src/linked_editing.rs @@ -0,0 +1,61 @@ +use serde::{Deserialize, Serialize}; + +use crate::{ + DynamicRegistrationClientCapabilities, Range, StaticRegistrationOptions, + TextDocumentPositionParams, TextDocumentRegistrationOptions, WorkDoneProgressOptions, + WorkDoneProgressParams, +}; + +pub type LinkedEditingRangeClientCapabilities = DynamicRegistrationClientCapabilities; + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct LinkedEditingRangeOptions { + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct LinkedEditingRangeRegistrationOptions { + #[serde(flatten)] + pub text_document_registration_options: TextDocumentRegistrationOptions, + + #[serde(flatten)] + pub linked_editing_range_options: LinkedEditingRangeOptions, + + #[serde(flatten)] + pub static_registration_options: StaticRegistrationOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum LinkedEditingRangeServerCapabilities { + Simple(bool), + Options(LinkedEditingRangeOptions), + RegistrationOptions(LinkedEditingRangeRegistrationOptions), +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct LinkedEditingRangeParams { + #[serde(flatten)] + pub text_document_position_params: TextDocumentPositionParams, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct LinkedEditingRanges { + /// A list of ranges that can be renamed together. The ranges must have + /// identical length and contain identical text content. The ranges cannot overlap. + pub ranges: Vec, + + /// An optional word pattern (regular expression) that describes valid contents for + /// the given ranges. If no pattern is provided, the client configuration's word + /// pattern will be used. + #[serde(skip_serializing_if = "Option::is_none")] + pub word_pattern: Option, +} diff --git a/vendor/lsp-types/src/lsif.rs b/vendor/lsp-types/src/lsif.rs new file mode 100644 index 00000000..be6df6e5 --- /dev/null +++ b/vendor/lsp-types/src/lsif.rs @@ -0,0 +1,336 @@ +//! Types of Language Server Index Format (LSIF). LSIF is a standard format +//! for language servers or other programming tools to dump their knowledge +//! about a workspace. +//! +//! Based on + +use crate::{Range, Url}; +use serde::{Deserialize, Serialize}; + +pub type Id = crate::NumberOrString; + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[serde(untagged)] +pub enum LocationOrRangeId { + Location(crate::Location), + RangeId(Id), +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Entry { + pub id: Id, + #[serde(flatten)] + pub data: Element, +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +#[serde(tag = "type")] +pub enum Element { + Vertex(Vertex), + Edge(Edge), +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +pub struct ToolInfo { + pub name: String, + #[serde(default = "Default::default")] + #[serde(skip_serializing_if = "Vec::is_empty")] + pub args: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + pub version: Option, +} + +#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, Copy)] +pub enum Encoding { + /// Currently only 'utf-16' is supported due to the limitations in LSP. + #[serde(rename = "utf-16")] + Utf16, +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +pub struct RangeBasedDocumentSymbol { + pub id: Id, + #[serde(default = "Default::default")] + #[serde(skip_serializing_if = "Vec::is_empty")] + pub children: Vec, +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +#[serde(untagged)] +pub enum DocumentSymbolOrRangeBasedVec { + DocumentSymbol(Vec), + RangeBased(Vec), +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct DefinitionTag { + /// The text covered by the range + text: String, + /// The symbol kind. + kind: crate::SymbolKind, + /// Indicates if this symbol is deprecated. + #[serde(default)] + #[serde(skip_serializing_if = "std::ops::Not::not")] + deprecated: bool, + /// The full range of the definition not including leading/trailing whitespace but everything else, e.g comments and code. + /// The range must be included in fullRange. + full_range: Range, + /// Optional detail information for the definition. + #[serde(skip_serializing_if = "Option::is_none")] + detail: Option, +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct DeclarationTag { + /// The text covered by the range + text: String, + /// The symbol kind. + kind: crate::SymbolKind, + /// Indicates if this symbol is deprecated. + #[serde(default)] + deprecated: bool, + /// The full range of the definition not including leading/trailing whitespace but everything else, e.g comments and code. + /// The range must be included in fullRange. + full_range: Range, + /// Optional detail information for the definition. + #[serde(skip_serializing_if = "Option::is_none")] + detail: Option, +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ReferenceTag { + text: String, +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct UnknownTag { + text: String, +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +#[serde(tag = "type")] +pub enum RangeTag { + Definition(DefinitionTag), + Declaration(DeclarationTag), + Reference(ReferenceTag), + Unknown(UnknownTag), +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +#[serde(tag = "label")] +pub enum Vertex { + MetaData(MetaData), + /// + Project(Project), + Document(Document), + /// + Range { + #[serde(flatten)] + range: Range, + #[serde(skip_serializing_if = "Option::is_none")] + tag: Option, + }, + /// + ResultSet(ResultSet), + Moniker(crate::Moniker), + PackageInformation(PackageInformation), + + #[serde(rename = "$event")] + Event(Event), + + DefinitionResult, + DeclarationResult, + TypeDefinitionResult, + ReferenceResult, + ImplementationResult, + FoldingRangeResult { + result: Vec, + }, + HoverResult { + result: crate::Hover, + }, + DocumentSymbolResult { + result: DocumentSymbolOrRangeBasedVec, + }, + DocumentLinkResult { + result: Vec, + }, + DiagnosticResult { + result: Vec, + }, +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub enum EventKind { + Begin, + End, +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub enum EventScope { + Document, + Project, +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +pub struct Event { + pub kind: EventKind, + pub scope: EventScope, + pub data: Id, +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +#[serde(tag = "label")] +pub enum Edge { + Contains(EdgeDataMultiIn), + Moniker(EdgeData), + NextMoniker(EdgeData), + Next(EdgeData), + PackageInformation(EdgeData), + Item(Item), + + // Methods + #[serde(rename = "textDocument/definition")] + Definition(EdgeData), + #[serde(rename = "textDocument/declaration")] + Declaration(EdgeData), + #[serde(rename = "textDocument/hover")] + Hover(EdgeData), + #[serde(rename = "textDocument/references")] + References(EdgeData), + #[serde(rename = "textDocument/implementation")] + Implementation(EdgeData), + #[serde(rename = "textDocument/typeDefinition")] + TypeDefinition(EdgeData), + #[serde(rename = "textDocument/foldingRange")] + FoldingRange(EdgeData), + #[serde(rename = "textDocument/documentLink")] + DocumentLink(EdgeData), + #[serde(rename = "textDocument/documentSymbol")] + DocumentSymbol(EdgeData), + #[serde(rename = "textDocument/diagnostic")] + Diagnostic(EdgeData), +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct EdgeData { + pub in_v: Id, + pub out_v: Id, +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct EdgeDataMultiIn { + pub in_vs: Vec, + pub out_v: Id, +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[serde(untagged)] +pub enum DefinitionResultType { + Scalar(LocationOrRangeId), + Array(LocationOrRangeId), +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub enum ItemKind { + Declarations, + Definitions, + References, + ReferenceResults, + ImplementationResults, +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Item { + pub document: Id, + #[serde(skip_serializing_if = "Option::is_none")] + pub property: Option, + #[serde(flatten)] + pub edge_data: EdgeDataMultiIn, +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Document { + pub uri: Url, + pub language_id: String, +} + +/// +#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ResultSet { + #[serde(skip_serializing_if = "Option::is_none")] + pub key: Option, +} + +/// +#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Project { + #[serde(skip_serializing_if = "Option::is_none")] + pub resource: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub content: Option, + pub kind: String, +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct MetaData { + /// The version of the LSIF format using semver notation. See . Please note + /// the version numbers starting with 0 don't adhere to semver and adopters have to assume + /// that each new version is breaking. + pub version: String, + + /// The project root (in form of an URI) used to compute this dump. + pub project_root: Url, + + /// The string encoding used to compute line and character values in + /// positions and ranges. + pub position_encoding: Encoding, + + /// Information about the tool that created the dump + #[serde(skip_serializing_if = "Option::is_none")] + pub tool_info: Option, +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Repository { + pub r#type: String, + pub url: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub commit_id: Option, +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PackageInformation { + pub name: String, + pub manager: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub uri: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub content: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub repository: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub version: Option, +} diff --git a/vendor/lsp-types/src/moniker.rs b/vendor/lsp-types/src/moniker.rs new file mode 100644 index 00000000..74bf8955 --- /dev/null +++ b/vendor/lsp-types/src/moniker.rs @@ -0,0 +1,92 @@ +use serde::{Deserialize, Serialize}; + +use crate::{ + DynamicRegistrationClientCapabilities, PartialResultParams, TextDocumentPositionParams, + TextDocumentRegistrationOptions, WorkDoneProgressOptions, WorkDoneProgressParams, +}; + +pub type MonikerClientCapabilities = DynamicRegistrationClientCapabilities; + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum MonikerServerCapabilities { + Options(MonikerOptions), + RegistrationOptions(MonikerRegistrationOptions), +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct MonikerOptions { + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct MonikerRegistrationOptions { + #[serde(flatten)] + pub text_document_registration_options: TextDocumentRegistrationOptions, + + #[serde(flatten)] + pub moniker_options: MonikerOptions, +} + +/// Moniker uniqueness level to define scope of the moniker. +#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Copy, Clone)] +#[serde(rename_all = "camelCase")] +pub enum UniquenessLevel { + /// The moniker is only unique inside a document + Document, + /// The moniker is unique inside a project for which a dump got created + Project, + /// The moniker is unique inside the group to which a project belongs + Group, + /// The moniker is unique inside the moniker scheme. + Scheme, + /// The moniker is globally unique + Global, +} + +/// The moniker kind. +#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Copy, Clone)] +#[serde(rename_all = "camelCase")] +pub enum MonikerKind { + /// The moniker represent a symbol that is imported into a project + Import, + /// The moniker represent a symbol that is exported into a project + Export, + /// The moniker represents a symbol that is local to a project (e.g. a local + /// variable of a function, a class not visible outside the project, ...) + Local, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct MonikerParams { + #[serde(flatten)] + pub text_document_position_params: TextDocumentPositionParams, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +/// Moniker definition to match LSIF 0.5 moniker definition. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Moniker { + /// The scheme of the moniker. For example tsc or .Net + pub scheme: String, + + /// The identifier of the moniker. The value is opaque in LSIF however + /// schema owners are allowed to define the structure if they want. + pub identifier: String, + + /// The scope in which the moniker is unique + pub unique: UniquenessLevel, + + /// The moniker kind if known. + #[serde(skip_serializing_if = "Option::is_none")] + pub kind: Option, +} diff --git a/vendor/lsp-types/src/notification.rs b/vendor/lsp-types/src/notification.rs new file mode 100644 index 00000000..aef011d3 --- /dev/null +++ b/vendor/lsp-types/src/notification.rs @@ -0,0 +1,361 @@ +use super::*; + +use serde::{de::DeserializeOwned, Serialize}; + +pub trait Notification { + type Params: DeserializeOwned + Serialize + Send + Sync + 'static; + const METHOD: &'static str; +} + +#[macro_export] +macro_rules! lsp_notification { + ("$/cancelRequest") => { + $crate::notification::Cancel + }; + ("$/setTrace") => { + $crate::notification::SetTrace + }; + ("$/logTrace") => { + $crate::notification::LogTrace + }; + ("initialized") => { + $crate::notification::Initialized + }; + ("exit") => { + $crate::notification::Exit + }; + + ("window/showMessage") => { + $crate::notification::ShowMessage + }; + ("window/logMessage") => { + $crate::notification::LogMessage + }; + ("window/workDoneProgress/cancel") => { + $crate::notification::WorkDoneProgressCancel + }; + + ("telemetry/event") => { + $crate::notification::TelemetryEvent + }; + + ("textDocument/didOpen") => { + $crate::notification::DidOpenTextDocument + }; + ("textDocument/didChange") => { + $crate::notification::DidChangeTextDocument + }; + ("textDocument/willSave") => { + $crate::notification::WillSaveTextDocument + }; + ("textDocument/didSave") => { + $crate::notification::DidSaveTextDocument + }; + ("textDocument/didClose") => { + $crate::notification::DidCloseTextDocument + }; + ("textDocument/publishDiagnostics") => { + $crate::notification::PublishDiagnostics + }; + + ("workspace/didChangeConfiguration") => { + $crate::notification::DidChangeConfiguration + }; + ("workspace/didChangeWatchedFiles") => { + $crate::notification::DidChangeWatchedFiles + }; + ("workspace/didChangeWorkspaceFolders") => { + $crate::notification::DidChangeWorkspaceFolders + }; + ("$/progress") => { + $crate::notification::Progress + }; + ("workspace/didCreateFiles") => { + $crate::notification::DidCreateFiles + }; + ("workspace/didRenameFiles") => { + $crate::notification::DidRenameFiles + }; + ("workspace/didDeleteFiles") => { + $crate::notification::DidDeleteFiles + }; +} + +/// The base protocol now offers support for request cancellation. To cancel a request, +/// a notification message with the following properties is sent: +/// +/// A request that got canceled still needs to return from the server and send a response back. +/// It can not be left open / hanging. This is in line with the JSON RPC protocol that requires +/// that every request sends a response back. In addition it allows for returning partial results on cancel. +#[derive(Debug)] +pub enum Cancel {} + +impl Notification for Cancel { + type Params = CancelParams; + const METHOD: &'static str = "$/cancelRequest"; +} + +/// A notification that should be used by the client to modify the trace +/// setting of the server. +#[derive(Debug)] +pub enum SetTrace {} + +impl Notification for SetTrace { + type Params = SetTraceParams; + const METHOD: &'static str = "$/setTrace"; +} + +/// A notification to log the trace of the server’s execution. +/// The amount and content of these notifications depends on the current trace configuration. +/// +/// `LogTrace` should be used for systematic trace reporting. For single debugging messages, +/// the server should send `LogMessage` notifications. +#[derive(Debug)] +pub enum LogTrace {} + +impl Notification for LogTrace { + type Params = LogTraceParams; + const METHOD: &'static str = "$/logTrace"; +} + +/// The initialized notification is sent from the client to the server after the client received +/// the result of the initialize request but before the client is sending any other request or +/// notification to the server. The server can use the initialized notification for example to +/// dynamically register capabilities. +#[derive(Debug)] +pub enum Initialized {} + +impl Notification for Initialized { + type Params = InitializedParams; + const METHOD: &'static str = "initialized"; +} + +/// A notification to ask the server to exit its process. +/// The server should exit with success code 0 if the shutdown request has been received before; +/// otherwise with error code 1. +#[derive(Debug)] +pub enum Exit {} + +impl Notification for Exit { + type Params = (); + const METHOD: &'static str = "exit"; +} + +/// The show message notification is sent from a server to a client to ask the client to display a particular message +/// in the user interface. +#[derive(Debug)] +pub enum ShowMessage {} + +impl Notification for ShowMessage { + type Params = ShowMessageParams; + const METHOD: &'static str = "window/showMessage"; +} + +/// The log message notification is sent from the server to the client to ask the client to log a particular message. +#[derive(Debug)] +pub enum LogMessage {} + +impl Notification for LogMessage { + type Params = LogMessageParams; + const METHOD: &'static str = "window/logMessage"; +} + +/// The telemetry notification is sent from the server to the client to ask the client to log a telemetry event. +/// The protocol doesn't specify the payload since no interpretation of the data happens in the protocol. Most clients even don't handle +/// the event directly but forward them to the extensions owning the corresponding server issuing the event. +#[derive(Debug)] +pub enum TelemetryEvent {} + +impl Notification for TelemetryEvent { + type Params = OneOf; + const METHOD: &'static str = "telemetry/event"; +} + +/// A notification sent from the client to the server to signal the change of configuration settings. +#[derive(Debug)] +pub enum DidChangeConfiguration {} + +impl Notification for DidChangeConfiguration { + type Params = DidChangeConfigurationParams; + const METHOD: &'static str = "workspace/didChangeConfiguration"; +} + +/// The document open notification is sent from the client to the server to signal newly opened text documents. +/// The document's truth is now managed by the client and the server must not try to read the document's truth +/// using the document's uri. +#[derive(Debug)] +pub enum DidOpenTextDocument {} + +impl Notification for DidOpenTextDocument { + type Params = DidOpenTextDocumentParams; + const METHOD: &'static str = "textDocument/didOpen"; +} + +/// The document change notification is sent from the client to the server to signal changes to a text document. +/// In 2.0 the shape of the params has changed to include proper version numbers and language ids. +#[derive(Debug)] +pub enum DidChangeTextDocument {} + +impl Notification for DidChangeTextDocument { + type Params = DidChangeTextDocumentParams; + const METHOD: &'static str = "textDocument/didChange"; +} + +/// The document will save notification is sent from the client to the server before the document +/// is actually saved. +#[derive(Debug)] +pub enum WillSaveTextDocument {} + +impl Notification for WillSaveTextDocument { + type Params = WillSaveTextDocumentParams; + const METHOD: &'static str = "textDocument/willSave"; +} + +/// The document close notification is sent from the client to the server when the document got closed in the client. +/// The document's truth now exists where the document's uri points to (e.g. if the document's uri is a file uri +/// the truth now exists on disk). +#[derive(Debug)] +pub enum DidCloseTextDocument {} + +impl Notification for DidCloseTextDocument { + type Params = DidCloseTextDocumentParams; + const METHOD: &'static str = "textDocument/didClose"; +} + +/// The document save notification is sent from the client to the server when the document was saved in the client. +#[derive(Debug)] +pub enum DidSaveTextDocument {} + +impl Notification for DidSaveTextDocument { + type Params = DidSaveTextDocumentParams; + const METHOD: &'static str = "textDocument/didSave"; +} + +/// The watched files notification is sent from the client to the server when the client detects changes to files and folders +/// watched by the language client (note although the name suggest that only file events are sent it is about file system events which include folders as well). +/// It is recommended that servers register for these file system events using the registration mechanism. +/// In former implementations clients pushed file events without the server actively asking for it. +#[derive(Debug)] +pub enum DidChangeWatchedFiles {} + +impl Notification for DidChangeWatchedFiles { + type Params = DidChangeWatchedFilesParams; + const METHOD: &'static str = "workspace/didChangeWatchedFiles"; +} + +/// The workspace/didChangeWorkspaceFolders notification is sent from the client to the server to inform the server +/// about workspace folder configuration changes +#[derive(Debug)] +pub enum DidChangeWorkspaceFolders {} + +impl Notification for DidChangeWorkspaceFolders { + type Params = DidChangeWorkspaceFoldersParams; + const METHOD: &'static str = "workspace/didChangeWorkspaceFolders"; +} + +/// Diagnostics notification are sent from the server to the client to signal results of validation runs. +#[derive(Debug)] +pub enum PublishDiagnostics {} + +impl Notification for PublishDiagnostics { + type Params = PublishDiagnosticsParams; + const METHOD: &'static str = "textDocument/publishDiagnostics"; +} + +/// The progress notification is sent from the server to the client to ask +/// the client to indicate progress. +#[derive(Debug)] +pub enum Progress {} + +impl Notification for Progress { + type Params = ProgressParams; + const METHOD: &'static str = "$/progress"; +} + +/// The `window/workDoneProgress/cancel` notification is sent from the client +/// to the server to cancel a progress initiated on the server side using the `window/workDoneProgress/create`. +#[derive(Debug)] +pub enum WorkDoneProgressCancel {} + +impl Notification for WorkDoneProgressCancel { + type Params = WorkDoneProgressCancelParams; + const METHOD: &'static str = "window/workDoneProgress/cancel"; +} + +/// The did create files notification is sent from the client to the server when files were created from within the client. +#[derive(Debug)] +pub enum DidCreateFiles {} + +impl Notification for DidCreateFiles { + type Params = CreateFilesParams; + const METHOD: &'static str = "workspace/didCreateFiles"; +} + +/// The did rename files notification is sent from the client to the server when files were renamed from within the client. +#[derive(Debug)] +pub enum DidRenameFiles {} + +impl Notification for DidRenameFiles { + type Params = RenameFilesParams; + const METHOD: &'static str = "workspace/didRenameFiles"; +} + +/// The did delete files notification is sent from the client to the server when files were deleted from within the client. +#[derive(Debug)] +pub enum DidDeleteFiles {} + +impl Notification for DidDeleteFiles { + type Params = DeleteFilesParams; + const METHOD: &'static str = "workspace/didDeleteFiles"; +} + +#[cfg(test)] +mod test { + use super::*; + + fn fake_call() + where + N: Notification, + N::Params: serde::Serialize, + { + } + + macro_rules! check_macro { + ($name:tt) => { + // check whether the macro name matches the method + assert_eq!(::METHOD, $name); + // test whether type checking passes for each component + fake_call::(); + }; + } + + #[test] + fn check_macro_definitions() { + check_macro!("$/cancelRequest"); + check_macro!("$/progress"); + check_macro!("$/logTrace"); + check_macro!("$/setTrace"); + check_macro!("initialized"); + check_macro!("exit"); + check_macro!("window/showMessage"); + check_macro!("window/logMessage"); + check_macro!("window/workDoneProgress/cancel"); + check_macro!("telemetry/event"); + check_macro!("textDocument/didOpen"); + check_macro!("textDocument/didChange"); + check_macro!("textDocument/willSave"); + check_macro!("textDocument/didSave"); + check_macro!("textDocument/didClose"); + check_macro!("textDocument/publishDiagnostics"); + check_macro!("workspace/didChangeConfiguration"); + check_macro!("workspace/didChangeWatchedFiles"); + check_macro!("workspace/didChangeWorkspaceFolders"); + check_macro!("workspace/didCreateFiles"); + check_macro!("workspace/didRenameFiles"); + check_macro!("workspace/didDeleteFiles"); + } + + #[test] + #[cfg(feature = "proposed")] + fn check_proposed_macro_definitions() {} +} diff --git a/vendor/lsp-types/src/progress.rs b/vendor/lsp-types/src/progress.rs new file mode 100644 index 00000000..95e64d13 --- /dev/null +++ b/vendor/lsp-types/src/progress.rs @@ -0,0 +1,135 @@ +use serde::{Deserialize, Serialize}; + +use crate::NumberOrString; + +pub type ProgressToken = NumberOrString; + +/// The progress notification is sent from the server to the client to ask +/// the client to indicate progress. +#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct ProgressParams { + /// The progress token provided by the client. + pub token: ProgressToken, + + /// The progress data. + pub value: ProgressParamsValue, +} + +#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] +#[serde(untagged)] +pub enum ProgressParamsValue { + WorkDone(WorkDoneProgress), +} + +/// The `window/workDoneProgress/create` request is sent +/// from the server to the client to ask the client to create a work done progress. +#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct WorkDoneProgressCreateParams { + /// The token to be used to report progress. + pub token: ProgressToken, +} + +/// The `window/workDoneProgress/cancel` notification is sent from the client +/// to the server to cancel a progress initiated on the server side using the `window/workDoneProgress/create`. +#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct WorkDoneProgressCancelParams { + /// The token to be used to report progress. + pub token: ProgressToken, +} + +/// Options to signal work done progress support in server capabilities. +#[derive(Debug, Eq, PartialEq, Default, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +#[allow(dead_code)] +pub struct WorkDoneProgressOptions { + #[serde(skip_serializing_if = "Option::is_none")] + pub work_done_progress: Option, +} + +/// An optional token that a server can use to report work done progress +#[derive(Debug, Eq, PartialEq, Default, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct WorkDoneProgressParams { + #[serde(skip_serializing_if = "Option::is_none")] + pub work_done_token: Option, +} + +#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct WorkDoneProgressBegin { + /// Mandatory title of the progress operation. Used to briefly inform + /// about the kind of operation being performed. + /// Examples: "Indexing" or "Linking dependencies". + pub title: String, + + /// Controls if a cancel button should show to allow the user to cancel the + /// long running operation. Clients that don't support cancellation are allowed + /// to ignore the setting. + #[serde(skip_serializing_if = "Option::is_none")] + pub cancellable: Option, + + /// Optional, more detailed associated progress message. Contains + /// complementary information to the `title`. + /// + /// Examples: "3/25 files", "project/src/module2", "node_modules/some_dep". + /// If unset, the previous progress message (if any) is still valid. + #[serde(skip_serializing_if = "Option::is_none")] + pub message: Option, + + /// Optional progress percentage to display (value 100 is considered 100%). + /// If not provided infinite progress is assumed and clients are allowed + /// to ignore the `percentage` value in subsequent in report notifications. + /// + /// The value should be steadily rising. Clients are free to ignore values + /// that are not following this rule. The value range is [0, 100] + #[serde(skip_serializing_if = "Option::is_none")] + pub percentage: Option, +} + +#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct WorkDoneProgressReport { + /// Controls if a cancel button should show to allow the user to cancel the + /// long running operation. Clients that don't support cancellation are allowed + /// to ignore the setting. + #[serde(skip_serializing_if = "Option::is_none")] + pub cancellable: Option, + + /// Optional, more detailed associated progress message. Contains + /// complementary information to the `title`. + /// Examples: "3/25 files", "project/src/module2", "node_modules/some_dep". + /// If unset, the previous progress message (if any) is still valid. + #[serde(skip_serializing_if = "Option::is_none")] + pub message: Option, + + /// Optional progress percentage to display (value 100 is considered 100%). + /// If not provided infinite progress is assumed and clients are allowed + /// to ignore the `percentage` value in subsequent in report notifications. + /// + /// The value should be steadily rising. Clients are free to ignore values + /// that are not following this rule. The value range is [0, 100] + #[serde(skip_serializing_if = "Option::is_none")] + pub percentage: Option, +} + +#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct WorkDoneProgressEnd { + /// Optional, more detailed associated progress message. Contains + /// complementary information to the `title`. + /// Examples: "3/25 files", "project/src/module2", "node_modules/some_dep". + /// If unset, the previous progress message (if any) is still valid. + #[serde(skip_serializing_if = "Option::is_none")] + pub message: Option, +} + +#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] +#[serde(tag = "kind", rename_all = "lowercase")] +pub enum WorkDoneProgress { + Begin(WorkDoneProgressBegin), + Report(WorkDoneProgressReport), + End(WorkDoneProgressEnd), +} diff --git a/vendor/lsp-types/src/references.rs b/vendor/lsp-types/src/references.rs new file mode 100644 index 00000000..cb590d58 --- /dev/null +++ b/vendor/lsp-types/src/references.rs @@ -0,0 +1,30 @@ +use crate::{ + DynamicRegistrationClientCapabilities, PartialResultParams, TextDocumentPositionParams, + WorkDoneProgressParams, +}; +use serde::{Deserialize, Serialize}; + +pub type ReferenceClientCapabilities = DynamicRegistrationClientCapabilities; +#[derive(Debug, Eq, PartialEq, Clone, Copy, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ReferenceContext { + /// Include the declaration of the current symbol. + pub include_declaration: bool, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ReferenceParams { + // Text Document and Position fields + #[serde(flatten)] + pub text_document_position: TextDocumentPositionParams, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, + + // ReferenceParams properties: + pub context: ReferenceContext, +} diff --git a/vendor/lsp-types/src/rename.rs b/vendor/lsp-types/src/rename.rs new file mode 100644 index 00000000..bb57e9af --- /dev/null +++ b/vendor/lsp-types/src/rename.rs @@ -0,0 +1,88 @@ +use crate::{Range, TextDocumentPositionParams, WorkDoneProgressOptions, WorkDoneProgressParams}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct RenameParams { + /// Text Document and Position fields + #[serde(flatten)] + pub text_document_position: TextDocumentPositionParams, + + /// The new name of the symbol. If the given name is not valid the + /// request must return a [ResponseError](#ResponseError) with an + /// appropriate message set. + pub new_name: String, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct RenameOptions { + /// Renames should be checked and tested before being executed. + #[serde(skip_serializing_if = "Option::is_none")] + pub prepare_provider: Option, + + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct RenameClientCapabilities { + /// Whether rename supports dynamic registration. + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, + + /// Client supports testing for validity of rename operations before execution. + /// + /// @since 3.12.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub prepare_support: Option, + + /// Client supports the default behavior result. + /// + /// The value indicates the default behavior used by the + /// client. + /// + /// @since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub prepare_support_default_behavior: Option, + + /// Whether the client honors the change annotations in + /// text edits and resource operations returned via the + /// rename request's workspace edit by for example presenting + /// the workspace edit in the user interface and asking + /// for confirmation. + /// + /// @since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub honors_change_annotations: Option, +} + +#[derive(Eq, PartialEq, Copy, Clone, Serialize, Deserialize)] +#[serde(transparent)] +pub struct PrepareSupportDefaultBehavior(i32); +lsp_enum! { +impl PrepareSupportDefaultBehavior { + /// The client's default behavior is to select the identifier + /// according the to language's syntax rule + pub const IDENTIFIER: PrepareSupportDefaultBehavior = PrepareSupportDefaultBehavior(1); +} +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +#[serde(rename_all = "camelCase")] +pub enum PrepareRenameResponse { + Range(Range), + RangeWithPlaceholder { + range: Range, + placeholder: String, + }, + #[serde(rename_all = "camelCase")] + DefaultBehavior { + default_behavior: bool, + }, +} diff --git a/vendor/lsp-types/src/request.rs b/vendor/lsp-types/src/request.rs new file mode 100644 index 00000000..7502546b --- /dev/null +++ b/vendor/lsp-types/src/request.rs @@ -0,0 +1,1068 @@ +use super::*; + +use serde::{de::DeserializeOwned, Serialize}; + +pub trait Request { + type Params: DeserializeOwned + Serialize + Send + Sync + 'static; + type Result: DeserializeOwned + Serialize + Send + Sync + 'static; + const METHOD: &'static str; +} + +#[macro_export] +macro_rules! lsp_request { + ("initialize") => { + $crate::request::Initialize + }; + ("shutdown") => { + $crate::request::Shutdown + }; + + ("window/showMessageRequest") => { + $crate::request::ShowMessageRequest + }; + + ("client/registerCapability") => { + $crate::request::RegisterCapability + }; + ("client/unregisterCapability") => { + $crate::request::UnregisterCapability + }; + + ("workspace/symbol") => { + $crate::request::WorkspaceSymbolRequest + }; + ("workspaceSymbol/resolve") => { + $crate::request::WorkspaceSymbolResolve + }; + ("workspace/executeCommand") => { + $crate::request::ExecuteCommand + }; + + ("textDocument/willSaveWaitUntil") => { + $crate::request::WillSaveWaitUntil + }; + + ("textDocument/completion") => { + $crate::request::Completion + }; + ("completionItem/resolve") => { + $crate::request::ResolveCompletionItem + }; + ("textDocument/hover") => { + $crate::request::HoverRequest + }; + ("textDocument/signatureHelp") => { + $crate::request::SignatureHelpRequest + }; + ("textDocument/declaration") => { + $crate::request::GotoDeclaration + }; + ("textDocument/definition") => { + $crate::request::GotoDefinition + }; + ("textDocument/references") => { + $crate::request::References + }; + ("textDocument/documentHighlight") => { + $crate::request::DocumentHighlightRequest + }; + ("textDocument/documentSymbol") => { + $crate::request::DocumentSymbolRequest + }; + ("textDocument/codeAction") => { + $crate::request::CodeActionRequest + }; + ("textDocument/codeLens") => { + $crate::request::CodeLensRequest + }; + ("codeLens/resolve") => { + $crate::request::CodeLensResolve + }; + ("textDocument/documentLink") => { + $crate::request::DocumentLinkRequest + }; + ("documentLink/resolve") => { + $crate::request::DocumentLinkResolve + }; + ("workspace/applyEdit") => { + $crate::request::ApplyWorkspaceEdit + }; + ("textDocument/rangeFormatting") => { + $crate::request::RangeFormatting + }; + ("textDocument/onTypeFormatting") => { + $crate::request::OnTypeFormatting + }; + ("textDocument/formatting") => { + $crate::request::Formatting + }; + ("textDocument/rename") => { + $crate::request::Rename + }; + ("textDocument/documentColor") => { + $crate::request::DocumentColor + }; + ("textDocument/colorPresentation") => { + $crate::request::ColorPresentationRequest + }; + ("textDocument/foldingRange") => { + $crate::request::FoldingRangeRequest + }; + ("textDocument/prepareRename") => { + $crate::request::PrepareRenameRequest + }; + ("textDocument/implementation") => { + $crate::request::GotoImplementation + }; + ("textDocument/typeDefinition") => { + $crate::request::GotoTypeDefinition + }; + ("textDocument/selectionRange") => { + $crate::request::SelectionRangeRequest + }; + ("workspace/workspaceFolders") => { + $crate::request::WorkspaceFoldersRequest + }; + ("workspace/configuration") => { + $crate::request::WorkspaceConfiguration + }; + ("window/workDoneProgress/create") => { + $crate::request::WorkDoneProgressCreate + }; + ("callHierarchy/incomingCalls") => { + $crate::request::CallHierarchyIncomingCalls + }; + ("callHierarchy/outgoingCalls") => { + $crate::request::CallHierarchyOutgoingCalls + }; + ("textDocument/moniker") => { + $crate::request::MonikerRequest + }; + ("textDocument/linkedEditingRange") => { + $crate::request::LinkedEditingRange + }; + ("textDocument/prepareCallHierarchy") => { + $crate::request::CallHierarchyPrepare + }; + ("textDocument/prepareTypeHierarchy") => { + $crate::request::TypeHierarchyPrepare + }; + ("textDocument/semanticTokens/full") => { + $crate::request::SemanticTokensFullRequest + }; + ("textDocument/semanticTokens/full/delta") => { + $crate::request::SemanticTokensFullDeltaRequest + }; + ("textDocument/semanticTokens/range") => { + $crate::request::SemanticTokensRangeRequest + }; + ("textDocument/inlayHint") => { + $crate::request::InlayHintRequest + }; + ("textDocument/inlineValue") => { + $crate::request::InlineValueRequest + }; + ("textDocument/diagnostic") => { + $crate::request::DocumentDiagnosticRequest + }; + ("workspace/diagnostic") => { + $crate::request::WorkspaceDiagnosticRequest + }; + ("workspace/diagnostic/refresh") => { + $crate::request::WorkspaceDiagnosticRefresh + }; + ("typeHierarchy/supertypes") => { + $crate::request::TypeHierarchySupertypes + }; + ("typeHierarchy/subtypes") => { + $crate::request::TypeHierarchySubtypes + }; + ("workspace/willCreateFiles") => { + $crate::request::WillCreateFiles + }; + ("workspace/willRenameFiles") => { + $crate::request::WillRenameFiles + }; + ("workspace/willDeleteFiles") => { + $crate::request::WillDeleteFiles + }; + ("workspace/semanticTokens/refresh") => { + $crate::request::SemanticTokensRefresh + }; + ("workspace/codeLens/refresh") => { + $crate::request::CodeLensRefresh + }; + ("workspace/inlayHint/refresh") => { + $crate::request::InlayHintRefreshRequest + }; + ("workspace/inlineValue/refresh") => { + $crate::request::InlineValueRefreshRequest + }; + ("codeAction/resolve") => { + $crate::request::CodeActionResolveRequest + }; + ("inlayHint/resolve") => { + $crate::request::InlayHintResolveRequest + }; + ("window/showDocument") => { + $crate::request::ShowDocument + }; +} + +/// The initialize request is sent as the first request from the client to the server. +/// If the server receives request or notification before the `initialize` request it should act as follows: +/// +/// * for a request the respond should be errored with `code: -32001`. The message can be picked by the server. +/// * notifications should be dropped. +#[derive(Debug)] +pub enum Initialize {} + +impl Request for Initialize { + type Params = InitializeParams; + type Result = InitializeResult; + const METHOD: &'static str = "initialize"; +} + +/// The shutdown request is sent from the client to the server. It asks the server to shut down, +/// but to not exit (otherwise the response might not be delivered correctly to the client). +/// There is a separate exit notification that asks the server to exit. +#[derive(Debug)] +pub enum Shutdown {} + +impl Request for Shutdown { + type Params = (); + type Result = (); + const METHOD: &'static str = "shutdown"; +} + +/// The show message request is sent from a server to a client to ask the client to display a particular message +/// in the user interface. In addition to the show message notification the request allows to pass actions and to +/// wait for an answer from the client. +#[derive(Debug)] +pub enum ShowMessageRequest {} + +impl Request for ShowMessageRequest { + type Params = ShowMessageRequestParams; + type Result = Option; + const METHOD: &'static str = "window/showMessageRequest"; +} + +/// The client/registerCapability request is sent from the server to the client to register for a new capability +/// on the client side. Not all clients need to support dynamic capability registration. A client opts in via the +/// ClientCapabilities.GenericCapability property. +#[derive(Debug)] +pub enum RegisterCapability {} + +impl Request for RegisterCapability { + type Params = RegistrationParams; + type Result = (); + const METHOD: &'static str = "client/registerCapability"; +} + +/// The client/unregisterCapability request is sent from the server to the client to unregister a +/// previously register capability. +#[derive(Debug)] +pub enum UnregisterCapability {} + +impl Request for UnregisterCapability { + type Params = UnregistrationParams; + type Result = (); + const METHOD: &'static str = "client/unregisterCapability"; +} + +/// The Completion request is sent from the client to the server to compute completion items at a given cursor position. +/// Completion items are presented in the IntelliSense user interface. If computing full completion items is expensive, +/// servers can additionally provide a handler for the completion item resolve request ('completionItem/resolve'). +/// This request is sent when a completion item is selected in the user interface. A typical use case is for example: +/// the 'textDocument/completion' request doesn’t fill in the documentation property for returned completion items +/// since it is expensive to compute. When the item is selected in the user interface then a ‘completionItem/resolve’ +/// request is sent with the selected completion item as a param. The returned completion item should have the +/// documentation property filled in. The request can delay the computation of the detail and documentation properties. +/// However, properties that are needed for the initial sorting and filtering, like sortText, filterText, insertText, +/// and textEdit must be provided in the textDocument/completion request and must not be changed during resolve. +#[derive(Debug)] +pub enum Completion {} + +impl Request for Completion { + type Params = CompletionParams; + type Result = Option; + const METHOD: &'static str = "textDocument/completion"; +} + +/// The request is sent from the client to the server to resolve additional information for a given completion item. +#[derive(Debug)] +pub enum ResolveCompletionItem {} + +impl Request for ResolveCompletionItem { + type Params = CompletionItem; + type Result = CompletionItem; + const METHOD: &'static str = "completionItem/resolve"; +} + +/// The hover request is sent from the client to the server to request hover information at a given text +/// document position. +#[derive(Debug)] +pub enum HoverRequest {} + +impl Request for HoverRequest { + type Params = HoverParams; + type Result = Option; + const METHOD: &'static str = "textDocument/hover"; +} + +/// The signature help request is sent from the client to the server to request signature information at +/// a given cursor position. +#[derive(Debug)] +pub enum SignatureHelpRequest {} + +impl Request for SignatureHelpRequest { + type Params = SignatureHelpParams; + type Result = Option; + const METHOD: &'static str = "textDocument/signatureHelp"; +} + +#[derive(Debug)] +pub enum GotoDeclaration {} +pub type GotoDeclarationParams = GotoDefinitionParams; +pub type GotoDeclarationResponse = GotoDefinitionResponse; + +/// The goto declaration request is sent from the client to the server to resolve the declaration location of +/// a symbol at a given text document position. +impl Request for GotoDeclaration { + type Params = GotoDeclarationParams; + type Result = Option; + const METHOD: &'static str = "textDocument/declaration"; +} + +/// The goto definition request is sent from the client to the server to resolve the definition location of +/// a symbol at a given text document position. +#[derive(Debug)] +pub enum GotoDefinition {} + +impl Request for GotoDefinition { + type Params = GotoDefinitionParams; + type Result = Option; + const METHOD: &'static str = "textDocument/definition"; +} + +/// The references request is sent from the client to the server to resolve project-wide references for the +/// symbol denoted by the given text document position. +#[derive(Debug)] +pub enum References {} + +impl Request for References { + type Params = ReferenceParams; + type Result = Option>; + const METHOD: &'static str = "textDocument/references"; +} + +/// The goto type definition request is sent from the client to the +/// server to resolve the type definition location of a symbol at a +/// given text document position. +#[derive(Debug)] +pub enum GotoTypeDefinition {} + +pub type GotoTypeDefinitionParams = GotoDefinitionParams; +pub type GotoTypeDefinitionResponse = GotoDefinitionResponse; + +impl Request for GotoTypeDefinition { + type Params = GotoTypeDefinitionParams; + type Result = Option; + const METHOD: &'static str = "textDocument/typeDefinition"; +} + +/// The goto implementation request is sent from the client to the +/// server to resolve the implementation location of a symbol at a +/// given text document position. +#[derive(Debug)] +pub enum GotoImplementation {} + +pub type GotoImplementationParams = GotoTypeDefinitionParams; +pub type GotoImplementationResponse = GotoDefinitionResponse; + +impl Request for GotoImplementation { + type Params = GotoImplementationParams; + type Result = Option; + const METHOD: &'static str = "textDocument/implementation"; +} + +/// The document highlight request is sent from the client to the server to resolve a document highlights +/// for a given text document position. +/// For programming languages this usually highlights all references to the symbol scoped to this file. +/// However we kept 'textDocument/documentHighlight' and 'textDocument/references' separate requests since +/// the first one is allowed to be more fuzzy. +/// Symbol matches usually have a DocumentHighlightKind of Read or Write whereas fuzzy or textual matches +/// use Text as the kind. +#[derive(Debug)] +pub enum DocumentHighlightRequest {} + +impl Request for DocumentHighlightRequest { + type Params = DocumentHighlightParams; + type Result = Option>; + const METHOD: &'static str = "textDocument/documentHighlight"; +} + +/// The document symbol request is sent from the client to the server to list all symbols found in a given +/// text document. +#[derive(Debug)] +pub enum DocumentSymbolRequest {} + +impl Request for DocumentSymbolRequest { + type Params = DocumentSymbolParams; + type Result = Option; + const METHOD: &'static str = "textDocument/documentSymbol"; +} + +/// The workspace symbol request is sent from the client to the server to list project-wide symbols +/// matching the query string. +#[derive(Debug)] +pub enum WorkspaceSymbolRequest {} + +impl Request for WorkspaceSymbolRequest { + type Params = WorkspaceSymbolParams; + type Result = Option; + const METHOD: &'static str = "workspace/symbol"; +} + +/// The `workspaceSymbol/resolve` request is sent from the client to the server to resolve +/// additional information for a given workspace symbol. +#[derive(Debug)] +pub enum WorkspaceSymbolResolve {} + +impl Request for WorkspaceSymbolResolve { + type Params = WorkspaceSymbol; + type Result = WorkspaceSymbol; + const METHOD: &'static str = "workspaceSymbol/resolve"; +} + +/// The workspace/executeCommand request is sent from the client to the server to trigger command execution on the server. +/// In most cases the server creates a WorkspaceEdit structure and applies the changes to the workspace using the request +/// workspace/applyEdit which is sent from the server to the client. +#[derive(Debug)] +pub enum ExecuteCommand {} + +impl Request for ExecuteCommand { + type Params = ExecuteCommandParams; + type Result = Option; + const METHOD: &'static str = "workspace/executeCommand"; +} + +/// The document will save request is sent from the client to the server before the document is +/// actually saved. The request can return an array of TextEdits which will be applied to the text +/// document before it is saved. Please note that clients might drop results if computing the text +/// edits took too long or if a server constantly fails on this request. This is done to keep the +/// save fast and reliable. +#[derive(Debug)] +pub enum WillSaveWaitUntil {} + +impl Request for WillSaveWaitUntil { + type Params = WillSaveTextDocumentParams; + type Result = Option>; + const METHOD: &'static str = "textDocument/willSaveWaitUntil"; +} + +/// The workspace/applyEdit request is sent from the server to the client to modify resource on the +/// client side. +#[derive(Debug)] +pub enum ApplyWorkspaceEdit {} + +impl Request for ApplyWorkspaceEdit { + type Params = ApplyWorkspaceEditParams; + type Result = ApplyWorkspaceEditResponse; + const METHOD: &'static str = "workspace/applyEdit"; +} + +/// The workspace/configuration request is sent from the server to the client to fetch configuration settings +/// from the client. The request can fetch several configuration settings in one roundtrip. +/// The order of the returned configuration settings correspond to the order of the passed ConfigurationItems +/// (e.g. the first item in the response is the result for the first configuration item in the params). +/// +/// A ConfigurationItem consists of the configuration section to ask for and an additional scope URI. +/// The configuration section ask for is defined by the server and doesn’t necessarily need to correspond to +/// the configuration store used be the client. So a server might ask for a configuration cpp.formatterOptions +/// but the client stores the configuration in a XML store layout differently. +/// It is up to the client to do the necessary conversion. If a scope URI is provided the client should return +/// the setting scoped to the provided resource. If the client for example uses EditorConfig to manage its +/// settings the configuration should be returned for the passed resource URI. If the client can’t provide a +/// configuration setting for a given scope then null need to be present in the returned array. +#[derive(Debug)] +pub enum WorkspaceConfiguration {} + +impl Request for WorkspaceConfiguration { + type Params = ConfigurationParams; + type Result = Vec; + const METHOD: &'static str = "workspace/configuration"; +} + +/// The code action request is sent from the client to the server to compute commands for a given text document +/// and range. The request is triggered when the user moves the cursor into a problem marker in the editor or +/// presses the lightbulb associated with a marker. +#[derive(Debug)] +pub enum CodeActionRequest {} + +impl Request for CodeActionRequest { + type Params = CodeActionParams; + type Result = Option; + const METHOD: &'static str = "textDocument/codeAction"; +} + +/// The request is sent from the client to the server to resolve additional information for a given code action. +/// This is usually used to compute the `edit` property of a code action to avoid its unnecessary computation +/// during the `textDocument/codeAction` request. +/// +/// @since 3.16.0 +#[derive(Debug)] +pub enum CodeActionResolveRequest {} + +impl Request for CodeActionResolveRequest { + type Params = CodeAction; + type Result = CodeAction; + const METHOD: &'static str = "codeAction/resolve"; +} + +/// The code lens request is sent from the client to the server to compute code lenses for a given text document. +#[derive(Debug)] +pub enum CodeLensRequest {} + +impl Request for CodeLensRequest { + type Params = CodeLensParams; + type Result = Option>; + const METHOD: &'static str = "textDocument/codeLens"; +} + +/// The code lens resolve request is sent from the client to the server to resolve the command for a +/// given code lens item. +#[derive(Debug)] +pub enum CodeLensResolve {} + +impl Request for CodeLensResolve { + type Params = CodeLens; + type Result = CodeLens; + const METHOD: &'static str = "codeLens/resolve"; +} + +/// The document links request is sent from the client to the server to request the location of links in a document. +#[derive(Debug)] +pub enum DocumentLinkRequest {} + +impl Request for DocumentLinkRequest { + type Params = DocumentLinkParams; + type Result = Option>; + const METHOD: &'static str = "textDocument/documentLink"; +} + +/// The document link resolve request is sent from the client to the server to resolve the target of +/// a given document link. +#[derive(Debug)] +pub enum DocumentLinkResolve {} + +impl Request for DocumentLinkResolve { + type Params = DocumentLink; + type Result = DocumentLink; + const METHOD: &'static str = "documentLink/resolve"; +} + +/// The document formatting request is sent from the server to the client to format a whole document. +#[derive(Debug)] +pub enum Formatting {} + +impl Request for Formatting { + type Params = DocumentFormattingParams; + type Result = Option>; + const METHOD: &'static str = "textDocument/formatting"; +} + +/// The document range formatting request is sent from the client to the server to format a given range in a document. +#[derive(Debug)] +pub enum RangeFormatting {} + +impl Request for RangeFormatting { + type Params = DocumentRangeFormattingParams; + type Result = Option>; + const METHOD: &'static str = "textDocument/rangeFormatting"; +} + +/// The document on type formatting request is sent from the client to the server to format parts of +/// the document during typing. +#[derive(Debug)] +pub enum OnTypeFormatting {} + +impl Request for OnTypeFormatting { + type Params = DocumentOnTypeFormattingParams; + type Result = Option>; + const METHOD: &'static str = "textDocument/onTypeFormatting"; +} + +/// The linked editing request is sent from the client to the server to return for a given position in a document +/// the range of the symbol at the position and all ranges that have the same content. +/// Optionally a word pattern can be returned to describe valid contents. A rename to one of the ranges can be applied +/// to all other ranges if the new content is valid. If no result-specific word pattern is provided, the word pattern from +/// the client’s language configuration is used. +#[derive(Debug)] +pub enum LinkedEditingRange {} + +impl Request for LinkedEditingRange { + type Params = LinkedEditingRangeParams; + type Result = Option; + const METHOD: &'static str = "textDocument/linkedEditingRange"; +} + +/// The rename request is sent from the client to the server to perform a workspace-wide rename of a symbol. +#[derive(Debug)] +pub enum Rename {} + +impl Request for Rename { + type Params = RenameParams; + type Result = Option; + const METHOD: &'static str = "textDocument/rename"; +} + +/// The document color request is sent from the client to the server to list all color references found in a given text document. +/// Along with the range, a color value in RGB is returned. +#[derive(Debug)] +pub enum DocumentColor {} + +impl Request for DocumentColor { + type Params = DocumentColorParams; + type Result = Vec; + const METHOD: &'static str = "textDocument/documentColor"; +} + +/// The color presentation request is sent from the client to the server to obtain a list of presentations for a color value +/// at a given location. +#[derive(Debug)] +pub enum ColorPresentationRequest {} + +impl Request for ColorPresentationRequest { + type Params = ColorPresentationParams; + type Result = Vec; + const METHOD: &'static str = "textDocument/colorPresentation"; +} + +/// The folding range request is sent from the client to the server to return all folding ranges found in a given text document. +#[derive(Debug)] +pub enum FoldingRangeRequest {} + +impl Request for FoldingRangeRequest { + type Params = FoldingRangeParams; + type Result = Option>; + const METHOD: &'static str = "textDocument/foldingRange"; +} + +/// The prepare rename request is sent from the client to the server to setup and test the validity of a rename operation +/// at a given location. +#[derive(Debug)] +pub enum PrepareRenameRequest {} + +impl Request for PrepareRenameRequest { + type Params = TextDocumentPositionParams; + type Result = Option; + const METHOD: &'static str = "textDocument/prepareRename"; +} + +#[derive(Debug)] +#[cfg(feature = "proposed")] +pub enum InlineCompletionRequest {} + +#[cfg(feature = "proposed")] +impl Request for InlineCompletionRequest { + type Params = InlineCompletionParams; + type Result = Option; + const METHOD: &'static str = "textDocument/inlineCompletion"; +} + +/// The workspace/workspaceFolders request is sent from the server to the client to fetch the current open list of +/// workspace folders. Returns null in the response if only a single file is open in the tool. +/// Returns an empty array if a workspace is open but no folders are configured. +#[derive(Debug)] +pub enum WorkspaceFoldersRequest {} + +impl Request for WorkspaceFoldersRequest { + type Params = (); + type Result = Option>; + const METHOD: &'static str = "workspace/workspaceFolders"; +} + +/// The `window/workDoneProgress/create` request is sent from the server +/// to the client to ask the client to create a work done progress. +#[derive(Debug)] +pub enum WorkDoneProgressCreate {} + +impl Request for WorkDoneProgressCreate { + type Params = WorkDoneProgressCreateParams; + type Result = (); + const METHOD: &'static str = "window/workDoneProgress/create"; +} + +/// The selection range request is sent from the client to the server to return +/// suggested selection ranges at given positions. A selection range is a range +/// around the cursor position which the user might be interested in selecting. +/// +/// A selection range in the return array is for the position in the provided parameters at the same index. +/// Therefore `positions[i]` must be contained in `result[i].range`. +/// +/// Typically, but not necessary, selection ranges correspond to the nodes of the +/// syntax tree. +pub enum SelectionRangeRequest {} + +impl Request for SelectionRangeRequest { + type Params = SelectionRangeParams; + type Result = Option>; + const METHOD: &'static str = "textDocument/selectionRange"; +} + +pub enum CallHierarchyPrepare {} + +impl Request for CallHierarchyPrepare { + type Params = CallHierarchyPrepareParams; + type Result = Option>; + const METHOD: &'static str = "textDocument/prepareCallHierarchy"; +} + +pub enum CallHierarchyIncomingCalls {} + +impl Request for CallHierarchyIncomingCalls { + type Params = CallHierarchyIncomingCallsParams; + type Result = Option>; + const METHOD: &'static str = "callHierarchy/incomingCalls"; +} + +pub enum CallHierarchyOutgoingCalls {} + +impl Request for CallHierarchyOutgoingCalls { + type Params = CallHierarchyOutgoingCallsParams; + type Result = Option>; + const METHOD: &'static str = "callHierarchy/outgoingCalls"; +} + +pub enum SemanticTokensFullRequest {} + +impl Request for SemanticTokensFullRequest { + type Params = SemanticTokensParams; + type Result = Option; + const METHOD: &'static str = "textDocument/semanticTokens/full"; +} + +pub enum SemanticTokensFullDeltaRequest {} + +impl Request for SemanticTokensFullDeltaRequest { + type Params = SemanticTokensDeltaParams; + type Result = Option; + const METHOD: &'static str = "textDocument/semanticTokens/full/delta"; +} + +pub enum SemanticTokensRangeRequest {} + +impl Request for SemanticTokensRangeRequest { + type Params = SemanticTokensRangeParams; + type Result = Option; + const METHOD: &'static str = "textDocument/semanticTokens/range"; +} + +/// The `workspace/semanticTokens/refresh` request is sent from the server to the client. +/// Servers can use it to ask clients to refresh the editors for which this server provides semantic tokens. +/// As a result the client should ask the server to recompute the semantic tokens for these editors. +/// This is useful if a server detects a project wide configuration change which requires a re-calculation of all semantic tokens. +/// Note that the client still has the freedom to delay the re-calculation of the semantic tokens if for example an editor is currently not visible. +pub enum SemanticTokensRefresh {} + +impl Request for SemanticTokensRefresh { + type Params = (); + type Result = (); + const METHOD: &'static str = "workspace/semanticTokens/refresh"; +} + +/// The workspace/codeLens/refresh request is sent from the server to the client. +/// Servers can use it to ask clients to refresh the code lenses currently shown in editors. +/// As a result the client should ask the server to recompute the code lenses for these editors. +/// This is useful if a server detects a configuration change which requires a re-calculation of all code lenses. +/// Note that the client still has the freedom to delay the re-calculation of the code lenses if for example an editor is currently not visible. +pub enum CodeLensRefresh {} + +impl Request for CodeLensRefresh { + type Params = (); + type Result = (); + const METHOD: &'static str = "workspace/codeLens/refresh"; +} + +/// The will create files request is sent from the client to the server before files are actually created as long as the creation is triggered from within the client. The request can return a WorkspaceEdit which will be applied to workspace before the files are created. Please note that clients might drop results if computing the edit took too long or if a server constantly fails on this request. This is done to keep creates fast and reliable. +pub enum WillCreateFiles {} + +impl Request for WillCreateFiles { + type Params = CreateFilesParams; + type Result = Option; + const METHOD: &'static str = "workspace/willCreateFiles"; +} + +/// The will rename files request is sent from the client to the server before files are actually renamed as long as the rename is triggered from within the client. The request can return a WorkspaceEdit which will be applied to workspace before the files are renamed. Please note that clients might drop results if computing the edit took too long or if a server constantly fails on this request. This is done to keep renames fast and reliable. +pub enum WillRenameFiles {} + +impl Request for WillRenameFiles { + type Params = RenameFilesParams; + type Result = Option; + const METHOD: &'static str = "workspace/willRenameFiles"; +} + +/// The will delete files request is sent from the client to the server before files are actually deleted as long as the deletion is triggered from within the client. The request can return a WorkspaceEdit which will be applied to workspace before the files are deleted. Please note that clients might drop results if computing the edit took too long or if a server constantly fails on this request. This is done to keep deletes fast and reliable. +pub enum WillDeleteFiles {} + +impl Request for WillDeleteFiles { + type Params = DeleteFilesParams; + type Result = Option; + const METHOD: &'static str = "workspace/willDeleteFiles"; +} + +/// The show document request is sent from a server to a client to ask the client to display a particular document in the user interface. +pub enum ShowDocument {} + +impl Request for ShowDocument { + type Params = ShowDocumentParams; + type Result = ShowDocumentResult; + const METHOD: &'static str = "window/showDocument"; +} + +pub enum MonikerRequest {} + +impl Request for MonikerRequest { + type Params = MonikerParams; + type Result = Option>; + const METHOD: &'static str = "textDocument/moniker"; +} + +/// The inlay hints request is sent from the client to the server to compute inlay hints for a given +/// [text document, range] tuple that may be rendered in the editor in place with other text. +pub enum InlayHintRequest {} + +impl Request for InlayHintRequest { + type Params = InlayHintParams; + type Result = Option>; + const METHOD: &'static str = "textDocument/inlayHint"; +} + +/// The `inlayHint/resolve` request is sent from the client to the server to resolve additional +/// information for a given inlay hint. This is usually used to compute the tooltip, location or +/// command properties of a inlay hint’s label part to avoid its unnecessary computation during the +/// `textDocument/inlayHint` request. +pub enum InlayHintResolveRequest {} + +impl Request for InlayHintResolveRequest { + type Params = InlayHint; + type Result = InlayHint; + const METHOD: &'static str = "inlayHint/resolve"; +} + +/// The `workspace/inlayHint/refresh` request is sent from the server to the client. Servers can use +/// it to ask clients to refresh the inlay hints currently shown in editors. As a result the client +/// should ask the server to recompute the inlay hints for these editors. This is useful if a server +/// detects a configuration change which requires a re-calculation of all inlay hints. Note that the +/// client still has the freedom to delay the re-calculation of the inlay hints if for example an +/// editor is currently not visible. +pub enum InlayHintRefreshRequest {} + +impl Request for InlayHintRefreshRequest { + type Params = (); + type Result = (); + const METHOD: &'static str = "workspace/inlayHint/refresh"; +} + +/// The inline value request is sent from the client to the server to compute inline values for a +/// given text document that may be rendered in the editor at the end of lines. +pub enum InlineValueRequest {} + +impl Request for InlineValueRequest { + type Params = InlineValueParams; + type Result = Option; + const METHOD: &'static str = "textDocument/inlineValue"; +} + +/// The `workspace/inlineValue/refresh` request is sent from the server to the client. Servers can +/// use it to ask clients to refresh the inline values currently shown in editors. As a result the +/// client should ask the server to recompute the inline values for these editors. This is useful if +/// a server detects a configuration change which requires a re-calculation of all inline values. +/// Note that the client still has the freedom to delay the re-calculation of the inline values if +/// for example an editor is currently not visible. +pub enum InlineValueRefreshRequest {} + +impl Request for InlineValueRefreshRequest { + type Params = (); + type Result = (); + const METHOD: &'static str = "workspace/inlineValue/refresh"; +} + +/// The text document diagnostic request is sent from the client to the server to ask the server to +/// compute the diagnostics for a given document. As with other pull requests the server is asked +/// to compute the diagnostics for the currently synced version of the document. +#[derive(Debug)] +pub enum DocumentDiagnosticRequest {} + +impl Request for DocumentDiagnosticRequest { + type Params = DocumentDiagnosticParams; + type Result = DocumentDiagnosticReportResult; + const METHOD: &'static str = "textDocument/diagnostic"; +} + +/// The workspace diagnostic request is sent from the client to the server to ask the server to +/// compute workspace wide diagnostics which previously where pushed from the server to the client. +/// In contrast to the document diagnostic request the workspace request can be long running and is +/// not bound to a specific workspace or document state. If the client supports streaming for the +/// workspace diagnostic pull it is legal to provide a document diagnostic report multiple times +/// for the same document URI. The last one reported will win over previous reports. +#[derive(Debug)] +pub enum WorkspaceDiagnosticRequest {} + +impl Request for WorkspaceDiagnosticRequest { + type Params = WorkspaceDiagnosticParams; + const METHOD: &'static str = "workspace/diagnostic"; + type Result = WorkspaceDiagnosticReportResult; +} + +/// The `workspace/diagnostic/refresh` request is sent from the server to the client. Servers can +/// use it to ask clients to refresh all needed document and workspace diagnostics. This is useful +/// if a server detects a project wide configuration change which requires a re-calculation of all +/// diagnostics. +#[derive(Debug)] +pub enum WorkspaceDiagnosticRefresh {} + +impl Request for WorkspaceDiagnosticRefresh { + type Params = (); + type Result = (); + const METHOD: &'static str = "workspace/diagnostic/refresh"; +} + +/// The type hierarchy request is sent from the client to the server to return a type hierarchy for +/// the language element of given text document positions. Will return null if the server couldn’t +/// infer a valid type from the position. The type hierarchy requests are executed in two steps: +/// +/// 1. first a type hierarchy item is prepared for the given text document position. +/// 2. for a type hierarchy item the supertype or subtype type hierarchy items are resolved. +pub enum TypeHierarchyPrepare {} + +impl Request for TypeHierarchyPrepare { + type Params = TypeHierarchyPrepareParams; + type Result = Option>; + const METHOD: &'static str = "textDocument/prepareTypeHierarchy"; +} + +/// The `typeHierarchy/supertypes` request is sent from the client to the server to resolve the +/// supertypes for a given type hierarchy item. Will return null if the server couldn’t infer a +/// valid type from item in the params. The request doesn’t define its own client and server +/// capabilities. It is only issued if a server registers for the +/// `textDocument/prepareTypeHierarchy` request. +pub enum TypeHierarchySupertypes {} + +impl Request for TypeHierarchySupertypes { + type Params = TypeHierarchySupertypesParams; + type Result = Option>; + const METHOD: &'static str = "typeHierarchy/supertypes"; +} + +/// The `typeHierarchy/subtypes` request is sent from the client to the server to resolve the +/// subtypes for a given type hierarchy item. Will return null if the server couldn’t infer a valid +/// type from item in the params. The request doesn’t define its own client and server capabilities. +/// It is only issued if a server registers for the textDocument/prepareTypeHierarchy request. +pub enum TypeHierarchySubtypes {} + +impl Request for TypeHierarchySubtypes { + type Params = TypeHierarchySubtypesParams; + type Result = Option>; + const METHOD: &'static str = "typeHierarchy/subtypes"; +} + +#[cfg(test)] +mod test { + use super::*; + + fn fake_call() + where + R: Request, + R::Params: serde::Serialize, + R::Result: serde::de::DeserializeOwned, + { + } + + macro_rules! check_macro { + ($name:tt) => { + // check whether the macro name matches the method + assert_eq!(::METHOD, $name); + // test whether type checking passes for each component + fake_call::(); + }; + } + + #[test] + fn check_macro_definitions() { + check_macro!("initialize"); + check_macro!("shutdown"); + + check_macro!("window/showDocument"); + check_macro!("window/showMessageRequest"); + check_macro!("window/workDoneProgress/create"); + + check_macro!("client/registerCapability"); + check_macro!("client/unregisterCapability"); + + check_macro!("textDocument/willSaveWaitUntil"); + check_macro!("textDocument/completion"); + check_macro!("textDocument/hover"); + check_macro!("textDocument/signatureHelp"); + check_macro!("textDocument/declaration"); + check_macro!("textDocument/definition"); + check_macro!("textDocument/references"); + check_macro!("textDocument/documentHighlight"); + check_macro!("textDocument/documentSymbol"); + check_macro!("textDocument/codeAction"); + check_macro!("textDocument/codeLens"); + check_macro!("textDocument/documentLink"); + check_macro!("textDocument/rangeFormatting"); + check_macro!("textDocument/onTypeFormatting"); + check_macro!("textDocument/formatting"); + check_macro!("textDocument/rename"); + check_macro!("textDocument/documentColor"); + check_macro!("textDocument/colorPresentation"); + check_macro!("textDocument/foldingRange"); + check_macro!("textDocument/prepareRename"); + check_macro!("textDocument/implementation"); + check_macro!("textDocument/selectionRange"); + check_macro!("textDocument/typeDefinition"); + check_macro!("textDocument/moniker"); + check_macro!("textDocument/linkedEditingRange"); + check_macro!("textDocument/prepareCallHierarchy"); + check_macro!("textDocument/prepareTypeHierarchy"); + check_macro!("textDocument/semanticTokens/full"); + check_macro!("textDocument/semanticTokens/full/delta"); + check_macro!("textDocument/semanticTokens/range"); + check_macro!("textDocument/inlayHint"); + check_macro!("textDocument/inlineValue"); + check_macro!("textDocument/diagnostic"); + + check_macro!("workspace/applyEdit"); + check_macro!("workspace/symbol"); + check_macro!("workspace/executeCommand"); + check_macro!("workspace/configuration"); + check_macro!("workspace/diagnostic"); + check_macro!("workspace/diagnostic/refresh"); + check_macro!("workspace/willCreateFiles"); + check_macro!("workspace/willRenameFiles"); + check_macro!("workspace/willDeleteFiles"); + check_macro!("workspace/workspaceFolders"); + check_macro!("workspace/semanticTokens/refresh"); + check_macro!("workspace/codeLens/refresh"); + check_macro!("workspace/inlayHint/refresh"); + check_macro!("workspace/inlineValue/refresh"); + + check_macro!("callHierarchy/incomingCalls"); + check_macro!("callHierarchy/outgoingCalls"); + check_macro!("codeAction/resolve"); + check_macro!("codeLens/resolve"); + check_macro!("completionItem/resolve"); + check_macro!("documentLink/resolve"); + check_macro!("inlayHint/resolve"); + check_macro!("typeHierarchy/subtypes"); + check_macro!("typeHierarchy/supertypes"); + check_macro!("workspaceSymbol/resolve"); + } + + #[test] + #[cfg(feature = "proposed")] + fn check_proposed_macro_definitions() {} +} diff --git a/vendor/lsp-types/src/selection_range.rs b/vendor/lsp-types/src/selection_range.rs new file mode 100644 index 00000000..048df6f9 --- /dev/null +++ b/vendor/lsp-types/src/selection_range.rs @@ -0,0 +1,86 @@ +use serde::{Deserialize, Serialize}; + +use crate::{ + PartialResultParams, Position, Range, StaticTextDocumentRegistrationOptions, + TextDocumentIdentifier, WorkDoneProgressOptions, WorkDoneProgressParams, +}; +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SelectionRangeClientCapabilities { + /// Whether implementation supports dynamic registration for selection range + /// providers. If this is set to `true` the client supports the new + /// `SelectionRangeRegistrationOptions` return value for the corresponding + /// server capability as well. + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +pub struct SelectionRangeOptions { + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct SelectionRangeRegistrationOptions { + #[serde(flatten)] + pub selection_range_options: SelectionRangeOptions, + + #[serde(flatten)] + pub registration_options: StaticTextDocumentRegistrationOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum SelectionRangeProviderCapability { + Simple(bool), + Options(SelectionRangeOptions), + RegistrationOptions(SelectionRangeRegistrationOptions), +} + +impl From for SelectionRangeProviderCapability { + fn from(from: SelectionRangeRegistrationOptions) -> Self { + Self::RegistrationOptions(from) + } +} + +impl From for SelectionRangeProviderCapability { + fn from(from: SelectionRangeOptions) -> Self { + Self::Options(from) + } +} + +impl From for SelectionRangeProviderCapability { + fn from(from: bool) -> Self { + Self::Simple(from) + } +} + +/// A parameter literal used in selection range requests. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SelectionRangeParams { + /// The text document. + pub text_document: TextDocumentIdentifier, + + /// The positions inside the text document. + pub positions: Vec, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +/// Represents a selection range. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SelectionRange { + /// Range of the selection. + pub range: Range, + + /// The parent selection range containing this range. + #[serde(skip_serializing_if = "Option::is_none")] + pub parent: Option>, +} diff --git a/vendor/lsp-types/src/semantic_tokens.rs b/vendor/lsp-types/src/semantic_tokens.rs new file mode 100644 index 00000000..842558ba --- /dev/null +++ b/vendor/lsp-types/src/semantic_tokens.rs @@ -0,0 +1,734 @@ +use std::borrow::Cow; + +use serde::ser::SerializeSeq; +use serde::{Deserialize, Serialize}; + +use crate::{ + PartialResultParams, Range, StaticRegistrationOptions, TextDocumentIdentifier, + TextDocumentRegistrationOptions, WorkDoneProgressOptions, WorkDoneProgressParams, +}; +/// A set of predefined token types. This set is not fixed +/// and clients can specify additional token types via the +/// corresponding client capabilities. +/// +/// @since 3.16.0 +#[derive(Debug, Eq, PartialEq, Hash, PartialOrd, Clone, Deserialize, Serialize)] +pub struct SemanticTokenType(Cow<'static, str>); + +impl SemanticTokenType { + pub const NAMESPACE: SemanticTokenType = SemanticTokenType::new("namespace"); + pub const TYPE: SemanticTokenType = SemanticTokenType::new("type"); + pub const CLASS: SemanticTokenType = SemanticTokenType::new("class"); + pub const ENUM: SemanticTokenType = SemanticTokenType::new("enum"); + pub const INTERFACE: SemanticTokenType = SemanticTokenType::new("interface"); + pub const STRUCT: SemanticTokenType = SemanticTokenType::new("struct"); + pub const TYPE_PARAMETER: SemanticTokenType = SemanticTokenType::new("typeParameter"); + pub const PARAMETER: SemanticTokenType = SemanticTokenType::new("parameter"); + pub const VARIABLE: SemanticTokenType = SemanticTokenType::new("variable"); + pub const PROPERTY: SemanticTokenType = SemanticTokenType::new("property"); + pub const ENUM_MEMBER: SemanticTokenType = SemanticTokenType::new("enumMember"); + pub const EVENT: SemanticTokenType = SemanticTokenType::new("event"); + pub const FUNCTION: SemanticTokenType = SemanticTokenType::new("function"); + pub const METHOD: SemanticTokenType = SemanticTokenType::new("method"); + pub const MACRO: SemanticTokenType = SemanticTokenType::new("macro"); + pub const KEYWORD: SemanticTokenType = SemanticTokenType::new("keyword"); + pub const MODIFIER: SemanticTokenType = SemanticTokenType::new("modifier"); + pub const COMMENT: SemanticTokenType = SemanticTokenType::new("comment"); + pub const STRING: SemanticTokenType = SemanticTokenType::new("string"); + pub const NUMBER: SemanticTokenType = SemanticTokenType::new("number"); + pub const REGEXP: SemanticTokenType = SemanticTokenType::new("regexp"); + pub const OPERATOR: SemanticTokenType = SemanticTokenType::new("operator"); + + /// @since 3.17.0 + pub const DECORATOR: SemanticTokenType = SemanticTokenType::new("decorator"); + + pub const fn new(tag: &'static str) -> Self { + SemanticTokenType(Cow::Borrowed(tag)) + } + + pub fn as_str(&self) -> &str { + &self.0 + } +} + +impl From for SemanticTokenType { + fn from(from: String) -> Self { + SemanticTokenType(Cow::from(from)) + } +} + +impl From<&'static str> for SemanticTokenType { + fn from(from: &'static str) -> Self { + SemanticTokenType::new(from) + } +} + +/// A set of predefined token modifiers. This set is not fixed +/// and clients can specify additional token types via the +/// corresponding client capabilities. +/// +/// @since 3.16.0 +#[derive(Debug, Eq, PartialEq, Hash, PartialOrd, Clone, Deserialize, Serialize)] +pub struct SemanticTokenModifier(Cow<'static, str>); + +impl SemanticTokenModifier { + pub const DECLARATION: SemanticTokenModifier = SemanticTokenModifier::new("declaration"); + pub const DEFINITION: SemanticTokenModifier = SemanticTokenModifier::new("definition"); + pub const READONLY: SemanticTokenModifier = SemanticTokenModifier::new("readonly"); + pub const STATIC: SemanticTokenModifier = SemanticTokenModifier::new("static"); + pub const DEPRECATED: SemanticTokenModifier = SemanticTokenModifier::new("deprecated"); + pub const ABSTRACT: SemanticTokenModifier = SemanticTokenModifier::new("abstract"); + pub const ASYNC: SemanticTokenModifier = SemanticTokenModifier::new("async"); + pub const MODIFICATION: SemanticTokenModifier = SemanticTokenModifier::new("modification"); + pub const DOCUMENTATION: SemanticTokenModifier = SemanticTokenModifier::new("documentation"); + pub const DEFAULT_LIBRARY: SemanticTokenModifier = SemanticTokenModifier::new("defaultLibrary"); + + pub const fn new(tag: &'static str) -> Self { + SemanticTokenModifier(Cow::Borrowed(tag)) + } + + pub fn as_str(&self) -> &str { + &self.0 + } +} + +impl From for SemanticTokenModifier { + fn from(from: String) -> Self { + SemanticTokenModifier(Cow::from(from)) + } +} + +impl From<&'static str> for SemanticTokenModifier { + fn from(from: &'static str) -> Self { + SemanticTokenModifier::new(from) + } +} + +#[derive(Debug, Eq, PartialEq, Hash, PartialOrd, Clone, Deserialize, Serialize)] +pub struct TokenFormat(Cow<'static, str>); + +impl TokenFormat { + pub const RELATIVE: TokenFormat = TokenFormat::new("relative"); + + pub const fn new(tag: &'static str) -> Self { + TokenFormat(Cow::Borrowed(tag)) + } + + pub fn as_str(&self) -> &str { + &self.0 + } +} + +impl From for TokenFormat { + fn from(from: String) -> Self { + TokenFormat(Cow::from(from)) + } +} + +impl From<&'static str> for TokenFormat { + fn from(from: &'static str) -> Self { + TokenFormat::new(from) + } +} + +/// @since 3.16.0 +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SemanticTokensLegend { + /// The token types a server uses. + pub token_types: Vec, + + /// The token modifiers a server uses. + pub token_modifiers: Vec, +} + +/// The actual tokens. +#[derive(Debug, Eq, PartialEq, Copy, Clone, Default)] +pub struct SemanticToken { + pub delta_line: u32, + pub delta_start: u32, + pub length: u32, + pub token_type: u32, + pub token_modifiers_bitset: u32, +} + +impl SemanticToken { + fn deserialize_tokens<'de, D>(deserializer: D) -> Result, D::Error> + where + D: serde::Deserializer<'de>, + { + let data = Vec::::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 serialize_tokens(tokens: &[SemanticToken], serializer: S) -> Result + 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>, D::Error> + where + D: serde::Deserializer<'de>, + { + #[derive(Deserialize)] + #[serde(transparent)] + struct Wrapper { + #[serde(deserialize_with = "SemanticToken::deserialize_tokens")] + tokens: Vec, + } + + Ok(Option::::deserialize(deserializer)?.map(|wrapper| wrapper.tokens)) + } + + fn serialize_tokens_opt( + data: &Option>, + serializer: S, + ) -> Result + where + S: serde::Serializer, + { + #[derive(Serialize)] + #[serde(transparent)] + struct Wrapper { + #[serde(serialize_with = "SemanticToken::serialize_tokens")] + tokens: Vec, + } + + let opt = data.as_ref().map(|t| Wrapper { tokens: t.to_vec() }); + + opt.serialize(serializer) + } +} + +/// @since 3.16.0 +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SemanticTokens { + /// An optional result id. If provided and clients support delta updating + /// the client will include the result id in the next semantic token request. + /// A server can then instead of computing all semantic tokens again simply + /// send a delta. + #[serde(skip_serializing_if = "Option::is_none")] + pub result_id: Option, + + /// The actual tokens. For a detailed description about how the data is + /// structured please see + /// + #[serde( + deserialize_with = "SemanticToken::deserialize_tokens", + serialize_with = "SemanticToken::serialize_tokens" + )] + pub data: Vec, +} + +/// @since 3.16.0 +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SemanticTokensPartialResult { + #[serde( + deserialize_with = "SemanticToken::deserialize_tokens", + serialize_with = "SemanticToken::serialize_tokens" + )] + pub data: Vec, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[serde(untagged)] +pub enum SemanticTokensResult { + Tokens(SemanticTokens), + Partial(SemanticTokensPartialResult), +} + +impl From for SemanticTokensResult { + fn from(from: SemanticTokens) -> Self { + SemanticTokensResult::Tokens(from) + } +} + +impl From for SemanticTokensResult { + fn from(from: SemanticTokensPartialResult) -> Self { + SemanticTokensResult::Partial(from) + } +} + +/// @since 3.16.0 +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SemanticTokensEdit { + pub start: u32, + pub delete_count: u32, + + #[serde( + default, + skip_serializing_if = "Option::is_none", + deserialize_with = "SemanticToken::deserialize_tokens_opt", + serialize_with = "SemanticToken::serialize_tokens_opt" + )] + pub data: Option>, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[serde(untagged)] +pub enum SemanticTokensFullDeltaResult { + Tokens(SemanticTokens), + TokensDelta(SemanticTokensDelta), + PartialTokensDelta { edits: Vec }, +} + +impl From for SemanticTokensFullDeltaResult { + fn from(from: SemanticTokens) -> Self { + SemanticTokensFullDeltaResult::Tokens(from) + } +} + +impl From for SemanticTokensFullDeltaResult { + fn from(from: SemanticTokensDelta) -> Self { + SemanticTokensFullDeltaResult::TokensDelta(from) + } +} + +/// @since 3.16.0 +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SemanticTokensDelta { + #[serde(skip_serializing_if = "Option::is_none")] + pub result_id: Option, + /// For a detailed description how these edits are structured please see + /// + pub edits: Vec, +} + +/// Capabilities specific to the `textDocument/semanticTokens/*` requests. +/// +/// @since 3.16.0 +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SemanticTokensClientCapabilities { + /// Whether implementation supports dynamic registration. If this is set to `true` + /// the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)` + /// return value for the corresponding server capability as well. + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, + + /// Which requests the client supports and might send to the server + /// depending on the server's capability. Please note that clients might not + /// show semantic tokens or degrade some of the user experience if a range + /// or full request is advertised by the client but not provided by the + /// server. If for example the client capability `requests.full` and + /// `request.range` are both set to true but the server only provides a + /// range provider the client might not render a minimap correctly or might + /// even decide to not show any semantic tokens at all. + pub requests: SemanticTokensClientCapabilitiesRequests, + + /// The token types that the client supports. + pub token_types: Vec, + + /// The token modifiers that the client supports. + pub token_modifiers: Vec, + + /// The token formats the clients supports. + pub formats: Vec, + + /// Whether the client supports tokens that can overlap each other. + #[serde(skip_serializing_if = "Option::is_none")] + pub overlapping_token_support: Option, + + /// Whether the client supports tokens that can span multiple lines. + #[serde(skip_serializing_if = "Option::is_none")] + pub multiline_token_support: Option, + + /// Whether the client allows the server to actively cancel a + /// semantic token request, e.g. supports returning + /// ErrorCodes.ServerCancelled. If a server does the client + /// needs to retrigger the request. + /// + /// @since 3.17.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub server_cancel_support: Option, + + /// Whether the client uses semantic tokens to augment existing + /// syntax tokens. If set to `true` client side created syntax + /// tokens and semantic tokens are both used for colorization. If + /// set to `false` the client only uses the returned semantic tokens + /// for colorization. + /// + /// If the value is `undefined` then the client behavior is not + /// specified. + /// + /// @since 3.17.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub augments_syntax_tokens: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SemanticTokensClientCapabilitiesRequests { + /// The client will send the `textDocument/semanticTokens/range` request if the server provides a corresponding handler. + #[serde(skip_serializing_if = "Option::is_none")] + pub range: Option, + + /// The client will send the `textDocument/semanticTokens/full` request if the server provides a corresponding handler. + #[serde(skip_serializing_if = "Option::is_none")] + pub full: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[serde(untagged)] +pub enum SemanticTokensFullOptions { + Bool(bool), + Delta { + /// The client will send the `textDocument/semanticTokens/full/delta` request if the server provides a corresponding handler. + /// The server supports deltas for full documents. + #[serde(skip_serializing_if = "Option::is_none")] + delta: Option, + }, +} + +/// @since 3.16.0 +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SemanticTokensOptions { + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, + + /// The legend used by the server + pub legend: SemanticTokensLegend, + + /// Server supports providing semantic tokens for a specific range + /// of a document. + #[serde(skip_serializing_if = "Option::is_none")] + pub range: Option, + + /// Server supports providing semantic tokens for a full document. + #[serde(skip_serializing_if = "Option::is_none")] + pub full: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SemanticTokensRegistrationOptions { + #[serde(flatten)] + pub text_document_registration_options: TextDocumentRegistrationOptions, + + #[serde(flatten)] + pub semantic_tokens_options: SemanticTokensOptions, + + #[serde(flatten)] + pub static_registration_options: StaticRegistrationOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[serde(untagged)] +pub enum SemanticTokensServerCapabilities { + SemanticTokensOptions(SemanticTokensOptions), + SemanticTokensRegistrationOptions(SemanticTokensRegistrationOptions), +} + +impl From for SemanticTokensServerCapabilities { + fn from(from: SemanticTokensOptions) -> Self { + SemanticTokensServerCapabilities::SemanticTokensOptions(from) + } +} + +impl From for SemanticTokensServerCapabilities { + fn from(from: SemanticTokensRegistrationOptions) -> Self { + SemanticTokensServerCapabilities::SemanticTokensRegistrationOptions(from) + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SemanticTokensWorkspaceClientCapabilities { + /// Whether the client implementation supports a refresh request sent from + /// the server to the client. + /// + /// Note that this event is global and will force the client to refresh all + /// semantic tokens currently shown. It should be used with absolute care + /// and is useful for situation where a server for example detect a project + /// wide change that requires such a calculation. + pub refresh_support: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SemanticTokensParams { + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, + + /// The text document. + pub text_document: TextDocumentIdentifier, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SemanticTokensDeltaParams { + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, + + /// The text document. + pub text_document: TextDocumentIdentifier, + + /// The result id of a previous response. The result Id can either point to a full response + /// or a delta response depending on what was received last. + pub previous_result_id: String, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SemanticTokensRangeParams { + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, + + /// The text document. + pub text_document: TextDocumentIdentifier, + + /// The range the semantic tokens are requested for. + pub range: Range, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[serde(untagged)] +pub enum SemanticTokensRangeResult { + Tokens(SemanticTokens), + Partial(SemanticTokensPartialResult), +} + +impl From for SemanticTokensRangeResult { + fn from(tokens: SemanticTokens) -> Self { + SemanticTokensRangeResult::Tokens(tokens) + } +} + +impl From for SemanticTokensRangeResult { + fn from(partial: SemanticTokensPartialResult) -> Self { + SemanticTokensRangeResult::Partial(partial) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::tests::{test_deserialization, test_serialization}; + + #[test] + fn test_semantic_tokens_support_serialization() { + test_serialization( + &SemanticTokens { + result_id: None, + data: vec![], + }, + r#"{"data":[]}"#, + ); + + test_serialization( + &SemanticTokens { + result_id: None, + data: vec![SemanticToken { + delta_line: 2, + delta_start: 5, + length: 3, + token_type: 0, + token_modifiers_bitset: 3, + }], + }, + r#"{"data":[2,5,3,0,3]}"#, + ); + + test_serialization( + &SemanticTokens { + result_id: None, + data: vec![ + SemanticToken { + delta_line: 2, + delta_start: 5, + length: 3, + token_type: 0, + token_modifiers_bitset: 3, + }, + SemanticToken { + delta_line: 0, + delta_start: 5, + length: 4, + token_type: 1, + token_modifiers_bitset: 0, + }, + ], + }, + r#"{"data":[2,5,3,0,3,0,5,4,1,0]}"#, + ); + } + + #[test] + fn test_semantic_tokens_support_deserialization() { + test_deserialization( + r#"{"data":[]}"#, + &SemanticTokens { + result_id: None, + data: vec![], + }, + ); + + test_deserialization( + r#"{"data":[2,5,3,0,3]}"#, + &SemanticTokens { + result_id: None, + data: vec![SemanticToken { + delta_line: 2, + delta_start: 5, + length: 3, + token_type: 0, + token_modifiers_bitset: 3, + }], + }, + ); + + test_deserialization( + r#"{"data":[2,5,3,0,3,0,5,4,1,0]}"#, + &SemanticTokens { + result_id: None, + data: vec![ + SemanticToken { + delta_line: 2, + delta_start: 5, + length: 3, + token_type: 0, + token_modifiers_bitset: 3, + }, + SemanticToken { + delta_line: 0, + delta_start: 5, + length: 4, + token_type: 1, + token_modifiers_bitset: 0, + }, + ], + }, + ); + } + + #[test] + #[should_panic] + fn test_semantic_tokens_support_deserialization_err() { + test_deserialization( + r#"{"data":[1]}"#, + &SemanticTokens { + result_id: None, + data: vec![], + }, + ); + } + + #[test] + fn test_semantic_tokens_edit_support_deserialization() { + test_deserialization( + r#"{"start":0,"deleteCount":1,"data":[2,5,3,0,3,0,5,4,1,0]}"#, + &SemanticTokensEdit { + start: 0, + delete_count: 1, + data: Some(vec![ + SemanticToken { + delta_line: 2, + delta_start: 5, + length: 3, + token_type: 0, + token_modifiers_bitset: 3, + }, + SemanticToken { + delta_line: 0, + delta_start: 5, + length: 4, + token_type: 1, + token_modifiers_bitset: 0, + }, + ]), + }, + ); + + test_deserialization( + r#"{"start":0,"deleteCount":1}"#, + &SemanticTokensEdit { + start: 0, + delete_count: 1, + data: None, + }, + ); + } + + #[test] + fn test_semantic_tokens_edit_support_serialization() { + test_serialization( + &SemanticTokensEdit { + start: 0, + delete_count: 1, + data: Some(vec![ + SemanticToken { + delta_line: 2, + delta_start: 5, + length: 3, + token_type: 0, + token_modifiers_bitset: 3, + }, + SemanticToken { + delta_line: 0, + delta_start: 5, + length: 4, + token_type: 1, + token_modifiers_bitset: 0, + }, + ]), + }, + r#"{"start":0,"deleteCount":1,"data":[2,5,3,0,3,0,5,4,1,0]}"#, + ); + + test_serialization( + &SemanticTokensEdit { + start: 0, + delete_count: 1, + data: None, + }, + r#"{"start":0,"deleteCount":1}"#, + ); + } +} diff --git a/vendor/lsp-types/src/signature_help.rs b/vendor/lsp-types/src/signature_help.rs new file mode 100644 index 00000000..2466d108 --- /dev/null +++ b/vendor/lsp-types/src/signature_help.rs @@ -0,0 +1,207 @@ +use serde::{Deserialize, Serialize}; + +use crate::{ + Documentation, MarkupKind, TextDocumentPositionParams, TextDocumentRegistrationOptions, + WorkDoneProgressOptions, WorkDoneProgressParams, +}; + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SignatureInformationSettings { + /// Client supports the follow content formats for the documentation + /// property. The order describes the preferred format of the client. + #[serde(skip_serializing_if = "Option::is_none")] + pub documentation_format: Option>, + + #[serde(skip_serializing_if = "Option::is_none")] + pub parameter_information: Option, + + /// The client support the `activeParameter` property on `SignatureInformation` + /// literal. + /// + /// @since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub active_parameter_support: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ParameterInformationSettings { + /// The client supports processing label offsets instead of a + /// simple label string. + /// + /// @since 3.14.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub label_offset_support: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SignatureHelpClientCapabilities { + /// Whether completion supports dynamic registration. + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, + + /// The client supports the following `SignatureInformation` + /// specific properties. + #[serde(skip_serializing_if = "Option::is_none")] + pub signature_information: Option, + + /// The client supports to send additional context information for a + /// `textDocument/signatureHelp` request. A client that opts into + /// contextSupport will also support the `retriggerCharacters` on + /// `SignatureHelpOptions`. + /// + /// @since 3.15.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub context_support: Option, +} + +/// Signature help options. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SignatureHelpOptions { + /// The characters that trigger signature help automatically. + #[serde(skip_serializing_if = "Option::is_none")] + pub trigger_characters: Option>, + + /// List of characters that re-trigger signature help. + /// These trigger characters are only active when signature help is already showing. All trigger characters + /// are also counted as re-trigger characters. + #[serde(skip_serializing_if = "Option::is_none")] + pub retrigger_characters: Option>, + + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, +} + +/// Signature help options. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct SignatureHelpRegistrationOptions { + #[serde(flatten)] + pub text_document_registration_options: TextDocumentRegistrationOptions, +} + +/// Signature help options. +#[derive(Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(transparent)] +pub struct SignatureHelpTriggerKind(i32); +lsp_enum! { +impl SignatureHelpTriggerKind { + /// Signature help was invoked manually by the user or by a command. + pub const INVOKED: SignatureHelpTriggerKind = SignatureHelpTriggerKind(1); + /// Signature help was triggered by a trigger character. + pub const TRIGGER_CHARACTER: SignatureHelpTriggerKind = SignatureHelpTriggerKind(2); + /// Signature help was triggered by the cursor moving or by the document content changing. + pub const CONTENT_CHANGE: SignatureHelpTriggerKind = SignatureHelpTriggerKind(3); +} +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SignatureHelpParams { + /// The signature help context. This is only available if the client specifies + /// to send this using the client capability `textDocument.signatureHelp.contextSupport === true` + #[serde(skip_serializing_if = "Option::is_none")] + pub context: Option, + + #[serde(flatten)] + pub text_document_position_params: TextDocumentPositionParams, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SignatureHelpContext { + /// Action that caused signature help to be triggered. + pub trigger_kind: SignatureHelpTriggerKind, + + /// Character that caused signature help to be triggered. + /// This is undefined when `triggerKind !== SignatureHelpTriggerKind.TriggerCharacter` + #[serde(skip_serializing_if = "Option::is_none")] + pub trigger_character: Option, + + /// `true` if signature help was already showing when it was triggered. + /// Retriggers occur when the signature help is already active and can be caused by actions such as + /// typing a trigger character, a cursor move, or document content changes. + pub is_retrigger: bool, + + /// The currently active `SignatureHelp`. + /// The `activeSignatureHelp` has its `SignatureHelp.activeSignature` field updated based on + /// the user navigating through available signatures. + #[serde(skip_serializing_if = "Option::is_none")] + pub active_signature_help: Option, +} + +/// Signature help represents the signature of something +/// callable. There can be multiple signature but only one +/// active and only one active parameter. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SignatureHelp { + /// One or more signatures. + pub signatures: Vec, + + /// The active signature. + #[serde(skip_serializing_if = "Option::is_none")] + pub active_signature: Option, + + /// The active parameter of the active signature. + #[serde(skip_serializing_if = "Option::is_none")] + pub active_parameter: Option, +} + +/// Represents the signature of something callable. A signature +/// can have a label, like a function-name, a doc-comment, and +/// a set of parameters. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SignatureInformation { + /// The label of this signature. Will be shown in + /// the UI. + pub label: String, + + /// The human-readable doc-comment of this signature. Will be shown + /// in the UI but can be omitted. + #[serde(skip_serializing_if = "Option::is_none")] + pub documentation: Option, + + /// The parameters of this signature. + #[serde(skip_serializing_if = "Option::is_none")] + pub parameters: Option>, + + /// The index of the active parameter. + /// + /// If provided, this is used in place of `SignatureHelp.activeParameter`. + /// + /// @since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub active_parameter: Option, +} + +/// Represents a parameter of a callable-signature. A parameter can +/// have a label and a doc-comment. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ParameterInformation { + /// The label of this parameter information. + /// + /// Either a string or an inclusive start and exclusive end offsets within its containing + /// signature label. (see SignatureInformation.label). *Note*: A label of type string must be + /// a substring of its containing signature label. + pub label: ParameterLabel, + + /// The human-readable doc-comment of this parameter. Will be shown + /// in the UI but can be omitted. + #[serde(skip_serializing_if = "Option::is_none")] + pub documentation: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum ParameterLabel { + Simple(String), + LabelOffsets([u32; 2]), +} diff --git a/vendor/lsp-types/src/trace.rs b/vendor/lsp-types/src/trace.rs new file mode 100644 index 00000000..7abcc567 --- /dev/null +++ b/vendor/lsp-types/src/trace.rs @@ -0,0 +1,77 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct SetTraceParams { + /// The new value that should be assigned to the trace setting. + pub value: TraceValue, +} + +/// A TraceValue represents the level of verbosity with which the server systematically +/// reports its execution trace using `LogTrace` notifications. +/// +/// The initial trace value is set by the client at initialization and can be modified +/// later using the `SetTrace` notification. +#[derive(Debug, Eq, PartialEq, Clone, Copy, Deserialize, Serialize, Default)] +#[serde(rename_all = "camelCase")] +pub enum TraceValue { + /// The server should not send any `$/logTrace` notification + #[default] + Off, + /// The server should not add the 'verbose' field in the `LogTraceParams` + Messages, + Verbose, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct LogTraceParams { + /// The message to be logged. + pub message: String, + /// Additional information that can be computed if the `trace` configuration + /// is set to `'verbose'` + #[serde(skip_serializing_if = "Option::is_none")] + pub verbose: Option, +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::tests::test_serialization; + + #[test] + fn test_set_trace_params() { + test_serialization( + &SetTraceParams { + value: TraceValue::Off, + }, + r#"{"value":"off"}"#, + ); + } + + #[test] + fn test_log_trace_params() { + test_serialization( + &LogTraceParams { + message: "message".into(), + verbose: None, + }, + r#"{"message":"message"}"#, + ); + + test_serialization( + &LogTraceParams { + message: "message".into(), + verbose: Some("verbose".into()), + }, + r#"{"message":"message","verbose":"verbose"}"#, + ); + } + + #[test] + fn test_trace_value() { + test_serialization( + &vec![TraceValue::Off, TraceValue::Messages, TraceValue::Verbose], + r#"["off","messages","verbose"]"#, + ); + } +} diff --git a/vendor/lsp-types/src/type_hierarchy.rs b/vendor/lsp-types/src/type_hierarchy.rs new file mode 100644 index 00000000..568a03e2 --- /dev/null +++ b/vendor/lsp-types/src/type_hierarchy.rs @@ -0,0 +1,90 @@ +use crate::{ + DynamicRegistrationClientCapabilities, LSPAny, PartialResultParams, Range, + StaticRegistrationOptions, SymbolKind, SymbolTag, TextDocumentPositionParams, + TextDocumentRegistrationOptions, Url, WorkDoneProgressOptions, WorkDoneProgressParams, +}; + +use serde::{Deserialize, Serialize}; + +pub type TypeHierarchyClientCapabilities = DynamicRegistrationClientCapabilities; + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +pub struct TypeHierarchyOptions { + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +pub struct TypeHierarchyRegistrationOptions { + #[serde(flatten)] + pub text_document_registration_options: TextDocumentRegistrationOptions, + #[serde(flatten)] + pub type_hierarchy_options: TypeHierarchyOptions, + #[serde(flatten)] + pub static_registration_options: StaticRegistrationOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct TypeHierarchyPrepareParams { + #[serde(flatten)] + pub text_document_position_params: TextDocumentPositionParams, + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct TypeHierarchySupertypesParams { + pub item: TypeHierarchyItem, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct TypeHierarchySubtypesParams { + pub item: TypeHierarchyItem, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TypeHierarchyItem { + /// The name of this item. + pub name: String, + + /// The kind of this item. + pub kind: SymbolKind, + + /// Tags for this item. + #[serde(skip_serializing_if = "Option::is_none")] + pub tags: Option, + + /// More detail for this item, e.g. the signature of a function. + #[serde(skip_serializing_if = "Option::is_none")] + pub detail: Option, + + /// The resource identifier of this item. + pub uri: Url, + + /// The range enclosing this symbol not including leading/trailing whitespace + /// but everything else, e.g. comments and code. + pub range: Range, + + /// The range that should be selected and revealed when this symbol is being + /// picked, e.g. the name of a function. Must be contained by the + /// [`range`](#TypeHierarchyItem.range). + pub selection_range: Range, + + /// A data entry field that is preserved between a type hierarchy prepare and + /// supertypes or subtypes requests. It could also be used to identify the + /// type hierarchy in the server, helping improve the performance on + /// resolving supertypes and subtypes. + #[serde(skip_serializing_if = "Option::is_none")] + pub data: Option, +} diff --git a/vendor/lsp-types/src/window.rs b/vendor/lsp-types/src/window.rs new file mode 100644 index 00000000..65b457ec --- /dev/null +++ b/vendor/lsp-types/src/window.rs @@ -0,0 +1,177 @@ +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; + +use serde_json::Value; + +use url::Url; + +use crate::Range; + +#[derive(Eq, PartialEq, Clone, Copy, Deserialize, Serialize)] +#[serde(transparent)] +pub struct MessageType(i32); +lsp_enum! { +impl MessageType { + /// An error message. + pub const ERROR: MessageType = MessageType(1); + /// A warning message. + pub const WARNING: MessageType = MessageType(2); + /// An information message; + pub const INFO: MessageType = MessageType(3); + /// A log message. + pub const LOG: MessageType = MessageType(4); + /// A debug message. + /// + /// @since 3.18.0 + pub const DEBUG: MessageType = MessageType(5); +} +} + +/// Window specific client capabilities. +#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct WindowClientCapabilities { + /// Whether client supports handling progress notifications. If set + /// servers are allowed to report in `workDoneProgress` property in the + /// request specific server capabilities. + /// + /// @since 3.15.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub work_done_progress: Option, + + /// Capabilities specific to the showMessage request. + /// + /// @since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub show_message: Option, + + /// Client capabilities for the show document request. + /// + /// @since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub show_document: Option, +} + +/// Show message request client capabilities +#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ShowMessageRequestClientCapabilities { + /// Capabilities specific to the `MessageActionItem` type. + #[serde(skip_serializing_if = "Option::is_none")] + pub message_action_item: Option, +} + +#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct MessageActionItemCapabilities { + /// Whether the client supports additional attributes which + /// are preserved and send back to the server in the + /// request's response. + #[serde(skip_serializing_if = "Option::is_none")] + pub additional_properties_support: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct MessageActionItem { + /// A short title like 'Retry', 'Open Log' etc. + pub title: String, + + /// Additional attributes that the client preserves and + /// sends back to the server. This depends on the client + /// capability window.messageActionItem.additionalPropertiesSupport + #[serde(flatten)] + pub properties: HashMap, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum MessageActionItemProperty { + String(String), + Boolean(bool), + Integer(i32), + Object(Value), +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct LogMessageParams { + /// The message type. See {@link MessageType} + #[serde(rename = "type")] + pub typ: MessageType, + + /// The actual message + pub message: String, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct ShowMessageParams { + /// The message type. See {@link MessageType}. + #[serde(rename = "type")] + pub typ: MessageType, + + /// The actual message. + pub message: String, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct ShowMessageRequestParams { + /// The message type. See {@link MessageType} + #[serde(rename = "type")] + pub typ: MessageType, + + /// The actual message + pub message: String, + + /// The message action items to present. + #[serde(skip_serializing_if = "Option::is_none")] + pub actions: Option>, +} + +/// Client capabilities for the show document request. +#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ShowDocumentClientCapabilities { + /// The client has support for the show document request. + pub support: bool, +} + +/// Params to show a document. +/// +/// @since 3.16.0 +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ShowDocumentParams { + /// The document uri to show. + pub uri: Url, + + /// Indicates to show the resource in an external program. + /// To show for example `https://code.visualstudio.com/` + /// in the default WEB browser set `external` to `true`. + #[serde(skip_serializing_if = "Option::is_none")] + pub external: Option, + + /// An optional property to indicate whether the editor + /// showing the document should take focus or not. + /// Clients might ignore this property if an external + /// program in started. + #[serde(skip_serializing_if = "Option::is_none")] + pub take_focus: Option, + + /// An optional selection range if the document is a text + /// document. Clients might ignore the property if an + /// external program is started or the file is not a text + /// file. + #[serde(skip_serializing_if = "Option::is_none")] + pub selection: Option, +} + +/// The result of an show document request. +/// +/// @since 3.16.0 +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ShowDocumentResult { + /// A boolean indicating if the show was successful. + pub success: bool, +} diff --git a/vendor/lsp-types/src/workspace_diagnostic.rs b/vendor/lsp-types/src/workspace_diagnostic.rs new file mode 100644 index 00000000..e8a7646b --- /dev/null +++ b/vendor/lsp-types/src/workspace_diagnostic.rs @@ -0,0 +1,149 @@ +use serde::{Deserialize, Serialize}; +use url::Url; + +use crate::{ + FullDocumentDiagnosticReport, PartialResultParams, UnchangedDocumentDiagnosticReport, + WorkDoneProgressParams, +}; + +/// Workspace client capabilities specific to diagnostic pull requests. +/// +/// @since 3.17.0 +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DiagnosticWorkspaceClientCapabilities { + /// Whether the client implementation supports a refresh request sent from + /// the server to the client. + /// + /// Note that this event is global and will force the client to refresh all + /// pulled diagnostics currently shown. It should be used with absolute care + /// and is useful for situation where a server for example detects a project + /// wide change that requires such a calculation. + #[serde(skip_serializing_if = "Option::is_none")] + pub refresh_support: Option, +} + +/// A previous result ID in a workspace pull request. +/// +/// @since 3.17.0 +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct PreviousResultId { + /// The URI for which the client knows a result ID. + pub uri: Url, + + /// The value of the previous result ID. + pub value: String, +} + +/// Parameters of the workspace diagnostic request. +/// +/// @since 3.17.0 +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct WorkspaceDiagnosticParams { + /// The additional identifier provided during registration. + pub identifier: Option, + + /// The currently known diagnostic reports with their + /// previous result ids. + pub previous_result_ids: Vec, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +/// A full document diagnostic report for a workspace diagnostic result. +/// +/// @since 3.17.0 +#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct WorkspaceFullDocumentDiagnosticReport { + /// The URI for which diagnostic information is reported. + pub uri: Url, + + /// The version number for which the diagnostics are reported. + /// + /// If the document is not marked as open, `None` can be provided. + pub version: Option, + + #[serde(flatten)] + pub full_document_diagnostic_report: FullDocumentDiagnosticReport, +} + +/// An unchanged document diagnostic report for a workspace diagnostic result. +/// +/// @since 3.17.0 +#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct WorkspaceUnchangedDocumentDiagnosticReport { + /// The URI for which diagnostic information is reported. + pub uri: Url, + + /// The version number for which the diagnostics are reported. + /// + /// If the document is not marked as open, `None` can be provided. + pub version: Option, + + #[serde(flatten)] + pub unchanged_document_diagnostic_report: UnchangedDocumentDiagnosticReport, +} + +/// A workspace diagnostic document report. +/// +/// @since 3.17.0 +#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] +#[serde(tag = "kind", rename_all = "lowercase")] +pub enum WorkspaceDocumentDiagnosticReport { + Full(WorkspaceFullDocumentDiagnosticReport), + Unchanged(WorkspaceUnchangedDocumentDiagnosticReport), +} + +impl From for WorkspaceDocumentDiagnosticReport { + fn from(from: WorkspaceFullDocumentDiagnosticReport) -> Self { + WorkspaceDocumentDiagnosticReport::Full(from) + } +} + +impl From for WorkspaceDocumentDiagnosticReport { + fn from(from: WorkspaceUnchangedDocumentDiagnosticReport) -> Self { + WorkspaceDocumentDiagnosticReport::Unchanged(from) + } +} + +/// A workspace diagnostic report. +/// +/// @since 3.17.0 +#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)] +pub struct WorkspaceDiagnosticReport { + pub items: Vec, +} + +/// A partial result for a workspace diagnostic report. +/// +/// @since 3.17.0 +#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)] +pub struct WorkspaceDiagnosticReportPartialResult { + pub items: Vec, +} + +#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] +#[serde(untagged)] +pub enum WorkspaceDiagnosticReportResult { + Report(WorkspaceDiagnosticReport), + Partial(WorkspaceDiagnosticReportPartialResult), +} + +impl From for WorkspaceDiagnosticReportResult { + fn from(from: WorkspaceDiagnosticReport) -> Self { + WorkspaceDiagnosticReportResult::Report(from) + } +} + +impl From for WorkspaceDiagnosticReportResult { + fn from(from: WorkspaceDiagnosticReportPartialResult) -> Self { + WorkspaceDiagnosticReportResult::Partial(from) + } +} diff --git a/vendor/lsp-types/src/workspace_folders.rs b/vendor/lsp-types/src/workspace_folders.rs new file mode 100644 index 00000000..aeca89ff --- /dev/null +++ b/vendor/lsp-types/src/workspace_folders.rs @@ -0,0 +1,49 @@ +use serde::{Deserialize, Serialize}; +use url::Url; + +use crate::OneOf; + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct WorkspaceFoldersServerCapabilities { + /// The server has support for workspace folders + #[serde(skip_serializing_if = "Option::is_none")] + pub supported: Option, + + /// Whether the server wants to receive workspace folder + /// change notifications. + /// + /// If a string is provided, the string is treated as an ID + /// under which the notification is registered on the client + /// side. The ID can be used to unregister for these events + /// using the `client/unregisterCapability` request. + #[serde(skip_serializing_if = "Option::is_none")] + pub change_notifications: Option>, +} + +#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct WorkspaceFolder { + /// The associated URI for this workspace folder. + pub uri: Url, + /// The name of the workspace folder. Defaults to the uri's basename. + pub name: String, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DidChangeWorkspaceFoldersParams { + /// The actual workspace folder change event. + pub event: WorkspaceFoldersChangeEvent, +} + +/// The workspace folder change event. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct WorkspaceFoldersChangeEvent { + /// The array of added workspace folders + pub added: Vec, + + /// The array of the removed workspace folders + pub removed: Vec, +} diff --git a/vendor/lsp-types/src/workspace_symbols.rs b/vendor/lsp-types/src/workspace_symbols.rs new file mode 100644 index 00000000..9ba80895 --- /dev/null +++ b/vendor/lsp-types/src/workspace_symbols.rs @@ -0,0 +1,105 @@ +use crate::{ + LSPAny, Location, OneOf, PartialResultParams, SymbolInformation, SymbolKind, + SymbolKindCapability, SymbolTag, TagSupport, Url, WorkDoneProgressParams, +}; + +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct WorkspaceSymbolClientCapabilities { + /// This capability supports dynamic registration. + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, + + /// Specific capabilities for the `SymbolKind` in the `workspace/symbol` request. + #[serde(skip_serializing_if = "Option::is_none")] + pub symbol_kind: Option, + + /// The client supports tags on `SymbolInformation`. + /// Clients supporting tags have to handle unknown tags gracefully. + /// + /// @since 3.16.0 + #[serde( + default, + skip_serializing_if = "Option::is_none", + deserialize_with = "TagSupport::deserialize_compat" + )] + pub tag_support: Option>, + + /// The client support partial workspace symbols. The client will send the + /// request `workspaceSymbol/resolve` to the server to resolve additional + /// properties. + /// + /// @since 3.17.0 + #[serde(skip_serializing_if = "Option::is_none")] + pub resolve_support: Option, +} + +/// The parameters of a Workspace Symbol Request. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +pub struct WorkspaceSymbolParams { + #[serde(flatten)] + pub partial_result_params: PartialResultParams, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + /// A non-empty query string + pub query: String, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +pub struct WorkspaceSymbolResolveSupportCapability { + /// The properties that a client can resolve lazily. Usually + /// `location.range` + pub properties: Vec, +} + +/// A special workspace symbol that supports locations without a range +/// +/// @since 3.17.0 +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct WorkspaceSymbol { + /// The name of this symbol. + pub name: String, + + /// The kind of this symbol. + pub kind: SymbolKind, + + /// Tags for this completion item. + #[serde(skip_serializing_if = "Option::is_none")] + pub tags: Option>, + + /// The name of the symbol containing this symbol. This information is for + /// user interface purposes (e.g. to render a qualifier in the user interface + /// if necessary). It can't be used to re-infer a hierarchy for the document + /// symbols. + #[serde(skip_serializing_if = "Option::is_none")] + pub container_name: Option, + + /// The location of this symbol. Whether a server is allowed to + /// return a location without a range depends on the client + /// capability `workspace.symbol.resolveSupport`. + /// + /// See also `SymbolInformation.location`. + pub location: OneOf, + + /// A data entry field that is preserved on a workspace symbol between a + /// workspace symbol request and a workspace symbol resolve request. + #[serde(skip_serializing_if = "Option::is_none")] + pub data: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct WorkspaceLocation { + pub uri: Url, +} + +#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum WorkspaceSymbolResponse { + Flat(Vec), + Nested(Vec), +} diff --git a/vendor/lsp-types/tests/lsif.rs b/vendor/lsp-types/tests/lsif.rs new file mode 100644 index 00000000..3b90c8bc --- /dev/null +++ b/vendor/lsp-types/tests/lsif.rs @@ -0,0 +1,18 @@ +#[test] +#[cfg(unix)] +fn run() { + use lsp_types::lsif::Entry; + + let jsonl = include_str!("tsc-unix.lsif"); + for json in jsonl.lines() { + let r = serde_json::from_str::(&json).expect(&format!("can not parse {}", json)); + let x = serde_json::to_string(&r).expect(&format!("can not serialize {}", json)); + assert_eq!( + serde_json::from_str::(&x).unwrap(), + serde_json::from_str::(json).unwrap(), + "and strings:\ntheir: {}\n our: {}", + json, + x, + ); + } +} diff --git a/vendor/lsp-types/tests/tsc-unix.lsif b/vendor/lsp-types/tests/tsc-unix.lsif new file mode 100644 index 00000000..24c4dc04 --- /dev/null +++ b/vendor/lsp-types/tests/tsc-unix.lsif @@ -0,0 +1,135 @@ +{"id":1,"type":"vertex","label":"metaData","version":"0.4.3","projectRoot":"file:///media/hamid/nv1/garbage","positionEncoding":"utf-16","toolInfo":{"name":"lsif-tsc","args":["-p","."],"version":"0.7.2"}} +{"id":2,"type":"vertex","label":"project","kind":"typescript"} +{"id":3,"type":"vertex","label":"$event","kind":"begin","scope":"project","data":2} +{"id":4,"type":"vertex","label":"document","uri":"file:///media/hamid/nv1/garbage/a.ts","languageId":"typescript"} +{"id":5,"type":"vertex","label":"$event","kind":"begin","scope":"document","data":4} +{"id":6,"type":"vertex","label":"resultSet"} +{"id":7,"type":"vertex","label":"moniker","kind":"export","unique":"document","scheme":"tsc","identifier":"a:"} +{"id":8,"type":"edge","label":"moniker","outV":6,"inV":7} +{"id":9,"type":"vertex","label":"packageInformation","name":"garbage","manager":"npm","version":"1.0.0"} +{"id":10,"type":"vertex","label":"moniker","kind":"export","unique":"global","scheme":"npm","identifier":"garbage:a:"} +{"id":11,"type":"edge","label":"packageInformation","outV":10,"inV":9} +{"id":12,"type":"edge","label":"nextMoniker","outV":7,"inV":10} +{"id":13,"type":"vertex","label":"range","start":{"line":0,"character":0},"end":{"line":0,"character":0},"tag":{"type":"definition","text":"","kind":7,"fullRange":{"start":{"line":0,"character":0},"end":{"line":3,"character":0}}}} +{"id":14,"type":"edge","label":"next","outV":13,"inV":6} +{"id":15,"type":"vertex","label":"resultSet"} +{"id":16,"type":"vertex","label":"moniker","kind":"export","unique":"document","scheme":"tsc","identifier":"a:a"} +{"id":17,"type":"edge","label":"moniker","outV":15,"inV":16} +{"id":18,"type":"vertex","label":"moniker","kind":"export","unique":"global","scheme":"npm","identifier":"garbage:a:a"} +{"id":19,"type":"edge","label":"packageInformation","outV":18,"inV":9} +{"id":20,"type":"edge","label":"nextMoniker","outV":16,"inV":18} +{"id":21,"type":"vertex","label":"range","start":{"line":0,"character":13},"end":{"line":0,"character":14},"tag":{"type":"definition","text":"a","kind":7,"fullRange":{"start":{"line":0,"character":13},"end":{"line":2,"character":1}}}} +{"id":22,"type":"edge","label":"next","outV":21,"inV":15} +{"id":23,"type":"vertex","label":"hoverResult","result":{"contents":[{"language":"typescript","value":"const a: (x: number, y: string) => string"}]}} +{"id":24,"type":"edge","label":"textDocument/hover","outV":15,"inV":23} +{"id":25,"type":"vertex","label":"resultSet"} +{"id":26,"type":"vertex","label":"moniker","kind":"local","unique":"document","scheme":"tsc","identifier":"dW50H+qRDGdPj+RYWpwLSg=="} +{"id":27,"type":"edge","label":"moniker","outV":25,"inV":26} +{"id":28,"type":"vertex","label":"range","start":{"line":0,"character":18},"end":{"line":0,"character":19},"tag":{"type":"definition","text":"x","kind":7,"fullRange":{"start":{"line":0,"character":18},"end":{"line":0,"character":27}}}} +{"id":29,"type":"edge","label":"next","outV":28,"inV":25} +{"id":30,"type":"vertex","label":"hoverResult","result":{"contents":[{"language":"typescript","value":"(parameter) x: number"}]}} +{"id":31,"type":"edge","label":"textDocument/hover","outV":25,"inV":30} +{"id":32,"type":"vertex","label":"resultSet"} +{"id":33,"type":"vertex","label":"moniker","kind":"local","unique":"document","scheme":"tsc","identifier":"W2CLXh2PW8+ib7xga5YF4A=="} +{"id":34,"type":"edge","label":"moniker","outV":32,"inV":33} +{"id":35,"type":"vertex","label":"range","start":{"line":0,"character":29},"end":{"line":0,"character":30},"tag":{"type":"definition","text":"y","kind":7,"fullRange":{"start":{"line":0,"character":29},"end":{"line":0,"character":38}}}} +{"id":36,"type":"edge","label":"next","outV":35,"inV":32} +{"id":37,"type":"vertex","label":"hoverResult","result":{"contents":[{"language":"typescript","value":"(parameter) y: string"}]}} +{"id":38,"type":"edge","label":"textDocument/hover","outV":32,"inV":37} +{"id":39,"type":"vertex","label":"resultSet"} +{"id":40,"type":"vertex","label":"moniker","kind":"local","unique":"document","scheme":"tsc","identifier":"WLUBvuhxsSADYrjTwQnBoA=="} +{"id":41,"type":"edge","label":"moniker","outV":39,"inV":40} +{"id":42,"type":"vertex","label":"range","start":{"line":0,"character":40},"end":{"line":0,"character":42},"tag":{"type":"reference","text":"=>"}} +{"id":43,"type":"edge","label":"next","outV":42,"inV":39} +{"id":44,"type":"vertex","label":"range","start":{"line":1,"character":18},"end":{"line":1,"character":19},"tag":{"type":"reference","text":"y"}} +{"id":45,"type":"edge","label":"next","outV":44,"inV":32} +{"id":46,"type":"vertex","label":"document","uri":"file:///media/hamid/nv1/garbage/node_modules/typescript-lsif/lib/lib.es2015.core.d.ts","languageId":"typescript"} +{"id":47,"type":"vertex","label":"$event","kind":"begin","scope":"document","data":46} +{"id":48,"type":"vertex","label":"resultSet"} +{"id":49,"type":"vertex","label":"moniker","kind":"export","unique":"document","scheme":"tsc","identifier":"node_modules/typescript-lsif/lib/lib.es2015.core:String.repeat"} +{"id":50,"type":"edge","label":"moniker","outV":48,"inV":49} +{"id":51,"type":"vertex","label":"moniker","kind":"export","unique":"global","scheme":"npm","identifier":"garbage:node_modules/typescript-lsif/lib/lib.es2015.core:String.repeat"} +{"id":52,"type":"edge","label":"packageInformation","outV":51,"inV":9} +{"id":53,"type":"edge","label":"nextMoniker","outV":49,"inV":51} +{"id":54,"type":"vertex","label":"range","start":{"line":446,"character":4},"end":{"line":446,"character":10},"tag":{"type":"definition","text":"repeat","kind":7,"fullRange":{"start":{"line":446,"character":4},"end":{"line":446,"character":34}}}} +{"id":55,"type":"edge","label":"next","outV":54,"inV":48} +{"id":56,"type":"vertex","label":"hoverResult","result":{"contents":[{"language":"typescript","value":"(method) String.repeat(count: number): string"},"Returns a String value that is made from count copies appended together. If count is 0,\nthe empty string is returned."]}} +{"id":57,"type":"edge","label":"textDocument/hover","outV":48,"inV":56} +{"id":58,"type":"vertex","label":"range","start":{"line":1,"character":20},"end":{"line":1,"character":26},"tag":{"type":"reference","text":"repeat"}} +{"id":59,"type":"edge","label":"next","outV":58,"inV":48} +{"id":60,"type":"vertex","label":"range","start":{"line":1,"character":27},"end":{"line":1,"character":28},"tag":{"type":"reference","text":"x"}} +{"id":61,"type":"edge","label":"next","outV":60,"inV":25} +{"id":62,"type":"vertex","label":"definitionResult"} +{"id":63,"type":"edge","label":"textDocument/definition","outV":6,"inV":62} +{"id":64,"type":"edge","label":"item","outV":62,"inVs":[13],"document":4} +{"id":65,"type":"vertex","label":"referenceResult"} +{"id":66,"type":"edge","label":"textDocument/references","outV":6,"inV":65} +{"id":67,"type":"edge","label":"item","outV":65,"inVs":[13],"document":4,"property":"definitions"} +{"id":68,"type":"vertex","label":"definitionResult"} +{"id":69,"type":"edge","label":"textDocument/definition","outV":15,"inV":68} +{"id":70,"type":"edge","label":"item","outV":68,"inVs":[21],"document":4} +{"id":71,"type":"vertex","label":"referenceResult"} +{"id":72,"type":"edge","label":"textDocument/references","outV":15,"inV":71} +{"id":73,"type":"edge","label":"item","outV":71,"inVs":[21],"document":4,"property":"definitions"} +{"id":74,"type":"vertex","label":"definitionResult"} +{"id":75,"type":"edge","label":"textDocument/definition","outV":25,"inV":74} +{"id":76,"type":"edge","label":"item","outV":74,"inVs":[28],"document":4} +{"id":77,"type":"vertex","label":"referenceResult"} +{"id":78,"type":"edge","label":"textDocument/references","outV":25,"inV":77} +{"id":79,"type":"edge","label":"item","outV":77,"inVs":[28],"document":4,"property":"definitions"} +{"id":80,"type":"edge","label":"item","outV":77,"inVs":[60],"document":4,"property":"references"} +{"id":81,"type":"vertex","label":"definitionResult"} +{"id":82,"type":"edge","label":"textDocument/definition","outV":32,"inV":81} +{"id":83,"type":"edge","label":"item","outV":81,"inVs":[35],"document":4} +{"id":84,"type":"vertex","label":"referenceResult"} +{"id":85,"type":"edge","label":"textDocument/references","outV":32,"inV":84} +{"id":86,"type":"edge","label":"item","outV":84,"inVs":[35],"document":4,"property":"definitions"} +{"id":87,"type":"edge","label":"item","outV":84,"inVs":[44],"document":4,"property":"references"} +{"id":88,"type":"vertex","label":"referenceResult"} +{"id":89,"type":"edge","label":"textDocument/references","outV":39,"inV":88} +{"id":90,"type":"edge","label":"item","outV":88,"inVs":[42],"document":4,"property":"references"} +{"id":91,"type":"vertex","label":"referenceResult"} +{"id":92,"type":"edge","label":"textDocument/references","outV":48,"inV":91} +{"id":93,"type":"edge","label":"item","outV":91,"inVs":[58],"document":4,"property":"references"} +{"id":94,"type":"vertex","label":"document","uri":"file:///media/hamid/nv1/garbage/b.ts","languageId":"typescript"} +{"id":95,"type":"vertex","label":"$event","kind":"begin","scope":"document","data":94} +{"id":96,"type":"vertex","label":"resultSet"} +{"id":97,"type":"vertex","label":"moniker","kind":"export","unique":"document","scheme":"tsc","identifier":"b:"} +{"id":98,"type":"edge","label":"moniker","outV":96,"inV":97} +{"id":99,"type":"vertex","label":"moniker","kind":"export","unique":"global","scheme":"npm","identifier":"garbage:b:"} +{"id":100,"type":"edge","label":"packageInformation","outV":99,"inV":9} +{"id":101,"type":"edge","label":"nextMoniker","outV":97,"inV":99} +{"id":102,"type":"vertex","label":"range","start":{"line":0,"character":0},"end":{"line":0,"character":0},"tag":{"type":"definition","text":"","kind":7,"fullRange":{"start":{"line":0,"character":0},"end":{"line":3,"character":0}}}} +{"id":103,"type":"edge","label":"next","outV":102,"inV":96} +{"id":104,"type":"vertex","label":"resultSet"} +{"id":105,"type":"edge","label":"next","outV":104,"inV":15} +{"id":106,"type":"vertex","label":"moniker","kind":"local","unique":"document","scheme":"tsc","identifier":"sNwThRvTZlfLwz6po1s2Zg=="} +{"id":107,"type":"edge","label":"moniker","outV":104,"inV":106} +{"id":108,"type":"vertex","label":"range","start":{"line":0,"character":9},"end":{"line":0,"character":10},"tag":{"type":"definition","text":"a","kind":7,"fullRange":{"start":{"line":0,"character":9},"end":{"line":0,"character":10}}}} +{"id":109,"type":"edge","label":"next","outV":108,"inV":104} +{"id":110,"type":"vertex","label":"hoverResult","result":{"contents":[{"language":"typescript","value":"(alias) const a: (x: number, y: string) => string\nimport a"}]}} +{"id":111,"type":"edge","label":"textDocument/hover","outV":104,"inV":110} +{"id":112,"type":"vertex","label":"range","start":{"line":0,"character":18},"end":{"line":0,"character":23},"tag":{"type":"reference","text":"\"./a\""}} +{"id":113,"type":"edge","label":"next","outV":112,"inV":6} +{"id":114,"type":"vertex","label":"range","start":{"line":2,"character":0},"end":{"line":2,"character":1},"tag":{"type":"reference","text":"a"}} +{"id":115,"type":"edge","label":"next","outV":114,"inV":104} +{"id":116,"type":"vertex","label":"definitionResult"} +{"id":117,"type":"edge","label":"textDocument/definition","outV":96,"inV":116} +{"id":118,"type":"edge","label":"item","outV":116,"inVs":[102],"document":94} +{"id":119,"type":"vertex","label":"referenceResult"} +{"id":120,"type":"edge","label":"textDocument/references","outV":96,"inV":119} +{"id":121,"type":"edge","label":"item","outV":119,"inVs":[102],"document":94,"property":"definitions"} +{"id":122,"type":"edge","label":"item","outV":71,"inVs":[108,114],"document":94,"property":"references"} +{"id":123,"type":"edge","label":"item","outV":65,"inVs":[112],"document":94,"property":"references"} +{"id":124,"type":"vertex","label":"definitionResult"} +{"id":125,"type":"edge","label":"textDocument/definition","outV":48,"inV":124} +{"id":126,"type":"edge","label":"item","outV":124,"inVs":[54],"document":46} +{"id":127,"type":"edge","label":"item","outV":91,"inVs":[54],"document":46,"property":"definitions"} +{"id":128,"type":"edge","label":"contains","outV":4,"inVs":[13,21,28,35,42,44,58,60]} +{"id":129,"type":"vertex","label":"$event","kind":"end","scope":"document","data":4} +{"id":130,"type":"edge","label":"contains","outV":46,"inVs":[54]} +{"id":131,"type":"vertex","label":"$event","kind":"end","scope":"document","data":46} +{"id":132,"type":"edge","label":"contains","outV":94,"inVs":[102,108,112,114]} +{"id":133,"type":"vertex","label":"$event","kind":"end","scope":"document","data":94} +{"id":134,"type":"edge","label":"contains","outV":2,"inVs":[4,46,94]} +{"id":135,"type":"vertex","label":"$event","kind":"end","scope":"project","data":2} diff --git a/vendor/psp-types/.gitignore b/vendor/psp-types/.gitignore new file mode 100644 index 00000000..4fffb2f8 --- /dev/null +++ b/vendor/psp-types/.gitignore @@ -0,0 +1,2 @@ +/target +/Cargo.lock diff --git a/vendor/psp-types/Cargo.toml b/vendor/psp-types/Cargo.toml new file mode 100644 index 00000000..35a499f2 --- /dev/null +++ b/vendor/psp-types/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "psp-types" +version = "0.1.0" +license = "Apache-2.0" +description = "Types for interaction with plugin server protocol" +edition = "2021" + +[dependencies] +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +lsp-types = { version = "0", features = ["proposed"] } diff --git a/vendor/psp-types/README.md b/vendor/psp-types/README.md new file mode 100644 index 00000000..45734a8a --- /dev/null +++ b/vendor/psp-types/README.md @@ -0,0 +1 @@ +# psp-types diff --git a/vendor/psp-types/src/lib.rs b/vendor/psp-types/src/lib.rs new file mode 100644 index 00000000..ea83685b --- /dev/null +++ b/vendor/psp-types/src/lib.rs @@ -0,0 +1,114 @@ +pub use lsp_types; +pub use lsp_types::notification::Notification; +pub use lsp_types::request::Request; +use lsp_types::{DocumentSelector, Url}; +use serde::{Deserialize, Serialize}; +use serde_json::Value; + +pub enum StartLspServer {} + +impl Request for StartLspServer { + type Params = StartLspServerParams; + type Result = StartLspServerResult; + const METHOD: &'static str = "host/startLspServer"; +} + +#[derive(Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct StartLspServerParams { + pub server_uri: Url, + pub server_args: Vec, + pub document_selector: DocumentSelector, + pub options: Option, +} + +/// The id of a started Language Server. +/// This is used to reference the server in future requests. +pub type LspId = u64; + +#[derive(Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct StartLspServerResult { + pub id: LspId, +} + +pub struct SendLspNotification {} + +impl Notification for SendLspNotification { + type Params = SendLspNotificationParams; + const METHOD: &'static str = "host/sendLspNotification"; +} + +#[derive(Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SendLspNotificationParams { + /// Id of the LSP server the notification should be sent to + pub id: LspId, + pub method: String, + pub params: Value, +} + +/// Send an LSP request to a started LSP server. +/// This does not include the `id` of the request, because that is handled by the client editor to +/// avoid collisions. +pub struct SendLspRequest {} + +impl Request for SendLspRequest { + type Params = SendLspRequestParams; + type Result = SendLspRequestResult; + const METHOD: &'static str = "host/sendLspRequest"; +} + +#[derive(Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SendLspRequestParams { + /// Id of the LSP server the notification should be sent to + pub id: LspId, + pub method: String, + pub params: Value, +} + +#[derive(Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SendLspRequestResult { + pub result: Value, +} + +pub enum ExecuteProcess {} + +impl Request for ExecuteProcess { + type Params = ExecuteProcessParams; + type Result = ExecuteProcessResult; + const METHOD: &'static str = "host/executeProcess"; +} + +#[derive(Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ExecuteProcessParams { + pub program: String, + pub args: Vec, +} + +#[derive(Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ExecuteProcessResult { + pub success: bool, + pub stdout: Option>, + pub stderr: Option>, +} + +pub enum RegisterDebuggerType {} + +impl Request for RegisterDebuggerType { + type Params = RegisterDebuggerTypeParams; + type Result = (); + const METHOD: &'static str = "host/registerDebuggerType"; +} + +#[derive(Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct RegisterDebuggerTypeParams { + pub debugger_type: String, + pub program: String, + pub args: Option>, +} diff --git a/vendor/structdesc/.gitignore b/vendor/structdesc/.gitignore new file mode 100644 index 00000000..96ef6c0b --- /dev/null +++ b/vendor/structdesc/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock diff --git a/vendor/structdesc/.taplo.toml b/vendor/structdesc/.taplo.toml new file mode 100644 index 00000000..ee911f0c --- /dev/null +++ b/vendor/structdesc/.taplo.toml @@ -0,0 +1,13 @@ +include = ["**/*.toml"] +exclude = ["lapce-proxy/src/**"] + +[[rule]] +include = ["**/Cargo.toml", ".taplo.toml", "Cargo.toml"] + +[rule.formatting] +align_entries = true +align_comments = true +array_trailing_comma = true +trailing_newline = true +column_width = 100 +inline_table_expand = false diff --git a/vendor/structdesc/Cargo.toml b/vendor/structdesc/Cargo.toml new file mode 100644 index 00000000..69fa9b84 --- /dev/null +++ b/vendor/structdesc/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "structdesc" +version = "0.1.0" +edition = "2021" +license = "MIT" + +[dependencies] +darling = { version = "0.14" } +proc-macro2 = { version = "1" } +quote = { version = "1.0.14" } +syn = { version = "1.0.84", features = ["full"] } + +[lib] +proc-macro = true diff --git a/vendor/structdesc/LICENCE b/vendor/structdesc/LICENCE new file mode 100644 index 00000000..a8bf03a3 --- /dev/null +++ b/vendor/structdesc/LICENCE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Lapce + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/structdesc/src/lib.rs b/vendor/structdesc/src/lib.rs new file mode 100644 index 00000000..ca2a3e59 --- /dev/null +++ b/vendor/structdesc/src/lib.rs @@ -0,0 +1,128 @@ +use darling::{ast::Data, FromDeriveInput, FromField}; +use proc_macro2::TokenStream; +use quote::{quote, ToTokens}; +use syn::{parse_macro_input, DeriveInput, Generics, Ident}; + +#[derive(FromDeriveInput)] +#[darling(supports(struct_named))] +pub(crate) struct Receiver { + ident: Ident, + generics: Generics, + data: Data<(), ReceiverField>, +} + +#[derive(FromField, Debug)] +#[darling(attributes(field_names))] +struct ReceiverField { + ident: Option, + #[darling(default)] + skip: bool, + #[darling(default)] + desc: String, +} + +impl ReceiverField { + fn name(&self) -> String { + self.ident + .as_ref() + .expect("FieldNames only supports named fields") + .to_string() + } +} + +impl ToTokens for Receiver { + fn to_tokens(&self, tokens: &mut TokenStream) { + let ident = &self.ident; + let (impl_generics, ty_generics, where_clause) = self.generics.split_for_impl(); + let fields = self.fields_to_emit(); + let descs = self.descs(); + let fields_len = fields.len(); + + tokens.extend(quote! { + #[automatically_derived] + impl #impl_generics #ident #ty_generics #where_clause { + pub const FIELDS: [&'static str; #fields_len] = [ + #(#fields),* + ]; + pub const DESCS: [&'static str; #fields_len] = [ + #(#descs),* + ]; + } + }) + } +} + +impl Receiver { + fn fields_to_emit(&self) -> Vec { + self.data + .as_ref() + .take_struct() + .expect("FieldNames only supports named structs") + .into_iter() + .filter(|field| !field.skip) + .map(|field| field.name()) + .collect() + } + + fn descs(&self) -> Vec { + self.data + .as_ref() + .take_struct() + .expect("FieldNames only supports named structs") + .into_iter() + .filter(|field| !field.skip) + .map(|field| field.desc.clone()) + .collect() + } +} + +#[proc_macro_derive(FieldNames, attributes(field_names))] +pub fn derive_field_names(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + Receiver::from_derive_input(&parse_macro_input!(input as DeriveInput)) + .map(|receiver| quote!(#receiver)) + .unwrap_or_else(|err| err.write_errors()) + .into() +} + +#[cfg(test)] +mod tests { + use super::Receiver; + use darling::FromDeriveInput; + use syn::parse_quote; + + #[test] + fn simple() { + let input = Receiver::from_derive_input(&parse_quote! { + #[derive(FieldNames)] + struct Example { + hello: String, + world: String, + } + }) + .unwrap(); + + assert_eq!( + input.fields_to_emit(), + vec!["hello".to_string(), "world".to_string()] + ); + } + + #[test] + fn skip_field() { + let input = Receiver::from_derive_input(&parse_quote! { + #[derive(FieldNames)] + struct Example { + hello: String, + #[field_names(skip)] + hidden: bool, + world: String, + } + }) + .unwrap(); + + assert_eq!( + input.descs(), + vec!["hello".to_string(), "world".to_string()] + ); + } +} From ebf26d49270f5527fd422dd72540088ff5da17c6 Mon Sep 17 00:00:00 2001 From: dev-josias Date: Tue, 3 Mar 2026 05:56:09 +0000 Subject: [PATCH 18/30] build: include remaining vendored path dependencies --- .gitignore | 4 + vendor/locale_config/.gitignore | 2 + vendor/locale_config/.travis.yml | 80 ++ vendor/locale_config/Cargo.toml | 37 + vendor/locale_config/LICENSE | 25 + vendor/locale_config/README.md | 135 ++ vendor/locale_config/appveyor.yml | 58 + vendor/locale_config/ci/install.sh | 27 + vendor/locale_config/ci/script.sh | 24 + .../examples/show-user-locale.rs | 5 + vendor/locale_config/src/cgi.rs | 12 + vendor/locale_config/src/emscripten.rs | 31 + vendor/locale_config/src/lib.rs | 1082 +++++++++++++++++ vendor/locale_config/src/macos.rs | 12 + vendor/locale_config/src/unix.rs | 65 + vendor/locale_config/src/win32.rs | 513 ++++++++ vendor/wasi-experimental-http | 1 + 17 files changed, 2113 insertions(+) create mode 100644 vendor/locale_config/.gitignore create mode 100644 vendor/locale_config/.travis.yml create mode 100644 vendor/locale_config/Cargo.toml create mode 100644 vendor/locale_config/LICENSE create mode 100644 vendor/locale_config/README.md create mode 100644 vendor/locale_config/appveyor.yml create mode 100644 vendor/locale_config/ci/install.sh create mode 100644 vendor/locale_config/ci/script.sh create mode 100644 vendor/locale_config/examples/show-user-locale.rs create mode 100644 vendor/locale_config/src/cgi.rs create mode 100644 vendor/locale_config/src/emscripten.rs create mode 100644 vendor/locale_config/src/lib.rs create mode 100644 vendor/locale_config/src/macos.rs create mode 100644 vendor/locale_config/src/unix.rs create mode 100644 vendor/locale_config/src/win32.rs create mode 160000 vendor/wasi-experimental-http diff --git a/.gitignore b/.gitignore index 9ece8756..01f24016 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,10 @@ vendor/* !vendor/lsp-types/** !vendor/psp-types/ !vendor/psp-types/** +!vendor/locale_config/ +!vendor/locale_config/** +!vendor/wasi-experimental-http/ +!vendor/wasi-experimental-http/** .DS_Store *.patch diff --git a/vendor/locale_config/.gitignore b/vendor/locale_config/.gitignore new file mode 100644 index 00000000..a9d37c56 --- /dev/null +++ b/vendor/locale_config/.gitignore @@ -0,0 +1,2 @@ +target +Cargo.lock diff --git a/vendor/locale_config/.travis.yml b/vendor/locale_config/.travis.yml new file mode 100644 index 00000000..e4c7c3db --- /dev/null +++ b/vendor/locale_config/.travis.yml @@ -0,0 +1,80 @@ +# TravisCI configuration based on https://github.com/japaric/trust +# +# We don't need binary build, only continuous integration, so we don't use +# the deploy step. We also only build a somewhat representative selection of +# targets. + +# Based on the "trust" template v0.1.1 +# https://github.com/japaric/trust/tree/v0.1.1 + +dist: trusty +language: rust +services: docker +sudo: required + +env: + global: + - CRATE_NAME=locale_config + +matrix: + include: + # Stable channel + # Linux + - env: TARGET=x86_64-unknown-linux-gnu + - env: TARGET=x86_64-unknown-linux-musl + - env: TARGET=i686-unknown-linux-gnu + - env: TARGET=i686-unknown-linux-musl + + # OSX + - env: TARGET=x86_64-apple-darwin + os: osx + + # *BSD + - env: TARGET=i686-unknown-freebsd DISABLE_TESTS=1 + - env: TARGET=x86_64-unknown-netbsd DISABLE_TESTS=1 + + # Other architectures + - env: TARGET=aarch64-unknown-linux-gnu + - env: TARGET=armv7-unknown-linux-gnueabihf + - env: TARGET=mips-unknown-linux-gnu + - env: TARGET=mips64-unknown-linux-gnuabi64 + - env: TARGET=mips64el-unknown-linux-gnuabi64 + - env: TARGET=mipsel-unknown-linux-gnu + - env: TARGET=powerpc-unknown-linux-gnu + - env: TARGET=powerpc64-unknown-linux-gnu + - env: TARGET=powerpc64le-unknown-linux-gnu + - env: TARGET=s390x-unknown-linux-gnu DISABLE_TESTS=1 + + # Asmjs & Wasm + # TODO: Emscripten seems to be broken in cross + # - env: TARGET=asmjs-unknown-emscripten + # - env: TARGET=wasm32-unknown-emscripten + # TODO: wasm-unknown-unknown not yet supported in cross + # - env: TARGET=wasm32-unknown-unknown + + # Testing other channels + - env: TARGET=x86_64-unknown-linux-gnu + rust: nightly + - env: TARGET=i686-unknown-linux-musl + rust: nightly + - env: TARGET=x86_64-apple-darwin + os: osx + rust: nightly + +before_install: set -e + +install: + - sh ci/install.sh + - source ~/.cargo/env || true + +script: + - bash ci/script.sh + +after_script: set +e + +cache: cargo +before_cache: + # Travis can't cache files that are not readable by "others" + - chmod -R a+r $HOME/.cargo + +# vim: set sw=2 sts=2: diff --git a/vendor/locale_config/Cargo.toml b/vendor/locale_config/Cargo.toml new file mode 100644 index 00000000..8df4714a --- /dev/null +++ b/vendor/locale_config/Cargo.toml @@ -0,0 +1,37 @@ +[package] +name = "locale_config" +version = "0.3.1-alpha.0" +edition = "2021" +description = """ +Maintains locale preferences for process and thread and initialises them by +inspecting the system for user preference. +""" +authors = [ + "Jan Hudec ", +] +license = "MIT" + +documentation = "https://docs.rs/locale_config/" +repository = "https://github.com/rust-locale/locale_config/" +readme = "README.md" +keywords = ["i18n"] +categories = ["os"] +exclude = ["/ci/*", "/.travis.yml", "/appveyor.yml"] + +[package.metadata.release] +upload-doc = true + +[badges] +travis-ci = { repository = "rust-locale/locale_config" } +appveyor = { repository = "rust-locale/locale_config" } + +[dependencies] +lazy_static = "1" +regex = "1" + +[target.'cfg(windows)'.dependencies] +winapi = { version = "0.3", features = ["winnls"] } + +[target.'cfg(target_os = "macos")'.dependencies] +objc2 = "0.5.1" +objc2-foundation = { version = "0.2", features = ["NSLocale", "NSString"] } diff --git a/vendor/locale_config/LICENSE b/vendor/locale_config/LICENSE new file mode 100644 index 00000000..97b3d203 --- /dev/null +++ b/vendor/locale_config/LICENSE @@ -0,0 +1,25 @@ +The MIT License (MIT) + +Copyright (c) 2016–2019 Jan Hudec +Copyright (c) 2016 A.J. Gardner +Copyright (c) 2019, Bastien Orivel +Copyright (c) 2019, Igor Gnatenko +Copyright (c) 2019, Sophie Tauchert <999eagle@999eagle.moe> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/locale_config/README.md b/vendor/locale_config/README.md new file mode 100644 index 00000000..e5014902 --- /dev/null +++ b/vendor/locale_config/README.md @@ -0,0 +1,135 @@ +[![TravisCI Build Status](https://travis-ci.org/rust-locale/locale_config.svg?branch=master)](https://travis-ci.org/rust-locale/locale_config) +[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/13100wtqs80tyink/branch/master?svg=true)](https://ci.appveyor.com/project/jan-hudec/locale-config/branch/master) +[![Crates.io Version](https://img.shields.io/crates/v/locale_config.svg)](https://crates.io/crates/locale_config) +[![Docs.rs](https://docs.rs/locale_config/badge.svg)](https://docs.rs/locale_config/) + +# `locale_config` + +Remembers locale configuration per-thread and per-process and initializes the +values by inspecting the system for user preferences. + +## Installation + +You can depend on this library by adding `locale_config` to your Cargo dependencies: + +```toml +[dependencies] +locale_config = "*" +``` + +Usually it is not recommended to depend on `*`, but in this case it is +important that incompatible version requirements don't cause multiple +versions to be pulled in the final binary, so I do recommend it here and +promise I will maintain good compatibility. Just please don't add traits to +the types defined here to avoid conflicts with potential future methods. + +## Using + +Usually you want to use this indirectly via a localization crate like +`locale`. However if you need to work with the identifier itself, or you need +to override it, use + +```rust +Locale::current() +``` + +to find what you should be using at any given point in the application, + +```rust +Locale::set_current() +``` + +to override it for current thread and + +```rust +Locale::set_global_default() +``` + +to override it for new threads. + +In case you need to access the initial value, you'll find it under + +```rust +Locale::user_default() +``` + +The value may contain language tags specific for various localization +aspects, called categories, and fallbacks. The `Locale::tags_for` method will +take care of selecting relevant tags for you. For preferred language of +translations, use + +```rust +Locale::current().tags_for("messages") +``` + +For formatting, use categories `"numeric"` for numbers, `"time"` for date and +time and `"monetary"` for money amounts. And use `"collate"` for collation. + +Note that this crate does not itself provide any translation, formatting nor +collation functionality. Formatting and collation will be provided by +`locale` crate, translation has multiple available implementations. + +See full documentation on [![Docs.rs](https://docs.rs/locale_config/badge.svg)](https://docs.rs/locale_config/) or [github](https://rust-locale.github.io/locale_config/locale_config/). + +## Supported systems + +* **Unix:** Using the POSIX standard environment variables `LANG`, `LC_*` and + `LANGUAGES`. The variables are recognized on all systems and take + precedence on most of them. + +* **Windows:** Vista and newer + + - Uses API available from Vista and Server 2008 only. + - The `GetUserPreferredUILanguages` is only available for desktop, but + not store applications. Store applications should have equivalent + functionality, but I didn't try accessing it from Rust yet. + - Customization to individual locale elements done in “Regional and + Language options” (digits, calendar, decimal and thousand separator + etc.) are not detected (yet). + - Not well tested. + +* **OS X:** Reads setting from `NSLocale`, can be overridden by setting the + Unix environment variables. + +* **CGI:** The `HTTP_ACCEPT_LANGUAGE` environment variable is used if + detected. Hopefully it is specific enough to the CGI environment that it + can be used whenever detected. + +## Changelog + +### 0.3.0 + + * Support OS X `NSLocale`. + Thanks Sophie Tauchert (@999eagle). + +### 0.2.3 + +* Try support getting locale in emscripten targets in browser. Unfortunately + the emscripten targets seem to have broken in cross meanwhile, so they are not + being tested. +* Update to winapi 0.3. +* Update ro regex 1.0. + +### 0.2.2 + +* Update dependencies: regex 0.2. + +### 0.2.1 + +* Interpret some overrides that can be set on Windows in Region and Language + dialog, namely: group, decimal and list separators, first day of week, + 12/24-hour time, measurement system, (decimal) number system, to an extent + negative monetary value format (only whether to use parenthesized format + or not) and to an extent date format (if ISO-8601 variant is selected). + +### 0.2.0 + +* Changed error handling to proper error type. + +### 0.1.1 + +* Added basic Windows support. + +### 0.1.0 + +* Initial version, with Unix and CGI support. diff --git a/vendor/locale_config/appveyor.yml b/vendor/locale_config/appveyor.yml new file mode 100644 index 00000000..1de9610c --- /dev/null +++ b/vendor/locale_config/appveyor.yml @@ -0,0 +1,58 @@ +# AppVeyor configuration based on https://github.com/japaric/trust +# +# We don't need binary build, only continuous integration, so we don't use +# the deploy step. We also only build subset of the configurations to keep +# the time down. + +# Based on the "trust" template v0.1.1 +# https://github.com/japaric/trust/tree/v0.1.1 + +environment: + global: + RUST_VERSION: stable + CRATE_NAME: locale_config + + matrix: + # MinGW + - TARGET: i686-pc-windows-gnu + - TARGET: x86_64-pc-windows-gnu + + # MSVC + - TARGET: i686-pc-windows-msvc + - TARGET: x86_64-pc-windows-msvc + + # Testing other channels + - TARGET: x86_64-pc-windows-gnu + RUST_VERSION: nightly + - TARGET: i686-pc-windows-msvc + RUST_VERSION: nightly + +install: + - ps: >- + If ($Env:TARGET -eq 'x86_64-pc-windows-gnu') { + $Env:PATH += ';C:\msys64\mingw64\bin' + } ElseIf ($Env:TARGET -eq 'i686-pc-windows-gnu') { + $Env:PATH += ';C:\msys64\mingw32\bin' + } + - curl -sSf -o rustup-init.exe https://win.rustup.rs/ + - rustup-init.exe -y --default-host %TARGET% --default-toolchain %RUST_VERSION% + - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin + - rustc -Vv + - cargo -V + +test_script: + - cargo build --target %TARGET% + - cargo build --target %TARGET% --release + - cargo test --target %TARGET% + - cargo test --target %TARGET% --release + - cargo run --target %TARGET% --example show-user-locale + - cargo run --target %TARGET% --release --example show-user-locale + +cache: + - C:\Users\appveyor\.cargo\registry + - target + +# Building is done in the test phase, so we disable Appveyor's build phase. +build: false + +# vim: set sw=2 sts=2: diff --git a/vendor/locale_config/ci/install.sh b/vendor/locale_config/ci/install.sh new file mode 100644 index 00000000..748ad9a9 --- /dev/null +++ b/vendor/locale_config/ci/install.sh @@ -0,0 +1,27 @@ +set -ex + +main() { + local target= + if [ $TRAVIS_OS_NAME = linux ]; then + target=x86_64-unknown-linux-musl + sort=sort + else + target=x86_64-apple-darwin + sort=gsort # for `sort --sort-version`, from brew's coreutils. + fi + + # This fetches latest stable release + local tag=$(git ls-remote --tags --refs --exit-code https://github.com/japaric/cross \ + | cut -d/ -f3 \ + | grep -E '^v[0.1.0-9.]+$' \ + | $sort --version-sort \ + | tail -n1) + curl -LSfs https://japaric.github.io/trust/install.sh | \ + sh -s -- \ + --force \ + --git japaric/cross \ + --tag $tag \ + --target $target +} + +main diff --git a/vendor/locale_config/ci/script.sh b/vendor/locale_config/ci/script.sh new file mode 100644 index 00000000..0c7c9074 --- /dev/null +++ b/vendor/locale_config/ci/script.sh @@ -0,0 +1,24 @@ +# This script takes care of testing your crate + +set -ex + +# TODO This is the "test phase", tweak it as you see fit +main() { + cross build --target $TARGET + cross build --target $TARGET --release + + if [ ! -z $DISABLE_TESTS ]; then + return + fi + + cross test --target $TARGET + cross test --target $TARGET --release + + cross run --target $TARGET --example show-user-locale + cross run --target $TARGET --release --example show-user-locale +} + +# we don't run the "test phase" when doing deploys +if [ -z $TRAVIS_TAG ]; then + main +fi diff --git a/vendor/locale_config/examples/show-user-locale.rs b/vendor/locale_config/examples/show-user-locale.rs new file mode 100644 index 00000000..646072b6 --- /dev/null +++ b/vendor/locale_config/examples/show-user-locale.rs @@ -0,0 +1,5 @@ +extern crate locale_config; + +pub fn main() { + println!("{}", locale_config::Locale::user_default()); +} diff --git a/vendor/locale_config/src/cgi.rs b/vendor/locale_config/src/cgi.rs new file mode 100644 index 00000000..31126130 --- /dev/null +++ b/vendor/locale_config/src/cgi.rs @@ -0,0 +1,12 @@ +//! Inspect CGI environment variables for locale configuration + +use super::Locale; +use std::env; + +pub fn system_locale() -> Option { + if let Ok(al) = env::var("HTTP_ACCEPT_LANGUAGE") { + Locale::new(al.as_ref()).ok() + } else { + None + } +} diff --git a/vendor/locale_config/src/emscripten.rs b/vendor/locale_config/src/emscripten.rs new file mode 100644 index 00000000..67888da7 --- /dev/null +++ b/vendor/locale_config/src/emscripten.rs @@ -0,0 +1,31 @@ +use std::ffi::CStr; +use std::os::raw::c_char; +use std::os::raw::c_int; + +use super::Locale; + +// Bind some emscripten functions. Copied from webplatform crate. +extern "C" { + pub fn emscripten_asm_const_int(s: *const c_char, ...) -> c_int; +} + +pub fn system_locale() -> Option { + const JS: &'static [u8] = b"\ + try { \ + return allocate(intArrayFromString(navigator.languages.join(',')), 'i8', ALLOC_STACK); \ + } catch(e) {} \ + try { \ + return allocate(intArrayFromString(navigator.language), 'i8', ALLOC_STACK); \ + } catch(e) {} \ + try { \ + return allocate(intArrayFromString(navigator.userLanguage), 'i8', ALLOC_STACK); \ + } catch(e) {} \ + return 0;\0"; + unsafe { + let cptr = emscripten_asm_const_int(&JS[0] as *const _ as *const c_char); + return CStr::from_ptr(cptr as *const c_char) + .to_str() + .ok() + .and_then(|s| Locale::new(s).ok()); + } +} diff --git a/vendor/locale_config/src/lib.rs b/vendor/locale_config/src/lib.rs new file mode 100644 index 00000000..b7d4dfc4 --- /dev/null +++ b/vendor/locale_config/src/lib.rs @@ -0,0 +1,1082 @@ +//! Global locale instances and system inspection. +//! +//! This is an auxiliary crate for i18n solutions that: +//! +//! - Holds the appropriate default instances of locale. +//! - Inspects the system for the initial values. +//! +//! You don't want to use it directly, but instead use an internationalisation crate like [locale]. +//! +//! This crate is separate and intentionally minimal so that multiple i18n crates or multiple +//! versions of one that get into the application still share the current locale setting. +//! +//! [locale]: https://crates.io/crates/locale + +#[macro_use] +extern crate lazy_static; + +#[cfg(target_os = "macos")] +extern crate objc2; + +#[cfg(target_os = "macos")] +extern crate objc2_foundation; + +extern crate regex; + +use regex::Regex; +use std::borrow::{Borrow, Cow}; +use std::cell::RefCell; +use std::convert::AsRef; +use std::fmt::{self, Display}; +use std::sync::Mutex; + +// ------------------------------ LANGUAGE RANGE --------------------------------- + +/// Language and culture identifier. +/// +/// This object holds a [RFC4647] extended language range. +/// +/// The internal data may be owned or shared from object with lifetime `'a`. The lifetime can be +/// extended using the `into_static()` method, which internally clones the data as needed. +/// +/// # Syntax +/// +/// The range is composed of `-`-separated alphanumeric subtags, possibly replaced by `*`s. It +/// might be empty. +/// +/// In agreement with [RFC4647], this object only requires that the tag matches: +/// +/// ```ebnf +/// language_tag = (alpha{1,8} | "*") +/// ("-" (alphanum{1,8} | "*"))* +/// ``` +/// +/// The exact interpretation is up to the downstream localization provider, but it expected that +/// it will be matched against a normalized [RFC5646] language tag, which has the structure: +/// +/// ```ebnf +/// language_tag = language +/// ("-" script)? +/// ("-" region)? +/// ("-" variant)* +/// ("-" extension)* +/// ("-" private)? +/// +/// language = alpha{2,3} ("-" alpha{3}){0,3} +/// +/// script = aplha{4} +/// +/// region = alpha{2} +/// | digit{3} +/// +/// variant = alphanum{5,8} +/// | digit alphanum{3} +/// +/// extension = [0-9a-wyz] ("-" alphanum{2,8})+ +/// +/// private = "x" ("-" alphanum{1,8})+ +/// ``` +/// +/// * `language` is an [ISO639] 2-letter or, where not defined, 3-letter code. A code for +/// macro-language might be followed by code of specific dialect. +/// * `script` is an [ISO15924] 4-letter code. +/// * `region` is either an [ISO3166] 2-letter code or, for areas other than countries, [UN M.49] +/// 3-digit numeric code. +/// * `variant` is a string indicating variant of the language. +/// * `extension` and `private` define additional options. The private part has same structure as +/// the Unicode [`-u-` extension][u_ext]. Available options are documented for the facets that +/// use them. +/// +/// The values obtained by inspecting the system are normalized according to those rules. +/// +/// The content will be case-normalized as recommended in [RFC5646] §2.1.1, namely: +/// +/// * `language` is written in lowercase, +/// * `script` is written with first capital, +/// * `country` is written in uppercase and +/// * all other subtags are written in lowercase. +/// +/// When detecting system configuration, additional options that may be generated under the +/// [`-u-` extension][u_ext] currently are: +/// +/// * `cf` — Currency format (`account` for parenthesized negative values, `standard` for minus +/// sign). +/// * `fw` — First day of week (`mon` to `sun`). +/// * `hc` — Hour cycle (`h12` for 1–12, `h23` for 0–23). +/// * `ms` — Measurement system (`metric` or `ussystem`). +/// * `nu` — Numbering system—only decimal systems are currently used. +/// * `va` — Variant when locale is specified in Unix format and the tag after `@` does not +/// correspond to any variant defined in [Language subtag registry]. +/// +/// And under the `-x-` extension, following options are defined: +/// +/// * `df` — Date format: +/// +/// * `iso`: Short date should be in ISO format of `yyyy-MM-dd`. +/// +/// For example `-df-iso`. +/// +/// * `dm` — Decimal separator for monetary: +/// +/// Followed by one or more Unicode codepoints in hexadecimal. For example `-dm-002d` means to +/// use comma. +/// +/// * `ds` — Decimal separator for numbers: +/// +/// Followed by one or more Unicode codepoints in hexadecimal. For example `-ds-002d` means to +/// use comma. +/// +/// * `gm` — Group (thousand) separator for monetary: +/// +/// Followed by one or more Unicode codepoints in hexadecimal. For example `-dm-00a0` means to +/// use non-breaking space. +/// +/// * `gs` — Group (thousand) separator for numbers: +/// +/// Followed by one or more Unicode codepoints in hexadecimal. For example `-ds-00a0` means to +/// use non-breaking space. +/// +/// * `ls` — List separator: +/// +/// Followed by one or more Unicode codepoints in hexadecimal. For example, `-ds-003b` means to +/// use a semicolon. +/// +/// [RFC5646]: https://www.rfc-editor.org/rfc/rfc5646.txt +/// [RFC4647]: https://www.rfc-editor.org/rfc/rfc4647.txt +/// [ISO639]: https://en.wikipedia.org/wiki/ISO_639 +/// [ISO15924]: https://en.wikipedia.org/wiki/ISO_15924 +/// [ISO3166]: https://en.wikipedia.org/wiki/ISO_3166 +/// [UN M.49]: https://en.wikipedia.org/wiki/UN_M.49 +/// [u_ext]: http://www.unicode.org/reports/tr35/#u_Extension +/// [Language subtag registry]: https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub struct LanguageRange<'a> { + language: Cow<'a, str>, +} + +lazy_static! { + static ref REGULAR_LANGUAGE_RANGE_REGEX: Regex = Regex::new( + r"(?x) ^ + (?P (?: + [[:alpha:]]{2,3} (?: - [[:alpha:]]{3} ){0,3} + | \* )) + (?P