mirror of
https://github.com/zed-industries/zed.git
synced 2024-11-07 20:39:04 +03:00
Merge branch 'main' into collab-titlebar-2
This commit is contained in:
commit
625814d30a
2
.cargo/config.toml
Normal file
2
.cargo/config.toml
Normal file
@ -0,0 +1,2 @@
|
||||
[alias]
|
||||
xtask = "run --package xtask --"
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -4,6 +4,8 @@
|
||||
/plugins/bin
|
||||
/script/node_modules
|
||||
/styles/node_modules
|
||||
/styles/src/types/zed.ts
|
||||
/crates/theme/schemas/theme.json
|
||||
/crates/collab/static/styles.css
|
||||
/vendor/bin
|
||||
/assets/themes/*.json
|
||||
|
118
Cargo.lock
generated
118
Cargo.lock
generated
@ -109,6 +109,8 @@ dependencies = [
|
||||
"isahc",
|
||||
"language",
|
||||
"menu",
|
||||
"project",
|
||||
"regex",
|
||||
"schemars",
|
||||
"search",
|
||||
"serde",
|
||||
@ -190,6 +192,55 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"is-terminal 0.4.7",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
|
||||
dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.71"
|
||||
@ -1102,8 +1153,8 @@ checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"bitflags",
|
||||
"clap_derive",
|
||||
"clap_lex",
|
||||
"clap_derive 3.2.25",
|
||||
"clap_lex 0.2.4",
|
||||
"indexmap",
|
||||
"once_cell",
|
||||
"strsim",
|
||||
@ -1111,6 +1162,30 @@ dependencies = [
|
||||
"textwrap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2686c4115cb0810d9a984776e197823d08ec94f176549a89a9efded477c456dc"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive 4.3.2",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e53afce1efce6ed1f633cf0e57612fe51db54a1ee4fd8f8503d078fe02d69ae"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"bitflags",
|
||||
"clap_lex 0.5.0",
|
||||
"strsim",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "3.2.25"
|
||||
@ -1124,6 +1199,18 @@ dependencies = [
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8cd2b2a819ad6eec39e8f1d6b53001af1e5469f8c177579cdaeb313115b825f"
|
||||
dependencies = [
|
||||
"heck 0.4.1",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.2.4"
|
||||
@ -1133,12 +1220,18 @@ dependencies = [
|
||||
"os_str_bytes",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b"
|
||||
|
||||
[[package]]
|
||||
name = "cli"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"clap 3.2.25",
|
||||
"core-foundation",
|
||||
"core-services",
|
||||
"dirs 3.0.2",
|
||||
@ -1248,7 +1341,7 @@ dependencies = [
|
||||
"axum-extra",
|
||||
"base64 0.13.1",
|
||||
"call",
|
||||
"clap",
|
||||
"clap 3.2.25",
|
||||
"client",
|
||||
"collections",
|
||||
"ctor",
|
||||
@ -1345,6 +1438,12 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||
|
||||
[[package]]
|
||||
name = "command_palette"
|
||||
version = "0.1.0"
|
||||
@ -8770,6 +8869,17 @@ version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9"
|
||||
|
||||
[[package]]
|
||||
name = "xtask"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.3.5",
|
||||
"schemars",
|
||||
"serde_json",
|
||||
"theme",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yaml-rust"
|
||||
version = "0.4.5"
|
||||
|
@ -65,6 +65,7 @@ members = [
|
||||
"crates/vim",
|
||||
"crates/workspace",
|
||||
"crates/welcome",
|
||||
"crates/xtask",
|
||||
"crates/zed",
|
||||
"crates/zed-actions"
|
||||
]
|
||||
@ -118,3 +119,4 @@ split-debuginfo = "unpacked"
|
||||
[profile.release]
|
||||
debug = true
|
||||
lto = "thin"
|
||||
codegen-units = 1
|
||||
|
1
assets/icons/assist_15.svg
Normal file
1
assets/icons/assist_15.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M13.9 0.499976C13.9 0.279062 13.7209 0.0999756 13.5 0.0999756C13.2791 0.0999756 13.1 0.279062 13.1 0.499976V1.09998H12.5C12.2791 1.09998 12.1 1.27906 12.1 1.49998C12.1 1.72089 12.2791 1.89998 12.5 1.89998H13.1V2.49998C13.1 2.72089 13.2791 2.89998 13.5 2.89998C13.7209 2.89998 13.9 2.72089 13.9 2.49998V1.89998H14.5C14.7209 1.89998 14.9 1.72089 14.9 1.49998C14.9 1.27906 14.7209 1.09998 14.5 1.09998H13.9V0.499976ZM11.8536 3.14642C12.0488 3.34168 12.0488 3.65826 11.8536 3.85353L10.8536 4.85353C10.6583 5.04879 10.3417 5.04879 10.1465 4.85353C9.9512 4.65827 9.9512 4.34169 10.1465 4.14642L11.1464 3.14643C11.3417 2.95116 11.6583 2.95116 11.8536 3.14642ZM9.85357 5.14642C10.0488 5.34168 10.0488 5.65827 9.85357 5.85353L2.85355 12.8535C2.65829 13.0488 2.34171 13.0488 2.14645 12.8535C1.95118 12.6583 1.95118 12.3417 2.14645 12.1464L9.14646 5.14642C9.34172 4.95116 9.65831 4.95116 9.85357 5.14642ZM13.5 5.09998C13.7209 5.09998 13.9 5.27906 13.9 5.49998V6.09998H14.5C14.7209 6.09998 14.9 6.27906 14.9 6.49998C14.9 6.72089 14.7209 6.89998 14.5 6.89998H13.9V7.49998C13.9 7.72089 13.7209 7.89998 13.5 7.89998C13.2791 7.89998 13.1 7.72089 13.1 7.49998V6.89998H12.5C12.2791 6.89998 12.1 6.72089 12.1 6.49998C12.1 6.27906 12.2791 6.09998 12.5 6.09998H13.1V5.49998C13.1 5.27906 13.2791 5.09998 13.5 5.09998ZM8.90002 0.499976C8.90002 0.279062 8.72093 0.0999756 8.50002 0.0999756C8.2791 0.0999756 8.10002 0.279062 8.10002 0.499976V1.09998H7.50002C7.2791 1.09998 7.10002 1.27906 7.10002 1.49998C7.10002 1.72089 7.2791 1.89998 7.50002 1.89998H8.10002V2.49998C8.10002 2.72089 8.2791 2.89998 8.50002 2.89998C8.72093 2.89998 8.90002 2.72089 8.90002 2.49998V1.89998H9.50002C9.72093 1.89998 9.90002 1.72089 9.90002 1.49998C9.90002 1.27906 9.72093 1.09998 9.50002 1.09998H8.90002V0.499976Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"></path></svg>
|
After Width: | Height: | Size: 1.9 KiB |
3
assets/icons/hamburger_15.svg
Normal file
3
assets/icons/hamburger_15.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 3C1.22386 3 1 3.22386 1 3.5C1 3.77614 1.22386 4 1.5 4H13.5C13.7761 4 14 3.77614 14 3.5C14 3.22386 13.7761 3 13.5 3H1.5ZM1 7.5C1 7.22386 1.22386 7 1.5 7H13.5C13.7761 7 14 7.22386 14 7.5C14 7.77614 13.7761 8 13.5 8H1.5C1.22386 8 1 7.77614 1 7.5ZM1 11.5C1 11.2239 1.22386 11 1.5 11H13.5C13.7761 11 14 11.2239 14 11.5C14 11.7761 13.7761 12 13.5 12H1.5C1.22386 12 1 11.7761 1 11.5Z" fill="#CCCAC2"/>
|
||||
</svg>
|
After Width: | Height: | Size: 552 B |
1
assets/icons/quote_15.svg
Normal file
1
assets/icons/quote_15.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M9.42503 3.44136C10.0561 3.23654 10.7837 3.2402 11.3792 3.54623C12.7532 4.25224 13.3477 6.07191 12.7946 8C12.5465 8.8649 12.1102 9.70472 11.1861 10.5524C10.262 11.4 8.98034 11.9 8.38571 11.9C8.17269 11.9 8 11.7321 8 11.525C8 11.3179 8.17644 11.15 8.38571 11.15C9.06497 11.15 9.67189 10.7804 10.3906 10.236C10.9406 9.8193 11.3701 9.28633 11.608 8.82191C12.0628 7.93367 12.0782 6.68174 11.3433 6.34901C10.9904 6.73455 10.5295 6.95946 9.97725 6.95946C8.7773 6.95946 8.0701 5.99412 8.10051 5.12009C8.12957 4.28474 8.66032 3.68954 9.42503 3.44136ZM3.42503 3.44136C4.05614 3.23654 4.78366 3.2402 5.37923 3.54623C6.7532 4.25224 7.34766 6.07191 6.79462 8C6.54654 8.8649 6.11019 9.70472 5.1861 10.5524C4.26201 11.4 2.98034 11.9 2.38571 11.9C2.17269 11.9 2 11.7321 2 11.525C2 11.3179 2.17644 11.15 2.38571 11.15C3.06497 11.15 3.67189 10.7804 4.39058 10.236C4.94065 9.8193 5.37014 9.28633 5.60797 8.82191C6.06282 7.93367 6.07821 6.68174 5.3433 6.34901C4.99037 6.73455 4.52948 6.95946 3.97725 6.95946C2.7773 6.95946 2.0701 5.99412 2.10051 5.12009C2.12957 4.28474 2.66032 3.68954 3.42503 3.44136Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"></path></svg>
|
After Width: | Height: | Size: 1.2 KiB |
1
assets/icons/split_message_15.svg
Normal file
1
assets/icons/split_message_15.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M7.81832 0.68179C7.64258 0.506054 7.35766 0.506054 7.18192 0.68179L5.18192 2.68179C5.00619 2.85753 5.00619 3.14245 5.18192 3.31819C5.35766 3.49392 5.64258 3.49392 5.81832 3.31819L7.05012 2.08638L7.05012 5.50023C7.05012 5.74876 7.25159 5.95023 7.50012 5.95023C7.74865 5.95023 7.95012 5.74876 7.95012 5.50023L7.95012 2.08638L9.18192 3.31819C9.35766 3.49392 9.64258 3.49392 9.81832 3.31819C9.99406 3.14245 9.99406 2.85753 9.81832 2.68179L7.81832 0.68179ZM7.95012 12.9136V9.50023C7.95012 9.2517 7.74865 9.05023 7.50012 9.05023C7.25159 9.05023 7.05012 9.2517 7.05012 9.50023V12.9136L5.81832 11.6818C5.64258 11.5061 5.35766 11.5061 5.18192 11.6818C5.00619 11.8575 5.00619 12.1424 5.18192 12.3182L7.18192 14.3182C7.26632 14.4026 7.38077 14.45 7.50012 14.45C7.61947 14.45 7.73393 14.4026 7.81832 14.3182L9.81832 12.3182C9.99406 12.1424 9.99406 11.8575 9.81832 11.6818C9.64258 11.5061 9.35766 11.5061 9.18192 11.6818L7.95012 12.9136ZM1.49994 7.00017C1.2238 7.00017 0.999939 7.22403 0.999939 7.50017C0.999939 7.77631 1.2238 8.00017 1.49994 8.00017L13.4999 8.00017C13.7761 8.00017 13.9999 7.77631 13.9999 7.50017C13.9999 7.22403 13.7761 7.00017 13.4999 7.00017L1.49994 7.00017Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"></path></svg>
|
After Width: | Height: | Size: 1.3 KiB |
@ -40,7 +40,8 @@
|
||||
"cmd-o": "workspace::Open",
|
||||
"alt-cmd-o": "projects::OpenRecent",
|
||||
"ctrl-~": "workspace::NewTerminal",
|
||||
"ctrl-`": "terminal_panel::ToggleFocus"
|
||||
"ctrl-`": "terminal_panel::ToggleFocus",
|
||||
"shift-escape": "workspace::ToggleZoom"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -197,9 +198,17 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"context": "AssistantEditor > Editor",
|
||||
"context": "AssistantPanel",
|
||||
"bindings": {
|
||||
"cmd-g": "search::SelectNextMatch",
|
||||
"cmd-shift-g": "search::SelectPrevMatch"
|
||||
}
|
||||
},
|
||||
{
|
||||
"context": "ConversationEditor > Editor",
|
||||
"bindings": {
|
||||
"cmd-enter": "assistant::Assist",
|
||||
"cmd-s": "workspace::Save",
|
||||
"cmd->": "assistant::QuoteSelection",
|
||||
"shift-enter": "assistant::Split",
|
||||
"ctrl-r": "assistant::CycleMessageRole"
|
||||
@ -234,8 +243,7 @@
|
||||
"cmd-shift-g": "search::SelectPrevMatch",
|
||||
"alt-cmd-c": "search::ToggleCaseSensitive",
|
||||
"alt-cmd-w": "search::ToggleWholeWord",
|
||||
"alt-cmd-r": "search::ToggleRegex",
|
||||
"shift-escape": "workspace::ToggleZoom"
|
||||
"alt-cmd-r": "search::ToggleRegex"
|
||||
}
|
||||
},
|
||||
// Bindings from VS Code
|
||||
|
@ -1,6 +1,6 @@
|
||||
[
|
||||
{
|
||||
"context": "Editor && VimControl && !VimWaiting",
|
||||
"context": "Editor && VimControl && !VimWaiting && !menu",
|
||||
"bindings": {
|
||||
"g": [
|
||||
"vim::PushOperator",
|
||||
@ -58,10 +58,6 @@
|
||||
}
|
||||
],
|
||||
"%": "vim::Matching",
|
||||
"ctrl-y": [
|
||||
"vim::Scroll",
|
||||
"LineUp"
|
||||
],
|
||||
"f": [
|
||||
"vim::PushOperator",
|
||||
{
|
||||
@ -137,7 +133,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"context": "Editor && vim_mode == normal && vim_operator == none && !VimWaiting",
|
||||
"context": "Editor && vim_mode == normal && (vim_operator == none || vim_operator == n) && !VimWaiting",
|
||||
"bindings": {
|
||||
"c": [
|
||||
"vim::PushOperator",
|
||||
@ -172,6 +168,7 @@
|
||||
"^": "vim::FirstNonWhitespace",
|
||||
"o": "vim::InsertLineBelow",
|
||||
"shift-o": "vim::InsertLineAbove",
|
||||
"~": "vim::ChangeCase",
|
||||
"v": [
|
||||
"vim::SwitchMode",
|
||||
{
|
||||
@ -197,30 +194,23 @@
|
||||
"focus": true
|
||||
}
|
||||
],
|
||||
"ctrl-f": [
|
||||
"vim::Scroll",
|
||||
"PageDown"
|
||||
],
|
||||
"ctrl-b": [
|
||||
"vim::Scroll",
|
||||
"PageUp"
|
||||
],
|
||||
"ctrl-d": [
|
||||
"vim::Scroll",
|
||||
"HalfPageDown"
|
||||
],
|
||||
"ctrl-u": [
|
||||
"vim::Scroll",
|
||||
"HalfPageUp"
|
||||
],
|
||||
"ctrl-e": [
|
||||
"vim::Scroll",
|
||||
"LineDown"
|
||||
],
|
||||
"ctrl-f": "vim::PageDown",
|
||||
"pagedown": "vim::PageDown",
|
||||
"ctrl-b": "vim::PageUp",
|
||||
"pageup": "vim::PageUp",
|
||||
"ctrl-d": "vim::ScrollDown",
|
||||
"ctrl-u": "vim::ScrollUp",
|
||||
"ctrl-e": "vim::LineDown",
|
||||
"ctrl-y": "vim::LineUp",
|
||||
"r": [
|
||||
"vim::PushOperator",
|
||||
"Replace"
|
||||
]
|
||||
],
|
||||
"s": "vim::Substitute",
|
||||
"> >": "editor::Indent",
|
||||
"< <": "editor::Outdent",
|
||||
"ctrl-pagedown": "pane::ActivateNextItem",
|
||||
"ctrl-pageup": "pane::ActivatePrevItem"
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -237,6 +227,8 @@
|
||||
"bindings": {
|
||||
"g": "vim::StartOfDocument",
|
||||
"h": "editor::Hover",
|
||||
"t": "pane::ActivateNextItem",
|
||||
"shift-t": "pane::ActivatePrevItem",
|
||||
"escape": [
|
||||
"vim::SwitchMode",
|
||||
"Normal"
|
||||
@ -307,10 +299,14 @@
|
||||
"x": "vim::VisualDelete",
|
||||
"y": "vim::VisualYank",
|
||||
"p": "vim::VisualPaste",
|
||||
"s": "vim::Substitute",
|
||||
"~": "vim::ChangeCase",
|
||||
"r": [
|
||||
"vim::PushOperator",
|
||||
"Replace"
|
||||
]
|
||||
],
|
||||
"> >": "editor::Indent",
|
||||
"< <": "editor::Outdent"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -57,37 +57,37 @@
|
||||
"show_whitespaces": "selection",
|
||||
// Scrollbar related settings
|
||||
"scrollbar": {
|
||||
// When to show the scrollbar in the editor.
|
||||
// This setting can take four values:
|
||||
//
|
||||
// 1. Show the scrollbar if there's important information or
|
||||
// follow the system's configured behavior (default):
|
||||
// "auto"
|
||||
// 2. Match the system's configured behavior:
|
||||
// "system"
|
||||
// 3. Always show the scrollbar:
|
||||
// "always"
|
||||
// 4. Never show the scrollbar:
|
||||
// "never"
|
||||
"show": "auto",
|
||||
// Whether to show git diff indicators in the scrollbar.
|
||||
"git_diff": true
|
||||
// When to show the scrollbar in the editor.
|
||||
// This setting can take four values:
|
||||
//
|
||||
// 1. Show the scrollbar if there's important information or
|
||||
// follow the system's configured behavior (default):
|
||||
// "auto"
|
||||
// 2. Match the system's configured behavior:
|
||||
// "system"
|
||||
// 3. Always show the scrollbar:
|
||||
// "always"
|
||||
// 4. Never show the scrollbar:
|
||||
// "never"
|
||||
"show": "auto",
|
||||
// Whether to show git diff indicators in the scrollbar.
|
||||
"git_diff": true
|
||||
},
|
||||
"project_panel": {
|
||||
// Whether to show the git status in the project panel.
|
||||
"git_status": true,
|
||||
// Where to dock project panel. Can be 'left' or 'right'.
|
||||
"dock": "left",
|
||||
// Default width of the project panel.
|
||||
"default_width": 240
|
||||
// Whether to show the git status in the project panel.
|
||||
"git_status": true,
|
||||
// Where to dock project panel. Can be 'left' or 'right'.
|
||||
"dock": "left",
|
||||
// Default width of the project panel.
|
||||
"default_width": 240
|
||||
},
|
||||
"assistant": {
|
||||
// Where to dock the assistant. Can be 'left', 'right' or 'bottom'.
|
||||
"dock": "right",
|
||||
// Default width when the assistant is docked to the left or right.
|
||||
"default_width": 450,
|
||||
// Default height when the assistant is docked to the bottom.
|
||||
"default_height": 320
|
||||
// Where to dock the assistant. Can be 'left', 'right' or 'bottom'.
|
||||
"dock": "right",
|
||||
// Default width when the assistant is docked to the left or right.
|
||||
"default_width": 640,
|
||||
// Default height when the assistant is docked to the bottom.
|
||||
"default_height": 320
|
||||
},
|
||||
// Whether the screen sharing icon is shown in the os status bar.
|
||||
"show_call_status_icon": true,
|
||||
|
@ -22,9 +22,10 @@ util = { path = "../util" }
|
||||
workspace = { path = "../workspace" }
|
||||
|
||||
anyhow.workspace = true
|
||||
chrono = "0.4"
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
futures.workspace = true
|
||||
isahc.workspace = true
|
||||
regex.workspace = true
|
||||
schemars.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
@ -33,3 +34,4 @@ tiktoken-rs = "0.4"
|
||||
|
||||
[dev-dependencies]
|
||||
editor = { path = "../editor", features = ["test-support"] }
|
||||
project = { path = "../project", features = ["test-support"] }
|
||||
|
@ -1,10 +1,22 @@
|
||||
pub mod assistant;
|
||||
mod assistant_settings;
|
||||
|
||||
use anyhow::Result;
|
||||
pub use assistant::AssistantPanel;
|
||||
use chrono::{DateTime, Local};
|
||||
use collections::HashMap;
|
||||
use fs::Fs;
|
||||
use futures::StreamExt;
|
||||
use gpui::AppContext;
|
||||
use regex::Regex;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{self, Display};
|
||||
use std::{
|
||||
cmp::Reverse,
|
||||
fmt::{self, Display},
|
||||
path::PathBuf,
|
||||
sync::Arc,
|
||||
};
|
||||
use util::paths::CONVERSATIONS_DIR;
|
||||
|
||||
// Data types for chat completion requests
|
||||
#[derive(Debug, Serialize)]
|
||||
@ -14,6 +26,84 @@ struct OpenAIRequest {
|
||||
stream: bool,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Copy, Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize,
|
||||
)]
|
||||
struct MessageId(usize);
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
struct MessageMetadata {
|
||||
role: Role,
|
||||
sent_at: DateTime<Local>,
|
||||
status: MessageStatus,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
enum MessageStatus {
|
||||
Pending,
|
||||
Done,
|
||||
Error(Arc<str>),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct SavedMessage {
|
||||
id: MessageId,
|
||||
start: usize,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct SavedConversation {
|
||||
zed: String,
|
||||
version: String,
|
||||
text: String,
|
||||
messages: Vec<SavedMessage>,
|
||||
message_metadata: HashMap<MessageId, MessageMetadata>,
|
||||
summary: String,
|
||||
model: String,
|
||||
}
|
||||
|
||||
impl SavedConversation {
|
||||
const VERSION: &'static str = "0.1.0";
|
||||
}
|
||||
|
||||
struct SavedConversationMetadata {
|
||||
title: String,
|
||||
path: PathBuf,
|
||||
mtime: chrono::DateTime<chrono::Local>,
|
||||
}
|
||||
|
||||
impl SavedConversationMetadata {
|
||||
pub async fn list(fs: Arc<dyn Fs>) -> Result<Vec<Self>> {
|
||||
fs.create_dir(&CONVERSATIONS_DIR).await?;
|
||||
|
||||
let mut paths = fs.read_dir(&CONVERSATIONS_DIR).await?;
|
||||
let mut conversations = Vec::<SavedConversationMetadata>::new();
|
||||
while let Some(path) = paths.next().await {
|
||||
let path = path?;
|
||||
|
||||
let pattern = r" - \d+.zed.json$";
|
||||
let re = Regex::new(pattern).unwrap();
|
||||
|
||||
let metadata = fs.metadata(&path).await?;
|
||||
if let Some((file_name, metadata)) = path
|
||||
.file_name()
|
||||
.and_then(|name| name.to_str())
|
||||
.zip(metadata)
|
||||
{
|
||||
let title = re.replace(file_name, "");
|
||||
conversations.push(Self {
|
||||
title: title.into_owned(),
|
||||
path,
|
||||
mtime: metadata.mtime.into(),
|
||||
});
|
||||
}
|
||||
}
|
||||
conversations.sort_unstable_by_key(|conversation| Reverse(conversation.mtime));
|
||||
|
||||
Ok(conversations)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
|
||||
struct RequestMessage {
|
||||
role: Role,
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,4 @@
|
||||
use crate::{TelemetrySettings, ZED_SECRET_CLIENT_TOKEN, ZED_SERVER_URL};
|
||||
use db::kvp::KEY_VALUE_STORE;
|
||||
use gpui::{executor::Background, serde_json, AppContext, Task};
|
||||
use lazy_static::lazy_static;
|
||||
use parking_lot::Mutex;
|
||||
@ -8,7 +7,6 @@ use std::{env, io::Write, mem, path::PathBuf, sync::Arc, time::Duration};
|
||||
use tempfile::NamedTempFile;
|
||||
use util::http::HttpClient;
|
||||
use util::{channel::ReleaseChannel, TryFutureExt};
|
||||
use uuid::Uuid;
|
||||
|
||||
pub struct Telemetry {
|
||||
http_client: Arc<dyn HttpClient>,
|
||||
@ -120,39 +118,15 @@ impl Telemetry {
|
||||
Some(self.state.lock().log_file.as_ref()?.path().to_path_buf())
|
||||
}
|
||||
|
||||
pub fn start(self: &Arc<Self>) {
|
||||
let this = self.clone();
|
||||
self.executor
|
||||
.spawn(
|
||||
async move {
|
||||
let installation_id =
|
||||
if let Ok(Some(installation_id)) = KEY_VALUE_STORE.read_kvp("device_id") {
|
||||
installation_id
|
||||
} else {
|
||||
let installation_id = Uuid::new_v4().to_string();
|
||||
KEY_VALUE_STORE
|
||||
.write_kvp("device_id".to_string(), installation_id.clone())
|
||||
.await?;
|
||||
installation_id
|
||||
};
|
||||
pub fn start(self: &Arc<Self>, installation_id: Option<String>) {
|
||||
let mut state = self.state.lock();
|
||||
state.installation_id = installation_id.map(|id| id.into());
|
||||
let has_clickhouse_events = !state.clickhouse_events_queue.is_empty();
|
||||
drop(state);
|
||||
|
||||
let installation_id: Arc<str> = installation_id.into();
|
||||
let mut state = this.state.lock();
|
||||
state.installation_id = Some(installation_id.clone());
|
||||
|
||||
let has_clickhouse_events = !state.clickhouse_events_queue.is_empty();
|
||||
|
||||
drop(state);
|
||||
|
||||
if has_clickhouse_events {
|
||||
this.flush_clickhouse_events();
|
||||
}
|
||||
|
||||
anyhow::Ok(())
|
||||
}
|
||||
.log_err(),
|
||||
)
|
||||
.detach();
|
||||
if has_clickhouse_events {
|
||||
self.flush_clickhouse_events();
|
||||
}
|
||||
}
|
||||
|
||||
/// This method takes the entire TelemetrySettings struct in order to force client code
|
||||
|
@ -7641,8 +7641,14 @@ impl View for Editor {
|
||||
keymap.add_identifier("renaming");
|
||||
}
|
||||
match self.context_menu.as_ref() {
|
||||
Some(ContextMenu::Completions(_)) => keymap.add_identifier("showing_completions"),
|
||||
Some(ContextMenu::CodeActions(_)) => keymap.add_identifier("showing_code_actions"),
|
||||
Some(ContextMenu::Completions(_)) => {
|
||||
keymap.add_identifier("menu");
|
||||
keymap.add_identifier("showing_completions")
|
||||
}
|
||||
Some(ContextMenu::CodeActions(_)) => {
|
||||
keymap.add_identifier("menu");
|
||||
keymap.add_identifier("showing_code_actions")
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
for layer in self.keymap_context_layers.values() {
|
||||
|
@ -1,5 +1,6 @@
|
||||
use super::*;
|
||||
use crate::{
|
||||
scroll::scroll_amount::ScrollAmount,
|
||||
test::{
|
||||
assert_text_with_selections, build_editor, editor_lsp_test_context::EditorLspTestContext,
|
||||
editor_test_context::EditorTestContext, select_ranges,
|
||||
@ -1359,6 +1360,43 @@ async fn test_move_start_of_paragraph_end_of_paragraph(cx: &mut gpui::TestAppCon
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_scroll_page_up_page_down(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
let mut cx = EditorTestContext::new(cx).await;
|
||||
let line_height = cx.editor(|editor, cx| editor.style(cx).text.line_height(cx.font_cache()));
|
||||
cx.simulate_window_resize(cx.window_id, vec2f(1000., 4. * line_height + 0.5));
|
||||
|
||||
cx.set_state(
|
||||
&r#"ˇone
|
||||
two
|
||||
three
|
||||
four
|
||||
five
|
||||
six
|
||||
seven
|
||||
eight
|
||||
nine
|
||||
ten
|
||||
"#,
|
||||
);
|
||||
|
||||
cx.update_editor(|editor, cx| {
|
||||
assert_eq!(editor.snapshot(cx).scroll_position(), vec2f(0., 0.));
|
||||
editor.scroll_screen(&ScrollAmount::Page(1.), cx);
|
||||
assert_eq!(editor.snapshot(cx).scroll_position(), vec2f(0., 3.));
|
||||
editor.scroll_screen(&ScrollAmount::Page(1.), cx);
|
||||
assert_eq!(editor.snapshot(cx).scroll_position(), vec2f(0., 6.));
|
||||
editor.scroll_screen(&ScrollAmount::Page(-1.), cx);
|
||||
assert_eq!(editor.snapshot(cx).scroll_position(), vec2f(0., 3.));
|
||||
|
||||
editor.scroll_screen(&ScrollAmount::Page(-0.5), cx);
|
||||
assert_eq!(editor.snapshot(cx).scroll_position(), vec2f(0., 2.));
|
||||
editor.scroll_screen(&ScrollAmount::Page(0.5), cx);
|
||||
assert_eq!(editor.snapshot(cx).scroll_position(), vec2f(0., 3.));
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_move_page_up_page_down(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
|
@ -368,7 +368,7 @@ impl Editor {
|
||||
}
|
||||
|
||||
let cur_position = self.scroll_position(cx);
|
||||
let new_pos = cur_position + vec2f(0., amount.lines(self) - 1.);
|
||||
let new_pos = cur_position + vec2f(0., amount.lines(self));
|
||||
self.set_scroll_position(new_pos, cx);
|
||||
}
|
||||
|
||||
|
@ -27,22 +27,22 @@ pub fn init(cx: &mut AppContext) {
|
||||
cx.add_action(Editor::scroll_cursor_center);
|
||||
cx.add_action(Editor::scroll_cursor_bottom);
|
||||
cx.add_action(|this: &mut Editor, _: &LineDown, cx| {
|
||||
this.scroll_screen(&ScrollAmount::LineDown, cx)
|
||||
this.scroll_screen(&ScrollAmount::Line(1.), cx)
|
||||
});
|
||||
cx.add_action(|this: &mut Editor, _: &LineUp, cx| {
|
||||
this.scroll_screen(&ScrollAmount::LineUp, cx)
|
||||
this.scroll_screen(&ScrollAmount::Line(-1.), cx)
|
||||
});
|
||||
cx.add_action(|this: &mut Editor, _: &HalfPageDown, cx| {
|
||||
this.scroll_screen(&ScrollAmount::HalfPageDown, cx)
|
||||
this.scroll_screen(&ScrollAmount::Page(0.5), cx)
|
||||
});
|
||||
cx.add_action(|this: &mut Editor, _: &HalfPageUp, cx| {
|
||||
this.scroll_screen(&ScrollAmount::HalfPageUp, cx)
|
||||
this.scroll_screen(&ScrollAmount::Page(-0.5), cx)
|
||||
});
|
||||
cx.add_action(|this: &mut Editor, _: &PageDown, cx| {
|
||||
this.scroll_screen(&ScrollAmount::PageDown, cx)
|
||||
this.scroll_screen(&ScrollAmount::Page(1.), cx)
|
||||
});
|
||||
cx.add_action(|this: &mut Editor, _: &PageUp, cx| {
|
||||
this.scroll_screen(&ScrollAmount::PageUp, cx)
|
||||
this.scroll_screen(&ScrollAmount::Page(-1.), cx)
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -6,12 +6,10 @@ use crate::Editor;
|
||||
|
||||
#[derive(Clone, PartialEq, Deserialize)]
|
||||
pub enum ScrollAmount {
|
||||
LineUp,
|
||||
LineDown,
|
||||
HalfPageUp,
|
||||
HalfPageDown,
|
||||
PageUp,
|
||||
PageDown,
|
||||
// Scroll N lines (positive is towards the end of the document)
|
||||
Line(f32),
|
||||
// Scroll N pages (positive is towards the end of the document)
|
||||
Page(f32),
|
||||
}
|
||||
|
||||
impl ScrollAmount {
|
||||
@ -24,10 +22,10 @@ impl ScrollAmount {
|
||||
let context_menu = editor.context_menu.as_mut()?;
|
||||
|
||||
match self {
|
||||
Self::LineDown | Self::HalfPageDown => context_menu.select_next(cx),
|
||||
Self::LineUp | Self::HalfPageUp => context_menu.select_prev(cx),
|
||||
Self::PageDown => context_menu.select_last(cx),
|
||||
Self::PageUp => context_menu.select_first(cx),
|
||||
Self::Line(c) if *c > 0. => context_menu.select_next(cx),
|
||||
Self::Line(_) => context_menu.select_prev(cx),
|
||||
Self::Page(c) if *c > 0. => context_menu.select_last(cx),
|
||||
Self::Page(_) => context_menu.select_first(cx),
|
||||
}
|
||||
.then_some(())
|
||||
})
|
||||
@ -36,13 +34,13 @@ impl ScrollAmount {
|
||||
|
||||
pub fn lines(&self, editor: &mut Editor) -> f32 {
|
||||
match self {
|
||||
Self::LineDown => 1.,
|
||||
Self::LineUp => -1.,
|
||||
Self::HalfPageDown => editor.visible_line_count().map(|l| l / 2.).unwrap_or(1.),
|
||||
Self::HalfPageUp => -editor.visible_line_count().map(|l| l / 2.).unwrap_or(1.),
|
||||
// Minus 1. here so that there is a pivot line that stays on the screen
|
||||
Self::PageDown => editor.visible_line_count().unwrap_or(1.) - 1.,
|
||||
Self::PageUp => -editor.visible_line_count().unwrap_or(1.) - 1.,
|
||||
Self::Line(count) => *count,
|
||||
Self::Page(count) => editor
|
||||
.visible_line_count()
|
||||
// subtract one to leave an anchor line
|
||||
// round towards zero (so page-up and page-down are symmetric)
|
||||
.map(|l| ((l - 1.) * count).trunc())
|
||||
.unwrap_or(0.),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,15 +6,16 @@ use std::{
|
||||
|
||||
use crate::json::ToJson;
|
||||
use pathfinder_color::{ColorF, ColorU};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{
|
||||
de::{self, Unexpected},
|
||||
Deserialize, Deserializer,
|
||||
};
|
||||
use serde_json::json;
|
||||
|
||||
#[derive(Clone, Copy, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
#[derive(Clone, Copy, Default, PartialEq, Eq, Hash, PartialOrd, Ord, JsonSchema)]
|
||||
#[repr(transparent)]
|
||||
pub struct Color(ColorU);
|
||||
pub struct Color(#[schemars(with = "String")] ColorU);
|
||||
|
||||
impl Color {
|
||||
pub fn transparent_black() -> Self {
|
||||
|
@ -41,13 +41,7 @@ use collections::HashMap;
|
||||
use core::panic;
|
||||
use json::ToJson;
|
||||
use smallvec::SmallVec;
|
||||
use std::{
|
||||
any::Any,
|
||||
borrow::Cow,
|
||||
marker::PhantomData,
|
||||
mem,
|
||||
ops::{Deref, DerefMut, Range},
|
||||
};
|
||||
use std::{any::Any, borrow::Cow, mem, ops::Range};
|
||||
|
||||
pub trait Element<V: View>: 'static {
|
||||
type LayoutState;
|
||||
@ -567,90 +561,6 @@ impl<V: View> RootElement<V> {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Component<V: View>: 'static {
|
||||
fn render(&self, view: &mut V, cx: &mut ViewContext<V>) -> AnyElement<V>;
|
||||
}
|
||||
|
||||
pub struct ComponentHost<V: View, C: Component<V>> {
|
||||
component: C,
|
||||
view_type: PhantomData<V>,
|
||||
}
|
||||
|
||||
impl<V: View, C: Component<V>> ComponentHost<V, C> {
|
||||
pub fn new(c: C) -> Self {
|
||||
Self {
|
||||
component: c,
|
||||
view_type: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: View, C: Component<V>> Deref for ComponentHost<V, C> {
|
||||
type Target = C;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.component
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: View, C: Component<V>> DerefMut for ComponentHost<V, C> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.component
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: View, C: Component<V>> Element<V> for ComponentHost<V, C> {
|
||||
type LayoutState = AnyElement<V>;
|
||||
type PaintState = ();
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
constraint: SizeConstraint,
|
||||
view: &mut V,
|
||||
cx: &mut LayoutContext<V>,
|
||||
) -> (Vector2F, AnyElement<V>) {
|
||||
let mut element = self.component.render(view, cx);
|
||||
let size = element.layout(constraint, view, cx);
|
||||
(size, element)
|
||||
}
|
||||
|
||||
fn paint(
|
||||
&mut self,
|
||||
scene: &mut SceneBuilder,
|
||||
bounds: RectF,
|
||||
visible_bounds: RectF,
|
||||
element: &mut AnyElement<V>,
|
||||
view: &mut V,
|
||||
cx: &mut ViewContext<V>,
|
||||
) {
|
||||
element.paint(scene, bounds.origin(), visible_bounds, view, cx);
|
||||
}
|
||||
|
||||
fn rect_for_text_range(
|
||||
&self,
|
||||
range_utf16: Range<usize>,
|
||||
_: RectF,
|
||||
_: RectF,
|
||||
element: &AnyElement<V>,
|
||||
_: &(),
|
||||
view: &V,
|
||||
cx: &ViewContext<V>,
|
||||
) -> Option<RectF> {
|
||||
element.rect_for_text_range(range_utf16, view, cx)
|
||||
}
|
||||
|
||||
fn debug(
|
||||
&self,
|
||||
_: RectF,
|
||||
element: &AnyElement<V>,
|
||||
_: &(),
|
||||
view: &V,
|
||||
cx: &ViewContext<V>,
|
||||
) -> serde_json::Value {
|
||||
element.debug(view, cx)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait AnyRootElement {
|
||||
fn layout(
|
||||
&mut self,
|
||||
|
@ -12,10 +12,11 @@ use crate::{
|
||||
scene::{self, Border, CursorRegion, Quad},
|
||||
AnyElement, Element, LayoutContext, SceneBuilder, SizeConstraint, View, ViewContext,
|
||||
};
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use serde_json::json;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, JsonSchema)]
|
||||
pub struct ContainerStyle {
|
||||
#[serde(default)]
|
||||
pub margin: Margin,
|
||||
@ -332,7 +333,7 @@ impl ToJson for ContainerStyle {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
#[derive(Clone, Copy, Debug, Default, JsonSchema)]
|
||||
pub struct Margin {
|
||||
pub top: f32,
|
||||
pub left: f32,
|
||||
@ -359,7 +360,7 @@ impl ToJson for Margin {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
#[derive(Clone, Copy, Debug, Default, JsonSchema)]
|
||||
pub struct Padding {
|
||||
pub top: f32,
|
||||
pub left: f32,
|
||||
@ -486,9 +487,10 @@ impl ToJson for Padding {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, JsonSchema)]
|
||||
pub struct Shadow {
|
||||
#[serde(default, deserialize_with = "deserialize_vec2f")]
|
||||
#[schemars(with = "Vec::<f32>")]
|
||||
offset: Vector2F,
|
||||
#[serde(default)]
|
||||
blur: f32,
|
||||
|
@ -8,6 +8,7 @@ use crate::{
|
||||
scene, Border, Element, ImageData, LayoutContext, SceneBuilder, SizeConstraint, View,
|
||||
ViewContext,
|
||||
};
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use std::{ops::Range, sync::Arc};
|
||||
|
||||
@ -21,7 +22,7 @@ pub struct Image {
|
||||
style: ImageStyle,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Default, Deserialize)]
|
||||
#[derive(Copy, Clone, Default, Deserialize, JsonSchema)]
|
||||
pub struct ImageStyle {
|
||||
#[serde(default)]
|
||||
pub border: Border,
|
||||
|
@ -10,6 +10,7 @@ use crate::{
|
||||
text_layout::{Line, RunStyle},
|
||||
Element, LayoutContext, SceneBuilder, SizeConstraint, View, ViewContext,
|
||||
};
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use serde_json::json;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
@ -20,7 +21,7 @@ pub struct Label {
|
||||
highlight_indices: Vec<usize>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Default)]
|
||||
#[derive(Clone, Debug, Deserialize, Default, JsonSchema)]
|
||||
pub struct LabelStyle {
|
||||
pub text: TextStyle,
|
||||
pub highlight_text: Option<TextStyle>,
|
||||
@ -164,6 +165,7 @@ impl<V: View> Element<V> for Label {
|
||||
_: &mut V,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> Self::PaintState {
|
||||
let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default();
|
||||
line.paint(
|
||||
scene,
|
||||
bounds.origin(),
|
||||
|
@ -1,7 +1,5 @@
|
||||
use std::{borrow::Cow, ops::Range};
|
||||
|
||||
use serde_json::json;
|
||||
|
||||
use super::constrain_size_preserving_aspect_ratio;
|
||||
use crate::json::ToJson;
|
||||
use crate::{
|
||||
color::Color,
|
||||
geometry::{
|
||||
@ -10,6 +8,10 @@ use crate::{
|
||||
},
|
||||
scene, Element, LayoutContext, SceneBuilder, SizeConstraint, View, ViewContext,
|
||||
};
|
||||
use schemars::JsonSchema;
|
||||
use serde_derive::Deserialize;
|
||||
use serde_json::json;
|
||||
use std::{borrow::Cow, ops::Range};
|
||||
|
||||
pub struct Svg {
|
||||
path: Cow<'static, str>,
|
||||
@ -24,6 +26,14 @@ impl Svg {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn for_style<V: View>(style: SvgStyle) -> impl Element<V> {
|
||||
Self::new(style.asset)
|
||||
.with_color(style.color)
|
||||
.constrained()
|
||||
.with_width(style.dimensions.width)
|
||||
.with_height(style.dimensions.height)
|
||||
}
|
||||
|
||||
pub fn with_color(mut self, color: Color) -> Self {
|
||||
self.color = color;
|
||||
self
|
||||
@ -105,9 +115,24 @@ impl<V: View> Element<V> for Svg {
|
||||
}
|
||||
}
|
||||
|
||||
use crate::json::ToJson;
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct SvgStyle {
|
||||
pub color: Color,
|
||||
pub asset: String,
|
||||
pub dimensions: Dimensions,
|
||||
}
|
||||
|
||||
use super::constrain_size_preserving_aspect_ratio;
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct Dimensions {
|
||||
pub width: f32,
|
||||
pub height: f32,
|
||||
}
|
||||
|
||||
impl Dimensions {
|
||||
pub fn to_vec(&self) -> Vector2F {
|
||||
vec2f(self.width, self.height)
|
||||
}
|
||||
}
|
||||
|
||||
fn from_usvg_rect(rect: usvg::Rect) -> RectF {
|
||||
RectF::new(
|
||||
|
@ -9,6 +9,7 @@ use crate::{
|
||||
Action, Axis, ElementStateHandle, LayoutContext, SceneBuilder, SizeConstraint, Task, View,
|
||||
ViewContext,
|
||||
};
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use std::{
|
||||
cell::{Cell, RefCell},
|
||||
@ -33,7 +34,7 @@ struct TooltipState {
|
||||
debounce: RefCell<Option<Task<()>>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct TooltipStyle {
|
||||
#[serde(flatten)]
|
||||
pub container: ContainerStyle,
|
||||
@ -42,7 +43,7 @@ pub struct TooltipStyle {
|
||||
pub max_text_width: Option<f32>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct KeystrokeStyle {
|
||||
#[serde(flatten)]
|
||||
container: ContainerStyle,
|
||||
|
@ -7,13 +7,14 @@ use crate::{
|
||||
use anyhow::{anyhow, Result};
|
||||
use ordered_float::OrderedFloat;
|
||||
use parking_lot::{RwLock, RwLockUpgradableReadGuard};
|
||||
use schemars::JsonSchema;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
ops::{Deref, DerefMut},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, JsonSchema)]
|
||||
pub struct FamilyId(usize);
|
||||
|
||||
struct Family {
|
||||
|
@ -16,7 +16,7 @@ use serde::{de, Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use std::{cell::RefCell, sync::Arc};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, JsonSchema)]
|
||||
pub struct FontId(pub usize);
|
||||
|
||||
pub type GlyphId = u32;
|
||||
@ -59,20 +59,44 @@ pub struct Features {
|
||||
pub zero: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, JsonSchema)]
|
||||
pub struct TextStyle {
|
||||
pub color: Color,
|
||||
pub font_family_name: Arc<str>,
|
||||
pub font_family_id: FamilyId,
|
||||
pub font_id: FontId,
|
||||
pub font_size: f32,
|
||||
#[schemars(with = "PropertiesDef")]
|
||||
pub font_properties: Properties,
|
||||
pub underline: Underline,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, PartialEq)]
|
||||
#[derive(JsonSchema)]
|
||||
#[serde(remote = "Properties")]
|
||||
pub struct PropertiesDef {
|
||||
/// The font style, as defined in CSS.
|
||||
pub style: StyleDef,
|
||||
/// The font weight, as defined in CSS.
|
||||
pub weight: f32,
|
||||
/// The font stretchiness, as defined in CSS.
|
||||
pub stretch: f32,
|
||||
}
|
||||
|
||||
#[derive(JsonSchema)]
|
||||
#[schemars(remote = "Style")]
|
||||
pub enum StyleDef {
|
||||
/// A face that is neither italic not obliqued.
|
||||
Normal,
|
||||
/// A form that is generally cursive in nature.
|
||||
Italic,
|
||||
/// A typically-sloped version of the regular face.
|
||||
Oblique,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, PartialEq, JsonSchema)]
|
||||
pub struct HighlightStyle {
|
||||
pub color: Option<Color>,
|
||||
#[schemars(with = "Option::<f32>")]
|
||||
pub weight: Option<Weight>,
|
||||
pub italic: Option<bool>,
|
||||
pub underline: Option<Underline>,
|
||||
@ -81,9 +105,10 @@ pub struct HighlightStyle {
|
||||
|
||||
impl Eq for HighlightStyle {}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
|
||||
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, JsonSchema)]
|
||||
pub struct Underline {
|
||||
pub color: Option<Color>,
|
||||
#[schemars(with = "f32")]
|
||||
pub thickness: OrderedFloat<f32>,
|
||||
pub squiggly: bool,
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ pub mod color;
|
||||
pub mod json;
|
||||
pub mod keymap_matcher;
|
||||
pub mod platform;
|
||||
pub use gpui_macros::test;
|
||||
pub use gpui_macros::{test, Element};
|
||||
pub use window::{Axis, SizeConstraint, Vector2FExt, WindowContext};
|
||||
|
||||
pub use anyhow;
|
||||
|
@ -25,6 +25,7 @@ use anyhow::{anyhow, bail, Result};
|
||||
use async_task::Runnable;
|
||||
pub use event::*;
|
||||
use postage::oneshot;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use sqlez::{
|
||||
bindable::{Bind, Column, StaticColumnCount},
|
||||
@ -282,7 +283,7 @@ pub enum PromptLevel {
|
||||
Critical,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Deserialize)]
|
||||
#[derive(Copy, Clone, Debug, Deserialize, JsonSchema)]
|
||||
pub enum CursorStyle {
|
||||
Arrow,
|
||||
ResizeLeftRight,
|
||||
|
@ -3,6 +3,7 @@ mod mouse_region;
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
use collections::HashSet;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use serde_json::json;
|
||||
use std::{borrow::Cow, sync::Arc};
|
||||
@ -99,7 +100,7 @@ pub struct Icon {
|
||||
pub color: Color,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Default, Debug)]
|
||||
#[derive(Clone, Copy, Default, Debug, JsonSchema)]
|
||||
pub struct Border {
|
||||
pub width: f32,
|
||||
pub color: Color,
|
||||
|
@ -3,8 +3,8 @@ use proc_macro2::Ident;
|
||||
use quote::{format_ident, quote};
|
||||
use std::mem;
|
||||
use syn::{
|
||||
parse_macro_input, parse_quote, spanned::Spanned as _, AttributeArgs, FnArg, ItemFn, Lit, Meta,
|
||||
NestedMeta, Type,
|
||||
parse_macro_input, parse_quote, spanned::Spanned as _, AttributeArgs, DeriveInput, FnArg,
|
||||
ItemFn, Lit, Meta, NestedMeta, Type,
|
||||
};
|
||||
|
||||
#[proc_macro_attribute]
|
||||
@ -275,3 +275,68 @@ fn parse_bool(literal: &Lit) -> Result<bool, TokenStream> {
|
||||
|
||||
result.map_err(|err| TokenStream::from(err.into_compile_error()))
|
||||
}
|
||||
|
||||
#[proc_macro_derive(Element)]
|
||||
pub fn element_derive(input: TokenStream) -> TokenStream {
|
||||
// Parse the input tokens into a syntax tree
|
||||
let input = parse_macro_input!(input as DeriveInput);
|
||||
|
||||
// The name of the struct/enum
|
||||
let name = input.ident;
|
||||
|
||||
let expanded = quote! {
|
||||
impl<V: gpui::View> gpui::elements::Element<V> for #name {
|
||||
type LayoutState = gpui::elements::AnyElement<V>;
|
||||
type PaintState = ();
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
constraint: gpui::SizeConstraint,
|
||||
view: &mut V,
|
||||
cx: &mut gpui::LayoutContext<V>,
|
||||
) -> (gpui::geometry::vector::Vector2F, gpui::elements::AnyElement<V>) {
|
||||
let mut element = self.render(view, cx);
|
||||
let size = element.layout(constraint, view, cx);
|
||||
(size, element)
|
||||
}
|
||||
|
||||
fn paint(
|
||||
&mut self,
|
||||
scene: &mut gpui::SceneBuilder,
|
||||
bounds: gpui::geometry::rect::RectF,
|
||||
visible_bounds: gpui::geometry::rect::RectF,
|
||||
element: &mut gpui::elements::AnyElement<V>,
|
||||
view: &mut V,
|
||||
cx: &mut gpui::ViewContext<V>,
|
||||
) {
|
||||
element.paint(scene, bounds.origin(), visible_bounds, view, cx);
|
||||
}
|
||||
|
||||
fn rect_for_text_range(
|
||||
&self,
|
||||
range_utf16: std::ops::Range<usize>,
|
||||
_: gpui::geometry::rect::RectF,
|
||||
_: gpui::geometry::rect::RectF,
|
||||
element: &gpui::elements::AnyElement<V>,
|
||||
_: &(),
|
||||
view: &V,
|
||||
cx: &gpui::ViewContext<V>,
|
||||
) -> Option<gpui::geometry::rect::RectF> {
|
||||
element.rect_for_text_range(range_utf16, view, cx)
|
||||
}
|
||||
|
||||
fn debug(
|
||||
&self,
|
||||
_: gpui::geometry::rect::RectF,
|
||||
element: &gpui::elements::AnyElement<V>,
|
||||
_: &(),
|
||||
view: &V,
|
||||
cx: &gpui::ViewContext<V>,
|
||||
) -> serde_json::Value {
|
||||
element.debug(view, cx)
|
||||
}
|
||||
}
|
||||
};
|
||||
// Return generated code
|
||||
TokenStream::from(expanded)
|
||||
}
|
||||
|
@ -153,6 +153,7 @@ pub fn init(cx: &mut AppContext) {
|
||||
);
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Event {
|
||||
OpenedEntry {
|
||||
entry_id: ProjectEntryId,
|
||||
|
@ -259,7 +259,11 @@ impl BufferSearchBar {
|
||||
}
|
||||
}
|
||||
|
||||
fn dismiss(&mut self, _: &Dismiss, cx: &mut ViewContext<Self>) {
|
||||
pub fn is_dismissed(&self) -> bool {
|
||||
self.dismissed
|
||||
}
|
||||
|
||||
pub fn dismiss(&mut self, _: &Dismiss, cx: &mut ViewContext<Self>) {
|
||||
self.dismissed = true;
|
||||
for searchable_item in self.seachable_items_with_matches.keys() {
|
||||
if let Some(searchable_item) =
|
||||
@ -275,7 +279,7 @@ impl BufferSearchBar {
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
fn show(&mut self, focus: bool, suggest_query: bool, cx: &mut ViewContext<Self>) -> bool {
|
||||
pub fn show(&mut self, focus: bool, suggest_query: bool, cx: &mut ViewContext<Self>) -> bool {
|
||||
let searchable_item = if let Some(searchable_item) = &self.active_searchable_item {
|
||||
SearchableItemHandle::boxed_clone(searchable_item.as_ref())
|
||||
} else {
|
||||
@ -484,7 +488,7 @@ impl BufferSearchBar {
|
||||
self.select_match(Direction::Prev, cx);
|
||||
}
|
||||
|
||||
fn select_match(&mut self, direction: Direction, cx: &mut ViewContext<Self>) {
|
||||
pub fn select_match(&mut self, direction: Direction, cx: &mut ViewContext<Self>) {
|
||||
if let Some(index) = self.active_match_index {
|
||||
if let Some(searchable_item) = self.active_searchable_item.as_ref() {
|
||||
if let Some(matches) = self
|
||||
|
@ -25,6 +25,7 @@ pub fn init(cx: &mut AppContext) {
|
||||
cx.add_action(TerminalPanel::new_terminal);
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Event {
|
||||
Close,
|
||||
DockPositionChanged,
|
||||
|
@ -4,15 +4,16 @@ pub mod ui;
|
||||
|
||||
use gpui::{
|
||||
color::Color,
|
||||
elements::{ContainerStyle, ImageStyle, LabelStyle, Shadow, TooltipStyle},
|
||||
elements::{ContainerStyle, ImageStyle, LabelStyle, Shadow, SvgStyle, TooltipStyle},
|
||||
fonts::{HighlightStyle, TextStyle},
|
||||
platform, AppContext, AssetSource, Border, MouseState,
|
||||
};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{de::DeserializeOwned, Deserialize};
|
||||
use serde_json::Value;
|
||||
use settings::SettingsStore;
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
use ui::{ButtonStyle, CheckboxStyle, IconStyle, ModalStyle, SvgStyle};
|
||||
use ui::{ButtonStyle, CheckboxStyle, IconStyle, ModalStyle};
|
||||
|
||||
pub use theme_registry::*;
|
||||
pub use theme_settings::*;
|
||||
@ -36,7 +37,7 @@ pub fn init(source: impl AssetSource, cx: &mut AppContext) {
|
||||
.detach();
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default)]
|
||||
#[derive(Deserialize, Default, JsonSchema)]
|
||||
pub struct Theme {
|
||||
#[serde(default)]
|
||||
pub meta: ThemeMeta,
|
||||
@ -68,7 +69,7 @@ pub struct Theme {
|
||||
pub titlebar: UserMenu,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default, Clone)]
|
||||
#[derive(Deserialize, Default, Clone, JsonSchema)]
|
||||
pub struct ThemeMeta {
|
||||
#[serde(skip_deserializing)]
|
||||
pub id: usize,
|
||||
@ -76,7 +77,7 @@ pub struct ThemeMeta {
|
||||
pub is_light: bool,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default)]
|
||||
#[derive(Deserialize, Default, JsonSchema)]
|
||||
pub struct Workspace {
|
||||
pub background: Color,
|
||||
pub blank_pane: BlankPaneStyle,
|
||||
@ -103,7 +104,7 @@ pub struct Workspace {
|
||||
pub drop_target_overlay_color: Color,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct BlankPaneStyle {
|
||||
pub logo: SvgStyle,
|
||||
pub logo_shadow: SvgStyle,
|
||||
@ -113,7 +114,7 @@ pub struct BlankPaneStyle {
|
||||
pub keyboard_hint_width: f32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct Titlebar {
|
||||
#[serde(flatten)]
|
||||
pub container: ContainerStyle,
|
||||
@ -141,17 +142,18 @@ pub struct Titlebar {
|
||||
pub toggle_contacts_badge: ContainerStyle,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct UserMenu {
|
||||
pub user_menu_button: UserMenuButton,
|
||||
}
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct UserMenuButton {
|
||||
pub user_menu: Toggleable<Interactive<Icon>>,
|
||||
pub avatar: AvatarStyle,
|
||||
pub icon: Icon,
|
||||
}
|
||||
#[derive(Copy, Clone, Deserialize, Default)]
|
||||
|
||||
#[derive(Copy, Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct AvatarStyle {
|
||||
#[serde(flatten)]
|
||||
pub image: ImageStyle,
|
||||
@ -159,14 +161,14 @@ pub struct AvatarStyle {
|
||||
pub outer_corner_radius: f32,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default, Clone)]
|
||||
#[derive(Deserialize, Default, Clone, JsonSchema)]
|
||||
pub struct Copilot {
|
||||
pub out_link_icon: Interactive<IconStyle>,
|
||||
pub modal: ModalStyle,
|
||||
pub auth: CopilotAuth,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default, Clone)]
|
||||
#[derive(Deserialize, Default, Clone, JsonSchema)]
|
||||
pub struct CopilotAuth {
|
||||
pub content_width: f32,
|
||||
pub prompting: CopilotAuthPrompting,
|
||||
@ -176,14 +178,14 @@ pub struct CopilotAuth {
|
||||
pub header: IconStyle,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default, Clone)]
|
||||
#[derive(Deserialize, Default, Clone, JsonSchema)]
|
||||
pub struct CopilotAuthPrompting {
|
||||
pub subheading: ContainedText,
|
||||
pub hint: ContainedText,
|
||||
pub device_code: DeviceCode,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default, Clone)]
|
||||
#[derive(Deserialize, Default, Clone, JsonSchema)]
|
||||
pub struct DeviceCode {
|
||||
pub text: TextStyle,
|
||||
pub cta: ButtonStyle,
|
||||
@ -193,19 +195,19 @@ pub struct DeviceCode {
|
||||
pub right_container: Interactive<ContainerStyle>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default, Clone)]
|
||||
#[derive(Deserialize, Default, Clone, JsonSchema)]
|
||||
pub struct CopilotAuthNotAuthorized {
|
||||
pub subheading: ContainedText,
|
||||
pub warning: ContainedText,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default, Clone)]
|
||||
#[derive(Deserialize, Default, Clone, JsonSchema)]
|
||||
pub struct CopilotAuthAuthorized {
|
||||
pub subheading: ContainedText,
|
||||
pub hint: ContainedText,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default)]
|
||||
#[derive(Deserialize, Default, JsonSchema)]
|
||||
pub struct ContactsPopover {
|
||||
#[serde(flatten)]
|
||||
pub container: ContainerStyle,
|
||||
@ -213,7 +215,7 @@ pub struct ContactsPopover {
|
||||
pub width: f32,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default)]
|
||||
#[derive(Deserialize, Default, JsonSchema)]
|
||||
pub struct ContactList {
|
||||
pub user_query_editor: FieldEditor,
|
||||
pub user_query_editor_height: f32,
|
||||
@ -235,7 +237,7 @@ pub struct ContactList {
|
||||
pub calling_indicator: ContainedText,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default)]
|
||||
#[derive(Deserialize, Default, JsonSchema)]
|
||||
pub struct ProjectRow {
|
||||
#[serde(flatten)]
|
||||
pub container: ContainerStyle,
|
||||
@ -243,13 +245,13 @@ pub struct ProjectRow {
|
||||
pub name: ContainedText,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default, Clone, Copy)]
|
||||
#[derive(Deserialize, Default, Clone, Copy, JsonSchema)]
|
||||
pub struct TreeBranch {
|
||||
pub width: f32,
|
||||
pub color: Color,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default)]
|
||||
#[derive(Deserialize, Default, JsonSchema)]
|
||||
pub struct ContactFinder {
|
||||
pub picker: Picker,
|
||||
pub row_height: f32,
|
||||
@ -259,7 +261,7 @@ pub struct ContactFinder {
|
||||
pub disabled_contact_button: IconButton,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default)]
|
||||
#[derive(Deserialize, Default, JsonSchema)]
|
||||
pub struct DropdownMenu {
|
||||
#[serde(flatten)]
|
||||
pub container: ContainerStyle,
|
||||
@ -269,7 +271,7 @@ pub struct DropdownMenu {
|
||||
pub row_height: f32,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default)]
|
||||
#[derive(Deserialize, Default, JsonSchema)]
|
||||
pub struct DropdownMenuItem {
|
||||
#[serde(flatten)]
|
||||
pub container: ContainerStyle,
|
||||
@ -280,7 +282,7 @@ pub struct DropdownMenuItem {
|
||||
pub secondary_text_spacing: f32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct TabBar {
|
||||
#[serde(flatten)]
|
||||
pub container: ContainerStyle,
|
||||
@ -308,13 +310,13 @@ impl TabBar {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct TabStyles {
|
||||
pub active_tab: Tab,
|
||||
pub inactive_tab: Tab,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct AvatarRibbon {
|
||||
#[serde(flatten)]
|
||||
pub container: ContainerStyle,
|
||||
@ -322,7 +324,7 @@ pub struct AvatarRibbon {
|
||||
pub height: f32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct OfflineIcon {
|
||||
#[serde(flatten)]
|
||||
pub container: ContainerStyle,
|
||||
@ -330,7 +332,7 @@ pub struct OfflineIcon {
|
||||
pub color: Color,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct Tab {
|
||||
pub height: f32,
|
||||
#[serde(flatten)]
|
||||
@ -347,7 +349,7 @@ pub struct Tab {
|
||||
pub icon_conflict: Color,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct Toolbar {
|
||||
#[serde(flatten)]
|
||||
pub container: ContainerStyle,
|
||||
@ -356,14 +358,14 @@ pub struct Toolbar {
|
||||
pub nav_button: Interactive<IconButton>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct Notifications {
|
||||
#[serde(flatten)]
|
||||
pub container: ContainerStyle,
|
||||
pub width: f32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct Search {
|
||||
#[serde(flatten)]
|
||||
pub container: ContainerStyle,
|
||||
@ -380,7 +382,7 @@ pub struct Search {
|
||||
pub dismiss_button: Interactive<IconButton>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct FindEditor {
|
||||
#[serde(flatten)]
|
||||
pub input: FieldEditor,
|
||||
@ -388,7 +390,7 @@ pub struct FindEditor {
|
||||
pub max_width: f32,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default)]
|
||||
#[derive(Deserialize, Default, JsonSchema)]
|
||||
pub struct StatusBar {
|
||||
#[serde(flatten)]
|
||||
pub container: ContainerStyle,
|
||||
@ -404,7 +406,7 @@ pub struct StatusBar {
|
||||
pub diagnostic_message: Interactive<ContainedText>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default)]
|
||||
#[derive(Deserialize, Default, JsonSchema)]
|
||||
pub struct StatusBarPanelButtons {
|
||||
pub group_left: ContainerStyle,
|
||||
pub group_bottom: ContainerStyle,
|
||||
@ -412,7 +414,7 @@ pub struct StatusBarPanelButtons {
|
||||
pub button: Toggleable<Interactive<PanelButton>>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default)]
|
||||
#[derive(Deserialize, Default, JsonSchema)]
|
||||
pub struct StatusBarDiagnosticSummary {
|
||||
pub container_ok: ContainerStyle,
|
||||
pub container_warning: ContainerStyle,
|
||||
@ -427,7 +429,7 @@ pub struct StatusBarDiagnosticSummary {
|
||||
pub summary_spacing: f32,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default)]
|
||||
#[derive(Deserialize, Default, JsonSchema)]
|
||||
pub struct StatusBarLspStatus {
|
||||
#[serde(flatten)]
|
||||
pub container: ContainerStyle,
|
||||
@ -438,14 +440,14 @@ pub struct StatusBarLspStatus {
|
||||
pub message: TextStyle,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default)]
|
||||
#[derive(Deserialize, Default, JsonSchema)]
|
||||
pub struct Dock {
|
||||
pub left: ContainerStyle,
|
||||
pub bottom: ContainerStyle,
|
||||
pub right: ContainerStyle,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct PanelButton {
|
||||
#[serde(flatten)]
|
||||
pub container: ContainerStyle,
|
||||
@ -454,7 +456,7 @@ pub struct PanelButton {
|
||||
pub label: ContainedText,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default)]
|
||||
#[derive(Deserialize, Default, JsonSchema)]
|
||||
pub struct ProjectPanel {
|
||||
#[serde(flatten)]
|
||||
pub container: ContainerStyle,
|
||||
@ -467,7 +469,7 @@ pub struct ProjectPanel {
|
||||
pub open_project_button: Interactive<ContainedText>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Default)]
|
||||
#[derive(Clone, Debug, Deserialize, Default, JsonSchema)]
|
||||
pub struct ProjectPanelEntry {
|
||||
pub height: f32,
|
||||
#[serde(flatten)]
|
||||
@ -479,19 +481,19 @@ pub struct ProjectPanelEntry {
|
||||
pub status: EntryStatus,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Default)]
|
||||
#[derive(Clone, Debug, Deserialize, Default, JsonSchema)]
|
||||
pub struct EntryStatus {
|
||||
pub git: GitProjectStatus,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Default)]
|
||||
#[derive(Clone, Debug, Deserialize, Default, JsonSchema)]
|
||||
pub struct GitProjectStatus {
|
||||
pub modified: Color,
|
||||
pub inserted: Color,
|
||||
pub conflict: Color,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Default)]
|
||||
#[derive(Clone, Debug, Deserialize, Default, JsonSchema)]
|
||||
pub struct ContextMenu {
|
||||
#[serde(flatten)]
|
||||
pub container: ContainerStyle,
|
||||
@ -500,7 +502,7 @@ pub struct ContextMenu {
|
||||
pub separator: ContainerStyle,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Default)]
|
||||
#[derive(Clone, Debug, Deserialize, Default, JsonSchema)]
|
||||
pub struct ContextMenuItem {
|
||||
#[serde(flatten)]
|
||||
pub container: ContainerStyle,
|
||||
@ -510,13 +512,13 @@ pub struct ContextMenuItem {
|
||||
pub icon_spacing: f32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Default)]
|
||||
#[derive(Debug, Deserialize, Default, JsonSchema)]
|
||||
pub struct CommandPalette {
|
||||
pub key: Toggleable<ContainedLabel>,
|
||||
pub keystroke_spacing: f32,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default)]
|
||||
#[derive(Deserialize, Default, JsonSchema)]
|
||||
pub struct InviteLink {
|
||||
#[serde(flatten)]
|
||||
pub container: ContainerStyle,
|
||||
@ -525,7 +527,7 @@ pub struct InviteLink {
|
||||
pub icon: Icon,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Clone, Copy, Default)]
|
||||
#[derive(Deserialize, Clone, Copy, Default, JsonSchema)]
|
||||
pub struct Icon {
|
||||
#[serde(flatten)]
|
||||
pub container: ContainerStyle,
|
||||
@ -533,7 +535,7 @@ pub struct Icon {
|
||||
pub width: f32,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Clone, Copy, Default)]
|
||||
#[derive(Deserialize, Clone, Copy, Default, JsonSchema)]
|
||||
pub struct IconButton {
|
||||
#[serde(flatten)]
|
||||
pub container: ContainerStyle,
|
||||
@ -542,7 +544,7 @@ pub struct IconButton {
|
||||
pub button_width: f32,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default)]
|
||||
#[derive(Deserialize, Default, JsonSchema)]
|
||||
pub struct ChatMessage {
|
||||
#[serde(flatten)]
|
||||
pub container: ContainerStyle,
|
||||
@ -551,7 +553,7 @@ pub struct ChatMessage {
|
||||
pub timestamp: ContainedText,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default)]
|
||||
#[derive(Deserialize, Default, JsonSchema)]
|
||||
pub struct ChannelSelect {
|
||||
#[serde(flatten)]
|
||||
pub container: ContainerStyle,
|
||||
@ -563,7 +565,7 @@ pub struct ChannelSelect {
|
||||
pub menu: ContainerStyle,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default)]
|
||||
#[derive(Deserialize, Default, JsonSchema)]
|
||||
pub struct ChannelName {
|
||||
#[serde(flatten)]
|
||||
pub container: ContainerStyle,
|
||||
@ -571,7 +573,7 @@ pub struct ChannelName {
|
||||
pub name: TextStyle,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct Picker {
|
||||
#[serde(flatten)]
|
||||
pub container: ContainerStyle,
|
||||
@ -582,7 +584,7 @@ pub struct Picker {
|
||||
pub item: Toggleable<Interactive<ContainedLabel>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Default)]
|
||||
#[derive(Clone, Debug, Deserialize, Default, JsonSchema)]
|
||||
pub struct ContainedText {
|
||||
#[serde(flatten)]
|
||||
pub container: ContainerStyle,
|
||||
@ -590,7 +592,7 @@ pub struct ContainedText {
|
||||
pub text: TextStyle,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Default)]
|
||||
#[derive(Clone, Debug, Deserialize, Default, JsonSchema)]
|
||||
pub struct ContainedLabel {
|
||||
#[serde(flatten)]
|
||||
pub container: ContainerStyle,
|
||||
@ -598,7 +600,7 @@ pub struct ContainedLabel {
|
||||
pub label: LabelStyle,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct ProjectDiagnostics {
|
||||
#[serde(flatten)]
|
||||
pub container: ContainerStyle,
|
||||
@ -608,7 +610,7 @@ pub struct ProjectDiagnostics {
|
||||
pub tab_summary_spacing: f32,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default)]
|
||||
#[derive(Deserialize, Default, JsonSchema)]
|
||||
pub struct ContactNotification {
|
||||
pub header_avatar: ImageStyle,
|
||||
pub header_message: ContainedText,
|
||||
@ -618,21 +620,21 @@ pub struct ContactNotification {
|
||||
pub dismiss_button: Interactive<IconButton>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default)]
|
||||
#[derive(Deserialize, Default, JsonSchema)]
|
||||
pub struct UpdateNotification {
|
||||
pub message: ContainedText,
|
||||
pub action_message: Interactive<ContainedText>,
|
||||
pub dismiss_button: Interactive<IconButton>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default)]
|
||||
#[derive(Deserialize, Default, JsonSchema)]
|
||||
pub struct MessageNotification {
|
||||
pub message: ContainedText,
|
||||
pub action_message: Interactive<ContainedText>,
|
||||
pub dismiss_button: Interactive<IconButton>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default)]
|
||||
#[derive(Deserialize, Default, JsonSchema)]
|
||||
pub struct ProjectSharedNotification {
|
||||
pub window_height: f32,
|
||||
pub window_width: f32,
|
||||
@ -649,7 +651,7 @@ pub struct ProjectSharedNotification {
|
||||
pub dismiss_button: ContainedText,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default)]
|
||||
#[derive(Deserialize, Default, JsonSchema)]
|
||||
pub struct IncomingCallNotification {
|
||||
pub window_height: f32,
|
||||
pub window_width: f32,
|
||||
@ -666,7 +668,7 @@ pub struct IncomingCallNotification {
|
||||
pub decline_button: ContainedText,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct Editor {
|
||||
pub text_color: Color,
|
||||
#[serde(default)]
|
||||
@ -707,7 +709,7 @@ pub struct Editor {
|
||||
pub whitespace: Color,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct Scrollbar {
|
||||
pub track: ContainerStyle,
|
||||
pub thumb: ContainerStyle,
|
||||
@ -716,14 +718,14 @@ pub struct Scrollbar {
|
||||
pub git: GitDiffColors,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct GitDiffColors {
|
||||
pub inserted: Color,
|
||||
pub modified: Color,
|
||||
pub deleted: Color,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct DiagnosticPathHeader {
|
||||
#[serde(flatten)]
|
||||
pub container: ContainerStyle,
|
||||
@ -732,7 +734,7 @@ pub struct DiagnosticPathHeader {
|
||||
pub text_scale_factor: f32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct DiagnosticHeader {
|
||||
#[serde(flatten)]
|
||||
pub container: ContainerStyle,
|
||||
@ -743,7 +745,7 @@ pub struct DiagnosticHeader {
|
||||
pub icon_width_factor: f32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct DiagnosticStyle {
|
||||
pub message: LabelStyle,
|
||||
#[serde(default)]
|
||||
@ -751,7 +753,7 @@ pub struct DiagnosticStyle {
|
||||
pub text_scale_factor: f32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct AutocompleteStyle {
|
||||
#[serde(flatten)]
|
||||
pub container: ContainerStyle,
|
||||
@ -761,13 +763,13 @@ pub struct AutocompleteStyle {
|
||||
pub match_highlight: HighlightStyle,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Default, Deserialize)]
|
||||
#[derive(Clone, Copy, Default, Deserialize, JsonSchema)]
|
||||
pub struct SelectionStyle {
|
||||
pub cursor: Color,
|
||||
pub selection: Color,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct FieldEditor {
|
||||
#[serde(flatten)]
|
||||
pub container: ContainerStyle,
|
||||
@ -777,19 +779,19 @@ pub struct FieldEditor {
|
||||
pub selection: SelectionStyle,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct InteractiveColor {
|
||||
pub color: Color,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct CodeActions {
|
||||
#[serde(default)]
|
||||
pub indicator: Toggleable<Interactive<InteractiveColor>>,
|
||||
pub vertical_scale: f32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct Folds {
|
||||
pub indicator: Toggleable<Interactive<InteractiveColor>>,
|
||||
pub ellipses: FoldEllipses,
|
||||
@ -799,14 +801,14 @@ pub struct Folds {
|
||||
pub foldable_icon: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct FoldEllipses {
|
||||
pub text_color: Color,
|
||||
pub background: Interactive<InteractiveColor>,
|
||||
pub corner_radius_factor: f32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct DiffStyle {
|
||||
pub inserted: Color,
|
||||
pub modified: Color,
|
||||
@ -816,7 +818,7 @@ pub struct DiffStyle {
|
||||
pub corner_radius: f32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
#[derive(Debug, Default, Clone, Copy, JsonSchema)]
|
||||
pub struct Interactive<T> {
|
||||
pub default: T,
|
||||
pub hovered: Option<T>,
|
||||
@ -824,7 +826,7 @@ pub struct Interactive<T> {
|
||||
pub disabled: Option<T>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, JsonSchema)]
|
||||
pub struct Toggleable<T> {
|
||||
active: T,
|
||||
inactive: T,
|
||||
@ -923,7 +925,7 @@ impl Editor {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[derive(Default, JsonSchema)]
|
||||
pub struct SyntaxTheme {
|
||||
pub highlights: Vec<(String, HighlightStyle)>,
|
||||
}
|
||||
@ -957,7 +959,7 @@ impl<'de> Deserialize<'de> for SyntaxTheme {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct HoverPopover {
|
||||
pub container: ContainerStyle,
|
||||
pub info_container: ContainerStyle,
|
||||
@ -969,7 +971,7 @@ pub struct HoverPopover {
|
||||
pub highlight: Color,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct TerminalStyle {
|
||||
pub black: Color,
|
||||
pub red: Color,
|
||||
@ -1003,24 +1005,39 @@ pub struct TerminalStyle {
|
||||
pub dim_foreground: Color,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct AssistantStyle {
|
||||
pub container: ContainerStyle,
|
||||
pub header: ContainerStyle,
|
||||
pub hamburger_button: Interactive<IconStyle>,
|
||||
pub split_button: Interactive<IconStyle>,
|
||||
pub assist_button: Interactive<IconStyle>,
|
||||
pub quote_button: Interactive<IconStyle>,
|
||||
pub zoom_in_button: Interactive<IconStyle>,
|
||||
pub zoom_out_button: Interactive<IconStyle>,
|
||||
pub plus_button: Interactive<IconStyle>,
|
||||
pub title: ContainedText,
|
||||
pub message_header: ContainerStyle,
|
||||
pub sent_at: ContainedText,
|
||||
pub user_sender: Interactive<ContainedText>,
|
||||
pub assistant_sender: Interactive<ContainedText>,
|
||||
pub system_sender: Interactive<ContainedText>,
|
||||
pub model_info_container: ContainerStyle,
|
||||
pub model: Interactive<ContainedText>,
|
||||
pub remaining_tokens: ContainedText,
|
||||
pub no_remaining_tokens: ContainedText,
|
||||
pub error_icon: Icon,
|
||||
pub api_key_editor: FieldEditor,
|
||||
pub api_key_prompt: ContainedText,
|
||||
pub saved_conversation: SavedConversation,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct SavedConversation {
|
||||
pub container: Interactive<ContainerStyle>,
|
||||
pub saved_at: ContainedText,
|
||||
pub title: ContainedText,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct FeedbackStyle {
|
||||
pub submit_button: Interactive<ContainedText>,
|
||||
pub button_margin: f32,
|
||||
@ -1029,7 +1046,7 @@ pub struct FeedbackStyle {
|
||||
pub link_text_hover: ContainedText,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct WelcomeStyle {
|
||||
pub page_width: f32,
|
||||
pub logo: SvgStyle,
|
||||
@ -1043,7 +1060,7 @@ pub struct WelcomeStyle {
|
||||
pub checkbox_group: ContainerStyle,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct ColorScheme {
|
||||
pub name: String,
|
||||
pub is_light: bool,
|
||||
@ -1058,13 +1075,13 @@ pub struct ColorScheme {
|
||||
pub players: Vec<Player>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct Player {
|
||||
pub cursor: Color,
|
||||
pub selection: Color,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct RampSet {
|
||||
pub neutral: Vec<Color>,
|
||||
pub red: Vec<Color>,
|
||||
@ -1077,7 +1094,7 @@ pub struct RampSet {
|
||||
pub magenta: Vec<Color>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct Layer {
|
||||
pub base: StyleSet,
|
||||
pub variant: StyleSet,
|
||||
@ -1088,7 +1105,7 @@ pub struct Layer {
|
||||
pub negative: StyleSet,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct StyleSet {
|
||||
pub default: Style,
|
||||
pub active: Style,
|
||||
@ -1098,7 +1115,7 @@ pub struct StyleSet {
|
||||
pub inverted: Style,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct Style {
|
||||
pub background: Color,
|
||||
pub border: Color,
|
||||
|
@ -14,12 +14,13 @@ use util::ResultExt as _;
|
||||
|
||||
const MIN_FONT_SIZE: f32 = 6.0;
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, JsonSchema)]
|
||||
pub struct ThemeSettings {
|
||||
pub buffer_font_family_name: String,
|
||||
pub buffer_font_features: fonts::Features,
|
||||
pub buffer_font_family: FamilyId,
|
||||
pub(crate) buffer_font_size: f32,
|
||||
#[serde(skip)]
|
||||
pub theme: Arc<Theme>,
|
||||
}
|
||||
|
||||
|
@ -1,23 +1,23 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use gpui::{
|
||||
color::Color,
|
||||
elements::{
|
||||
ConstrainedBox, Container, ContainerStyle, Empty, Flex, KeystrokeLabel, Label,
|
||||
MouseEventHandler, ParentElement, Stack, Svg,
|
||||
ConstrainedBox, Container, ContainerStyle, Dimensions, Empty, Flex, KeystrokeLabel, Label,
|
||||
MouseEventHandler, ParentElement, Stack, Svg, SvgStyle,
|
||||
},
|
||||
fonts::TextStyle,
|
||||
geometry::vector::{vec2f, Vector2F},
|
||||
geometry::vector::Vector2F,
|
||||
platform,
|
||||
platform::MouseButton,
|
||||
scene::MouseClick,
|
||||
Action, Element, EventContext, MouseState, View, ViewContext,
|
||||
};
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::{ContainedText, Interactive};
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct CheckboxStyle {
|
||||
pub icon: SvgStyle,
|
||||
pub label: ContainedText,
|
||||
@ -93,25 +93,6 @@ where
|
||||
.with_cursor_style(platform::CursorStyle::PointingHand)
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
pub struct SvgStyle {
|
||||
pub color: Color,
|
||||
pub asset: String,
|
||||
pub dimensions: Dimensions,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
pub struct Dimensions {
|
||||
pub width: f32,
|
||||
pub height: f32,
|
||||
}
|
||||
|
||||
impl Dimensions {
|
||||
pub fn to_vec(&self) -> Vector2F {
|
||||
vec2f(self.width, self.height)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn svg<V: View>(style: &SvgStyle) -> ConstrainedBox<V> {
|
||||
Svg::new(style.asset.clone())
|
||||
.with_color(style.color)
|
||||
@ -120,10 +101,10 @@ pub fn svg<V: View>(style: &SvgStyle) -> ConstrainedBox<V> {
|
||||
.with_height(style.dimensions.height)
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct IconStyle {
|
||||
icon: SvgStyle,
|
||||
container: ContainerStyle,
|
||||
pub icon: SvgStyle,
|
||||
pub container: ContainerStyle,
|
||||
}
|
||||
|
||||
pub fn icon<V: View>(style: &IconStyle) -> Container<V> {
|
||||
@ -182,7 +163,7 @@ where
|
||||
.with_cursor_style(platform::CursorStyle::PointingHand)
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Default)]
|
||||
#[derive(Clone, Deserialize, Default, JsonSchema)]
|
||||
pub struct ModalStyle {
|
||||
close_icon: Interactive<IconStyle>,
|
||||
container: ContainerStyle,
|
||||
|
@ -5,6 +5,7 @@ use serde::{Deserialize, Serialize};
|
||||
lazy_static::lazy_static! {
|
||||
pub static ref HOME: PathBuf = dirs::home_dir().expect("failed to determine home directory");
|
||||
pub static ref CONFIG_DIR: PathBuf = HOME.join(".config").join("zed");
|
||||
pub static ref CONVERSATIONS_DIR: PathBuf = HOME.join(".config/zed/conversations");
|
||||
pub static ref LOGS_DIR: PathBuf = HOME.join("Library/Logs/Zed");
|
||||
pub static ref SUPPORT_DIR: PathBuf = HOME.join("Library/Application Support/Zed");
|
||||
pub static ref LANGUAGES_DIR: PathBuf = HOME.join("Library/Application Support/Zed/languages");
|
||||
|
@ -209,8 +209,9 @@ impl Motion {
|
||||
map: &DisplaySnapshot,
|
||||
point: DisplayPoint,
|
||||
goal: SelectionGoal,
|
||||
times: usize,
|
||||
maybe_times: Option<usize>,
|
||||
) -> Option<(DisplayPoint, SelectionGoal)> {
|
||||
let times = maybe_times.unwrap_or(1);
|
||||
use Motion::*;
|
||||
let infallible = self.infallible();
|
||||
let (new_point, goal) = match self {
|
||||
@ -236,7 +237,10 @@ impl Motion {
|
||||
EndOfLine => (end_of_line(map, point), SelectionGoal::None),
|
||||
CurrentLine => (end_of_line(map, point), SelectionGoal::None),
|
||||
StartOfDocument => (start_of_document(map, point, times), SelectionGoal::None),
|
||||
EndOfDocument => (end_of_document(map, point, times), SelectionGoal::None),
|
||||
EndOfDocument => (
|
||||
end_of_document(map, point, maybe_times),
|
||||
SelectionGoal::None,
|
||||
),
|
||||
Matching => (matching(map, point), SelectionGoal::None),
|
||||
FindForward { before, text } => (
|
||||
find_forward(map, point, *before, text.clone(), times),
|
||||
@ -257,7 +261,7 @@ impl Motion {
|
||||
&self,
|
||||
map: &DisplaySnapshot,
|
||||
selection: &mut Selection<DisplayPoint>,
|
||||
times: usize,
|
||||
times: Option<usize>,
|
||||
expand_to_surrounding_newline: bool,
|
||||
) -> bool {
|
||||
if let Some((new_head, goal)) =
|
||||
@ -473,14 +477,19 @@ fn start_of_document(map: &DisplaySnapshot, point: DisplayPoint, line: usize) ->
|
||||
map.clip_point(new_point, Bias::Left)
|
||||
}
|
||||
|
||||
fn end_of_document(map: &DisplaySnapshot, point: DisplayPoint, line: usize) -> DisplayPoint {
|
||||
let mut new_point = if line == 1 {
|
||||
map.max_point()
|
||||
fn end_of_document(
|
||||
map: &DisplaySnapshot,
|
||||
point: DisplayPoint,
|
||||
line: Option<usize>,
|
||||
) -> DisplayPoint {
|
||||
let new_row = if let Some(line) = line {
|
||||
(line - 1) as u32
|
||||
} else {
|
||||
Point::new((line - 1) as u32, 0).to_display_point(map)
|
||||
map.max_buffer_row()
|
||||
};
|
||||
*new_point.column_mut() = point.column();
|
||||
map.clip_point(new_point, Bias::Left)
|
||||
|
||||
let new_point = Point::new(new_row, point.column());
|
||||
map.clip_point(new_point.to_display_point(map), Bias::Left)
|
||||
}
|
||||
|
||||
fn matching(map: &DisplaySnapshot, display_point: DisplayPoint) -> DisplayPoint {
|
||||
|
@ -1,8 +1,11 @@
|
||||
mod case;
|
||||
mod change;
|
||||
mod delete;
|
||||
mod scroll;
|
||||
mod substitute;
|
||||
mod yank;
|
||||
|
||||
use std::{borrow::Cow, cmp::Ordering, sync::Arc};
|
||||
use std::{borrow::Cow, sync::Arc};
|
||||
|
||||
use crate::{
|
||||
motion::Motion,
|
||||
@ -12,25 +15,22 @@ use crate::{
|
||||
};
|
||||
use collections::{HashMap, HashSet};
|
||||
use editor::{
|
||||
display_map::ToDisplayPoint,
|
||||
scroll::{autoscroll::Autoscroll, scroll_amount::ScrollAmount},
|
||||
Anchor, Bias, ClipboardSelection, DisplayPoint, Editor,
|
||||
display_map::ToDisplayPoint, scroll::autoscroll::Autoscroll, Anchor, Bias, ClipboardSelection,
|
||||
DisplayPoint,
|
||||
};
|
||||
use gpui::{actions, impl_actions, AppContext, ViewContext, WindowContext};
|
||||
use gpui::{actions, AppContext, ViewContext, WindowContext};
|
||||
use language::{AutoindentMode, Point, SelectionGoal};
|
||||
use log::error;
|
||||
use serde::Deserialize;
|
||||
use workspace::Workspace;
|
||||
|
||||
use self::{
|
||||
case::change_case,
|
||||
change::{change_motion, change_object},
|
||||
delete::{delete_motion, delete_object},
|
||||
substitute::substitute,
|
||||
yank::{yank_motion, yank_object},
|
||||
};
|
||||
|
||||
#[derive(Clone, PartialEq, Deserialize)]
|
||||
struct Scroll(ScrollAmount);
|
||||
|
||||
actions!(
|
||||
vim,
|
||||
[
|
||||
@ -45,17 +45,24 @@ actions!(
|
||||
DeleteToEndOfLine,
|
||||
Paste,
|
||||
Yank,
|
||||
Substitute,
|
||||
ChangeCase,
|
||||
]
|
||||
);
|
||||
|
||||
impl_actions!(vim, [Scroll]);
|
||||
|
||||
pub fn init(cx: &mut AppContext) {
|
||||
cx.add_action(insert_after);
|
||||
cx.add_action(insert_first_non_whitespace);
|
||||
cx.add_action(insert_end_of_line);
|
||||
cx.add_action(insert_line_above);
|
||||
cx.add_action(insert_line_below);
|
||||
cx.add_action(change_case);
|
||||
cx.add_action(|_: &mut Workspace, _: &Substitute, cx| {
|
||||
Vim::update(cx, |vim, cx| {
|
||||
let times = vim.pop_number_operator(cx);
|
||||
substitute(vim, times, cx);
|
||||
})
|
||||
});
|
||||
cx.add_action(|_: &mut Workspace, _: &DeleteLeft, cx| {
|
||||
Vim::update(cx, |vim, cx| {
|
||||
let times = vim.pop_number_operator(cx);
|
||||
@ -81,19 +88,14 @@ pub fn init(cx: &mut AppContext) {
|
||||
})
|
||||
});
|
||||
cx.add_action(paste);
|
||||
cx.add_action(|_: &mut Workspace, Scroll(amount): &Scroll, cx| {
|
||||
Vim::update(cx, |vim, cx| {
|
||||
vim.update_active_editor(cx, |editor, cx| {
|
||||
scroll(editor, amount, cx);
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
scroll::init(cx);
|
||||
}
|
||||
|
||||
pub fn normal_motion(
|
||||
motion: Motion,
|
||||
operator: Option<Operator>,
|
||||
times: usize,
|
||||
times: Option<usize>,
|
||||
cx: &mut WindowContext,
|
||||
) {
|
||||
Vim::update(cx, |vim, cx| {
|
||||
@ -129,7 +131,7 @@ pub fn normal_object(object: Object, cx: &mut WindowContext) {
|
||||
})
|
||||
}
|
||||
|
||||
fn move_cursor(vim: &mut Vim, motion: Motion, times: usize, cx: &mut WindowContext) {
|
||||
fn move_cursor(vim: &mut Vim, motion: Motion, times: Option<usize>, cx: &mut WindowContext) {
|
||||
vim.update_active_editor(cx, |editor, cx| {
|
||||
editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
|
||||
s.move_cursors_with(|map, cursor, goal| {
|
||||
@ -147,7 +149,7 @@ fn insert_after(_: &mut Workspace, _: &InsertAfter, cx: &mut ViewContext<Workspa
|
||||
vim.update_active_editor(cx, |editor, cx| {
|
||||
editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
|
||||
s.maybe_move_cursors_with(|map, cursor, goal| {
|
||||
Motion::Right.move_point(map, cursor, goal, 1)
|
||||
Motion::Right.move_point(map, cursor, goal, None)
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -164,7 +166,7 @@ fn insert_first_non_whitespace(
|
||||
vim.update_active_editor(cx, |editor, cx| {
|
||||
editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
|
||||
s.maybe_move_cursors_with(|map, cursor, goal| {
|
||||
Motion::FirstNonWhitespace.move_point(map, cursor, goal, 1)
|
||||
Motion::FirstNonWhitespace.move_point(map, cursor, goal, None)
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -177,7 +179,7 @@ fn insert_end_of_line(_: &mut Workspace, _: &InsertEndOfLine, cx: &mut ViewConte
|
||||
vim.update_active_editor(cx, |editor, cx| {
|
||||
editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
|
||||
s.maybe_move_cursors_with(|map, cursor, goal| {
|
||||
Motion::EndOfLine.move_point(map, cursor, goal, 1)
|
||||
Motion::EndOfLine.move_point(map, cursor, goal, None)
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -237,7 +239,7 @@ fn insert_line_below(_: &mut Workspace, _: &InsertLineBelow, cx: &mut ViewContex
|
||||
});
|
||||
editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
|
||||
s.maybe_move_cursors_with(|map, cursor, goal| {
|
||||
Motion::EndOfLine.move_point(map, cursor, goal, 1)
|
||||
Motion::EndOfLine.move_point(map, cursor, goal, None)
|
||||
});
|
||||
});
|
||||
editor.edit_with_autoindent(edits, cx);
|
||||
@ -384,46 +386,6 @@ fn paste(_: &mut Workspace, _: &Paste, cx: &mut ViewContext<Workspace>) {
|
||||
});
|
||||
}
|
||||
|
||||
fn scroll(editor: &mut Editor, amount: &ScrollAmount, cx: &mut ViewContext<Editor>) {
|
||||
let should_move_cursor = editor.newest_selection_on_screen(cx).is_eq();
|
||||
editor.scroll_screen(amount, cx);
|
||||
if should_move_cursor {
|
||||
let selection_ordering = editor.newest_selection_on_screen(cx);
|
||||
if selection_ordering.is_eq() {
|
||||
return;
|
||||
}
|
||||
|
||||
let visible_rows = if let Some(visible_rows) = editor.visible_line_count() {
|
||||
visible_rows as u32
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
|
||||
let scroll_margin_rows = editor.vertical_scroll_margin() as u32;
|
||||
let top_anchor = editor.scroll_manager.anchor().anchor;
|
||||
|
||||
editor.change_selections(None, cx, |s| {
|
||||
s.replace_cursors_with(|snapshot| {
|
||||
let mut new_point = top_anchor.to_display_point(&snapshot);
|
||||
|
||||
match selection_ordering {
|
||||
Ordering::Less => {
|
||||
*new_point.row_mut() += scroll_margin_rows;
|
||||
new_point = snapshot.clip_point(new_point, Bias::Right);
|
||||
}
|
||||
Ordering::Greater => {
|
||||
*new_point.row_mut() += visible_rows - scroll_margin_rows as u32;
|
||||
new_point = snapshot.clip_point(new_point, Bias::Left);
|
||||
}
|
||||
Ordering::Equal => unreachable!(),
|
||||
}
|
||||
|
||||
vec![new_point]
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn normal_replace(text: Arc<str>, cx: &mut WindowContext) {
|
||||
Vim::update(cx, |vim, cx| {
|
||||
vim.update_active_editor(cx, |editor, cx| {
|
||||
|
64
crates/vim/src/normal/case.rs
Normal file
64
crates/vim/src/normal/case.rs
Normal file
@ -0,0 +1,64 @@
|
||||
use gpui::ViewContext;
|
||||
use language::Point;
|
||||
use workspace::Workspace;
|
||||
|
||||
use crate::{motion::Motion, normal::ChangeCase, Vim};
|
||||
|
||||
pub fn change_case(_: &mut Workspace, _: &ChangeCase, cx: &mut ViewContext<Workspace>) {
|
||||
Vim::update(cx, |vim, cx| {
|
||||
let count = vim.pop_number_operator(cx);
|
||||
vim.update_active_editor(cx, |editor, cx| {
|
||||
editor.set_clip_at_line_ends(false, cx);
|
||||
editor.transact(cx, |editor, cx| {
|
||||
editor.change_selections(None, cx, |s| {
|
||||
s.move_with(|map, selection| {
|
||||
if selection.start == selection.end {
|
||||
Motion::Right.expand_selection(map, selection, count, true);
|
||||
}
|
||||
})
|
||||
});
|
||||
let selections = editor.selections.all::<Point>(cx);
|
||||
for selection in selections.into_iter().rev() {
|
||||
let snapshot = editor.buffer().read(cx).snapshot(cx);
|
||||
editor.buffer().update(cx, |buffer, cx| {
|
||||
let range = selection.start..selection.end;
|
||||
let text = snapshot
|
||||
.text_for_range(selection.start..selection.end)
|
||||
.flat_map(|s| s.chars())
|
||||
.flat_map(|c| {
|
||||
if c.is_lowercase() {
|
||||
c.to_uppercase().collect::<Vec<char>>()
|
||||
} else {
|
||||
c.to_lowercase().collect::<Vec<char>>()
|
||||
}
|
||||
})
|
||||
.collect::<String>();
|
||||
|
||||
buffer.edit([(range, text)], None, cx)
|
||||
})
|
||||
}
|
||||
});
|
||||
editor.set_clip_at_line_ends(true, cx);
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::{state::Mode, test::VimTestContext};
|
||||
use indoc::indoc;
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_change_case(cx: &mut gpui::TestAppContext) {
|
||||
let mut cx = VimTestContext::new(cx, true).await;
|
||||
cx.set_state(indoc! {"ˇabC\n"}, Mode::Normal);
|
||||
cx.simulate_keystrokes(["~"]);
|
||||
cx.assert_editor_state("AˇbC\n");
|
||||
cx.simulate_keystrokes(["2", "~"]);
|
||||
cx.assert_editor_state("ABcˇ\n");
|
||||
|
||||
cx.set_state(indoc! {"a😀C«dÉ1*fˇ»\n"}, Mode::Normal);
|
||||
cx.simulate_keystrokes(["~"]);
|
||||
cx.assert_editor_state("a😀CDé1*Fˇ\n");
|
||||
}
|
||||
}
|
@ -6,7 +6,7 @@ use editor::{
|
||||
use gpui::WindowContext;
|
||||
use language::Selection;
|
||||
|
||||
pub fn change_motion(vim: &mut Vim, motion: Motion, times: usize, cx: &mut WindowContext) {
|
||||
pub fn change_motion(vim: &mut Vim, motion: Motion, times: Option<usize>, cx: &mut WindowContext) {
|
||||
// Some motions ignore failure when switching to normal mode
|
||||
let mut motion_succeeded = matches!(
|
||||
motion,
|
||||
@ -78,10 +78,10 @@ pub fn change_object(vim: &mut Vim, object: Object, around: bool, cx: &mut Windo
|
||||
fn expand_changed_word_selection(
|
||||
map: &DisplaySnapshot,
|
||||
selection: &mut Selection<DisplayPoint>,
|
||||
times: usize,
|
||||
times: Option<usize>,
|
||||
ignore_punctuation: bool,
|
||||
) -> bool {
|
||||
if times == 1 {
|
||||
if times.is_none() || times.unwrap() == 1 {
|
||||
let in_word = map
|
||||
.chars_at(selection.head())
|
||||
.next()
|
||||
@ -97,7 +97,8 @@ fn expand_changed_word_selection(
|
||||
});
|
||||
true
|
||||
} else {
|
||||
Motion::NextWordStart { ignore_punctuation }.expand_selection(map, selection, 1, false)
|
||||
Motion::NextWordStart { ignore_punctuation }
|
||||
.expand_selection(map, selection, None, false)
|
||||
}
|
||||
} else {
|
||||
Motion::NextWordStart { ignore_punctuation }.expand_selection(map, selection, times, false)
|
||||
|
@ -3,7 +3,7 @@ use collections::{HashMap, HashSet};
|
||||
use editor::{display_map::ToDisplayPoint, scroll::autoscroll::Autoscroll, Bias};
|
||||
use gpui::WindowContext;
|
||||
|
||||
pub fn delete_motion(vim: &mut Vim, motion: Motion, times: usize, cx: &mut WindowContext) {
|
||||
pub fn delete_motion(vim: &mut Vim, motion: Motion, times: Option<usize>, cx: &mut WindowContext) {
|
||||
vim.update_active_editor(cx, |editor, cx| {
|
||||
editor.transact(cx, |editor, cx| {
|
||||
editor.set_clip_at_line_ends(false, cx);
|
||||
|
120
crates/vim/src/normal/scroll.rs
Normal file
120
crates/vim/src/normal/scroll.rs
Normal file
@ -0,0 +1,120 @@
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use crate::Vim;
|
||||
use editor::{display_map::ToDisplayPoint, scroll::scroll_amount::ScrollAmount, Editor};
|
||||
use gpui::{actions, AppContext, ViewContext};
|
||||
use language::Bias;
|
||||
use workspace::Workspace;
|
||||
|
||||
actions!(
|
||||
vim,
|
||||
[LineUp, LineDown, ScrollUp, ScrollDown, PageUp, PageDown,]
|
||||
);
|
||||
|
||||
pub fn init(cx: &mut AppContext) {
|
||||
cx.add_action(|_: &mut Workspace, _: &LineDown, cx| {
|
||||
scroll(cx, |c| ScrollAmount::Line(c.unwrap_or(1.)))
|
||||
});
|
||||
cx.add_action(|_: &mut Workspace, _: &LineUp, cx| {
|
||||
scroll(cx, |c| ScrollAmount::Line(-c.unwrap_or(1.)))
|
||||
});
|
||||
cx.add_action(|_: &mut Workspace, _: &PageDown, cx| {
|
||||
scroll(cx, |c| ScrollAmount::Page(c.unwrap_or(1.)))
|
||||
});
|
||||
cx.add_action(|_: &mut Workspace, _: &PageUp, cx| {
|
||||
scroll(cx, |c| ScrollAmount::Page(-c.unwrap_or(1.)))
|
||||
});
|
||||
cx.add_action(|_: &mut Workspace, _: &ScrollDown, cx| {
|
||||
scroll(cx, |c| {
|
||||
if let Some(c) = c {
|
||||
ScrollAmount::Line(c)
|
||||
} else {
|
||||
ScrollAmount::Page(0.5)
|
||||
}
|
||||
})
|
||||
});
|
||||
cx.add_action(|_: &mut Workspace, _: &ScrollUp, cx| {
|
||||
scroll(cx, |c| {
|
||||
if let Some(c) = c {
|
||||
ScrollAmount::Line(-c)
|
||||
} else {
|
||||
ScrollAmount::Page(-0.5)
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn scroll(cx: &mut ViewContext<Workspace>, by: fn(c: Option<f32>) -> ScrollAmount) {
|
||||
Vim::update(cx, |vim, cx| {
|
||||
let amount = by(vim.pop_number_operator(cx).map(|c| c as f32));
|
||||
vim.update_active_editor(cx, |editor, cx| scroll_editor(editor, &amount, cx));
|
||||
})
|
||||
}
|
||||
|
||||
fn scroll_editor(editor: &mut Editor, amount: &ScrollAmount, cx: &mut ViewContext<Editor>) {
|
||||
let should_move_cursor = editor.newest_selection_on_screen(cx).is_eq();
|
||||
editor.scroll_screen(amount, cx);
|
||||
if should_move_cursor {
|
||||
let selection_ordering = editor.newest_selection_on_screen(cx);
|
||||
if selection_ordering.is_eq() {
|
||||
return;
|
||||
}
|
||||
|
||||
let visible_rows = if let Some(visible_rows) = editor.visible_line_count() {
|
||||
visible_rows as u32
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
|
||||
let top_anchor = editor.scroll_manager.anchor().anchor;
|
||||
|
||||
editor.change_selections(None, cx, |s| {
|
||||
s.replace_cursors_with(|snapshot| {
|
||||
let mut new_point = top_anchor.to_display_point(&snapshot);
|
||||
|
||||
match selection_ordering {
|
||||
Ordering::Less => {
|
||||
new_point = snapshot.clip_point(new_point, Bias::Right);
|
||||
}
|
||||
Ordering::Greater => {
|
||||
*new_point.row_mut() += visible_rows - 1;
|
||||
new_point = snapshot.clip_point(new_point, Bias::Left);
|
||||
}
|
||||
Ordering::Equal => unreachable!(),
|
||||
}
|
||||
|
||||
vec![new_point]
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::{state::Mode, test::VimTestContext};
|
||||
use gpui::geometry::vector::vec2f;
|
||||
use indoc::indoc;
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_scroll(cx: &mut gpui::TestAppContext) {
|
||||
let mut cx = VimTestContext::new(cx, true).await;
|
||||
|
||||
cx.set_state(indoc! {"ˇa\nb\nc\nd\ne\n"}, Mode::Normal);
|
||||
|
||||
cx.update_editor(|editor, cx| {
|
||||
assert_eq!(editor.snapshot(cx).scroll_position(), vec2f(0., 0.))
|
||||
});
|
||||
cx.simulate_keystrokes(["ctrl-e"]);
|
||||
cx.update_editor(|editor, cx| {
|
||||
assert_eq!(editor.snapshot(cx).scroll_position(), vec2f(0., 1.))
|
||||
});
|
||||
cx.simulate_keystrokes(["2", "ctrl-e"]);
|
||||
cx.update_editor(|editor, cx| {
|
||||
assert_eq!(editor.snapshot(cx).scroll_position(), vec2f(0., 3.))
|
||||
});
|
||||
cx.simulate_keystrokes(["ctrl-y"]);
|
||||
cx.update_editor(|editor, cx| {
|
||||
assert_eq!(editor.snapshot(cx).scroll_position(), vec2f(0., 2.))
|
||||
});
|
||||
}
|
||||
}
|
73
crates/vim/src/normal/substitute.rs
Normal file
73
crates/vim/src/normal/substitute.rs
Normal file
@ -0,0 +1,73 @@
|
||||
use gpui::WindowContext;
|
||||
use language::Point;
|
||||
|
||||
use crate::{motion::Motion, Mode, Vim};
|
||||
|
||||
pub fn substitute(vim: &mut Vim, count: Option<usize>, cx: &mut WindowContext) {
|
||||
vim.update_active_editor(cx, |editor, cx| {
|
||||
editor.set_clip_at_line_ends(false, cx);
|
||||
editor.transact(cx, |editor, cx| {
|
||||
editor.change_selections(None, cx, |s| {
|
||||
s.move_with(|map, selection| {
|
||||
if selection.start == selection.end {
|
||||
Motion::Right.expand_selection(map, selection, count, true);
|
||||
}
|
||||
})
|
||||
});
|
||||
let selections = editor.selections.all::<Point>(cx);
|
||||
for selection in selections.into_iter().rev() {
|
||||
editor.buffer().update(cx, |buffer, cx| {
|
||||
buffer.edit([(selection.start..selection.end, "")], None, cx)
|
||||
})
|
||||
}
|
||||
});
|
||||
editor.set_clip_at_line_ends(true, cx);
|
||||
});
|
||||
vim.switch_mode(Mode::Insert, true, cx)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::{state::Mode, test::VimTestContext};
|
||||
use indoc::indoc;
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_substitute(cx: &mut gpui::TestAppContext) {
|
||||
let mut cx = VimTestContext::new(cx, true).await;
|
||||
|
||||
// supports a single cursor
|
||||
cx.set_state(indoc! {"ˇabc\n"}, Mode::Normal);
|
||||
cx.simulate_keystrokes(["s", "x"]);
|
||||
cx.assert_editor_state("xˇbc\n");
|
||||
|
||||
// supports a selection
|
||||
cx.set_state(indoc! {"a«bcˇ»\n"}, Mode::Visual { line: false });
|
||||
cx.assert_editor_state("a«bcˇ»\n");
|
||||
cx.simulate_keystrokes(["s", "x"]);
|
||||
cx.assert_editor_state("axˇ\n");
|
||||
|
||||
// supports counts
|
||||
cx.set_state(indoc! {"ˇabc\n"}, Mode::Normal);
|
||||
cx.simulate_keystrokes(["2", "s", "x"]);
|
||||
cx.assert_editor_state("xˇc\n");
|
||||
|
||||
// supports multiple cursors
|
||||
cx.set_state(indoc! {"a«bcˇ»deˇffg\n"}, Mode::Normal);
|
||||
cx.simulate_keystrokes(["2", "s", "x"]);
|
||||
cx.assert_editor_state("axˇdexˇg\n");
|
||||
|
||||
// does not read beyond end of line
|
||||
cx.set_state(indoc! {"ˇabc\n"}, Mode::Normal);
|
||||
cx.simulate_keystrokes(["5", "s", "x"]);
|
||||
cx.assert_editor_state("xˇ\n");
|
||||
|
||||
// it handles multibyte characters
|
||||
cx.set_state(indoc! {"ˇcàfé\n"}, Mode::Normal);
|
||||
cx.simulate_keystrokes(["4", "s"]);
|
||||
cx.assert_editor_state("ˇ\n");
|
||||
|
||||
// should transactionally undo selection changes
|
||||
cx.simulate_keystrokes(["escape", "u"]);
|
||||
cx.assert_editor_state("ˇcàfé\n");
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@ use crate::{motion::Motion, object::Object, utils::copy_selections_content, Vim}
|
||||
use collections::HashMap;
|
||||
use gpui::WindowContext;
|
||||
|
||||
pub fn yank_motion(vim: &mut Vim, motion: Motion, times: usize, cx: &mut WindowContext) {
|
||||
pub fn yank_motion(vim: &mut Vim, motion: Motion, times: Option<usize>, cx: &mut WindowContext) {
|
||||
vim.update_active_editor(cx, |editor, cx| {
|
||||
editor.transact(cx, |editor, cx| {
|
||||
editor.set_clip_at_line_ends(false, cx);
|
||||
|
@ -109,3 +109,33 @@ async fn test_count_down(cx: &mut gpui::TestAppContext) {
|
||||
cx.simulate_keystrokes(["9", "down"]);
|
||||
cx.assert_editor_state("aa\nbb\ncc\ndd\neˇe");
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_end_of_document_710(cx: &mut gpui::TestAppContext) {
|
||||
let mut cx = VimTestContext::new(cx, true).await;
|
||||
|
||||
// goes to end by default
|
||||
cx.set_state(indoc! {"aˇa\nbb\ncc"}, Mode::Normal);
|
||||
cx.simulate_keystrokes(["shift-g"]);
|
||||
cx.assert_editor_state("aa\nbb\ncˇc");
|
||||
|
||||
// can go to line 1 (https://github.com/zed-industries/community/issues/710)
|
||||
cx.simulate_keystrokes(["1", "shift-g"]);
|
||||
cx.assert_editor_state("aˇa\nbb\ncc");
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_indent_outdent(cx: &mut gpui::TestAppContext) {
|
||||
let mut cx = VimTestContext::new(cx, true).await;
|
||||
|
||||
// works in normal mode
|
||||
cx.set_state(indoc! {"aa\nbˇb\ncc"}, Mode::Normal);
|
||||
cx.simulate_keystrokes([">", ">"]);
|
||||
cx.assert_editor_state("aa\n bˇb\ncc");
|
||||
cx.simulate_keystrokes(["<", "<"]);
|
||||
cx.assert_editor_state("aa\nbˇb\ncc");
|
||||
|
||||
// works in visuial mode
|
||||
cx.simulate_keystrokes(["shift-v", "down", ">", ">"]);
|
||||
cx.assert_editor_state("aa\n b«b\n cˇ»c");
|
||||
}
|
||||
|
@ -238,13 +238,12 @@ impl Vim {
|
||||
popped_operator
|
||||
}
|
||||
|
||||
fn pop_number_operator(&mut self, cx: &mut WindowContext) -> usize {
|
||||
let mut times = 1;
|
||||
fn pop_number_operator(&mut self, cx: &mut WindowContext) -> Option<usize> {
|
||||
if let Some(Operator::Number(number)) = self.active_operator() {
|
||||
times = number;
|
||||
self.pop_operator(cx);
|
||||
return Some(number);
|
||||
}
|
||||
times
|
||||
None
|
||||
}
|
||||
|
||||
fn clear_operator(&mut self, cx: &mut WindowContext) {
|
||||
|
@ -25,7 +25,7 @@ pub fn init(cx: &mut AppContext) {
|
||||
cx.add_action(paste);
|
||||
}
|
||||
|
||||
pub fn visual_motion(motion: Motion, times: usize, cx: &mut WindowContext) {
|
||||
pub fn visual_motion(motion: Motion, times: Option<usize>, cx: &mut WindowContext) {
|
||||
Vim::update(cx, |vim, cx| {
|
||||
vim.update_active_editor(cx, |editor, cx| {
|
||||
editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
|
||||
|
@ -249,7 +249,7 @@ impl Dock {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_panel<T: Panel>(&mut self, panel: ViewHandle<T>, cx: &mut ViewContext<Self>) {
|
||||
pub(crate) fn add_panel<T: Panel>(&mut self, panel: ViewHandle<T>, cx: &mut ViewContext<Self>) {
|
||||
let subscriptions = [
|
||||
cx.observe(&panel, |_, _, cx| cx.notify()),
|
||||
cx.subscribe(&panel, |this, panel, event, cx| {
|
||||
@ -605,6 +605,7 @@ pub mod test {
|
||||
use super::*;
|
||||
use gpui::{ViewContext, WindowContext};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum TestPanelEvent {
|
||||
PositionChanged,
|
||||
Activated,
|
||||
|
@ -1,9 +1,10 @@
|
||||
mod dragged_item_receiver;
|
||||
|
||||
use super::{ItemHandle, SplitDirection};
|
||||
pub use crate::toolbar::Toolbar;
|
||||
use crate::{
|
||||
item::WeakItemHandle, notify_of_new_dock, toolbar::Toolbar, AutosaveSetting, Item,
|
||||
NewCenterTerminal, NewFile, NewSearch, ToggleZoom, Workspace, WorkspaceSettings,
|
||||
item::WeakItemHandle, notify_of_new_dock, AutosaveSetting, Item, NewCenterTerminal, NewFile,
|
||||
NewSearch, ToggleZoom, Workspace, WorkspaceSettings,
|
||||
};
|
||||
use anyhow::Result;
|
||||
use collections::{HashMap, HashSet, VecDeque};
|
||||
@ -250,7 +251,7 @@ impl Pane {
|
||||
pane: handle.clone(),
|
||||
next_timestamp,
|
||||
}))),
|
||||
toolbar: cx.add_view(|_| Toolbar::new(handle)),
|
||||
toolbar: cx.add_view(|_| Toolbar::new(Some(handle))),
|
||||
tab_bar_context_menu: TabBarContextMenu {
|
||||
kind: TabBarContextMenuKind::New,
|
||||
handle: context_menu,
|
||||
@ -1112,7 +1113,7 @@ impl Pane {
|
||||
.get(self.active_item_index)
|
||||
.map(|item| item.as_ref());
|
||||
self.toolbar.update(cx, |toolbar, cx| {
|
||||
toolbar.set_active_pane_item(active_item, cx);
|
||||
toolbar.set_active_item(active_item, cx);
|
||||
});
|
||||
}
|
||||
|
||||
@ -1602,7 +1603,7 @@ impl View for Pane {
|
||||
}
|
||||
|
||||
self.toolbar.update(cx, |toolbar, cx| {
|
||||
toolbar.pane_focus_update(true, cx);
|
||||
toolbar.focus_changed(true, cx);
|
||||
});
|
||||
|
||||
if let Some(active_item) = self.active_item() {
|
||||
@ -1631,7 +1632,7 @@ impl View for Pane {
|
||||
fn focus_out(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
|
||||
self.has_focus = false;
|
||||
self.toolbar.update(cx, |toolbar, cx| {
|
||||
toolbar.pane_focus_update(false, cx);
|
||||
toolbar.focus_changed(false, cx);
|
||||
});
|
||||
cx.notify();
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ trait ToolbarItemViewHandle {
|
||||
active_pane_item: Option<&dyn ItemHandle>,
|
||||
cx: &mut WindowContext,
|
||||
) -> ToolbarItemLocation;
|
||||
fn pane_focus_update(&mut self, pane_focused: bool, cx: &mut WindowContext);
|
||||
fn focus_changed(&mut self, pane_focused: bool, cx: &mut WindowContext);
|
||||
fn row_count(&self, cx: &WindowContext) -> usize;
|
||||
}
|
||||
|
||||
@ -51,10 +51,10 @@ pub enum ToolbarItemLocation {
|
||||
}
|
||||
|
||||
pub struct Toolbar {
|
||||
active_pane_item: Option<Box<dyn ItemHandle>>,
|
||||
active_item: Option<Box<dyn ItemHandle>>,
|
||||
hidden: bool,
|
||||
can_navigate: bool,
|
||||
pane: WeakViewHandle<Pane>,
|
||||
pane: Option<WeakViewHandle<Pane>>,
|
||||
items: Vec<(Box<dyn ToolbarItemViewHandle>, ToolbarItemLocation)>,
|
||||
}
|
||||
|
||||
@ -121,7 +121,7 @@ impl View for Toolbar {
|
||||
let pane = self.pane.clone();
|
||||
let mut enable_go_backward = false;
|
||||
let mut enable_go_forward = false;
|
||||
if let Some(pane) = pane.upgrade(cx) {
|
||||
if let Some(pane) = pane.and_then(|pane| pane.upgrade(cx)) {
|
||||
let pane = pane.read(cx);
|
||||
enable_go_backward = pane.can_navigate_backward();
|
||||
enable_go_forward = pane.can_navigate_forward();
|
||||
@ -143,19 +143,17 @@ impl View for Toolbar {
|
||||
enable_go_backward,
|
||||
spacing,
|
||||
{
|
||||
let pane = pane.clone();
|
||||
move |toolbar, cx| {
|
||||
if let Some(workspace) = toolbar
|
||||
.pane
|
||||
.upgrade(cx)
|
||||
.and_then(|pane| pane.read(cx).workspace().upgrade(cx))
|
||||
if let Some(pane) = toolbar.pane.as_ref().and_then(|pane| pane.upgrade(cx))
|
||||
{
|
||||
let pane = pane.clone();
|
||||
cx.window_context().defer(move |cx| {
|
||||
workspace.update(cx, |workspace, cx| {
|
||||
workspace.go_back(pane.clone(), cx).detach_and_log_err(cx);
|
||||
});
|
||||
})
|
||||
if let Some(workspace) = pane.read(cx).workspace().upgrade(cx) {
|
||||
let pane = pane.downgrade();
|
||||
cx.window_context().defer(move |cx| {
|
||||
workspace.update(cx, |workspace, cx| {
|
||||
workspace.go_back(pane, cx).detach_and_log_err(cx);
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -171,21 +169,17 @@ impl View for Toolbar {
|
||||
enable_go_forward,
|
||||
spacing,
|
||||
{
|
||||
let pane = pane.clone();
|
||||
move |toolbar, cx| {
|
||||
if let Some(workspace) = toolbar
|
||||
.pane
|
||||
.upgrade(cx)
|
||||
.and_then(|pane| pane.read(cx).workspace().upgrade(cx))
|
||||
if let Some(pane) = toolbar.pane.as_ref().and_then(|pane| pane.upgrade(cx))
|
||||
{
|
||||
let pane = pane.clone();
|
||||
cx.window_context().defer(move |cx| {
|
||||
workspace.update(cx, |workspace, cx| {
|
||||
workspace
|
||||
.go_forward(pane.clone(), cx)
|
||||
.detach_and_log_err(cx);
|
||||
});
|
||||
});
|
||||
if let Some(workspace) = pane.read(cx).workspace().upgrade(cx) {
|
||||
let pane = pane.downgrade();
|
||||
cx.window_context().defer(move |cx| {
|
||||
workspace.update(cx, |workspace, cx| {
|
||||
workspace.go_forward(pane, cx).detach_and_log_err(cx);
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -269,9 +263,9 @@ fn nav_button<A: Action, F: 'static + Fn(&mut Toolbar, &mut ViewContext<Toolbar>
|
||||
}
|
||||
|
||||
impl Toolbar {
|
||||
pub fn new(pane: WeakViewHandle<Pane>) -> Self {
|
||||
pub fn new(pane: Option<WeakViewHandle<Pane>>) -> Self {
|
||||
Self {
|
||||
active_pane_item: None,
|
||||
active_item: None,
|
||||
pane,
|
||||
items: Default::default(),
|
||||
hidden: false,
|
||||
@ -288,7 +282,7 @@ impl Toolbar {
|
||||
where
|
||||
T: 'static + ToolbarItemView,
|
||||
{
|
||||
let location = item.set_active_pane_item(self.active_pane_item.as_deref(), cx);
|
||||
let location = item.set_active_pane_item(self.active_item.as_deref(), cx);
|
||||
cx.subscribe(&item, |this, item, event, cx| {
|
||||
if let Some((_, current_location)) =
|
||||
this.items.iter_mut().find(|(i, _)| i.id() == item.id())
|
||||
@ -307,20 +301,16 @@ impl Toolbar {
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
pub fn set_active_pane_item(
|
||||
&mut self,
|
||||
pane_item: Option<&dyn ItemHandle>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) {
|
||||
self.active_pane_item = pane_item.map(|item| item.boxed_clone());
|
||||
pub fn set_active_item(&mut self, item: Option<&dyn ItemHandle>, cx: &mut ViewContext<Self>) {
|
||||
self.active_item = item.map(|item| item.boxed_clone());
|
||||
self.hidden = self
|
||||
.active_pane_item
|
||||
.active_item
|
||||
.as_ref()
|
||||
.map(|item| !item.show_toolbar(cx))
|
||||
.unwrap_or(false);
|
||||
|
||||
for (toolbar_item, current_location) in self.items.iter_mut() {
|
||||
let new_location = toolbar_item.set_active_pane_item(pane_item, cx);
|
||||
let new_location = toolbar_item.set_active_pane_item(item, cx);
|
||||
if new_location != *current_location {
|
||||
*current_location = new_location;
|
||||
cx.notify();
|
||||
@ -328,9 +318,9 @@ impl Toolbar {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pane_focus_update(&mut self, pane_focused: bool, cx: &mut ViewContext<Self>) {
|
||||
pub fn focus_changed(&mut self, focused: bool, cx: &mut ViewContext<Self>) {
|
||||
for (toolbar_item, _) in self.items.iter_mut() {
|
||||
toolbar_item.pane_focus_update(pane_focused, cx);
|
||||
toolbar_item.focus_changed(focused, cx);
|
||||
}
|
||||
}
|
||||
|
||||
@ -364,7 +354,7 @@ impl<T: ToolbarItemView> ToolbarItemViewHandle for ViewHandle<T> {
|
||||
})
|
||||
}
|
||||
|
||||
fn pane_focus_update(&mut self, pane_focused: bool, cx: &mut WindowContext) {
|
||||
fn focus_changed(&mut self, pane_focused: bool, cx: &mut WindowContext) {
|
||||
self.update(cx, |this, cx| {
|
||||
this.pane_focus_update(pane_focused, cx);
|
||||
cx.notify();
|
||||
|
@ -861,7 +861,10 @@ impl Workspace {
|
||||
&self.right_dock
|
||||
}
|
||||
|
||||
pub fn add_panel<T: Panel>(&mut self, panel: ViewHandle<T>, cx: &mut ViewContext<Self>) {
|
||||
pub fn add_panel<T: Panel>(&mut self, panel: ViewHandle<T>, cx: &mut ViewContext<Self>)
|
||||
where
|
||||
T::Event: std::fmt::Debug,
|
||||
{
|
||||
let dock = match panel.position(cx) {
|
||||
DockPosition::Left => &self.left_dock,
|
||||
DockPosition::Bottom => &self.bottom_dock,
|
||||
@ -904,10 +907,11 @@ impl Workspace {
|
||||
});
|
||||
} else if T::should_zoom_in_on_event(event) {
|
||||
dock.update(cx, |dock, cx| dock.set_panel_zoomed(&panel, true, cx));
|
||||
if panel.has_focus(cx) {
|
||||
this.zoomed = Some(panel.downgrade().into_any());
|
||||
this.zoomed_position = Some(panel.read(cx).position(cx));
|
||||
if !panel.has_focus(cx) {
|
||||
cx.focus(&panel);
|
||||
}
|
||||
this.zoomed = Some(panel.downgrade().into_any());
|
||||
this.zoomed_position = Some(panel.read(cx).position(cx));
|
||||
} else if T::should_zoom_out_on_event(event) {
|
||||
dock.update(cx, |dock, cx| dock.set_panel_zoomed(&panel, false, cx));
|
||||
if this.zoomed_position == Some(prev_position) {
|
||||
@ -1702,6 +1706,11 @@ impl Workspace {
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub fn zoomed_view(&self, cx: &AppContext) -> Option<AnyViewHandle> {
|
||||
self.zoomed.and_then(|view| view.upgrade(cx))
|
||||
}
|
||||
|
||||
fn dismiss_zoomed_items_to_reveal(
|
||||
&mut self,
|
||||
dock_to_reveal: Option<DockPosition>,
|
||||
|
13
crates/xtask/Cargo.toml
Normal file
13
crates/xtask/Cargo.toml
Normal file
@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "xtask"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
clap = {version = "4.0", features = ["derive"]}
|
||||
theme = {path = "../theme"}
|
||||
serde_json.workspace = true
|
||||
schemars.workspace = true
|
23
crates/xtask/src/cli.rs
Normal file
23
crates/xtask/src/cli.rs
Normal file
@ -0,0 +1,23 @@
|
||||
use clap::{Parser, Subcommand};
|
||||
use std::path::PathBuf;
|
||||
/// Common utilities for Zed developers.
|
||||
// For more information, see [matklad's repository README](https://github.com/matklad/cargo-xtask/)
|
||||
#[derive(Parser)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
#[command(propagate_version = true)]
|
||||
pub struct Cli {
|
||||
#[command(subcommand)]
|
||||
pub command: Commands,
|
||||
}
|
||||
|
||||
/// Command to run.
|
||||
#[derive(Subcommand)]
|
||||
pub enum Commands {
|
||||
/// Builds theme types for interop with Typescript.
|
||||
BuildThemeTypes {
|
||||
#[clap(short, long, default_value = "schemas")]
|
||||
out_dir: PathBuf,
|
||||
#[clap(short, long, default_value = "theme.json")]
|
||||
file_name: PathBuf,
|
||||
},
|
||||
}
|
29
crates/xtask/src/main.rs
Normal file
29
crates/xtask/src/main.rs
Normal file
@ -0,0 +1,29 @@
|
||||
mod cli;
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
use anyhow::Result;
|
||||
use clap::Parser;
|
||||
use schemars::schema_for;
|
||||
use theme::Theme;
|
||||
|
||||
fn build_themes(out_dir: PathBuf, file_name: PathBuf) -> Result<()> {
|
||||
let theme = schema_for!(Theme);
|
||||
let output = serde_json::to_string_pretty(&theme)?;
|
||||
|
||||
std::fs::create_dir(&out_dir)?;
|
||||
|
||||
let mut file_path = out_dir;
|
||||
file_path.push(file_name);
|
||||
|
||||
std::fs::write(file_path, output)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let args = cli::Cli::parse();
|
||||
match args.command {
|
||||
cli::Commands::BuildThemeTypes { out_dir, file_name } => build_themes(out_dir, file_name),
|
||||
}
|
||||
}
|
@ -48,6 +48,7 @@ use util::{
|
||||
http::{self, HttpClient},
|
||||
paths::PathLikeWithPosition,
|
||||
};
|
||||
use uuid::Uuid;
|
||||
use welcome::{show_welcome_experience, FIRST_OPEN};
|
||||
|
||||
use fs::RealFs;
|
||||
@ -68,7 +69,8 @@ fn main() {
|
||||
log::info!("========== starting zed ==========");
|
||||
let mut app = gpui::App::new(Assets).unwrap();
|
||||
|
||||
init_panic_hook(&app);
|
||||
let installation_id = app.background().block(installation_id()).ok();
|
||||
init_panic_hook(&app, installation_id.clone());
|
||||
|
||||
app.background();
|
||||
|
||||
@ -168,7 +170,7 @@ fn main() {
|
||||
})
|
||||
.detach();
|
||||
|
||||
client.telemetry().start();
|
||||
client.telemetry().start(installation_id);
|
||||
|
||||
let app_state = Arc::new(AppState {
|
||||
languages,
|
||||
@ -268,6 +270,22 @@ fn main() {
|
||||
});
|
||||
}
|
||||
|
||||
async fn installation_id() -> Result<String> {
|
||||
let legacy_key_name = "device_id";
|
||||
|
||||
if let Ok(Some(installation_id)) = KEY_VALUE_STORE.read_kvp(legacy_key_name) {
|
||||
Ok(installation_id)
|
||||
} else {
|
||||
let installation_id = Uuid::new_v4().to_string();
|
||||
|
||||
KEY_VALUE_STORE
|
||||
.write_kvp(legacy_key_name.to_string(), installation_id.clone())
|
||||
.await?;
|
||||
|
||||
Ok(installation_id)
|
||||
}
|
||||
}
|
||||
|
||||
fn open_urls(
|
||||
urls: Vec<String>,
|
||||
cli_connections_tx: &mpsc::UnboundedSender<(
|
||||
@ -371,6 +389,8 @@ struct Panic {
|
||||
os_version: Option<String>,
|
||||
architecture: String,
|
||||
panicked_on: u128,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
installation_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
@ -379,7 +399,7 @@ struct PanicRequest {
|
||||
token: String,
|
||||
}
|
||||
|
||||
fn init_panic_hook(app: &App) {
|
||||
fn init_panic_hook(app: &App, installation_id: Option<String>) {
|
||||
let is_pty = stdout_is_a_pty();
|
||||
let platform = app.platform();
|
||||
|
||||
@ -432,6 +452,7 @@ fn init_panic_hook(app: &App) {
|
||||
.unwrap()
|
||||
.as_millis(),
|
||||
backtrace,
|
||||
installation_id: installation_id.clone(),
|
||||
};
|
||||
|
||||
if is_pty {
|
||||
|
1764
styles/package-lock.json
generated
1764
styles/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -7,6 +7,7 @@
|
||||
"build": "ts-node ./src/buildThemes.ts",
|
||||
"build-licenses": "ts-node ./src/buildLicenses.ts",
|
||||
"build-tokens": "ts-node ./src/buildTokens.ts",
|
||||
"build-types": "cd ../crates/theme && cargo test && cd ../../styles && ts-node ./src/buildTypes.ts",
|
||||
"test": "vitest"
|
||||
},
|
||||
"author": "",
|
||||
@ -20,6 +21,7 @@
|
||||
"case-anything": "^2.1.10",
|
||||
"chroma-js": "^2.4.2",
|
||||
"deepmerge": "^4.3.0",
|
||||
"json-schema-to-typescript": "^13.0.2",
|
||||
"toml": "^3.0.0",
|
||||
"ts-deepmerge": "^6.0.3",
|
||||
"ts-node": "^10.9.1",
|
||||
|
64
styles/src/buildTypes.ts
Normal file
64
styles/src/buildTypes.ts
Normal file
@ -0,0 +1,64 @@
|
||||
import * as fs from "fs/promises"
|
||||
import * as fsSync from "fs"
|
||||
import * as path from "path"
|
||||
import { compile } from "json-schema-to-typescript"
|
||||
|
||||
const BANNER = `/*
|
||||
* This file is autogenerated
|
||||
*/\n\n`
|
||||
const dirname = __dirname
|
||||
|
||||
async function main() {
|
||||
let schemasPath = path.join(dirname, "../../", "crates/theme/schemas")
|
||||
let schemaFiles = (await fs.readdir(schemasPath)).filter((x) =>
|
||||
x.endsWith(".json")
|
||||
)
|
||||
|
||||
let compiledTypes = new Set()
|
||||
|
||||
for (let filename of schemaFiles) {
|
||||
let filePath = path.join(schemasPath, filename)
|
||||
const fileContents = await fs.readFile(filePath)
|
||||
let schema = JSON.parse(fileContents.toString())
|
||||
let compiled = await compile(schema, schema.title, {
|
||||
bannerComment: "",
|
||||
})
|
||||
let eachType = compiled.split("export")
|
||||
for (let type of eachType) {
|
||||
if (!type) {
|
||||
continue
|
||||
}
|
||||
compiledTypes.add("export " + type.trim())
|
||||
}
|
||||
}
|
||||
|
||||
let output = BANNER + Array.from(compiledTypes).join("\n\n")
|
||||
let outputPath = path.join(dirname, "../../styles/src/types/zed.ts")
|
||||
|
||||
try {
|
||||
let existing = await fs.readFile(outputPath)
|
||||
if (existing.toString() == output) {
|
||||
// Skip writing if it hasn't changed
|
||||
console.log("Schemas are up to date")
|
||||
return
|
||||
}
|
||||
} catch (e) {
|
||||
// It's fine if there's no output from a previous run.
|
||||
// @ts-ignore
|
||||
if (e.code !== "ENOENT") {
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
const typesDic = path.dirname(outputPath)
|
||||
if (!fsSync.existsSync(typesDic)) {
|
||||
await fs.mkdir(typesDic)
|
||||
}
|
||||
await fs.writeFile(outputPath, output)
|
||||
console.log(`Wrote Typescript types to ${outputPath}`)
|
||||
}
|
||||
|
||||
main().catch((e) => {
|
||||
console.error(e)
|
||||
process.exit(1)
|
||||
})
|
@ -10,11 +10,190 @@ export default function assistant(colorScheme: ColorScheme) {
|
||||
background: editor(colorScheme).background,
|
||||
padding: { left: 12 },
|
||||
},
|
||||
header: {
|
||||
messageHeader: {
|
||||
border: border(layer, "default", { bottom: true, top: true }),
|
||||
margin: { bottom: 6, top: 6 },
|
||||
background: editor(colorScheme).background,
|
||||
},
|
||||
hamburgerButton: interactive({
|
||||
base: {
|
||||
icon: {
|
||||
color: foreground(layer, "variant"),
|
||||
asset: "icons/hamburger_15.svg",
|
||||
dimensions: {
|
||||
width: 15,
|
||||
height: 15,
|
||||
},
|
||||
},
|
||||
container: {
|
||||
margin: { left: 12 },
|
||||
}
|
||||
},
|
||||
state: {
|
||||
hovered: {
|
||||
icon: {
|
||||
color: foreground(layer, "hovered")
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
splitButton: interactive({
|
||||
base: {
|
||||
icon: {
|
||||
color: foreground(layer, "variant"),
|
||||
asset: "icons/split_message_15.svg",
|
||||
dimensions: {
|
||||
width: 15,
|
||||
height: 15,
|
||||
},
|
||||
},
|
||||
container: {
|
||||
margin: { left: 12 },
|
||||
}
|
||||
},
|
||||
state: {
|
||||
hovered: {
|
||||
icon: {
|
||||
color: foreground(layer, "hovered")
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
quoteButton: interactive({
|
||||
base: {
|
||||
icon: {
|
||||
color: foreground(layer, "variant"),
|
||||
asset: "icons/quote_15.svg",
|
||||
dimensions: {
|
||||
width: 15,
|
||||
height: 15,
|
||||
},
|
||||
},
|
||||
container: {
|
||||
margin: { left: 12 },
|
||||
}
|
||||
},
|
||||
state: {
|
||||
hovered: {
|
||||
icon: {
|
||||
color: foreground(layer, "hovered")
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
assistButton: interactive({
|
||||
base: {
|
||||
icon: {
|
||||
color: foreground(layer, "variant"),
|
||||
asset: "icons/assist_15.svg",
|
||||
dimensions: {
|
||||
width: 15,
|
||||
height: 15,
|
||||
},
|
||||
},
|
||||
container: {
|
||||
margin: { left: 12, right: 24 },
|
||||
}
|
||||
},
|
||||
state: {
|
||||
hovered: {
|
||||
icon: {
|
||||
color: foreground(layer, "hovered")
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
zoomInButton: interactive({
|
||||
base: {
|
||||
icon: {
|
||||
color: foreground(layer, "variant"),
|
||||
asset: "icons/maximize_8.svg",
|
||||
dimensions: {
|
||||
width: 12,
|
||||
height: 12,
|
||||
},
|
||||
},
|
||||
container: {
|
||||
margin: { right: 12 },
|
||||
}
|
||||
},
|
||||
state: {
|
||||
hovered: {
|
||||
icon: {
|
||||
color: foreground(layer, "hovered")
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
zoomOutButton: interactive({
|
||||
base: {
|
||||
icon: {
|
||||
color: foreground(layer, "variant"),
|
||||
asset: "icons/minimize_8.svg",
|
||||
dimensions: {
|
||||
width: 12,
|
||||
height: 12,
|
||||
},
|
||||
},
|
||||
container: {
|
||||
margin: { right: 12 },
|
||||
}
|
||||
},
|
||||
state: {
|
||||
hovered: {
|
||||
icon: {
|
||||
color: foreground(layer, "hovered")
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
plusButton: interactive({
|
||||
base: {
|
||||
icon: {
|
||||
color: foreground(layer, "variant"),
|
||||
asset: "icons/plus_12.svg",
|
||||
dimensions: {
|
||||
width: 12,
|
||||
height: 12,
|
||||
},
|
||||
},
|
||||
container: {
|
||||
margin: { right: 12 },
|
||||
}
|
||||
},
|
||||
state: {
|
||||
hovered: {
|
||||
icon: {
|
||||
color: foreground(layer, "hovered")
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
title: {
|
||||
margin: { left: 12 },
|
||||
...text(layer, "sans", "default", { size: "sm" })
|
||||
},
|
||||
savedConversation: {
|
||||
container: interactive({
|
||||
base: {
|
||||
background: background(layer, "on"),
|
||||
padding: { top: 4, bottom: 4 }
|
||||
},
|
||||
state: {
|
||||
hovered: {
|
||||
background: background(layer, "on", "hovered"),
|
||||
}
|
||||
},
|
||||
}),
|
||||
savedAt: {
|
||||
margin: { left: 8 },
|
||||
...text(layer, "sans", "default", { size: "xs" }),
|
||||
},
|
||||
title: {
|
||||
margin: { left: 16 },
|
||||
...text(layer, "sans", "default", { size: "sm", weight: "bold" }),
|
||||
}
|
||||
},
|
||||
userSender: {
|
||||
default: {
|
||||
...text(layer, "sans", "default", {
|
||||
@ -43,13 +222,10 @@ export default function assistant(colorScheme: ColorScheme) {
|
||||
margin: { top: 2, left: 8 },
|
||||
...text(layer, "sans", "default", { size: "2xs" }),
|
||||
},
|
||||
modelInfoContainer: {
|
||||
margin: { right: 16, top: 4 },
|
||||
},
|
||||
model: interactive({
|
||||
base: {
|
||||
background: background(layer, "on"),
|
||||
border: border(layer, "on", { overlay: true }),
|
||||
margin: { left: 12, right: 12, top: 12 },
|
||||
padding: 4,
|
||||
cornerRadius: 4,
|
||||
...text(layer, "sans", "default", { size: "xs" }),
|
||||
@ -57,22 +233,21 @@ export default function assistant(colorScheme: ColorScheme) {
|
||||
state: {
|
||||
hovered: {
|
||||
background: background(layer, "on", "hovered"),
|
||||
border: border(layer, "on", { overlay: true }),
|
||||
},
|
||||
},
|
||||
}),
|
||||
remainingTokens: {
|
||||
background: background(layer, "on"),
|
||||
border: border(layer, "on", { overlay: true }),
|
||||
margin: { top: 12, right: 12 },
|
||||
padding: 4,
|
||||
margin: { left: 4 },
|
||||
cornerRadius: 4,
|
||||
...text(layer, "sans", "positive", { size: "xs" }),
|
||||
},
|
||||
noRemainingTokens: {
|
||||
background: background(layer, "on"),
|
||||
border: border(layer, "on", { overlay: true }),
|
||||
margin: { top: 12, right: 12 },
|
||||
padding: 4,
|
||||
margin: { left: 4 },
|
||||
cornerRadius: 4,
|
||||
...text(layer, "sans", "negative", { size: "xs" }),
|
||||
},
|
||||
|
@ -30,7 +30,7 @@ const getTheme = (variant: Variant): ThemeConfig => {
|
||||
return {
|
||||
name: `${meta.name} Forest Light`,
|
||||
author: meta.author,
|
||||
appearance: ThemeAppearance.Dark,
|
||||
appearance: ThemeAppearance.Light,
|
||||
licenseType: meta.licenseType,
|
||||
licenseUrl: meta.licenseUrl,
|
||||
licenseFile: `${__dirname}/LICENSE`,
|
||||
|
Loading…
Reference in New Issue
Block a user