Merge branch 'master' into master
This commit is contained in:
commit
3ce7bd56ca
24 changed files with 1446 additions and 791 deletions
19
.github/workflows/flakehub-publish-rolling.yml
vendored
Normal file
19
.github/workflows/flakehub-publish-rolling.yml
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
name: "Publish every Git push to master to FlakeHub"
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- "master"
|
||||||
|
jobs:
|
||||||
|
flakehub-publish:
|
||||||
|
runs-on: "ubuntu-latest"
|
||||||
|
permissions:
|
||||||
|
id-token: "write"
|
||||||
|
contents: "read"
|
||||||
|
steps:
|
||||||
|
- uses: "actions/checkout@v3"
|
||||||
|
- uses: "DeterminateSystems/nix-installer-action@main"
|
||||||
|
- uses: "DeterminateSystems/flakehub-push@main"
|
||||||
|
with:
|
||||||
|
name: "pop-os/cosmic-term"
|
||||||
|
rolling: true
|
||||||
|
visibility: "public"
|
||||||
976
Cargo.lock
generated
976
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -10,7 +10,7 @@ rust-version = "1.71"
|
||||||
vergen = { version = "8", features = ["git", "gitcl"] }
|
vergen = { version = "8", features = ["git", "gitcl"] }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
alacritty_terminal = "0.20"
|
alacritty_terminal = "0.23"
|
||||||
env_logger = "0.10"
|
env_logger = "0.10"
|
||||||
hex_color = { version = "3", features = ["serde"] }
|
hex_color = { version = "3", features = ["serde"] }
|
||||||
indexmap = "2"
|
indexmap = "2"
|
||||||
|
|
@ -21,7 +21,8 @@ open = "5.0.2"
|
||||||
palette = { version = "0.7", features = ["serde"] }
|
palette = { version = "0.7", features = ["serde"] }
|
||||||
paste = "1.0"
|
paste = "1.0"
|
||||||
ron = "0.8"
|
ron = "0.8"
|
||||||
serde = { version = "1", features = ["serde_derive"] }
|
#TODO: downgrading serde for better compatibility with older rust
|
||||||
|
serde = { version = "=1.0.197", features = ["serde_derive"] }
|
||||||
shlex = "1"
|
shlex = "1"
|
||||||
tokio = { version = "1", features = ["sync"] }
|
tokio = { version = "1", features = ["sync"] }
|
||||||
# Internationalization
|
# Internationalization
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
(
|
(
|
||||||
name: "gruvbox-dark",
|
name: "Gruvbox Dark",
|
||||||
foreground: "#EBDBB2",
|
foreground: "#EBDBB2",
|
||||||
background: "#282828",
|
background: "#282828",
|
||||||
cursor: "#EBDBB2",
|
cursor: "#EBDBB2",
|
||||||
|
|
@ -35,4 +35,4 @@
|
||||||
cyan: "#547055",
|
cyan: "#547055",
|
||||||
white: "#747474",
|
white: "#747474",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
1
debian/control
vendored
1
debian/control
vendored
|
|
@ -4,6 +4,7 @@ Priority: optional
|
||||||
Maintainer: Jeremy Soller <jeremy@system76.com>
|
Maintainer: Jeremy Soller <jeremy@system76.com>
|
||||||
Build-Depends:
|
Build-Depends:
|
||||||
debhelper-compat (=13),
|
debhelper-compat (=13),
|
||||||
|
git,
|
||||||
just (>= 1.13.0),
|
just (>= 1.13.0),
|
||||||
pkg-config,
|
pkg-config,
|
||||||
rust-all,
|
rust-all,
|
||||||
|
|
|
||||||
96
i18n/de/cosmic_term.ftl
Normal file
96
i18n/de/cosmic_term.ftl
Normal file
|
|
@ -0,0 +1,96 @@
|
||||||
|
cosmic-terminal = COSMIC Terminal
|
||||||
|
new-terminal = Neues Terminal
|
||||||
|
|
||||||
|
# Context Pages
|
||||||
|
|
||||||
|
## About
|
||||||
|
git-description = Git commit {$hash} vom {$date}
|
||||||
|
|
||||||
|
## Color schemes
|
||||||
|
color-schemes = Farbschemen
|
||||||
|
rename = Umbenennen
|
||||||
|
export = Exportieren
|
||||||
|
delete = Löschen
|
||||||
|
import = Importieren
|
||||||
|
import-errors = Importfehler
|
||||||
|
|
||||||
|
## Profiles
|
||||||
|
profiles = Profile
|
||||||
|
name = Name
|
||||||
|
command-line = Startbefehl
|
||||||
|
tab-title = Überschrift
|
||||||
|
tab-title-description = Standardtitel des Tabs überschreiben
|
||||||
|
add-profile = Profil hinzufügen
|
||||||
|
new-profile = Neues Profil
|
||||||
|
make-default = Als Standard setzen
|
||||||
|
|
||||||
|
## Settings
|
||||||
|
settings = Einstellungen
|
||||||
|
|
||||||
|
### Appearance
|
||||||
|
appearance = Aussehen
|
||||||
|
theme = Thema
|
||||||
|
match-desktop = An System anpassen
|
||||||
|
dark = Dunkel
|
||||||
|
light = Hell
|
||||||
|
syntax-dark = Dunkles Farbschema
|
||||||
|
syntax-light = Helles Farbschema
|
||||||
|
default-zoom-step = Zoomstufen
|
||||||
|
opacity = Deckkraft des Hintergrundes
|
||||||
|
|
||||||
|
### Font
|
||||||
|
font = Schrift
|
||||||
|
advanced-font-settings = Fortgeschrittene Schrifteinstellungen
|
||||||
|
default-font = Schriftart
|
||||||
|
default-font-size = Schriftgröße
|
||||||
|
default-font-stretch = Schriftbreite
|
||||||
|
default-font-weight = Normale Schriftstärke
|
||||||
|
default-dim-font-weight = Matte Schriftstärke
|
||||||
|
default-bold-font-weight = Fette Schriftstärke
|
||||||
|
use-bright-bold = Fetten Text heller darstellen
|
||||||
|
|
||||||
|
### Splits
|
||||||
|
splits = Aufteilungen
|
||||||
|
focus-follow-mouse = Tippen folgt Maus
|
||||||
|
|
||||||
|
### Advanced
|
||||||
|
advanced = Fortgeschritten
|
||||||
|
show-headerbar = Kopfzeile anzeigen
|
||||||
|
show-header-description = Kopfzeile kann via Rechtsklickmenü angezeigt werden
|
||||||
|
|
||||||
|
# Find
|
||||||
|
find-placeholder = Suche...
|
||||||
|
find-previous = Vorheriges
|
||||||
|
find-next = Nächstes
|
||||||
|
|
||||||
|
# Menu
|
||||||
|
|
||||||
|
## File
|
||||||
|
file = Datei
|
||||||
|
new-tab = Neuer Tab
|
||||||
|
new-window = Neues Fenster
|
||||||
|
profile = Profil
|
||||||
|
menu-profiles = Profile...
|
||||||
|
close-tab = Tab schließen
|
||||||
|
quit = Beenden
|
||||||
|
|
||||||
|
## Edit
|
||||||
|
edit = Bearbeiten
|
||||||
|
copy = Kopieren
|
||||||
|
paste = Einfügen
|
||||||
|
select-all = Alles auswählen
|
||||||
|
find = Suche
|
||||||
|
|
||||||
|
## View
|
||||||
|
view = Ansicht
|
||||||
|
zoom-in = Schrift vergrößern
|
||||||
|
zoom-reset = Standardschriftgröße
|
||||||
|
zoom-out = Schrift verkleinern
|
||||||
|
next-tab = Nächster Tab
|
||||||
|
previous-tab = Vorheriger Tab
|
||||||
|
split-horizontal = Horizontal aufteilen
|
||||||
|
split-vertical = Vertikal aufteilen
|
||||||
|
pane-toggle-maximize = Vollbild umschalten
|
||||||
|
menu-color-schemes = Farbthemen...
|
||||||
|
menu-settings = Einstellungen...
|
||||||
|
menu-about = Über COSMIC Terminal...
|
||||||
|
|
@ -23,6 +23,9 @@ tab-title-description = Override the default tab title
|
||||||
add-profile = Add profile
|
add-profile = Add profile
|
||||||
new-profile = New profile
|
new-profile = New profile
|
||||||
make-default = Make default
|
make-default = Make default
|
||||||
|
working-directory = Working directory
|
||||||
|
hold = Hold
|
||||||
|
remain-open = Remain open after child process exits.
|
||||||
|
|
||||||
## Settings
|
## Settings
|
||||||
settings = Settings
|
settings = Settings
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ tab-title = Título de pestaña
|
||||||
tab-title-description = Cambiar el título por defecto de la pestaña
|
tab-title-description = Cambiar el título por defecto de la pestaña
|
||||||
add-profile = Añadir perfil
|
add-profile = Añadir perfil
|
||||||
new-profile = Nuevo perfil
|
new-profile = Nuevo perfil
|
||||||
make-default = Impostar como defecto
|
make-default = Establecer como predeterminado
|
||||||
|
|
||||||
## Settings
|
## Settings
|
||||||
settings = Ajustes
|
settings = Ajustes
|
||||||
|
|
@ -31,22 +31,22 @@ settings = Ajustes
|
||||||
appearance = Apariencia
|
appearance = Apariencia
|
||||||
theme = Tema
|
theme = Tema
|
||||||
match-desktop = Automático
|
match-desktop = Automático
|
||||||
dark = Obscuro
|
dark = Oscuro
|
||||||
light = Claro
|
light = Claro
|
||||||
syntax-dark = Esquema de color obscura
|
syntax-dark = Esquema de color oscuro
|
||||||
syntax-light = Esquema de color clara
|
syntax-light = Esquema de color claro
|
||||||
default-zoom-step = Pasos de zoom
|
default-zoom-step = Escalas de zoom
|
||||||
opacity = Opacidad del fondo
|
opacity = Opacidad de fondo
|
||||||
|
|
||||||
### Font
|
### Font
|
||||||
font = Fuente
|
font = Fuente
|
||||||
advanced-font-settings = Ajustes avanzados del fuente
|
advanced-font-settings = Ajustes avanzados de fuente
|
||||||
default-font = Fuente
|
default-font = Fuente
|
||||||
default-font-size = Tamaño del fuente
|
default-font-size = Tamaño de fuente
|
||||||
default-font-stretch = Anchura del fuente
|
default-font-stretch = Anchura de fuente
|
||||||
default-font-weight = Peso del fuente normal
|
default-font-weight = Peso de fuente normal
|
||||||
default-dim-font-weight = Peso del fuente delgado
|
default-dim-font-weight = Peso de fuente delgado
|
||||||
default-bold-font-weight = Peso del fuente en negritas
|
default-bold-font-weight = Peso de fuente en negritas
|
||||||
use-bright-bold = Mostrar negritas en colores claros
|
use-bright-bold = Mostrar negritas en colores claros
|
||||||
|
|
||||||
### Splits
|
### Splits
|
||||||
|
|
@ -54,9 +54,9 @@ splits = Splits
|
||||||
focus-follow-mouse = Enfoque del tecleo sigue el ratón
|
focus-follow-mouse = Enfoque del tecleo sigue el ratón
|
||||||
|
|
||||||
### Advanced
|
### Advanced
|
||||||
advanced = Advanzado
|
advanced = Avanzado
|
||||||
show-headerbar = Mostrar encabezado
|
show-headerbar = Mostrar encabezado
|
||||||
show-header-description = Mostrar el encabezado desde el menú del clic secundario.
|
show-header-description = Mostrar encabezado desde el menú del clic secundario.
|
||||||
|
|
||||||
# Find
|
# Find
|
||||||
find-placeholder = Buscar...
|
find-placeholder = Buscar...
|
||||||
|
|
@ -68,7 +68,7 @@ find-next = Buscar siguiente
|
||||||
## File
|
## File
|
||||||
file = Archivo
|
file = Archivo
|
||||||
new-tab = Nueva pestaña
|
new-tab = Nueva pestaña
|
||||||
new-window = Ventana nueva
|
new-window = Nueva ventana
|
||||||
profile = Perfil
|
profile = Perfil
|
||||||
menu-profiles = Perfiles...
|
menu-profiles = Perfiles...
|
||||||
close-tab = Cerrar pestaña
|
close-tab = Cerrar pestaña
|
||||||
|
|
@ -84,7 +84,7 @@ find = Buscar
|
||||||
## View
|
## View
|
||||||
view = Vista
|
view = Vista
|
||||||
zoom-in = Texto más grande
|
zoom-in = Texto más grande
|
||||||
zoom-reset = Tamaño por defecto del fuente
|
zoom-reset = Tamaño de fuente por defecto
|
||||||
zoom-out = Texto más pequeño
|
zoom-out = Texto más pequeño
|
||||||
next-tab = Pestaña siguiente
|
next-tab = Pestaña siguiente
|
||||||
previous-tab = Pestaña previa
|
previous-tab = Pestaña previa
|
||||||
|
|
|
||||||
96
i18n/fr/cosmic_term.ftl
Normal file
96
i18n/fr/cosmic_term.ftl
Normal file
|
|
@ -0,0 +1,96 @@
|
||||||
|
cosmic-terminal = Terminal COSMIC
|
||||||
|
new-terminal = Nouveau terminal
|
||||||
|
|
||||||
|
# Context Pages
|
||||||
|
|
||||||
|
## About
|
||||||
|
git-description = Git commit {$hash} le {$date}
|
||||||
|
|
||||||
|
## Color schemes
|
||||||
|
color-schemes = Palettes de couleurs
|
||||||
|
rename = Renommer
|
||||||
|
export = Exporter
|
||||||
|
delete = Supprimer
|
||||||
|
import = Importer
|
||||||
|
import-errors = Importer erreurs
|
||||||
|
|
||||||
|
## Profiles
|
||||||
|
profiles = Profils
|
||||||
|
name = Nom
|
||||||
|
command-line = Ligne de commande
|
||||||
|
tab-title = Titre de l'onglet
|
||||||
|
tab-title-description = Remplacer le titre d'onglet par défaut
|
||||||
|
add-profile = Ajouter profil
|
||||||
|
new-profile = Nouveau profil
|
||||||
|
make-default = Rendre par défaut
|
||||||
|
|
||||||
|
## Settings
|
||||||
|
settings = Paramètres
|
||||||
|
|
||||||
|
### Appearance
|
||||||
|
appearance = Apparence
|
||||||
|
theme = Thème
|
||||||
|
match-desktop = Assortir au bureau
|
||||||
|
dark = Sombre
|
||||||
|
light = Clair
|
||||||
|
syntax-dark = Palette de couleur sombre
|
||||||
|
syntax-light = Palette de couleur claire
|
||||||
|
default-zoom-step = Pas du zoom
|
||||||
|
opacity = Opacité de l'arrière-plan
|
||||||
|
|
||||||
|
### Font
|
||||||
|
font = Police
|
||||||
|
advanced-font-settings = Paramètres de police avancés
|
||||||
|
default-font = Police
|
||||||
|
default-font-size = Taille de la police
|
||||||
|
default-font-stretch = Étirement de la police
|
||||||
|
default-font-weight = Graisse de caractère normale
|
||||||
|
default-dim-font-weight = Graisse de caractère légère
|
||||||
|
default-bold-font-weight = Graisse de caractère grasse
|
||||||
|
use-bright-bold = Rendre le texte en gras plus clair
|
||||||
|
|
||||||
|
### Splits
|
||||||
|
splits = Divisions
|
||||||
|
focus-follow-mouse = Le focus de la saisie suit la souris
|
||||||
|
|
||||||
|
### Advanced
|
||||||
|
advanced = Avancé
|
||||||
|
show-headerbar = Afficher l'en-tête
|
||||||
|
show-header-description = Révéler l'en-tête du menu contextuel.
|
||||||
|
|
||||||
|
# Find
|
||||||
|
find-placeholder = Rechercher...
|
||||||
|
find-previous = Chercher précédent
|
||||||
|
find-next = Chercher suivant
|
||||||
|
|
||||||
|
# Menu
|
||||||
|
|
||||||
|
## File
|
||||||
|
file = Fichier
|
||||||
|
new-tab = Nouvel onglet
|
||||||
|
new-window = Nouvelle fenêtre
|
||||||
|
profile = Profil
|
||||||
|
menu-profiles = Profils...
|
||||||
|
close-tab = Fermer l'onglet
|
||||||
|
quit = Quitter
|
||||||
|
|
||||||
|
## Edit
|
||||||
|
edit = Modifier
|
||||||
|
copy = Copier
|
||||||
|
paste = Coller
|
||||||
|
select-all = Sélectionner tout
|
||||||
|
find = Rechercher
|
||||||
|
|
||||||
|
## View
|
||||||
|
view = Affichage
|
||||||
|
zoom-in = Texte plus grand
|
||||||
|
zoom-reset = Taille de texte par défaut
|
||||||
|
zoom-out = Texte plus petit
|
||||||
|
next-tab = Onglet suivant
|
||||||
|
previous-tab = Onglet précédent
|
||||||
|
split-horizontal = Diviser horizontalement
|
||||||
|
split-vertical = Diviser verticalement
|
||||||
|
pane-toggle-maximize = Maximiser l'affichage
|
||||||
|
menu-color-schemes = Palettes de couleurs...
|
||||||
|
menu-settings = Paramètres...
|
||||||
|
menu-about = À propos du terminal COSMIC...
|
||||||
|
|
@ -18,7 +18,7 @@ import-errors = インポートエラー
|
||||||
profiles = プロファイル
|
profiles = プロファイル
|
||||||
name = 名前
|
name = 名前
|
||||||
command-line = コマンドライン
|
command-line = コマンドライン
|
||||||
tab-title = タブのイトル
|
tab-title = タブタイトル
|
||||||
tab-title-description = デフォルトのタブタイトルを無効にします
|
tab-title-description = デフォルトのタブタイトルを無効にします
|
||||||
add-profile = プロファイルを追加
|
add-profile = プロファイルを追加
|
||||||
new-profile = 新しいプロファイル
|
new-profile = 新しいプロファイル
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ new-terminal = Nowy terminal
|
||||||
# Context Pages
|
# Context Pages
|
||||||
|
|
||||||
## About
|
## About
|
||||||
git-description = Git commit {$hash} on {$date}
|
git-description = Git commit {$hash} z {$date}
|
||||||
|
|
||||||
## Color schemes
|
## Color schemes
|
||||||
color-schemes = Schemat kolorów
|
color-schemes = Schemat kolorów
|
||||||
|
|
@ -24,7 +24,6 @@ add-profile = Dodaj profil
|
||||||
new-profile = Nowy profil
|
new-profile = Nowy profil
|
||||||
make-default = Uczyń domyślnym
|
make-default = Uczyń domyślnym
|
||||||
|
|
||||||
|
|
||||||
## Settings
|
## Settings
|
||||||
settings = Ustawienia
|
settings = Ustawienia
|
||||||
|
|
||||||
|
|
@ -70,6 +69,8 @@ find-next = Szukaj następny
|
||||||
file = Plik
|
file = Plik
|
||||||
new-tab = Nowa karta
|
new-tab = Nowa karta
|
||||||
new-window = Nowe okno
|
new-window = Nowe okno
|
||||||
|
profile = Profil
|
||||||
|
menu-profiles = Profile...
|
||||||
close-tab = Zamknij kartę
|
close-tab = Zamknij kartę
|
||||||
quit = Zamknij
|
quit = Zamknij
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,29 @@
|
||||||
|
cosmic-terminal = Терминал COSMIC
|
||||||
|
new-terminal = Новый терминал
|
||||||
|
|
||||||
# Context Pages
|
# Context Pages
|
||||||
|
|
||||||
|
## About
|
||||||
|
git-description = Git-коммит {$hash} от {$date}
|
||||||
|
|
||||||
|
## Color schemes
|
||||||
|
color-schemes = Цветовые схемы
|
||||||
|
rename = Переименовать
|
||||||
|
export = Экспортировать
|
||||||
|
delete = Удалить
|
||||||
|
import = Импортировать
|
||||||
|
import-errors = Ошибки при импорте
|
||||||
|
|
||||||
|
## Profiles
|
||||||
|
profiles = Профили
|
||||||
|
name = Имя
|
||||||
|
command-line = Командная строка
|
||||||
|
tab-title = Заголовок вкладки
|
||||||
|
tab-title-description = Переопределить заголовок вкладки по умолчанию
|
||||||
|
add-profile = Добавить профиль
|
||||||
|
new-profile = Новый профиль
|
||||||
|
make-default = Установить по умолчанию
|
||||||
|
|
||||||
## Settings
|
## Settings
|
||||||
settings = Параметры
|
settings = Параметры
|
||||||
|
|
||||||
|
|
@ -12,6 +36,7 @@ light = Светлая
|
||||||
syntax-dark = Цветовая схема темная
|
syntax-dark = Цветовая схема темная
|
||||||
syntax-light = Цветовая схема светлая
|
syntax-light = Цветовая схема светлая
|
||||||
default-zoom-step = Шаги масштабирования
|
default-zoom-step = Шаги масштабирования
|
||||||
|
opacity = Прозрачность фона
|
||||||
|
|
||||||
### Font
|
### Font
|
||||||
font = Шрифт
|
font = Шрифт
|
||||||
|
|
@ -44,6 +69,8 @@ find-next = Найти далее
|
||||||
file = Файл
|
file = Файл
|
||||||
new-tab = Новая вкладка
|
new-tab = Новая вкладка
|
||||||
new-window = Новое окно
|
new-window = Новое окно
|
||||||
|
profile = Профиль
|
||||||
|
menu-profiles = Профили...
|
||||||
close-tab = Закрыть вкладку
|
close-tab = Закрыть вкладку
|
||||||
quit = Завершить
|
quit = Завершить
|
||||||
|
|
||||||
|
|
@ -64,4 +91,6 @@ previous-tab = Предыдущая вкладка
|
||||||
split-horizontal = Разделение по горизонтали
|
split-horizontal = Разделение по горизонтали
|
||||||
split-vertical = Разделение по вертикали
|
split-vertical = Разделение по вертикали
|
||||||
pane-toggle-maximize = Переключить на весь экран
|
pane-toggle-maximize = Переключить на весь экран
|
||||||
|
menu-color-schemes = Цветовые схемы...
|
||||||
menu-settings = Параметры...
|
menu-settings = Параметры...
|
||||||
|
menu-about = О Терминале COSMIC...
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,33 @@
|
||||||
# Context sidor
|
cosmic-terminal = COSMIC Terminal
|
||||||
|
new-terminal = Ny terminal
|
||||||
|
|
||||||
## Settings
|
# Context Pages
|
||||||
|
|
||||||
|
## Om
|
||||||
|
git-description = Git commit {$hash} på {$date}
|
||||||
|
|
||||||
|
## Färgscheman
|
||||||
|
color-schemes = Färgscheman
|
||||||
|
rename = Byt namn
|
||||||
|
export = Exportera
|
||||||
|
delete = Ta bort
|
||||||
|
import = Importera
|
||||||
|
import-errors = Fel vid import
|
||||||
|
|
||||||
|
## Profiler
|
||||||
|
profiles = Profiler
|
||||||
|
name = Namn
|
||||||
|
command-line = Kommandorad
|
||||||
|
tab-title = Titel på flik
|
||||||
|
tab-title-description = Åsidosätt standardtitel för flik
|
||||||
|
add-profile = Lägg till profil
|
||||||
|
new-profile = Ny profil
|
||||||
|
make-default = Gör till standard
|
||||||
|
|
||||||
|
## Inställningar
|
||||||
settings = Inställningar
|
settings = Inställningar
|
||||||
|
|
||||||
### Appearance
|
### Utseende
|
||||||
appearance = Utseende
|
appearance = Utseende
|
||||||
theme = Tema
|
theme = Tema
|
||||||
match-desktop = Matcha skrivbordet
|
match-desktop = Matcha skrivbordet
|
||||||
|
|
@ -12,6 +36,7 @@ light = Ljust
|
||||||
syntax-dark = Färgschema mörkt
|
syntax-dark = Färgschema mörkt
|
||||||
syntax-light = Färgschema ljust
|
syntax-light = Färgschema ljust
|
||||||
default-zoom-step = Zoom steg
|
default-zoom-step = Zoom steg
|
||||||
|
opacity = Bakgrundens opacitet
|
||||||
|
|
||||||
### Teckensnitt
|
### Teckensnitt
|
||||||
font = Teckensnitt
|
font = Teckensnitt
|
||||||
|
|
@ -44,6 +69,8 @@ find-next = Hitta nästa
|
||||||
file = Fil
|
file = Fil
|
||||||
new-tab = Ny flik
|
new-tab = Ny flik
|
||||||
new-window = Nytt fönster
|
new-window = Nytt fönster
|
||||||
|
profile = Profil
|
||||||
|
menu-profiles = Profiler…
|
||||||
close-tab = Stäng flik
|
close-tab = Stäng flik
|
||||||
quit = Avsluta
|
quit = Avsluta
|
||||||
|
|
||||||
|
|
@ -64,4 +91,6 @@ previous-tab = Föregående flik
|
||||||
split-horizontal = Dela horisontellt
|
split-horizontal = Dela horisontellt
|
||||||
split-vertical = Dela vertikalt
|
split-vertical = Dela vertikalt
|
||||||
pane-toggle-maximize = Växla maximerad
|
pane-toggle-maximize = Växla maximerad
|
||||||
|
menu-color-schemes = Färgscheman…
|
||||||
menu-settings = Inställningar…
|
menu-settings = Inställningar…
|
||||||
|
menu-about = Om COSMIC Terminal…
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,19 @@
|
||||||
|
cosmic-terminal = COSMIC Uçbirim
|
||||||
|
new-terminal = Yeni uçbirim
|
||||||
|
|
||||||
# Context Pages
|
# Context Pages
|
||||||
|
|
||||||
|
## About
|
||||||
|
git-description = Git commit {$hash}, {$date}
|
||||||
|
|
||||||
|
## Color schemes
|
||||||
|
color-schemes = Renk şemaları
|
||||||
|
rename = Yeniden adlandır
|
||||||
|
export = Dışa akar
|
||||||
|
delete = Sil
|
||||||
|
import = İçe aktar
|
||||||
|
import-errors = İçe aktarma hataları
|
||||||
|
|
||||||
## Profiles
|
## Profiles
|
||||||
profiles = Profiller
|
profiles = Profiller
|
||||||
name = İsim
|
name = İsim
|
||||||
|
|
@ -8,6 +22,7 @@ tab-title = Sekme başlığı
|
||||||
tab-title-description = Varsayılan sekme başlığını geçersiz kılar
|
tab-title-description = Varsayılan sekme başlığını geçersiz kılar
|
||||||
add-profile = Profil ekle
|
add-profile = Profil ekle
|
||||||
new-profile = Yeni profil
|
new-profile = Yeni profil
|
||||||
|
make-default = Varsayılan yap
|
||||||
|
|
||||||
## Settings
|
## Settings
|
||||||
settings = Ayarlar
|
settings = Ayarlar
|
||||||
|
|
@ -21,6 +36,7 @@ light = Aydınlık
|
||||||
syntax-dark = Karanlık renk şeması
|
syntax-dark = Karanlık renk şeması
|
||||||
syntax-light = Aydınlık renk şeması
|
syntax-light = Aydınlık renk şeması
|
||||||
default-zoom-step = Yakınlaştırma basamakları
|
default-zoom-step = Yakınlaştırma basamakları
|
||||||
|
opacity = Arkaplan saydamlığı
|
||||||
|
|
||||||
### Font
|
### Font
|
||||||
font = Yazı tipi
|
font = Yazı tipi
|
||||||
|
|
@ -74,5 +90,7 @@ next-tab = Sonraki sekme
|
||||||
previous-tab = Önceki sekme
|
previous-tab = Önceki sekme
|
||||||
split-horizontal = Yatay böl
|
split-horizontal = Yatay böl
|
||||||
split-vertical = Dikey böl
|
split-vertical = Dikey böl
|
||||||
pane-toggle-maximize = En üste geç
|
pane-toggle-maximize = Tam ekrana geç
|
||||||
|
menu-color-schemes = Renk şemaları...
|
||||||
menu-settings = Ayarlar...
|
menu-settings = Ayarlar...
|
||||||
|
menu-about = COSMIC Uçbirim hakkında
|
||||||
|
|
|
||||||
99
i18n/zh-CN/cosmic_term.ftl
Normal file
99
i18n/zh-CN/cosmic_term.ftl
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
cosmic-terminal = COSMIC 终端
|
||||||
|
new-terminal = 新建终端
|
||||||
|
|
||||||
|
# Context Pages
|
||||||
|
|
||||||
|
## About
|
||||||
|
git-description = Git 提交 {$hash} 于 {$date}
|
||||||
|
|
||||||
|
## Color schemes
|
||||||
|
color-schemes = 配色方案
|
||||||
|
rename = 重命名
|
||||||
|
export = 导出
|
||||||
|
delete = 删除
|
||||||
|
import = 导入
|
||||||
|
import-errors = 导入错误
|
||||||
|
|
||||||
|
## Profiles
|
||||||
|
profiles = 配置文件
|
||||||
|
name = 名称
|
||||||
|
command-line = 命令行
|
||||||
|
tab-title = 标签标题
|
||||||
|
tab-title-description = 覆盖默认标签标题
|
||||||
|
add-profile = 添加配置文件
|
||||||
|
new-profile = 新建配置文件
|
||||||
|
make-default = 设为默认配置
|
||||||
|
working-directory = 工作目录
|
||||||
|
hold = 保留
|
||||||
|
remain-open = 子进程结束后保持打开
|
||||||
|
|
||||||
|
## Settings
|
||||||
|
settings = 设置
|
||||||
|
|
||||||
|
### Appearance
|
||||||
|
appearance = 外观
|
||||||
|
theme = 主题
|
||||||
|
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 = 使粗体更亮
|
||||||
|
|
||||||
|
### Splits
|
||||||
|
splits = 终端分割
|
||||||
|
focus-follow-mouse = 聚焦窗口跟随鼠标
|
||||||
|
|
||||||
|
### Advanced
|
||||||
|
advanced = 高级
|
||||||
|
show-headerbar = 显示标题栏
|
||||||
|
show-header-description = 从右键菜单显示标题栏
|
||||||
|
|
||||||
|
# Find
|
||||||
|
find-placeholder = 查找...
|
||||||
|
find-previous = 上一个
|
||||||
|
find-next = 下一个
|
||||||
|
|
||||||
|
# Menu
|
||||||
|
|
||||||
|
## File
|
||||||
|
file = 文件
|
||||||
|
new-tab = 新建标签页
|
||||||
|
new-window = 新建窗口
|
||||||
|
profile = 配置文件
|
||||||
|
menu-profiles = 配置文件...
|
||||||
|
close-tab = 关闭标签页
|
||||||
|
quit = 退出
|
||||||
|
|
||||||
|
## Edit
|
||||||
|
edit = 编辑
|
||||||
|
copy = 复制
|
||||||
|
paste = 粘贴
|
||||||
|
select-all = 全选
|
||||||
|
find = 查找
|
||||||
|
|
||||||
|
## View
|
||||||
|
view = 视图
|
||||||
|
zoom-in = 放大文字
|
||||||
|
zoom-reset = 默认文字大小
|
||||||
|
zoom-out = 缩小文字
|
||||||
|
next-tab = 下一个标签页
|
||||||
|
previous-tab = 上一个标签页
|
||||||
|
split-horizontal = 水平分割
|
||||||
|
split-vertical = 垂直分割
|
||||||
|
pane-toggle-maximize = 切换最大化
|
||||||
|
menu-color-schemes = 配色方案...
|
||||||
|
menu-settings = 设置...
|
||||||
|
menu-about = 关于 COSMIC 终端...
|
||||||
|
|
@ -14,6 +14,8 @@ use std::sync::OnceLock;
|
||||||
use crate::fl;
|
use crate::fl;
|
||||||
|
|
||||||
pub const CONFIG_VERSION: u64 = 1;
|
pub const CONFIG_VERSION: u64 = 1;
|
||||||
|
pub const COSMIC_THEME_DARK: &str = "COSMIC Dark";
|
||||||
|
pub const COSMIC_THEME_LIGHT: &str = "COSMIC Light";
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
||||||
pub enum AppTheme {
|
pub enum AppTheme {
|
||||||
|
|
@ -186,6 +188,10 @@ pub struct Profile {
|
||||||
pub syntax_theme_light: String,
|
pub syntax_theme_light: String,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub tab_title: String,
|
pub tab_title: String,
|
||||||
|
#[serde(default)]
|
||||||
|
pub working_directory: String,
|
||||||
|
#[serde(default)]
|
||||||
|
pub hold: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Profile {
|
impl Default for Profile {
|
||||||
|
|
@ -193,9 +199,11 @@ impl Default for Profile {
|
||||||
Self {
|
Self {
|
||||||
name: fl!("new-profile"),
|
name: fl!("new-profile"),
|
||||||
command: String::new(),
|
command: String::new(),
|
||||||
syntax_theme_dark: "COSMIC Dark".to_string(),
|
syntax_theme_dark: COSMIC_THEME_DARK.to_string(),
|
||||||
syntax_theme_light: "COSMIC Light".to_string(),
|
syntax_theme_light: COSMIC_THEME_LIGHT.to_string(),
|
||||||
tab_title: String::new(),
|
tab_title: String::new(),
|
||||||
|
working_directory: String::new(),
|
||||||
|
hold: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -239,8 +247,8 @@ impl Default for Config {
|
||||||
opacity: 100,
|
opacity: 100,
|
||||||
profiles: BTreeMap::new(),
|
profiles: BTreeMap::new(),
|
||||||
show_headerbar: true,
|
show_headerbar: true,
|
||||||
syntax_theme_dark: "COSMIC Dark".to_string(),
|
syntax_theme_dark: COSMIC_THEME_DARK.to_string(),
|
||||||
syntax_theme_light: "COSMIC Light".to_string(),
|
syntax_theme_light: COSMIC_THEME_LIGHT.to_string(),
|
||||||
use_bright_bold: false,
|
use_bright_bold: false,
|
||||||
default_profile: None,
|
default_profile: None,
|
||||||
}
|
}
|
||||||
|
|
@ -284,11 +292,11 @@ impl Config {
|
||||||
let color_schemes = self.color_schemes(color_scheme_kind);
|
let color_schemes = self.color_schemes(color_scheme_kind);
|
||||||
let mut color_scheme_names =
|
let mut color_scheme_names =
|
||||||
Vec::<(String, ColorSchemeId)>::with_capacity(color_schemes.len());
|
Vec::<(String, ColorSchemeId)>::with_capacity(color_schemes.len());
|
||||||
for (color_scheme_id, color_scheme) in color_schemes.iter() {
|
for (color_scheme_id, color_scheme) in color_schemes {
|
||||||
let mut name = color_scheme.name.clone();
|
let mut name = color_scheme.name.clone();
|
||||||
|
|
||||||
let mut copies = 1;
|
let mut copies = 1;
|
||||||
while color_scheme_names.iter().find(|x| x.0 == name).is_some() {
|
while color_scheme_names.iter().any(|x| x.0 == name) {
|
||||||
copies += 1;
|
copies += 1;
|
||||||
name = format!("{} ({})", color_scheme.name, copies);
|
name = format!("{} ({})", color_scheme.name, copies);
|
||||||
}
|
}
|
||||||
|
|
@ -314,17 +322,17 @@ impl Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn opacity_ratio(&self) -> f32 {
|
pub fn opacity_ratio(&self) -> f32 {
|
||||||
(self.opacity as f32) / 100.0
|
f32::from(self.opacity) / 100.0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a sorted and adjusted for duplicates list of profile names and ids
|
// Get a sorted and adjusted for duplicates list of profile names and ids
|
||||||
pub fn profile_names(&self) -> Vec<(String, ProfileId)> {
|
pub fn profile_names(&self) -> Vec<(String, ProfileId)> {
|
||||||
let mut profile_names = Vec::<(String, ProfileId)>::with_capacity(self.profiles.len());
|
let mut profile_names = Vec::<(String, ProfileId)>::with_capacity(self.profiles.len());
|
||||||
for (profile_id, profile) in self.profiles.iter() {
|
for (profile_id, profile) in &self.profiles {
|
||||||
let mut name = profile.name.clone();
|
let mut name = profile.name.clone();
|
||||||
|
|
||||||
let mut copies = 1;
|
let mut copies = 1;
|
||||||
while profile_names.iter().find(|x| x.0 == name).is_some() {
|
while profile_names.iter().any(|x| x.0 == name) {
|
||||||
copies += 1;
|
copies += 1;
|
||||||
name = format!("{} ({})", profile.name, copies);
|
name = format!("{} ({})", profile.name, copies);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,49 +1,9 @@
|
||||||
use cosmic::{
|
use cosmic::widget::menu::key_bind::{KeyBind, Modifier};
|
||||||
iced::keyboard::{Key, Modifiers},
|
use cosmic::{iced::keyboard::Key, iced_core::keyboard::key::Named};
|
||||||
iced_core::keyboard::key::Named,
|
use std::collections::HashMap;
|
||||||
};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use std::{collections::HashMap, fmt};
|
|
||||||
|
|
||||||
use crate::Action;
|
use crate::Action;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
|
|
||||||
pub enum Modifier {
|
|
||||||
Super,
|
|
||||||
Ctrl,
|
|
||||||
Alt,
|
|
||||||
Shift,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
|
|
||||||
pub struct KeyBind {
|
|
||||||
pub modifiers: Vec<Modifier>,
|
|
||||||
pub key: Key,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl KeyBind {
|
|
||||||
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)
|
|
||||||
&& modifiers.shift() == self.modifiers.contains(&Modifier::Shift)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for KeyBind {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
for modifier in self.modifiers.iter() {
|
|
||||||
write!(f, "{:?} + ", modifier)?;
|
|
||||||
}
|
|
||||||
match &self.key {
|
|
||||||
Key::Character(c) => write!(f, "{}", c.to_uppercase()),
|
|
||||||
Key::Named(named) => write!(f, "{:?}", named),
|
|
||||||
other => write!(f, "{:?}", other),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: load from config
|
//TODO: load from config
|
||||||
pub fn key_binds() -> HashMap<KeyBind, Action> {
|
pub fn key_binds() -> HashMap<KeyBind, Action> {
|
||||||
let mut key_binds = HashMap::new();
|
let mut key_binds = HashMap::new();
|
||||||
|
|
@ -68,6 +28,7 @@ pub fn key_binds() -> HashMap<KeyBind, Action> {
|
||||||
bind!([Ctrl, Shift], Key::Character("Q".into()), WindowClose);
|
bind!([Ctrl, Shift], Key::Character("Q".into()), WindowClose);
|
||||||
bind!([Ctrl, Shift], Key::Character("T".into()), TabNew);
|
bind!([Ctrl, Shift], Key::Character("T".into()), TabNew);
|
||||||
bind!([Ctrl, Shift], Key::Character("V".into()), Paste);
|
bind!([Ctrl, Shift], Key::Character("V".into()), Paste);
|
||||||
|
bind!([Shift], Key::Named(Named::Insert), PastePrimary);
|
||||||
bind!([Ctrl, Shift], Key::Character("W".into()), TabClose);
|
bind!([Ctrl, Shift], Key::Character("W".into()), TabClose);
|
||||||
bind!([Ctrl], Key::Character(",".into()), Settings);
|
bind!([Ctrl], Key::Character(",".into()), Settings);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,6 @@ pub fn localize() {
|
||||||
let requested_languages = i18n_embed::DesktopLanguageRequester::requested_languages();
|
let requested_languages = i18n_embed::DesktopLanguageRequester::requested_languages();
|
||||||
|
|
||||||
if let Err(error) = localizer.select(&requested_languages) {
|
if let Err(error) = localizer.select(&requested_languages) {
|
||||||
eprintln!("Error while loading language for App List {}", error);
|
eprintln!("Error while loading language for App List {error}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
398
src/main.rs
398
src/main.rs
|
|
@ -2,6 +2,8 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use alacritty_terminal::{event::Event as TermEvent, term, term::color::Colors as TermColors, tty};
|
use alacritty_terminal::{event::Event as TermEvent, term, term::color::Colors as TermColors, tty};
|
||||||
|
use cosmic::widget::menu::action::MenuAction;
|
||||||
|
use cosmic::widget::menu::key_bind::KeyBind;
|
||||||
use cosmic::{
|
use cosmic::{
|
||||||
app::{message, Command, Core, Settings},
|
app::{message, Command, Core, Settings},
|
||||||
cosmic_config::{self, ConfigSet, CosmicConfigEntry},
|
cosmic_config::{self, ConfigSet, CosmicConfigEntry},
|
||||||
|
|
@ -12,6 +14,7 @@ use cosmic::{
|
||||||
clipboard, event,
|
clipboard, event,
|
||||||
futures::SinkExt,
|
futures::SinkExt,
|
||||||
keyboard::{Event as KeyEvent, Key, Modifiers},
|
keyboard::{Event as KeyEvent, Key, Modifiers},
|
||||||
|
mouse::{Button as MouseButton, Event as MouseEvent},
|
||||||
subscription::{self, Subscription},
|
subscription::{self, Subscription},
|
||||||
window, Alignment, Color, Event, Length, Limits, Padding, Point,
|
window, Alignment, Color, Event, Length, Limits, Padding, Point,
|
||||||
},
|
},
|
||||||
|
|
@ -40,7 +43,7 @@ mod mouse_reporter;
|
||||||
use icon_cache::IconCache;
|
use icon_cache::IconCache;
|
||||||
mod icon_cache;
|
mod icon_cache;
|
||||||
|
|
||||||
use key_bind::{key_binds, KeyBind};
|
use key_bind::key_binds;
|
||||||
mod key_bind;
|
mod key_bind;
|
||||||
|
|
||||||
mod localize;
|
mod localize;
|
||||||
|
|
@ -145,13 +148,6 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
|
||||||
let mut settings = Settings::default();
|
let mut settings = Settings::default();
|
||||||
settings = settings.theme(config.app_theme.theme());
|
settings = settings.theme(config.app_theme.theme());
|
||||||
|
|
||||||
#[cfg(target_os = "redox")]
|
|
||||||
{
|
|
||||||
// Redox does not support resize if doing CSDs
|
|
||||||
settings = settings.client_decorations(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
settings = settings.size_limits(Limits::NONE.min_width(360.0).min_height(180.0));
|
settings = settings.size_limits(Limits::NONE.min_width(360.0).min_height(180.0));
|
||||||
|
|
||||||
let flags = Flags {
|
let flags = Flags {
|
||||||
|
|
@ -178,6 +174,7 @@ pub enum Action {
|
||||||
About,
|
About,
|
||||||
ColorSchemes(ColorSchemeKind),
|
ColorSchemes(ColorSchemeKind),
|
||||||
Copy,
|
Copy,
|
||||||
|
CopyPrimary,
|
||||||
Find,
|
Find,
|
||||||
PaneFocusDown,
|
PaneFocusDown,
|
||||||
PaneFocusLeft,
|
PaneFocusLeft,
|
||||||
|
|
@ -187,6 +184,7 @@ pub enum Action {
|
||||||
PaneSplitVertical,
|
PaneSplitVertical,
|
||||||
PaneToggleMaximized,
|
PaneToggleMaximized,
|
||||||
Paste,
|
Paste,
|
||||||
|
PastePrimary,
|
||||||
ProfileOpen(ProfileId),
|
ProfileOpen(ProfileId),
|
||||||
Profiles,
|
Profiles,
|
||||||
SelectAll,
|
SelectAll,
|
||||||
|
|
@ -212,46 +210,50 @@ pub enum Action {
|
||||||
ZoomReset,
|
ZoomReset,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Action {
|
impl MenuAction for Action {
|
||||||
pub fn message(self, entity_opt: Option<segmented_button::Entity>) -> Message {
|
type Message = Message;
|
||||||
|
|
||||||
|
fn message(&self, entity_opt: Option<segmented_button::Entity>) -> Message {
|
||||||
match self {
|
match self {
|
||||||
Action::About => Message::ToggleContextPage(ContextPage::About),
|
Self::About => Message::ToggleContextPage(ContextPage::About),
|
||||||
Action::ColorSchemes(color_scheme_kind) => {
|
Self::ColorSchemes(color_scheme_kind) => {
|
||||||
Message::ToggleContextPage(ContextPage::ColorSchemes(color_scheme_kind))
|
Message::ToggleContextPage(ContextPage::ColorSchemes(*color_scheme_kind))
|
||||||
}
|
}
|
||||||
Action::Copy => Message::Copy(entity_opt),
|
Self::Copy => Message::Copy(entity_opt),
|
||||||
Action::Find => Message::Find(true),
|
Self::CopyPrimary => Message::CopyPrimary(entity_opt),
|
||||||
Action::PaneFocusDown => Message::PaneFocusAdjacent(pane_grid::Direction::Down),
|
Self::Find => Message::Find(true),
|
||||||
Action::PaneFocusLeft => Message::PaneFocusAdjacent(pane_grid::Direction::Left),
|
Self::PaneFocusDown => Message::PaneFocusAdjacent(pane_grid::Direction::Down),
|
||||||
Action::PaneFocusRight => Message::PaneFocusAdjacent(pane_grid::Direction::Right),
|
Self::PaneFocusLeft => Message::PaneFocusAdjacent(pane_grid::Direction::Left),
|
||||||
Action::PaneFocusUp => Message::PaneFocusAdjacent(pane_grid::Direction::Up),
|
Self::PaneFocusRight => Message::PaneFocusAdjacent(pane_grid::Direction::Right),
|
||||||
Action::PaneSplitHorizontal => Message::PaneSplit(pane_grid::Axis::Horizontal),
|
Self::PaneFocusUp => Message::PaneFocusAdjacent(pane_grid::Direction::Up),
|
||||||
Action::PaneSplitVertical => Message::PaneSplit(pane_grid::Axis::Vertical),
|
Self::PaneSplitHorizontal => Message::PaneSplit(pane_grid::Axis::Horizontal),
|
||||||
Action::PaneToggleMaximized => Message::PaneToggleMaximized,
|
Self::PaneSplitVertical => Message::PaneSplit(pane_grid::Axis::Vertical),
|
||||||
Action::Paste => Message::Paste(entity_opt),
|
Self::PaneToggleMaximized => Message::PaneToggleMaximized,
|
||||||
Action::ProfileOpen(profile_id) => Message::ProfileOpen(profile_id),
|
Self::Paste => Message::Paste(entity_opt),
|
||||||
Action::Profiles => Message::ToggleContextPage(ContextPage::Profiles),
|
Self::PastePrimary => Message::PastePrimary(entity_opt),
|
||||||
Action::SelectAll => Message::SelectAll(entity_opt),
|
Self::ProfileOpen(profile_id) => Message::ProfileOpen(*profile_id),
|
||||||
Action::Settings => Message::ToggleContextPage(ContextPage::Settings),
|
Self::Profiles => Message::ToggleContextPage(ContextPage::Profiles),
|
||||||
Action::ShowHeaderBar(show_headerbar) => Message::ShowHeaderBar(show_headerbar),
|
Self::SelectAll => Message::SelectAll(entity_opt),
|
||||||
Action::TabActivate0 => Message::TabActivateJump(0),
|
Self::Settings => Message::ToggleContextPage(ContextPage::Settings),
|
||||||
Action::TabActivate1 => Message::TabActivateJump(1),
|
Self::ShowHeaderBar(show_headerbar) => Message::ShowHeaderBar(*show_headerbar),
|
||||||
Action::TabActivate2 => Message::TabActivateJump(2),
|
Self::TabActivate0 => Message::TabActivateJump(0),
|
||||||
Action::TabActivate3 => Message::TabActivateJump(3),
|
Self::TabActivate1 => Message::TabActivateJump(1),
|
||||||
Action::TabActivate4 => Message::TabActivateJump(4),
|
Self::TabActivate2 => Message::TabActivateJump(2),
|
||||||
Action::TabActivate5 => Message::TabActivateJump(5),
|
Self::TabActivate3 => Message::TabActivateJump(3),
|
||||||
Action::TabActivate6 => Message::TabActivateJump(6),
|
Self::TabActivate4 => Message::TabActivateJump(4),
|
||||||
Action::TabActivate7 => Message::TabActivateJump(7),
|
Self::TabActivate5 => Message::TabActivateJump(5),
|
||||||
Action::TabActivate8 => Message::TabActivateJump(8),
|
Self::TabActivate6 => Message::TabActivateJump(6),
|
||||||
Action::TabClose => Message::TabClose(entity_opt),
|
Self::TabActivate7 => Message::TabActivateJump(7),
|
||||||
Action::TabNew => Message::TabNew,
|
Self::TabActivate8 => Message::TabActivateJump(8),
|
||||||
Action::TabNext => Message::TabNext,
|
Self::TabClose => Message::TabClose(entity_opt),
|
||||||
Action::TabPrev => Message::TabPrev,
|
Self::TabNew => Message::TabNew,
|
||||||
Action::WindowClose => Message::WindowClose,
|
Self::TabNext => Message::TabNext,
|
||||||
Action::WindowNew => Message::WindowNew,
|
Self::TabPrev => Message::TabPrev,
|
||||||
Action::ZoomIn => Message::ZoomIn,
|
Self::WindowClose => Message::WindowClose,
|
||||||
Action::ZoomOut => Message::ZoomOut,
|
Self::WindowNew => Message::WindowNew,
|
||||||
Action::ZoomReset => Message::ZoomReset,
|
Self::ZoomIn => Message::ZoomIn,
|
||||||
|
Self::ZoomOut => Message::ZoomOut,
|
||||||
|
Self::ZoomReset => Message::ZoomReset,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -272,6 +274,7 @@ pub enum Message {
|
||||||
ColorSchemeTabActivate(widget::segmented_button::Entity),
|
ColorSchemeTabActivate(widget::segmented_button::Entity),
|
||||||
Config(Config),
|
Config(Config),
|
||||||
Copy(Option<segmented_button::Entity>),
|
Copy(Option<segmented_button::Entity>),
|
||||||
|
CopyPrimary(Option<segmented_button::Entity>),
|
||||||
DefaultBoldFontWeight(usize),
|
DefaultBoldFontWeight(usize),
|
||||||
DefaultDimFontWeight(usize),
|
DefaultDimFontWeight(usize),
|
||||||
DefaultFont(usize),
|
DefaultFont(usize),
|
||||||
|
|
@ -284,6 +287,7 @@ pub enum Message {
|
||||||
FindNext,
|
FindNext,
|
||||||
FindPrevious,
|
FindPrevious,
|
||||||
FindSearchValueChanged(String),
|
FindSearchValueChanged(String),
|
||||||
|
MiddleClick(pane_grid::Pane, Option<segmented_button::Entity>),
|
||||||
FocusFollowMouse(bool),
|
FocusFollowMouse(bool),
|
||||||
Key(Modifiers, Key),
|
Key(Modifiers, Key),
|
||||||
LaunchUrl(String),
|
LaunchUrl(String),
|
||||||
|
|
@ -297,10 +301,13 @@ pub enum Message {
|
||||||
PaneSplit(pane_grid::Axis),
|
PaneSplit(pane_grid::Axis),
|
||||||
PaneToggleMaximized,
|
PaneToggleMaximized,
|
||||||
Paste(Option<segmented_button::Entity>),
|
Paste(Option<segmented_button::Entity>),
|
||||||
|
PastePrimary(Option<segmented_button::Entity>),
|
||||||
PasteValue(Option<segmented_button::Entity>, String),
|
PasteValue(Option<segmented_button::Entity>, String),
|
||||||
ProfileCollapse(ProfileId),
|
ProfileCollapse(ProfileId),
|
||||||
ProfileCommand(ProfileId, String),
|
ProfileCommand(ProfileId, String),
|
||||||
|
ProfileDirectory(ProfileId, String),
|
||||||
ProfileExpand(ProfileId),
|
ProfileExpand(ProfileId),
|
||||||
|
ProfileHold(ProfileId, bool),
|
||||||
ProfileName(ProfileId, String),
|
ProfileName(ProfileId, String),
|
||||||
ProfileNew,
|
ProfileNew,
|
||||||
ProfileOpen(ProfileId),
|
ProfileOpen(ProfileId),
|
||||||
|
|
@ -459,9 +466,9 @@ impl App {
|
||||||
{
|
{
|
||||||
let color = Color::from(theme.cosmic().background.base);
|
let color = Color::from(theme.cosmic().background.base);
|
||||||
let bytes = color.into_rgba8();
|
let bytes = color.into_rgba8();
|
||||||
let data = (bytes[2] as u32)
|
let data = u32::from(bytes[2])
|
||||||
| ((bytes[1] as u32) << 8)
|
| (u32::from(bytes[1]) << 8)
|
||||||
| ((bytes[0] as u32) << 16)
|
| (u32::from(bytes[0]) << 16)
|
||||||
| 0xFF000000;
|
| 0xFF000000;
|
||||||
terminal::WINDOW_BG_COLOR.store(data, Ordering::SeqCst);
|
terminal::WINDOW_BG_COLOR.store(data, Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
|
|
@ -498,17 +505,14 @@ impl App {
|
||||||
fn save_color_schemes(&mut self, color_scheme_kind: ColorSchemeKind) -> Command<Message> {
|
fn save_color_schemes(&mut self, color_scheme_kind: ColorSchemeKind) -> Command<Message> {
|
||||||
// Optimized for just saving color_schemes
|
// Optimized for just saving color_schemes
|
||||||
if let Some(ref config_handler) = self.config_handler {
|
if let Some(ref config_handler) = self.config_handler {
|
||||||
match config_handler.set(
|
if let Err(err) = config_handler.set(
|
||||||
match color_scheme_kind {
|
match color_scheme_kind {
|
||||||
ColorSchemeKind::Dark => "color_schemes_dark",
|
ColorSchemeKind::Dark => "color_schemes_dark",
|
||||||
ColorSchemeKind::Light => "color_schemes_light",
|
ColorSchemeKind::Light => "color_schemes_light",
|
||||||
},
|
},
|
||||||
&self.config.color_schemes(color_scheme_kind),
|
self.config.color_schemes(color_scheme_kind),
|
||||||
) {
|
) {
|
||||||
Ok(()) => {}
|
log::error!("failed to save config: {}", err);
|
||||||
Err(err) => {
|
|
||||||
log::error!("failed to save config: {}", err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.update_color_schemes();
|
self.update_color_schemes();
|
||||||
|
|
@ -663,7 +667,7 @@ impl App {
|
||||||
hash = short_hash.as_str(),
|
hash = short_hash.as_str(),
|
||||||
date = date
|
date = date
|
||||||
))
|
))
|
||||||
.on_press(Message::LaunchUrl(format!("{}/commits/{}", repository, hash)))
|
.on_press(Message::LaunchUrl(format!("{repository}/commits/{hash}")))
|
||||||
.padding(0)
|
.padding(0)
|
||||||
.into(),
|
.into(),
|
||||||
])
|
])
|
||||||
|
|
@ -753,7 +757,7 @@ impl App {
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
|
|
||||||
for error in self.color_scheme_errors.iter() {
|
for error in &self.color_scheme_errors {
|
||||||
sections.push(
|
sections.push(
|
||||||
widget::row::with_children(vec![
|
widget::row::with_children(vec![
|
||||||
icon_cache_get("dialog-error-symbolic", 16)
|
icon_cache_get("dialog-error-symbolic", 16)
|
||||||
|
|
@ -796,9 +800,8 @@ impl App {
|
||||||
if !self.config.profiles.is_empty() {
|
if !self.config.profiles.is_empty() {
|
||||||
let mut profiles_section = widget::settings::view_section("");
|
let mut profiles_section = widget::settings::view_section("");
|
||||||
for (profile_name, profile_id) in self.config.profile_names() {
|
for (profile_name, profile_id) in self.config.profile_names() {
|
||||||
let profile = match self.config.profiles.get(&profile_id) {
|
let Some(profile) = self.config.profiles.get(&profile_id) else {
|
||||||
Some(some) => some,
|
continue;
|
||||||
None => continue,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let expanded = self.profile_expanded == Some(profile_id);
|
let expanded = self.profile_expanded == Some(profile_id);
|
||||||
|
|
@ -858,6 +861,16 @@ impl App {
|
||||||
])
|
])
|
||||||
.spacing(space_xxxs)
|
.spacing(space_xxxs)
|
||||||
.into(),
|
.into(),
|
||||||
|
widget::column::with_children(vec![
|
||||||
|
widget::text(fl!("working-directory")).into(),
|
||||||
|
widget::text_input("", &profile.working_directory)
|
||||||
|
.on_input(move |text| {
|
||||||
|
Message::ProfileDirectory(profile_id, text)
|
||||||
|
})
|
||||||
|
.into(),
|
||||||
|
])
|
||||||
|
.spacing(space_xxxs)
|
||||||
|
.into(),
|
||||||
widget::column::with_children(vec![
|
widget::column::with_children(vec![
|
||||||
widget::text(fl!("tab-title")).into(),
|
widget::text(fl!("tab-title")).into(),
|
||||||
widget::text_input("", &profile.tab_title)
|
widget::text_input("", &profile.tab_title)
|
||||||
|
|
@ -908,18 +921,35 @@ impl App {
|
||||||
.add(
|
.add(
|
||||||
widget::settings::item::builder(fl!("make-default")).control(
|
widget::settings::item::builder(fl!("make-default")).control(
|
||||||
widget::toggler(
|
widget::toggler(
|
||||||
"".to_string(),
|
None,
|
||||||
self.get_default_profile().is_some_and(|p| p == profile_id),
|
self.get_default_profile().is_some_and(|p| p == profile_id),
|
||||||
move |t| Message::UpdateDefaultProfile((t, profile_id)),
|
move |t| Message::UpdateDefaultProfile((t, profile_id)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
)
|
||||||
|
.add(
|
||||||
|
widget::row::with_children(vec![
|
||||||
|
widget::column::with_children(vec![
|
||||||
|
widget::text(fl!("hold")).into(),
|
||||||
|
widget::text::caption(fl!("remain-open")).into(),
|
||||||
|
])
|
||||||
|
.spacing(space_xxxs)
|
||||||
|
.into(),
|
||||||
|
widget::horizontal_space(Length::Fill).into(),
|
||||||
|
widget::toggler(None, profile.hold, move |t| {
|
||||||
|
Message::ProfileHold(profile_id, t)
|
||||||
|
})
|
||||||
|
.into(),
|
||||||
|
])
|
||||||
|
.align_items(Alignment::Center)
|
||||||
|
.padding([0, space_s]),
|
||||||
);
|
);
|
||||||
|
|
||||||
let padding = Padding {
|
let padding = Padding {
|
||||||
top: 0.0,
|
top: 0.0,
|
||||||
bottom: 0.0,
|
bottom: 0.0,
|
||||||
left: space_s as f32,
|
left: space_s.into(),
|
||||||
right: space_s as f32,
|
right: space_s.into(),
|
||||||
};
|
};
|
||||||
profiles_section =
|
profiles_section =
|
||||||
profiles_section.add(widget::container(expanded_section).padding(padding))
|
profiles_section.add(widget::container(expanded_section).padding(padding))
|
||||||
|
|
@ -1144,7 +1174,19 @@ impl App {
|
||||||
self.pane_model.focus = pane;
|
self.pane_model.focus = pane;
|
||||||
match &self.term_event_tx_opt {
|
match &self.term_event_tx_opt {
|
||||||
Some(term_event_tx) => {
|
Some(term_event_tx) => {
|
||||||
match self.themes.get(&self.config.syntax_theme(profile_id_opt)) {
|
let colors = self
|
||||||
|
.themes
|
||||||
|
.get(&self.config.syntax_theme(profile_id_opt))
|
||||||
|
.or_else(|| match self.config.color_scheme_kind() {
|
||||||
|
ColorSchemeKind::Dark => self
|
||||||
|
.themes
|
||||||
|
.get(&(config::COSMIC_THEME_DARK.to_string(), ColorSchemeKind::Dark)),
|
||||||
|
ColorSchemeKind::Light => self.themes.get(&(
|
||||||
|
config::COSMIC_THEME_LIGHT.to_string(),
|
||||||
|
ColorSchemeKind::Light,
|
||||||
|
)),
|
||||||
|
});
|
||||||
|
match colors {
|
||||||
Some(colors) => {
|
Some(colors) => {
|
||||||
let current_pane = self.pane_model.focus;
|
let current_pane = self.pane_model.focus;
|
||||||
if let Some(tab_model) = self.pane_model.active_mut() {
|
if let Some(tab_model) = self.pane_model.active_mut() {
|
||||||
|
|
@ -1153,7 +1195,6 @@ impl App {
|
||||||
.and_then(|profile_id| self.config.profiles.get(&profile_id))
|
.and_then(|profile_id| self.config.profiles.get(&profile_id))
|
||||||
{
|
{
|
||||||
Some(profile) => {
|
Some(profile) => {
|
||||||
if !profile.tab_title.is_empty() {}
|
|
||||||
let mut shell = None;
|
let mut shell = None;
|
||||||
if let Some(mut args) = shlex::split(&profile.command) {
|
if let Some(mut args) = shlex::split(&profile.command) {
|
||||||
if !args.is_empty() {
|
if !args.is_empty() {
|
||||||
|
|
@ -1161,17 +1202,19 @@ impl App {
|
||||||
shell = Some(tty::Shell::new(command, args));
|
shell = Some(tty::Shell::new(command, args));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let working_directory = (!profile.working_directory.is_empty())
|
||||||
|
.then(|| profile.working_directory.clone().into());
|
||||||
|
|
||||||
let options = tty::Options {
|
let options = tty::Options {
|
||||||
shell,
|
shell,
|
||||||
//TODO: configurable working directory?
|
working_directory,
|
||||||
working_directory: None,
|
hold: profile.hold,
|
||||||
//TODO: configurable hold (keep open when child exits)?
|
env: HashMap::new(),
|
||||||
hold: false,
|
|
||||||
};
|
};
|
||||||
let tab_title_override = if !profile.tab_title.is_empty() {
|
let tab_title_override = if profile.tab_title.is_empty() {
|
||||||
Some(profile.tab_title.clone())
|
|
||||||
} else {
|
|
||||||
None
|
None
|
||||||
|
} else {
|
||||||
|
Some(profile.tab_title.clone())
|
||||||
};
|
};
|
||||||
(options, tab_title_override)
|
(options, tab_title_override)
|
||||||
}
|
}
|
||||||
|
|
@ -1226,7 +1269,7 @@ impl App {
|
||||||
log::warn!("tried to create new tab before having event channel");
|
log::warn!("tried to create new tab before having event channel");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return self.update_title(Some(pane));
|
self.update_title(Some(pane))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1307,7 +1350,7 @@ impl Application for App {
|
||||||
let mut font_size_names = Vec::new();
|
let mut font_size_names = Vec::new();
|
||||||
let mut font_sizes = Vec::new();
|
let mut font_sizes = Vec::new();
|
||||||
for font_size in 4..=32 {
|
for font_size in 4..=32 {
|
||||||
font_size_names.push(format!("{}px", font_size));
|
font_size_names.push(format!("{font_size}px"));
|
||||||
font_sizes.push(font_size);
|
font_sizes.push(font_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1358,7 +1401,7 @@ impl Application for App {
|
||||||
let mut terminal_ids = HashMap::new();
|
let mut terminal_ids = HashMap::new();
|
||||||
terminal_ids.insert(pane_model.focus, widget::Id::unique());
|
terminal_ids.insert(pane_model.focus, widget::Id::unique());
|
||||||
|
|
||||||
let mut app = App {
|
let mut app = Self {
|
||||||
core,
|
core,
|
||||||
pane_model,
|
pane_model,
|
||||||
config_handler: flags.config_handler,
|
config_handler: flags.config_handler,
|
||||||
|
|
@ -1422,10 +1465,10 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_context_drawer(&mut self) -> Command<Message> {
|
fn on_context_drawer(&mut self) -> Command<Message> {
|
||||||
if !self.core.window.show_context {
|
if self.core.window.show_context {
|
||||||
self.update_focus()
|
|
||||||
} else {
|
|
||||||
Command::none()
|
Command::none()
|
||||||
|
} else {
|
||||||
|
self.update_focus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1436,15 +1479,10 @@ impl Application for App {
|
||||||
($name: ident, $value: expr) => {
|
($name: ident, $value: expr) => {
|
||||||
match &self.config_handler {
|
match &self.config_handler {
|
||||||
Some(config_handler) => {
|
Some(config_handler) => {
|
||||||
match paste::paste! { self.config.[<set_ $name>](config_handler, $value) } {
|
if let Err(err) =
|
||||||
Ok(_) => {}
|
paste::paste! { self.config.[<set_ $name>](config_handler, $value) }
|
||||||
Err(err) => {
|
{
|
||||||
log::warn!(
|
log::warn!("failed to save config {:?}: {}", stringify!($name), err);
|
||||||
"failed to save config {:?}: {}",
|
|
||||||
stringify!($name),
|
|
||||||
err
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
|
|
@ -1490,7 +1528,7 @@ impl Application for App {
|
||||||
move |result| {
|
move |result| {
|
||||||
Message::ColorSchemeExportResult(
|
Message::ColorSchemeExportResult(
|
||||||
color_scheme_kind,
|
color_scheme_kind,
|
||||||
color_scheme_id.clone(),
|
color_scheme_id,
|
||||||
result,
|
result,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
@ -1514,9 +1552,8 @@ impl Application for App {
|
||||||
&color_scheme,
|
&color_scheme,
|
||||||
ron::ser::PrettyConfig::new(),
|
ron::ser::PrettyConfig::new(),
|
||||||
) {
|
) {
|
||||||
Ok(ron) => match fs::write(path, &ron) {
|
Ok(ron) => {
|
||||||
Ok(()) => {}
|
if let Err(err) = fs::write(path, ron) {
|
||||||
Err(err) => {
|
|
||||||
log::error!(
|
log::error!(
|
||||||
"failed to export {:?} to {:?}: {}",
|
"failed to export {:?} to {:?}: {}",
|
||||||
color_scheme_id,
|
color_scheme_id,
|
||||||
|
|
@ -1524,7 +1561,7 @@ impl Application for App {
|
||||||
err
|
err
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
log::error!(
|
log::error!(
|
||||||
"failed to serialize color scheme {:?}: {}",
|
"failed to serialize color scheme {:?}: {}",
|
||||||
|
|
@ -1558,12 +1595,12 @@ impl Application for App {
|
||||||
self.dialog_opt = None;
|
self.dialog_opt = None;
|
||||||
if let DialogResult::Open(paths) = result {
|
if let DialogResult::Open(paths) = result {
|
||||||
self.color_scheme_errors.clear();
|
self.color_scheme_errors.clear();
|
||||||
for path in paths.iter() {
|
for path in &paths {
|
||||||
let mut file = match fs::File::open(path) {
|
let mut file = match fs::File::open(path) {
|
||||||
Ok(ok) => ok,
|
Ok(ok) => ok,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
self.color_scheme_errors
|
self.color_scheme_errors
|
||||||
.push(format!("Failed to open {:?}: {}", path, err));
|
.push(format!("Failed to open {path:?}: {err}"));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -1582,7 +1619,7 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
self.color_scheme_errors
|
self.color_scheme_errors
|
||||||
.push(format!("Failed to parse {:?}: {}", path, err));
|
.push(format!("Failed to parse {path:?}: {err}"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1645,6 +1682,23 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
return self.update_focus();
|
return self.update_focus();
|
||||||
}
|
}
|
||||||
|
Message::CopyPrimary(entity_opt) => {
|
||||||
|
if let Some(tab_model) = self.pane_model.active() {
|
||||||
|
let entity = entity_opt.unwrap_or_else(|| tab_model.active());
|
||||||
|
if let Some(terminal) = tab_model.data::<Mutex<Terminal>>(entity) {
|
||||||
|
let terminal = terminal.lock().unwrap();
|
||||||
|
let term = terminal.term.lock();
|
||||||
|
if let Some(text) = term.selection_to_string() {
|
||||||
|
return Command::batch([
|
||||||
|
clipboard::write_primary(text),
|
||||||
|
self.update_focus(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log::warn!("Failed to get focused pane");
|
||||||
|
}
|
||||||
|
}
|
||||||
Message::DefaultFont(index) => {
|
Message::DefaultFont(index) => {
|
||||||
match self.font_names.get(index) {
|
match self.font_names.get(index) {
|
||||||
Some(font_name) => {
|
Some(font_name) => {
|
||||||
|
|
@ -1793,22 +1847,31 @@ impl Application for App {
|
||||||
Message::FindSearchValueChanged(value) => {
|
Message::FindSearchValueChanged(value) => {
|
||||||
self.find_search_value = value;
|
self.find_search_value = value;
|
||||||
}
|
}
|
||||||
|
Message::MiddleClick(pane, entity_opt) => {
|
||||||
|
self.pane_model.focus = pane;
|
||||||
|
return Command::batch([
|
||||||
|
self.update_focus(),
|
||||||
|
clipboard::read_primary(move |value_opt| match value_opt {
|
||||||
|
Some(value) => message::app(Message::PasteValue(entity_opt, value)),
|
||||||
|
None => message::none(),
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
}
|
||||||
Message::FocusFollowMouse(focus_follow_mouse) => {
|
Message::FocusFollowMouse(focus_follow_mouse) => {
|
||||||
config_set!(focus_follow_mouse, focus_follow_mouse);
|
config_set!(focus_follow_mouse, focus_follow_mouse);
|
||||||
}
|
}
|
||||||
Message::Key(modifiers, key) => {
|
Message::Key(modifiers, key) => {
|
||||||
for (key_bind, action) in self.key_binds.iter() {
|
for (key_bind, action) in &self.key_binds {
|
||||||
if key_bind.matches(modifiers, &key) {
|
if key_bind.matches(modifiers, &key) {
|
||||||
return self.update(action.message(None));
|
return self.update(action.message(None));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::LaunchUrl(url) => match open::that_detached(&url) {
|
Message::LaunchUrl(url) => {
|
||||||
Ok(()) => {}
|
if let Err(err) = open::that_detached(&url) {
|
||||||
Err(err) => {
|
|
||||||
log::warn!("failed to open {:?}: {}", url, err);
|
log::warn!("failed to open {:?}: {}", url, err);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Message::Modifiers(modifiers) => {
|
Message::Modifiers(modifiers) => {
|
||||||
self.modifiers = modifiers;
|
self.modifiers = modifiers;
|
||||||
}
|
}
|
||||||
|
|
@ -1868,6 +1931,12 @@ impl Application for App {
|
||||||
None => message::none(),
|
None => message::none(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Message::PastePrimary(entity_opt) => {
|
||||||
|
return clipboard::read_primary(move |value_opt| match value_opt {
|
||||||
|
Some(value) => message::app(Message::PasteValue(entity_opt, value)),
|
||||||
|
None => message::none(),
|
||||||
|
});
|
||||||
|
}
|
||||||
Message::PasteValue(entity_opt, value) => {
|
Message::PasteValue(entity_opt, value) => {
|
||||||
if let Some(tab_model) = self.pane_model.active() {
|
if let Some(tab_model) = self.pane_model.active() {
|
||||||
let entity = entity_opt.unwrap_or_else(|| tab_model.active());
|
let entity = entity_opt.unwrap_or_else(|| tab_model.active());
|
||||||
|
|
@ -1887,9 +1956,21 @@ impl Application for App {
|
||||||
return self.save_profiles();
|
return self.save_profiles();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Message::ProfileDirectory(profile_id, text) => {
|
||||||
|
if let Some(profile) = self.config.profiles.get_mut(&profile_id) {
|
||||||
|
profile.working_directory = text;
|
||||||
|
return self.save_profiles();
|
||||||
|
}
|
||||||
|
}
|
||||||
Message::ProfileExpand(profile_id) => {
|
Message::ProfileExpand(profile_id) => {
|
||||||
self.profile_expanded = Some(profile_id);
|
self.profile_expanded = Some(profile_id);
|
||||||
}
|
}
|
||||||
|
Message::ProfileHold(profile_id, hold) => {
|
||||||
|
if let Some(profile) = self.config.profiles.get_mut(&profile_id) {
|
||||||
|
profile.hold = hold;
|
||||||
|
return self.save_profiles();
|
||||||
|
}
|
||||||
|
}
|
||||||
Message::ProfileName(profile_id, text) => {
|
Message::ProfileName(profile_id, text) => {
|
||||||
if let Some(profile) = self.config.profiles.get_mut(&profile_id) {
|
if let Some(profile) = self.config.profiles.get_mut(&profile_id) {
|
||||||
profile.name = text;
|
profile.name = text;
|
||||||
|
|
@ -2237,6 +2318,9 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
TermEvent::ChildExit(_error_code) => {
|
||||||
|
//Ignore this for now
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::TermEventTx(term_event_tx) => {
|
Message::TermEventTx(term_event_tx) => {
|
||||||
|
|
@ -2277,31 +2361,28 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extra work to do to prepare context pages
|
// Extra work to do to prepare context pages
|
||||||
match self.context_page {
|
if let ContextPage::ColorSchemes(color_scheme_kind) = self.context_page {
|
||||||
ContextPage::ColorSchemes(color_scheme_kind) => {
|
self.color_scheme_errors.clear();
|
||||||
self.color_scheme_errors.clear();
|
self.color_scheme_expanded = None;
|
||||||
self.color_scheme_expanded = None;
|
self.color_scheme_renaming = None;
|
||||||
self.color_scheme_renaming = None;
|
self.color_scheme_tab_model = widget::segmented_button::Model::default();
|
||||||
self.color_scheme_tab_model = widget::segmented_button::Model::default();
|
let dark_entity = self
|
||||||
let dark_entity = self
|
.color_scheme_tab_model
|
||||||
.color_scheme_tab_model
|
.insert()
|
||||||
.insert()
|
.text(fl!("dark"))
|
||||||
.text(fl!("dark"))
|
.data(ColorSchemeKind::Dark)
|
||||||
.data(ColorSchemeKind::Dark)
|
.id();
|
||||||
.id();
|
let light_entity = self
|
||||||
let light_entity = self
|
.color_scheme_tab_model
|
||||||
.color_scheme_tab_model
|
.insert()
|
||||||
.insert()
|
.text(fl!("light"))
|
||||||
.text(fl!("light"))
|
.data(ColorSchemeKind::Light)
|
||||||
.data(ColorSchemeKind::Light)
|
.id();
|
||||||
.id();
|
self.color_scheme_tab_model
|
||||||
self.color_scheme_tab_model
|
.activate(match color_scheme_kind {
|
||||||
.activate(match color_scheme_kind {
|
ColorSchemeKind::Dark => dark_entity,
|
||||||
ColorSchemeKind::Dark => dark_entity,
|
ColorSchemeKind::Light => light_entity,
|
||||||
ColorSchemeKind::Light => light_entity,
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.set_context_title(context_page.title());
|
self.set_context_title(context_page.title());
|
||||||
|
|
@ -2395,43 +2476,39 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
|
|
||||||
let entity = tab_model.active();
|
let entity = tab_model.active();
|
||||||
|
let entity_middle_click = tab_model.active();
|
||||||
let terminal_id = self
|
let terminal_id = self
|
||||||
.terminal_ids
|
.terminal_ids
|
||||||
.get(&pane)
|
.get(&pane)
|
||||||
.cloned()
|
.cloned()
|
||||||
.unwrap_or_else(widget::Id::unique);
|
.unwrap_or_else(widget::Id::unique);
|
||||||
match tab_model.data::<Mutex<Terminal>>(entity) {
|
if let Some(terminal) = tab_model.data::<Mutex<Terminal>>(entity) {
|
||||||
Some(terminal) => {
|
let mut terminal_box = terminal_box(terminal)
|
||||||
let mut terminal_box = terminal_box(terminal)
|
.id(terminal_id)
|
||||||
.id(terminal_id)
|
.on_context_menu(move |position_opt| {
|
||||||
.on_context_menu(move |position_opt| {
|
Message::TabContextMenu(pane, position_opt)
|
||||||
Message::TabContextMenu(pane, position_opt)
|
})
|
||||||
})
|
.on_middle_click(move || Message::MiddleClick(pane, Some(entity_middle_click)))
|
||||||
.opacity(self.config.opacity_ratio())
|
.opacity(self.config.opacity_ratio())
|
||||||
.padding(space_xxs);
|
.padding(space_xxs);
|
||||||
|
|
||||||
if self.config.focus_follow_mouse {
|
if self.config.focus_follow_mouse {
|
||||||
terminal_box =
|
terminal_box = terminal_box.on_mouse_enter(move || Message::MouseEnter(pane));
|
||||||
terminal_box.on_mouse_enter(move || Message::MouseEnter(pane));
|
|
||||||
}
|
|
||||||
|
|
||||||
let context_menu = {
|
|
||||||
let terminal = terminal.lock().unwrap();
|
|
||||||
terminal.context_menu
|
|
||||||
};
|
|
||||||
|
|
||||||
let tab_element: Element<'_, Message> = match context_menu {
|
|
||||||
Some(point) => widget::popover(terminal_box.context_menu(point))
|
|
||||||
.popup(menu::context_menu(&self.config, &self.key_binds, entity))
|
|
||||||
.position(widget::popover::Position::Point(point))
|
|
||||||
.into(),
|
|
||||||
None => terminal_box.into(),
|
|
||||||
};
|
|
||||||
tab_column = tab_column.push(tab_element);
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
//TODO
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let context_menu = {
|
||||||
|
let terminal = terminal.lock().unwrap();
|
||||||
|
terminal.context_menu
|
||||||
|
};
|
||||||
|
|
||||||
|
let tab_element: Element<'_, Message> = match context_menu {
|
||||||
|
Some(point) => widget::popover(terminal_box.context_menu(point))
|
||||||
|
.popup(menu::context_menu(&self.config, &self.key_binds, entity))
|
||||||
|
.position(widget::popover::Position::Point(point))
|
||||||
|
.into(),
|
||||||
|
None => terminal_box.into(),
|
||||||
|
};
|
||||||
|
tab_column = tab_column.push(tab_element);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Only draw find in the currently focused pane
|
//Only draw find in the currently focused pane
|
||||||
|
|
@ -2487,10 +2564,10 @@ impl Application for App {
|
||||||
.padding(space_xxs)
|
.padding(space_xxs)
|
||||||
.spacing(space_xxs);
|
.spacing(space_xxs);
|
||||||
|
|
||||||
tab_column = tab_column.push(
|
tab_column = tab_column
|
||||||
widget::cosmic_container::container(find_widget)
|
.push(widget::layer_container(find_widget).layer(cosmic_theme::Layer::Primary));
|
||||||
.layer(cosmic_theme::Layer::Primary),
|
} else {
|
||||||
);
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
pane_grid::Content::new(tab_column)
|
pane_grid::Content::new(tab_column)
|
||||||
|
|
@ -2519,6 +2596,9 @@ impl Application for App {
|
||||||
Event::Keyboard(KeyEvent::ModifiersChanged(modifiers)) => {
|
Event::Keyboard(KeyEvent::ModifiersChanged(modifiers)) => {
|
||||||
Some(Message::Modifiers(modifiers))
|
Some(Message::Modifiers(modifiers))
|
||||||
}
|
}
|
||||||
|
Event::Mouse(MouseEvent::ButtonReleased(MouseButton::Left)) => {
|
||||||
|
Some(Message::CopyPrimary(None))
|
||||||
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
}),
|
}),
|
||||||
subscription::channel(
|
subscription::channel(
|
||||||
|
|
|
||||||
145
src/menu.rs
145
src/menu.rs
|
|
@ -1,38 +1,24 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
|
use cosmic::widget::menu::key_bind::KeyBind;
|
||||||
|
use cosmic::widget::menu::{items as menu_items, root as menu_root, Item as MenuItem};
|
||||||
use cosmic::{
|
use cosmic::{
|
||||||
//TODO: export in cosmic::widget
|
|
||||||
iced::{
|
iced::{
|
||||||
widget::{column, horizontal_rule, horizontal_space},
|
widget::{column, horizontal_rule, horizontal_space},
|
||||||
Alignment, Background, Length,
|
Alignment, Background, Length,
|
||||||
},
|
},
|
||||||
iced_core::Border,
|
iced_core::Border,
|
||||||
theme,
|
menu_button, theme,
|
||||||
widget::{
|
widget::{
|
||||||
self,
|
self,
|
||||||
menu::{ItemHeight, ItemWidth, MenuBar, MenuTree},
|
menu::{ItemHeight, ItemWidth, MenuBar, Tree as MenuTree},
|
||||||
segmented_button,
|
segmented_button,
|
||||||
},
|
},
|
||||||
Element,
|
Element,
|
||||||
};
|
};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::{fl, Action, ColorSchemeId, ColorSchemeKind, Config, KeyBind, Message};
|
use crate::{fl, Action, ColorSchemeId, ColorSchemeKind, Config, Message};
|
||||||
|
|
||||||
macro_rules! menu_button {
|
|
||||||
($($x:expr),+ $(,)?) => (
|
|
||||||
widget::button(
|
|
||||||
widget::Row::with_children(
|
|
||||||
vec![$(Element::from($x)),+]
|
|
||||||
)
|
|
||||||
.align_items(Alignment::Center)
|
|
||||||
)
|
|
||||||
.height(Length::Fixed(32.0))
|
|
||||||
.padding([4, 16])
|
|
||||||
.width(Length::Fill)
|
|
||||||
.style(theme::Button::MenuItem)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn context_menu<'a>(
|
pub fn context_menu<'a>(
|
||||||
config: &Config,
|
config: &Config,
|
||||||
|
|
@ -40,7 +26,7 @@ pub fn context_menu<'a>(
|
||||||
entity: segmented_button::Entity,
|
entity: segmented_button::Entity,
|
||||||
) -> Element<'a, Message> {
|
) -> Element<'a, Message> {
|
||||||
let find_key = |action: &Action| -> String {
|
let find_key = |action: &Action| -> String {
|
||||||
for (key_bind, key_action) in key_binds.iter() {
|
for (key_bind, key_action) in key_binds {
|
||||||
if action == key_action {
|
if action == key_action {
|
||||||
return key_bind.to_string();
|
return key_bind.to_string();
|
||||||
}
|
}
|
||||||
|
|
@ -145,90 +131,69 @@ pub fn color_scheme_menu<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn menu_bar<'a>(config: &Config, 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))
|
|
||||||
.padding([4, 12])
|
|
||||||
.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 {
|
|
||||||
return key_bind.to_string();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
String::new()
|
|
||||||
};
|
|
||||||
|
|
||||||
let menu_item = |label, action| {
|
|
||||||
let key = find_key(&action);
|
|
||||||
MenuTree::new(
|
|
||||||
menu_button!(
|
|
||||||
widget::text(label),
|
|
||||||
horizontal_space(Length::Fill),
|
|
||||||
widget::text(key)
|
|
||||||
)
|
|
||||||
.on_press(action.message(None)),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut profile_items = Vec::with_capacity(config.profiles.len());
|
let mut profile_items = Vec::with_capacity(config.profiles.len());
|
||||||
for (name, id) in config.profile_names() {
|
for (name, id) in config.profile_names() {
|
||||||
profile_items.push(menu_item(name, Action::ProfileOpen(id)));
|
profile_items.push(MenuItem::Button(name, Action::ProfileOpen(id)));
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: what to do if there are no profiles?
|
//TODO: what to do if there are no profiles?
|
||||||
|
|
||||||
MenuBar::new(vec![
|
MenuBar::new(vec![
|
||||||
MenuTree::with_children(
|
MenuTree::with_children(
|
||||||
menu_root(fl!("file")),
|
menu_root(fl!("file")),
|
||||||
vec![
|
menu_items(
|
||||||
menu_item(fl!("new-tab"), Action::TabNew),
|
key_binds,
|
||||||
menu_item(fl!("new-window"), Action::WindowNew),
|
vec![
|
||||||
MenuTree::new(horizontal_rule(1)),
|
MenuItem::Button(fl!("new-tab"), Action::TabNew),
|
||||||
MenuTree::with_children(menu_folder(fl!("profile")), profile_items),
|
MenuItem::Button(fl!("new-window"), Action::WindowNew),
|
||||||
menu_item(fl!("menu-profiles"), Action::Profiles),
|
MenuItem::Divider,
|
||||||
MenuTree::new(horizontal_rule(1)),
|
MenuItem::Folder(fl!("profile"), profile_items),
|
||||||
menu_item(fl!("close-tab"), Action::TabClose),
|
MenuItem::Button(fl!("menu-profiles"), Action::Profiles),
|
||||||
MenuTree::new(horizontal_rule(1)),
|
MenuItem::Divider,
|
||||||
menu_item(fl!("quit"), Action::WindowClose),
|
MenuItem::Button(fl!("close-tab"), Action::TabClose),
|
||||||
],
|
MenuItem::Divider,
|
||||||
|
MenuItem::Button(fl!("quit"), Action::WindowClose),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
MenuTree::with_children(
|
MenuTree::with_children(
|
||||||
menu_root(fl!("edit")),
|
menu_root(fl!("edit")),
|
||||||
vec![
|
menu_items(
|
||||||
menu_item(fl!("copy"), Action::Copy),
|
key_binds,
|
||||||
menu_item(fl!("paste"), Action::Paste),
|
vec![
|
||||||
menu_item(fl!("select-all"), Action::SelectAll),
|
MenuItem::Button(fl!("copy"), Action::Copy),
|
||||||
MenuTree::new(horizontal_rule(1)),
|
MenuItem::Button(fl!("paste"), Action::Paste),
|
||||||
menu_item(fl!("find"), Action::Find),
|
MenuItem::Button(fl!("select-all"), Action::SelectAll),
|
||||||
],
|
MenuItem::Divider,
|
||||||
|
MenuItem::Button(fl!("find"), Action::Find),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
MenuTree::with_children(
|
MenuTree::with_children(
|
||||||
menu_root(fl!("view")),
|
menu_root(fl!("view")),
|
||||||
vec![
|
menu_items(
|
||||||
menu_item(fl!("zoom-in"), Action::ZoomIn),
|
key_binds,
|
||||||
menu_item(fl!("zoom-reset"), Action::ZoomReset),
|
vec![
|
||||||
menu_item(fl!("zoom-out"), Action::ZoomOut),
|
MenuItem::Button(fl!("zoom-in"), Action::ZoomIn),
|
||||||
MenuTree::new(horizontal_rule(1)),
|
MenuItem::Button(fl!("zoom-reset"), Action::ZoomReset),
|
||||||
menu_item(fl!("next-tab"), Action::TabNext),
|
MenuItem::Button(fl!("zoom-out"), Action::ZoomOut),
|
||||||
menu_item(fl!("previous-tab"), Action::TabPrev),
|
MenuItem::Divider,
|
||||||
MenuTree::new(horizontal_rule(1)),
|
MenuItem::Button(fl!("next-tab"), Action::TabNext),
|
||||||
menu_item(fl!("split-horizontal"), Action::PaneSplitHorizontal),
|
MenuItem::Button(fl!("previous-tab"), Action::TabPrev),
|
||||||
menu_item(fl!("split-vertical"), Action::PaneSplitVertical),
|
MenuItem::Divider,
|
||||||
menu_item(fl!("pane-toggle-maximize"), Action::PaneToggleMaximized),
|
MenuItem::Button(fl!("split-horizontal"), Action::PaneSplitHorizontal),
|
||||||
MenuTree::new(horizontal_rule(1)),
|
MenuItem::Button(fl!("split-vertical"), Action::PaneSplitVertical),
|
||||||
menu_item(
|
MenuItem::Button(fl!("pane-toggle-maximize"), Action::PaneToggleMaximized),
|
||||||
fl!("menu-color-schemes"),
|
MenuItem::Divider,
|
||||||
Action::ColorSchemes(config.color_scheme_kind()),
|
MenuItem::Button(
|
||||||
),
|
fl!("menu-color-schemes"),
|
||||||
menu_item(fl!("menu-settings"), Action::Settings),
|
Action::ColorSchemes(config.color_scheme_kind()),
|
||||||
MenuTree::new(horizontal_rule(1)),
|
),
|
||||||
menu_item(fl!("menu-about"), Action::About),
|
MenuItem::Button(fl!("menu-settings"), Action::Settings),
|
||||||
],
|
MenuItem::Divider,
|
||||||
|
MenuItem::Button(fl!("menu-about"), Action::About),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
])
|
])
|
||||||
.item_height(ItemHeight::Dynamic(40))
|
.item_height(ItemHeight::Dynamic(40))
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ pub struct MouseReporter {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MouseReporter {
|
impl MouseReporter {
|
||||||
fn button_number(&self, button: Button) -> Option<u8> {
|
fn button_number(button: Button) -> Option<u8> {
|
||||||
match button {
|
match button {
|
||||||
Button::Left => Some(0),
|
Button::Left => Some(0),
|
||||||
Button::Middle => Some(1),
|
Button::Middle => Some(1),
|
||||||
|
|
@ -36,10 +36,10 @@ impl MouseReporter {
|
||||||
) -> Option<Vec<u8>> {
|
) -> Option<Vec<u8>> {
|
||||||
//Buttons are handle slightly different between normal and sgr
|
//Buttons are handle slightly different between normal and sgr
|
||||||
//for normal/utf8 the button release is always reported as button 3
|
//for normal/utf8 the button release is always reported as button 3
|
||||||
let Some(mut button) = (match event {
|
let mut button = (match event {
|
||||||
Event::Mouse(MouseEvent::ButtonPressed(b)) => {
|
Event::Mouse(MouseEvent::ButtonPressed(b)) => {
|
||||||
self.button = Some(b);
|
self.button = Some(b);
|
||||||
self.button_number(b)
|
Self::button_number(b)
|
||||||
}
|
}
|
||||||
Event::Mouse(MouseEvent::ButtonReleased(_b)) => {
|
Event::Mouse(MouseEvent::ButtonReleased(_b)) => {
|
||||||
self.button = None;
|
self.button = None;
|
||||||
|
|
@ -59,14 +59,10 @@ impl MouseReporter {
|
||||||
//character, Cb).
|
//character, Cb).
|
||||||
//For example, motion into cell x,y with button 1 down is reported as
|
//For example, motion into cell x,y with button 1 down is reported as
|
||||||
//CSI M @ CxCy ( @ = 32 + 0 (button 1) + 32 (motion indicator) ).
|
//CSI M @ CxCy ( @ = 32 + 0 (button 1) + 32 (motion indicator) ).
|
||||||
self.button
|
self.button.and_then(Self::button_number).map(|b| b + 32)
|
||||||
.and_then(|button| self.button_number(button))
|
|
||||||
.map(|b| b + 32)
|
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
}) else {
|
})?;
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
if modifiers.shift() {
|
if modifiers.shift() {
|
||||||
button += 4;
|
button += 4;
|
||||||
|
|
@ -127,16 +123,16 @@ impl MouseReporter {
|
||||||
x: u32,
|
x: u32,
|
||||||
y: u32,
|
y: u32,
|
||||||
) -> Option<Vec<u8>> {
|
) -> Option<Vec<u8>> {
|
||||||
let Some((button_no, event_code)) = (match event {
|
let (button_no, event_code) = (match event {
|
||||||
Event::Mouse(MouseEvent::ButtonPressed(button)) => {
|
Event::Mouse(MouseEvent::ButtonPressed(button)) => {
|
||||||
//Button pressed is reported as button 0,1,2 and event code M
|
//Button pressed is reported as button 0,1,2 and event code M
|
||||||
self.button = Some(button);
|
self.button = Some(button);
|
||||||
Some((self.button_number(button), "M"))
|
Some((Self::button_number(button), "M"))
|
||||||
}
|
}
|
||||||
Event::Mouse(MouseEvent::ButtonReleased(button)) => {
|
Event::Mouse(MouseEvent::ButtonReleased(button)) => {
|
||||||
//Button pressed is reported as button 0,1,2 and event code m
|
//Button pressed is reported as button 0,1,2 and event code m
|
||||||
self.button = None;
|
self.button = None;
|
||||||
Some((self.button_number(button), "m"))
|
Some((Self::button_number(button), "m"))
|
||||||
}
|
}
|
||||||
Event::Mouse(MouseEvent::CursorMoved { .. }) => {
|
Event::Mouse(MouseEvent::CursorMoved { .. }) => {
|
||||||
//Button pressed is reported as button 32 + 0,1,2 and event code M
|
//Button pressed is reported as button 32 + 0,1,2 and event code M
|
||||||
|
|
@ -148,12 +144,10 @@ impl MouseReporter {
|
||||||
self.last_movment_y = Some(y);
|
self.last_movment_y = Some(y);
|
||||||
}
|
}
|
||||||
self.button
|
self.button
|
||||||
.map(|button| (self.button_number(button).map(|b| b + 32), "M"))
|
.map(|button| (Self::button_number(button).map(|b| b + 32), "M"))
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
}) else {
|
})?;
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(mut button_no) = button_no {
|
if let Some(mut button_no) = button_no {
|
||||||
if modifiers.shift() {
|
if modifiers.shift() {
|
||||||
|
|
@ -174,7 +168,6 @@ impl MouseReporter {
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn report_sgr_mouse_wheel_scroll(
|
pub fn report_sgr_mouse_wheel_scroll(
|
||||||
&self,
|
|
||||||
terminal: &Terminal,
|
terminal: &Terminal,
|
||||||
term_cell_width: f32,
|
term_cell_width: f32,
|
||||||
term_cell_height: f32,
|
term_cell_height: f32,
|
||||||
|
|
@ -217,7 +210,6 @@ impl MouseReporter {
|
||||||
//Emulate mouse wheel scroll with up/down arrows. Using mouse spec uses
|
//Emulate mouse wheel scroll with up/down arrows. Using mouse spec uses
|
||||||
//scroll-back and scroll-forw actions, which moves whole windows like page up/page down.
|
//scroll-back and scroll-forw actions, which moves whole windows like page up/page down.
|
||||||
pub fn report_mouse_wheel_as_arrows(
|
pub fn report_mouse_wheel_as_arrows(
|
||||||
&self,
|
|
||||||
terminal: &Terminal,
|
terminal: &Terminal,
|
||||||
term_cell_width: f32,
|
term_cell_width: f32,
|
||||||
term_cell_height: f32,
|
term_cell_height: f32,
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,8 @@ use cosmic::{
|
||||||
widget::{pane_grid, segmented_button},
|
widget::{pane_grid, segmented_button},
|
||||||
};
|
};
|
||||||
use cosmic_text::{
|
use cosmic_text::{
|
||||||
Attrs, AttrsList, Buffer, BufferLine, CacheKeyFlags, Family, Metrics, Shaping, Weight, Wrap,
|
Attrs, AttrsList, Buffer, BufferLine, CacheKeyFlags, Family, LineEnding, Metrics, Shaping,
|
||||||
|
Weight, Wrap,
|
||||||
};
|
};
|
||||||
use indexmap::IndexSet;
|
use indexmap::IndexSet;
|
||||||
use std::{
|
use std::{
|
||||||
|
|
@ -110,25 +111,25 @@ fn convert_color(colors: &Colors, color: Color) -> cosmic_text::Color {
|
||||||
let rgb = match color {
|
let rgb = match color {
|
||||||
Color::Named(named_color) => match colors[named_color] {
|
Color::Named(named_color) => match colors[named_color] {
|
||||||
Some(rgb) => rgb,
|
Some(rgb) => rgb,
|
||||||
None => match named_color {
|
None => {
|
||||||
NamedColor::Background => {
|
if named_color == NamedColor::Background {
|
||||||
// Allow using an unset background
|
// Allow using an unset background
|
||||||
return cosmic_text::Color(WINDOW_BG_COLOR.load(Ordering::SeqCst));
|
return cosmic_text::Color(WINDOW_BG_COLOR.load(Ordering::SeqCst));
|
||||||
}
|
} else {
|
||||||
_ => {
|
|
||||||
log::warn!("missing named color {:?}", named_color);
|
log::warn!("missing named color {:?}", named_color);
|
||||||
Rgb::default()
|
Rgb::default()
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
Color::Spec(rgb) => rgb,
|
Color::Spec(rgb) => rgb,
|
||||||
Color::Indexed(index) => match colors[index as usize] {
|
Color::Indexed(index) => {
|
||||||
Some(rgb) => rgb,
|
if let Some(rgb) = colors[index as usize] {
|
||||||
None => {
|
rgb
|
||||||
|
} else {
|
||||||
log::warn!("missing indexed color {}", index);
|
log::warn!("missing indexed color {}", index);
|
||||||
Rgb::default()
|
Rgb::default()
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
cosmic_text::Color::rgb(rgb.r, rgb.g, rgb.b)
|
cosmic_text::Color::rgb(rgb.r, rgb.g, rgb.b)
|
||||||
}
|
}
|
||||||
|
|
@ -276,7 +277,7 @@ impl Terminal {
|
||||||
let window_id = 0;
|
let window_id = 0;
|
||||||
let pty = tty::new(&options, size.into(), window_id)?;
|
let pty = tty::new(&options, size.into(), window_id)?;
|
||||||
|
|
||||||
let pty_event_loop = EventLoop::new(term.clone(), event_proxy, pty, options.hold, false);
|
let pty_event_loop = EventLoop::new(term.clone(), event_proxy, pty, options.hold, false)?;
|
||||||
let notifier = Notifier(pty_event_loop.channel());
|
let notifier = Notifier(pty_event_loop.channel());
|
||||||
let _pty_join_handle = pty_event_loop.spawn();
|
let _pty_join_handle = pty_event_loop.spawn();
|
||||||
|
|
||||||
|
|
@ -437,9 +438,8 @@ impl Terminal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let search_regex = match &mut self.search_regex_opt {
|
let Some(search_regex) = &mut self.search_regex_opt else {
|
||||||
Some(some) => some,
|
return;
|
||||||
None => return,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Determine search origin
|
// Determine search origin
|
||||||
|
|
@ -572,11 +572,14 @@ impl Terminal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if changed {
|
if changed {
|
||||||
self.update_colors(config);
|
|
||||||
update = true;
|
update = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: this is done on every set_config because the changed boolean above does not capture
|
||||||
|
// WINDOW_BG changes
|
||||||
|
self.update_colors(config);
|
||||||
|
|
||||||
if update_cell_size {
|
if update_cell_size {
|
||||||
self.update_cell_size();
|
self.update_cell_size();
|
||||||
} else if update {
|
} else if update {
|
||||||
|
|
@ -664,13 +667,18 @@ impl Terminal {
|
||||||
while line_i >= buffer.lines.len() {
|
while line_i >= buffer.lines.len() {
|
||||||
buffer.lines.push(BufferLine::new(
|
buffer.lines.push(BufferLine::new(
|
||||||
"",
|
"",
|
||||||
|
LineEnding::default(),
|
||||||
AttrsList::new(self.default_attrs),
|
AttrsList::new(self.default_attrs),
|
||||||
Shaping::Advanced,
|
Shaping::Advanced,
|
||||||
));
|
));
|
||||||
buffer.set_redraw(true);
|
buffer.set_redraw(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if buffer.lines[line_i].set_text(text.clone(), attrs_list.clone()) {
|
if buffer.lines[line_i].set_text(
|
||||||
|
text.clone(),
|
||||||
|
LineEnding::default(),
|
||||||
|
attrs_list.clone(),
|
||||||
|
) {
|
||||||
buffer.set_redraw(true);
|
buffer.set_redraw(true);
|
||||||
}
|
}
|
||||||
line_i += 1;
|
line_i += 1;
|
||||||
|
|
@ -783,13 +791,14 @@ impl Terminal {
|
||||||
while line_i >= buffer.lines.len() {
|
while line_i >= buffer.lines.len() {
|
||||||
buffer.lines.push(BufferLine::new(
|
buffer.lines.push(BufferLine::new(
|
||||||
"",
|
"",
|
||||||
|
LineEnding::default(),
|
||||||
AttrsList::new(self.default_attrs),
|
AttrsList::new(self.default_attrs),
|
||||||
Shaping::Advanced,
|
Shaping::Advanced,
|
||||||
));
|
));
|
||||||
buffer.set_redraw(true);
|
buffer.set_redraw(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if buffer.lines[line_i].set_text(text, attrs_list) {
|
if buffer.lines[line_i].set_text(text, LineEnding::default(), attrs_list) {
|
||||||
buffer.set_redraw(true);
|
buffer.set_redraw(true);
|
||||||
}
|
}
|
||||||
line_i += 1;
|
line_i += 1;
|
||||||
|
|
@ -853,7 +862,7 @@ impl Terminal {
|
||||||
let term_lock = self.term.lock();
|
let term_lock = self.term.lock();
|
||||||
let mode = term_lock.mode();
|
let mode = term_lock.mode();
|
||||||
if mode.contains(TermMode::SGR_MOUSE) {
|
if mode.contains(TermMode::SGR_MOUSE) {
|
||||||
self.mouse_reporter.report_sgr_mouse_wheel_scroll(
|
MouseReporter::report_sgr_mouse_wheel_scroll(
|
||||||
self,
|
self,
|
||||||
self.size().cell_width,
|
self.size().cell_width,
|
||||||
self.size().cell_height,
|
self.size().cell_height,
|
||||||
|
|
@ -863,7 +872,7 @@ impl Terminal {
|
||||||
y,
|
y,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
self.mouse_reporter.report_mouse_wheel_as_arrows(
|
MouseReporter::report_mouse_wheel_as_arrows(
|
||||||
self,
|
self,
|
||||||
self.size().cell_width,
|
self.size().cell_width,
|
||||||
self.size().cell_height,
|
self.size().cell_height,
|
||||||
|
|
@ -876,6 +885,8 @@ impl Terminal {
|
||||||
impl Drop for Terminal {
|
impl Drop for Terminal {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// Ensure shutdown on terminal drop
|
// Ensure shutdown on terminal drop
|
||||||
self.notifier.0.send(Msg::Shutdown);
|
if let Err(err) = self.notifier.0.send(Msg::Shutdown) {
|
||||||
|
log::warn!("Failed to send shutdown message on dropped terminal: {err}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ use alacritty_terminal::{
|
||||||
selection::{Selection, SelectionType},
|
selection::{Selection, SelectionType},
|
||||||
term::{cell::Flags, TermMode},
|
term::{cell::Flags, TermMode},
|
||||||
};
|
};
|
||||||
|
use cosmic::widget::menu::key_bind::KeyBind;
|
||||||
use cosmic::{
|
use cosmic::{
|
||||||
cosmic_theme::palette::{blend::Compose, WithAlpha},
|
cosmic_theme::palette::{blend::Compose, WithAlpha},
|
||||||
iced::{
|
iced::{
|
||||||
|
|
@ -40,11 +41,7 @@ use std::{
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{key_bind::key_binds, terminal::Metadata, Action, Terminal, TerminalScroll};
|
||||||
key_bind::{key_binds, KeyBind},
|
|
||||||
terminal::Metadata,
|
|
||||||
Action, Terminal, TerminalScroll,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct TerminalBox<'a, Message> {
|
pub struct TerminalBox<'a, Message> {
|
||||||
terminal: &'a Mutex<Terminal>,
|
terminal: &'a Mutex<Terminal>,
|
||||||
|
|
@ -57,6 +54,7 @@ pub struct TerminalBox<'a, Message> {
|
||||||
on_mouse_enter: Option<Box<dyn Fn() -> Message + 'a>>,
|
on_mouse_enter: Option<Box<dyn Fn() -> Message + 'a>>,
|
||||||
opacity: Option<f32>,
|
opacity: Option<f32>,
|
||||||
mouse_inside_boundary: Option<bool>,
|
mouse_inside_boundary: Option<bool>,
|
||||||
|
on_middle_click: Option<Box<dyn Fn() -> Message + 'a>>,
|
||||||
key_binds: HashMap<KeyBind, Action>,
|
key_binds: HashMap<KeyBind, Action>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -76,6 +74,7 @@ where
|
||||||
on_mouse_enter: None,
|
on_mouse_enter: None,
|
||||||
opacity: None,
|
opacity: None,
|
||||||
mouse_inside_boundary: None,
|
mouse_inside_boundary: None,
|
||||||
|
on_middle_click: None,
|
||||||
key_binds: key_binds(),
|
key_binds: key_binds(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -118,6 +117,11 @@ where
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn on_middle_click(mut self, on_middle_click: impl Fn() -> Message + 'a) -> Self {
|
||||||
|
self.on_middle_click = Some(Box::new(on_middle_click));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn opacity(mut self, opacity: f32) -> Self {
|
pub fn opacity(mut self, opacity: f32) -> Self {
|
||||||
self.opacity = Some(opacity);
|
self.opacity = Some(opacity);
|
||||||
self
|
self
|
||||||
|
|
@ -168,10 +172,9 @@ where
|
||||||
// Calculate layout lines
|
// Calculate layout lines
|
||||||
terminal.with_buffer(|buffer| {
|
terminal.with_buffer(|buffer| {
|
||||||
let mut layout_lines = 0;
|
let mut layout_lines = 0;
|
||||||
for line in buffer.lines.iter() {
|
for line in &buffer.lines {
|
||||||
match line.layout_opt() {
|
if let Some(layout) = line.layout_opt() {
|
||||||
Some(layout) => layout_lines += layout.len(),
|
layout_lines += layout.len()
|
||||||
None => (),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -237,7 +240,7 @@ where
|
||||||
let state = tree.state.downcast_ref::<State>();
|
let state = tree.state.downcast_ref::<State>();
|
||||||
|
|
||||||
let cosmic_theme = theme.cosmic();
|
let cosmic_theme = theme.cosmic();
|
||||||
let scrollbar_w = cosmic_theme.spacing.space_xxs as f32;
|
let scrollbar_w = f32::from(cosmic_theme.spacing.space_xxs);
|
||||||
|
|
||||||
let view_position = layout.position() + [self.padding.left, self.padding.top].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)
|
let view_w = cmp::min(viewport.width as i32, layout.bounds().width as i32)
|
||||||
|
|
@ -274,12 +277,12 @@ where
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
Color::new(
|
Color::new(
|
||||||
background_color.r() as f32 / 255.0,
|
f32::from(background_color.r()) / 255.0,
|
||||||
background_color.g() as f32 / 255.0,
|
f32::from(background_color.g()) / 255.0,
|
||||||
background_color.b() as f32 / 255.0,
|
f32::from(background_color.b()) / 255.0,
|
||||||
match self.opacity {
|
match self.opacity {
|
||||||
Some(opacity) => opacity,
|
Some(opacity) => opacity,
|
||||||
None => background_color.a() as f32 / 255.0,
|
None => f32::from(background_color.a()) / 255.0,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
@ -325,10 +328,10 @@ where
|
||||||
) {
|
) {
|
||||||
let cosmic_text_to_iced_color = |color: cosmic_text::Color| {
|
let cosmic_text_to_iced_color = |color: cosmic_text::Color| {
|
||||||
Color::new(
|
Color::new(
|
||||||
color.r() as f32 / 255.0,
|
f32::from(color.r()) / 255.0,
|
||||||
color.g() as f32 / 255.0,
|
f32::from(color.g()) / 255.0,
|
||||||
color.b() as f32 / 255.0,
|
f32::from(color.b()) / 255.0,
|
||||||
color.a() as f32 / 255.0,
|
f32::from(color.a()) / 255.0,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -366,8 +369,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
if !metadata.flags.is_empty() {
|
if !metadata.flags.is_empty() {
|
||||||
let style_line_height =
|
let style_line_height = (self.glyph_font_size / 10.0).clamp(2.0, 16.0);
|
||||||
(self.glyph_font_size / 10.0).max(2.0).min(16.0);
|
|
||||||
|
|
||||||
let line_color = cosmic_text_to_iced_color(metadata.underline_color);
|
let line_color = cosmic_text_to_iced_color(metadata.underline_color);
|
||||||
|
|
||||||
|
|
@ -484,7 +486,7 @@ where
|
||||||
view_position,
|
view_position,
|
||||||
metadata_set,
|
metadata_set,
|
||||||
};
|
};
|
||||||
for glyph in run.glyphs.iter() {
|
for glyph in run.glyphs {
|
||||||
bg_rect.update(glyph, renderer, state.is_focused);
|
bg_rect.update(glyph, renderer, state.is_focused);
|
||||||
}
|
}
|
||||||
bg_rect.fill(renderer, state.is_focused);
|
bg_rect.fill(renderer, state.is_focused);
|
||||||
|
|
@ -602,7 +604,7 @@ where
|
||||||
modifiers,
|
modifiers,
|
||||||
..
|
..
|
||||||
}) if state.is_focused => {
|
}) if state.is_focused => {
|
||||||
for (key_bind, _) in self.key_binds.iter() {
|
for key_bind in self.key_binds.keys() {
|
||||||
if key_bind.matches(modifiers, &Key::Named(named)) {
|
if key_bind.matches(modifiers, &Key::Named(named)) {
|
||||||
return Status::Captured;
|
return Status::Captured;
|
||||||
}
|
}
|
||||||
|
|
@ -611,8 +613,22 @@ where
|
||||||
let escape_code = match named {
|
let escape_code = match named {
|
||||||
Named::Insert => csi("2", "~", mod_no),
|
Named::Insert => csi("2", "~", mod_no),
|
||||||
Named::Delete => csi("3", "~", mod_no),
|
Named::Delete => csi("3", "~", mod_no),
|
||||||
Named::PageUp => csi("5", "~", mod_no),
|
Named::PageUp => {
|
||||||
Named::PageDown => csi("6", "~", mod_no),
|
if modifiers.shift() {
|
||||||
|
terminal.scroll(TerminalScroll::PageUp);
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
csi("5", "~", mod_no)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Named::PageDown => {
|
||||||
|
if modifiers.shift() {
|
||||||
|
terminal.scroll(TerminalScroll::PageDown);
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
csi("6", "~", mod_no)
|
||||||
|
}
|
||||||
|
}
|
||||||
Named::ArrowUp => {
|
Named::ArrowUp => {
|
||||||
if is_app_cursor {
|
if is_app_cursor {
|
||||||
ss3("A", mod_no)
|
ss3("A", mod_no)
|
||||||
|
|
@ -642,14 +658,20 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Named::End => {
|
Named::End => {
|
||||||
if is_app_cursor {
|
if modifiers.shift() {
|
||||||
|
terminal.scroll(TerminalScroll::Bottom);
|
||||||
|
None
|
||||||
|
} else if is_app_cursor {
|
||||||
ss3("F", mod_no)
|
ss3("F", mod_no)
|
||||||
} else {
|
} else {
|
||||||
csi("F", "", mod_no)
|
csi("F", "", mod_no)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Named::Home => {
|
Named::Home => {
|
||||||
if is_app_cursor {
|
if modifiers.shift() {
|
||||||
|
terminal.scroll(TerminalScroll::Top);
|
||||||
|
None
|
||||||
|
} else if is_app_cursor {
|
||||||
ss3("H", mod_no)
|
ss3("H", mod_no)
|
||||||
} else {
|
} else {
|
||||||
csi("H", "", mod_no)
|
csi("H", "", mod_no)
|
||||||
|
|
@ -681,8 +703,7 @@ where
|
||||||
match named {
|
match named {
|
||||||
Named::Backspace => {
|
Named::Backspace => {
|
||||||
let code = if modifiers.control() { "\x08" } else { "\x7f" };
|
let code = if modifiers.control() { "\x08" } else { "\x7f" };
|
||||||
terminal
|
terminal.input_scroll(format!("{alt_prefix}{code}").as_bytes().to_vec());
|
||||||
.input_scroll(format!("{}{}", alt_prefix, code).as_bytes().to_vec());
|
|
||||||
status = Status::Captured;
|
status = Status::Captured;
|
||||||
}
|
}
|
||||||
Named::Enter => {
|
Named::Enter => {
|
||||||
|
|
@ -711,8 +732,7 @@ where
|
||||||
}
|
}
|
||||||
Named::Tab => {
|
Named::Tab => {
|
||||||
let code = if modifiers.shift() { "\x1b[Z" } else { "\x09" };
|
let code = if modifiers.shift() { "\x1b[Z" } else { "\x09" };
|
||||||
terminal
|
terminal.input_scroll(format!("{alt_prefix}{code}").as_bytes().to_vec());
|
||||||
.input_scroll(format!("{}{}", alt_prefix, code).as_bytes().to_vec());
|
|
||||||
status = Status::Captured;
|
status = Status::Captured;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
@ -727,7 +747,7 @@ where
|
||||||
key,
|
key,
|
||||||
..
|
..
|
||||||
}) if state.is_focused => {
|
}) if state.is_focused => {
|
||||||
for (key_bind, _) in self.key_binds.iter() {
|
for key_bind in self.key_binds.keys() {
|
||||||
if key_bind.matches(modifiers, &key) {
|
if key_bind.matches(modifiers, &key) {
|
||||||
return Status::Captured;
|
return Status::Captured;
|
||||||
}
|
}
|
||||||
|
|
@ -880,6 +900,10 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if button == Button::Middle {
|
||||||
|
if let Some(on_middle_click) = &self.on_middle_click {
|
||||||
|
shell.publish(on_middle_click());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Update context menu state
|
// Update context menu state
|
||||||
if let Some(on_context_menu) = &self.on_context_menu {
|
if let Some(on_context_menu) = &self.on_context_menu {
|
||||||
|
|
@ -1036,9 +1060,9 @@ fn shade(color: cosmic_text::Color, is_focused: bool) -> cosmic_text::Color {
|
||||||
} else {
|
} else {
|
||||||
let shade = 0.92;
|
let shade = 0.92;
|
||||||
cosmic_text::Color::rgba(
|
cosmic_text::Color::rgba(
|
||||||
(color.r() as f32 * shade) as u8,
|
(f32::from(color.r()) * shade) as u8,
|
||||||
(color.g() as f32 * shade) as u8,
|
(f32::from(color.g()) * shade) as u8,
|
||||||
(color.b() as f32 * shade) as u8,
|
(f32::from(color.b()) * shade) as u8,
|
||||||
color.a(),
|
color.a(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -1078,8 +1102,8 @@ pub struct State {
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
/// Creates a new [`State`].
|
/// Creates a new [`State`].
|
||||||
pub fn new() -> State {
|
pub fn new() -> Self {
|
||||||
State {
|
Self {
|
||||||
modifiers: Modifiers::empty(),
|
modifiers: Modifiers::empty(),
|
||||||
click: None,
|
click: None,
|
||||||
dragging: None,
|
dragging: None,
|
||||||
|
|
@ -1114,7 +1138,7 @@ meta 0b100000 (32)
|
||||||
caps_lock 0b1000000 (64)
|
caps_lock 0b1000000 (64)
|
||||||
num_lock 0b10000000 (128)
|
num_lock 0b10000000 (128)
|
||||||
*/
|
*/
|
||||||
fn calculate_modifier_number(state: &mut State) -> u8 {
|
fn calculate_modifier_number(state: &State) -> u8 {
|
||||||
let mut mod_no = 0;
|
let mut mod_no = 0;
|
||||||
if state.modifiers.shift() {
|
if state.modifiers.shift() {
|
||||||
mod_no |= 1;
|
mod_no |= 1;
|
||||||
|
|
@ -1134,10 +1158,10 @@ fn calculate_modifier_number(state: &mut State) -> u8 {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn csi(code: &str, suffix: &str, modifiers: u8) -> Option<Vec<u8>> {
|
fn csi(code: &str, suffix: &str, modifiers: u8) -> Option<Vec<u8>> {
|
||||||
if modifiers == 1 {
|
if modifiers == 1 {
|
||||||
Some(format!("\x1B[{}{}", code, suffix).as_bytes().to_vec())
|
Some(format!("\x1B[{code}{suffix}").as_bytes().to_vec())
|
||||||
} else {
|
} else {
|
||||||
Some(
|
Some(
|
||||||
format!("\x1B[{};{}{}", code, modifiers, suffix)
|
format!("\x1B[{code};{modifiers}{suffix}")
|
||||||
.as_bytes()
|
.as_bytes()
|
||||||
.to_vec(),
|
.to_vec(),
|
||||||
)
|
)
|
||||||
|
|
@ -1147,8 +1171,8 @@ fn csi(code: &str, suffix: &str, modifiers: u8) -> Option<Vec<u8>> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn ss3(code: &str, modifiers: u8) -> Option<Vec<u8>> {
|
fn ss3(code: &str, modifiers: u8) -> Option<Vec<u8>> {
|
||||||
if modifiers == 1 {
|
if modifiers == 1 {
|
||||||
Some(format!("\x1B\x4F{}", code).as_bytes().to_vec())
|
Some(format!("\x1B\x4F{code}").as_bytes().to_vec())
|
||||||
} else {
|
} else {
|
||||||
Some(format!("\x1B[1;{}{}", modifiers, code).as_bytes().to_vec())
|
Some(format!("\x1B[1;{modifiers}{code}").as_bytes().to_vec())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,9 @@ use hex_color::HexColor;
|
||||||
use palette::{encoding::Srgb, rgb::Rgb as PRgb, FromColor, Okhsl};
|
use palette::{encoding::Srgb, rgb::Rgb as PRgb, FromColor, Okhsl};
|
||||||
use std::{collections::HashMap, fs};
|
use std::{collections::HashMap, fs};
|
||||||
|
|
||||||
use crate::config::{ColorScheme, ColorSchemeAnsi, ColorSchemeKind};
|
use crate::config::{
|
||||||
|
ColorScheme, ColorSchemeAnsi, ColorSchemeKind, COSMIC_THEME_DARK, COSMIC_THEME_LIGHT,
|
||||||
|
};
|
||||||
|
|
||||||
// Fill missing dim/bright colors with derived values from normal ones.
|
// Fill missing dim/bright colors with derived values from normal ones.
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
|
@ -53,8 +55,8 @@ impl ColorDerive {
|
||||||
fn color_adj(rgb: Rgb, saturation_adj: f32, lightness_adj: f32) -> Rgb {
|
fn color_adj(rgb: Rgb, saturation_adj: f32, lightness_adj: f32) -> Rgb {
|
||||||
let mut okhsl = Self::rgb_to_okhsl(rgb);
|
let mut okhsl = Self::rgb_to_okhsl(rgb);
|
||||||
|
|
||||||
okhsl.saturation = (okhsl.saturation + saturation_adj).max(0.0).min(1.0);
|
okhsl.saturation = (okhsl.saturation + saturation_adj).clamp(0.0, 1.0);
|
||||||
okhsl.lightness = (okhsl.lightness + lightness_adj).max(0.0).min(1.0);
|
okhsl.lightness = (okhsl.lightness + lightness_adj).clamp(0.0, 1.0);
|
||||||
|
|
||||||
Self::okhsl_to_rgb(okhsl)
|
Self::okhsl_to_rgb(okhsl)
|
||||||
}
|
}
|
||||||
|
|
@ -338,11 +340,11 @@ fn cosmic_light() -> Colors {
|
||||||
pub fn terminal_themes() -> HashMap<(String, ColorSchemeKind), Colors> {
|
pub fn terminal_themes() -> HashMap<(String, ColorSchemeKind), Colors> {
|
||||||
let mut themes = HashMap::new();
|
let mut themes = HashMap::new();
|
||||||
themes.insert(
|
themes.insert(
|
||||||
("COSMIC Dark".to_string(), ColorSchemeKind::Dark),
|
(COSMIC_THEME_DARK.to_string(), ColorSchemeKind::Dark),
|
||||||
cosmic_dark(),
|
cosmic_dark(),
|
||||||
);
|
);
|
||||||
themes.insert(
|
themes.insert(
|
||||||
("COSMIC Light".to_string(), ColorSchemeKind::Light),
|
(COSMIC_THEME_LIGHT.to_string(), ColorSchemeKind::Light),
|
||||||
cosmic_light(),
|
cosmic_light(),
|
||||||
);
|
);
|
||||||
themes
|
themes
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue