Compare commits

...

24 Commits

Author SHA1 Message Date
Joseph T Lyons
549de5cea4 v0.144.x stable 2024-07-17 11:29:04 -04:00
Zed Bot
f11a992cf1 Bump to 0.144.3 for @ConradIrwin 2024-07-16 12:25:07 -07:00
Conrad Irwin
d77d608221 Fix xkbcommon overflow more (#14571)
Release Notes:

- linux: Fixed overflow in xkbcommon-rs
2024-07-16 13:22:31 -06:00
aohanhongzhi
a0a28081f9 Fix text appearing twice after Chinese character input (#14558)
Release Notes:

- Fixed the issue where text appears twice in the editor after Chinese
Character input.([linux: Fix IME on
fcitx](https://github.com/zed-industries/zed/pull/14508)).

Before:

![zed2](https://github.com/user-attachments/assets/e387d70b-ca91-49c8-93e4-850f9e3ef227)

After Fixed:

![zed](https://github.com/user-attachments/assets/8307c12f-30a7-4e82-8c65-d0b53bb8cf44)
2024-07-16 13:20:27 -06:00
Conrad Irwin
e03a50c86c linux: Hide Install CLI from welcome (#14506)
Release Notes:

- linux: Remove "Install CLI" from welcome, it is not necessary
2024-07-16 13:20:10 -06:00
Fernando Tagawa
80408d3779 x11: Fix capitalization with neo 2 (#14466)
Fixed #14282

Release Notes:

- N/A
2024-07-16 13:19:27 -06:00
apricotbucket28
39b937ae16 linux: Show warning if file picker portal is missing (#14401)
This PR adds a warning when the file chooser couldn't be opened on Linux

It's quite confusing when trying to open a file and apparently nothing
happens:

fixes https://github.com/zed-industries/zed/issues/11089,
https://github.com/zed-industries/zed/issues/14328,
https://github.com/zed-industries/zed/issues/13753#issuecomment-2225812703,
https://github.com/zed-industries/zed/issues/13766,
https://github.com/zed-industries/zed/issues/14384,
https://github.com/zed-industries/zed/issues/14353,
https://github.com/zed-industries/zed/issues/9209


![image](https://github.com/user-attachments/assets/5acabdaa-7a9d-4225-9480-e371d20387c3)


Release Notes:

- N/A
2024-07-16 13:18:33 -06:00
Conrad Irwin
0da8464d6a linux: re-add open fallback (#14359)
Release Notes:

- linux: Fixed opening urls/directories on systems where the xdg desktop
portal doesn't handle those requests.
2024-07-16 13:18:28 -06:00
Conrad Irwin
b370d6fedb linux: Fix IME on fcitx5 (#14508)
Release Notes:

- linux: Fix IME under fcitx5 (#14192)
2024-07-16 13:18:20 -06:00
apricotbucket28
65d73274e8 wayland: Fix drag and drop for paths with spaces (#14574)
This wasn't doing any proper parsing before, so `%20` or similar encoded
characters weren't handled correctly.

Release Notes:

- N/A
2024-07-16 13:17:27 -06:00
Kirill Bulatov
b16e2ee46d Do not fold excerpts by default in the outline panel (#14378)
Release Notes:

- N/A
2024-07-15 12:33:23 +03:00
Kirill Bulatov
cca31c7f07 Lookup prettier more leniently (#14403)
Do not require the `prettier` dependency name to be in package.json's
[dev]Dependencies, instead just checking the `node_modules` contents.

Release Notes:

- Improved `prettier` detection to pick up its installation from
transitive dependencies
([12731](https://github.com/zed-industries/zed/issues/12731)
2024-07-15 12:33:12 +03:00
Kirill Bulatov
94e8c32862 Do not send textDocument/didSave message if server does not declare its support (#14412)
Release Notes:

- Improved Zed logic for sending `textDocument/didSave` request
([14286](https://github.com/zed-industries/zed/issues/14286))
2024-07-15 12:32:55 +03:00
Kirill Bulatov
4c8821b557 Turn off use_on_type_format too, for languages that have format_on_save disabled (#14413)
Based on the discussion in
https://github.com/zed-industries/zed/issues/14400


Release Notes:

- N/A
2024-07-15 12:31:53 +03:00
Kirill Bulatov
c7d9867b69 Support dynamic formatting capabilities [un]registration (#14478)
Closes https://github.com/zed-industries/zed/issues/12661

Release Notes:

- Added dynamic [un]registration for LSP formatting capabilities
([#12661](https://github.com/zed-industries/zed/issues/12661))
2024-07-15 12:31:35 +03:00
Zed Bot
89e6dffd0d Bump to 0.144.2 for @ConradIrwin 2024-07-11 16:29:59 -07:00
gcp-cherry-pick-bot[bot]
4160d1869a linux: Fix panic handling unknown keys (cherry-pick #14274) (#14276)
Cherry-picked linux: Fix panic handling unknown keys (#14274)

Pulls in https://github.com/rust-x-bindings/xkbcommon-rs/pull/54 to
avoid
panicking.

Release Notes:

- linux: Fix a panic in keyboard handling

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2024-07-11 17:24:56 -06:00
gcp-cherry-pick-bot[bot]
7714982a9d Don't panic on unknown cursor style on x11 (cherry-pick #14264) (#14273)
Cherry-picked Don't panic on unknown cursor style on x11 (#14264)

Release Notes:

- linux: Fixed a panic if we request a cursor style your system doesn't
support

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2024-07-11 17:03:30 -06:00
gcp-cherry-pick-bot[bot]
7dde13e77d linux: Panic less on window init (cherry-pick #14255) (#14272)
Cherry-picked linux: Panic less on window init (#14255)

This change pulls in https://github.com/kvark/blade/pull/135 and updates
the simplelog dependency for compatibility with that.


Release Notes:

- linux: Show link to troubleshooting docs when we can't open a window

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2024-07-11 16:24:06 -06:00
Peter Tripp
fbefe44e81 zed 0.144.1 2024-07-11 14:20:56 -04:00
gcp-cherry-pick-bot[bot]
ba941097f6 Keymap changes for editor::JoinLines (cherry-pick #14136) (#14234)
Cherry-picked Keymap changes for `editor::JoinLines` (#14136)
2024-07-11 14:18:55 -04:00
gcp-cherry-pick-bot[bot]
7d36760364 Fix reverse selections always being cleared (cherry-pick #14150) (#14231)
Cherry-picked Fix reverse selections always being cleared (#14150)

When I implemented #13701, I kinda messed up with the reversed
selections, thinking that their anchors are flipped, so I flipped them
again. This caused the reverse selections to always be cleared

Release Notes:

- Fix reverse selections always being cleared, even if the right click
was performed inside

Co-authored-by: Stanislav Alekseev <43210583+WeetHet@users.noreply.github.com>
2024-07-11 11:54:28 -06:00
gcp-cherry-pick-bot[bot]
8a0d5ae067 Build x86 linux too :/ (cherry-pick #14068) (#14073)
Cherry-picked Build x86 linux too :/ (#14068)

Release Notes:

- N/A

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2024-07-10 11:54:46 -06:00
Joseph T Lyons
962be2e09c v0.144.x preview 2024-07-10 10:12:26 -04:00
33 changed files with 800 additions and 408 deletions

View File

@@ -319,7 +319,6 @@ jobs:
- name: Upload app bundle to release
uses: softprops/action-gh-release@v1
if: ${{ env.RELEASE_CHANNEL == 'preview' }}
with:
draft: true
prerelease: ${{ env.RELEASE_CHANNEL == 'preview' }}

199
Cargo.lock generated
View File

@@ -87,7 +87,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6d1ea4484c8676f295307a4892d478c70ac8da1dbd8c7c10830a504b7f1022f"
dependencies = [
"base64 0.22.0",
"bitflags 2.4.2",
"bitflags 2.6.0",
"home",
"libc",
"log",
@@ -110,7 +110,7 @@ version = "0.24.1-dev"
source = "git+https://github.com/alacritty/alacritty?rev=cacdb5bb3b72bad2c729227537979d95af75978f#cacdb5bb3b72bad2c729227537979d95af75978f"
dependencies = [
"base64 0.22.0",
"bitflags 2.4.2",
"bitflags 2.6.0",
"home",
"libc",
"log",
@@ -341,8 +341,9 @@ dependencies = [
[[package]]
name = "ashpd"
version = "0.9.0"
source = "git+https://github.com/bilelmoussaoui/ashpd?rev=29f2e1a#29f2e1a6f4b0911f504658f5f4630c02e01b13f2"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfe7e0dd0ac5a401dc116ed9f9119cf9decc625600474cb41f0fc0a0050abc9a"
dependencies = [
"async-fs 2.1.1",
"async-net 2.0.0",
@@ -1581,7 +1582,16 @@ version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1"
dependencies = [
"bit-vec",
"bit-vec 0.6.3",
]
[[package]]
name = "bit-set"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0481a0e032742109b1133a095184ee93d88f3dc9e0d28a5d033dc77a073f44f"
dependencies = [
"bit-vec 0.7.0",
]
[[package]]
@@ -1590,6 +1600,12 @@ version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
[[package]]
name = "bit-vec"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2c54ff287cfc0a34f38a6b832ea1bd8e448a330b3e40a50859e6488bee07f22"
[[package]]
name = "bit_field"
version = "0.10.2"
@@ -1604,9 +1620,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.4.2"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
dependencies = [
"serde",
]
@@ -1632,11 +1648,11 @@ dependencies = [
[[package]]
name = "blade-graphics"
version = "0.4.0"
source = "git+https://github.com/kvark/blade?rev=21a56f780e21e4cb42c70a1dcf4b59842d1ad7f7#21a56f780e21e4cb42c70a1dcf4b59842d1ad7f7"
source = "git+https://github.com/zed-industries/blade?rev=a477c2008db27db0b9f745715e119b3ee7ab7818#a477c2008db27db0b9f745715e119b3ee7ab7818"
dependencies = [
"ash",
"ash-window",
"bitflags 2.4.2",
"bitflags 2.6.0",
"block",
"bytemuck",
"codespan-reporting",
@@ -1662,7 +1678,7 @@ dependencies = [
[[package]]
name = "blade-macros"
version = "0.2.1"
source = "git+https://github.com/kvark/blade?rev=21a56f780e21e4cb42c70a1dcf4b59842d1ad7f7#21a56f780e21e4cb42c70a1dcf4b59842d1ad7f7"
source = "git+https://github.com/zed-industries/blade?rev=a477c2008db27db0b9f745715e119b3ee7ab7818#a477c2008db27db0b9f745715e119b3ee7ab7818"
dependencies = [
"proc-macro2",
"quote",
@@ -1672,7 +1688,7 @@ dependencies = [
[[package]]
name = "blade-util"
version = "0.1.0"
source = "git+https://github.com/kvark/blade?rev=21a56f780e21e4cb42c70a1dcf4b59842d1ad7f7#21a56f780e21e4cb42c70a1dcf4b59842d1ad7f7"
source = "git+https://github.com/zed-industries/blade?rev=a477c2008db27db0b9f745715e119b3ee7ab7818#a477c2008db27db0b9f745715e119b3ee7ab7818"
dependencies = [
"blade-graphics",
"bytemuck",
@@ -1920,7 +1936,7 @@ version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"log",
"polling 3.3.2",
"rustix 0.38.32",
@@ -2855,7 +2871,7 @@ name = "cosmic-text"
version = "0.11.2"
source = "git+https://github.com/pop-os/cosmic-text?rev=542b20c#542b20ca4376a3b5de5fa629db1a4ace44e18e0c"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"fontdb",
"log",
"rangemap",
@@ -4008,7 +4024,7 @@ version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7493d4c459da9f84325ad297371a6b2b8a162800873a22e3b6b6512e61d18c05"
dependencies = [
"bit-set",
"bit-set 0.5.3",
"regex",
]
@@ -4065,7 +4081,7 @@ name = "feedback"
version = "0.1.0"
dependencies = [
"anyhow",
"bitflags 2.4.2",
"bitflags 2.6.0",
"client",
"db",
"editor",
@@ -4265,7 +4281,7 @@ checksum = "e32eac81c1135c1df01d4e6d4233c47ba11f6a6d07f33e0bba09d18797077770"
dependencies = [
"fontconfig-parser",
"log",
"memmap2 0.9.4",
"memmap2",
"slotmap",
"tinyvec",
"ttf-parser",
@@ -4399,7 +4415,7 @@ dependencies = [
name = "fsevent"
version = "0.1.0"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"core-foundation",
"fsevent-sys 3.1.0",
"parking_lot",
@@ -4710,7 +4726,7 @@ version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b903b73e45dc0c6c596f2d37eccece7c1c8bb6e4407b001096387c63d0d93724"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"libc",
"libgit2-sys",
"log",
@@ -4821,7 +4837,7 @@ version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"gpu-alloc-types",
]
@@ -4842,7 +4858,7 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
]
[[package]]
@@ -4892,6 +4908,7 @@ dependencies = [
"num_cpus",
"objc",
"oo7",
"open",
"parking",
"parking_lot",
"pathfinder_geometry",
@@ -5099,7 +5116,7 @@ version = "0.20.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f7acb9683d7c7068aa46d47557bfa4e35a277964b350d9504a87b03610163fd"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"byteorder",
"heed-traits",
"heed-types",
@@ -5703,6 +5720,25 @@ version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6"
[[package]]
name = "is-docker"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3"
dependencies = [
"once_cell",
]
[[package]]
name = "is-wsl"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5"
dependencies = [
"is-docker",
"once_cell",
]
[[package]]
name = "isahc"
version = "1.7.2"
@@ -6520,15 +6556,6 @@ dependencies = [
"rustix 0.38.32",
]
[[package]]
name = "memmap2"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43a5a03cefb0d953ec0be133036f14e109412fa594edc2f77227249db66cc3ed"
dependencies = [
"libc",
]
[[package]]
name = "memmap2"
version = "0.9.4"
@@ -6662,17 +6689,17 @@ checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a"
[[package]]
name = "naga"
version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae585df4b6514cf8842ac0f1ab4992edc975892704835b549cf818dc0191249e"
version = "0.20.0"
source = "git+https://github.com/gfx-rs/wgpu?rev=425526828f738c95ec50b016c6a761bc00d2fb25#425526828f738c95ec50b016c6a761bc00d2fb25"
dependencies = [
"bit-set",
"bitflags 2.4.2",
"arrayvec",
"bit-set 0.6.0",
"bitflags 2.6.0",
"cfg_aliases",
"codespan-reporting",
"hexf-parse",
"indexmap 2.2.6",
"log",
"num-traits",
"rustc-hash",
"spirv",
"termcolor",
@@ -6768,7 +6795,7 @@ version = "0.27.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"cfg-if",
"libc",
"memoffset",
@@ -6780,7 +6807,7 @@ version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"cfg-if",
"cfg_aliases",
"libc",
@@ -6849,7 +6876,7 @@ version = "6.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"crossbeam-channel",
"filetime",
"fsevent-sys 4.1.0",
@@ -7062,6 +7089,15 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "num_threads"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9"
dependencies = [
"libc",
]
[[package]]
name = "nvim-rs"
version = "0.6.0-pre"
@@ -7191,6 +7227,17 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]]
name = "open"
version = "5.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61a877bf6abd716642a53ef1b89fb498923a4afca5c754f9050b4d081c05c4b3"
dependencies = [
"is-wsl",
"libc",
"pathdiff",
]
[[package]]
name = "open_ai"
version = "0.1.0"
@@ -7211,7 +7258,7 @@ version = "0.10.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"cfg-if",
"foreign-types 0.3.2",
"libc",
@@ -8225,7 +8272,7 @@ version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dce76ce678ffc8e5675b22aa1405de0b7037e2fdf8913fea40d1926c6fe1e6e7"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"memchr",
"unicase",
]
@@ -9036,7 +9083,7 @@ version = "0.38.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"errno 0.3.8",
"itoa",
"libc",
@@ -9111,7 +9158,7 @@ version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfb9cf8877777222e4a3bc7eb247e398b56baba500c38c1c46842431adc8b55c"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"bytemuck",
"libm",
"smallvec",
@@ -9334,7 +9381,7 @@ version = "0.1.0"
dependencies = [
"any_vec",
"anyhow",
"bitflags 2.4.2",
"bitflags 2.6.0",
"client",
"collections",
"editor",
@@ -9762,13 +9809,13 @@ dependencies = [
[[package]]
name = "simplelog"
version = "0.9.0"
version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bc0ffd69814a9b251d43afcabf96dad1b29f5028378056257be9e3fecc9f720"
checksum = "16257adbfaef1ee58b1363bdc0664c9b8e1e30aed86049635fb5f147d065a9c0"
dependencies = [
"chrono",
"log",
"termcolor",
"time",
]
[[package]]
@@ -9921,12 +9968,11 @@ dependencies = [
[[package]]
name = "spirv"
version = "0.2.0+1.5.4"
version = "0.3.0+sdk-1.3.268.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "246bfa38fe3db3f1dfc8ca5a2cdeb7348c78be2112740cc0ec8ef18b6d94f830"
checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844"
dependencies = [
"bitflags 1.3.2",
"num-traits",
"bitflags 2.6.0",
]
[[package]]
@@ -10102,7 +10148,7 @@ dependencies = [
"atoi",
"base64 0.21.7",
"bigdecimal",
"bitflags 2.4.2",
"bitflags 2.6.0",
"byteorder",
"bytes 1.5.0",
"chrono",
@@ -10149,7 +10195,7 @@ dependencies = [
"atoi",
"base64 0.21.7",
"bigdecimal",
"bitflags 2.4.2",
"bitflags 2.6.0",
"byteorder",
"chrono",
"crc",
@@ -10571,7 +10617,7 @@ version = "0.27.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9aef1f9d4c1dbdd1cb3a63be9efd2f04d8ddbc919d46112982c76818ffc2f1a7"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"cap-fs-ext",
"cap-std",
"fd-lock",
@@ -10712,9 +10758,9 @@ dependencies = [
[[package]]
name = "termcolor"
version = "1.1.3"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
dependencies = [
"winapi-util",
]
@@ -10874,18 +10920,18 @@ dependencies = [
[[package]]
name = "thiserror"
version = "1.0.60"
version = "1.0.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18"
checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.60"
version = "1.0.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524"
checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
dependencies = [
"proc-macro2",
"quote",
@@ -10936,7 +10982,9 @@ checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
dependencies = [
"deranged",
"itoa",
"libc",
"num-conv",
"num_threads",
"powerfmt",
"serde",
"time-core",
@@ -11295,7 +11343,7 @@ version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"bytes 1.5.0",
"futures-core",
"futures-util",
@@ -12066,7 +12114,7 @@ version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40eb22ae96f050e0c0d6f7ce43feeae26c348fc4dea56928ca81537cfaa6188b"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"cursor-icon",
"log",
"serde",
@@ -12218,7 +12266,7 @@ version = "0.201.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84e5df6dba6c0d7fafc63a450f1738451ed7a0b52295d83e868218fa286bf708"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"indexmap 2.2.6",
"semver",
]
@@ -12485,7 +12533,7 @@ checksum = "371d828b6849ea06d598ae7dd1c316e8dd9e99b76f77d93d5886cb25c7f8e188"
dependencies = [
"anyhow",
"async-trait",
"bitflags 2.4.2",
"bitflags 2.6.0",
"bytes 1.5.0",
"cap-fs-ext",
"cap-net-ext",
@@ -12572,7 +12620,7 @@ version = "0.31.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82fb96ee935c2cea6668ccb470fb7771f6215d1691746c2d896b447a00ad3f1f"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"rustix 0.38.32",
"wayland-backend",
"wayland-scanner",
@@ -12595,7 +12643,7 @@ version = "0.31.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f81f365b8b4a97f422ac0e8737c438024b5951734506b0e1d775c73030561f4"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"wayland-backend",
"wayland-client",
"wayland-scanner",
@@ -12607,7 +12655,7 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23803551115ff9ea9bce586860c5c5a971e360825a0309264102a9495a5ff479"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"wayland-backend",
"wayland-client",
"wayland-protocols",
@@ -12726,7 +12774,7 @@ checksum = "ae1136a209614ace00b0c11f04dc7cf42540773be3b22eff6ad165110aba29c1"
dependencies = [
"anyhow",
"async-trait",
"bitflags 2.4.2",
"bitflags 2.6.0",
"thiserror",
"tracing",
"wasmtime",
@@ -13156,7 +13204,7 @@ version = "0.36.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9643b83820c0cd246ecabe5fa454dd04ba4fa67996369466d0747472d337346"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"windows-sys 0.52.0",
]
@@ -13175,7 +13223,7 @@ version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "288f992ea30e6b5c531b52cdd5f3be81c148554b09ea416f058d16556ba92c27"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
"wit-bindgen-rt",
"wit-bindgen-rust-macro",
]
@@ -13231,7 +13279,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "421c0c848a0660a8c22e2fd217929a0191f14476b68962afd2af89fd22e39825"
dependencies = [
"anyhow",
"bitflags 2.4.2",
"bitflags 2.6.0",
"indexmap 2.2.6",
"log",
"serde",
@@ -13437,18 +13485,17 @@ name = "xim-parser"
version = "0.2.1"
source = "git+https://github.com/npmania/xim-rs?rev=27132caffc5b9bc9c432ca4afad184ab6e7c16af#27132caffc5b9bc9c432ca4afad184ab6e7c16af"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.6.0",
]
[[package]]
name = "xkbcommon"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13867d259930edc7091a6c41b4ce6eee464328c6ff9659b7e4c668ca20d4c91e"
source = "git+https://github.com/ConradIrwin/xkbcommon-rs?rev=fcbb4612185cc129ceeff51d22f7fb51810a03b2#fcbb4612185cc129ceeff51d22f7fb51810a03b2"
dependencies = [
"as-raw-xcb-connection",
"libc",
"memmap2 0.8.0",
"memmap2",
"xkeysym",
]
@@ -13581,7 +13628,7 @@ dependencies = [
[[package]]
name = "zed"
version = "0.144.0"
version = "0.144.3"
dependencies = [
"activity_indicator",
"anyhow",

View File

@@ -274,7 +274,7 @@ zed_actions = { path = "crates/zed_actions" }
alacritty_terminal = "0.23"
any_vec = "0.13"
anyhow = "1.0.57"
ashpd = { git = "https://github.com/bilelmoussaoui/ashpd", rev = "29f2e1a" }
ashpd = "0.9.1"
async-compression = { version = "0.4", features = ["gzip", "futures-io"] }
async-dispatcher = { version = "0.1" }
async-fs = "1.6"
@@ -284,10 +284,10 @@ async-trait = "0.1"
async-watch = "0.3.1"
async_zip = { version = "0.0.17", features = ["deflate", "deflate64"] }
base64 = "0.13"
bitflags = "2.4.2"
blade-graphics = { git = "https://github.com/kvark/blade", rev = "21a56f780e21e4cb42c70a1dcf4b59842d1ad7f7" }
blade-macros = { git = "https://github.com/kvark/blade", rev = "21a56f780e21e4cb42c70a1dcf4b59842d1ad7f7" }
blade-util = { git = "https://github.com/kvark/blade", rev = "21a56f780e21e4cb42c70a1dcf4b59842d1ad7f7" }
bitflags = "2.6.0"
blade-graphics = { git = "https://github.com/zed-industries/blade", rev = "a477c2008db27db0b9f745715e119b3ee7ab7818" }
blade-macros = { git = "https://github.com/zed-industries/blade", rev = "a477c2008db27db0b9f745715e119b3ee7ab7818" }
blade-util = { git = "https://github.com/zed-industries/blade", rev = "a477c2008db27db0b9f745715e119b3ee7ab7818" }
cap-std = "3.0"
cargo_toml = "0.20"
chrono = { version = "0.4", features = ["serde"] }
@@ -365,6 +365,7 @@ shellexpand = "2.1.0"
shlex = "1.3.0"
signal-hook = "0.3.17"
similar = "1.3"
simplelog = "0.12.2"
smallvec = { version = "1.6", features = ["union"] }
smol = "1.2"
strum = { version = "0.25.0", features = ["derive"] }

View File

@@ -397,7 +397,7 @@
"bindings": {
"ctrl-shift-k": "editor::DeleteLine",
"ctrl-shift-d": "editor::DuplicateLineDown",
"ctrl-j": "editor::JoinLines",
"ctrl-shift-j": "editor::JoinLines",
"ctrl-alt-backspace": "editor::DeleteToPreviousSubwordStart",
"ctrl-alt-h": "editor::DeleteToPreviousSubwordStart",
"ctrl-alt-delete": "editor::DeleteToNextSubwordEnd",

View File

@@ -27,6 +27,7 @@
"ctrl-,": "editor::GoToPrevHunk",
"cmd-k cmd-u": "editor::ConvertToUpperCase",
"cmd-k cmd-l": "editor::ConvertToLowerCase",
"cmd-shift-j": "editor::JoinLines",
"shift-alt-m": "markdown::OpenPreviewToTheSide",
"ctrl-backspace": "editor::DeleteToPreviousWordStart",
"ctrl-delete": "editor::DeleteToNextWordEnd"

View File

@@ -128,14 +128,7 @@
// The default number of lines to expand excerpts in the multibuffer by.
"expand_excerpt_lines": 3,
// Globs to match against file paths to determine if a file is private.
"private_files": [
"**/.env*",
"**/*.pem",
"**/*.key",
"**/*.cert",
"**/*.crt",
"**/secrets.yml"
],
"private_files": ["**/.env*", "**/*.pem", "**/*.key", "**/*.cert", "**/*.crt", "**/secrets.yml"],
// Whether to use additional LSP queries to format (and amend) the code after
// every "trigger" symbol input, defined by LSP server capabilities.
"use_on_type_format": true,
@@ -714,10 +707,12 @@
}
},
"C": {
"format_on_save": "off"
"format_on_save": "off",
"use_on_type_format": false
},
"C++": {
"format_on_save": "off"
"format_on_save": "off",
"use_on_type_format": false
},
"CSS": {
"prettier": {
@@ -769,6 +764,7 @@
},
"Markdown": {
"format_on_save": "off",
"use_on_type_format": false,
"prettier": {
"allowed": true
}

View File

@@ -49,13 +49,11 @@ fn display_ranges<'a>(
.pending
.as_ref()
.map(|pending| &pending.selection);
selections.disjoint.iter().chain(pending).map(move |s| {
if s.reversed {
s.end.to_display_point(&display_map)..s.start.to_display_point(&display_map)
} else {
s.start.to_display_point(&display_map)..s.end.to_display_point(&display_map)
}
})
selections
.disjoint
.iter()
.chain(pending)
.map(move |s| s.start.to_display_point(&display_map)..s.end.to_display_point(&display_map))
}
pub fn deploy_context_menu(

View File

@@ -12,7 +12,7 @@ use editor::{Editor, EditorElement, EditorStyle};
use extension::{ExtensionManifest, ExtensionOperation, ExtensionStore};
use fuzzy::{match_strings, StringMatchCandidate};
use gpui::{
actions, uniform_list, AnyElement, AppContext, EventEmitter, FocusableView, FontStyle,
actions, uniform_list, AnyElement, AppContext, EventEmitter, Flatten, FocusableView, FontStyle,
InteractiveElement, KeyContext, ParentElement, Render, Styled, Task, TextStyle,
UniformListScrollHandle, View, ViewContext, VisualContext, WeakView, WhiteSpace, WindowContext,
};
@@ -24,7 +24,6 @@ use std::time::Duration;
use std::{ops::Range, sync::Arc};
use theme::ThemeSettings;
use ui::{prelude::*, ContextMenu, PopoverMenu, ToggleButton, Tooltip};
use util::ResultExt as _;
use workspace::item::TabContentParams;
use workspace::{
item::{Item, ItemEvent},
@@ -58,9 +57,23 @@ pub fn init(cx: &mut AppContext) {
multiple: false,
});
let workspace_handle = cx.view().downgrade();
cx.deref_mut()
.spawn(|mut cx| async move {
let extension_path = prompt.await.log_err()??.pop()?;
let extension_path =
match Flatten::flatten(prompt.await.map_err(|e| e.into())) {
Ok(Some(mut paths)) => paths.pop()?,
Ok(None) => return None,
Err(err) => {
workspace_handle
.update(&mut cx, |workspace, cx| {
workspace.show_portal_error(err.to_string(), cx);
})
.ok();
return None;
}
};
store
.update(&mut cx, |store, cx| {
store

View File

@@ -124,6 +124,7 @@ wayland-protocols = { version = "0.31.2", features = [
] }
wayland-protocols-plasma = { version = "0.2.0", features = ["client"] }
oo7 = "0.3.0"
open = "5.2.0"
filedescriptor = "0.8.2"
x11rb = { version = "0.13.0", features = [
"allow-unsafe-code",
@@ -134,7 +135,10 @@ x11rb = { version = "0.13.0", features = [
"resource_manager",
"sync",
] }
xkbcommon = { version = "0.7", features = ["wayland", "x11"] }
xkbcommon = { git = "https://github.com/ConradIrwin/xkbcommon-rs", rev = "fcbb4612185cc129ceeff51d22f7fb51810a03b2", features = [
"wayland",
"x11",
] }
xim = { git = "https://github.com/npmania/xim-rs", rev = "27132caffc5b9bc9c432ca4afad184ab6e7c16af", features = [
"x11rb-xcb",
"x11rb-client",

View File

@@ -612,10 +612,11 @@ impl AppContext {
/// Displays a platform modal for selecting paths.
/// When one or more paths are selected, they'll be relayed asynchronously via the returned oneshot channel.
/// If cancelled, a `None` will be relayed instead.
/// May return an error on Linux if the file picker couldn't be opened.
pub fn prompt_for_paths(
&self,
options: PathPromptOptions,
) -> oneshot::Receiver<Option<Vec<PathBuf>>> {
) -> oneshot::Receiver<Result<Option<Vec<PathBuf>>>> {
self.platform.prompt_for_paths(options)
}
@@ -623,7 +624,11 @@ impl AppContext {
/// The provided directory will be used to set the initial location.
/// When a path is selected, it is relayed asynchronously via the returned oneshot channel.
/// If cancelled, a `None` will be relayed instead.
pub fn prompt_for_new_path(&self, directory: &Path) -> oneshot::Receiver<Option<PathBuf>> {
/// May return an error on Linux if the file picker couldn't be opened.
pub fn prompt_for_new_path(
&self,
directory: &Path,
) -> oneshot::Receiver<Result<Option<PathBuf>>> {
self.platform.prompt_for_new_path(directory)
}

View File

@@ -137,8 +137,8 @@ pub(crate) trait Platform: 'static {
fn prompt_for_paths(
&self,
options: PathPromptOptions,
) -> oneshot::Receiver<Option<Vec<PathBuf>>>;
fn prompt_for_new_path(&self, directory: &Path) -> oneshot::Receiver<Option<PathBuf>>;
) -> oneshot::Receiver<Result<Option<Vec<PathBuf>>>>;
fn prompt_for_new_path(&self, directory: &Path) -> oneshot::Receiver<Result<Option<PathBuf>>>;
fn reveal_path(&self, path: &Path);
fn on_quit(&self, callback: Box<dyn FnMut()>);

View File

@@ -21,6 +21,7 @@ use std::{
use anyhow::anyhow;
use ashpd::desktop::file_chooser::{OpenFileRequest, SaveFileRequest};
use ashpd::desktop::open_uri::{OpenDirectoryRequest, OpenFileRequest as OpenUriRequest};
use ashpd::desktop::ResponseError;
use ashpd::{url, ActivationToken};
use async_task::Runnable;
use calloop::channel::Channel;
@@ -54,6 +55,9 @@ pub(crate) const DOUBLE_CLICK_INTERVAL: Duration = Duration::from_millis(400);
pub(crate) const DOUBLE_CLICK_DISTANCE: Pixels = px(5.0);
pub(crate) const KEYRING_LABEL: &str = "zed-github-account";
const FILE_PICKER_PORTAL_MISSING: &str =
"Couldn't open file picker due to missing xdg-desktop-portal implementation.";
pub trait LinuxClient {
fn compositor_name(&self) -> &'static str;
fn with_common<R>(&self, f: impl FnOnce(&mut LinuxCommon) -> R) -> R;
@@ -256,7 +260,7 @@ impl<P: LinuxClient + 'static> Platform for P {
fn prompt_for_paths(
&self,
options: PathPromptOptions,
) -> oneshot::Receiver<Option<Vec<PathBuf>>> {
) -> oneshot::Receiver<Result<Option<Vec<PathBuf>>>> {
let (done_tx, done_rx) = oneshot::channel();
self.foreground_executor()
.spawn(async move {
@@ -274,7 +278,7 @@ impl<P: LinuxClient + 'static> Platform for P {
}
};
let result = OpenFileRequest::default()
let request = match OpenFileRequest::default()
.modal(true)
.title(title)
.accept_label("Select")
@@ -282,49 +286,68 @@ impl<P: LinuxClient + 'static> Platform for P {
.directory(options.directories)
.send()
.await
.ok()
.and_then(|request| request.response().ok())
.and_then(|response| {
{
Ok(request) => request,
Err(err) => {
let result = match err {
ashpd::Error::PortalNotFound(_) => anyhow!(FILE_PICKER_PORTAL_MISSING),
err => err.into(),
};
done_tx.send(Err(result));
return;
}
};
let result = match request.response() {
Ok(response) => Ok(Some(
response
.uris()
.iter()
.map(|uri| uri.to_file_path().ok())
.collect()
});
.filter_map(|uri| uri.to_file_path().ok())
.collect::<Vec<_>>(),
)),
Err(ashpd::Error::Response(ResponseError::Cancelled)) => Ok(None),
Err(e) => Err(e.into()),
};
done_tx.send(result);
})
.detach();
done_rx
}
fn prompt_for_new_path(&self, directory: &Path) -> oneshot::Receiver<Option<PathBuf>> {
fn prompt_for_new_path(&self, directory: &Path) -> oneshot::Receiver<Result<Option<PathBuf>>> {
let (done_tx, done_rx) = oneshot::channel();
let directory = directory.to_owned();
self.foreground_executor()
.spawn(async move {
let request = SaveFileRequest::default()
let request = match SaveFileRequest::default()
.modal(true)
.title("Select new path")
.accept_label("Accept")
.current_folder(directory);
let result = if let Ok(request) = request {
request
.send()
.await
.ok()
.and_then(|request| request.response().ok())
.and_then(|response| {
response
.uris()
.first()
.and_then(|uri| uri.to_file_path().ok())
})
} else {
None
.current_folder(directory)
.expect("pathbuf should not be nul terminated")
.send()
.await
{
Ok(request) => request,
Err(err) => {
let result = match err {
ashpd::Error::PortalNotFound(_) => anyhow!(FILE_PICKER_PORTAL_MISSING),
err => err.into(),
};
done_tx.send(Err(result));
return;
}
};
let result = match request.response() {
Ok(response) => Ok(response
.uris()
.first()
.and_then(|uri| uri.to_file_path().ok())),
Err(ashpd::Error::Response(ResponseError::Cancelled)) => Ok(None),
Err(e) => Err(e.into()),
};
done_tx.send(result);
})
.detach();
@@ -502,11 +525,26 @@ pub(super) fn open_uri_internal(
if let Some(uri) = url::Url::parse(uri).log_err() {
executor
.spawn(async move {
OpenUriRequest::default()
.activation_token(activation_token.map(ActivationToken::from))
match OpenUriRequest::default()
.activation_token(activation_token.clone().map(ActivationToken::from))
.send_uri(&uri)
.await
.log_err();
{
Ok(_) => return,
Err(e) => log::error!("Failed to open with dbus: {}", e),
}
for mut command in open::commands(uri.to_string()) {
if let Some(token) = activation_token.as_ref() {
command.env("XDG_ACTIVATION_TOKEN", token);
}
match command.spawn() {
Ok(_) => return,
Err(e) => {
log::error!("Failed to open with {:?}: {}", command.get_program(), e)
}
}
}
})
.detach();
}
@@ -519,12 +557,20 @@ pub(super) fn reveal_path_internal(
) {
executor
.spawn(async move {
if let Some(dir) = File::open(path).log_err() {
OpenDirectoryRequest::default()
if let Some(dir) = File::open(path.clone()).log_err() {
match OpenDirectoryRequest::default()
.activation_token(activation_token.map(ActivationToken::from))
.send(&dir.as_fd())
.await
.log_err();
{
Ok(_) => return,
Err(e) => log::error!("Failed to open with dbus: {}", e),
}
if path.is_dir() {
open::that_detached(path).log_err();
} else {
open::that_detached(path.parent().unwrap_or(Path::new(""))).log_err();
}
}
})
.detach();

View File

@@ -11,6 +11,7 @@ use calloop_wayland_source::WaylandSource;
use collections::HashMap;
use filedescriptor::Pipe;
use http::Url;
use smallvec::SmallVec;
use util::ResultExt;
use wayland_backend::client::ObjectId;
@@ -1791,7 +1792,8 @@ impl Dispatch<wl_data_device::WlDataDevice, ()> for WaylandClientStatePtr {
let paths: SmallVec<[_; 2]> = file_list
.lines()
.map(|path| PathBuf::from(path.replace("file://", "")))
.filter_map(|path| Url::parse(path).log_err())
.filter_map(|url| url.to_file_path().log_err())
.collect();
let position = Point::new(x.into(), y.into());

View File

@@ -24,7 +24,7 @@ use x11rb::xcb_ffi::XCBConnection;
use xim::{x11rb::X11rbClient, Client};
use xim::{AttributeName, InputStyle};
use xkbc::x11::ffi::{XKB_X11_MIN_MAJOR_XKB_VERSION, XKB_X11_MIN_MINOR_XKB_VERSION};
use xkbcommon::xkb as xkbc;
use xkbcommon::xkb::{self as xkbc, LayoutIndex, ModMask};
use crate::platform::linux::LinuxClient;
use crate::platform::{LinuxCommon, PlatformWindow};
@@ -94,6 +94,13 @@ impl From<xim::ClientError> for EventHandlerError {
}
}
#[derive(Debug, Default, Clone)]
struct XKBStateNotiy {
depressed_layout: LayoutIndex,
latched_layout: LayoutIndex,
locked_layout: LayoutIndex,
}
pub struct X11ClientState {
pub(crate) loop_handle: LoopHandle<'static, X11Client>,
pub(crate) event_loop: Option<calloop::EventLoop<'static, X11Client>>,
@@ -112,6 +119,7 @@ pub struct X11ClientState {
pub(crate) windows: HashMap<xproto::Window, WindowRef>,
pub(crate) focused_window: Option<xproto::Window>,
pub(crate) xkb: xkbc::State,
previous_xkb_state: XKBStateNotiy,
pub(crate) ximc: Option<X11rbClient<Rc<XCBConnection>>>,
pub(crate) xim_handler: Option<XimHandler>,
pub modifiers: Modifiers,
@@ -343,6 +351,7 @@ impl X11Client {
windows: HashMap::default(),
focused_window: None,
xkb: xkb_state,
previous_xkb_state: XKBStateNotiy::default(),
ximc,
xim_handler,
@@ -615,7 +624,11 @@ impl X11Client {
event.latched_group as u32,
event.locked_group.into(),
);
state.previous_xkb_state = XKBStateNotiy {
depressed_layout: event.base_group as u32,
latched_layout: event.latched_group as u32,
locked_layout: event.locked_group.into(),
};
let modifiers = Modifiers::from_xkb(&state.xkb);
if state.modifiers == modifiers {
drop(state);
@@ -637,11 +650,18 @@ impl X11Client {
let modifiers = modifiers_from_state(event.state);
state.modifiers = modifiers;
state.pre_ime_key_down.take();
let keystroke = {
let code = event.detail.into();
let xkb_state = state.previous_xkb_state.clone();
state.xkb.update_mask(
event.state.bits() as ModMask,
0,
0,
xkb_state.depressed_layout,
xkb_state.latched_layout,
xkb_state.locked_layout,
);
let mut keystroke = crate::Keystroke::from_xkb(&state.xkb, modifiers, code);
state.xkb.update_key(code, xkbc::KeyDirection::Down);
let keysym = state.xkb.key_get_one_sym(code);
if keysym.is_modifier_key() {
return Some(());
@@ -700,8 +720,16 @@ impl X11Client {
let keystroke = {
let code = event.detail.into();
let xkb_state = state.previous_xkb_state.clone();
state.xkb.update_mask(
event.state.bits() as ModMask,
0,
0,
xkb_state.depressed_layout,
xkb_state.latched_layout,
xkb_state.locked_layout,
);
let keystroke = crate::Keystroke::from_xkb(&state.xkb, modifiers, code);
state.xkb.update_key(code, xkbc::KeyDirection::Up);
let keysym = state.xkb.key_get_one_sym(code);
if keysym.is_modifier_key() {
return Some(());
@@ -947,20 +975,17 @@ impl X11Client {
fn xim_handle_commit(&self, window: xproto::Window, text: String) -> Option<()> {
let window = self.get_window(window).unwrap();
let mut state = self.0.borrow_mut();
if !state.composing {
if let Some(keystroke) = state.pre_ime_key_down.take() {
drop(state);
window.handle_input(PlatformInput::KeyDown(crate::KeyDownEvent {
keystroke,
is_held: false,
}));
return Some(());
}
}
let keystroke = state.pre_ime_key_down.take();
state.composing = false;
drop(state);
if let Some(mut keystroke) = keystroke {
keystroke.ime_key = Some(text.clone());
window.handle_input(PlatformInput::KeyDown(crate::KeyDownEvent {
keystroke,
is_held: false,
}));
}
window.handle_ime_commit(text);
Some(())
}
@@ -1154,10 +1179,13 @@ impl LinuxClient for X11Client {
let cursor = match state.cursor_cache.get(&style) {
Some(cursor) => *cursor,
None => {
let cursor = state
let Some(cursor) = state
.cursor_handle
.load_cursor(&state.xcb_connection, &style.to_icon_name())
.expect("failed to load cursor");
.log_err()
else {
return;
};
state.cursor_cache.insert(style, cursor);
cursor
}

View File

@@ -602,7 +602,7 @@ impl Platform for MacPlatform {
fn prompt_for_paths(
&self,
options: PathPromptOptions,
) -> oneshot::Receiver<Option<Vec<PathBuf>>> {
) -> oneshot::Receiver<Result<Option<Vec<PathBuf>>>> {
let (done_tx, done_rx) = oneshot::channel();
self.foreground_executor()
.spawn(async move {
@@ -632,7 +632,7 @@ impl Platform for MacPlatform {
};
if let Some(done_tx) = done_tx.take() {
let _ = done_tx.send(result);
let _ = done_tx.send(Ok(result));
}
});
let block = block.copy();
@@ -643,7 +643,7 @@ impl Platform for MacPlatform {
done_rx
}
fn prompt_for_new_path(&self, directory: &Path) -> oneshot::Receiver<Option<PathBuf>> {
fn prompt_for_new_path(&self, directory: &Path) -> oneshot::Receiver<Result<Option<PathBuf>>> {
let directory = directory.to_owned();
let (done_tx, done_rx) = oneshot::channel();
self.foreground_executor()
@@ -665,7 +665,7 @@ impl Platform for MacPlatform {
}
if let Some(done_tx) = done_tx.take() {
let _ = done_tx.send(result);
let _ = done_tx.send(Ok(result));
}
});
let block = block.copy();

View File

@@ -34,7 +34,7 @@ pub(crate) struct TestPlatform {
#[derive(Default)]
pub(crate) struct TestPrompts {
multiple_choice: VecDeque<oneshot::Sender<usize>>,
new_path: VecDeque<(PathBuf, oneshot::Sender<Option<PathBuf>>)>,
new_path: VecDeque<(PathBuf, oneshot::Sender<Result<Option<PathBuf>>>)>,
}
impl TestPlatform {
@@ -80,7 +80,7 @@ impl TestPlatform {
.new_path
.pop_front()
.expect("no pending new path prompt");
tx.send(select_path(&path)).ok();
tx.send(Ok(select_path(&path))).ok();
}
pub(crate) fn simulate_prompt_answer(&self, response_ix: usize) {
@@ -216,14 +216,14 @@ impl Platform for TestPlatform {
fn prompt_for_paths(
&self,
_options: crate::PathPromptOptions,
) -> oneshot::Receiver<Option<Vec<std::path::PathBuf>>> {
) -> oneshot::Receiver<Result<Option<Vec<std::path::PathBuf>>>> {
unimplemented!()
}
fn prompt_for_new_path(
&self,
directory: &std::path::Path,
) -> oneshot::Receiver<Option<std::path::PathBuf>> {
) -> oneshot::Receiver<Result<Option<std::path::PathBuf>>> {
let (tx, rx) = oneshot::channel();
self.prompts
.borrow_mut()

View File

@@ -316,7 +316,10 @@ impl Platform for WindowsPlatform {
self.state.borrow_mut().callbacks.open_urls = Some(callback);
}
fn prompt_for_paths(&self, options: PathPromptOptions) -> Receiver<Option<Vec<PathBuf>>> {
fn prompt_for_paths(
&self,
options: PathPromptOptions,
) -> Receiver<Result<Option<Vec<PathBuf>>>> {
let (tx, rx) = oneshot::channel();
self.foreground_executor()
@@ -355,7 +358,7 @@ impl Platform for WindowsPlatform {
if hr.unwrap_err().code() == HRESULT(0x800704C7u32 as i32) {
// user canceled error
if let Some(tx) = tx.take() {
tx.send(None).unwrap();
tx.send(Ok(None)).unwrap();
}
return;
}
@@ -374,10 +377,10 @@ impl Platform for WindowsPlatform {
}
if let Some(tx) = tx.take() {
if paths.len() == 0 {
tx.send(None).unwrap();
if paths.is_empty() {
tx.send(Ok(None)).unwrap();
} else {
tx.send(Some(paths)).unwrap();
tx.send(Ok(Some(paths))).unwrap();
}
}
})
@@ -386,27 +389,27 @@ impl Platform for WindowsPlatform {
rx
}
fn prompt_for_new_path(&self, directory: &Path) -> Receiver<Option<PathBuf>> {
fn prompt_for_new_path(&self, directory: &Path) -> Receiver<Result<Option<PathBuf>>> {
let directory = directory.to_owned();
let (tx, rx) = oneshot::channel();
self.foreground_executor()
.spawn(async move {
unsafe {
let Ok(dialog) = show_savefile_dialog(directory) else {
let _ = tx.send(None);
let _ = tx.send(Ok(None));
return;
};
let Ok(_) = dialog.Show(None) else {
let _ = tx.send(None); // user cancel
let _ = tx.send(Ok(None)); // user cancel
return;
};
if let Ok(shell_item) = dialog.GetResult() {
if let Ok(file) = shell_item.GetDisplayName(SIGDN_FILESYSPATH) {
let _ = tx.send(Some(PathBuf::from(file.to_string().unwrap())));
let _ = tx.send(Ok(Some(PathBuf::from(file.to_string().unwrap()))));
return;
}
}
let _ = tx.send(None);
let _ = tx.send(Ok(None));
}
})
.detach();

View File

@@ -57,7 +57,7 @@ gpui = { workspace = true, features = ["test-support"] }
live_kit_server.workspace = true
nanoid.workspace = true
sha2.workspace = true
simplelog = "0.9"
simplelog.workspace = true
[build-dependencies]
serde.workspace = true

View File

@@ -7,7 +7,7 @@ use anyhow::{anyhow, Context, Result};
use collections::HashMap;
use futures::{channel::oneshot, io::BufWriter, select, AsyncRead, AsyncWrite, Future, FutureExt};
use gpui::{AppContext, AsyncAppContext, BackgroundExecutor, Task};
use parking_lot::Mutex;
use parking_lot::{Mutex, RwLock};
use postage::{barrier, prelude::Stream};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use serde_json::{json, value::RawValue, Value};
@@ -24,6 +24,7 @@ use std::{
ffi::OsString,
fmt,
io::Write,
ops::DerefMut,
path::PathBuf,
pin::Pin,
sync::{
@@ -69,7 +70,7 @@ pub struct LanguageServer {
next_id: AtomicI32,
outbound_tx: channel::Sender<String>,
name: Arc<str>,
capabilities: ServerCapabilities,
capabilities: RwLock<ServerCapabilities>,
code_action_kinds: Option<Vec<CodeActionKind>>,
notification_handlers: Arc<Mutex<HashMap<&'static str, NotificationHandler>>>,
response_handlers: Arc<Mutex<Option<HashMap<RequestId, ResponseHandler>>>>,
@@ -640,12 +641,19 @@ impl LanguageServer {
..Default::default()
}),
formatting: Some(DynamicRegistrationClientCapabilities {
dynamic_registration: None,
dynamic_registration: Some(true),
}),
range_formatting: Some(DynamicRegistrationClientCapabilities {
dynamic_registration: Some(true),
}),
on_type_formatting: Some(DynamicRegistrationClientCapabilities {
dynamic_registration: None,
dynamic_registration: Some(true),
}),
..Default::default()
synchronization: Some(TextDocumentSyncClientCapabilities {
did_save: Some(true),
..TextDocumentSyncClientCapabilities::default()
}),
..TextDocumentClientCapabilities::default()
}),
experimental: Some(json!({
"serverStatusNotification": true,
@@ -676,7 +684,7 @@ impl LanguageServer {
if let Some(info) = response.server_info {
self.name = info.name.into();
}
self.capabilities = response.capabilities;
self.capabilities = RwLock::new(response.capabilities);
self.notify::<notification::Initialized>(InitializedParams {})?;
Ok(Arc::new(self))
@@ -891,8 +899,12 @@ impl LanguageServer {
}
/// Get the reported capabilities of the running language server.
pub fn capabilities(&self) -> &ServerCapabilities {
&self.capabilities
pub fn capabilities(&self) -> ServerCapabilities {
self.capabilities.read().clone()
}
pub fn update_capabilities(&self, update: impl FnOnce(&mut ServerCapabilities)) {
update(self.capabilities.write().deref_mut());
}
/// Get the id of the running language server.

View File

@@ -1622,11 +1622,7 @@ impl OutlinePanel {
ExcerptOutlines::Invalidated(_) => ExcerptOutlines::NotFetched,
ExcerptOutlines::NotFetched => ExcerptOutlines::NotFetched,
},
None => {
new_collapsed_entries
.insert(CollapsedEntry::Excerpt(buffer_id, excerpt_id));
ExcerptOutlines::NotFetched
}
None => ExcerptOutlines::NotFetched,
};
new_excerpts.entry(buffer_id).or_default().insert(
excerpt_id,
@@ -1674,11 +1670,6 @@ impl OutlinePanel {
.insert(CollapsedEntry::ExternalFile(buffer_id));
}
}
for excerpt_id in &excerpts {
new_collapsed_entries
.insert(CollapsedEntry::Excerpt(buffer_id, *excerpt_id));
}
}
if let Some(worktree) = worktree {

View File

@@ -84,7 +84,7 @@ impl Prettier {
path_to_check.pop();
}
let mut project_path_with_prettier_dependency = None;
let mut closest_package_json_path = None;
loop {
if installed_prettiers.contains(&path_to_check) {
log::debug!("Found prettier path {path_to_check:?} in installed prettiers");
@@ -92,61 +92,44 @@ impl Prettier {
} else if let Some(package_json_contents) =
read_package_json(fs, &path_to_check).await?
{
if has_prettier_in_package_json(&package_json_contents) {
if has_prettier_in_node_modules(fs, &path_to_check).await? {
log::debug!("Found prettier path {path_to_check:?} in both package.json and node_modules");
return Ok(ControlFlow::Continue(Some(path_to_check)));
} else if project_path_with_prettier_dependency.is_none() {
project_path_with_prettier_dependency = Some(path_to_check.clone());
}
if has_prettier_in_node_modules(fs, &path_to_check).await? {
log::debug!("Found prettier path {path_to_check:?} in the node_modules");
return Ok(ControlFlow::Continue(Some(path_to_check)));
} else {
match package_json_contents.get("workspaces") {
Some(serde_json::Value::Array(workspaces)) => {
match &project_path_with_prettier_dependency {
Some(project_path_with_prettier_dependency) => {
let subproject_path = project_path_with_prettier_dependency.strip_prefix(&path_to_check).expect("traversing path parents, should be able to strip prefix");
if workspaces.iter().filter_map(|value| {
if let serde_json::Value::String(s) = value {
Some(s.clone())
} else {
log::warn!("Skipping non-string 'workspaces' value: {value:?}");
None
}
}).any(|workspace_definition| {
if let Some(path_matcher) = PathMatcher::new(&[workspace_definition.clone()]).ok() {
path_matcher.is_match(subproject_path)
} else {
workspace_definition == subproject_path.to_string_lossy()
}
}) {
anyhow::ensure!(has_prettier_in_node_modules(fs, &path_to_check).await?, "Found prettier path {path_to_check:?} in the workspace root for project in {project_path_with_prettier_dependency:?}, but it's not installed into workspace root's node_modules");
log::info!("Found prettier path {path_to_check:?} in the workspace root for project in {project_path_with_prettier_dependency:?}");
return Ok(ControlFlow::Continue(Some(path_to_check)));
match &closest_package_json_path {
None => closest_package_json_path = Some(path_to_check.clone()),
Some(closest_package_json_path) => {
match package_json_contents.get("workspaces") {
Some(serde_json::Value::Array(workspaces)) => {
let subproject_path = closest_package_json_path.strip_prefix(&path_to_check).expect("traversing path parents, should be able to strip prefix");
if workspaces.iter().filter_map(|value| {
if let serde_json::Value::String(s) = value {
Some(s.clone())
} else {
log::warn!("Skipping path {path_to_check:?} that has prettier in its 'node_modules' subdirectory, but is not included in its package.json workspaces {workspaces:?}");
log::warn!("Skipping non-string 'workspaces' value: {value:?}");
None
}
}).any(|workspace_definition| {
workspace_definition == subproject_path.to_string_lossy() || PathMatcher::new(&[workspace_definition]).ok().map_or(false, |path_matcher| path_matcher.is_match(subproject_path))
}) {
anyhow::ensure!(has_prettier_in_node_modules(fs, &path_to_check).await?, "Path {path_to_check:?} is the workspace root for project in {closest_package_json_path:?}, but it has no prettier installed");
log::info!("Found prettier path {path_to_check:?} in the workspace root for project in {closest_package_json_path:?}");
return Ok(ControlFlow::Continue(Some(path_to_check)));
} else {
log::warn!("Skipping path {path_to_check:?} workspace root with workspaces {workspaces:?} that have no prettier installed");
}
None => {
log::warn!("Skipping path {path_to_check:?} that has prettier in its 'node_modules' subdirectory, but has no prettier in its package.json");
}
}
},
Some(unknown) => log::error!("Failed to parse workspaces for {path_to_check:?} from package.json, got {unknown:?}. Skipping."),
None => log::warn!("Skipping path {path_to_check:?} that has no prettier dependency and no workspaces section in its package.json"),
},
Some(unknown) => log::error!("Failed to parse workspaces for {path_to_check:?} from package.json, got {unknown:?}. Skipping."),
None => log::warn!("Skipping path {path_to_check:?} that has no prettier dependency and no workspaces section in its package.json"),
}
}
}
}
}
if !path_to_check.pop() {
match project_path_with_prettier_dependency {
Some(closest_prettier_discovered) => {
anyhow::bail!("No prettier found in node_modules for ancestors of {locate_from:?}, but discovered prettier package.json dependency in {closest_prettier_discovered:?}")
}
None => {
log::debug!("Found no prettier in ancestors of {locate_from:?}");
return Ok(ControlFlow::Continue(None));
}
}
log::debug!("Found no prettier in ancestors of {locate_from:?}");
return Ok(ControlFlow::Continue(None));
}
}
}
@@ -448,22 +431,6 @@ async fn read_package_json(
Ok(None)
}
fn has_prettier_in_package_json(
package_json_contents: &HashMap<String, serde_json::Value>,
) -> bool {
if let Some(serde_json::Value::Object(o)) = package_json_contents.get("dependencies") {
if o.contains_key(PRETTIER_PACKAGE_NAME) {
return true;
}
}
if let Some(serde_json::Value::Object(o)) = package_json_contents.get("devDependencies") {
if o.contains_key(PRETTIER_PACKAGE_NAME) {
return true;
}
}
false
}
enum Format {}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
@@ -548,40 +515,36 @@ mod tests {
)
.await;
assert!(
matches!(
Prettier::locate_prettier_installation(
fs.as_ref(),
&HashSet::default(),
Path::new("/root/.config/zed/settings.json"),
)
.await,
Ok(ControlFlow::Continue(None))
),
"Should successfully find no prettier for path hierarchy without it"
assert_eq!(
Prettier::locate_prettier_installation(
fs.as_ref(),
&HashSet::default(),
Path::new("/root/.config/zed/settings.json"),
)
.await
.unwrap(),
ControlFlow::Continue(None),
"Should find no prettier for path hierarchy without it"
);
assert!(
matches!(
Prettier::locate_prettier_installation(
fs.as_ref(),
&HashSet::default(),
Path::new("/root/work/project/src/index.js")
)
.await,
Ok(ControlFlow::Continue(None))
),
"Should successfully find no prettier for path hierarchy that has node_modules with prettier, but no package.json mentions of it"
assert_eq!(
Prettier::locate_prettier_installation(
fs.as_ref(),
&HashSet::default(),
Path::new("/root/work/project/src/index.js")
)
.await.unwrap(),
ControlFlow::Continue(Some(PathBuf::from("/root/work/project"))),
"Should successfully find a prettier for path hierarchy that has node_modules with prettier, but no package.json mentions of it"
);
assert!(
matches!(
Prettier::locate_prettier_installation(
fs.as_ref(),
&HashSet::default(),
Path::new("/root/work/project/node_modules/expect/build/print.js")
)
.await,
Ok(ControlFlow::Break(()))
),
assert_eq!(
Prettier::locate_prettier_installation(
fs.as_ref(),
&HashSet::default(),
Path::new("/root/work/project/node_modules/expect/build/print.js")
)
.await
.unwrap(),
ControlFlow::Break(()),
"Should not format files inside node_modules/"
);
}
@@ -691,18 +654,17 @@ mod tests {
)
.await;
match Prettier::locate_prettier_installation(
fs.as_ref(),
&HashSet::default(),
Path::new("/root/work/web_blog/pages/[slug].tsx")
)
.await {
Ok(path) => panic!("Expected to fail for prettier in package.json but not in node_modules found, but got path {path:?}"),
Err(e) => {
let message = e.to_string();
assert!(message.contains("/root/work/web_blog"), "Error message should mention which project had prettier defined");
},
};
assert_eq!(
Prettier::locate_prettier_installation(
fs.as_ref(),
&HashSet::default(),
Path::new("/root/work/web_blog/pages/[slug].tsx")
)
.await
.unwrap(),
ControlFlow::Continue(None),
"Should find no prettier when node_modules don't have it"
);
assert_eq!(
Prettier::locate_prettier_installation(

View File

@@ -2471,7 +2471,7 @@ impl LspCommand for InlayHints {
lsp_adapter.name.0.as_ref() == "typescript-language-server";
let hints = message.unwrap_or_default().into_iter().map(|lsp_hint| {
let resolve_state = if InlayHints::can_resolve_inlays(lsp_server.capabilities()) {
let resolve_state = if InlayHints::can_resolve_inlays(&lsp_server.capabilities()) {
ResolveState::CanResolve(lsp_server.server_id(), lsp_hint.data.clone())
} else {
ResolveState::Resolved

View File

@@ -2853,15 +2853,21 @@ impl Project {
};
for (_, _, server) in self.language_servers_for_worktree(worktree_id) {
let text = include_text(server.as_ref()).then(|| buffer.read(cx).text());
server
.notify::<lsp::notification::DidSaveTextDocument>(
lsp::DidSaveTextDocumentParams {
text_document: text_document.clone(),
text,
},
)
.log_err();
if let Some(include_text) = include_text(server.as_ref()) {
let text = if include_text {
Some(buffer.read(cx).text())
} else {
None
};
server
.notify::<lsp::notification::DidSaveTextDocument>(
lsp::DidSaveTextDocumentParams {
text_document: text_document.clone(),
text,
},
)
.log_err();
}
}
for language_server_id in self.language_server_ids_for_buffer(buffer.read(cx), cx) {
@@ -3496,7 +3502,7 @@ impl Project {
}
async fn setup_pending_language_server(
this: WeakModel<Self>,
project: WeakModel<Self>,
override_options: Option<serde_json::Value>,
pending_server: PendingLanguageServer,
delegate: Arc<dyn LspAdapterDelegate>,
@@ -3515,7 +3521,7 @@ impl Project {
language_server
.on_notification::<lsp::notification::PublishDiagnostics, _>({
let adapter = adapter.clone();
let this = this.clone();
let this = project.clone();
move |mut params, mut cx| {
let adapter = adapter.clone();
if let Some(this) = this.upgrade() {
@@ -3569,7 +3575,7 @@ impl Project {
// to these requests when initializing.
language_server
.on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
let this = this.clone();
let this = project.clone();
move |params, mut cx| {
let this = this.clone();
async move {
@@ -3590,20 +3596,103 @@ impl Project {
language_server
.on_request::<lsp::request::RegisterCapability, _, _>({
let this = this.clone();
let project = project.clone();
move |params, mut cx| {
let this = this.clone();
let project = project.clone();
async move {
for reg in params.registrations {
if reg.method == "workspace/didChangeWatchedFiles" {
if let Some(options) = reg.register_options {
let options = serde_json::from_value(options)?;
this.update(&mut cx, |this, cx| {
this.on_lsp_did_change_watched_files(
server_id, &reg.id, options, cx,
);
})?;
match reg.method.as_str() {
"workspace/didChangeWatchedFiles" => {
if let Some(options) = reg.register_options {
let options = serde_json::from_value(options)?;
project.update(&mut cx, |project, cx| {
project.on_lsp_did_change_watched_files(
server_id, &reg.id, options, cx,
);
})?;
}
}
"textDocument/rangeFormatting" => {
project.update(&mut cx, |project, _| {
if let Some(server) =
project.language_server_for_id(server_id)
{
let options = reg
.register_options
.map(|options| {
serde_json::from_value::<
lsp::DocumentRangeFormattingOptions,
>(
options
)
})
.transpose()?;
let provider = match options {
None => OneOf::Left(true),
Some(options) => OneOf::Right(options),
};
server.update_capabilities(|capabilities| {
capabilities.document_range_formatting_provider =
Some(provider);
})
}
anyhow::Ok(())
})??;
}
"textDocument/onTypeFormatting" => {
project.update(&mut cx, |project, _| {
if let Some(server) =
project.language_server_for_id(server_id)
{
let options = reg
.register_options
.map(|options| {
serde_json::from_value::<
lsp::DocumentOnTypeFormattingOptions,
>(
options
)
})
.transpose()?;
if let Some(options) = options {
server.update_capabilities(|capabilities| {
capabilities
.document_on_type_formatting_provider =
Some(options);
})
}
}
anyhow::Ok(())
})??;
}
"textDocument/formatting" => {
project.update(&mut cx, |project, _| {
if let Some(server) =
project.language_server_for_id(server_id)
{
let options = reg
.register_options
.map(|options| {
serde_json::from_value::<
lsp::DocumentFormattingOptions,
>(
options
)
})
.transpose()?;
let provider = match options {
None => OneOf::Left(true),
Some(options) => OneOf::Right(options),
};
server.update_capabilities(|capabilities| {
capabilities.document_formatting_provider =
Some(provider);
})
}
anyhow::Ok(())
})??;
}
_ => log::warn!("unhandled capability registration: {reg:?}"),
}
}
Ok(())
@@ -3614,17 +3703,55 @@ impl Project {
language_server
.on_request::<lsp::request::UnregisterCapability, _, _>({
let this = this.clone();
let this = project.clone();
move |params, mut cx| {
let this = this.clone();
let project = this.clone();
async move {
for unreg in params.unregisterations.iter() {
if unreg.method == "workspace/didChangeWatchedFiles" {
this.update(&mut cx, |this, cx| {
this.on_lsp_unregister_did_change_watched_files(
server_id, &unreg.id, cx,
);
})?;
match unreg.method.as_str() {
"workspace/didChangeWatchedFiles" => {
project.update(&mut cx, |project, cx| {
project.on_lsp_unregister_did_change_watched_files(
server_id, &unreg.id, cx,
);
})?;
}
"textDocument/rangeFormatting" => {
project.update(&mut cx, |project, _| {
if let Some(server) =
project.language_server_for_id(server_id)
{
server.update_capabilities(|capabilities| {
capabilities.document_range_formatting_provider =
None
})
}
})?;
}
"textDocument/onTypeFormatting" => {
project.update(&mut cx, |project, _| {
if let Some(server) =
project.language_server_for_id(server_id)
{
server.update_capabilities(|capabilities| {
capabilities.document_on_type_formatting_provider =
None;
})
}
})?;
}
"textDocument/formatting" => {
project.update(&mut cx, |project, _| {
if let Some(server) =
project.language_server_for_id(server_id)
{
server.update_capabilities(|capabilities| {
capabilities.document_formatting_provider = None;
})
}
})?;
}
_ => log::warn!("unhandled capability unregistration: {unreg:?}"),
}
}
Ok(())
@@ -3636,7 +3763,7 @@ impl Project {
language_server
.on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
let adapter = adapter.clone();
let this = this.clone();
let this = project.clone();
move |params, cx| {
Self::on_lsp_workspace_edit(
this.clone(),
@@ -3651,7 +3778,7 @@ impl Project {
language_server
.on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
let this = this.clone();
let this = project.clone();
move |(), mut cx| {
let this = this.clone();
async move {
@@ -3670,7 +3797,7 @@ impl Project {
language_server
.on_request::<lsp::request::ShowMessageRequest, _, _>({
let this = this.clone();
let this = project.clone();
let name = name.to_string();
move |params, mut cx| {
let this = this.clone();
@@ -3709,7 +3836,7 @@ impl Project {
language_server
.on_notification::<ServerStatus, _>({
let this = this.clone();
let this = project.clone();
let name = name.to_string();
move |params, mut cx| {
let this = this.clone();
@@ -3752,7 +3879,7 @@ impl Project {
.detach();
language_server
.on_notification::<lsp::notification::ShowMessage, _>({
let this = this.clone();
let this = project.clone();
let name = name.to_string();
move |params, mut cx| {
let this = this.clone();
@@ -3779,7 +3906,7 @@ impl Project {
.detach();
language_server
.on_notification::<lsp::notification::Progress, _>(move |params, mut cx| {
if let Some(this) = this.upgrade() {
if let Some(this) = project.upgrade() {
this.update(&mut cx, |this, cx| {
this.on_lsp_progress(
params,
@@ -7026,7 +7153,7 @@ impl Project {
} else {
return Task::ready(Ok(hint));
};
if !InlayHints::can_resolve_inlays(lang_server.capabilities()) {
if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
return Task::ready(Ok(hint));
}
@@ -7438,7 +7565,7 @@ impl Project {
let lsp_params = request.to_lsp(&file.abs_path(cx), buffer, &language_server, cx);
let status = request.status();
return cx.spawn(move |this, cx| async move {
if !request.check_capabilities(language_server.capabilities()) {
if !request.check_capabilities(&language_server.capabilities()) {
return Ok(Default::default());
}
@@ -7532,7 +7659,7 @@ impl Project {
let scope = position.and_then(|position| snapshot.language_scope_at(position));
let mut response_results = self
.language_servers_for_buffer(buffer.read(cx), cx)
.filter(|(_, server)| server_capabilities_check(server.capabilities()))
.filter(|(_, server)| server_capabilities_check(&server.capabilities()))
.filter(|(adapter, _)| {
scope
.as_ref()
@@ -11713,20 +11840,27 @@ fn is_not_found_error(error: &anyhow::Error) -> bool {
.is_some_and(|err| err.kind() == io::ErrorKind::NotFound)
}
fn include_text(server: &lsp::LanguageServer) -> bool {
server
.capabilities()
.text_document_sync
.as_ref()
.and_then(|sync| match sync {
lsp::TextDocumentSyncCapability::Kind(_) => None,
lsp::TextDocumentSyncCapability::Options(options) => options.save.as_ref(),
})
.and_then(|save_options| match save_options {
lsp::TextDocumentSyncSaveOptions::Supported(_) => None,
lsp::TextDocumentSyncSaveOptions::SaveOptions(options) => options.include_text,
})
.unwrap_or(false)
fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
match server.capabilities().text_document_sync.as_ref()? {
lsp::TextDocumentSyncCapability::Kind(kind) => match kind {
&lsp::TextDocumentSyncKind::NONE => None,
&lsp::TextDocumentSyncKind::FULL => Some(true),
&lsp::TextDocumentSyncKind::INCREMENTAL => Some(false),
_ => None,
},
lsp::TextDocumentSyncCapability::Options(options) => match options.save.as_ref()? {
lsp::TextDocumentSyncSaveOptions::Supported(supported) => {
if *supported {
Some(true)
} else {
None
}
}
lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
Some(save_options.include_text.unwrap_or(false))
}
},
}
}
async fn load_shell_environment(dir: &Path) -> Result<HashMap<String, String>> {

View File

@@ -322,6 +322,12 @@ async fn test_managing_language_servers(cx: &mut gpui::TestAppContext) {
trigger_characters: Some(vec![".".to_string(), "::".to_string()]),
..Default::default()
}),
text_document_sync: Some(lsp::TextDocumentSyncCapability::Options(
lsp::TextDocumentSyncOptions {
save: Some(lsp::TextDocumentSyncSaveOptions::Supported(true)),
..Default::default()
},
)),
..Default::default()
},
..Default::default()
@@ -336,6 +342,12 @@ async fn test_managing_language_servers(cx: &mut gpui::TestAppContext) {
trigger_characters: Some(vec![":".to_string()]),
..Default::default()
}),
text_document_sync: Some(lsp::TextDocumentSyncCapability::Options(
lsp::TextDocumentSyncOptions {
save: Some(lsp::TextDocumentSyncSaveOptions::Supported(true)),
..Default::default()
},
)),
..Default::default()
},
..Default::default()

View File

@@ -29,7 +29,7 @@ picker.workspace = true
project.workspace = true
rust-embed.workspace = true
settings.workspace = true
simplelog = "0.9"
simplelog.workspace = true
story.workspace = true
strum = { version = "0.25.0", features = ["derive"] }
theme.workspace = true

View File

@@ -20,7 +20,7 @@ schemars = { workspace = true, features = ["indexmap"] }
serde.workspace = true
serde_json.workspace = true
serde_json_lenient.workspace = true
simplelog = "0.9"
simplelog.workspace= true
strum = { version = "0.25.0", features = ["derive"] }
theme.workspace = true
vscode_theme = "0.2.0"

View File

@@ -12,6 +12,7 @@ use indexmap::IndexMap;
use log::LevelFilter;
use schemars::schema_for;
use serde::Deserialize;
use simplelog::ColorChoice;
use simplelog::{TermLogger, TerminalMode};
use theme::{Appearance, AppearanceContent, ThemeFamilyContent};
@@ -94,11 +95,6 @@ fn main() -> Result<()> {
let log_config = {
let mut config = simplelog::ConfigBuilder::new();
config
.set_level_color(log::Level::Trace, simplelog::Color::Cyan)
.set_level_color(log::Level::Info, simplelog::Color::Blue)
.set_level_color(log::Level::Warn, simplelog::Color::Yellow)
.set_level_color(log::Level::Error, simplelog::Color::Red);
if !args.warn_on_missing {
config.add_filter_ignore_str("theme_printer");
@@ -107,8 +103,13 @@ fn main() -> Result<()> {
config.build()
};
TermLogger::init(LevelFilter::Trace, log_config, TerminalMode::Mixed)
.expect("could not initialize logger");
TermLogger::init(
LevelFilter::Trace,
log_config,
TerminalMode::Mixed,
ColorChoice::Auto,
)
.expect("could not initialize logger");
if let Some(command) = args.command {
match command {

View File

@@ -123,20 +123,22 @@ impl Render for WelcomePage {
.ok();
})),
)
.child(
Button::new("install-cli", "Install the CLI")
.full_width()
.on_click(cx.listener(|this, _, cx| {
this.telemetry.report_app_event(
"welcome page: install cli".to_string(),
);
cx.app_mut()
.spawn(|cx| async move {
install_cli::install_cli(&cx).await
})
.detach_and_log_err(cx);
})),
)
.when(cfg!(target_os = "macos"), |el| {
el.child(
Button::new("install-cli", "Install the CLI")
.full_width()
.on_click(cx.listener(|this, _, cx| {
this.telemetry.report_app_event(
"welcome page: install cli".to_string(),
);
cx.app_mut()
.spawn(|cx| async move {
install_cli::install_cli(&cx).await
})
.detach_and_log_err(cx);
})),
)
})
.child(
Button::new("sign-in-to-copilot", "Sign in to GitHub Copilot")
.full_width()

View File

@@ -160,14 +160,23 @@ impl Workspace {
self.show_notification(
NotificationId::unique::<WorkspaceErrorNotification>(),
cx,
|cx| {
cx.new_view(|_cx| {
simple_message_notification::MessageNotification::new(format!("Error: {err:#}"))
})
},
|cx| cx.new_view(|_cx| ErrorMessagePrompt::new(format!("Error: {err:#}"))),
);
}
pub fn show_portal_error(&mut self, err: String, cx: &mut ViewContext<Self>) {
struct PortalError;
self.show_notification(NotificationId::unique::<PortalError>(), cx, |cx| {
cx.new_view(|_cx| {
ErrorMessagePrompt::new(err.to_string()).with_link_button(
"See docs",
"https://zed.dev/docs/linux#i-cant-open-any-files",
)
})
});
}
pub fn dismiss_notification(&mut self, id: &NotificationId, cx: &mut ViewContext<Self>) {
self.dismiss_notification_internal(id, cx)
}
@@ -349,6 +358,84 @@ impl Render for LanguageServerPrompt {
impl EventEmitter<DismissEvent> for LanguageServerPrompt {}
pub struct ErrorMessagePrompt {
message: SharedString,
label_and_url_button: Option<(SharedString, SharedString)>,
}
impl ErrorMessagePrompt {
pub fn new<S>(message: S) -> Self
where
S: Into<SharedString>,
{
Self {
message: message.into(),
label_and_url_button: None,
}
}
pub fn with_link_button<S>(mut self, label: S, url: S) -> Self
where
S: Into<SharedString>,
{
self.label_and_url_button = Some((label.into(), url.into()));
self
}
}
impl Render for ErrorMessagePrompt {
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
h_flex()
.id("error_message_prompt_notification")
.occlude()
.elevation_3(cx)
.items_start()
.justify_between()
.p_2()
.gap_2()
.w_full()
.child(
v_flex()
.w_full()
.child(
h_flex()
.w_full()
.justify_between()
.child(
svg()
.size(cx.text_style().font_size)
.flex_none()
.mr_2()
.mt(px(-2.0))
.map(|icon| {
icon.path(IconName::ExclamationTriangle.path())
.text_color(Color::Error.color(cx))
}),
)
.child(
ui::IconButton::new("close", ui::IconName::Close)
.on_click(cx.listener(|_, _, cx| cx.emit(gpui::DismissEvent))),
),
)
.child(
div()
.max_w_80()
.child(Label::new(self.message.clone()).size(LabelSize::Small)),
)
.when_some(self.label_and_url_button.clone(), |elm, (label, url)| {
elm.child(
div().mt_2().child(
ui::Button::new("error_message_prompt_notification_button", label)
.on_click(move |_, cx| cx.open_url(&url)),
),
)
}),
)
}
}
impl EventEmitter<DismissEvent> for ErrorMessagePrompt {}
pub mod simple_message_notification {
use gpui::{
div, DismissEvent, EventEmitter, InteractiveElement, ParentElement, Render, SharedString,

View File

@@ -30,10 +30,10 @@ use gpui::{
action_as, actions, canvas, impl_action_as, impl_actions, point, relative, size,
transparent_black, Action, AnyElement, AnyView, AnyWeakView, AppContext, AsyncAppContext,
AsyncWindowContext, Bounds, CursorStyle, Decorations, DragMoveEvent, Entity as _, EntityId,
EventEmitter, FocusHandle, FocusableView, Global, Hsla, KeyContext, Keystroke, ManagedView,
Model, ModelContext, MouseButton, PathPromptOptions, Point, PromptLevel, Render, ResizeEdge,
Size, Stateful, Subscription, Task, Tiling, View, WeakView, WindowBounds, WindowHandle,
WindowOptions,
EventEmitter, Flatten, FocusHandle, FocusableView, Global, Hsla, KeyContext, Keystroke,
ManagedView, Model, ModelContext, MouseButton, PathPromptOptions, Point, PromptLevel, Render,
ResizeEdge, Size, Stateful, Subscription, Task, Tiling, View, WeakView, WindowBounds,
WindowHandle, WindowOptions,
};
use item::{
FollowableItem, FollowableItemHandle, Item, ItemHandle, ItemSettings, PreviewTabsSettings,
@@ -307,13 +307,31 @@ pub fn init(app_state: Arc<AppState>, cx: &mut AppContext) {
if let Some(app_state) = app_state.upgrade() {
cx.spawn(move |cx| async move {
if let Some(paths) = paths.await.log_err().flatten() {
cx.update(|cx| {
open_paths(&paths, app_state, OpenOptions::default(), cx)
.detach_and_log_err(cx)
})
.ok();
}
match Flatten::flatten(paths.await.map_err(|e| e.into())) {
Ok(Some(paths)) => {
cx.update(|cx| {
open_paths(&paths, app_state, OpenOptions::default(), cx)
.detach_and_log_err(cx)
})
.ok();
}
Ok(None) => {}
Err(err) => {
cx.update(|cx| {
if let Some(workspace_window) = cx
.active_window()
.and_then(|window| window.downcast::<Workspace>())
{
workspace_window
.update(cx, |workspace, cx| {
workspace.show_portal_error(err.to_string(), cx);
})
.ok();
}
})
.ok();
}
};
})
.detach();
}
@@ -1296,7 +1314,15 @@ impl Workspace {
let (tx, rx) = oneshot::channel();
let abs_path = cx.prompt_for_new_path(&start_abs_path);
cx.spawn(|this, mut cx| async move {
let abs_path = abs_path.await?;
let abs_path: Option<PathBuf> =
Flatten::flatten(abs_path.await.map_err(|e| e.into())).map_err(|err| {
this.update(&mut cx, |this, cx| {
this.show_portal_error(err.to_string(), cx);
})
.ok();
err
})?;
let project_path = abs_path.and_then(|abs_path| {
this.update(&mut cx, |this, cx| {
this.project.update(cx, |project, cx| {
@@ -1585,8 +1611,16 @@ impl Workspace {
});
cx.spawn(|this, mut cx| async move {
let Some(paths) = paths.await.log_err().flatten() else {
return;
let paths = match Flatten::flatten(paths.await.map_err(|e| e.into())) {
Ok(Some(paths)) => paths,
Ok(None) => return,
Err(err) => {
this.update(&mut cx, |this, cx| {
this.show_portal_error(err.to_string(), cx);
})
.ok();
return;
}
};
if let Some(task) = this
@@ -1748,7 +1782,14 @@ impl Workspace {
multiple: true,
});
cx.spawn(|this, mut cx| async move {
if let Some(paths) = paths.await.log_err().flatten() {
let paths = Flatten::flatten(paths.await.map_err(|e| e.into())).map_err(|err| {
this.update(&mut cx, |this, cx| {
this.show_portal_error(err.to_string(), cx);
})
.ok();
err
})?;
if let Some(paths) = paths {
let results = this
.update(&mut cx, |this, cx| {
this.open_paths(paths, OpenVisible::All, None, cx)

View File

@@ -2,7 +2,7 @@
description = "The fast, collaborative code editor."
edition = "2021"
name = "zed"
version = "0.144.0"
version = "0.144.3"
publish = false
license = "GPL-3.0-or-later"
authors = ["Zed Team <hi@zed.dev>"]
@@ -85,7 +85,7 @@ search.workspace = true
serde.workspace = true
serde_json.workspace = true
settings.workspace = true
simplelog = "0.9"
simplelog.workspace = true
smol.workspace = true
snippet_provider.workspace = true
tab_switcher.workspace = true

View File

@@ -1 +1 @@
dev
stable

View File

@@ -80,7 +80,9 @@ fn fail_to_open_window_async(e: anyhow::Error, cx: &mut AsyncAppContext) {
}
fn fail_to_open_window(e: anyhow::Error, _cx: &mut AppContext) {
eprintln!("Zed failed to open a window: {e:?}");
eprintln!(
"Zed failed to open a window: {e:?}. See https://zed.dev/docs/linux for troubleshooting steps."
);
#[cfg(not(target_os = "linux"))]
{
process::exit(1);
@@ -99,7 +101,12 @@ fn fail_to_open_window(e: anyhow::Error, _cx: &mut AppContext) {
.add_notification(
notification_id,
Notification::new("Zed failed to launch")
.body(Some(format!("{e:?}").as_str()))
.body(Some(
format!(
"{e:?}. See https://zed.dev/docs/linux for troubleshooting steps."
)
.as_str(),
))
.priority(Priority::High)
.icon(ashpd::desktop::Icon::with_names(&[
"dialog-question-symbolic",
@@ -708,8 +715,8 @@ fn init_logger() {
Ok(log_file) => {
let mut config_builder = ConfigBuilder::new();
config_builder.set_time_format_str("%Y-%m-%dT%T%:z");
config_builder.set_time_to_local(true);
config_builder.set_time_format_rfc3339();
config_builder.set_time_offset_to_local().log_err();
#[cfg(target_os = "linux")]
{