Brings in settings rebuilt after T3 Code: its flat navigation and search, every page's sections and rows with T3's wording and defaults (General, Appearance with the theme cards, Keybindings, Providers in two panes with the Add provider wizard, Integrations, Source Control, Storage, Connections, Archive, Usage, Diagnostics, Open source licenses), per-row resets and Restore device defaults. On top of the merge, the settings it added now take effect: the send shortcut (Enter, Ctrl+Enter for multiline prompts, Ctrl+Enter always), chat width, models hidden from the picker, diff colors in the commit dialog and the panel, sound-only notifications, and the double-press quit message. Project grouping keeps the sidebar's three-way rule behind T3's switch, and Unarchive restores the thread to the sidebar. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Showing 34 changed files with 7054 additions and 2619 deletions.
| @@ -125,7 +125,7 @@ Gruvbox, Rosé Pine, Solarized and Dracula. | ||
| 125 | 125 | branch is then renamed after the first message (Settings → Source Control → Worktree |
| 126 | 126 | branch naming: a prefix plus a few words, a semantic prefix like `feat/`, or your own |
| 127 | 127 | instructions). Ctrl+Shift+L starts in the project's previous worktree instead. |
| 128 | - - Thread titles written by a small model from the first message (Settings → Text generation). | |
| 128 | + - Thread titles written by a small model from the first message (Settings → General → Text generation). | |
| 129 | 129 | - Pin threads to the top, snooze them until later, rename them, archive them to Settings → |
| 130 | 130 | Archive. Working threads can fold into a Working shelf until they need you. |
| 131 | 131 | - When a usage limit stops a thread, it can snooze until the limit resets and continue then. |
| @@ -140,27 +140,47 @@ Gruvbox, Rosé Pine, Solarized and Dracula. | ||
| 140 | 140 | another. The host's projects and threads appear in the sidebar tagged with its name; open, |
| 141 | 141 | continue or start threads there and they run on the host. The connection is a WebSocket |
| 142 | 142 | guarded by the key but not encrypted, so use it on trusted networks or over a VPN. |
| 143 | - - A settings view (Ctrl+, or **Settings** in the sidebar), laid out like T3 Code's: | |
| 144 | - - **General**: what new threads start with (model, reasoning, permissions, workspace, | |
| 145 | - submodules), the text generation model, projects and threads, organization of the | |
| 146 | - sidebar, and confirmations (unpin, settle, delete, and the quit shortcut). | |
| 147 | - - **Behavior**: notifications (desktop, with sound, in-app), time format, response | |
| 148 | - streaming, turn folding and costs, proactive diffs, diff defaults, the composer (skills in | |
| 149 | - the `/` menu, collapsing on scroll, send key, follow-up behavior), update checks, | |
| 150 | - continuing after restarts, background activity, and the editor "Open in" uses. | |
| 151 | - - **Appearance**: comfortable or compact thread cards. | |
| 152 | - - **Themes**: Light, Dark or System mode (System follows the desktop), and a light and a | |
| 153 | - dark theme picked from live previews: Bone and Graphite; Tokyo Night (Night, Storm, Day); | |
| 154 | - Catppuccin (Mocha, Macchiato, Frappé, Latte); GitHub (Dark, Dark Dimmed, Light); One Dark | |
| 155 | - and One Light; Nord; Gruvbox Dark and Light; Rosé Pine (Main, Moon, Dawn); Solarized Dark | |
| 156 | - and Light; and Dracula. | |
| 143 | + - A settings view (Ctrl+, or **Settings** in the sidebar), laid out like T3 Code's: a | |
| 144 | + search field over the pages (press `/` to search, ↑/↓ and Enter to jump to a setting, | |
| 145 | + which scrolls into view and pulses), a "Settings / Page" breadcrumb, and every setting as | |
| 146 | + a row with its description, its control and, once changed, a button that resets it. | |
| 147 | + **Restore device defaults** on General lists what it will reset before it does. | |
| 148 | + - **General**: New threads (model and reasoning, permissions, workspace, submodules); | |
| 149 | + Organization (project grouping and order, auto-resume and snooze for usage-limited | |
| 150 | + threads, the Working section, auto-settling merged and inactive threads); Behavior | |
| 151 | + (thread notifications off, as notifications, as sound or both, in-app notifications, time | |
| 152 | + format, response streaming by token, paragraph or whole turn, turn folding and costs, diff | |
| 153 | + whitespace, file state and Stacked or Split layout, proactive panels, skills in the `/` | |
| 154 | + menu, the rich text composer, collapsing on scroll, the send shortcut (Enter, Ctrl+Enter | |
| 155 | + for multiline prompts, or Ctrl+Enter always), follow-up behavior, update checks, | |
| 156 | + continuing after restarts, background activity); Projects & threads; Confirmations | |
| 157 | + (unpin, archive, delete, and the quit shortcut: Direct, Hold or Double press); the text | |
| 158 | + generation model; the version; Diagnostics (CPU, memory and every process the app | |
| 159 | + started, with interrupt and kill buttons) and the open source licenses; and the folded | |
| 160 | + Legacy features (plan mode, the context window ring, the per-project sidebar). | |
| 161 | + - **Appearance**: System, Light or Dark (System follows the desktop), and a card per theme | |
| 162 | + family whose swatches set the light and the dark theme: Vectrum (Bone and Graphite); Tokyo | |
| 163 | + Night (Day, Night, Storm); Catppuccin (Latte, Mocha, Macchiato, Frappé); GitHub (Light, | |
| 164 | + Dark, Dark Dimmed); One; Nord; Gruvbox; Rosé Pine (Dawn, Main, Moon); Solarized; and | |
| 165 | + Dracula. Then diff colors (red and green, or blue and orange), composer context, chat | |
| 166 | + width and thread cards. | |
| 167 | + - **Keybindings**: the app's shortcuts in T3 Code's groups, searchable, read from the live | |
| 168 | + keymap, with when each applies. | |
| 157 | 169 | - **Providers**: every agent instance (several Claude, Pi or jcode instances side by side, |
| 158 | - say two accounts), each with a switch, its version, login and plan, display name, binary, config | |
| 159 | - folder, launch arguments and environment variables, plus updates and the health check | |
| 160 | - interval, and usage hubs (CLIProxyAPI servers, with their management key). | |
| 170 | + say two accounts) in a list with its status and a switch, and an editor for the selected | |
| 171 | + one: display name and accent color, account, binary, home folder, Claude's auto-compact | |
| 172 | + threshold, launch arguments, environment variables (sensitive ones are kept in a | |
| 173 | + `secrets.json` only you can read), and its models: favorites, which ones the picker | |
| 174 | + shows, their order, and custom models. **Add provider** walks through kind, identity and | |
| 175 | + configuration. Below: usage hubs (CLIProxyAPI servers) and the health check interval. | |
| 176 | + - **Integrations**: whether agents may use the shared browser, and the editor "Open in" uses. | |
| 177 | + - **Source Control**: the git and GitHub CLI found on this machine, and how worktree | |
| 178 | + branches are named (a static prefix, a prefix the model picks, or your instructions). | |
| 179 | + - **Storage**: where new worktrees go, and the app's folders. | |
| 180 | + - **Connections**: remote connections to and from other devices. | |
| 181 | + - **Archive**: settled threads by project, with Unarchive (and Delete on right-click). | |
| 161 | 182 | - **Usage**: cost, tokens and plan limits over the past day, week, month or quarter, read |
| 162 | 183 | from Claude Code's and Pi's local logs and any usage hubs, by provider, model and day. |
| 163 | - - **Connections**, **Keybindings**, an **Archive** of settled threads, and **About**. | |
| 164 | 184 | |
| 165 | 185 | ## Requirements |
| 166 | 186 | |
| @@ -241,7 +261,12 @@ in its `scratch` folder. | ||
| 241 | 261 | - `src/ui/chat.rs`: start screen, transcript (with turn folding), tool cards, permission bar |
| 242 | 262 | and composer. |
| 243 | 263 | - `src/ui/pickers.rs`: the model, reasoning and access pickers. |
| 244 | - - `src/ui/settings.rs`: the settings view and its pages. | |
| 264 | + - `src/ui/settings/`: the settings view (`mod.rs`: nav, search, top bar), the row and | |
| 265 | + section building blocks (`widgets.rs`), the search catalog (`search.rs`) and a file per | |
| 266 | + page. | |
| 267 | + - `assets/licenses.tsv`: the crates the app is built from, with their licenses, for the | |
| 268 | + Open source licenses page (regenerate it from `cargo metadata` after changing | |
| 269 | + dependencies). | |
| 245 | 270 | - `src/ui/changes.rs`: the per-turn change overview and the diff view. |
| 246 | 271 | - `src/ui/workspace.rs`: window root: thread sidebar, top bar and project panel, plus the |
| 247 | 272 | git and editor helpers behind it. Its submodules hold the sidebar (`sidebar.rs`, and the |
| @@ -252,7 +277,7 @@ in its `scratch` folder. | ||
| 252 | 277 | MetalUI's CSS, the theme mapping for the stock widgets, and the primitives (caps, wells, |
| 253 | 278 | keycaps, status LEDs, segmented switch). |
| 254 | 279 | - `src/ui/themes.rs`: the color schemes, the palette builder that turns each into a full |
| 255 | - MetalUI palette, the light/dark/system selection, and the Themes page. | |
| 280 | + MetalUI palette, the light/dark/system selection, and the theme families. | |
| 256 | 281 | - `assets/fonts/`: Geist, Geist Mono and Geist Pixel, embedded in the binary |
| 257 | 282 | (SIL Open Font License, see `assets/fonts/OFL.txt`). |
| 258 | 283 | |
| @@ -0,0 +1,609 @@ | ||
| 1 | + # Crates compiled into Vectrum Code: name, version, license, repository. | |
| 2 | + # Regenerate with cargo metadata (see src/ui/settings/licenses.rs). | |
| 3 | + accesskit 0.24.1 MIT OR Apache-2.0 https://github.com/AccessKit/accesskit | |
| 4 | + accesskit_atspi_common 0.19.1 MIT OR Apache-2.0 https://github.com/AccessKit/accesskit | |
| 5 | + accesskit_consumer 0.38.0 MIT OR Apache-2.0 https://github.com/AccessKit/accesskit | |
| 6 | + accesskit_unix 0.22.1 MIT OR Apache-2.0 https://github.com/AccessKit/accesskit | |
| 7 | + addr2line 0.25.1 Apache-2.0 OR MIT https://github.com/gimli-rs/addr2line | |
| 8 | + adler2 2.0.1 0BSD OR MIT OR Apache-2.0 https://github.com/oyvindln/adler2 | |
| 9 | + aes 0.8.4 MIT OR Apache-2.0 https://github.com/RustCrypto/block-ciphers | |
| 10 | + ahash 0.8.12 MIT OR Apache-2.0 https://github.com/tkaitchuck/ahash | |
| 11 | + aho-corasick 1.1.5 Unlicense OR MIT https://github.com/BurntSushi/aho-corasick | |
| 12 | + aligned 0.4.3 MIT OR Apache-2.0 https://github.com/rust-embedded-community/aligned | |
| 13 | + aligned-vec 0.6.4 MIT https://github.com/sarah-ek/aligned-vec/ | |
| 14 | + allocator-api2 0.2.21 MIT OR Apache-2.0 https://github.com/zakarumych/allocator-api2 | |
| 15 | + annotate-snippets 0.12.16 MIT OR Apache-2.0 https://github.com/rust-lang/annotate-snippets-rs | |
| 16 | + anstyle 1.0.14 MIT OR Apache-2.0 https://github.com/rust-cli/anstyle.git | |
| 17 | + anyhow 1.0.104 MIT OR Apache-2.0 https://github.com/dtolnay/anyhow | |
| 18 | + arc-swap 1.9.2 MIT OR Apache-2.0 https://github.com/vorner/arc-swap | |
| 19 | + arg_enum_proc_macro 0.3.4 MIT https://github.com/lu-zero/arg_enum_proc_macro | |
| 20 | + arraydeque 0.5.1 MIT OR Apache-2.0 https://github.com/andylokandy/arraydeque | |
| 21 | + arrayref 0.3.9 BSD-2-Clause https://github.com/droundy/arrayref | |
| 22 | + arrayvec 0.7.8 MIT OR Apache-2.0 https://github.com/bluss/arrayvec | |
| 23 | + as-raw-xcb-connection 1.0.1 MIT OR Apache-2.0 https://github.com/psychon/as-raw-xcb-connection | |
| 24 | + as-slice 0.2.1 MIT OR Apache-2.0 https://github.com/japaric/as-slice | |
| 25 | + ash 0.38.0+1.3.281 MIT OR Apache-2.0 https://github.com/ash-rs/ash | |
| 26 | + ashpd 0.13.13 MIT https://github.com/bilelmoussaoui/ashpd | |
| 27 | + async-broadcast 0.7.2 MIT OR Apache-2.0 https://github.com/smol-rs/async-broadcast | |
| 28 | + async-channel 2.5.0 Apache-2.0 OR MIT https://github.com/smol-rs/async-channel | |
| 29 | + async-compression 0.4.50 MIT OR Apache-2.0 https://github.com/Nullus157/async-compression | |
| 30 | + async-executor 1.14.0 Apache-2.0 OR MIT https://github.com/smol-rs/async-executor | |
| 31 | + async-fs 2.2.0 Apache-2.0 OR MIT https://github.com/smol-rs/async-fs | |
| 32 | + async-io 2.6.0 Apache-2.0 OR MIT https://github.com/smol-rs/async-io | |
| 33 | + async-lock 3.4.2 Apache-2.0 OR MIT https://github.com/smol-rs/async-lock | |
| 34 | + async-net 2.0.0 Apache-2.0 OR MIT https://github.com/smol-rs/async-net | |
| 35 | + async-process 2.5.0 Apache-2.0 OR MIT https://github.com/smol-rs/async-process | |
| 36 | + async-recursion 1.2.0 MIT OR Apache-2.0 https://github.com/dcchut/async-recursion | |
| 37 | + async-signal 0.2.14 Apache-2.0 OR MIT https://github.com/smol-rs/async-signal | |
| 38 | + async-task 4.7.1 Apache-2.0 OR MIT https://github.com/smol-rs/async-task | |
| 39 | + async-trait 0.1.92 MIT OR Apache-2.0 https://github.com/dtolnay/async-trait | |
| 40 | + atomic 0.5.3 Apache-2.0 OR MIT https://github.com/Amanieu/atomic-rs | |
| 41 | + atomic-waker 1.1.2 Apache-2.0 OR MIT https://github.com/smol-rs/atomic-waker | |
| 42 | + atspi 0.29.0 Apache-2.0 OR MIT https://github.com/odilia-app/atspi | |
| 43 | + atspi-common 0.13.0 Apache-2.0 OR MIT https://github.com/odilia-app/atspi | |
| 44 | + atspi-proxies 0.13.0 Apache-2.0 OR MIT https://github.com/odilia-app/atspi | |
| 45 | + autocfg 1.5.1 Apache-2.0 OR MIT https://github.com/cuviper/autocfg | |
| 46 | + av-scenechange 0.14.1 MIT https://github.com/rust-av/av-scenechange | |
| 47 | + av1-grain 0.2.5 BSD-2-Clause https://github.com/rust-av/av1-grain | |
| 48 | + avif-serialize 0.8.9 BSD-3-Clause https://github.com/kornelski/avif-serialize | |
| 49 | + backtrace 0.3.76 MIT OR Apache-2.0 https://github.com/rust-lang/backtrace-rs | |
| 50 | + base62 2.2.6 MIT https://github.com/fbernier/base62 | |
| 51 | + base64 0.22.1 MIT OR Apache-2.0 https://github.com/marshallpierce/rust-base64 | |
| 52 | + base64 0.23.1 MIT OR Apache-2.0 https://github.com/marshallpierce/rust-base64 | |
| 53 | + bit-set 0.9.1 Apache-2.0 OR MIT https://github.com/contain-rs/bit-set | |
| 54 | + bit-vec 0.9.1 Apache-2.0 OR MIT https://github.com/contain-rs/bit-vec | |
| 55 | + bit_field 0.10.3 Apache-2.0 OR MIT https://github.com/phil-opp/rust-bit-field | |
| 56 | + bitflags 1.3.2 MIT OR Apache-2.0 https://github.com/bitflags/bitflags | |
| 57 | + bitflags 2.13.2 MIT OR Apache-2.0 https://github.com/bitflags/bitflags | |
| 58 | + bitstream-io 4.10.0 MIT OR Apache-2.0 https://github.com/tuffy/bitstream-io | |
| 59 | + block-buffer 0.10.4 MIT OR Apache-2.0 https://github.com/RustCrypto/utils | |
| 60 | + block-buffer 0.12.1 MIT OR Apache-2.0 https://github.com/RustCrypto/utils | |
| 61 | + block-padding 0.3.3 MIT OR Apache-2.0 https://github.com/RustCrypto/utils | |
| 62 | + blocking 1.7.0 Apache-2.0 OR MIT https://github.com/smol-rs/blocking | |
| 63 | + bstr 1.13.1 MIT OR Apache-2.0 https://github.com/BurntSushi/bstr | |
| 64 | + built 0.8.1 MIT https://github.com/lukaslueg/built | |
| 65 | + bumpalo 3.20.3 MIT OR Apache-2.0 https://github.com/fitzgen/bumpalo | |
| 66 | + bytemuck 1.25.2 Zlib OR Apache-2.0 OR MIT https://github.com/Lokathor/bytemuck | |
| 67 | + bytemuck_derive 1.12.1 Zlib OR Apache-2.0 OR MIT https://github.com/Lokathor/bytemuck | |
| 68 | + byteorder 1.5.0 Unlicense OR MIT https://github.com/BurntSushi/byteorder | |
| 69 | + byteorder-lite 0.1.0 Unlicense OR MIT https://github.com/image-rs/byteorder-lite | |
| 70 | + bytes 1.12.1 MIT https://github.com/tokio-rs/bytes | |
| 71 | + bzip2 0.6.1 MIT OR Apache-2.0 https://github.com/trifectatechfoundation/bzip2-rs | |
| 72 | + calloop 0.14.5 MIT https://github.com/Smithay/calloop | |
| 73 | + calloop-wayland-source 0.4.1 MIT https://github.com/smithay/calloop-wayland-source | |
| 74 | + cbc 0.1.2 MIT OR Apache-2.0 https://github.com/RustCrypto/block-modes | |
| 75 | + cc 1.6.0 MIT OR Apache-2.0 https://github.com/rust-lang/cc-rs | |
| 76 | + cfg-if 1.0.5 MIT OR Apache-2.0 https://github.com/rust-lang/cfg-if | |
| 77 | + cfg_aliases 0.2.2 MIT https://github.com/katharostech/cfg_aliases | |
| 78 | + chacha20 0.10.2 MIT OR Apache-2.0 https://github.com/RustCrypto/stream-ciphers | |
| 79 | + chrono 0.4.45 MIT OR Apache-2.0 https://github.com/chronotope/chrono | |
| 80 | + cipher 0.4.4 MIT OR Apache-2.0 https://github.com/RustCrypto/traits | |
| 81 | + codespan-reporting 0.13.1 Apache-2.0 https://github.com/brendanzab/codespan | |
| 82 | + color_quant 1.1.0 MIT https://github.com/image-rs/color_quant.git | |
| 83 | + compression-codecs 0.4.45 MIT OR Apache-2.0 https://github.com/Nullus157/async-compression | |
| 84 | + compression-core 0.4.33 MIT OR Apache-2.0 https://github.com/Nullus157/async-compression | |
| 85 | + concurrent-queue 2.5.0 Apache-2.0 OR MIT https://github.com/smol-rs/concurrent-queue | |
| 86 | + const-oid 0.10.2 Apache-2.0 OR MIT https://github.com/RustCrypto/formats | |
| 87 | + const-random 0.1.18 MIT OR Apache-2.0 https://github.com/tkaitchuck/constrandom | |
| 88 | + const-random-macro 0.1.16 MIT OR Apache-2.0 https://github.com/tkaitchuck/constrandom | |
| 89 | + convert_case 0.10.0 MIT https://github.com/rutrum/convert-case | |
| 90 | + core_detect 1.0.0 MIT OR Apache-2.0 https://github.com/thomcc/core_detect | |
| 91 | + core_maths 0.1.1 MIT https://github.com/robertbastian/core_maths | |
| 92 | + cosmic-text 0.19.0 MIT OR Apache-2.0 https://github.com/pop-os/cosmic-text | |
| 93 | + cpufeatures 0.2.17 MIT OR Apache-2.0 https://github.com/RustCrypto/utils | |
| 94 | + cpufeatures 0.3.1 MIT OR Apache-2.0 https://github.com/RustCrypto/utils | |
| 95 | + crc32fast 1.5.2 MIT OR Apache-2.0 https://github.com/srijs/rust-crc32fast | |
| 96 | + crossbeam-deque 0.8.8 MIT OR Apache-2.0 https://github.com/crossbeam-rs/crossbeam | |
| 97 | + crossbeam-epoch 0.9.21 MIT OR Apache-2.0 https://github.com/crossbeam-rs/crossbeam | |
| 98 | + crossbeam-queue 0.3.14 MIT OR Apache-2.0 https://github.com/crossbeam-rs/crossbeam | |
| 99 | + crossbeam-utils 0.8.23 MIT OR Apache-2.0 https://github.com/crossbeam-rs/crossbeam | |
| 100 | + crunchy 0.2.4 MIT https://github.com/eira-fransham/crunchy | |
| 101 | + crypto-common 0.1.7 MIT OR Apache-2.0 https://github.com/RustCrypto/traits | |
| 102 | + crypto-common 0.2.2 MIT OR Apache-2.0 https://github.com/RustCrypto/traits | |
| 103 | + ctor 1.0.13 Apache-2.0 OR MIT https://github.com/mmastrac/linktime | |
| 104 | + data-encoding 2.11.1 MIT https://github.com/ia0/data-encoding | |
| 105 | + data-url 0.3.2 MIT OR Apache-2.0 https://github.com/servo/rust-url | |
| 106 | + derive_more 2.1.1 MIT https://github.com/JelteF/derive_more | |
| 107 | + derive_more-impl 2.1.1 MIT https://github.com/JelteF/derive_more | |
| 108 | + digest 0.10.7 MIT OR Apache-2.0 https://github.com/RustCrypto/traits | |
| 109 | + digest 0.11.3 MIT OR Apache-2.0 https://github.com/RustCrypto/traits | |
| 110 | + dirs 5.0.1 MIT OR Apache-2.0 https://github.com/soc/dirs-rs | |
| 111 | + dirs 6.0.0 MIT OR Apache-2.0 https://github.com/soc/dirs-rs | |
| 112 | + dirs-sys 0.4.1 MIT OR Apache-2.0 https://github.com/dirs-dev/dirs-sys-rs | |
| 113 | + dirs-sys 0.5.0 MIT OR Apache-2.0 https://github.com/dirs-dev/dirs-sys-rs | |
| 114 | + displaydoc 0.2.7 MIT OR Apache-2.0 https://github.com/yaahc/displaydoc | |
| 115 | + dlib 0.5.3 MIT https://github.com/elinorbgr/dlib | |
| 116 | + document-features 0.2.12 MIT OR Apache-2.0 https://github.com/slint-ui/document-features | |
| 117 | + downcast-rs 1.2.1 MIT OR Apache-2.0 https://github.com/marcianx/downcast-rs | |
| 118 | + dyn-clone 1.0.20 MIT OR Apache-2.0 https://github.com/dtolnay/dyn-clone | |
| 119 | + either 1.19.0 MIT OR Apache-2.0 https://github.com/rayon-rs/either | |
| 120 | + embed-resource 3.0.12 MIT https://github.com/nabijaczleweli/rust-embed-resource | |
| 121 | + encoding_rs 0.8.42 (Apache-2.0 OR MIT) AND BSD-3-Clause https://github.com/hsivonen/encoding_rs | |
| 122 | + encoding_rs_io 0.1.8 MIT OR Apache-2.0 https://github.com/BurntSushi/encoding_rs_io | |
| 123 | + endi 1.1.1 MIT https://github.com/zeenix/endi | |
| 124 | + enum-iterator 2.3.0 0BSD https://github.com/stephaneyfx/enum-iterator.git | |
| 125 | + enum-iterator-derive 1.5.0 0BSD https://github.com/stephaneyfx/enum-iterator.git | |
| 126 | + enumflags2 0.7.12 MIT OR Apache-2.0 https://github.com/meithecatte/enumflags2 | |
| 127 | + enumflags2_derive 0.7.12 MIT OR Apache-2.0 https://github.com/meithecatte/enumflags2 | |
| 128 | + enumn 0.1.14 MIT OR Apache-2.0 https://github.com/dtolnay/enumn | |
| 129 | + equator 0.4.2 MIT https://github.com/sarah-ek/equator/ | |
| 130 | + equator-macro 0.4.2 MIT https://github.com/sarah-ek/equator/ | |
| 131 | + equivalent 1.0.2 Apache-2.0 OR MIT https://github.com/indexmap-rs/equivalent | |
| 132 | + erased-serde 0.4.10 MIT OR Apache-2.0 https://github.com/dtolnay/erased-serde | |
| 133 | + errno 0.3.14 MIT OR Apache-2.0 https://github.com/lambda-fairy/rust-errno | |
| 134 | + etagere 0.2.15 MIT OR Apache-2.0 https://github.com/nical/etagere | |
| 135 | + euclid 0.22.14 MIT OR Apache-2.0 https://github.com/servo/euclid | |
| 136 | + event-listener 5.4.2 Apache-2.0 OR MIT https://github.com/smol-rs/event-listener | |
| 137 | + event-listener-strategy 0.5.4 Apache-2.0 OR MIT https://github.com/smol-rs/event-listener-strategy | |
| 138 | + exr 1.74.2 BSD-3-Clause https://github.com/johannesvollmer/exrs | |
| 139 | + fastrand 2.5.0 Apache-2.0 OR MIT https://github.com/smol-rs/fastrand | |
| 140 | + fax 0.2.7 MIT https://github.com/pdf-rs/fax | |
| 141 | + fdeflate 0.3.7 MIT OR Apache-2.0 https://github.com/image-rs/fdeflate | |
| 142 | + filedescriptor 0.8.3 MIT https://github.com/wezterm/wezterm | |
| 143 | + find-msvc-tools 0.1.14 MIT OR Apache-2.0 https://github.com/rust-lang/cc-rs | |
| 144 | + fixedbitset 0.5.7 MIT OR Apache-2.0 https://github.com/petgraph/fixedbitset | |
| 145 | + flate2 1.1.10 MIT OR Apache-2.0 https://github.com/rust-lang/flate2-rs | |
| 146 | + float-cmp 0.9.0 MIT https://github.com/mikedilger/float-cmp | |
| 147 | + float-ord 0.3.2 MIT OR Apache-2.0 https://github.com/notriddle/rust-float-ord | |
| 148 | + float_next_after 1.0.0 MIT https://gitlab.com/bronsonbdevost/next_afterf | |
| 149 | + fluent-uri 0.1.4 MIT https://github.com/yescallop/fluent-uri-rs | |
| 150 | + flume 0.12.0 Apache-2.0 OR MIT https://github.com/zesterer/flume | |
| 151 | + foldhash 0.1.5 Zlib https://github.com/orlp/foldhash | |
| 152 | + foldhash 0.2.0 Zlib https://github.com/orlp/foldhash | |
| 153 | + font-types 0.11.3 MIT OR Apache-2.0 https://github.com/googlefonts/fontations | |
| 154 | + font-types 0.12.6 MIT OR Apache-2.0 https://github.com/googlefonts/fontations | |
| 155 | + fontconfig-parser 0.5.8 MIT https://github.com/Riey/fontconfig-parser | |
| 156 | + fontdb 0.23.0 MIT https://github.com/RazrFalcon/fontdb | |
| 157 | + form_urlencoded 1.2.2 MIT OR Apache-2.0 https://github.com/servo/rust-url | |
| 158 | + freetype-sys 0.20.1 MIT https://github.com/PistonDevelopers/freetype-sys.git | |
| 159 | + futf 0.1.5 MIT OR Apache-2.0 https://github.com/servo/futf | |
| 160 | + futures 0.3.34 MIT OR Apache-2.0 https://github.com/rust-lang/futures-rs | |
| 161 | + futures-channel 0.3.34 MIT OR Apache-2.0 https://github.com/rust-lang/futures-rs | |
| 162 | + futures-concurrency 7.7.1 MIT OR Apache-2.0 https://github.com/yoshuawuyts/futures-concurrency | |
| 163 | + futures-core 0.3.34 MIT OR Apache-2.0 https://github.com/rust-lang/futures-rs | |
| 164 | + futures-executor 0.3.34 MIT OR Apache-2.0 https://github.com/rust-lang/futures-rs | |
| 165 | + futures-io 0.3.34 MIT OR Apache-2.0 https://github.com/rust-lang/futures-rs | |
| 166 | + futures-lite 2.6.1 Apache-2.0 OR MIT https://github.com/smol-rs/futures-lite | |
| 167 | + futures-macro 0.3.34 MIT OR Apache-2.0 https://github.com/rust-lang/futures-rs | |
| 168 | + futures-sink 0.3.34 MIT OR Apache-2.0 https://github.com/rust-lang/futures-rs | |
| 169 | + futures-task 0.3.34 MIT OR Apache-2.0 https://github.com/rust-lang/futures-rs | |
| 170 | + futures-util 0.3.34 MIT OR Apache-2.0 https://github.com/rust-lang/futures-rs | |
| 171 | + generic-array 0.14.7 MIT https://github.com/fizyk20/generic-array.git | |
| 172 | + gethostname 1.1.0 Apache-2.0 https://codeberg.org/swsnr/gethostname.rs.git | |
| 173 | + getrandom 0.2.17 MIT OR Apache-2.0 https://github.com/rust-random/getrandom | |
| 174 | + getrandom 0.3.4 MIT OR Apache-2.0 https://github.com/rust-random/getrandom | |
| 175 | + getrandom 0.4.3 MIT OR Apache-2.0 https://github.com/rust-random/getrandom | |
| 176 | + gif 0.14.2 MIT OR Apache-2.0 https://github.com/image-rs/image-gif | |
| 177 | + gimli 0.32.3 MIT OR Apache-2.0 https://github.com/gimli-rs/gimli | |
| 178 | + glob 0.3.4 MIT OR Apache-2.0 https://github.com/rust-lang/glob | |
| 179 | + globset 0.4.20 Unlicense OR MIT https://github.com/BurntSushi/ripgrep/tree/master/crates/globset | |
| 180 | + globwalk 0.8.1 MIT https://github.com/gilnaa/globwalk | |
| 181 | + glow 0.17.0 MIT OR Apache-2.0 OR Zlib https://github.com/grovesNL/glow | |
| 182 | + gpu-allocator 0.28.0 MIT OR Apache-2.0 https://github.com/Traverse-Research/gpu-allocator | |
| 183 | + gpu-descriptor 0.3.2 MIT OR Apache-2.0 https://github.com/zakarumych/gpu-descriptor | |
| 184 | + gpu-descriptor-types 0.2.0 MIT OR Apache-2.0 https://github.com/zakarumych/gpu-descriptor | |
| 185 | + gpui-base 0.7.1 Apache-2.0 https://github.com/longbridge/gpui-kit | |
| 186 | + gpui-component 0.7.1 Apache-2.0 https://github.com/longbridge/gpui-kit | |
| 187 | + gpui-component-macros 0.7.1 Apache-2.0 | |
| 188 | + gpui-kit 0.7.1 Apache-2.0 https://github.com/longbridge/gpui-kit | |
| 189 | + gpui-kit-assets 0.7.1 Apache-2.0 https://github.com/longbridge/gpui-kit | |
| 190 | + gpui-pre 0.3.8 Apache-2.0 https://github.com/zed-industries/zed | |
| 191 | + gpui-pre-collections 0.3.8 Apache-2.0 https://github.com/zed-industries/zed | |
| 192 | + gpui-pre-derive-refineable 0.3.8 Apache-2.0 https://github.com/zed-industries/zed | |
| 193 | + gpui-pre-http-client 0.3.8 Apache-2.0 https://github.com/zed-industries/zed | |
| 194 | + gpui-pre-linux 0.3.8 Apache-2.0 https://github.com/zed-industries/zed | |
| 195 | + gpui-pre-macros 0.3.8 Apache-2.0 https://github.com/zed-industries/zed | |
| 196 | + gpui-pre-perf 0.3.8 Apache-2.0 https://github.com/zed-industries/zed | |
| 197 | + gpui-pre-platform 0.3.8 Apache-2.0 https://github.com/zed-industries/zed | |
| 198 | + gpui-pre-refineable 0.3.8 Apache-2.0 https://github.com/zed-industries/zed | |
| 199 | + gpui-pre-scheduler 0.3.8 Apache-2.0 https://github.com/zed-industries/zed | |
| 200 | + gpui-pre-shared-string 0.3.8 Apache-2.0 https://github.com/zed-industries/zed | |
| 201 | + gpui-pre-sum-tree 0.3.8 Apache-2.0 https://github.com/zed-industries/zed | |
| 202 | + gpui-pre-util 0.3.8 Apache-2.0 https://github.com/zed-industries/zed | |
| 203 | + gpui-pre-util-macros 0.3.8 Apache-2.0 https://github.com/zed-industries/zed | |
| 204 | + gpui-pre-wgpu 0.3.8 Apache-2.0 https://github.com/zed-industries/zed | |
| 205 | + gpui-pre-zlog 0.3.8 Apache-2.0 https://github.com/zed-industries/zed | |
| 206 | + gpui-pre-ztracing 0.3.8 Apache-2.0 https://github.com/zed-industries/zed | |
| 207 | + gpui-pre-ztracing-macro 0.3.8 Apache-2.0 https://github.com/zed-industries/zed | |
| 208 | + granit-parser 1.3.0 MIT OR Apache-2.0 https://github.com/bourumir-wyngs/granit-parser | |
| 209 | + half 2.7.1 MIT OR Apache-2.0 https://github.com/VoidStarKat/half-rs | |
| 210 | + harfrust 0.5.2 MIT https://github.com/harfbuzz/harfrust | |
| 211 | + hash32 0.3.1 MIT OR Apache-2.0 https://github.com/japaric/hash32 | |
| 212 | + hashbrown 0.14.5 MIT OR Apache-2.0 https://github.com/rust-lang/hashbrown | |
| 213 | + hashbrown 0.15.5 MIT OR Apache-2.0 https://github.com/rust-lang/hashbrown | |
| 214 | + hashbrown 0.16.1 MIT OR Apache-2.0 https://github.com/rust-lang/hashbrown | |
| 215 | + hashbrown 0.17.1 MIT OR Apache-2.0 https://github.com/rust-lang/hashbrown | |
| 216 | + heapless 0.9.3 MIT OR Apache-2.0 https://github.com/rust-embedded/heapless | |
| 217 | + heck 0.5.0 MIT OR Apache-2.0 https://github.com/withoutboats/heck | |
| 218 | + hex 0.4.3 MIT OR Apache-2.0 https://github.com/KokaKiwi/rust-hex | |
| 219 | + hexf-parse 0.2.1 CC0-1.0 https://github.com/lifthrasiir/hexf | |
| 220 | + hkdf 0.12.4 MIT OR Apache-2.0 https://github.com/RustCrypto/KDFs/ | |
| 221 | + hmac 0.12.1 MIT OR Apache-2.0 https://github.com/RustCrypto/MACs | |
| 222 | + html5ever 0.27.0 MIT OR Apache-2.0 https://github.com/servo/html5ever | |
| 223 | + http 1.5.0 MIT OR Apache-2.0 https://github.com/hyperium/http | |
| 224 | + http-body 1.1.0 MIT https://github.com/hyperium/http-body | |
| 225 | + httparse 1.10.1 MIT OR Apache-2.0 https://github.com/seanmonstar/httparse | |
| 226 | + hybrid-array 0.4.15 MIT OR Apache-2.0 https://github.com/RustCrypto/hybrid-array | |
| 227 | + iana-time-zone 0.1.65 MIT OR Apache-2.0 https://github.com/strawlab/iana-time-zone | |
| 228 | + icu_collections 2.3.0 Unicode-3.0 https://github.com/unicode-org/icu4x | |
| 229 | + icu_locale_core 2.3.0 Unicode-3.0 https://github.com/unicode-org/icu4x | |
| 230 | + icu_normalizer 2.3.0 Unicode-3.0 https://github.com/unicode-org/icu4x | |
| 231 | + icu_normalizer_data 2.3.0 Unicode-3.0 https://github.com/unicode-org/icu4x | |
| 232 | + icu_properties 2.3.0 Unicode-3.0 https://github.com/unicode-org/icu4x | |
| 233 | + icu_properties_data 2.3.0 Unicode-3.0 https://github.com/unicode-org/icu4x | |
| 234 | + icu_provider 2.3.1 Unicode-3.0 https://github.com/unicode-org/icu4x | |
| 235 | + idna 1.1.0 MIT OR Apache-2.0 https://github.com/servo/rust-url/ | |
| 236 | + idna_adapter 1.2.2 Apache-2.0 OR MIT https://github.com/hsivonen/idna_adapter | |
| 237 | + ignore 0.4.33 Unlicense OR MIT https://github.com/BurntSushi/ripgrep/tree/master/crates/ignore | |
| 238 | + image 0.25.10 MIT OR Apache-2.0 https://github.com/image-rs/image | |
| 239 | + image-webp 0.2.4 MIT OR Apache-2.0 https://github.com/image-rs/image-webp | |
| 240 | + imagesize 0.14.0 MIT https://github.com/Roughsketch/imagesize | |
| 241 | + imgref 1.12.3 CC0-1.0 OR Apache-2.0 https://github.com/kornelski/imgref | |
| 242 | + indexmap 2.14.2 Apache-2.0 OR MIT https://github.com/indexmap-rs/indexmap | |
| 243 | + inotify 0.11.5 ISC https://github.com/hannobraun/inotify-rs | |
| 244 | + inotify-sys 0.1.8 ISC https://github.com/hannobraun/inotify-sys | |
| 245 | + inout 0.1.4 MIT OR Apache-2.0 https://github.com/RustCrypto/utils | |
| 246 | + instant 0.1.13 BSD-3-Clause https://github.com/sebcrozet/instant | |
| 247 | + inventory 0.3.25 MIT OR Apache-2.0 https://github.com/dtolnay/inventory | |
| 248 | + is-docker 0.2.0 MIT https://github.com/TheLarkInn/is-docker | |
| 249 | + is-wsl 0.4.0 MIT https://github.com/TheLarkInn/is-wsl | |
| 250 | + itertools 0.11.0 MIT OR Apache-2.0 https://github.com/rust-itertools/itertools | |
| 251 | + itertools 0.13.0 MIT OR Apache-2.0 https://github.com/rust-itertools/itertools | |
| 252 | + itertools 0.14.0 MIT OR Apache-2.0 https://github.com/rust-itertools/itertools | |
| 253 | + itoa 1.0.18 MIT OR Apache-2.0 https://github.com/dtolnay/itoa | |
| 254 | + jobserver 0.1.35 MIT OR Apache-2.0 https://github.com/rust-lang/jobserver-rs | |
| 255 | + khronos-egl 6.0.0 MIT OR Apache-2.0 https://github.com/timothee-haudebourg/khronos-egl | |
| 256 | + kurbo 0.13.1 Apache-2.0 OR MIT https://github.com/linebender/kurbo | |
| 257 | + lazy_static 1.5.1 MIT OR Apache-2.0 https://github.com/rust-lang-nursery/lazy-static.rs | |
| 258 | + lebe 0.5.3 BSD-3-Clause https://github.com/johannesvollmer/lebe | |
| 259 | + libbz2-rs-sys 0.2.5 bzip2-1.0.6 https://github.com/trifectatechfoundation/libbzip2-rs | |
| 260 | + libc 0.2.190 MIT OR Apache-2.0 https://github.com/rust-lang/libc | |
| 261 | + libloading 0.8.9 ISC https://github.com/nagisa/rust_libloading/ | |
| 262 | + libm 0.2.16 MIT https://github.com/rust-lang/compiler-builtins | |
| 263 | + linebender_resource_handle 0.1.1 Apache-2.0 OR MIT https://github.com/linebender/raw_resource_handle | |
| 264 | + link-section 0.19.3 Apache-2.0 OR MIT https://github.com/mmastrac/linktime | |
| 265 | + linktime-proc-macro 0.2.3 Apache-2.0 OR MIT https://github.com/mmastrac/linktime | |
| 266 | + linux-raw-sys 0.12.1 Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT https://github.com/sunfishcode/linux-raw-sys | |
| 267 | + litemap 0.8.3 Unicode-3.0 https://github.com/unicode-org/icu4x | |
| 268 | + litrs 1.0.0 MIT OR Apache-2.0 https://github.com/LukasKalbertodt/litrs | |
| 269 | + lock_api 0.4.14 MIT OR Apache-2.0 https://github.com/Amanieu/parking_lot | |
| 270 | + log 0.4.34 MIT OR Apache-2.0 https://github.com/rust-lang/log | |
| 271 | + loop9 0.1.5 MIT https://gitlab.com/kornelski/loop9.git | |
| 272 | + lsp-types 0.97.0 MIT https://github.com/gluon-lang/lsp-types | |
| 273 | + lyon 1.0.19 MIT OR Apache-2.0 https://github.com/nical/lyon | |
| 274 | + lyon_algorithms 1.0.21 MIT OR Apache-2.0 https://github.com/nical/lyon | |
| 275 | + lyon_geom 1.0.19 MIT OR Apache-2.0 https://github.com/nical/lyon | |
| 276 | + lyon_path 1.0.19 MIT OR Apache-2.0 https://github.com/nical/lyon | |
| 277 | + lyon_tessellation 1.0.22 MIT OR Apache-2.0 https://github.com/nical/lyon | |
| 278 | + mac 0.1.1 MIT OR Apache-2.0 https://github.com/reem/rust-mac.git | |
| 279 | + markdown 1.0.0 MIT https://github.com/wooorm/markdown-rs | |
| 280 | + markup5ever 0.12.1 MIT OR Apache-2.0 https://github.com/servo/html5ever | |
| 281 | + markup5ever_rcdom 0.3.0 MIT OR Apache-2.0 https://github.com/servo/html5ever | |
| 282 | + maybe-rayon 0.1.1 MIT https://github.com/shssoichiro/maybe-rayon | |
| 283 | + md-5 0.10.6 MIT OR Apache-2.0 https://github.com/RustCrypto/hashes | |
| 284 | + memchr 2.8.3 Unlicense OR MIT https://github.com/BurntSushi/memchr | |
| 285 | + memmap2 0.9.11 MIT OR Apache-2.0 https://github.com/RazrFalcon/memmap2-rs | |
| 286 | + mime 0.3.17 MIT OR Apache-2.0 https://github.com/hyperium/mime | |
| 287 | + mime_guess 2.0.5 MIT https://github.com/abonander/mime_guess | |
| 288 | + miniz_oxide 0.8.9 MIT OR Zlib OR Apache-2.0 https://github.com/Frommi/miniz_oxide/tree/master/miniz_oxide | |
| 289 | + miniz_oxide 0.9.1 MIT OR Zlib OR Apache-2.0 https://github.com/Frommi/miniz_oxide/tree/master/miniz_oxide | |
| 290 | + mio 1.2.4 MIT https://github.com/tokio-rs/mio | |
| 291 | + moxcms 0.8.1 BSD-3-Clause OR Apache-2.0 https://github.com/awxkee/moxcms.git | |
| 292 | + multiversion_no_op 1.0.0 Apache-2.0 OR MIT https://github.com/hsivonen/multiversion_no_op | |
| 293 | + naga 29.0.4 MIT OR Apache-2.0 https://github.com/gfx-rs/wgpu | |
| 294 | + new_debug_unreachable 1.0.6 MIT https://github.com/mbrubeck/rust-debug-unreachable | |
| 295 | + no_std_io2 0.9.4 Apache-2.0 OR MIT https://github.com/wcampbell0x2a/no-std-io2 | |
| 296 | + nohash-hasher 0.2.0 Apache-2.0 OR MIT https://github.com/paritytech/nohash-hasher | |
| 297 | + nom 8.0.0 MIT https://github.com/rust-bakery/nom | |
| 298 | + noop_proc_macro 0.3.0 MIT https://github.com/lu-zero/noop_proc_macro | |
| 299 | + normpath 1.5.2 MIT OR Apache-2.0 https://github.com/dylni/normpath | |
| 300 | + notify 8.2.0 CC0-1.0 https://github.com/notify-rs/notify.git | |
| 301 | + notify-rust 4.18.2 MIT OR Apache-2.0 https://github.com/hoodie/notify-rust | |
| 302 | + notify-types 2.1.0 MIT OR Apache-2.0 https://github.com/notify-rs/notify.git | |
| 303 | + nu-ansi-term 0.50.3 MIT https://github.com/nushell/nu-ansi-term | |
| 304 | + num 0.4.3 MIT OR Apache-2.0 https://github.com/rust-num/num | |
| 305 | + num-bigint 0.4.8 MIT OR Apache-2.0 https://github.com/rust-num/num-bigint | |
| 306 | + num-bigint-dig 0.9.1 MIT OR Apache-2.0 https://github.com/dignifiedquire/num-bigint | |
| 307 | + num-complex 0.4.6 MIT OR Apache-2.0 https://github.com/rust-num/num-complex | |
| 308 | + num-derive 0.4.2 MIT OR Apache-2.0 https://github.com/rust-num/num-derive | |
| 309 | + num-integer 0.1.47 MIT OR Apache-2.0 https://github.com/rust-num/num-integer | |
| 310 | + num-iter 0.1.46 MIT OR Apache-2.0 https://github.com/rust-num/num-iter | |
| 311 | + num-rational 0.4.2 MIT OR Apache-2.0 https://github.com/rust-num/num-rational | |
| 312 | + num-traits 0.2.19 MIT OR Apache-2.0 https://github.com/rust-num/num-traits | |
| 313 | + num_cpus 1.17.0 MIT OR Apache-2.0 https://github.com/seanmonstar/num_cpus | |
| 314 | + object 0.37.3 Apache-2.0 OR MIT https://github.com/gimli-rs/object | |
| 315 | + once_cell 1.21.4 MIT OR Apache-2.0 https://github.com/matklad/once_cell | |
| 316 | + oo7 0.6.0 MIT https://github.com/linux-credentials/oo7 | |
| 317 | + open 5.4.4 MIT https://github.com/Byron/open-rs | |
| 318 | + option-ext 0.2.0 MPL-2.0 https://github.com/soc/option-ext.git | |
| 319 | + ordered-float 5.5.0 MIT https://github.com/reem/rust-ordered-float | |
| 320 | + ordered-stream 0.2.0 MIT OR Apache-2.0 https://github.com/danieldg/ordered-stream | |
| 321 | + parking 2.2.1 Apache-2.0 OR MIT https://github.com/smol-rs/parking | |
| 322 | + parking_lot 0.12.5 MIT OR Apache-2.0 https://github.com/Amanieu/parking_lot | |
| 323 | + parking_lot_core 0.9.12 MIT OR Apache-2.0 https://github.com/Amanieu/parking_lot | |
| 324 | + paste 1.0.15 MIT OR Apache-2.0 https://github.com/dtolnay/paste | |
| 325 | + pastey 0.1.1 MIT OR Apache-2.0 https://github.com/as1100k/pastey | |
| 326 | + pathfinder_geometry 0.5.1 MIT OR Apache-2.0 https://github.com/servo/pathfinder | |
| 327 | + pathfinder_simd 0.5.6 MIT OR Apache-2.0 https://github.com/servo/pathfinder | |
| 328 | + pbkdf2 0.12.2 MIT OR Apache-2.0 https://github.com/RustCrypto/password-hashes/tree/master/pbkdf2 | |
| 329 | + percent-encoding 2.3.2 MIT OR Apache-2.0 https://github.com/servo/rust-url/ | |
| 330 | + phf 0.11.3 MIT https://github.com/rust-phf/rust-phf | |
| 331 | + phf 0.13.1 MIT https://github.com/rust-phf/rust-phf | |
| 332 | + phf_codegen 0.11.3 MIT https://github.com/rust-phf/rust-phf | |
| 333 | + phf_generator 0.11.3 MIT https://github.com/rust-phf/rust-phf | |
| 334 | + phf_generator 0.13.1 MIT https://github.com/rust-phf/rust-phf | |
| 335 | + phf_macros 0.13.1 MIT https://github.com/rust-phf/rust-phf | |
| 336 | + phf_shared 0.11.3 MIT https://github.com/rust-phf/rust-phf | |
| 337 | + phf_shared 0.13.1 MIT https://github.com/rust-phf/rust-phf | |
| 338 | + pico-args 0.5.0 MIT https://github.com/RazrFalcon/pico-args | |
| 339 | + pin-project 1.1.13 Apache-2.0 OR MIT https://github.com/taiki-e/pin-project | |
| 340 | + pin-project-internal 1.1.13 Apache-2.0 OR MIT https://github.com/taiki-e/pin-project | |
| 341 | + pin-project-lite 0.2.17 Apache-2.0 OR MIT https://github.com/taiki-e/pin-project-lite | |
| 342 | + piper 0.2.5 MIT OR Apache-2.0 https://github.com/smol-rs/piper | |
| 343 | + pkg-config 0.3.34 MIT OR Apache-2.0 https://github.com/rust-lang/pkg-config-rs | |
| 344 | + png 0.17.16 MIT OR Apache-2.0 https://github.com/image-rs/image-png | |
| 345 | + png 0.18.1 MIT OR Apache-2.0 https://github.com/image-rs/image-png | |
| 346 | + polling 3.11.0 Apache-2.0 OR MIT https://github.com/smol-rs/polling | |
| 347 | + pollster 0.2.5 Apache-2.0 OR MIT https://github.com/zesterer/pollster | |
| 348 | + pollster 0.4.0 Apache-2.0 OR MIT https://github.com/zesterer/pollster | |
| 349 | + polycool 0.4.0 MIT OR Apache-2.0 https://github.com/linebender/kurbo | |
| 350 | + postage 0.5.0 MIT https://github.com/austinjones/postage-rs | |
| 351 | + potential_utf 0.1.6 Unicode-3.0 https://github.com/unicode-org/icu4x | |
| 352 | + ppv-lite86 0.2.21 MIT OR Apache-2.0 https://github.com/cryptocorrosion/cryptocorrosion | |
| 353 | + precomputed-hash 0.1.1 MIT https://github.com/emilio/precomputed-hash | |
| 354 | + presser 0.3.1 MIT OR Apache-2.0 https://github.com/EmbarkStudios/presser | |
| 355 | + proc-macro-crate 3.5.0 MIT OR Apache-2.0 https://github.com/bkchr/proc-macro-crate | |
| 356 | + proc-macro2 1.0.107 MIT OR Apache-2.0 https://github.com/dtolnay/proc-macro2 | |
| 357 | + profiling 1.0.18 MIT OR Apache-2.0 https://github.com/aclysma/profiling | |
| 358 | + profiling-procmacros 1.0.18 MIT OR Apache-2.0 https://github.com/aclysma/profiling | |
| 359 | + pulp 0.22.3 MIT https://github.com/sarah-quinones/pulp/ | |
| 360 | + pulp-wasm-simd-flag 0.1.1 MIT https://github.com/sarah-quinones/pulp/ | |
| 361 | + pxfm 0.1.30 BSD-3-Clause OR Apache-2.0 https://github.com/awxkee/pxfm | |
| 362 | + qoi 0.4.1 MIT OR Apache-2.0 https://github.com/aldanor/qoi-rust | |
| 363 | + quick-error 2.0.1 MIT OR Apache-2.0 http://github.com/tailhook/quick-error | |
| 364 | + quick-xml 0.41.0 MIT https://github.com/tafia/quick-xml | |
| 365 | + quote 1.0.47 MIT OR Apache-2.0 https://github.com/dtolnay/quote | |
| 366 | + rand 0.10.3 MIT OR Apache-2.0 https://github.com/rust-random/rand | |
| 367 | + rand 0.8.8 MIT OR Apache-2.0 https://github.com/rust-random/rand | |
| 368 | + rand 0.9.5 MIT OR Apache-2.0 https://github.com/rust-random/rand | |
| 369 | + rand_chacha 0.3.1 MIT OR Apache-2.0 https://github.com/rust-random/rand | |
| 370 | + rand_chacha 0.9.0 MIT OR Apache-2.0 https://github.com/rust-random/rand | |
| 371 | + rand_core 0.10.1 MIT OR Apache-2.0 https://github.com/rust-random/rand_core | |
| 372 | + rand_core 0.6.4 MIT OR Apache-2.0 https://github.com/rust-random/rand | |
| 373 | + rand_core 0.9.5 MIT OR Apache-2.0 https://github.com/rust-random/rand | |
| 374 | + rangemap 1.8.0 MIT OR Apache-2.0 https://github.com/jeffparsons/rangemap | |
| 375 | + rav1e 0.8.1 BSD-2-Clause https://github.com/xiph/rav1e/ | |
| 376 | + ravif 0.13.0 BSD-3-Clause https://github.com/kornelski/cavif-rs | |
| 377 | + raw-cpuid 11.6.0 MIT https://github.com/gz/rust-cpuid | |
| 378 | + raw-window-handle 0.6.2 MIT OR Apache-2.0 OR Zlib https://github.com/rust-windowing/raw-window-handle | |
| 379 | + rayon 1.12.0 MIT OR Apache-2.0 https://github.com/rayon-rs/rayon | |
| 380 | + rayon-core 1.13.0 MIT OR Apache-2.0 https://github.com/rayon-rs/rayon | |
| 381 | + read-fonts 0.37.0 MIT OR Apache-2.0 https://github.com/googlefonts/fontations | |
| 382 | + read-fonts 0.41.0 MIT OR Apache-2.0 https://github.com/googlefonts/fontations | |
| 383 | + reborrow 0.5.5 MIT https://github.com/sarah-ek/reborrow/ | |
| 384 | + ref-cast 1.0.27 MIT OR Apache-2.0 https://github.com/dtolnay/ref-cast | |
| 385 | + ref-cast-impl 1.0.27 MIT OR Apache-2.0 https://github.com/dtolnay/ref-cast | |
| 386 | + regex 1.13.1 MIT OR Apache-2.0 https://github.com/rust-lang/regex | |
| 387 | + regex-automata 0.4.18 MIT OR Apache-2.0 https://github.com/rust-lang/regex | |
| 388 | + regex-syntax 0.8.11 MIT OR Apache-2.0 https://github.com/rust-lang/regex | |
| 389 | + renderdoc-sys 1.1.0 MIT OR Apache-2.0 https://github.com/ebkalderon/renderdoc-rs | |
| 390 | + resvg 0.46.0 Apache-2.0 OR MIT https://github.com/linebender/resvg | |
| 391 | + rgb 0.8.53 MIT https://github.com/kornelski/rust-rgb | |
| 392 | + ring 0.17.14 Apache-2.0 AND ISC https://github.com/briansmith/ring | |
| 393 | + ropey 2.0.0-beta.1 MIT OR Apache-2.0 https://github.com/cessen/ropey | |
| 394 | + roxmltree 0.20.0 MIT OR Apache-2.0 https://github.com/RazrFalcon/roxmltree | |
| 395 | + roxmltree 0.21.1 MIT OR Apache-2.0 https://github.com/RazrFalcon/roxmltree | |
| 396 | + rust-embed 8.13.0 MIT https://pyrossh.dev/repos/rust-embed | |
| 397 | + rust-embed-impl 8.13.0 MIT https://pyrossh.dev/repos/rust-embed | |
| 398 | + rust-embed-utils 8.13.0 MIT https://pyrossh.dev/repos/rust-embed | |
| 399 | + rust-i18n 4.2.4 MIT https://github.com/longbridge/rust-i18n | |
| 400 | + rust-i18n-macro 4.2.4 MIT https://github.com/longbridge/rust-i18n | |
| 401 | + rust-i18n-support 4.2.4 MIT https://github.com/longbridge/rust-i18n | |
| 402 | + rustc-demangle 0.1.28 MIT OR Apache-2.0 https://github.com/rust-lang/rustc-demangle | |
| 403 | + rustc-hash 1.1.0 Apache-2.0 OR MIT https://github.com/rust-lang-nursery/rustc-hash | |
| 404 | + rustc-hash 2.1.3 Apache-2.0 OR MIT https://github.com/rust-lang/rustc-hash | |
| 405 | + rustc_version 0.4.1 MIT OR Apache-2.0 https://github.com/djc/rustc-version-rs | |
| 406 | + rustix 1.1.5 Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT https://github.com/bytecodealliance/rustix | |
| 407 | + rustls 0.23.45 Apache-2.0 OR ISC OR MIT https://github.com/rustls/rustls | |
| 408 | + rustls-pki-types 1.15.1 MIT OR Apache-2.0 https://github.com/rustls/pki-types | |
| 409 | + rustls-webpki 0.103.15 ISC https://github.com/rustls/webpki | |
| 410 | + rustversion 1.0.23 MIT OR Apache-2.0 https://github.com/dtolnay/rustversion | |
| 411 | + rustybuzz 0.20.1 MIT https://github.com/harfbuzz/rustybuzz | |
| 412 | + ryu 1.0.23 Apache-2.0 OR BSL-1.0 https://github.com/dtolnay/ryu | |
| 413 | + same-file 1.0.6 Unlicense OR MIT https://github.com/BurntSushi/same-file | |
| 414 | + schemars 1.2.2 MIT https://github.com/GREsau/schemars | |
| 415 | + schemars_derive 1.2.2 MIT https://github.com/GREsau/schemars | |
| 416 | + scoped-tls 1.0.1 MIT OR Apache-2.0 https://github.com/alexcrichton/scoped-tls | |
| 417 | + scopeguard 1.2.0 MIT OR Apache-2.0 https://github.com/bluss/scopeguard | |
| 418 | + seahash 4.1.0 MIT https://gitlab.redox-os.org/redox-os/seahash | |
| 419 | + self_cell 1.3.0 Apache-2.0 OR GPL-2.0-only https://github.com/Voultapher/self_cell | |
| 420 | + semver 1.0.28 MIT OR Apache-2.0 https://github.com/dtolnay/semver | |
| 421 | + serde 1.0.229 MIT OR Apache-2.0 https://github.com/serde-rs/serde | |
| 422 | + serde-saphyr 1.3.0 MIT OR Apache-2.0 https://github.com/bourumir-wyngs/serde-saphyr | |
| 423 | + serde_bytes 0.11.19 MIT OR Apache-2.0 https://github.com/serde-rs/bytes | |
| 424 | + serde_core 1.0.229 MIT OR Apache-2.0 https://github.com/serde-rs/serde | |
| 425 | + serde_derive 1.0.229 MIT OR Apache-2.0 https://github.com/serde-rs/serde | |
| 426 | + serde_derive_internals 0.30.0 MIT OR Apache-2.0 https://github.com/serde-rs/serde | |
| 427 | + serde_fmt 1.1.0 Apache-2.0 OR MIT https://github.com/KodrAus/serde_fmt.git | |
| 428 | + serde_json 1.0.151 MIT OR Apache-2.0 https://github.com/serde-rs/json | |
| 429 | + serde_repr 0.1.21 MIT OR Apache-2.0 https://github.com/dtolnay/serde-repr | |
| 430 | + serde_spanned 0.6.9 MIT OR Apache-2.0 https://github.com/toml-rs/toml | |
| 431 | + serde_spanned 1.1.2 MIT OR Apache-2.0 https://github.com/toml-rs/toml | |
| 432 | + serde_urlencoded 0.7.1 MIT OR Apache-2.0 https://github.com/nox/serde_urlencoded | |
| 433 | + sha1 0.11.0 MIT OR Apache-2.0 https://github.com/RustCrypto/hashes | |
| 434 | + sha1_smol 1.0.1 BSD-3-Clause https://github.com/mitsuhiko/sha1-smol | |
| 435 | + sha2 0.10.9 MIT OR Apache-2.0 https://github.com/RustCrypto/hashes | |
| 436 | + sha2 0.11.0 MIT OR Apache-2.0 https://github.com/RustCrypto/hashes | |
| 437 | + sharded-slab 0.1.7 MIT https://github.com/hawkw/sharded-slab | |
| 438 | + shellexpand 3.1.2 MIT OR Apache-2.0 https://gitlab.com/ijackson/rust-shellexpand | |
| 439 | + shlex 2.0.1 MIT OR Apache-2.0 https://github.com/comex/rust-shlex | |
| 440 | + signal-hook-registry 1.4.8 MIT OR Apache-2.0 https://github.com/vorner/signal-hook | |
| 441 | + simd-adler32 0.3.10 MIT https://github.com/mcountryman/simd-adler32 | |
| 442 | + simd_helpers 0.1.0 MIT https://github.com/lu-zero/simd_helpers | |
| 443 | + simdutf8 0.1.5 MIT OR Apache-2.0 https://github.com/rusticstuff/simdutf8 | |
| 444 | + simplecss 0.2.2 Apache-2.0 OR MIT https://github.com/linebender/simplecss | |
| 445 | + siphasher 1.0.4 MIT OR Apache-2.0 https://github.com/jedisct1/rust-siphash | |
| 446 | + skrifa 0.40.0 MIT OR Apache-2.0 https://github.com/googlefonts/fontations | |
| 447 | + skrifa 0.44.0 MIT OR Apache-2.0 https://github.com/googlefonts/fontations | |
| 448 | + slab 0.4.12 MIT https://github.com/tokio-rs/slab | |
| 449 | + slotmap 1.1.1 Zlib https://github.com/orlp/slotmap | |
| 450 | + smallvec 1.16.2 MIT OR Apache-2.0 https://github.com/servo/rust-smallvec | |
| 451 | + smol 2.0.2 Apache-2.0 OR MIT https://github.com/smol-rs/smol | |
| 452 | + smol_str 0.3.6 MIT OR Apache-2.0 https://github.com/rust-lang/rust-analyzer/tree/master/lib/smol_str | |
| 453 | + spin 0.10.1 MIT https://github.com/mvdnes/spin-rs.git | |
| 454 | + spin 0.9.9 MIT https://github.com/mvdnes/spin-rs.git | |
| 455 | + spirv 0.4.0+sdk-1.4.341.0 Apache-2.0 https://github.com/gfx-rs/rspirv | |
| 456 | + stable_deref_trait 1.2.1 MIT OR Apache-2.0 https://github.com/storyyeller/stable_deref_trait | |
| 457 | + static_assertions 1.1.0 MIT OR Apache-2.0 https://github.com/nvzqz/static-assertions-rs | |
| 458 | + str_indices 0.4.4 MIT OR Apache-2.0 https://github.com/cessen/str_indices | |
| 459 | + strict-num 0.1.1 MIT https://github.com/RazrFalcon/strict-num | |
| 460 | + string_cache 0.8.9 MIT OR Apache-2.0 https://github.com/servo/string-cache | |
| 461 | + string_cache_codegen 0.5.4 MIT OR Apache-2.0 https://github.com/servo/string-cache | |
| 462 | + strum 0.28.0 MIT https://github.com/Peternator7/strum | |
| 463 | + strum_macros 0.28.0 MIT https://github.com/Peternator7/strum | |
| 464 | + subtle 2.6.1 BSD-3-Clause https://github.com/dalek-cryptography/subtle | |
| 465 | + sval 2.22.0 Apache-2.0 OR MIT https://github.com/sval-rs/sval | |
| 466 | + sval_buffer 2.22.0 Apache-2.0 OR MIT https://github.com/sval-rs/sval | |
| 467 | + sval_dynamic 2.22.0 Apache-2.0 OR MIT https://github.com/sval-rs/sval | |
| 468 | + sval_fmt 2.22.0 Apache-2.0 OR MIT https://github.com/sval-rs/sval | |
| 469 | + sval_json 2.22.0 Apache-2.0 OR MIT https://github.com/sval-rs/sval | |
| 470 | + sval_nested 2.22.0 Apache-2.0 OR MIT https://github.com/sval-rs/sval | |
| 471 | + sval_ref 2.22.0 Apache-2.0 OR MIT https://github.com/sval-rs/sval | |
| 472 | + sval_serde 2.22.0 Apache-2.0 OR MIT https://github.com/sval-rs/sval | |
| 473 | + svg_fmt 0.4.5 MIT OR Apache-2.0 https://github.com/nical/rust_debug | |
| 474 | + svgtypes 0.16.1 Apache-2.0 OR MIT https://github.com/linebender/svgtypes | |
| 475 | + swash 0.2.10 Apache-2.0 OR MIT https://github.com/dfrg/swash | |
| 476 | + syn 2.0.119 MIT OR Apache-2.0 https://github.com/dtolnay/syn | |
| 477 | + syn 3.0.6 MIT OR Apache-2.0 https://github.com/dtolnay/syn | |
| 478 | + synstructure 0.14.0 MIT https://github.com/mystor/synstructure | |
| 479 | + sys-locale 0.3.2 MIT OR Apache-2.0 https://github.com/1Password/sys-locale | |
| 480 | + sysinfo 0.31.4 MIT https://github.com/GuillaumeGomez/sysinfo | |
| 481 | + taffy 0.13.0 MIT https://github.com/DioxusLabs/taffy | |
| 482 | + tendril 0.4.3 MIT OR Apache-2.0 https://github.com/servo/tendril | |
| 483 | + termcolor 1.4.1 Unlicense OR MIT https://github.com/BurntSushi/termcolor | |
| 484 | + thiserror 1.0.69 MIT OR Apache-2.0 https://github.com/dtolnay/thiserror | |
| 485 | + thiserror 2.0.21 MIT OR Apache-2.0 https://github.com/dtolnay/thiserror | |
| 486 | + thiserror-impl 1.0.69 MIT OR Apache-2.0 https://github.com/dtolnay/thiserror | |
| 487 | + thiserror-impl 2.0.21 MIT OR Apache-2.0 https://github.com/dtolnay/thiserror | |
| 488 | + thread_local 1.1.10 MIT OR Apache-2.0 https://github.com/Amanieu/thread_local-rs | |
| 489 | + tiff 0.11.3 MIT https://github.com/image-rs/image-tiff | |
| 490 | + tiny-keccak 2.0.2 CC0-1.0 | |
| 491 | + tiny-skia 0.11.4 BSD-3-Clause https://github.com/RazrFalcon/tiny-skia | |
| 492 | + tiny-skia-path 0.11.4 BSD-3-Clause https://github.com/RazrFalcon/tiny-skia/tree/master/path | |
| 493 | + tinystr 0.8.4 Unicode-3.0 https://github.com/unicode-org/icu4x | |
| 494 | + tinyvec 1.13.3 Zlib OR Apache-2.0 OR MIT https://github.com/Lokathor/tinyvec | |
| 495 | + toml 0.8.23 MIT OR Apache-2.0 https://github.com/toml-rs/toml | |
| 496 | + toml 1.1.8+spec-1.1.0 MIT OR Apache-2.0 https://github.com/toml-rs/toml | |
| 497 | + toml_datetime 0.6.11 MIT OR Apache-2.0 https://github.com/toml-rs/toml | |
| 498 | + toml_datetime 1.1.2+spec-1.1.0 MIT OR Apache-2.0 https://github.com/toml-rs/toml | |
| 499 | + toml_edit 0.22.27 MIT OR Apache-2.0 https://github.com/toml-rs/toml | |
| 500 | + toml_edit 0.25.17+spec-1.1.0 MIT OR Apache-2.0 https://github.com/toml-rs/toml | |
| 501 | + toml_parser 1.1.5+spec-1.1.0 MIT OR Apache-2.0 https://github.com/toml-rs/toml | |
| 502 | + toml_write 0.1.2 MIT OR Apache-2.0 https://github.com/toml-rs/toml | |
| 503 | + toml_writer 1.1.3+spec-1.1.0 MIT OR Apache-2.0 https://github.com/toml-rs/toml | |
| 504 | + tracing 0.1.44 MIT https://github.com/tokio-rs/tracing | |
| 505 | + tracing-attributes 0.1.31 MIT https://github.com/tokio-rs/tracing | |
| 506 | + tracing-core 0.1.36 MIT https://github.com/tokio-rs/tracing | |
| 507 | + tracing-log 0.2.0 MIT https://github.com/tokio-rs/tracing | |
| 508 | + tracing-subscriber 0.3.23 MIT https://github.com/tokio-rs/tracing | |
| 509 | + triomphe 0.1.16 MIT OR Apache-2.0 https://github.com/Manishearth/triomphe | |
| 510 | + ttf-parser 0.25.1 MIT OR Apache-2.0 https://github.com/harfbuzz/ttf-parser | |
| 511 | + tungstenite 0.30.0 MIT OR Apache-2.0 https://github.com/snapview/tungstenite-rs | |
| 512 | + typeid 1.0.3 MIT OR Apache-2.0 https://github.com/dtolnay/typeid | |
| 513 | + typenum 1.20.1 MIT OR Apache-2.0 https://github.com/paholg/typenum | |
| 514 | + unicase 2.10.0 MIT OR Apache-2.0 https://github.com/seanmonstar/unicase | |
| 515 | + unicode-bidi 0.3.18 MIT OR Apache-2.0 https://github.com/servo/unicode-bidi | |
| 516 | + unicode-bidi-mirroring 0.4.0 MIT OR Apache-2.0 https://github.com/RazrFalcon/unicode-bidi-mirroring | |
| 517 | + unicode-ccc 0.4.0 MIT OR Apache-2.0 https://github.com/RazrFalcon/unicode-ccc | |
| 518 | + unicode-id 0.3.7 MIT OR Apache-2.0 https://github.com/Boshen/unicode-id | |
| 519 | + unicode-ident 1.0.26 (MIT OR Apache-2.0) AND Unicode-3.0 https://github.com/dtolnay/unicode-ident | |
| 520 | + unicode-linebreak 0.1.5 Apache-2.0 https://github.com/axelf4/unicode-linebreak | |
| 521 | + unicode-properties 0.1.4 MIT OR Apache-2.0 https://github.com/unicode-rs/unicode-properties | |
| 522 | + unicode-script 0.5.8 MIT OR Apache-2.0 https://github.com/unicode-rs/unicode-script | |
| 523 | + unicode-segmentation 1.13.3 MIT OR Apache-2.0 https://github.com/unicode-rs/unicode-segmentation | |
| 524 | + unicode-vo 0.1.0 MIT OR Apache-2.0 https://github.com/RazrFalcon/unicode-vo | |
| 525 | + unicode-width 0.2.2 MIT OR Apache-2.0 https://github.com/unicode-rs/unicode-width | |
| 526 | + unicode-xid 0.2.6 MIT OR Apache-2.0 https://github.com/unicode-rs/unicode-xid | |
| 527 | + untrusted 0.9.0 ISC https://github.com/briansmith/untrusted | |
| 528 | + ureq 2.12.1 MIT OR Apache-2.0 https://github.com/algesten/ureq | |
| 529 | + url 2.5.8 MIT OR Apache-2.0 https://github.com/servo/rust-url | |
| 530 | + usvg 0.46.0 Apache-2.0 OR MIT https://github.com/linebender/resvg | |
| 531 | + utf-8 0.7.6 MIT OR Apache-2.0 https://github.com/SimonSapin/rust-utf8 | |
| 532 | + utf8_iter 1.0.4 Apache-2.0 OR MIT https://github.com/hsivonen/utf8_iter | |
| 533 | + uuid 1.27.0 Apache-2.0 OR MIT https://github.com/uuid-rs/uuid | |
| 534 | + v_frame 0.3.9 BSD-2-Clause https://github.com/rust-av/v_frame | |
| 535 | + value-bag 1.14.1 Apache-2.0 OR MIT https://github.com/sval-rs/value-bag | |
| 536 | + value-bag-serde1 1.14.1 Apache-2.0 OR MIT | |
| 537 | + value-bag-sval2 1.14.1 Apache-2.0 OR MIT | |
| 538 | + version_check 0.9.5 MIT OR Apache-2.0 https://github.com/SergioBenitez/version_check | |
| 539 | + waker-fn 1.2.0 Apache-2.0 OR MIT https://github.com/smol-rs/waker-fn | |
| 540 | + walkdir 2.5.0 Unlicense OR MIT https://github.com/BurntSushi/walkdir | |
| 541 | + wasm-bindgen 0.2.129 MIT OR Apache-2.0 https://github.com/wasm-bindgen/wasm-bindgen | |
| 542 | + wasm-bindgen-macro 0.2.129 MIT OR Apache-2.0 https://github.com/wasm-bindgen/wasm-bindgen/tree/master/crates/macro | |
| 543 | + wasm-bindgen-macro-support 0.2.129 MIT OR Apache-2.0 https://github.com/wasm-bindgen/wasm-bindgen/tree/main/crates/macro-support | |
| 544 | + wasm-bindgen-shared 0.2.129 MIT OR Apache-2.0 https://github.com/wasm-bindgen/wasm-bindgen/tree/master/crates/shared | |
| 545 | + wayland-backend 0.3.17 MIT https://github.com/smithay/wayland-rs | |
| 546 | + wayland-client 0.31.15 MIT https://github.com/smithay/wayland-rs | |
| 547 | + wayland-cursor 0.31.14 MIT https://github.com/smithay/wayland-rs | |
| 548 | + wayland-protocols 0.32.13 MIT https://github.com/smithay/wayland-rs | |
| 549 | + wayland-protocols-plasma 0.3.12 MIT https://github.com/smithay/wayland-rs | |
| 550 | + wayland-protocols-wlr 0.3.12 MIT https://github.com/smithay/wayland-rs | |
| 551 | + wayland-scanner 0.31.11 MIT https://github.com/smithay/wayland-rs | |
| 552 | + wayland-sys 0.31.11 MIT https://github.com/smithay/wayland-rs | |
| 553 | + web-time 1.1.0 MIT OR Apache-2.0 https://github.com/daxpedda/web-time | |
| 554 | + webpki-roots 0.26.11 CDLA-Permissive-2.0 https://github.com/rustls/webpki-roots | |
| 555 | + webpki-roots 1.0.9 CDLA-Permissive-2.0 https://github.com/rustls/webpki-roots | |
| 556 | + weezl 0.1.12 MIT OR Apache-2.0 https://github.com/image-rs/weezl | |
| 557 | + wgpu 29.0.4 MIT OR Apache-2.0 https://github.com/gfx-rs/wgpu | |
| 558 | + wgpu-core 29.0.4 MIT OR Apache-2.0 https://github.com/gfx-rs/wgpu | |
| 559 | + wgpu-core-deps-windows-linux-android 29.0.4 MIT OR Apache-2.0 https://github.com/gfx-rs/wgpu | |
| 560 | + wgpu-hal 29.0.4 MIT OR Apache-2.0 https://github.com/gfx-rs/wgpu | |
| 561 | + wgpu-naga-bridge 29.0.4 MIT OR Apache-2.0 https://github.com/gfx-rs/wgpu | |
| 562 | + wgpu-types 29.0.4 MIT OR Apache-2.0 https://github.com/gfx-rs/wgpu | |
| 563 | + winnow 0.7.15 MIT https://github.com/winnow-rs/winnow | |
| 564 | + winnow 1.0.4 MIT https://github.com/winnow-rs/winnow | |
| 565 | + writeable 0.6.4 Unicode-3.0 https://github.com/unicode-org/icu4x | |
| 566 | + x11 2.21.0 MIT https://github.com/AltF02/x11-rs.git | |
| 567 | + x11rb 0.13.2 MIT OR Apache-2.0 https://github.com/psychon/x11rb | |
| 568 | + x11rb-protocol 0.13.2 MIT OR Apache-2.0 https://github.com/psychon/x11rb | |
| 569 | + xcb 1.7.1 MIT https://github.com/rust-x-bindings/rust-xcb | |
| 570 | + xcursor 0.3.11 MIT https://github.com/esposm03/xcursor-rs | |
| 571 | + xim-ctext 0.3.0 MIT https://github.com/Riey/xim-rs | |
| 572 | + xim-parser 0.2.2 MIT https://github.com/Riey/xim-rs | |
| 573 | + xkbcommon 0.8.0 MIT https://github.com/rust-x-bindings/xkbcommon-rs | |
| 574 | + xkeysym 0.2.1 MIT OR Apache-2.0 OR Zlib https://github.com/notgull/xkeysym | |
| 575 | + xml5ever 0.18.1 MIT OR Apache-2.0 https://github.com/servo/html5ever | |
| 576 | + xmlwriter 0.1.0 MIT https://github.com/RazrFalcon/xmlwriter | |
| 577 | + y4m 0.8.0 MIT https://github.com/image-rs/y4m.git | |
| 578 | + yazi 0.2.1 Apache-2.0 OR MIT https://github.com/dfrg/yazi | |
| 579 | + yeslogic-fontconfig-sys 6.0.1 MIT https://github.com/yeslogic/fontconfig-rs | |
| 580 | + yoke 0.8.3 Unicode-3.0 https://github.com/unicode-org/icu4x | |
| 581 | + yoke-derive 0.8.4 Unicode-3.0 https://github.com/unicode-org/icu4x | |
| 582 | + zbus 5.19.0 MIT https://github.com/z-galaxy/zbus/ | |
| 583 | + zbus-lockstep 0.5.2 MIT https://github.com/luukvanderduim/zbus-lockstep | |
| 584 | + zbus-lockstep-macros 0.5.2 MIT https://github.com/luukvanderduim/zbus-lockstep | |
| 585 | + zbus_macros 5.19.0 MIT https://github.com/z-galaxy/zbus/ | |
| 586 | + zbus_names 4.3.4 MIT https://github.com/z-galaxy/zbus/ | |
| 587 | + zbus_xml 5.2.1 MIT https://github.com/z-galaxy/zbus/ | |
| 588 | + zcheapstr 1.1.0 MIT https://github.com/z-galaxy/zcheapstr/ | |
| 589 | + zed-font-kit 0.14.1-zed MIT OR Apache-2.0 https://github.com/servo/font-kit | |
| 590 | + zed-scap 0.0.8-zed MIT https://github.com/helmerapp/scap | |
| 591 | + zed-xim 0.4.0-zed MIT https://github.com/Riey/xim-rs | |
| 592 | + zeno 0.3.3 Apache-2.0 OR MIT https://github.com/dfrg/zeno | |
| 593 | + zerocopy 0.8.62 BSD-2-Clause OR Apache-2.0 OR MIT https://github.com/google/zerocopy | |
| 594 | + zerocopy-derive 0.8.62 BSD-2-Clause OR Apache-2.0 OR MIT https://github.com/google/zerocopy | |
| 595 | + zerofrom 0.1.8 Unicode-3.0 https://github.com/unicode-org/icu4x | |
| 596 | + zerofrom-derive 0.1.8 Unicode-3.0 https://github.com/unicode-org/icu4x | |
| 597 | + zeroize 1.9.1 Apache-2.0 OR MIT https://github.com/RustCrypto/utils | |
| 598 | + zeroize_derive 1.5.0 Apache-2.0 OR MIT https://github.com/RustCrypto/utils | |
| 599 | + zerotrie 0.2.5 Unicode-3.0 https://github.com/unicode-org/icu4x | |
| 600 | + zerovec 0.11.8 Unicode-3.0 https://github.com/unicode-org/icu4x | |
| 601 | + zerovec-derive 0.11.6 Unicode-3.0 https://github.com/unicode-org/icu4x | |
| 602 | + zlib-rs 0.6.8 Zlib https://github.com/trifectatechfoundation/zlib-rs | |
| 603 | + zmij 1.0.23 MIT https://github.com/dtolnay/zmij | |
| 604 | + zune-core 0.5.3 MIT OR Apache-2.0 OR Zlib https://github.com/etemesi254/zune-image | |
| 605 | + zune-inflate 0.2.54 MIT OR Apache-2.0 OR Zlib | |
| 606 | + zune-jpeg 0.5.15 MIT OR Apache-2.0 OR Zlib https://github.com/etemesi254/zune-image/tree/dev/crates/zune-jpeg | |
| 607 | + zvariant 5.15.0 MIT https://github.com/z-galaxy/zbus/ | |
| 608 | + zvariant_derive 5.15.0 MIT https://github.com/z-galaxy/zbus/ | |
| 609 | + zvariant_utils 4.2.0 MIT https://github.com/z-galaxy/zbus/ | |
| @@ -328,10 +328,20 @@ fn claude_command(config: &LaunchConfig) -> Result<(PathBuf, Command)> { | ||
| 328 | 328 | if let Some(session_id) = &config.resume { |
| 329 | 329 | command.args(["--resume", session_id]); |
| 330 | 330 | } |
| 331 | + if let Some(window) = auto_compact_window(&config.instance.auto_compact) { | |
| 332 | + command.args(["--settings", &format!(r#"{{"autoCompactWindow":{window}}}"#)]); | |
| 333 | + } | |
| 331 | 334 | command.args(split_args(&config.instance.args)); |
| 332 | 335 | Ok((binary, command)) |
| 333 | 336 | } |
| 334 | 337 | |
| 338 | + /// The "Auto-compact after" field as a token count, if it's one Claude | |
| 339 | + /// takes: 100,000 to 1,000,000. | |
| 340 | + pub fn auto_compact_window(text: &str) -> Option<u64> { | |
| 341 | + let digits: String = text.chars().filter(|c| !matches!(c, ',' | '_' | ' ')).collect(); | |
| 342 | + digits.parse::<u64>().ok().filter(|tokens| (100_000..=1_000_000).contains(tokens)) | |
| 343 | + } | |
| 344 | + | |
| 335 | 345 | fn pi_command(config: &LaunchConfig) -> Result<(PathBuf, Command)> { |
| 336 | 346 | let (binary, mut command) = base_command(&config.instance)?; |
| 337 | 347 | command.args(["--mode", "rpc"]).current_dir(&config.cwd); |
| @@ -403,10 +413,8 @@ pub fn base_command(instance: &ProviderInstance) -> Result<(PathBuf, Command)> { | ||
| 403 | 413 | } |
| 404 | 414 | command.env(home_var(instance.kind), home); |
| 405 | 415 | } |
| 406 | - for var in &instance.env { | |
| 407 | - if !var.key.trim().is_empty() { | |
| 408 | - command.env(var.key.trim(), &var.value); | |
| 409 | - } | |
| 416 | + for (key, value) in instance.env_vars() { | |
| 417 | + command.env(key, value); | |
| 410 | 418 | } |
| 411 | 419 | // Pi is a Node script; a desktop launcher's PATH may not reach the Node it |
| 412 | 420 | // was installed with, which usually sits next to it. |
| @@ -508,7 +516,16 @@ pub fn is_executable(path: &Path) -> bool { | ||
| 508 | 516 | |
| 509 | 517 | #[cfg(test)] |
| 510 | 518 | mod tests { |
| 511 | - use super::split_args; | |
| 519 | + use super::{auto_compact_window, split_args}; | |
| 520 | + | |
| 521 | + #[::core::prelude::v1::test] | |
| 522 | + fn auto_compact_takes_claudes_range() { | |
| 523 | + assert_eq!(auto_compact_window("300000"), Some(300_000)); | |
| 524 | + assert_eq!(auto_compact_window("1,000,000"), Some(1_000_000)); | |
| 525 | + assert_eq!(auto_compact_window("99999"), None); | |
| 526 | + assert_eq!(auto_compact_window("2000000"), None); | |
| 527 | + assert_eq!(auto_compact_window(""), None); | |
| 528 | + } | |
| 512 | 529 | |
| 513 | 530 | #[::core::prelude::v1::test] |
| 514 | 531 | fn splits_like_a_shell() { |
| @@ -165,7 +165,11 @@ fn quit(_: &Quit, cx: &mut App) { | ||
| 165 | 165 | *first = Some(Instant::now()); |
| 166 | 166 | if let Some(window) = cx.active_window() { |
| 167 | 167 | let _ = window.update(cx, |_, window, cx| { |
| 168 | - window.push_notification(Notification::info("Hold Ctrl+Q, or press it again, to quit."), cx); | |
| 168 | + let message = match settings::get(|settings| settings.quit_shortcut) { | |
| 169 | + settings::QuitShortcut::Double => "Press Ctrl+Q again to quit.", | |
| 170 | + _ => "Hold Ctrl+Q, or press it again, to quit.", | |
| 171 | + }; | |
| 172 | + window.push_notification(Notification::info(message), cx); | |
| 169 | 173 | }); |
| 170 | 174 | } |
| 171 | 175 | } |
| @@ -164,7 +164,11 @@ pub struct InstanceState { | ||
| 164 | 164 | pub status: ProbeStatus, |
| 165 | 165 | /// A check is running; the fields keep the previous one's findings. |
| 166 | 166 | pub checking: bool, |
| 167 | + /// The models the agent offers plus the custom ones, in the order the | |
| 168 | + /// settings put them. | |
| 167 | 169 | pub models: Vec<ModelEntry>, |
| 170 | + /// The models as the agent reported them. | |
| 171 | + reported: Vec<ModelEntry>, | |
| 168 | 172 | /// Claude's `default` entry, which the picker shows as the model it resolves to. |
| 169 | 173 | pub default: Option<ModelEntry>, |
| 170 | 174 | /// The signed-in account (Claude's email). |
| @@ -187,6 +191,7 @@ impl InstanceState { | ||
| 187 | 191 | config, |
| 188 | 192 | checking: false, |
| 189 | 193 | models: Vec::new(), |
| 194 | + reported: Vec::new(), | |
| 190 | 195 | default: None, |
| 191 | 196 | account: None, |
| 192 | 197 | plan: None, |
| @@ -217,6 +222,44 @@ impl InstanceState { | ||
| 217 | 222 | _ => false, |
| 218 | 223 | } |
| 219 | 224 | } |
| 225 | + | |
| 226 | + /// Whether a model was added by hand rather than reported by the agent. | |
| 227 | + pub fn is_custom(&self, model: &ModelEntry) -> bool { | |
| 228 | + self.config.custom_models.iter().any(|custom| custom.slug == model.id) | |
| 229 | + && !self.reported.iter().any(|reported| reported.id == model.id) | |
| 230 | + } | |
| 231 | + | |
| 232 | + /// Takes the agent's model list, adding the custom models and putting | |
| 233 | + /// them in the settings' order. | |
| 234 | + fn set_reported(&mut self, models: Vec<ModelEntry>) { | |
| 235 | + self.reported = models; | |
| 236 | + self.arrange(); | |
| 237 | + } | |
| 238 | + | |
| 239 | + fn arrange(&mut self) { | |
| 240 | + let mut models = self.reported.clone(); | |
| 241 | + for custom in &self.config.custom_models { | |
| 242 | + if custom.slug.trim().is_empty() || models.iter().any(|model| model.id == custom.slug) { | |
| 243 | + continue; | |
| 244 | + } | |
| 245 | + models.push(ModelEntry { | |
| 246 | + provider: self.config.kind, | |
| 247 | + instance: self.config.id.clone(), | |
| 248 | + id: custom.slug.clone(), | |
| 249 | + resolved: custom.slug.clone(), | |
| 250 | + name: if custom.name.trim().is_empty() { custom.slug.clone() } else { custom.name.trim().to_string() }, | |
| 251 | + detail: "Custom".into(), | |
| 252 | + legacy: false, | |
| 253 | + efforts: Vec::new(), | |
| 254 | + fast_mode: false, | |
| 255 | + auto_mode: false, | |
| 256 | + context_window: None, | |
| 257 | + }); | |
| 258 | + } | |
| 259 | + let order = settings::get(|settings| settings.model_order.clone()); | |
| 260 | + models.sort_by_key(|model| order.iter().position(|key| *key == model.key()).unwrap_or(usize::MAX)); | |
| 261 | + self.models = models; | |
| 262 | + } | |
| 220 | 263 | } |
| 221 | 264 | |
| 222 | 265 | pub struct Catalog { |
| @@ -266,6 +309,7 @@ impl Catalog { | ||
| 266 | 309 | if state.config != config { |
| 267 | 310 | let enabled = config.enabled; |
| 268 | 311 | state.config = config; |
| 312 | + state.arrange(); | |
| 269 | 313 | if !enabled { |
| 270 | 314 | state.status = ProbeStatus::Disabled; |
| 271 | 315 | } |
| @@ -341,7 +385,7 @@ impl Catalog { | ||
| 341 | 385 | Ok(probe) => { |
| 342 | 386 | state.status = ProbeStatus::Ready; |
| 343 | 387 | if !probe.models.is_empty() || state.config.kind != Provider::Claude { |
| 344 | - state.models = probe.models; | |
| 388 | + state.set_reported(probe.models); | |
| 345 | 389 | state.default = probe.default; |
| 346 | 390 | } |
| 347 | 391 | state.account = probe.account.or(state.account.take()); |
| @@ -359,7 +403,7 @@ impl Catalog { | ||
| 359 | 403 | state.status = status; |
| 360 | 404 | } |
| 361 | 405 | if state.config.kind != Provider::Claude { |
| 362 | - state.models.clear(); | |
| 406 | + state.set_reported(Vec::new()); | |
| 363 | 407 | } |
| 364 | 408 | } |
| 365 | 409 | } |
| @@ -401,8 +445,8 @@ impl Catalog { | ||
| 401 | 445 | state.plan = probe.plan; |
| 402 | 446 | changed = true; |
| 403 | 447 | } |
| 404 | - if !probe.models.is_empty() && state.models != probe.models { | |
| 405 | - state.models = probe.models; | |
| 448 | + if !probe.models.is_empty() && state.reported != probe.models { | |
| 449 | + state.set_reported(probe.models); | |
| 406 | 450 | state.default = probe.default; |
| 407 | 451 | changed = true; |
| 408 | 452 | } |
| @@ -446,6 +490,21 @@ impl Catalog { | ||
| 446 | 490 | self.instance(instance).map(|state| state.commands.as_slice()).unwrap_or_default() |
| 447 | 491 | } |
| 448 | 492 | |
| 493 | + /// Puts every instance's models in the order the settings give them, | |
| 494 | + /// after that order changed. | |
| 495 | + pub fn rearrange(cx: &mut App) { | |
| 496 | + for state in &mut cx.global_mut::<Catalog>().instances { | |
| 497 | + state.arrange(); | |
| 498 | + } | |
| 499 | + cx.refresh_windows(); | |
| 500 | + } | |
| 501 | + | |
| 502 | + /// Whether the settings hide a model from the model picker. | |
| 503 | + pub fn is_hidden(&self, model: &ModelEntry) -> bool { | |
| 504 | + let key = model.key(); | |
| 505 | + settings::get(|settings| settings.hidden_models.contains(&key)) | |
| 506 | + } | |
| 507 | + | |
| 449 | 508 | pub fn is_favorite(&self, model: &ModelEntry) -> bool { |
| 450 | 509 | self.favorites.contains(&model.key()) |
| 451 | 510 | } |
| @@ -720,7 +720,7 @@ impl Session { | ||
| 720 | 720 | permission_mode: self.permission_mode, |
| 721 | 721 | effort: self.reasoning.effort(), |
| 722 | 722 | resume: resume.clone(), |
| 723 | - browser_session: Some(browser::session_name(&self.id)), | |
| 723 | + browser_session: settings::get(|settings| settings.agent_browser).then(|| browser::session_name(&self.id)), | |
| 724 | 724 | }; |
| 725 | 725 | let process = match AgentProcess::spawn(&config, tx) { |
| 726 | 726 | Ok(process) => process, |
| @@ -760,6 +760,7 @@ impl Session { | ||
| 760 | 760 | Provider::Jcode => { |
| 761 | 761 | self.jcode = JcodeLink { |
| 762 | 762 | browser_note: browser::find_binary() |
| 763 | + .filter(|_| config.browser_session.is_some()) | |
| 763 | 764 | .map(|binary| browser::jcode_prompt(&browser::session_name(&self.id), &binary)), |
| 764 | 765 | ..JcodeLink::default() |
| 765 | 766 | }; |
| @@ -2992,15 +2993,26 @@ impl Session { | ||
| 2992 | 2993 | /// Adds streamed text to an answer. With "Show finished paragraphs" on, |
| 2993 | 2994 | /// the view only takes whole paragraphs and code blocks. |
| 2994 | 2995 | fn append_text(&mut self, ix: usize, delta: &str, cx: &mut Context<Self>) { |
| 2995 | - let paragraphs = settings::get(|settings| settings.streaming == Streaming::Paragraphs); | |
| 2996 | + let streaming = settings::get(|settings| settings.streaming); | |
| 2996 | 2997 | let Some(ChatItem::Assistant(answer)) = self.items.get_mut(ix) else { return }; |
| 2997 | 2998 | answer.text.push_str(delta); |
| 2998 | - let target = if paragraphs { finished_prefix(&answer.text) } else { answer.text.len() }; | |
| 2999 | + let target = match streaming { | |
| 3000 | + Streaming::Tokens => answer.text.len(), | |
| 3001 | + Streaming::Paragraphs => finished_prefix(&answer.text), | |
| 3002 | + Streaming::Turn => return, | |
| 3003 | + }; | |
| 2999 | 3004 | answer.show(target, cx); |
| 3000 | 3005 | } |
| 3001 | 3006 | |
| 3002 | - /// Shows the rest of an answer's text. | |
| 3007 | + /// Shows the rest of an answer's text once its message is complete, | |
| 3008 | + /// unless answers wait for the end of the turn. | |
| 3003 | 3009 | fn flush_item(&mut self, ix: usize, cx: &mut Context<Self>) { |
| 3010 | + if settings::get(|settings| settings.streaming) != Streaming::Turn { | |
| 3011 | + self.show_all(ix, cx); | |
| 3012 | + } | |
| 3013 | + } | |
| 3014 | + | |
| 3015 | + fn show_all(&mut self, ix: usize, cx: &mut Context<Self>) { | |
| 3004 | 3016 | if let Some(ChatItem::Assistant(answer)) = self.items.get_mut(ix) { |
| 3005 | 3017 | let end = answer.text.len(); |
| 3006 | 3018 | answer.show(end, cx); |
| @@ -3009,7 +3021,7 @@ impl Session { | ||
| 3009 | 3021 | |
| 3010 | 3022 | fn flush_text(&mut self, cx: &mut Context<Self>) { |
| 3011 | 3023 | for ix in 0..self.items.len() { |
| 3012 | - self.flush_item(ix, cx); | |
| 3024 | + self.show_all(ix, cx); | |
| 3013 | 3025 | } |
| 3014 | 3026 | } |
| 3015 | 3027 | |
| @@ -45,11 +45,47 @@ pub enum BranchNaming { | ||
| 45 | 45 | #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] |
| 46 | 46 | #[serde(rename_all = "snake_case")] |
| 47 | 47 | pub enum QuitShortcut { |
| 48 | - /// One press quits. | |
| 48 | + /// One press quits ("Direct"). | |
| 49 | 49 | Press, |
| 50 | 50 | /// Holding the keys, or pressing them twice quickly, quits. |
| 51 | 51 | #[default] |
| 52 | 52 | Hold, |
| 53 | + /// Two quick presses quit. | |
| 54 | + Double, | |
| 55 | + } | |
| 56 | + | |
| 57 | + /// Which keys send a prompt from the composer. | |
| 58 | + #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] | |
| 59 | + #[serde(rename_all = "snake_case")] | |
| 60 | + pub enum SendShortcut { | |
| 61 | + /// Enter sends, Shift+Enter starts a new line. | |
| 62 | + #[default] | |
| 63 | + Enter, | |
| 64 | + /// Enter sends a one-line prompt; once the prompt has several lines, | |
| 65 | + /// Enter starts a new line and Ctrl+Enter sends. | |
| 66 | + ModEnterMultiline, | |
| 67 | + /// Ctrl+Enter sends, Enter starts a new line. | |
| 68 | + ModEnter, | |
| 69 | + } | |
| 70 | + | |
| 71 | + /// The colors diffs and change counts use for additions and deletions. | |
| 72 | + #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] | |
| 73 | + #[serde(rename_all = "snake_case")] | |
| 74 | + pub enum DiffColors { | |
| 75 | + #[default] | |
| 76 | + RedGreen, | |
| 77 | + /// Easier to tell apart with red-green color blindness. | |
| 78 | + BlueOrange, | |
| 79 | + } | |
| 80 | + | |
| 81 | + /// How wide the conversation and the composer may grow on large screens. | |
| 82 | + #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] | |
| 83 | + #[serde(rename_all = "snake_case")] | |
| 84 | + pub enum ChatWidth { | |
| 85 | + #[default] | |
| 86 | + Comfortable, | |
| 87 | + Wide, | |
| 88 | + Full, | |
| 53 | 89 | } |
| 54 | 90 | |
| 55 | 91 | /// How projects are ordered in the sidebar and the project menus. |
| @@ -136,10 +172,13 @@ pub enum TimeFormat { | ||
| 136 | 172 | #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] |
| 137 | 173 | #[serde(rename_all = "snake_case")] |
| 138 | 174 | pub enum Streaming { |
| 139 | - #[default] | |
| 175 | + /// Every token as it arrives. | |
| 140 | 176 | Tokens, |
| 141 | 177 | /// Each paragraph or code block once it's complete. |
| 178 | + #[default] | |
| 142 | 179 | Paragraphs, |
| 180 | + /// The whole answer once the turn ends. | |
| 181 | + Turn, | |
| 143 | 182 | } |
| 144 | 183 | |
| 145 | 184 | /// What a message sent while the agent works does. |
| @@ -147,9 +186,9 @@ pub enum Streaming { | ||
| 147 | 186 | #[serde(rename_all = "snake_case")] |
| 148 | 187 | pub enum FollowUp { |
| 149 | 188 | /// Hand it to the agent at once, so it can change course mid-turn. |
| 150 | - #[default] | |
| 151 | 189 | Steer, |
| 152 | 190 | /// Hold it until the turn ends. |
| 191 | + #[default] | |
| 153 | 192 | Queue, |
| 154 | 193 | } |
| 155 | 194 | |
| @@ -170,7 +209,22 @@ pub enum BackgroundActivity { | ||
| 170 | 209 | #[serde(default)] |
| 171 | 210 | pub struct EnvVar { |
| 172 | 211 | pub key: String, |
| 212 | + /// Empty for a sensitive variable: its value lives in the secrets file. | |
| 173 | 213 | pub value: String, |
| 214 | + /// Kept out of `settings.json`, in a file only this user can read, and | |
| 215 | + /// never shown again once saved. | |
| 216 | + pub sensitive: bool, | |
| 217 | + } | |
| 218 | + | |
| 219 | + /// A model added by hand to an instance's list, for models the agent | |
| 220 | + /// doesn't report. | |
| 221 | + #[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] | |
| 222 | + #[serde(default)] | |
| 223 | + pub struct CustomModel { | |
| 224 | + /// What the agent is launched with: `claude-sonnet-5`, `anthropic/claude-sonnet-5`. | |
| 225 | + pub slug: String, | |
| 226 | + /// Empty shows the slug. | |
| 227 | + pub name: String, | |
| 174 | 228 | } |
| 175 | 229 | |
| 176 | 230 | /// One configured agent: Claude Code or Pi, with its own binary, home |
| @@ -193,6 +247,13 @@ pub struct ProviderInstance { | ||
| 193 | 247 | /// Extra arguments, split like a shell would. |
| 194 | 248 | pub args: String, |
| 195 | 249 | pub env: Vec<EnvVar>, |
| 250 | + /// A hex color (`#3e9bfa`) marking the instance in lists and pickers; | |
| 251 | + /// empty for none. | |
| 252 | + pub accent: String, | |
| 253 | + /// Claude: compact the conversation after this many tokens (100,000 to | |
| 254 | + /// 1,000,000); empty keeps Claude's default. | |
| 255 | + pub auto_compact: String, | |
| 256 | + pub custom_models: Vec<CustomModel>, | |
| 196 | 257 | } |
| 197 | 258 | |
| 198 | 259 | impl Default for ProviderInstance { |
| @@ -212,12 +273,33 @@ impl ProviderInstance { | ||
| 212 | 273 | home: String::new(), |
| 213 | 274 | args: String::new(), |
| 214 | 275 | env: Vec::new(), |
| 276 | + accent: String::new(), | |
| 277 | + auto_compact: String::new(), | |
| 278 | + custom_models: Vec::new(), | |
| 215 | 279 | } |
| 216 | 280 | } |
| 217 | 281 | |
| 218 | 282 | pub fn label(&self) -> String { |
| 219 | 283 | if self.name.trim().is_empty() { self.kind.label().to_string() } else { self.name.trim().to_string() } |
| 220 | 284 | } |
| 285 | + | |
| 286 | + /// The variables the agent runs with, sensitive values read from the | |
| 287 | + /// secrets file. | |
| 288 | + pub fn env_vars(&self) -> Vec<(String, String)> { | |
| 289 | + let secrets = if self.env.iter().any(|var| var.sensitive) { read_secrets() } else { Default::default() }; | |
| 290 | + self.env | |
| 291 | + .iter() | |
| 292 | + .filter(|var| !var.key.trim().is_empty()) | |
| 293 | + .map(|var| { | |
| 294 | + let key = var.key.trim().to_string(); | |
| 295 | + let value = match var.sensitive { | |
| 296 | + true => secrets.get(&secret_key(&self.id, &key)).cloned().unwrap_or_default(), | |
| 297 | + false => var.value.clone(), | |
| 298 | + }; | |
| 299 | + (key, value) | |
| 300 | + }) | |
| 301 | + .collect() | |
| 302 | + } | |
| 221 | 303 | } |
| 222 | 304 | |
| 223 | 305 | /// Another device's app this one connects to. |
| @@ -261,6 +343,11 @@ pub struct Settings { | ||
| 261 | 343 | /// Model keys (`claude:opus`, `pi:anthropic/claude-sonnet-5-5`), in the |
| 262 | 344 | /// order they were starred. |
| 263 | 345 | pub favorites: Vec<String>, |
| 346 | + /// Model keys the model picker leaves out. | |
| 347 | + pub hidden_models: Vec<String>, | |
| 348 | + /// Model keys in the order the picker lists them; models not in it | |
| 349 | + /// follow in the agent's order. | |
| 350 | + pub model_order: Vec<String>, | |
| 264 | 351 | |
| 265 | 352 | // ---- new threads ---- |
| 266 | 353 | /// The model key new threads start on. `None` follows the open thread. |
| @@ -305,7 +392,9 @@ pub struct Settings { | ||
| 305 | 392 | pub fold_turns: bool, |
| 306 | 393 | /// Show what threads and turns cost. |
| 307 | 394 | pub show_costs: bool, |
| 308 | - /// Send with Ctrl+Enter, so Enter starts a new line. | |
| 395 | + pub send_shortcut: SendShortcut, | |
| 396 | + /// Send with Ctrl+Enter, so Enter starts a new line. Follows | |
| 397 | + /// `send_shortcut` (true for [`SendShortcut::ModEnter`]). | |
| 309 | 398 | pub send_with_ctrl_enter: bool, |
| 310 | 399 | pub follow_up: FollowUp, |
| 311 | 400 | pub streaming: Streaming, |
| @@ -324,6 +413,10 @@ pub struct Settings { | ||
| 324 | 413 | pub diff_collapsed: bool, |
| 325 | 414 | pub diff_side_by_side: bool, |
| 326 | 415 | |
| 416 | + // ---- appearance ---- | |
| 417 | + pub diff_colors: DiffColors, | |
| 418 | + pub chat_width: ChatWidth, | |
| 419 | + | |
| 327 | 420 | // ---- sidebar ---- |
| 328 | 421 | /// T3 Code's legacy sidebar: threads in per-project trees instead of the |
| 329 | 422 | /// default flat inbox. |
| @@ -338,8 +431,7 @@ pub struct Settings { | ||
| 338 | 431 | pub project_grouping_overrides: std::collections::BTreeMap<String, ProjectGrouping>, |
| 339 | 432 | /// One-line thread cards in the sidebar. |
| 340 | 433 | pub compact_threads: bool, |
| 341 | - /// Group sidebar threads under their project: turns on the legacy | |
| 342 | - /// sidebar, like `legacy_sidebar`. | |
| 434 | + /// Group sidebar threads under their project. Follows `legacy_sidebar`. | |
| 343 | 435 | pub group_by_project: bool, |
| 344 | 436 | pub project_order: ProjectOrder, |
| 345 | 437 | /// Fold working threads into their own section until they need you. |
| @@ -379,6 +471,8 @@ pub struct Settings { | ||
| 379 | 471 | pub health_check_secs: u64, |
| 380 | 472 | |
| 381 | 473 | // ---- integrations ---- |
| 474 | + /// Let agents use the browser panel's shared browser. | |
| 475 | + pub agent_browser: bool, | |
| 382 | 476 | /// The editor "Open in" uses, by name (`Zed`). |
| 383 | 477 | pub editor: Option<String>, |
| 384 | 478 | pub providers: Vec<ProviderInstance>, |
| @@ -410,12 +504,14 @@ impl Default for Settings { | ||
| 410 | 504 | light_theme: "bone".into(), |
| 411 | 505 | dark_theme: "graphite".into(), |
| 412 | 506 | favorites: Vec::new(), |
| 507 | + hidden_models: Vec::new(), | |
| 508 | + model_order: Vec::new(), | |
| 413 | 509 | default_model: None, |
| 414 | 510 | default_reasoning: None, |
| 415 | 511 | default_access: None, |
| 416 | 512 | workspace: WorkspaceMode::Local, |
| 417 | 513 | submodules: Submodules::Recursive, |
| 418 | - start_from_origin: false, | |
| 514 | + start_from_origin: true, | |
| 419 | 515 | branch_naming: BranchNaming::Static, |
| 420 | 516 | branch_prefix: "vectrum".into(), |
| 421 | 517 | branch_instructions: String::new(), |
| @@ -428,17 +524,20 @@ impl Default for Settings { | ||
| 428 | 524 | text_reasoning: Some("low".into()), |
| 429 | 525 | fold_turns: true, |
| 430 | 526 | show_costs: true, |
| 527 | + send_shortcut: SendShortcut::Enter, | |
| 431 | 528 | send_with_ctrl_enter: false, |
| 432 | - follow_up: FollowUp::Steer, | |
| 433 | - streaming: Streaming::Tokens, | |
| 529 | + follow_up: FollowUp::Queue, | |
| 530 | + streaming: Streaming::Paragraphs, | |
| 434 | 531 | slash_skills: true, |
| 435 | 532 | rich_composer: true, |
| 436 | - collapse_composer: false, | |
| 533 | + collapse_composer: true, | |
| 437 | 534 | time_format: TimeFormat::System, |
| 438 | 535 | proactive_panels: false, |
| 439 | 536 | hide_whitespace: true, |
| 440 | - diff_collapsed: false, | |
| 537 | + diff_collapsed: true, | |
| 441 | 538 | diff_side_by_side: false, |
| 539 | + diff_colors: DiffColors::RedGreen, | |
| 540 | + chat_width: ChatWidth::Comfortable, | |
| 442 | 541 | legacy_sidebar: false, |
| 443 | 542 | thread_order: ThreadOrder::LastMessage, |
| 444 | 543 | visible_threads: 6, |
| @@ -462,9 +561,10 @@ impl Default for Settings { | ||
| 462 | 561 | notify_sound: false, |
| 463 | 562 | in_app_notifications: false, |
| 464 | 563 | continue_after_restart: false, |
| 465 | - update_checks: false, | |
| 564 | + update_checks: true, | |
| 466 | 565 | background_activity: BackgroundActivity::Balanced, |
| 467 | 566 | health_check_secs: 300, |
| 567 | + agent_browser: true, | |
| 468 | 568 | editor: None, |
| 469 | 569 | providers: Vec::new(), |
| 470 | 570 | usage_hubs: Vec::new(), |
| @@ -497,6 +597,77 @@ impl Settings { | ||
| 497 | 597 | self.providers.push(instance); |
| 498 | 598 | } |
| 499 | 599 | } |
| 600 | + // Fields older code reads, kept in step with the ones replacing them. | |
| 601 | + self.send_with_ctrl_enter = self.send_shortcut == SendShortcut::ModEnter; | |
| 602 | + self.group_by_project = self.legacy_sidebar; | |
| 603 | + } | |
| 604 | + | |
| 605 | + /// The settings "Restore device defaults" would change, by their | |
| 606 | + /// labels on the settings pages, in the order T3 Code lists them. | |
| 607 | + pub fn differing_defaults(&self) -> Vec<&'static str> { | |
| 608 | + let d = Settings::default(); | |
| 609 | + let theme = (self.theme_mode, &self.light_theme, &self.dark_theme) != (d.theme_mode, &d.light_theme, &d.dark_theme); | |
| 610 | + [ | |
| 611 | + ("Theme", theme), | |
| 612 | + ("Diff colors", self.diff_colors != d.diff_colors), | |
| 613 | + ("Chat width", self.chat_width != d.chat_width), | |
| 614 | + ("Time format", self.time_format != d.time_format), | |
| 615 | + ("Thread notifications", (self.notify, self.notify_sound) != (d.notify, d.notify_sound)), | |
| 616 | + ("In-app notifications", self.in_app_notifications != d.in_app_notifications), | |
| 617 | + ("Project Grouping", self.project_grouping != d.project_grouping), | |
| 618 | + ("Project order", self.project_order != d.project_order), | |
| 619 | + ("Working section", self.working_section != d.working_section), | |
| 620 | + ( | |
| 621 | + "Auto-settle inactive threads", | |
| 622 | + (self.auto_settle_inactive, self.inactive_days) != (d.auto_settle_inactive, d.inactive_days), | |
| 623 | + ), | |
| 624 | + ("Auto-settle merged threads", self.auto_settle_merged != d.auto_settle_merged), | |
| 625 | + ("Auto-resume limited threads", self.auto_resume_limited != d.auto_resume_limited), | |
| 626 | + ("Snooze limited threads", self.snooze_limited != d.snooze_limited), | |
| 627 | + ("Composer context", self.composer_context != d.composer_context), | |
| 628 | + ("Thread cards", self.compact_threads != d.compact_threads), | |
| 629 | + ("Default diff file state", self.diff_collapsed != d.diff_collapsed), | |
| 630 | + ("Diff whitespace changes", self.hide_whitespace != d.hide_whitespace), | |
| 631 | + ("Diff layout", self.diff_side_by_side != d.diff_side_by_side), | |
| 632 | + ("Proactive panels", self.proactive_panels != d.proactive_panels), | |
| 633 | + ("Show skills in slash menu", self.slash_skills != d.slash_skills), | |
| 634 | + ("Collapse composer on scroll", self.collapse_composer != d.collapse_composer), | |
| 635 | + ("Rich text composer", self.rich_composer != d.rich_composer), | |
| 636 | + ("Send shortcut", self.send_shortcut != d.send_shortcut), | |
| 637 | + ("Follow-up behavior", self.follow_up != d.follow_up), | |
| 638 | + ("Context window indicator", self.context_meter != d.context_meter), | |
| 639 | + ("Plan mode", self.plan_mode != d.plan_mode), | |
| 640 | + ("Sidebar", self.legacy_sidebar != d.legacy_sidebar), | |
| 641 | + ("Response streaming", self.streaming != d.streaming), | |
| 642 | + ("Fold finished turns", self.fold_turns != d.fold_turns), | |
| 643 | + ("Show costs", self.show_costs != d.show_costs), | |
| 644 | + ("Provider update checks", self.update_checks != d.update_checks), | |
| 645 | + ("Continue threads after restarts", self.continue_after_restart != d.continue_after_restart), | |
| 646 | + ("Background activity", self.background_activity != d.background_activity), | |
| 647 | + ("Health check interval", self.health_check_secs != d.health_check_secs), | |
| 648 | + ("Default model", (&self.default_model, &self.default_reasoning) != (&d.default_model, &d.default_reasoning)), | |
| 649 | + ("Permissions", self.default_access != d.default_access), | |
| 650 | + ("New thread mode", self.workspace != d.workspace), | |
| 651 | + ("Submodules", self.submodules != d.submodules), | |
| 652 | + ("New worktrees start from origin", self.start_from_origin != d.start_from_origin), | |
| 653 | + ("Add project base directory", self.add_project_dir != d.add_project_dir), | |
| 654 | + ("Unpin confirmation", self.confirm_unpin != d.confirm_unpin), | |
| 655 | + ("Archive confirmation", self.confirm_settle != d.confirm_settle), | |
| 656 | + ("Delete confirmation", self.confirm_delete != d.confirm_delete), | |
| 657 | + ("Quit shortcut", self.quit_shortcut != d.quit_shortcut), | |
| 658 | + ("Text generation model", (&self.text_model, &self.text_reasoning) != (&d.text_model, &d.text_reasoning)), | |
| 659 | + ( | |
| 660 | + "Worktree branch naming", | |
| 661 | + (self.branch_naming, &self.branch_prefix, &self.branch_instructions) | |
| 662 | + != (d.branch_naming, &d.branch_prefix, &d.branch_instructions), | |
| 663 | + ), | |
| 664 | + ("Worktree location", self.worktrees_dir != d.worktrees_dir), | |
| 665 | + ("Agent browser access", self.agent_browser != d.agent_browser), | |
| 666 | + ("Open in", self.editor != d.editor), | |
| 667 | + ] | |
| 668 | + .into_iter() | |
| 669 | + .filter_map(|(label, differs)| differs.then_some(label)) | |
| 670 | + .collect() | |
| 500 | 671 | } |
| 501 | 672 | |
| 502 | 673 | pub fn instance(&self, id: &str) -> Option<&ProviderInstance> { |
| @@ -519,7 +690,16 @@ fn read_file() -> Settings { | ||
| 519 | 690 | |
| 520 | 691 | /// Reads a settings file's text, falling back to the defaults. |
| 521 | 692 | fn parse(text: &str) -> Settings { |
| 522 | - let mut settings: Settings = serde_json::from_str(text).unwrap_or_default(); | |
| 693 | + let raw: serde_json::Value = serde_json::from_str(text).unwrap_or_default(); | |
| 694 | + let mut settings: Settings = serde_json::from_value(raw.clone()).unwrap_or_default(); | |
| 695 | + // Carry settings over from the fields that came before these. | |
| 696 | + let missing = |key: &str| raw.get(key).is_none(); | |
| 697 | + if missing("send_shortcut") && settings.send_with_ctrl_enter { | |
| 698 | + settings.send_shortcut = SendShortcut::ModEnter; | |
| 699 | + } | |
| 700 | + if missing("legacy_sidebar") { | |
| 701 | + settings.legacy_sidebar = settings.group_by_project; | |
| 702 | + } | |
| 523 | 703 | settings.normalize(); |
| 524 | 704 | settings |
| 525 | 705 | } |
| @@ -564,12 +744,14 @@ pub fn update(edit: impl FnOnce(&mut Settings)) { | ||
| 564 | 744 | } |
| 565 | 745 | } |
| 566 | 746 | |
| 567 | - /// Puts everything but favorites, agents, usage hubs and remote connections | |
| 568 | - /// back to its default. | |
| 747 | + /// Puts everything but favorites and model preferences, agents, usage hubs | |
| 748 | + /// and remote connections back to its default. | |
| 569 | 749 | pub fn restore_defaults() { |
| 570 | 750 | update(|settings| { |
| 571 | 751 | let kept = Settings { |
| 572 | 752 | favorites: std::mem::take(&mut settings.favorites), |
| 753 | + hidden_models: std::mem::take(&mut settings.hidden_models), | |
| 754 | + model_order: std::mem::take(&mut settings.model_order), | |
| 573 | 755 | providers: std::mem::take(&mut settings.providers), |
| 574 | 756 | usage_hubs: std::mem::take(&mut settings.usage_hubs), |
| 575 | 757 | remote_server: settings.remote_server, |
| @@ -582,6 +764,64 @@ pub fn restore_defaults() { | ||
| 582 | 764 | }); |
| 583 | 765 | } |
| 584 | 766 | |
| 767 | + // ---- secrets --------------------------------------------------------------- | |
| 768 | + | |
| 769 | + /// Where sensitive environment variables are kept: next to the settings, | |
| 770 | + /// readable by this user only. | |
| 771 | + fn secrets_path() -> Option<PathBuf> { | |
| 772 | + Some(path()?.with_file_name("secrets.json")) | |
| 773 | + } | |
| 774 | + | |
| 775 | + fn secret_key(instance: &str, var: &str) -> String { | |
| 776 | + format!("{instance}/{var}") | |
| 777 | + } | |
| 778 | + | |
| 779 | + fn read_secrets() -> std::collections::BTreeMap<String, String> { | |
| 780 | + secrets_path() | |
| 781 | + .and_then(|path| std::fs::read_to_string(path).ok()) | |
| 782 | + .and_then(|text| serde_json::from_str(&text).ok()) | |
| 783 | + .unwrap_or_default() | |
| 784 | + } | |
| 785 | + | |
| 786 | + /// Whether a sensitive variable has a stored value. | |
| 787 | + pub fn has_secret(instance: &str, var: &str) -> bool { | |
| 788 | + read_secrets().contains_key(&secret_key(instance, var.trim())) | |
| 789 | + } | |
| 790 | + | |
| 791 | + /// Stores a sensitive variable's value, or forgets it with `None`. | |
| 792 | + pub fn set_secret(instance: &str, var: &str, value: Option<&str>) { | |
| 793 | + let mut secrets = read_secrets(); | |
| 794 | + let key = secret_key(instance, var.trim()); | |
| 795 | + match value { | |
| 796 | + Some(value) => secrets.insert(key, value.to_string()), | |
| 797 | + None => secrets.remove(&key), | |
| 798 | + }; | |
| 799 | + write_secrets(&secrets); | |
| 800 | + } | |
| 801 | + | |
| 802 | + /// Keeps a sensitive variable's value when the variable is renamed. | |
| 803 | + pub fn rename_secret(instance: &str, from: &str, to: &str) { | |
| 804 | + let mut secrets = read_secrets(); | |
| 805 | + if let Some(value) = secrets.remove(&secret_key(instance, from.trim())) { | |
| 806 | + if !to.trim().is_empty() { | |
| 807 | + secrets.insert(secret_key(instance, to.trim()), value); | |
| 808 | + } | |
| 809 | + write_secrets(&secrets); | |
| 810 | + } | |
| 811 | + } | |
| 812 | + | |
| 813 | + fn write_secrets(secrets: &std::collections::BTreeMap<String, String>) { | |
| 814 | + let Some(path) = secrets_path() else { return }; | |
| 815 | + let written = path.parent().map(std::fs::create_dir_all).unwrap_or(Ok(())).and_then(|_| { | |
| 816 | + use std::{io::Write as _, os::unix::fs::OpenOptionsExt as _}; | |
| 817 | + let mut file = std::fs::OpenOptions::new().write(true).create(true).truncate(true).mode(0o600).open(&path)?; | |
| 818 | + file.write_all(serde_json::to_string_pretty(&secrets).unwrap_or_default().as_bytes()) | |
| 819 | + }); | |
| 820 | + if let Err(err) = written { | |
| 821 | + eprintln!("vectrum-code: couldn't save {}: {err}", path.display()); | |
| 822 | + } | |
| 823 | + } | |
| 824 | + | |
| 585 | 825 | /// `~/bin/claude` → `/home/me/bin/claude`. |
| 586 | 826 | pub fn expand_home(path: &str) -> PathBuf { |
| 587 | 827 | match (path.strip_prefix("~/"), std::env::var_os("HOME")) { |
| @@ -601,7 +841,7 @@ pub fn data_dir() -> Option<PathBuf> { | ||
| 601 | 841 | |
| 602 | 842 | #[cfg(test)] |
| 603 | 843 | mod tests { |
| 604 | - use super::{ThemeMode, parse}; | |
| 844 | + use super::{SendShortcut, ThemeMode, parse}; | |
| 605 | 845 | |
| 606 | 846 | #[test] |
| 607 | 847 | fn old_colorways_become_theme_modes() { |
| @@ -616,4 +856,26 @@ mod tests { | ||
| 616 | 856 | let saved = parse(r#"{"theme_mode": "dark", "dark_theme": "nord"}"#); |
| 617 | 857 | assert_eq!((saved.theme_mode, saved.dark_theme.as_str()), (ThemeMode::Dark, "nord")); |
| 618 | 858 | } |
| 859 | + | |
| 860 | + #[test] | |
| 861 | + fn older_fields_carry_over() { | |
| 862 | + let old = parse(r#"{"send_with_ctrl_enter": true, "group_by_project": true}"#); | |
| 863 | + assert_eq!(old.send_shortcut, SendShortcut::ModEnter); | |
| 864 | + assert!(old.legacy_sidebar && old.group_by_project); | |
| 865 | + // The new fields win once they're saved, and the old ones follow them. | |
| 866 | + let new = parse(r#"{"send_with_ctrl_enter": true, "send_shortcut": "mod_enter_multiline", "legacy_sidebar": false}"#); | |
| 867 | + assert_eq!(new.send_shortcut, SendShortcut::ModEnterMultiline); | |
| 868 | + assert!(!new.send_with_ctrl_enter && !new.group_by_project && !new.legacy_sidebar); | |
| 869 | + let fresh = parse("{}"); | |
| 870 | + assert_eq!((fresh.send_shortcut, fresh.legacy_sidebar), (SendShortcut::Enter, false)); | |
| 871 | + } | |
| 872 | + | |
| 873 | + #[test] | |
| 874 | + fn restore_lists_what_changed() { | |
| 875 | + let mut settings = parse("{}"); | |
| 876 | + assert!(settings.differing_defaults().is_empty()); | |
| 877 | + settings.chat_width = super::ChatWidth::Wide; | |
| 878 | + settings.dark_theme = "nord".into(); | |
| 879 | + assert_eq!(settings.differing_defaults(), ["Theme", "Chat width"]); | |
| 880 | + } | |
| 619 | 881 | } |
| @@ -102,9 +102,11 @@ fn counts(added: Option<u64>, removed: Option<u64>, p: &Palette) -> Div { | ||
| 102 | 102 | .font_family(metal::MONO) |
| 103 | 103 | .text_size(px(11.5)) |
| 104 | 104 | .map(|this| match (added, removed) { |
| 105 | - (Some(added), Some(removed)) => this | |
| 106 | - .child(div().text_color(p.green_ink).child(format!("+{}", format_count(added)))) | |
| 107 | - .child(div().text_color(p.red).child(format!("−{}", format_count(removed)))), | |
| 105 | + (Some(added), Some(removed)) => { | |
| 106 | + let ink = metal::diff_ink(p); | |
| 107 | + this.child(div().text_color(ink.added).child(format!("+{}", format_count(added)))) | |
| 108 | + .child(div().text_color(ink.removed).child(format!("−{}", format_count(removed)))) | |
| 109 | + } | |
| 108 | 110 | _ => this.child(div().text_color(p.ink3).child("binary")), |
| 109 | 111 | }) |
| 110 | 112 | } |
| @@ -345,8 +347,8 @@ fn split_rows(lines: &[DiffLine]) -> Vec<SplitRow<'_>> { | ||
| 345 | 347 | /// A line's sign, background and ink. |
| 346 | 348 | fn line_style(kind: LineKind, p: &Palette) -> (&'static str, Option<Hsla>, Hsla) { |
| 347 | 349 | match kind { |
| 348 | - LineKind::Added => ("+", Some(p.green_deep.opacity(0.14)), p.ink), | |
| 349 | - LineKind::Removed => ("−", Some(p.red.opacity(0.12)), p.ink), | |
| 350 | + LineKind::Added => ("+", Some(metal::diff_ink(p).added_bg), p.ink), | |
| 351 | + LineKind::Removed => ("−", Some(metal::diff_ink(p).removed_bg), p.ink), | |
| 350 | 352 | LineKind::Hunk => ("", Some(p.ink.opacity(0.04)), p.ink3), |
| 351 | 353 | LineKind::Context => (" ", None, p.ink2), |
| 352 | 354 | } |
| @@ -36,7 +36,7 @@ use crate::session::{ | ||
| 36 | 36 | use crate::worktree::StageStatus; |
| 37 | 37 | use crate::settings::{self, FollowUp, WorkspaceMode}; |
| 38 | 38 | use crate::ui::changes::{self, DiffAction, DiffView}; |
| 39 | - use crate::ui::composer::{self, CONTENT_WIDTH, Density, Tone}; | |
| 39 | + use crate::ui::composer::{self, Density, Tone}; | |
| 40 | 40 | use crate::ui::icons::Lucide; |
| 41 | 41 | use crate::ui::markdown_input::{self, MarkdownInput}; |
| 42 | 42 | use crate::ui::metal::{self, Led, MetalButton, MetalStyled as _, Palette}; |
| @@ -214,7 +214,7 @@ impl ChatView { | ||
| 214 | 214 | pub fn new(session: Entity<Session>, window: &mut Window, cx: &mut Context<Self>) -> Self { |
| 215 | 215 | let composer = cx.new(|cx| { |
| 216 | 216 | markdown_input::composer_state(EditorState::new(window, cx), settings::get(|settings| settings.rich_composer)) |
| 217 | - .submit_on_enter(!settings::get(|settings| settings.send_with_ctrl_enter)) | |
| 217 | + .submit_on_enter(settings::get(|settings| settings.send_shortcut) != settings::SendShortcut::ModEnter) | |
| 218 | 218 | .placeholder(DEFAULT_PLACEHOLDER) |
| 219 | 219 | }); |
| 220 | 220 | let item_count = session.read(cx).items.len(); |
| @@ -238,7 +238,7 @@ impl ChatView { | ||
| 238 | 238 | }), |
| 239 | 239 | cx.subscribe_in(&composer, window, |this, _, event, window, cx| match event { |
| 240 | 240 | InputEvent::PressEnter { shift: false, secondary } => { |
| 241 | - let ctrl_enter = settings::get(|settings| settings.send_with_ctrl_enter); | |
| 241 | + let ctrl_enter = this.ctrl_sends(cx); | |
| 242 | 242 | if *secondary || !ctrl_enter { |
| 243 | 243 | // With Enter sending, Ctrl+Enter does the opposite |
| 244 | 244 | // of the follow-up setting. |
| @@ -248,6 +248,7 @@ impl ChatView { | ||
| 248 | 248 | InputEvent::Change => { |
| 249 | 249 | this.menu_selected = 0; |
| 250 | 250 | this.stash_open = false; |
| 251 | + this.update_send_key(cx); | |
| 251 | 252 | this.sync_custom_answer(cx); |
| 252 | 253 | this.expand(cx); |
| 253 | 254 | this.load_files_if_mentioning(cx); |
| @@ -344,14 +345,29 @@ impl ChatView { | ||
| 344 | 345 | /// Picks up changed settings: the send key, and folding, which changes |
| 345 | 346 | /// the height of transcript rows. |
| 346 | 347 | pub fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) { |
| 347 | - let ctrl_enter = settings::get(|settings| settings.send_with_ctrl_enter); | |
| 348 | - self.composer.update(cx, |composer, cx| composer.set_submit_on_enter(!ctrl_enter, cx)); | |
| 348 | + self.update_send_key(cx); | |
| 349 | 349 | markdown_input::enable(&self.composer, settings::get(|settings| settings.rich_composer), cx); |
| 350 | 350 | self.scroller.update(cx, |scroller, cx| scroller.remeasure(cx)); |
| 351 | 351 | self.sync_with_session(window, cx); |
| 352 | 352 | cx.notify(); |
| 353 | 353 | } |
| 354 | 354 | |
| 355 | + /// Whether Ctrl+Enter sends right now, as Settings → Send shortcut says: | |
| 356 | + /// always, never, or once the prompt runs over several lines. | |
| 357 | + pub(super) fn ctrl_sends(&self, cx: &App) -> bool { | |
| 358 | + match settings::get(|settings| settings.send_shortcut) { | |
| 359 | + settings::SendShortcut::Enter => false, | |
| 360 | + settings::SendShortcut::ModEnter => true, | |
| 361 | + settings::SendShortcut::ModEnterMultiline => self.composer.read(cx).value().contains('\n'), | |
| 362 | + } | |
| 363 | + } | |
| 364 | + | |
| 365 | + /// Lets Enter send, or start a new line, as the send shortcut wants. | |
| 366 | + fn update_send_key(&mut self, cx: &mut Context<Self>) { | |
| 367 | + let enter_sends = !self.ctrl_sends(cx); | |
| 368 | + self.composer.update(cx, |composer, cx| composer.set_submit_on_enter(enter_sends, cx)); | |
| 369 | + } | |
| 370 | + | |
| 355 | 371 | pub fn focus_composer(&self, window: &mut Window, cx: &mut App) { |
| 356 | 372 | self.composer.update(cx, |composer, cx| composer.focus(window, cx)); |
| 357 | 373 | } |
| @@ -1441,7 +1457,7 @@ impl ChatView { | ||
| 1441 | 1457 | Some( |
| 1442 | 1458 | h_flex() |
| 1443 | 1459 | .w_full() |
| 1444 | - .max_w(px(CONTENT_WIDTH)) | |
| 1460 | + .max_w(composer::content_width()) | |
| 1445 | 1461 | .px(px(16.)) |
| 1446 | 1462 | .pb(px(8.)) |
| 1447 | 1463 | .gap(px(6.)) |
| @@ -1532,7 +1548,7 @@ impl ChatView { | ||
| 1532 | 1548 | let (cancel, local) = (self.session.clone(), self.session.clone()); |
| 1533 | 1549 | v_flex() |
| 1534 | 1550 | .w_full() |
| 1535 | - .max_w(px(CONTENT_WIDTH)) | |
| 1551 | + .max_w(composer::content_width()) | |
| 1536 | 1552 | .px(px(16.)) |
| 1537 | 1553 | .pb(px(8.)) |
| 1538 | 1554 | .child( |
| @@ -1754,7 +1770,7 @@ impl ChatView { | ||
| 1754 | 1770 | .child( |
| 1755 | 1771 | v_flex() |
| 1756 | 1772 | .w_full() |
| 1757 | - .max_w(px(CONTENT_WIDTH)) | |
| 1773 | + .max_w(composer::content_width()) | |
| 1758 | 1774 | .capture_key_down(cx.listener(|this, event: &KeyDownEvent, window, cx| { |
| 1759 | 1775 | this.composer_key(event, window, cx) |
| 1760 | 1776 | })) |
| @@ -28,7 +28,7 @@ use crate::session::{ | ||
| 28 | 28 | }; |
| 29 | 29 | use crate::settings; |
| 30 | 30 | use crate::ui::changes; |
| 31 | - use crate::ui::composer::CONTENT_WIDTH; | |
| 31 | + use crate::ui::composer; | |
| 32 | 32 | use crate::ui::icons::Lucide; |
| 33 | 33 | use crate::ui::metal::{self, Led, MetalButton, MetalStyled as _, Palette}; |
| 34 | 34 | |
| @@ -417,7 +417,7 @@ pub(super) fn render_item( | ||
| 417 | 417 | .child( |
| 418 | 418 | v_flex() |
| 419 | 419 | .w_full() |
| 420 | - .max_w(px(CONTENT_WIDTH)) | |
| 420 | + .max_w(composer::content_width()) | |
| 421 | 421 | .map(|this| match item { |
| 422 | 422 | ChatItem::TaskEvent { .. } => this.children(content).children(summary.map(|summary| div().pt(px(8.)).child(summary))), |
| 423 | 423 | _ => this.children(summary.map(|summary| div().pb(px(6.)).child(summary))).children(content.map(|content| { |
| @@ -15,8 +15,15 @@ pub const INSET: f32 = 22.; | ||
| 15 | 15 | pub const OVERLAP: f32 = 17.; |
| 16 | 16 | /// The icon column of a banner row. |
| 17 | 17 | pub const ICON_COLUMN: f32 = 24.; |
| 18 | - /// The widest the conversation and the composer grow. | |
| 19 | - pub const CONTENT_WIDTH: f32 = 736.; | |
| 18 | + /// The widest the conversation and the composer grow, as Settings → | |
| 19 | + /// Appearance → Chat width says: 736px, 1152px, or the whole pane. | |
| 20 | + pub fn content_width() -> Pixels { | |
| 21 | + match crate::settings::get(|settings| settings.chat_width) { | |
| 22 | + crate::settings::ChatWidth::Comfortable => px(736.), | |
| 23 | + crate::settings::ChatWidth::Wide => px(1152.), | |
| 24 | + crate::settings::ChatWidth::Full => px(100_000.), | |
| 25 | + } | |
| 26 | + } | |
| 20 | 27 | |
| 21 | 28 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] |
| 22 | 29 | pub enum Tone { |
| @@ -11,8 +11,10 @@ gpui_kit::assets::icon_assets!(ExtraIcons, [ | ||
| 11 | 11 | AlarmClock, |
| 12 | 12 | AlarmClockOff, |
| 13 | 13 | Archive, |
| 14 | + ArchiveX, | |
| 14 | 15 | ArchiveRestore, |
| 15 | 16 | Bell, |
| 17 | + Blocks, | |
| 16 | 18 | Brain, |
| 17 | 19 | ChevronsDownUp, |
| 18 | 20 | ChevronsUpDown, |
| @@ -24,6 +26,7 @@ gpui_kit::assets::icon_assets!(ExtraIcons, [ | ||
| 24 | 26 | FolderGit2, |
| 25 | 27 | FolderPlus, |
| 26 | 28 | Gauge, |
| 29 | + HardDrive, | |
| 27 | 30 | GitBranch, |
| 28 | 31 | GitCommitHorizontal, |
| 29 | 32 | GitPullRequest, |
| @@ -31,6 +34,7 @@ gpui_kit::assets::icon_assets!(ExtraIcons, [ | ||
| 31 | 34 | Keyboard, |
| 32 | 35 | Laptop, |
| 33 | 36 | Layers, |
| 37 | + Link2, | |
| 34 | 38 | ListOrdered, |
| 35 | 39 | Lock, |
| 36 | 40 | MonitorSmartphone, |
| @@ -50,6 +54,7 @@ gpui_kit::assets::icon_assets!(ExtraIcons, [ | ||
| 50 | 54 | Plus, |
| 51 | 55 | RotateCcw, |
| 52 | 56 | Server, |
| 57 | + Settings2, | |
| 53 | 58 | ShieldCheck, |
| 54 | 59 | SquareSlash, |
| 55 | 60 | SlidersHorizontal, |
| @@ -59,6 +64,7 @@ gpui_kit::assets::icon_assets!(ExtraIcons, [ | ||
| 59 | 64 | SwatchBook, |
| 60 | 65 | Star, |
| 61 | 66 | Trash, |
| 67 | + Undo2, | |
| 62 | 68 | Zap, |
| 63 | 69 | Bookmark, |
| 64 | 70 | Bot, |
| @@ -476,6 +476,34 @@ pub fn badge(initials: impl Into<SharedString>, tint: usize, p: &Palette) -> Div | ||
| 476 | 476 | .child(initials.into()) |
| 477 | 477 | } |
| 478 | 478 | |
| 479 | + /// The colors diffs and change counts use, from the palette, as the Diff | |
| 480 | + /// colors setting picks them. | |
| 481 | + pub struct DiffInk { | |
| 482 | + /// Text for additions: `+12`. | |
| 483 | + pub added: Hsla, | |
| 484 | + pub removed: Hsla, | |
| 485 | + /// The tint behind an added line. | |
| 486 | + pub added_bg: Hsla, | |
| 487 | + pub removed_bg: Hsla, | |
| 488 | + } | |
| 489 | + | |
| 490 | + pub fn diff_ink(p: &Palette) -> DiffInk { | |
| 491 | + match crate::settings::get(|settings| settings.diff_colors) { | |
| 492 | + crate::settings::DiffColors::RedGreen => DiffInk { | |
| 493 | + added: p.green_ink, | |
| 494 | + removed: p.red, | |
| 495 | + added_bg: p.green_deep.opacity(0.14), | |
| 496 | + removed_bg: p.red.opacity(0.12), | |
| 497 | + }, | |
| 498 | + crate::settings::DiffColors::BlueOrange => DiffInk { | |
| 499 | + added: p.blue_ink, | |
| 500 | + removed: p.tints[0], | |
| 501 | + added_bg: p.blue_ink.opacity(0.14), | |
| 502 | + removed_bg: p.tints[0].opacity(0.14), | |
| 503 | + }, | |
| 504 | + } | |
| 505 | + } | |
| 506 | + | |
| 479 | 507 | /// A vertical hairline, for separating toolbar groups. |
| 480 | 508 | pub fn vrule(p: &Palette) -> Div { |
| 481 | 509 | div().flex_none().w(px(1.)).h(px(16.)).bg(p.rule) |
| @@ -339,6 +339,7 @@ impl ModelPicker { | ||
| 339 | 339 | let words: Vec<&str> = query.split_whitespace().collect(); |
| 340 | 340 | let mut matches: Vec<(bool, ModelEntry)> = catalog |
| 341 | 341 | .all_models() |
| 342 | + .filter(|model| !catalog.is_hidden(model)) | |
| 342 | 343 | .filter(|model| { |
| 343 | 344 | let haystack = format!( |
| 344 | 345 | "{} {} {} {} {}", |
| @@ -359,8 +360,9 @@ impl ModelPicker { | ||
| 359 | 360 | match &self.rail { |
| 360 | 361 | Rail::Favorites => (catalog.favorites().into_iter().cloned().collect(), Vec::new()), |
| 361 | 362 | Rail::Instance(instance) => { |
| 363 | + // Models hidden in Settings → Providers stay out of the picker. | |
| 362 | 364 | let (mut current, legacy): (Vec<ModelEntry>, Vec<ModelEntry>) = |
| 363 | - catalog.models(instance).iter().cloned().partition(|model| !model.legacy); | |
| 365 | + catalog.models(instance).iter().filter(|model| !catalog.is_hidden(model)).cloned().partition(|model| !model.legacy); | |
| 364 | 366 | // Favorites float to the top, the rest keep the provider's order. |
| 365 | 367 | current.sort_by_key(|model| !catalog.is_favorite(model)); |
| 366 | 368 | (current, legacy) |
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.