Merge branch 'master' into primary
This commit is contained in:
commit
5b2bbe84cb
21 changed files with 2064 additions and 1382 deletions
1291
Cargo.lock
generated
1291
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -11,8 +11,10 @@ alacritty_terminal = "0.20"
|
|||
env_logger = "0.10"
|
||||
lazy_static = "1"
|
||||
indexmap = "2"
|
||||
lexical-sort = "0.3.1"
|
||||
log = "0.4"
|
||||
serde = { version = "1", features = ["serde_derive"] }
|
||||
shlex = "1"
|
||||
tokio = { version = "1", features = ["sync"] }
|
||||
# Internationalization
|
||||
i18n-embed = { version = "0.13", features = ["fluent-system", "desktop-requester"] }
|
||||
|
|
@ -21,8 +23,13 @@ rust-embed = "6"
|
|||
paste = "1.0"
|
||||
palette = "0.7"
|
||||
|
||||
[dependencies.smol_str]
|
||||
version = "0.2.1"
|
||||
features = ["serde"]
|
||||
|
||||
[dependencies.cosmic-text]
|
||||
git = "https://github.com/pop-os/cosmic-text.git"
|
||||
features = ["shape-run-cache"]
|
||||
|
||||
[dependencies.libcosmic]
|
||||
git = "https://github.com/pop-os/libcosmic.git"
|
||||
|
|
@ -36,7 +43,6 @@ wgpu = ["libcosmic/wgpu"]
|
|||
[patch.crates-io]
|
||||
# https://github.com/rust-lang/libc/pull/3512
|
||||
libc = { git = "https://gitlab.redox-os.org/redox-os/liblibc.git", branch = "redox_0.2.151" }
|
||||
smithay-client-toolkit = { git = "https://github.com/pop-os/client-toolkit", branch = "wayland-resize" }
|
||||
|
||||
[profile.release-with-debug]
|
||||
inherits = "release"
|
||||
|
|
|
|||
1
debian/control
vendored
1
debian/control
vendored
|
|
@ -13,4 +13,5 @@ Homepage: https://github.com/pop-os/cosmic-term
|
|||
Package: cosmic-term
|
||||
Architecture: amd64 arm64
|
||||
Depends: ${misc:Depends}, ${shlibs:Depends}
|
||||
Provides: x-terminal-emulator
|
||||
Description: Cosmic Terminal
|
||||
|
|
|
|||
|
|
@ -1,5 +1,16 @@
|
|||
new-terminal = New terminal
|
||||
|
||||
# Context Pages
|
||||
|
||||
## Profiles
|
||||
profiles = Profiles
|
||||
name = Name
|
||||
command-line = Command line
|
||||
tab-title = Tab title
|
||||
tab-title-description = Override the default tab title
|
||||
add-profile = Add profile
|
||||
new-profile = New profile
|
||||
|
||||
## Settings
|
||||
settings = Settings
|
||||
|
||||
|
|
@ -12,6 +23,7 @@ light = Light
|
|||
syntax-dark = Color scheme dark
|
||||
syntax-light = Color scheme light
|
||||
default-zoom-step = Zoom steps
|
||||
opacity = Background opacity
|
||||
|
||||
### Font
|
||||
font = Font
|
||||
|
|
@ -44,6 +56,8 @@ find-next = Find next
|
|||
file = File
|
||||
new-tab = New tab
|
||||
new-window = New window
|
||||
profile = Profile
|
||||
menu-profiles = Profiles...
|
||||
close-tab = Close tab
|
||||
quit = Quit
|
||||
|
||||
|
|
|
|||
|
|
@ -1,25 +1,47 @@
|
|||
# Context Pages
|
||||
|
||||
## Profiles
|
||||
profiles = プロファイル
|
||||
name = 名前
|
||||
command-line = コマンドライン
|
||||
tab-title = タブのイトル
|
||||
tab-title-description = デフォルトのタブタイトルを無効にします
|
||||
add-profile = プロファイルを追加
|
||||
new-profile = 新しいプロファイル
|
||||
|
||||
## Settings
|
||||
settings = 設定
|
||||
|
||||
### Appearance
|
||||
appearance = 外観
|
||||
theme = テーマ
|
||||
match-desktop = デスクトップに合わす
|
||||
dark = 暗い
|
||||
light = 明かり
|
||||
syntax-dark = 暗いシンタックス
|
||||
syntax-light = 明かりシンタックス
|
||||
advanced-font-settings = 詳細なフォント設定
|
||||
default-font = デフォルトフォント
|
||||
default-font-stretch = デフォルトのフォント幅
|
||||
default-font-weight = デフォルトのフォントの太さ
|
||||
default-dim-font-weight = デフォルトの暗いフォントの太さ
|
||||
default-bold-font-weight = デフォルトの太字の太さ
|
||||
match-desktop = システム設定に従う
|
||||
dark = ダーク
|
||||
light = ライト
|
||||
syntax-dark = ダークシンタックスハイライト
|
||||
syntax-light = ライトシンタックスハイライト
|
||||
default-zoom-step = 拡大縮小の間隔
|
||||
opacity = 不透明度
|
||||
|
||||
### Font
|
||||
font = フォント
|
||||
advanced-font-settings = フォントの詳細設定
|
||||
default-font = フォント名
|
||||
default-font-size = サイズ
|
||||
default-font-stretch = 幅
|
||||
default-font-weight = スタイル
|
||||
default-dim-font-weight = 細字のスタイル
|
||||
default-bold-font-weight = 太字のスタイル
|
||||
use-bright-bold = 太字を明るい色で表示する
|
||||
default-font-size = デフォルトのフォントサイズ
|
||||
default-zoom-step =ズームの間隔
|
||||
|
||||
### Splits
|
||||
splits = ウィンドウの分割
|
||||
focus-follow-mouse = フォーカスをマウスに追従
|
||||
|
||||
### Advanced
|
||||
advanced = 高度な設定
|
||||
show-headerbar = ヘッダーを表示する
|
||||
show-header-description = 右クリックでヘッダーを表示する
|
||||
|
||||
# Find
|
||||
find-placeholder = 検索...
|
||||
|
|
@ -32,6 +54,8 @@ find-next = 次を検索
|
|||
file = ファイル
|
||||
new-tab = 新しいタブ
|
||||
new-window = 新しいウィンドウ
|
||||
profile = プロファイル
|
||||
menu-profiles = プロファイル...
|
||||
close-tab = タブを閉じる
|
||||
quit = 終了
|
||||
|
||||
|
|
@ -44,7 +68,12 @@ find = 検索
|
|||
|
||||
## View
|
||||
view = 表示
|
||||
zoom-in = 拡大
|
||||
zoom-reset = デフォルトに戻す
|
||||
zoom-out = 縮小
|
||||
next-tab = 次のタブ
|
||||
previous-tab = 前のタブ
|
||||
split-horizontal = 上下に分割
|
||||
split-vertical = 左右に分割
|
||||
pane-toggle-maximize = ペインの最大化を切替
|
||||
menu-settings = 設定...
|
||||
|
||||
# Context menu
|
||||
show-headerbar = ヘッダーバーを表す
|
||||
|
|
|
|||
|
|
@ -11,20 +11,32 @@ dark = Ciemny
|
|||
light = Jasny
|
||||
syntax-dark = Ciemna składnia
|
||||
syntax-light = Jasna składnia
|
||||
advanced-font-settings = Advanced Font Settings
|
||||
default-zoom-step = Domyślny poziom przybliżenia
|
||||
|
||||
### Font
|
||||
font = Czcionka
|
||||
advanced-font-settings = Zaawansowane Ustawienia Czcionek
|
||||
default-font = Domyślna czcionka
|
||||
default-font-size = Domyślny rozmiar czcionki
|
||||
default-font-stretch = Domyślne rozciągnięcie czcionki
|
||||
default-font-weight = Domyślna grubość czcionki
|
||||
default-dim-font-weight = Domyślna grubość przyciemnionej czcionki
|
||||
default-bold-font-weight = Domyślna grubość pogrubionej czcionki
|
||||
use-bright-bold = Użyj jasnych kolorów przy pogrubionym tekście
|
||||
default-font-size = Domyślny rozmiar czcionki
|
||||
default-zoom-step = Domyślny poziom przybliżenia
|
||||
use-bright-bold = Rozjaśnij pogrubiony tekst
|
||||
|
||||
### Splits
|
||||
splits = Podziel
|
||||
focus-follow-mouse = Aktywne okno pisania odpowiada położeniu myszki
|
||||
|
||||
### Advanced
|
||||
advanced = Zaawansowane
|
||||
show-headerbar = Pokaż pasek nagłówka
|
||||
show-header-description = Ukazuje pasek nagłówka z menu wybieranego prawym przyciskiem myszki.
|
||||
|
||||
# Find
|
||||
find-placeholder = Find...
|
||||
find-previous = Find previous
|
||||
find-next = Find next
|
||||
find-placeholder = Szukaj...
|
||||
find-previous = Szukaj poprzedni
|
||||
find-next = Szukaj następny
|
||||
|
||||
# Menu
|
||||
|
||||
|
|
@ -44,7 +56,12 @@ find = Szukaj
|
|||
|
||||
## View
|
||||
view = Widok
|
||||
zoom-in = Większy tekst
|
||||
zoom-reset = Domyślny rozmiar tekstu
|
||||
zoom-out = Mniejszy tekst
|
||||
next-tab = Natępna karta
|
||||
previous-tab = Poprzednia karta
|
||||
split-horizontal = Podziel w poziomie
|
||||
split-vertical = Podziel w pionie
|
||||
pane-toggle-maximize = Przełącznik maksymalizacji
|
||||
menu-settings = Ustawienia...
|
||||
|
||||
# Context menu
|
||||
show-headerbar = Pokaż pasek nagłówka
|
||||
|
|
|
|||
|
|
@ -9,17 +9,29 @@ theme = Тема
|
|||
match-desktop = Как в системе
|
||||
dark = Темная
|
||||
light = Светлая
|
||||
syntax-dark = Синтаксис темный
|
||||
syntax-light = Синтаксис светлый
|
||||
syntax-dark = Цветовая схема темная
|
||||
syntax-light = Цветовая схема светлая
|
||||
default-zoom-step = Шаги масштабирования
|
||||
|
||||
### Font
|
||||
font = Шрифт
|
||||
advanced-font-settings = Дополнительные настройки шрифта
|
||||
default-font = Шрифт по умолчанию
|
||||
default-font-stretch = Растяжение шрифта по умолчанию
|
||||
default-font-weight = Масса шрифта по умолчанию
|
||||
default-dim-font-weight = Масса dim шрифта по умолчанию
|
||||
default-bold-font-weight = Масса жирного шрифта по умолчанию
|
||||
use-bright-bold = Использовать яркие цвета и жирный текст
|
||||
default-font-size = Размер шрифта по умолчанию
|
||||
default-zoom-step = Шаг масштабирования по умолчанию
|
||||
default-font-size = Размер шрифта
|
||||
default-font-stretch = Растяжение шрифта
|
||||
default-font-weight = Масса шрифта
|
||||
default-dim-font-weight = Масса dim шрифта
|
||||
default-bold-font-weight = Масса жирного шрифта
|
||||
use-bright-bold = Сделать жирный текст ярче
|
||||
|
||||
### Splits
|
||||
splits = Деления
|
||||
focus-follow-mouse = Фокус при наборе следует за мышью
|
||||
|
||||
### Advanced
|
||||
advanced = Дополнительно
|
||||
show-headerbar = Отображать заголовок
|
||||
show-header-description = Раскройте заголовок из меню правой кнопки мыши.
|
||||
|
||||
# Find
|
||||
find-placeholder = Найти...
|
||||
|
|
@ -44,7 +56,12 @@ find = Найти
|
|||
|
||||
## View
|
||||
view = Вид
|
||||
zoom-in = Текст крупнее
|
||||
zoom-reset = Размер текста по умолчанию
|
||||
zoom-out = Текст меньше
|
||||
next-tab = Следующая вкладка
|
||||
previous-tab = Предыдущая вкладка
|
||||
split-horizontal = Разделение по горизонтали
|
||||
split-vertical = Разделение по вертикали
|
||||
pane-toggle-maximize = Переключить на весь экран
|
||||
menu-settings = Параметры...
|
||||
|
||||
# Context menu
|
||||
show-headerbar = Отображать заголовок
|
||||
67
i18n/sv-SE/cosmic_term.ftl
Normal file
67
i18n/sv-SE/cosmic_term.ftl
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
# Context sidor
|
||||
|
||||
## Settings
|
||||
settings = Inställningar
|
||||
|
||||
### Appearance
|
||||
appearance = Utseende
|
||||
theme = Tema
|
||||
match-desktop = Matcha skrivbordet
|
||||
dark = Mörkt
|
||||
light = Ljust
|
||||
syntax-dark = Färgschema mörkt
|
||||
syntax-light = Färgschema ljust
|
||||
default-zoom-step = Zoom steg
|
||||
|
||||
### Teckensnitt
|
||||
font = Teckensnitt
|
||||
advanced-font-settings = Avancerade teckensnittsinställningar
|
||||
default-font = Teckensnitt
|
||||
default-font-size = Teckenstorlek
|
||||
default-font-stretch = Teckenstretch
|
||||
default-font-weight = Normal teckensnittsvikt
|
||||
default-dim-font-weight = Dämpad teckensnittsvikt
|
||||
default-bold-font-weight = Fet teckensnittsvikt
|
||||
use-bright-bold = Gör fet text ljusare
|
||||
|
||||
### Delar
|
||||
splits = Delar
|
||||
focus-follow-mouse = Skrivfokus följer mus
|
||||
|
||||
### Avancerat
|
||||
advanced = Avancerat
|
||||
show-headerbar = Visa rubrikrad
|
||||
show-header-description = Visa rubrikrad från högerklicksmenyn.
|
||||
|
||||
# Sök
|
||||
find-placeholder = Sök…
|
||||
find-previous = Hitta föregående
|
||||
find-next = Hitta nästa
|
||||
|
||||
# Meny
|
||||
|
||||
## Fil
|
||||
file = Fil
|
||||
new-tab = Ny flik
|
||||
new-window = Nytt fönster
|
||||
close-tab = Stäng flik
|
||||
quit = Avsluta
|
||||
|
||||
## Redigera
|
||||
edit = Redigera
|
||||
copy = Kopiera
|
||||
paste = Klistra in
|
||||
select-all = Välj alla
|
||||
find = Sök
|
||||
|
||||
## Visa
|
||||
view = Visa
|
||||
zoom-in = Zooma in
|
||||
zoom-reset = Återställ zoom
|
||||
zoom-out = Zooma ut
|
||||
next-tab = Nästa flik
|
||||
previous-tab = Föregående flik
|
||||
split-horizontal = Dela horisontellt
|
||||
split-vertical = Dela vertikalt
|
||||
pane-toggle-maximize = Växla maximerad
|
||||
menu-settings = Inställningar…
|
||||
78
i18n/tr/cosmic-term.ftl
Normal file
78
i18n/tr/cosmic-term.ftl
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
# Context Pages
|
||||
|
||||
## Profiles
|
||||
profiles = Profiller
|
||||
name = İsim
|
||||
command-line = Komut satırı
|
||||
tab-title = Sekme başlığı
|
||||
tab-title-description = Varsayılan sekme başlığını geçersiz kılar
|
||||
add-profile = Profil ekle
|
||||
new-profile = Yeni profil
|
||||
|
||||
## Settings
|
||||
settings = Ayarlar
|
||||
|
||||
### Appearance
|
||||
appearance = Görünüm
|
||||
theme = Tema
|
||||
match-desktop = Masaüstüyle eşle
|
||||
dark = Karanlık
|
||||
light = Aydınlık
|
||||
syntax-dark = Karanlık renk şeması
|
||||
syntax-light = Aydınlık renk şeması
|
||||
default-zoom-step = Yakınlaştırma basamakları
|
||||
|
||||
### Font
|
||||
font = Yazı tipi
|
||||
advanced-font-settings = Gelişmiş Yazı tipi Seçenekleri
|
||||
default-font = Yazı tipi
|
||||
default-font-size = Yazı tipi boyutu
|
||||
default-font-stretch = Yazı tipi esnekliği
|
||||
default-font-weight = Normal yazı tipi ağırlığı
|
||||
default-dim-font-weight = Soluk yazı tipi ağırlığı
|
||||
default-bold-font-weight = Kalın yazı tipi ağırlığı
|
||||
use-bright-bold = Kalın metni daha parlak yap
|
||||
|
||||
### Splits
|
||||
splits = Bölmeler
|
||||
focus-follow-mouse = Yazma odağı fareyi takip etsin
|
||||
|
||||
### Advanced
|
||||
advanced = Gelişmiş
|
||||
show-headerbar = Başlığı göster
|
||||
show-header-description = Sağ tıklama menüsünden başlığı gösterin.
|
||||
|
||||
# Find
|
||||
find-placeholder = Bul...
|
||||
find-previous = Öncekini bul
|
||||
find-next = Sonrakini bul
|
||||
|
||||
# Menu
|
||||
|
||||
## File
|
||||
file = Dosyal
|
||||
new-tab = Yeni sekme
|
||||
new-window = Yeni pencere
|
||||
profile = Profil
|
||||
menu-profiles = Profiller...
|
||||
close-tab = Sekmeyi kapat
|
||||
quit = Çık
|
||||
|
||||
## Edit
|
||||
edit = Düzenle
|
||||
copy = Kopyala
|
||||
paste = Yapıştır
|
||||
select-all = Hepsini seç
|
||||
find = Bul
|
||||
|
||||
## View
|
||||
view = Görünüş
|
||||
zoom-in = Daha büyük metin
|
||||
zoom-reset = Varsayılan metin boyutu
|
||||
zoom-out = Daha küçük metin
|
||||
next-tab = Sonraki sekme
|
||||
previous-tab = Önceki sekme
|
||||
split-horizontal = Yatay böl
|
||||
split-vertical = Dikey böl
|
||||
pane-toggle-maximize = En üste geç
|
||||
menu-settings = Ayarlar...
|
||||
6
justfile
6
justfile
|
|
@ -46,9 +46,13 @@ check *args:
|
|||
# Runs a clippy check with JSON message format
|
||||
check-json: (check '--message-format=json')
|
||||
|
||||
dev *args:
|
||||
cargo fmt
|
||||
just run {{args}}
|
||||
|
||||
# Run with debug logs
|
||||
run *args:
|
||||
env RUST_LOG=debug RUST_BACKTRACE=full cargo run --release {{args}}
|
||||
env RUST_LOG=cosmic_term=debug RUST_BACKTRACE=full cargo run --release {{args}}
|
||||
|
||||
# Installs files
|
||||
install:
|
||||
|
|
|
|||
4
res/icons/edit-delete-symbolic.svg
Normal file
4
res/icons/edit-delete-symbolic.svg
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M2 4.98999V13.99C2 14.514 2.476 14.99 3 14.99H12C12.524 14.99 13 14.514 13 13.99V4.98999H2Z" fill="#232323"/>
|
||||
<path d="M1 2.99001V3.99001L14 3.98701V2.99001C14 1.99001 13 1.98701 13 1.98701H10C10 1.98701 10 0.987 9 0.987H6C5 0.987 5 1.98701 5 1.98701H2C2 1.98701 1 1.99001 1 2.99001Z" fill="#232323"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 414 B |
3
res/icons/list-add-symbolic.svg
Normal file
3
res/icons/list-add-symbolic.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8 3C7.73478 3 7.48043 3.10536 7.29289 3.29289C7.10536 3.48043 7 3.73478 7 4V6.996L4 7C3.73478 7 3.48043 7.10536 3.29289 7.29289C3.10536 7.48043 3 7.73478 3 8C3 8.26522 3.10536 8.51957 3.29289 8.70711C3.48043 8.89464 3.73478 9 4 9L7 8.996V12C7 12.2652 7.10536 12.5196 7.29289 12.7071C7.48043 12.8946 7.73478 13 8 13C8.26522 13 8.51957 12.8946 8.70711 12.7071C8.89464 12.5196 9 12.2652 9 12V8.996L12 9C12.2652 9 12.5196 8.89464 12.7071 8.70711C12.8946 8.51957 13 8.26522 13 8C13 7.73478 12.8946 7.48043 12.7071 7.29289C12.5196 7.10536 12.2652 7 12 7L9 6.996V4C9 3.73478 8.89464 3.48043 8.70711 3.29289C8.51957 3.10536 8.26522 3 8 3Z" fill="#232323"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 762 B |
|
|
@ -10,6 +10,8 @@ use serde::{Deserialize, Serialize};
|
|||
use std::collections::BTreeMap;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use crate::fl;
|
||||
|
||||
pub const CONFIG_VERSION: u64 = 1;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
|
|
@ -29,6 +31,35 @@ impl AppTheme {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct ProfileId(pub u64);
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
pub struct Profile {
|
||||
pub name: String,
|
||||
#[serde(default)]
|
||||
pub command: String,
|
||||
#[serde(default)]
|
||||
pub syntax_theme_dark: String,
|
||||
#[serde(default)]
|
||||
pub syntax_theme_light: String,
|
||||
#[serde(default)]
|
||||
pub tab_title: String,
|
||||
}
|
||||
|
||||
impl Default for Profile {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
name: fl!("new-profile"),
|
||||
command: String::new(),
|
||||
syntax_theme_dark: "COSMIC Dark".to_string(),
|
||||
syntax_theme_light: "COSMIC Light".to_string(),
|
||||
tab_title: String::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, CosmicConfigEntry, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
pub struct Config {
|
||||
pub app_theme: AppTheme,
|
||||
|
|
@ -39,6 +70,8 @@ pub struct Config {
|
|||
pub bold_font_weight: u16,
|
||||
pub font_stretch: u16,
|
||||
pub font_size_zoom_step_mul_100: u16,
|
||||
pub opacity: u8,
|
||||
pub profiles: BTreeMap<ProfileId, Profile>,
|
||||
pub show_headerbar: bool,
|
||||
pub use_bright_bold: bool,
|
||||
pub syntax_theme_dark: String,
|
||||
|
|
@ -50,18 +83,20 @@ impl Default for Config {
|
|||
fn default() -> Self {
|
||||
Self {
|
||||
app_theme: AppTheme::System,
|
||||
bold_font_weight: Weight::BOLD.0,
|
||||
dim_font_weight: Weight::NORMAL.0,
|
||||
focus_follow_mouse: false,
|
||||
font_name: "Fira Mono".to_string(),
|
||||
font_size: 14,
|
||||
font_weight: Weight::NORMAL.0,
|
||||
dim_font_weight: Weight::NORMAL.0,
|
||||
bold_font_weight: Weight::BOLD.0,
|
||||
font_stretch: Stretch::Normal.to_number(),
|
||||
font_size_zoom_step_mul_100: 100,
|
||||
font_stretch: Stretch::Normal.to_number(),
|
||||
font_weight: Weight::NORMAL.0,
|
||||
opacity: 100,
|
||||
profiles: BTreeMap::new(),
|
||||
show_headerbar: true,
|
||||
use_bright_bold: false,
|
||||
syntax_theme_dark: "COSMIC Dark".to_string(),
|
||||
syntax_theme_light: "COSMIC Light".to_string(),
|
||||
focus_follow_mouse: false,
|
||||
use_bright_bold: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -81,13 +116,46 @@ impl Config {
|
|||
Metrics::new(font_size, line_height)
|
||||
}
|
||||
|
||||
pub fn opacity_ratio(&self) -> f32 {
|
||||
(self.opacity as f32) / 100.0
|
||||
}
|
||||
|
||||
// Get a sorted and adjusted for duplicates list of profiles names and ids
|
||||
pub fn profile_names(&self) -> Vec<(String, ProfileId)> {
|
||||
let mut profile_names = Vec::<(String, ProfileId)>::with_capacity(self.profiles.len());
|
||||
for (profile_id, profile) in self.profiles.iter() {
|
||||
let mut name = profile.name.clone();
|
||||
|
||||
let mut copies = 1;
|
||||
while profile_names.iter().find(|x| x.0 == name).is_some() {
|
||||
copies += 1;
|
||||
name = format!("{} ({})", profile.name, copies);
|
||||
}
|
||||
|
||||
profile_names.push((name, *profile_id));
|
||||
}
|
||||
profile_names.sort_by(|a, b| lexical_sort::natural_lexical_cmp(&a.0, &b.0));
|
||||
profile_names
|
||||
}
|
||||
|
||||
// Get current syntax theme based on dark mode
|
||||
pub fn syntax_theme(&self) -> &str {
|
||||
pub fn syntax_theme(&self, profile_id_opt: Option<ProfileId>) -> &str {
|
||||
let dark = self.app_theme.theme().theme_type.is_dark();
|
||||
if dark {
|
||||
&self.syntax_theme_dark
|
||||
} else {
|
||||
&self.syntax_theme_light
|
||||
match profile_id_opt.and_then(|profile_id| self.profiles.get(&profile_id)) {
|
||||
Some(profile) => {
|
||||
if dark {
|
||||
&profile.syntax_theme_dark
|
||||
} else {
|
||||
&profile.syntax_theme_light
|
||||
}
|
||||
}
|
||||
None => {
|
||||
if dark {
|
||||
&self.syntax_theme_dark
|
||||
} else {
|
||||
&self.syntax_theme_light
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ impl IconCache {
|
|||
}
|
||||
|
||||
bundle!("edit-clear-symbolic", 16);
|
||||
bundle!("edit-delete-symbolic", 16);
|
||||
bundle!("list-add-symbolic", 16);
|
||||
bundle!("go-down-symbolic", 16);
|
||||
bundle!("go-up-symbolic", 16);
|
||||
bundle!("window-close-symbolic", 16);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
use cosmic::iced::keyboard::{KeyCode, Modifiers};
|
||||
use cosmic::{
|
||||
iced::keyboard::{Key, Modifiers},
|
||||
iced_core::keyboard::key::Named,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{collections::HashMap, fmt};
|
||||
|
||||
|
|
@ -15,12 +18,12 @@ pub enum Modifier {
|
|||
#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
|
||||
pub struct KeyBind {
|
||||
pub modifiers: Vec<Modifier>,
|
||||
pub key_code: KeyCode,
|
||||
pub key: Key,
|
||||
}
|
||||
|
||||
impl KeyBind {
|
||||
pub fn matches(&self, modifiers: Modifiers, key_code: KeyCode) -> bool {
|
||||
self.key_code == key_code
|
||||
pub fn matches(&self, modifiers: Modifiers, key: &Key) -> bool {
|
||||
key == &self.key
|
||||
&& modifiers.logo() == self.modifiers.contains(&Modifier::Super)
|
||||
&& modifiers.control() == self.modifiers.contains(&Modifier::Ctrl)
|
||||
&& modifiers.alt() == self.modifiers.contains(&Modifier::Alt)
|
||||
|
|
@ -33,7 +36,11 @@ impl fmt::Display for KeyBind {
|
|||
for modifier in self.modifiers.iter() {
|
||||
write!(f, "{:?} + ", modifier)?;
|
||||
}
|
||||
write!(f, "{:?}", self.key_code)
|
||||
match &self.key {
|
||||
Key::Character(c) => write!(f, "{}", c.to_uppercase()),
|
||||
Key::Named(named) => write!(f, "{:?}", named),
|
||||
other => write!(f, "{:?}", other),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -42,11 +49,11 @@ pub fn key_binds() -> HashMap<KeyBind, Action> {
|
|||
let mut key_binds = HashMap::new();
|
||||
|
||||
macro_rules! bind {
|
||||
([$($modifier:ident),+ $(,)?], $key_code:ident, $action:ident) => {{
|
||||
([$($modifier:ident),+ $(,)?], $key:expr, $action:ident) => {{
|
||||
key_binds.insert(
|
||||
KeyBind {
|
||||
modifiers: vec![$(Modifier::$modifier),+],
|
||||
key_code: KeyCode::$key_code,
|
||||
key: $key,
|
||||
},
|
||||
Action::$action,
|
||||
);
|
||||
|
|
@ -54,52 +61,56 @@ pub fn key_binds() -> HashMap<KeyBind, Action> {
|
|||
}
|
||||
|
||||
// Standard key bindings
|
||||
bind!([Ctrl, Shift], A, SelectAll);
|
||||
bind!([Ctrl, Shift], C, Copy);
|
||||
bind!([Ctrl, Shift], F, Find);
|
||||
bind!([Ctrl, Shift], N, WindowNew);
|
||||
bind!([Ctrl, Shift], Q, WindowClose);
|
||||
bind!([Ctrl, Shift], T, TabNew);
|
||||
bind!([Ctrl, Shift], V, Paste);
|
||||
bind!([Shift], Insert, PastePrimary);
|
||||
bind!([Ctrl, Shift], W, TabClose);
|
||||
bind!([Ctrl, Shift], Key::Character("A".into()), SelectAll);
|
||||
bind!([Ctrl, Shift], Key::Character("C".into()), Copy);
|
||||
bind!([Ctrl, Shift], Key::Character("F".into()), Find);
|
||||
bind!([Ctrl, Shift], Key::Character("N".into()), WindowNew);
|
||||
bind!([Ctrl, Shift], Key::Character("Q".into()), WindowClose);
|
||||
bind!([Ctrl, Shift], Key::Character("T".into()), TabNew);
|
||||
bind!([Ctrl, Shift], Key::Character("V".into()), Paste);
|
||||
bind!([Shift], Key::Named(Named::Insert), PastePrimary);
|
||||
bind!([Ctrl, Shift], Key::Character("W".into()), TabClose);
|
||||
|
||||
// Ctrl+Alt+D splits horizontally, Ctrl+Alt+R splits vertically, Ctrl+Shift+X maximizes split
|
||||
//TODO: Adjust bindings as desired by UX
|
||||
bind!([Ctrl, Alt], D, PaneSplitHorizontal);
|
||||
bind!([Ctrl, Alt], R, PaneSplitVertical);
|
||||
bind!([Ctrl, Shift], X, PaneToggleMaximized);
|
||||
bind!([Ctrl, Alt], Key::Character("d".into()), PaneSplitHorizontal);
|
||||
bind!([Ctrl, Alt], Key::Character("r".into()), PaneSplitVertical);
|
||||
bind!(
|
||||
[Ctrl, Shift],
|
||||
Key::Character("X".into()),
|
||||
PaneToggleMaximized
|
||||
);
|
||||
|
||||
// Ctrl+Tab and Ctrl+Shift+Tab cycle through tabs
|
||||
// Ctrl+Tab is not a special key for terminals and is free to use
|
||||
bind!([Ctrl], Tab, TabNext);
|
||||
bind!([Ctrl, Shift], Tab, TabPrev);
|
||||
bind!([Ctrl], Key::Named(Named::Tab), TabNext);
|
||||
bind!([Ctrl, Shift], Key::Named(Named::Tab), TabPrev);
|
||||
|
||||
// Ctrl+Shift+# activates tabs by index
|
||||
bind!([Ctrl, Shift], Key1, TabActivate0);
|
||||
bind!([Ctrl, Shift], Key2, TabActivate1);
|
||||
bind!([Ctrl, Shift], Key3, TabActivate2);
|
||||
bind!([Ctrl, Shift], Key4, TabActivate3);
|
||||
bind!([Ctrl, Shift], Key5, TabActivate4);
|
||||
bind!([Ctrl, Shift], Key6, TabActivate5);
|
||||
bind!([Ctrl, Shift], Key7, TabActivate6);
|
||||
bind!([Ctrl, Shift], Key8, TabActivate7);
|
||||
bind!([Ctrl, Shift], Key9, TabActivate8);
|
||||
bind!([Ctrl, Shift], Key::Character("!".into()), TabActivate0);
|
||||
bind!([Ctrl, Shift], Key::Character("@".into()), TabActivate1);
|
||||
bind!([Ctrl, Shift], Key::Character("#".into()), TabActivate2);
|
||||
bind!([Ctrl, Shift], Key::Character("$".into()), TabActivate3);
|
||||
bind!([Ctrl, Shift], Key::Character("%".into()), TabActivate4);
|
||||
bind!([Ctrl, Shift], Key::Character("^".into()), TabActivate5);
|
||||
bind!([Ctrl, Shift], Key::Character("&".into()), TabActivate6);
|
||||
bind!([Ctrl, Shift], Key::Character("*".into()), TabActivate7);
|
||||
bind!([Ctrl, Shift], Key::Character("(".into()), TabActivate8);
|
||||
|
||||
// Ctrl+0, Ctrl+-, and Ctrl+= are not special keys for terminals and are free to use
|
||||
bind!([Ctrl], Key0, ZoomReset);
|
||||
bind!([Ctrl], Minus, ZoomOut);
|
||||
bind!([Ctrl], Equals, ZoomIn);
|
||||
bind!([Ctrl], Key::Character("0".into()), ZoomReset);
|
||||
bind!([Ctrl], Key::Character("-".into()), ZoomOut);
|
||||
bind!([Ctrl], Key::Character("=".into()), ZoomIn);
|
||||
|
||||
// Ctrl+Arrows and Ctrl+HJKL move between splits
|
||||
bind!([Ctrl, Shift], Left, PaneFocusLeft);
|
||||
bind!([Ctrl, Shift], H, PaneFocusLeft);
|
||||
bind!([Ctrl, Shift], Down, PaneFocusDown);
|
||||
bind!([Ctrl, Shift], J, PaneFocusDown);
|
||||
bind!([Ctrl, Shift], Up, PaneFocusUp);
|
||||
bind!([Ctrl, Shift], K, PaneFocusUp);
|
||||
bind!([Ctrl, Shift], Right, PaneFocusRight);
|
||||
bind!([Ctrl, Shift], L, PaneFocusRight);
|
||||
bind!([Ctrl, Shift], Key::Named(Named::ArrowLeft), PaneFocusLeft);
|
||||
bind!([Ctrl, Shift], Key::Character("H".into()), PaneFocusLeft);
|
||||
bind!([Ctrl, Shift], Key::Named(Named::ArrowDown), PaneFocusDown);
|
||||
bind!([Ctrl, Shift], Key::Character("J".into()), PaneFocusDown);
|
||||
bind!([Ctrl, Shift], Key::Named(Named::ArrowUp), PaneFocusUp);
|
||||
bind!([Ctrl, Shift], Key::Character("K".into()), PaneFocusUp);
|
||||
bind!([Ctrl, Shift], Key::Named(Named::ArrowRight), PaneFocusRight);
|
||||
bind!([Ctrl, Shift], Key::Character("L".into()), PaneFocusRight);
|
||||
|
||||
key_binds
|
||||
}
|
||||
|
|
|
|||
658
src/main.rs
658
src/main.rs
File diff suppressed because it is too large
Load diff
24
src/menu.rs
24
src/menu.rs
|
|
@ -6,6 +6,7 @@ use cosmic::{
|
|||
widget::{column, horizontal_rule, horizontal_space},
|
||||
Alignment, Background, Length,
|
||||
},
|
||||
iced_core::Border,
|
||||
theme,
|
||||
widget::{
|
||||
self,
|
||||
|
|
@ -95,16 +96,19 @@ pub fn context_menu<'a>(
|
|||
icon_color: Some(component.on.into()),
|
||||
text_color: Some(component.on.into()),
|
||||
background: Some(Background::Color(component.base.into())),
|
||||
border_radius: 8.0.into(),
|
||||
border_width: 1.0,
|
||||
border_color: component.divider.into(),
|
||||
border: Border {
|
||||
radius: 8.0.into(),
|
||||
width: 1.0,
|
||||
color: component.divider.into(),
|
||||
},
|
||||
..Default::default()
|
||||
}
|
||||
}))
|
||||
.width(Length::Fixed(240.0))
|
||||
.into()
|
||||
}
|
||||
|
||||
pub fn menu_bar<'a>(key_binds: &HashMap<KeyBind, Action>) -> Element<'a, Message> {
|
||||
pub fn menu_bar<'a>(config: &Config, key_binds: &HashMap<KeyBind, Action>) -> Element<'a, Message> {
|
||||
//TODO: port to libcosmic
|
||||
let menu_root = |label| {
|
||||
widget::button(widget::text(label))
|
||||
|
|
@ -112,6 +116,9 @@ pub fn menu_bar<'a>(key_binds: &HashMap<KeyBind, Action>) -> Element<'a, Message
|
|||
.style(theme::Button::MenuRoot)
|
||||
};
|
||||
|
||||
let menu_folder =
|
||||
|label| menu_button!(widget::text(label), horizontal_space(Length::Fill), ">");
|
||||
|
||||
let find_key = |action: &Action| -> String {
|
||||
for (key_bind, key_action) in key_binds.iter() {
|
||||
if action == key_action {
|
||||
|
|
@ -133,6 +140,12 @@ pub fn menu_bar<'a>(key_binds: &HashMap<KeyBind, Action>) -> Element<'a, Message
|
|||
)
|
||||
};
|
||||
|
||||
let mut profile_items = Vec::with_capacity(config.profiles.len());
|
||||
for (name, id) in config.profile_names() {
|
||||
profile_items.push(menu_item(name, Action::ProfileOpen(id)));
|
||||
}
|
||||
//TODO: what to do if there are no profiles?
|
||||
|
||||
MenuBar::new(vec![
|
||||
MenuTree::with_children(
|
||||
menu_root(fl!("file")),
|
||||
|
|
@ -140,6 +153,9 @@ pub fn menu_bar<'a>(key_binds: &HashMap<KeyBind, Action>) -> Element<'a, Message
|
|||
menu_item(fl!("new-tab"), Action::TabNew),
|
||||
menu_item(fl!("new-window"), Action::WindowNew),
|
||||
MenuTree::new(horizontal_rule(1)),
|
||||
MenuTree::with_children(menu_folder(fl!("profile")), profile_items),
|
||||
menu_item(fl!("menu-profiles"), Action::Profiles),
|
||||
MenuTree::new(horizontal_rule(1)),
|
||||
menu_item(fl!("close-tab"), Action::TabClose),
|
||||
MenuTree::new(horizontal_rule(1)),
|
||||
menu_item(fl!("quit"), Action::WindowClose),
|
||||
|
|
|
|||
|
|
@ -172,6 +172,7 @@ impl MouseReporter {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn report_sgr_mouse_wheel_scroll(
|
||||
&self,
|
||||
terminal: &Terminal,
|
||||
|
|
|
|||
159
src/terminal.rs
159
src/terminal.rs
|
|
@ -9,7 +9,7 @@ use alacritty_terminal::{
|
|||
cell::Flags,
|
||||
color::{self, Colors},
|
||||
search::RegexSearch,
|
||||
viewport_to_point, Config, TermMode,
|
||||
viewport_to_point, Config, TermDamage, TermMode,
|
||||
},
|
||||
tty::{self, Options},
|
||||
vte::ansi::{Color, NamedColor, Rgb},
|
||||
|
|
@ -27,7 +27,7 @@ use indexmap::IndexSet;
|
|||
use std::{
|
||||
borrow::Cow,
|
||||
collections::HashMap,
|
||||
mem,
|
||||
io, mem,
|
||||
sync::{
|
||||
atomic::{AtomicU32, Ordering},
|
||||
Arc, Weak,
|
||||
|
|
@ -38,7 +38,10 @@ use tokio::sync::mpsc;
|
|||
|
||||
pub use alacritty_terminal::grid::Scroll as TerminalScroll;
|
||||
|
||||
use crate::{config::Config as AppConfig, mouse_reporter::MouseReporter};
|
||||
use crate::{
|
||||
config::{Config as AppConfig, ProfileId},
|
||||
mouse_reporter::MouseReporter,
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Size {
|
||||
|
|
@ -187,21 +190,23 @@ impl Metadata {
|
|||
}
|
||||
|
||||
pub struct Terminal {
|
||||
default_attrs: Attrs<'static>,
|
||||
buffer: Arc<Buffer>,
|
||||
size: Size,
|
||||
pub term: Arc<FairMutex<Term<EventProxy>>>,
|
||||
colors: Colors,
|
||||
dim_font_weight: Weight,
|
||||
bold_font_weight: Weight,
|
||||
use_bright_bold: bool,
|
||||
notifier: Notifier,
|
||||
pub context_menu: Option<cosmic::iced::Point>,
|
||||
pub metadata_set: IndexSet<Metadata>,
|
||||
pub needs_update: bool,
|
||||
pub profile_id_opt: Option<ProfileId>,
|
||||
pub tab_title_override: Option<String>,
|
||||
pub term: Arc<FairMutex<Term<EventProxy>>>,
|
||||
bold_font_weight: Weight,
|
||||
buffer: Arc<Buffer>,
|
||||
colors: Colors,
|
||||
default_attrs: Attrs<'static>,
|
||||
dim_font_weight: Weight,
|
||||
mouse_reporter: MouseReporter,
|
||||
notifier: Notifier,
|
||||
search_regex_opt: Option<RegexSearch>,
|
||||
search_value: String,
|
||||
pub metadata_set: IndexSet<Metadata>,
|
||||
mouse_reporter: MouseReporter,
|
||||
size: Size,
|
||||
use_bright_bold: bool,
|
||||
}
|
||||
|
||||
impl Terminal {
|
||||
|
|
@ -214,7 +219,9 @@ impl Terminal {
|
|||
options: Options,
|
||||
app_config: &AppConfig,
|
||||
colors: Colors,
|
||||
) -> Self {
|
||||
profile_id_opt: Option<ProfileId>,
|
||||
tab_title_override: Option<String>,
|
||||
) -> Result<Self, io::Error> {
|
||||
let font_stretch = app_config.typed_font_stretch();
|
||||
let font_weight = app_config.font_weight;
|
||||
let dim_font_weight = app_config.dim_font_weight;
|
||||
|
|
@ -242,12 +249,12 @@ impl Terminal {
|
|||
|
||||
let (cell_width, cell_height) = {
|
||||
let mut font_system = font_system().write().unwrap();
|
||||
let mut font_system = font_system.raw();
|
||||
buffer.set_wrap(&mut font_system, Wrap::None);
|
||||
let font_system = font_system.raw();
|
||||
buffer.set_wrap(font_system, Wrap::None);
|
||||
|
||||
// Use size of space to determine cell size
|
||||
buffer.set_text(&mut font_system, " ", default_attrs, Shaping::Advanced);
|
||||
let layout = buffer.line_layout(&mut font_system, 0).unwrap();
|
||||
buffer.set_text(font_system, " ", default_attrs, Shaping::Advanced);
|
||||
let layout = buffer.line_layout(font_system, 0).unwrap();
|
||||
let w = layout[0].w;
|
||||
buffer.set_monospace_width(font_system, Some(w));
|
||||
(w, metrics.line_height)
|
||||
|
|
@ -267,29 +274,31 @@ impl Terminal {
|
|||
)));
|
||||
|
||||
let window_id = 0;
|
||||
let pty = tty::new(&options, size.into(), window_id).unwrap();
|
||||
let pty = tty::new(&options, size.into(), window_id)?;
|
||||
|
||||
let pty_event_loop = EventLoop::new(term.clone(), event_proxy, pty, options.hold, false);
|
||||
let notifier = Notifier(pty_event_loop.channel());
|
||||
let _pty_join_handle = pty_event_loop.spawn();
|
||||
|
||||
Self {
|
||||
colors,
|
||||
dim_font_weight: Weight(dim_font_weight),
|
||||
Ok(Self {
|
||||
bold_font_weight: Weight(bold_font_weight),
|
||||
use_bright_bold,
|
||||
default_attrs,
|
||||
buffer: Arc::new(buffer),
|
||||
size,
|
||||
term,
|
||||
notifier,
|
||||
colors,
|
||||
context_menu: None,
|
||||
needs_update: true,
|
||||
search_regex_opt: None,
|
||||
search_value: String::new(),
|
||||
default_attrs,
|
||||
dim_font_weight: Weight(dim_font_weight),
|
||||
metadata_set,
|
||||
mouse_reporter: Default::default(),
|
||||
}
|
||||
needs_update: true,
|
||||
notifier,
|
||||
profile_id_opt,
|
||||
search_regex_opt: None,
|
||||
search_value: String::new(),
|
||||
size,
|
||||
tab_title_override,
|
||||
term,
|
||||
use_bright_bold,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn buffer_weak(&self) -> Weak<Buffer> {
|
||||
|
|
@ -371,6 +380,8 @@ impl Terminal {
|
|||
buffer.set_size(font_system.raw(), width as f32, height as f32);
|
||||
});
|
||||
|
||||
self.needs_update = true;
|
||||
|
||||
log::debug!("resize {:?}", instant.elapsed());
|
||||
}
|
||||
}
|
||||
|
|
@ -459,7 +470,7 @@ impl Terminal {
|
|||
};
|
||||
|
||||
// Find next search match
|
||||
match term.search_next(
|
||||
if let Some(search_match) = term.search_next(
|
||||
search_regex,
|
||||
search_origin,
|
||||
if forwards {
|
||||
|
|
@ -471,21 +482,18 @@ impl Terminal {
|
|||
if forwards { Side::Left } else { Side::Right },
|
||||
None,
|
||||
) {
|
||||
Some(search_match) => {
|
||||
// Scroll to match
|
||||
if forwards {
|
||||
term.scroll_to_point(*search_match.end());
|
||||
} else {
|
||||
term.scroll_to_point(*search_match.start());
|
||||
}
|
||||
|
||||
// Set selection to match
|
||||
let mut selection =
|
||||
Selection::new(SelectionType::Simple, *search_match.start(), Side::Left);
|
||||
selection.update(*search_match.end(), Side::Right);
|
||||
term.selection = Some(selection);
|
||||
// Scroll to match
|
||||
if forwards {
|
||||
term.scroll_to_point(*search_match.end());
|
||||
} else {
|
||||
term.scroll_to_point(*search_match.start());
|
||||
}
|
||||
None => {}
|
||||
|
||||
// Set selection to match
|
||||
let mut selection =
|
||||
Selection::new(SelectionType::Simple, *search_match.start(), Side::Left);
|
||||
selection.update(*search_match.end(), Side::Right);
|
||||
term.selection = Some(selection);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -551,7 +559,7 @@ impl Terminal {
|
|||
update_cell_size = true;
|
||||
}
|
||||
|
||||
if let Some(colors) = themes.get(config.syntax_theme()) {
|
||||
if let Some(colors) = themes.get(config.syntax_theme(self.profile_id_opt)) {
|
||||
let mut changed = false;
|
||||
for i in 0..color::COUNT {
|
||||
if self.colors[i] != colors[i] {
|
||||
|
|
@ -560,19 +568,7 @@ impl Terminal {
|
|||
}
|
||||
}
|
||||
if changed {
|
||||
self.metadata_set.clear();
|
||||
let default_bg = convert_color(&colors, Color::Named(NamedColor::Background));
|
||||
let default_fg = convert_color(&colors, Color::Named(NamedColor::Foreground));
|
||||
|
||||
let default_metadata = Metadata::new(default_bg, default_fg);
|
||||
let (default_metadata_idx, _) = self.metadata_set.insert_full(default_metadata);
|
||||
|
||||
self.default_attrs = Attrs::new()
|
||||
.family(Family::Monospace)
|
||||
.weight(Weight(config.font_weight))
|
||||
.stretch(config.typed_font_stretch())
|
||||
.color(default_fg)
|
||||
.metadata(default_metadata_idx);
|
||||
self.update_colors(config);
|
||||
update = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -584,6 +580,22 @@ impl Terminal {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn update_colors(&mut self, config: &AppConfig) {
|
||||
self.metadata_set.clear();
|
||||
let default_bg = convert_color(&self.colors, Color::Named(NamedColor::Background));
|
||||
let default_fg = convert_color(&self.colors, Color::Named(NamedColor::Foreground));
|
||||
|
||||
let default_metadata = Metadata::new(default_bg, default_fg);
|
||||
let (default_metadata_idx, _) = self.metadata_set.insert_full(default_metadata);
|
||||
|
||||
self.default_attrs = Attrs::new()
|
||||
.family(Family::Monospace)
|
||||
.weight(Weight(config.font_weight))
|
||||
.stretch(config.typed_font_stretch())
|
||||
.color(default_fg)
|
||||
.metadata(default_metadata_idx);
|
||||
}
|
||||
|
||||
pub fn update_cell_size(&mut self) {
|
||||
let default_attrs = self.default_attrs;
|
||||
let (cell_width, cell_height) = {
|
||||
|
|
@ -634,7 +646,14 @@ impl Terminal {
|
|||
let mut text = String::from(LRI);
|
||||
let mut attrs_list = AttrsList::new(self.default_attrs);
|
||||
{
|
||||
let term = self.term.lock();
|
||||
let mut term = self.term.lock();
|
||||
//TODO: use damage?
|
||||
match term.damage() {
|
||||
TermDamage::Full => {}
|
||||
TermDamage::Partial(_damage_lines) => {}
|
||||
}
|
||||
term.reset_damage();
|
||||
|
||||
let grid = term.grid();
|
||||
for indexed in grid.display_iter() {
|
||||
if indexed.point.line != last_point.unwrap_or(indexed.point).line {
|
||||
|
|
@ -647,10 +666,7 @@ impl Terminal {
|
|||
buffer.set_redraw(true);
|
||||
}
|
||||
|
||||
// Tab skip/stop is handled by alacritty_terminal
|
||||
if buffer.lines[line_i]
|
||||
.set_text(text.replace('\t', " "), attrs_list.clone())
|
||||
{
|
||||
if buffer.lines[line_i].set_text(text.clone(), attrs_list.clone()) {
|
||||
buffer.set_redraw(true);
|
||||
}
|
||||
line_i += 1;
|
||||
|
|
@ -668,7 +684,11 @@ impl Terminal {
|
|||
}
|
||||
|
||||
let start = text.len();
|
||||
text.push(indexed.cell.c);
|
||||
// Tab skip/stop is handled by alacritty_terminal
|
||||
text.push(match indexed.cell.c {
|
||||
'\t' => ' ',
|
||||
c => c,
|
||||
});
|
||||
if let Some(zerowidth) = indexed.cell.zerowidth() {
|
||||
for &c in zerowidth {
|
||||
text.push(c);
|
||||
|
|
@ -775,9 +795,11 @@ impl Terminal {
|
|||
buffer.set_redraw(true);
|
||||
}
|
||||
|
||||
// Shape and trim shape run cache
|
||||
{
|
||||
let mut font_system = font_system().write().unwrap();
|
||||
buffer.shape_until_scroll(font_system.raw(), true);
|
||||
font_system.raw().shape_run_cache.trim(1024);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -800,6 +822,7 @@ impl Terminal {
|
|||
) {
|
||||
let term_lock = self.term.lock();
|
||||
let mode = term_lock.mode();
|
||||
#[allow(clippy::collapsible_else_if)]
|
||||
if mode.contains(TermMode::SGR_MOUSE) {
|
||||
if let Some(code) = self.mouse_reporter.sgr_mouse_code(event, modifiers, x, y) {
|
||||
self.input_no_scroll(code)
|
||||
|
|
@ -849,6 +872,6 @@ impl Terminal {
|
|||
impl Drop for Terminal {
|
||||
fn drop(&mut self) {
|
||||
// Ensure shutdown on terminal drop
|
||||
let _ = self.notifier.0.send(Msg::Shutdown);
|
||||
self.notifier.0.send(Msg::Shutdown);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,14 +8,15 @@ use alacritty_terminal::{
|
|||
use cosmic::{
|
||||
cosmic_theme::palette::{blend::Compose, WithAlpha},
|
||||
iced::{
|
||||
advanced::graphics::text::{font_system, Raw},
|
||||
advanced::graphics::text::Raw,
|
||||
event::{Event, Status},
|
||||
keyboard::{Event as KeyEvent, KeyCode, Modifiers},
|
||||
keyboard::{Event as KeyEvent, Key, Modifiers},
|
||||
mouse::{self, Button, Event as MouseEvent, ScrollDelta},
|
||||
Color, Element, Length, Padding, Point, Rectangle, Size, Vector,
|
||||
},
|
||||
iced_core::{
|
||||
clipboard::Clipboard,
|
||||
keyboard::key::Named,
|
||||
layout::{self, Layout},
|
||||
renderer::{self, Quad, Renderer as _},
|
||||
text::Renderer as _,
|
||||
|
|
@ -24,7 +25,7 @@ use cosmic::{
|
|||
operation::{self, Operation, OperationOutputWrapper},
|
||||
tree, Id, Widget,
|
||||
},
|
||||
Shell,
|
||||
Border, Shell,
|
||||
},
|
||||
theme::Theme,
|
||||
Renderer,
|
||||
|
|
@ -34,22 +35,30 @@ use indexmap::IndexSet;
|
|||
use std::{
|
||||
cell::Cell,
|
||||
cmp,
|
||||
collections::HashMap,
|
||||
sync::Mutex,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
use crate::{terminal::Metadata, Terminal, TerminalScroll};
|
||||
use crate::{
|
||||
key_bind::{key_binds, KeyBind},
|
||||
terminal::Metadata,
|
||||
Action, Terminal, TerminalScroll,
|
||||
};
|
||||
|
||||
pub struct TerminalBox<'a, Message> {
|
||||
terminal: &'a Mutex<Terminal>,
|
||||
id: Option<Id>,
|
||||
border: Border,
|
||||
padding: Padding,
|
||||
click_timing: Duration,
|
||||
context_menu: Option<Point>,
|
||||
on_context_menu: Option<Box<dyn Fn(Option<Point>) -> Message + 'a>>,
|
||||
on_mouse_enter: Option<Box<dyn Fn() -> Message + 'a>>,
|
||||
opacity: Option<f32>,
|
||||
mouse_inside_boundary: Option<bool>,
|
||||
on_middle_click: Option<Box<dyn Fn() -> Message + 'a>>,
|
||||
key_binds: HashMap<KeyBind, Action>,
|
||||
}
|
||||
|
||||
impl<'a, Message> TerminalBox<'a, Message>
|
||||
|
|
@ -60,13 +69,16 @@ where
|
|||
Self {
|
||||
terminal,
|
||||
id: None,
|
||||
border: Border::default(),
|
||||
padding: Padding::new(0.0),
|
||||
click_timing: Duration::from_millis(500),
|
||||
context_menu: None,
|
||||
on_context_menu: None,
|
||||
on_mouse_enter: None,
|
||||
opacity: None,
|
||||
mouse_inside_boundary: None,
|
||||
on_middle_click: None,
|
||||
key_binds: key_binds(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -75,6 +87,11 @@ where
|
|||
self
|
||||
}
|
||||
|
||||
pub fn border<B: Into<Border>>(mut self, border: B) -> Self {
|
||||
self.border = border.into();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self {
|
||||
self.padding = padding.into();
|
||||
self
|
||||
|
|
@ -107,16 +124,21 @@ where
|
|||
self.on_middle_click = Some(Box::new(on_middle_click));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn opacity(mut self, opacity: f32) -> Self {
|
||||
self.opacity = Some(opacity);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub fn terminal_box<'a, Message>(terminal: &'a Mutex<Terminal>) -> TerminalBox<'a, Message>
|
||||
pub fn terminal_box<Message>(terminal: &Mutex<Terminal>) -> TerminalBox<'_, Message>
|
||||
where
|
||||
Message: Clone,
|
||||
{
|
||||
TerminalBox::new(terminal)
|
||||
}
|
||||
|
||||
impl<'a, Message> Widget<Message, Renderer> for TerminalBox<'a, Message>
|
||||
impl<'a, Message> Widget<Message, cosmic::Theme, Renderer> for TerminalBox<'a, Message>
|
||||
where
|
||||
Message: Clone,
|
||||
{
|
||||
|
|
@ -128,12 +150,8 @@ where
|
|||
tree::State::new(State::new())
|
||||
}
|
||||
|
||||
fn width(&self) -> Length {
|
||||
Length::Fill
|
||||
}
|
||||
|
||||
fn height(&self) -> Length {
|
||||
Length::Fill
|
||||
fn size(&self) -> Size<Length> {
|
||||
Size::new(Length::Fill, Length::Fill)
|
||||
}
|
||||
|
||||
fn layout(
|
||||
|
|
@ -154,12 +172,6 @@ where
|
|||
terminal.needs_update = false;
|
||||
}
|
||||
|
||||
// Ensure terminal is shaped
|
||||
terminal.with_buffer_mut(|buffer| {
|
||||
let mut font_system = font_system().write().unwrap();
|
||||
buffer.shape_until_scroll(font_system.raw(), true);
|
||||
});
|
||||
|
||||
// Calculate layout lines
|
||||
terminal.with_buffer(|buffer| {
|
||||
let mut layout_lines = 0;
|
||||
|
|
@ -173,7 +185,7 @@ where
|
|||
let height = layout_lines as f32 * buffer.metrics().line_height;
|
||||
let size = Size::new(limits.max().width, height);
|
||||
|
||||
layout::Node::new(limits.resolve(size))
|
||||
layout::Node::new(limits.resolve(Length::Fill, Length::Fill, size))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -199,9 +211,8 @@ where
|
|||
) -> mouse::Interaction {
|
||||
let state = tree.state.downcast_ref::<State>();
|
||||
|
||||
match &state.dragging {
|
||||
Some(Dragging::Scrollbar { .. }) => return mouse::Interaction::Idle,
|
||||
_ => {}
|
||||
if let Some(Dragging::Scrollbar { .. }) = &state.dragging {
|
||||
return mouse::Interaction::Idle;
|
||||
}
|
||||
|
||||
if let Some(p) = cursor_position.position_in(layout.bounds()) {
|
||||
|
|
@ -235,8 +246,7 @@ where
|
|||
let cosmic_theme = theme.cosmic();
|
||||
let scrollbar_w = cosmic_theme.spacing.space_xxs as f32;
|
||||
|
||||
let view_position =
|
||||
layout.position() + [self.padding.left as f32, self.padding.top as f32].into();
|
||||
let view_position = layout.position() + [self.padding.left, self.padding.top].into();
|
||||
let view_w = cmp::min(viewport.width as i32, layout.bounds().width as i32)
|
||||
- self.padding.horizontal() as i32
|
||||
- scrollbar_w as i32;
|
||||
|
|
@ -259,12 +269,6 @@ where
|
|||
terminal.needs_update = false;
|
||||
}
|
||||
|
||||
// Ensure terminal is shaped
|
||||
terminal.with_buffer_mut(|buffer| {
|
||||
let mut font_system = font_system().write().unwrap();
|
||||
buffer.shape_until_scroll(font_system.raw(), true);
|
||||
});
|
||||
|
||||
// Render default background
|
||||
{
|
||||
let meta = &terminal.metadata_set[terminal.default_attrs().metadata];
|
||||
|
|
@ -272,19 +276,18 @@ where
|
|||
|
||||
renderer.fill_quad(
|
||||
Quad {
|
||||
bounds: Rectangle::new(
|
||||
view_position,
|
||||
Size::new(view_w as f32 + scrollbar_w, view_h as f32),
|
||||
),
|
||||
border_radius: 0.0.into(),
|
||||
border_width: 0.0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
bounds: layout.bounds(),
|
||||
border: self.border,
|
||||
..Default::default()
|
||||
},
|
||||
Color::new(
|
||||
background_color.r() as f32 / 255.0,
|
||||
background_color.g() as f32 / 255.0,
|
||||
background_color.b() as f32 / 255.0,
|
||||
background_color.a() as f32 / 255.0,
|
||||
match self.opacity {
|
||||
Some(opacity) => opacity,
|
||||
None => background_color.a() as f32 / 255.0,
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
@ -327,10 +330,6 @@ where
|
|||
renderer: &mut Renderer,
|
||||
is_focused: bool,
|
||||
) {
|
||||
if self.metadata == self.default_metadata {
|
||||
return;
|
||||
}
|
||||
|
||||
let cosmic_text_to_iced_color = |color: cosmic_text::Color| {
|
||||
Color::new(
|
||||
color.r() as f32 / 255.0,
|
||||
|
|
@ -356,9 +355,7 @@ where
|
|||
self.view_position + $pos_offset,
|
||||
Size::new($width, $style_line_height),
|
||||
),
|
||||
border_radius: 0.0.into(),
|
||||
border_width: 0.0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
..Default::default()
|
||||
}
|
||||
};
|
||||
($pos_offset:expr, $style_line_height:expr) => {
|
||||
|
|
@ -367,11 +364,13 @@ where
|
|||
}
|
||||
|
||||
let metadata = &self.metadata_set[self.metadata];
|
||||
let color = shade(metadata.bg, is_focused);
|
||||
renderer.fill_quad(
|
||||
mk_quad!(mk_pos_offset!(0.0, self.line_height), self.line_height),
|
||||
cosmic_text_to_iced_color(color),
|
||||
);
|
||||
if metadata.bg != self.metadata_set[self.default_metadata].bg {
|
||||
let color = shade(metadata.bg, is_focused);
|
||||
renderer.fill_quad(
|
||||
mk_quad!(mk_pos_offset!(0.0, self.line_height), self.line_height),
|
||||
cosmic_text_to_iced_color(color),
|
||||
);
|
||||
}
|
||||
|
||||
if !metadata.flags.is_empty() {
|
||||
let style_line_height =
|
||||
|
|
@ -462,7 +461,7 @@ where
|
|||
dot_width = dot_width.min(full_width - accu_width);
|
||||
|
||||
let dot_bottom_offset = match accu_width as u32 % 8 {
|
||||
3 | 4 | 5 => bottom_offset + style_line_height,
|
||||
3..=5 => bottom_offset + style_line_height,
|
||||
2 | 6 => bottom_offset + 2.0 * style_line_height / 3.0,
|
||||
1 | 7 => bottom_offset + 1.0 * style_line_height / 3.0,
|
||||
_ => bottom_offset,
|
||||
|
|
@ -515,10 +514,7 @@ where
|
|||
Size::new(scrollbar_w, scrollbar_h),
|
||||
);
|
||||
|
||||
let pressed = match &state.dragging {
|
||||
Some(Dragging::Scrollbar { .. }) => true,
|
||||
_ => false,
|
||||
};
|
||||
let pressed = matches!(&state.dragging, Some(Dragging::Scrollbar { .. }));
|
||||
|
||||
let mut hover = false;
|
||||
if let Some(p) = cursor_position.position_in(layout.bounds()) {
|
||||
|
|
@ -568,9 +564,12 @@ where
|
|||
renderer.fill_quad(
|
||||
Quad {
|
||||
bounds: scrollbar_draw,
|
||||
border_radius: (scrollbar_draw.width / 2.0).into(),
|
||||
border_width: 0.0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
border: Border {
|
||||
radius: (scrollbar_draw.width / 2.0).into(),
|
||||
width: 0.0,
|
||||
color: Color::TRANSPARENT,
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
scrollbar_color,
|
||||
);
|
||||
|
|
@ -606,238 +605,100 @@ where
|
|||
let mut status = Status::Ignored;
|
||||
match event {
|
||||
Event::Keyboard(KeyEvent::KeyPressed {
|
||||
key_code,
|
||||
key: Key::Named(named),
|
||||
modifiers,
|
||||
}) if state.is_focused => match (
|
||||
modifiers.logo(),
|
||||
modifiers.control(),
|
||||
modifiers.alt(),
|
||||
modifiers.shift(),
|
||||
) {
|
||||
(true, _, _, _) => {
|
||||
// Ignore super keys
|
||||
..
|
||||
}) if state.is_focused => {
|
||||
for (key_bind, _) in self.key_binds.iter() {
|
||||
if key_bind.matches(modifiers, &Key::Named(named)) {
|
||||
return Status::Captured;
|
||||
}
|
||||
}
|
||||
(_, true, _, _) => match key_code {
|
||||
KeyCode::Up => {
|
||||
terminal.input_scroll(b"\x1B[1;5A".as_slice());
|
||||
let mod_no = calculate_modifier_number(state);
|
||||
let escape_code = match named {
|
||||
Named::Insert => csi("2", "~", mod_no),
|
||||
Named::Delete => csi("3", "~", mod_no),
|
||||
Named::PageUp => csi("5", "~", mod_no),
|
||||
Named::PageDown => csi("6", "~", mod_no),
|
||||
Named::ArrowUp => {
|
||||
if is_app_cursor {
|
||||
ss3("A", mod_no)
|
||||
} else {
|
||||
csi("A", "", mod_no)
|
||||
}
|
||||
}
|
||||
Named::ArrowDown => {
|
||||
if is_app_cursor {
|
||||
ss3("B", mod_no)
|
||||
} else {
|
||||
csi("B", "", mod_no)
|
||||
}
|
||||
}
|
||||
Named::ArrowRight => {
|
||||
if is_app_cursor {
|
||||
ss3("C", mod_no)
|
||||
} else {
|
||||
csi("C", "", mod_no)
|
||||
}
|
||||
}
|
||||
Named::ArrowLeft => {
|
||||
if is_app_cursor {
|
||||
ss3("D", mod_no)
|
||||
} else {
|
||||
csi("D", "", mod_no)
|
||||
}
|
||||
}
|
||||
Named::End => {
|
||||
if is_app_cursor {
|
||||
ss3("F", mod_no)
|
||||
} else {
|
||||
csi("F", "", mod_no)
|
||||
}
|
||||
}
|
||||
Named::Home => {
|
||||
if is_app_cursor {
|
||||
ss3("H", mod_no)
|
||||
} else {
|
||||
csi("H", "", mod_no)
|
||||
}
|
||||
}
|
||||
Named::F1 => ss3("P", mod_no),
|
||||
Named::F2 => ss3("Q", mod_no),
|
||||
Named::F3 => ss3("R", mod_no),
|
||||
Named::F4 => ss3("S", mod_no),
|
||||
Named::F5 => csi("15", "~", mod_no),
|
||||
Named::F6 => csi("17", "~", mod_no),
|
||||
Named::F7 => csi("18", "~", mod_no),
|
||||
Named::F8 => csi("19", "~", mod_no),
|
||||
Named::F9 => csi("20", "~", mod_no),
|
||||
Named::F10 => csi("21", "~", mod_no),
|
||||
Named::F11 => csi("23", "~", mod_no),
|
||||
Named::F12 => csi("24", "~", mod_no),
|
||||
_ => None,
|
||||
};
|
||||
if let Some(escape_code) = escape_code {
|
||||
terminal.input_scroll(escape_code);
|
||||
return Status::Captured;
|
||||
}
|
||||
|
||||
//Special handle Enter, Escape, Backspace and Tab as described in
|
||||
//https://sw.kovidgoyal.net/kitty/keyboard-protocol/#legacy-key-event-encoding
|
||||
//Also special handle Ctrl-_ to behave like xterm
|
||||
let alt_prefix = if modifiers.alt() { "\x1B" } else { "" };
|
||||
match named {
|
||||
Named::Backspace => {
|
||||
let code = if modifiers.control() { "\x08" } else { "\x7f" };
|
||||
terminal
|
||||
.input_scroll(format!("{}{}", alt_prefix, code).as_bytes().to_vec());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Down => {
|
||||
terminal.input_scroll(b"\x1B[1;5B".as_slice());
|
||||
Named::Enter => {
|
||||
terminal
|
||||
.input_scroll(format!("{}{}", alt_prefix, "\x0D").as_bytes().to_vec());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Right => {
|
||||
terminal.input_scroll(b"\x1B[1;5C".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Left => {
|
||||
terminal.input_scroll(b"\x1B[1;5D".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::End => {
|
||||
terminal.input_scroll(b"\x1B[1;5F".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Home => {
|
||||
terminal.input_scroll(b"\x1B[1;5H".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Insert => {
|
||||
terminal.input_scroll(b"\x1B[2;5~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Delete => {
|
||||
terminal.input_scroll(b"\x1B[3;5~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::PageUp => {
|
||||
terminal.input_scroll(b"\x1B[5;5~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::PageDown => {
|
||||
terminal.input_scroll(b"\x1B[6;5~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F1 => {
|
||||
terminal.input_scroll(b"\x1BO;5P".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F2 => {
|
||||
terminal.input_scroll(b"\x1BO;5Q".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F3 => {
|
||||
terminal.input_scroll(b"\x1BO;5R".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F4 => {
|
||||
terminal.input_scroll(b"\x1BO;5S".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F5 => {
|
||||
terminal.input_scroll(b"\x1B[15;5~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F6 => {
|
||||
terminal.input_scroll(b"\x1B[17;5~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F7 => {
|
||||
terminal.input_scroll(b"\x1B[18;5~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F8 => {
|
||||
terminal.input_scroll(b"\x1B[19;5~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F9 => {
|
||||
terminal.input_scroll(b"\x1B[20;5~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F10 => {
|
||||
terminal.input_scroll(b"\x1B[21;5~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F11 => {
|
||||
terminal.input_scroll(b"\x1B[23;5~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F12 => {
|
||||
terminal.input_scroll(b"\x1B[24;5~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
_ => (),
|
||||
},
|
||||
// Handle alt keys
|
||||
(_, _, true, _) => match key_code {
|
||||
KeyCode::Up => {
|
||||
terminal.input_scroll(b"\x1B[1;3A".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Down => {
|
||||
terminal.input_scroll(b"\x1B[1;3B".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Right => {
|
||||
terminal.input_scroll(b"\x1B[1;3C".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Left => {
|
||||
terminal.input_scroll(b"\x1B[1;3D".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::End => {
|
||||
terminal.input_scroll(b"\x1B[1;3F".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Home => {
|
||||
terminal.input_scroll(b"\x1B[1;3H".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Insert => {
|
||||
terminal.input_scroll(b"\x1B[2;3~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Delete => {
|
||||
terminal.input_scroll(b"\x1B[3;3~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::PageUp => {
|
||||
terminal.input_scroll(b"\x1B[5;3~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::PageDown => {
|
||||
terminal.input_scroll(b"\x1B[6;3~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F1 => {
|
||||
terminal.input_scroll(b"\x1B[1;3P".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F2 => {
|
||||
terminal.input_scroll(b"\x1B1;3Q".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F3 => {
|
||||
terminal.input_scroll(b"\x1B1;3R".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F4 => {
|
||||
terminal.input_scroll(b"\x1B1;3S".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F5 => {
|
||||
terminal.input_scroll(b"\x1B[15;3~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F6 => {
|
||||
terminal.input_scroll(b"\x1B[17;3~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F7 => {
|
||||
terminal.input_scroll(b"\x1B[18;3~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F8 => {
|
||||
terminal.input_scroll(b"\x1B[19;3~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F9 => {
|
||||
terminal.input_scroll(b"\x1B[20;3~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F10 => {
|
||||
terminal.input_scroll(b"\x1B[21;3~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F11 => {
|
||||
terminal.input_scroll(b"\x1B[23;3~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F12 => {
|
||||
terminal.input_scroll(b"\x1B[24;3~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Backspace => {
|
||||
terminal.input_scroll(b"\x1B\x7F".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
_ => (),
|
||||
},
|
||||
// Handle shift keys
|
||||
(_, _, _, true) => match key_code {
|
||||
KeyCode::End => {
|
||||
terminal.scroll(TerminalScroll::Bottom);
|
||||
}
|
||||
KeyCode::Home => {
|
||||
terminal.scroll(TerminalScroll::Top);
|
||||
}
|
||||
KeyCode::PageDown => {
|
||||
terminal.scroll(TerminalScroll::PageDown);
|
||||
}
|
||||
KeyCode::PageUp => {
|
||||
terminal.scroll(TerminalScroll::PageUp);
|
||||
}
|
||||
KeyCode::Tab => {
|
||||
terminal.input_scroll(b"\x1B[Z".as_slice());
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
// Handle keys with no modifiers
|
||||
(_, _, _, false) => match key_code {
|
||||
KeyCode::Backspace => {
|
||||
terminal.input_scroll(b"\x7F".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Tab => {
|
||||
terminal.input_scroll(b"\t".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Enter => {
|
||||
terminal.input_scroll(b"\r".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Escape => {
|
||||
Named::Escape => {
|
||||
//Escape with any modifier will cancel selection
|
||||
let had_selection = {
|
||||
let mut term = terminal.term.lock();
|
||||
term.selection.take().is_some()
|
||||
|
|
@ -845,138 +706,60 @@ where
|
|||
if had_selection {
|
||||
terminal.update();
|
||||
} else {
|
||||
terminal.input_scroll(b"\x1B".as_slice());
|
||||
terminal.input_scroll(
|
||||
format!("{}{}", alt_prefix, "\x1B").as_bytes().to_vec(),
|
||||
);
|
||||
}
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Up => {
|
||||
let code = if is_app_cursor { b"\x1BOA" } else { b"\x1B[A" };
|
||||
|
||||
terminal.input_scroll(code.as_slice());
|
||||
Named::Space => {
|
||||
terminal.input_scroll(format!("{}{}", alt_prefix, " ").as_bytes().to_vec());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Down => {
|
||||
let code = if is_app_cursor { b"\x1BOB" } else { b"\x1B[B" };
|
||||
|
||||
terminal.input_scroll(code.as_slice());
|
||||
Named::Tab => {
|
||||
let code = if modifiers.shift() { "\x1b[Z" } else { "\x09" };
|
||||
terminal
|
||||
.input_scroll(format!("{}{}", alt_prefix, code).as_bytes().to_vec());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Right => {
|
||||
let code = if is_app_cursor { b"\x1BOC" } else { b"\x1B[C" };
|
||||
|
||||
terminal.input_scroll(code.as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Left => {
|
||||
let code = if is_app_cursor { b"\x1BOD" } else { b"\x1B[D" };
|
||||
|
||||
terminal.input_scroll(code.as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::End => {
|
||||
let code = if is_app_cursor { b"\x1BOF" } else { b"\x1B[F" };
|
||||
|
||||
terminal.input_scroll(code.as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Home => {
|
||||
let code = if is_app_cursor { b"\x1BOH" } else { b"\x1B[H" };
|
||||
|
||||
terminal.input_scroll(code.as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Insert => {
|
||||
terminal.input_scroll(b"\x1B[2~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::Delete => {
|
||||
terminal.input_scroll(b"\x1B[3~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::PageUp => {
|
||||
terminal.input_scroll(b"\x1B[5~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::PageDown => {
|
||||
terminal.input_scroll(b"\x1B[6~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F1 => {
|
||||
terminal.input_scroll(b"\x1BOP".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F2 => {
|
||||
terminal.input_scroll(b"\x1BOQ".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F3 => {
|
||||
terminal.input_scroll(b"\x1BOR".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F4 => {
|
||||
terminal.input_scroll(b"\x1BOS".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F5 => {
|
||||
terminal.input_scroll(b"\x1B[15~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F6 => {
|
||||
terminal.input_scroll(b"\x1B[17~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F7 => {
|
||||
terminal.input_scroll(b"\x1B[18~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F8 => {
|
||||
terminal.input_scroll(b"\x1B[19~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F9 => {
|
||||
terminal.input_scroll(b"\x1B[20~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F10 => {
|
||||
terminal.input_scroll(b"\x1B[21~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F11 => {
|
||||
terminal.input_scroll(b"\x1B[23~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
KeyCode::F12 => {
|
||||
terminal.input_scroll(b"\x1B[24~".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
_ => (),
|
||||
},
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Event::Keyboard(KeyEvent::ModifiersChanged(modifiers)) => {
|
||||
state.modifiers = modifiers;
|
||||
}
|
||||
Event::Keyboard(KeyEvent::CharacterReceived(character)) if state.is_focused => {
|
||||
Event::Keyboard(KeyEvent::KeyPressed {
|
||||
text,
|
||||
modifiers,
|
||||
key,
|
||||
..
|
||||
}) if state.is_focused => {
|
||||
for (key_bind, _) in self.key_binds.iter() {
|
||||
if key_bind.matches(modifiers, &key) {
|
||||
return Status::Captured;
|
||||
}
|
||||
}
|
||||
let character = text.and_then(|c| c.chars().next()).unwrap_or_default();
|
||||
match (
|
||||
state.modifiers.logo(),
|
||||
state.modifiers.control(),
|
||||
state.modifiers.alt(),
|
||||
state.modifiers.shift(),
|
||||
modifiers.logo(),
|
||||
modifiers.control(),
|
||||
modifiers.alt(),
|
||||
modifiers.shift(),
|
||||
) {
|
||||
(true, _, _, _) => {
|
||||
// Ignore super
|
||||
}
|
||||
(false, true, true, false) => {
|
||||
(false, true, true, _) => {
|
||||
// Handle ctrl-alt for non-control characters
|
||||
// Or should I try to minimize this to only
|
||||
// catch control sequences that conflicts with
|
||||
// keykodes for Split
|
||||
// if character != '\u{4}' && character != '\u{12}' {
|
||||
// is there any valid case for control characters with modifers
|
||||
// ctrl-alt?
|
||||
if !character.is_control() {
|
||||
let mut buf = [0, 0, 0, 0];
|
||||
let str = character.encode_utf8(&mut buf);
|
||||
terminal.input_scroll(str.as_bytes().to_vec());
|
||||
// and control characters 0-32
|
||||
if !character.is_control() || (character as u32) < 32 {
|
||||
// Handle alt for non-control characters
|
||||
let mut buf = [0x1B, 0, 0, 0, 0];
|
||||
let len = {
|
||||
let str = character.encode_utf8(&mut buf[1..]);
|
||||
str.len() + 1
|
||||
};
|
||||
terminal.input_scroll(buf[..len].to_vec());
|
||||
status = Status::Captured;
|
||||
}
|
||||
}
|
||||
|
|
@ -990,7 +773,14 @@ where
|
|||
}
|
||||
}
|
||||
(false, true, _, true) => {
|
||||
// Ignore ctrl+shift
|
||||
//This is normally Ctrl+Minus, but since that
|
||||
//is taken by zoom, we send that code for
|
||||
//Ctrl+Underline instead, like xterm and
|
||||
//gnome-terminal
|
||||
if key == Key::Character("_".into()) {
|
||||
terminal.input_scroll(b"\x1F".as_slice());
|
||||
status = Status::Captured;
|
||||
}
|
||||
}
|
||||
(false, false, true, _) => {
|
||||
if !character.is_control() {
|
||||
|
|
@ -1029,6 +819,7 @@ where
|
|||
state.is_focused = true;
|
||||
|
||||
// Handle left click drag
|
||||
#[allow(clippy::collapsible_if)]
|
||||
if let Button::Left = button {
|
||||
let x = p.x - self.padding.left;
|
||||
let y = p.y - self.padding.top;
|
||||
|
|
@ -1264,7 +1055,7 @@ fn shade(color: cosmic_text::Color, is_focused: bool) -> cosmic_text::Color {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, Message> From<TerminalBox<'a, Message>> for Element<'a, Message, Renderer>
|
||||
impl<'a, Message> From<TerminalBox<'a, Message>> for Element<'a, Message, cosmic::Theme, Renderer>
|
||||
where
|
||||
Message: Clone + 'a,
|
||||
{
|
||||
|
|
@ -1323,3 +1114,52 @@ impl operation::Focusable for State {
|
|||
self.is_focused = false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
shift 0b1 (1)
|
||||
alt 0b10 (2)
|
||||
ctrl 0b100 (4)
|
||||
super 0b1000 (8)
|
||||
hyper 0b10000 (16)
|
||||
meta 0b100000 (32)
|
||||
caps_lock 0b1000000 (64)
|
||||
num_lock 0b10000000 (128)
|
||||
*/
|
||||
fn calculate_modifier_number(state: &mut State) -> u8 {
|
||||
let mut mod_no = 0;
|
||||
if state.modifiers.shift() {
|
||||
mod_no |= 1;
|
||||
}
|
||||
if state.modifiers.alt() {
|
||||
mod_no |= 2;
|
||||
}
|
||||
if state.modifiers.control() {
|
||||
mod_no |= 4;
|
||||
}
|
||||
if state.modifiers.logo() {
|
||||
mod_no |= 8;
|
||||
}
|
||||
mod_no + 1
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn csi(code: &str, suffix: &str, modifiers: u8) -> Option<Vec<u8>> {
|
||||
if modifiers == 1 {
|
||||
Some(format!("\x1B[{}{}", code, suffix).as_bytes().to_vec())
|
||||
} else {
|
||||
Some(
|
||||
format!("\x1B[{};{}{}", code, modifiers, suffix)
|
||||
.as_bytes()
|
||||
.to_vec(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn ss3(code: &str, modifiers: u8) -> Option<Vec<u8>> {
|
||||
if modifiers == 1 {
|
||||
Some(format!("\x1B\x4F{}", code).as_bytes().to_vec())
|
||||
} else {
|
||||
Some(format!("\x1B[1;{}{}", modifiers, code).as_bytes().to_vec())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -656,6 +656,166 @@ fn pop_dark() -> Colors {
|
|||
colors
|
||||
}
|
||||
|
||||
fn selenized_white() -> Colors {
|
||||
let mut colors = auto_colors();
|
||||
|
||||
let encode_rgb = |data: u32| -> Rgb {
|
||||
Rgb {
|
||||
r: (data >> 16) as u8,
|
||||
g: (data >> 8) as u8,
|
||||
b: data as u8,
|
||||
}
|
||||
};
|
||||
|
||||
colors[NamedColor::Black] = Some(encode_rgb(0xEBEBEB));
|
||||
colors[NamedColor::Red] = Some(encode_rgb(0xD6000C));
|
||||
colors[NamedColor::Green] = Some(encode_rgb(0x1D9700));
|
||||
colors[NamedColor::Yellow] = Some(encode_rgb(0xC49700));
|
||||
colors[NamedColor::Blue] = Some(encode_rgb(0x0064E4));
|
||||
colors[NamedColor::Magenta] = Some(encode_rgb(0xDD0F9D));
|
||||
colors[NamedColor::Cyan] = Some(encode_rgb(0x00AD9C));
|
||||
colors[NamedColor::White] = Some(encode_rgb(0x878787));
|
||||
|
||||
colors[NamedColor::BrightBlack] = Some(encode_rgb(0xCDCDCD));
|
||||
colors[NamedColor::BrightRed] = Some(encode_rgb(0xBF0000));
|
||||
colors[NamedColor::BrightGreen] = Some(encode_rgb(0x008400));
|
||||
colors[NamedColor::BrightYellow] = Some(encode_rgb(0xAF8500));
|
||||
colors[NamedColor::BrightBlue] = Some(encode_rgb(0x0054CF));
|
||||
colors[NamedColor::BrightMagenta] = Some(encode_rgb(0xC7008B));
|
||||
colors[NamedColor::BrightCyan] = Some(encode_rgb(0x009A8A));
|
||||
colors[NamedColor::BrightWhite] = Some(encode_rgb(0x282828));
|
||||
|
||||
// Set special colors
|
||||
colors[NamedColor::Background] = Some(encode_rgb(0xFFFFFF));
|
||||
colors[NamedColor::Foreground] = Some(encode_rgb(0x474747));
|
||||
colors[NamedColor::Cursor] = colors[NamedColor::Black];
|
||||
|
||||
// Fill missing dim colors
|
||||
ColorDerive::new().fill_missing_dims(&mut colors);
|
||||
|
||||
colors
|
||||
}
|
||||
|
||||
fn selenized_light() -> Colors {
|
||||
let mut colors = auto_colors();
|
||||
|
||||
let encode_rgb = |data: u32| -> Rgb {
|
||||
Rgb {
|
||||
r: (data >> 16) as u8,
|
||||
g: (data >> 8) as u8,
|
||||
b: data as u8,
|
||||
}
|
||||
};
|
||||
|
||||
colors[NamedColor::Black] = Some(encode_rgb(0xECE3CC));
|
||||
colors[NamedColor::Red] = Some(encode_rgb(0xD2212D));
|
||||
colors[NamedColor::Green] = Some(encode_rgb(0x489100));
|
||||
colors[NamedColor::Yellow] = Some(encode_rgb(0xAD8900));
|
||||
colors[NamedColor::Blue] = Some(encode_rgb(0x0072D4));
|
||||
colors[NamedColor::Magenta] = Some(encode_rgb(0xCA4898));
|
||||
colors[NamedColor::Cyan] = Some(encode_rgb(0x009C8F));
|
||||
colors[NamedColor::White] = Some(encode_rgb(0x909995));
|
||||
|
||||
colors[NamedColor::BrightBlack] = Some(encode_rgb(0xD5CDB6));
|
||||
colors[NamedColor::BrightRed] = Some(encode_rgb(0xCC1729));
|
||||
colors[NamedColor::BrightGreen] = Some(encode_rgb(0x428B00));
|
||||
colors[NamedColor::BrightYellow] = Some(encode_rgb(0xA78300));
|
||||
colors[NamedColor::BrightBlue] = Some(encode_rgb(0x006DCE));
|
||||
colors[NamedColor::BrightMagenta] = Some(encode_rgb(0xC44392));
|
||||
colors[NamedColor::BrightCyan] = Some(encode_rgb(0x00978A));
|
||||
colors[NamedColor::BrightWhite] = Some(encode_rgb(0x3A4D53));
|
||||
|
||||
// Set special colors
|
||||
colors[NamedColor::Background] = Some(encode_rgb(0xFBF3DB));
|
||||
colors[NamedColor::Foreground] = Some(encode_rgb(0x53676D));
|
||||
colors[NamedColor::Cursor] = colors[NamedColor::Black];
|
||||
|
||||
// Fill missing dim colors
|
||||
ColorDerive::new().fill_missing_dims(&mut colors);
|
||||
|
||||
colors
|
||||
}
|
||||
|
||||
fn selenized_dark() -> Colors {
|
||||
let mut colors = auto_colors();
|
||||
|
||||
let encode_rgb = |data: u32| -> Rgb {
|
||||
Rgb {
|
||||
r: (data >> 16) as u8,
|
||||
g: (data >> 8) as u8,
|
||||
b: data as u8,
|
||||
}
|
||||
};
|
||||
|
||||
colors[NamedColor::Black] = Some(encode_rgb(0x184956));
|
||||
colors[NamedColor::Red] = Some(encode_rgb(0xFA5750));
|
||||
colors[NamedColor::Green] = Some(encode_rgb(0x75B938));
|
||||
colors[NamedColor::Yellow] = Some(encode_rgb(0xDBB32D));
|
||||
colors[NamedColor::Blue] = Some(encode_rgb(0x4695F7));
|
||||
colors[NamedColor::Magenta] = Some(encode_rgb(0xF275BE));
|
||||
colors[NamedColor::Cyan] = Some(encode_rgb(0x41C7B9));
|
||||
colors[NamedColor::White] = Some(encode_rgb(0x72898F));
|
||||
|
||||
colors[NamedColor::BrightBlack] = Some(encode_rgb(0x2D5B69));
|
||||
colors[NamedColor::BrightRed] = Some(encode_rgb(0xFF665C));
|
||||
colors[NamedColor::BrightGreen] = Some(encode_rgb(0x84C747));
|
||||
colors[NamedColor::BrightYellow] = Some(encode_rgb(0xEBC13D));
|
||||
colors[NamedColor::BrightBlue] = Some(encode_rgb(0x58A3FF));
|
||||
colors[NamedColor::BrightMagenta] = Some(encode_rgb(0xFF84CD));
|
||||
colors[NamedColor::BrightCyan] = Some(encode_rgb(0x53D6C7));
|
||||
colors[NamedColor::BrightWhite] = Some(encode_rgb(0xCAD8D9));
|
||||
|
||||
// Set special colors
|
||||
colors[NamedColor::Background] = Some(encode_rgb(0x103C48));
|
||||
colors[NamedColor::Foreground] = Some(encode_rgb(0xADBCBC));
|
||||
colors[NamedColor::Cursor] = colors[NamedColor::White];
|
||||
|
||||
// Fill missing dim colors
|
||||
ColorDerive::new().fill_missing_dims(&mut colors);
|
||||
|
||||
colors
|
||||
}
|
||||
|
||||
fn selenized_black() -> Colors {
|
||||
let mut colors = auto_colors();
|
||||
|
||||
let encode_rgb = |data: u32| -> Rgb {
|
||||
Rgb {
|
||||
r: (data >> 16) as u8,
|
||||
g: (data >> 8) as u8,
|
||||
b: data as u8,
|
||||
}
|
||||
};
|
||||
|
||||
colors[NamedColor::Black] = Some(encode_rgb(0x252525));
|
||||
colors[NamedColor::Red] = Some(encode_rgb(0xED4A46));
|
||||
colors[NamedColor::Green] = Some(encode_rgb(0x70B433));
|
||||
colors[NamedColor::Yellow] = Some(encode_rgb(0xDBB32D));
|
||||
colors[NamedColor::Blue] = Some(encode_rgb(0x368AEB));
|
||||
colors[NamedColor::Magenta] = Some(encode_rgb(0xEB6EB7));
|
||||
colors[NamedColor::Cyan] = Some(encode_rgb(0x3FC5B7));
|
||||
colors[NamedColor::White] = Some(encode_rgb(0x777777));
|
||||
|
||||
colors[NamedColor::BrightBlack] = Some(encode_rgb(0x3B3B3B));
|
||||
colors[NamedColor::BrightRed] = Some(encode_rgb(0xFF5E56));
|
||||
colors[NamedColor::BrightGreen] = Some(encode_rgb(0x83C746));
|
||||
colors[NamedColor::BrightYellow] = Some(encode_rgb(0xEFC541));
|
||||
colors[NamedColor::BrightBlue] = Some(encode_rgb(0x4F9CFE));
|
||||
colors[NamedColor::BrightMagenta] = Some(encode_rgb(0xFF81CA));
|
||||
colors[NamedColor::BrightCyan] = Some(encode_rgb(0x56D8C9));
|
||||
colors[NamedColor::BrightWhite] = Some(encode_rgb(0xDEDEDE));
|
||||
|
||||
// Set special colors
|
||||
colors[NamedColor::Background] = Some(encode_rgb(0x181818));
|
||||
colors[NamedColor::Foreground] = Some(encode_rgb(0xB9B9B9));
|
||||
colors[NamedColor::Cursor] = colors[NamedColor::White];
|
||||
|
||||
// Fill missing dim colors
|
||||
ColorDerive::new().fill_missing_dims(&mut colors);
|
||||
|
||||
colors
|
||||
}
|
||||
|
||||
pub fn terminal_themes() -> HashMap<String, Colors> {
|
||||
let mut themes = HashMap::new();
|
||||
themes.insert("Tango Dark".to_string(), tango_dark());
|
||||
|
|
@ -672,5 +832,9 @@ pub fn terminal_themes() -> HashMap<String, Colors> {
|
|||
themes.insert("gruvbox-dark".to_string(), gruvbox_dark());
|
||||
themes.insert("OneHalfDark".to_string(), one_half_dark());
|
||||
themes.insert("Pop Dark".to_string(), pop_dark());
|
||||
themes.insert("Selenized Black".to_string(), selenized_black());
|
||||
themes.insert("Selenized Dark".to_string(), selenized_dark());
|
||||
themes.insert("Selenized Light".to_string(), selenized_light());
|
||||
themes.insert("Selenized White".to_string(), selenized_white());
|
||||
themes
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue