Compare commits
15 commits
5af952d285
...
e87a7f214a
| Author | SHA1 | Date | |
|---|---|---|---|
| e87a7f214a | |||
| f93673c6f4 | |||
| 821f54693e | |||
|
|
7a8ee76e8f | ||
|
|
3a60da0213 | ||
|
|
fe2b6ca484 | ||
|
|
a301e64503 | ||
|
|
a3132220e2 | ||
|
|
b6cc5d0e37 | ||
| 8db4948de3 | |||
| 437665dd78 | |||
| 87128d72d6 | |||
| 4d05e77e1b | |||
| 65fc96eab8 | |||
| 6b5a7ee8c8 |
22 changed files with 541 additions and 659 deletions
719
Cargo.lock
generated
719
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "cosmic-term"
|
name = "cosmic-term"
|
||||||
version = "1.2.0"
|
version = "1.0.14"
|
||||||
authors = ["Jeremy Soller <jeremy@system76.com>"]
|
authors = ["Jeremy Soller <jeremy@system76.com>"]
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
license = "GPL-3.0-only"
|
license = "GPL-3.0-only"
|
||||||
|
|
|
||||||
24
debian/changelog
vendored
24
debian/changelog
vendored
|
|
@ -1,27 +1,3 @@
|
||||||
cosmic-term (1.2.0) noble; urgency=medium
|
|
||||||
|
|
||||||
* Epoch 1.2.0 version update
|
|
||||||
|
|
||||||
-- Jeremy Soller <jeremy@system76.com> Tue, 30 Jun 2026 12:21:56 -0600
|
|
||||||
|
|
||||||
cosmic-term (1.1.0) noble; urgency=medium
|
|
||||||
|
|
||||||
* Epoch 1.1.0 version update
|
|
||||||
|
|
||||||
-- Jeremy Soller <jeremy@system76.com> Tue, 23 Jun 2026 08:49:37 -0600
|
|
||||||
|
|
||||||
cosmic-term (1.0.16) noble; urgency=medium
|
|
||||||
|
|
||||||
* Epoch 1.0.16 version update
|
|
||||||
|
|
||||||
-- Jeremy Soller <jeremy@system76.com> Tue, 09 Jun 2026 10:26:45 -0600
|
|
||||||
|
|
||||||
cosmic-term (1.0.15) noble; urgency=medium
|
|
||||||
|
|
||||||
* Epoch 1.0.15 version update
|
|
||||||
|
|
||||||
-- Jeremy Soller <jeremy@system76.com> Tue, 02 Jun 2026 11:03:25 -0600
|
|
||||||
|
|
||||||
cosmic-term (1.0.14) noble; urgency=medium
|
cosmic-term (1.0.14) noble; urgency=medium
|
||||||
|
|
||||||
* Epoch 1.0.14 version update
|
* Epoch 1.0.14 version update
|
||||||
|
|
|
||||||
|
|
@ -145,5 +145,5 @@ tab-activate = نشّط لسان { $number }
|
||||||
toggle-fullscreen = بدّل ملء الشاشة
|
toggle-fullscreen = بدّل ملء الشاشة
|
||||||
type-to-search = اكتب للبحث...
|
type-to-search = اكتب للبحث...
|
||||||
copy-link = انسخ الرابط
|
copy-link = انسخ الرابط
|
||||||
tab-new-inherit-working-directory = الألسنة الجديدة والنوافذ تستخدم المجلد الحالي
|
tab-new-inherit-working-directory = الألسنة الجديدة تستخدم المجلد الحالي
|
||||||
tab-new-inherit-working-directory-description = افتح الألسنة الجديدة والنوافذ في مجلد العمل الخاص باللسان النشط
|
tab-new-inherit-working-directory-description = افتح ألسنة جديدة في مجلد العمل الخاص باللسان النشط
|
||||||
|
|
|
||||||
|
|
@ -107,5 +107,5 @@ shortcut-replace-body = { $binding } je již přiřazena k „{ $existing }“.
|
||||||
shortcut-capture-hint = Stiskněte kombinaci kláves
|
shortcut-capture-hint = Stiskněte kombinaci kláves
|
||||||
paste-primary = Vložit primární
|
paste-primary = Vložit primární
|
||||||
copy-link = Kopírovat odkaz
|
copy-link = Kopírovat odkaz
|
||||||
tab-new-inherit-working-directory = Nové karty a okna používají aktuální adresář
|
tab-new-inherit-working-directory = Nové karty používají aktuální adresář
|
||||||
tab-new-inherit-working-directory-description = Otevírat nové karty a okna v pracovním adresáři aktivní karty
|
tab-new-inherit-working-directory-description = Otevírat nové karty v pracovním adresáři aktivní karty
|
||||||
|
|
|
||||||
|
|
@ -147,5 +147,5 @@ paste-primary = Primär einfügen
|
||||||
add-another-keybinding = Weitere Tastenbelegung hinzufügen
|
add-another-keybinding = Weitere Tastenbelegung hinzufügen
|
||||||
shortcut-replace-body = { $binding } ist bereits { $existing } zugeordnet. Durch { $new_action } ersetzen?
|
shortcut-replace-body = { $binding } ist bereits { $existing } zugeordnet. Durch { $new_action } ersetzen?
|
||||||
keywords = Befehl;Shell;Terminal;CLI;
|
keywords = Befehl;Shell;Terminal;CLI;
|
||||||
tab-new-inherit-working-directory = Neue Tabs und Fenster verwenden das aktuelle Verzeichnis
|
tab-new-inherit-working-directory = Neue Tabs verwenden das aktuelle Verzeichnis
|
||||||
tab-new-inherit-working-directory-description = Neue Tabs und Fenster im Arbeitsverzeichnis des aktiven Tabs öffnen
|
tab-new-inherit-working-directory-description = Neue Tabs im Arbeitsverzeichnis des aktiven Tabs öffnen
|
||||||
|
|
|
||||||
|
|
@ -150,5 +150,5 @@ paste-primary = Πρωτεύουσα επικόλληση
|
||||||
shortcut-group-other = Άλλες
|
shortcut-group-other = Άλλες
|
||||||
shortcut-group-zoom = Ζουμ
|
shortcut-group-zoom = Ζουμ
|
||||||
shortcut-replace-body = Ο συνδυασμός { $binding } έχει ήδη αντιστοιχιστεί στην ενέργεια «{ $existing }». Θέλετε να αντικατασταθεί με την ενέργεια «{ $new_action }»;
|
shortcut-replace-body = Ο συνδυασμός { $binding } έχει ήδη αντιστοιχιστεί στην ενέργεια «{ $existing }». Θέλετε να αντικατασταθεί με την ενέργεια «{ $new_action }»;
|
||||||
tab-new-inherit-working-directory = Οι νέες καρτέλες και παράθυρα χρησιμοποιούν τον τρέχοντα κατάλογο
|
tab-new-inherit-working-directory = Οι νέες καρτέλες χρησιμοποιούν τον τρέχοντα κατάλογο
|
||||||
tab-new-inherit-working-directory-description = Άνοιγμα νέων καρτελών και παραθύρων στον τρέχοντα κατάλογο της ενεργής καρτέλας
|
tab-new-inherit-working-directory-description = Άνοιγμα νέων καρτελών στον τρέχοντα κατάλογο της ενεργής καρτέλας
|
||||||
|
|
|
||||||
|
|
@ -152,5 +152,5 @@ tab-name-placeholder = Nom de l'onglet
|
||||||
tab-rename-title = Renommer l'onglet
|
tab-rename-title = Renommer l'onglet
|
||||||
comment = Émulateur de terminal pour le bureau COSMIC
|
comment = Émulateur de terminal pour le bureau COSMIC
|
||||||
keywords = Commande;Shell;Terminal;CLI;
|
keywords = Commande;Shell;Terminal;CLI;
|
||||||
tab-new-inherit-working-directory = Les nouveaux onglets et fenêtres utilisent le répertoire actuel
|
tab-new-inherit-working-directory = Les nouveaux onglets utilisent le répertoire actuel
|
||||||
tab-new-inherit-working-directory-description = Ouvrir les nouveaux onglets et fenêtres dans le répertoire de travail de l'onglet actif
|
tab-new-inherit-working-directory-description = Ouvrir les nouveaux onglets dans le répertoire de travail de l'onglet actif
|
||||||
|
|
|
||||||
|
|
@ -147,5 +147,5 @@ tab-activate = { $number }. lap aktiválása
|
||||||
toggle-fullscreen = Teljes képernyő váltása
|
toggle-fullscreen = Teljes képernyő váltása
|
||||||
type-to-search = Gépelj a kereséshez…
|
type-to-search = Gépelj a kereséshez…
|
||||||
copy-link = Hivatkozás másolása
|
copy-link = Hivatkozás másolása
|
||||||
tab-new-inherit-working-directory = Az új lapok és ablakok az aktuális könyvtárat használják
|
tab-new-inherit-working-directory = Az új lapok az aktuális könyvtárat használják
|
||||||
tab-new-inherit-working-directory-description = Az új lapok és ablakok az aktív lap munkakönyvtárában nyílnak meg
|
tab-new-inherit-working-directory-description = Az új lapok az aktív lap munkakönyvtárában nyílnak meg
|
||||||
|
|
|
||||||
|
|
@ -107,5 +107,5 @@ focus-pane-up = Fokuskan panel ke atas
|
||||||
comment = Emulator terminal untuk desktop COSMIC
|
comment = Emulator terminal untuk desktop COSMIC
|
||||||
keywords = Perintah;Shell;Terminal;CLI;
|
keywords = Perintah;Shell;Terminal;CLI;
|
||||||
copy-link = Salin Tautan
|
copy-link = Salin Tautan
|
||||||
tab-new-inherit-working-directory = Tab dan jendela baru menggunakan direktori saat ini
|
tab-new-inherit-working-directory = Tab baru menggunakan direktori saat ini
|
||||||
tab-new-inherit-working-directory-description = Buka tab dan jendela baru di direktori pekerjaan tab aktif
|
tab-new-inherit-working-directory-description = Buka tab baru di direktori pekerjaan tab aktif
|
||||||
|
|
|
||||||
|
|
@ -1,111 +0,0 @@
|
||||||
rename = Navê biguhêrîne
|
|
||||||
cancel = Têk bibe
|
|
||||||
name = Nav
|
|
||||||
delete = Jê bibe
|
|
||||||
add-profile = Profîlê tevlî bike
|
|
||||||
find-next = Yê pêş bibîne
|
|
||||||
splits = Beşkirin
|
|
||||||
import-errors = Şaşetiyan têxîne
|
|
||||||
select-all = Hemûyan hilbijêre
|
|
||||||
new-window = Çarçoveya nû
|
|
||||||
menu-profiles = Profîl...
|
|
||||||
new-terminal = Termînala nû
|
|
||||||
tab-title-description = Sernavê rûgerê yê berdest biguhêrîne
|
|
||||||
remain-open = Piştî derketina pêvajoyê vekirî bimîne.
|
|
||||||
working-directory = Rêgeha xebatê
|
|
||||||
import = Têxîne
|
|
||||||
profiles = Profîl
|
|
||||||
tab-title = Sernavê rûgerê
|
|
||||||
quit = Biqedîne
|
|
||||||
edit = Biguhêrîne
|
|
||||||
copy = Jê bigire
|
|
||||||
export = Derxîne
|
|
||||||
theme = Rûkar
|
|
||||||
appearance = Xuyang
|
|
||||||
close-tab = Rûgerê bigire
|
|
||||||
light = Ronî
|
|
||||||
advanced = Pêşketî
|
|
||||||
support = Piştgirî
|
|
||||||
default-font = Cûrenivîs
|
|
||||||
paste = Pêve bike
|
|
||||||
menu-settings = Sazkarî...
|
|
||||||
command-line = Rêza fermanê
|
|
||||||
view = Dîtin
|
|
||||||
dark = Tarî
|
|
||||||
hold = Ragire
|
|
||||||
match-desktop = Li gorî sermaseyê
|
|
||||||
find-previous = Yê paş bibîne
|
|
||||||
cosmic-terminal = Termînalê COSMIC
|
|
||||||
find-placeholder = Bibîne...
|
|
||||||
advanced-font-settings = Sazkariyên pêşketî yên cûrenivîsê
|
|
||||||
settings = Sazkarî
|
|
||||||
font = Cûrenivîs
|
|
||||||
default-zoom-step = Gavên nêzîkbûnê
|
|
||||||
clear-scrollback = Dîroka şemitandinê pak bike
|
|
||||||
open-link = Girêdanê veke
|
|
||||||
file = Pel
|
|
||||||
make-default = Bike berdest
|
|
||||||
new-profile = Profîla nû
|
|
||||||
profile = Profîl
|
|
||||||
new-tab = Rûgera nû
|
|
||||||
comment = Emûlatorê termînalê ji bo sermaseya COSMIC
|
|
||||||
keywords = Ferman;Shell;Termînal;CLI;
|
|
||||||
close-window = Çarçoveyê bigire
|
|
||||||
keyboard-shortcuts = Kurteriyên kilîtdankê
|
|
||||||
menu-keyboard-shortcuts = Kurteriyên kilîtdankê...
|
|
||||||
no-shortcuts = Kurterê tune ne
|
|
||||||
shortcut-group-clipboard = Jêgirtdank
|
|
||||||
shortcut-group-other = Ên din
|
|
||||||
shortcut-group-tabs = Rûger
|
|
||||||
shortcut-group-window = Çarçove
|
|
||||||
shortcut-group-zoom = Nêzîkbûn
|
|
||||||
repository = Embar
|
|
||||||
find = Bibîne
|
|
||||||
replace = Biguhêrîne
|
|
||||||
syntax-light = Şêwaza rengê ronî
|
|
||||||
default-font-weight = Giraniya cûrenivîsê ya normal
|
|
||||||
zoom-in = Nivîsa mezintir
|
|
||||||
previous-tab = Rûgera paş
|
|
||||||
show-headerbar = Sernavê nîşan bide
|
|
||||||
zoom-out = Nivîsa biçûktir
|
|
||||||
split-vertical = Stûnî dabeş bike
|
|
||||||
syntax-dark = Şêwaza rengê tarî
|
|
||||||
menu-about = Derbarê termînala COSMIC...
|
|
||||||
menu-color-schemes = Şêwazên rengê...
|
|
||||||
opacity = Zelaliya paşrûyê
|
|
||||||
zoom-reset = Mezinahiya nivîsê ya berdest
|
|
||||||
passwords-title = Borînpeyv
|
|
||||||
pane-toggle-maximize = Mezinkirinê biguhêrîne
|
|
||||||
password-input = Borînpeyv
|
|
||||||
color-schemes = Şêwazên rengê
|
|
||||||
default-dim-font-weight = Giraniya cûrenivîsê ya sivik
|
|
||||||
use-bright-bold = Nivîsa qalind ronîtir bike
|
|
||||||
default-bold-font-weight = Giraniya cûrenivîsê ya qalind
|
|
||||||
password-input-description = Danasîn
|
|
||||||
add-password = Borînpeyvê tevlî bike
|
|
||||||
default-font-stretch = Dirêjahiya cûrenivîsê
|
|
||||||
menu-password-manager = Borînpeyv...
|
|
||||||
default-font-size = Mezinahiya cûrenivîsê
|
|
||||||
split-horizontal = Asoyî dabeş bike
|
|
||||||
focus-follow-mouse = Balkişandinê nivîsê mişkê dişopîne
|
|
||||||
next-tab = Rûgera pêş
|
|
||||||
show-header-description = Sernavê ji menuya rast-tikandin nîşan bide
|
|
||||||
tab-new-inherit-working-directory = Rûger û çarçoveyên nû peldanka heyî bi kar bîne
|
|
||||||
tab-new-inherit-working-directory-description = Rûger û çarçoveyên nû di peldanka xebatê ya çalak de veke
|
|
||||||
add-another-keybinding = Kurteriyeke din tevlî bike
|
|
||||||
copy-or-sigint = Jê bigire yan jî SIGINT
|
|
||||||
disable = Neçalak bike
|
|
||||||
focus-pane-down = Balê bikişîne ser destgeha jêrîn
|
|
||||||
focus-pane-left = Balê bikişîne ser destgeha çepê
|
|
||||||
focus-pane-right = Balê bikişîne ser destgeha rastê
|
|
||||||
focus-pane-up = Balê bikişîne ser destgeha jorîn
|
|
||||||
password-manager = Rêveberê borînpeyvê
|
|
||||||
paste-primary = A sereke pêve bike
|
|
||||||
reset-to-default = Vegere rewşa berdest
|
|
||||||
shortcut-capture-hint = Kombînasyona kilîtan bitikîne
|
|
||||||
shortcut-replace-body = { $binding } berê ji bo { $existing } hatiye destnîşankirin. Tu dixwazî bi { $new_action } re biguherînî?
|
|
||||||
shortcut-replace-title = Kurterê biguhêrînî?
|
|
||||||
tab-activate = Rûgera { $number } çalak bike
|
|
||||||
toggle-fullscreen = Dîmendera tijî biguhêrîne
|
|
||||||
type-to-search = Ji bo lêgerînê binivîse...
|
|
||||||
copy-link = Girêdanê jê bigire
|
|
||||||
|
|
@ -147,5 +147,5 @@ focus-pane-left = Aktywuj lewy panel
|
||||||
focus-pane-right = Aktywuj prawy panel
|
focus-pane-right = Aktywuj prawy panel
|
||||||
focus-pane-up = Aktywuj panel wyżej
|
focus-pane-up = Aktywuj panel wyżej
|
||||||
copy-link = Skopiuj Odnośnik
|
copy-link = Skopiuj Odnośnik
|
||||||
tab-new-inherit-working-directory = Nowe karty i okna użyją obecnego katalogu
|
tab-new-inherit-working-directory = Nowe karty użyją obecnego katalogu
|
||||||
tab-new-inherit-working-directory-description = Otwieraj nowe karty i okna w katalogu roboczym aktywnej karty
|
tab-new-inherit-working-directory-description = Otwieraj nowe karty w katalogu roboczym aktywnej karty
|
||||||
|
|
|
||||||
|
|
@ -147,5 +147,5 @@ tab-activate = Ativar aba { $number }
|
||||||
toggle-fullscreen = Alternar para tela cheia
|
toggle-fullscreen = Alternar para tela cheia
|
||||||
type-to-search = Digite para pesquisar...
|
type-to-search = Digite para pesquisar...
|
||||||
copy-link = Copiar link
|
copy-link = Copiar link
|
||||||
tab-new-inherit-working-directory = Novas abas e janelas usam o diretório atual
|
tab-new-inherit-working-directory = Novas abas usam o diretório atual
|
||||||
tab-new-inherit-working-directory-description = Abrir novas abas e janelas no diretório de trabalho da aba ativa
|
tab-new-inherit-working-directory-description = Abrir novas abas no diretório de trabalho da aba ativa
|
||||||
|
|
|
||||||
|
|
@ -151,5 +151,5 @@ shortcut-group-other = Andra
|
||||||
shortcut-group-tabs = Flikar
|
shortcut-group-tabs = Flikar
|
||||||
shortcut-group-zoom = Zooma
|
shortcut-group-zoom = Zooma
|
||||||
copy-link = Kopiera länk
|
copy-link = Kopiera länk
|
||||||
tab-new-inherit-working-directory-description = Öppna nya flikar och fönster i den aktiva flikens arbetskatalog
|
tab-new-inherit-working-directory-description = Öppna nya flikar i den aktiva flikens arbetskatalog
|
||||||
tab-new-inherit-working-directory = Nya flikar och fönster använder aktuell katalog
|
tab-new-inherit-working-directory = Nya flikar använder aktuell katalog
|
||||||
|
|
|
||||||
|
|
@ -147,5 +147,5 @@ toggle-fullscreen = 切换全屏
|
||||||
comment = COSMIC 桌面的终端模拟器
|
comment = COSMIC 桌面的终端模拟器
|
||||||
keywords = 指令;外壳;终端;命令行界面;
|
keywords = 指令;外壳;终端;命令行界面;
|
||||||
copy-link = 复制链接
|
copy-link = 复制链接
|
||||||
tab-new-inherit-working-directory = 新标签和窗口使用当前目录
|
tab-new-inherit-working-directory = 新标签使用当前目录
|
||||||
tab-new-inherit-working-directory-description = 在活动标签的工作目录中打开新标签和窗口
|
tab-new-inherit-working-directory-description = 在活动标签的工作目录中打开新标签
|
||||||
|
|
|
||||||
|
|
@ -147,5 +147,5 @@ copy-link = 複製連結
|
||||||
shortcut-replace-body = { $binding } 已經分配至 { $existing }。 要取代它為 { $new_action }?
|
shortcut-replace-body = { $binding } 已經分配至 { $existing }。 要取代它為 { $new_action }?
|
||||||
clear-scrollback = 清除捲動回朔
|
clear-scrollback = 清除捲動回朔
|
||||||
comment = COSMIC 桌面終端機模擬器
|
comment = COSMIC 桌面終端機模擬器
|
||||||
tab-new-inherit-working-directory = 新分頁和視窗使用目前目錄
|
tab-new-inherit-working-directory = 新分頁使用目前目錄
|
||||||
tab-new-inherit-working-directory-description = 在作用中分頁的工作目錄開啟新分頁和視窗
|
tab-new-inherit-working-directory-description = 在作用中分頁的工作目錄開啟新分頁
|
||||||
|
|
|
||||||
|
|
@ -290,19 +290,13 @@ impl Config {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn color_scheme_kind(&self, system_theme: &theme::Theme) -> ColorSchemeKind {
|
pub fn color_scheme_kind(&self) -> ColorSchemeKind {
|
||||||
match self.app_theme {
|
if self.app_theme.theme().theme_type.is_dark() {
|
||||||
AppTheme::Dark => ColorSchemeKind::Dark,
|
|
||||||
AppTheme::Light => ColorSchemeKind::Light,
|
|
||||||
AppTheme::System => {
|
|
||||||
if system_theme.theme_type.is_dark() {
|
|
||||||
ColorSchemeKind::Dark
|
ColorSchemeKind::Dark
|
||||||
} else {
|
} else {
|
||||||
ColorSchemeKind::Light
|
ColorSchemeKind::Light
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get a sorted and adjusted for duplicates list of color scheme names and ids
|
// Get a sorted and adjusted for duplicates list of color scheme names and ids
|
||||||
pub fn color_scheme_names(
|
pub fn color_scheme_names(
|
||||||
|
|
@ -364,11 +358,8 @@ impl Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get current syntax theme based on dark mode
|
// Get current syntax theme based on dark mode
|
||||||
pub fn syntax_theme(
|
pub fn syntax_theme(&self, profile_id_opt: Option<ProfileId>) -> (String, ColorSchemeKind) {
|
||||||
&self,
|
let color_scheme_kind = self.color_scheme_kind();
|
||||||
color_scheme_kind: ColorSchemeKind,
|
|
||||||
profile_id_opt: Option<ProfileId>,
|
|
||||||
) -> (String, ColorSchemeKind) {
|
|
||||||
let theme_name = match profile_id_opt.and_then(|profile_id| self.profiles.get(&profile_id))
|
let theme_name = match profile_id_opt.and_then(|profile_id| self.profiles.get(&profile_id))
|
||||||
{
|
{
|
||||||
Some(profile) => match color_scheme_kind {
|
Some(profile) => match color_scheme_kind {
|
||||||
|
|
|
||||||
28
src/main.rs
28
src/main.rs
|
|
@ -186,10 +186,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Terminal config setup
|
// Terminal config setup
|
||||||
let term_config = term::Config {
|
let term_config = term::Config::default();
|
||||||
scrolling_history: 100_000,
|
|
||||||
..term::Config::default()
|
|
||||||
};
|
|
||||||
// Set up environmental variables for terminal
|
// Set up environmental variables for terminal
|
||||||
tty::setup_env();
|
tty::setup_env();
|
||||||
// Override TERM for better compatibility
|
// Override TERM for better compatibility
|
||||||
|
|
@ -698,12 +695,11 @@ impl App {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set config of all tabs
|
// Set config of all tabs
|
||||||
let color_scheme_kind = self.config.color_scheme_kind(&theme);
|
|
||||||
for (_pane, tab_model) in self.pane_model.panes.iter() {
|
for (_pane, tab_model) in self.pane_model.panes.iter() {
|
||||||
for entity in tab_model.iter() {
|
for entity in tab_model.iter() {
|
||||||
if let Some(terminal) = tab_model.data::<Mutex<Terminal>>(entity) {
|
if let Some(terminal) = tab_model.data::<Mutex<Terminal>>(entity) {
|
||||||
let mut terminal = terminal.lock().unwrap();
|
let mut terminal = terminal.lock().unwrap();
|
||||||
terminal.set_config(&self.config, color_scheme_kind, &self.themes);
|
terminal.set_config(&self.config, &self.themes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -719,7 +715,6 @@ impl App {
|
||||||
// skip writing config to fs when zoom in/ out
|
// skip writing config to fs when zoom in/ out
|
||||||
// recalculate the pane due to the changes of zoom_adj value
|
// recalculate the pane due to the changes of zoom_adj value
|
||||||
// but only for the active pane/tab
|
// but only for the active pane/tab
|
||||||
let color_scheme_kind = self.config.color_scheme_kind(self.core.system_theme());
|
|
||||||
if let Some(tab_model) = self.pane_model.active() {
|
if let Some(tab_model) = self.pane_model.active() {
|
||||||
for entity in tab_model.iter() {
|
for entity in tab_model.iter() {
|
||||||
if tab_model.is_active(entity)
|
if tab_model.is_active(entity)
|
||||||
|
|
@ -736,7 +731,7 @@ impl App {
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
terminal.set_config(&self.config, color_scheme_kind, &self.themes);
|
terminal.set_config(&self.config, &self.themes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1566,11 +1561,10 @@ impl App {
|
||||||
self.pane_model.set_focus(pane);
|
self.pane_model.set_focus(pane);
|
||||||
match &self.term_event_tx_opt {
|
match &self.term_event_tx_opt {
|
||||||
Some(term_event_tx) => {
|
Some(term_event_tx) => {
|
||||||
let color_scheme_kind = self.config.color_scheme_kind(self.core.system_theme());
|
|
||||||
let colors = self
|
let colors = self
|
||||||
.themes
|
.themes
|
||||||
.get(&self.config.syntax_theme(color_scheme_kind, profile_id_opt))
|
.get(&self.config.syntax_theme(profile_id_opt))
|
||||||
.or_else(|| match color_scheme_kind {
|
.or_else(|| match self.config.color_scheme_kind() {
|
||||||
ColorSchemeKind::Dark => self
|
ColorSchemeKind::Dark => self
|
||||||
.themes
|
.themes
|
||||||
.get(&(config::COSMIC_THEME_DARK.to_string(), ColorSchemeKind::Dark)),
|
.get(&(config::COSMIC_THEME_DARK.to_string(), ColorSchemeKind::Dark)),
|
||||||
|
|
@ -1647,11 +1641,7 @@ impl App {
|
||||||
tab_title_override,
|
tab_title_override,
|
||||||
) {
|
) {
|
||||||
Ok(mut terminal) => {
|
Ok(mut terminal) => {
|
||||||
terminal.set_config(
|
terminal.set_config(&self.config, &self.themes);
|
||||||
&self.config,
|
|
||||||
color_scheme_kind,
|
|
||||||
&self.themes,
|
|
||||||
);
|
|
||||||
tab_model
|
tab_model
|
||||||
.data_set::<Mutex<Terminal>>(entity, Mutex::new(terminal));
|
.data_set::<Mutex<Terminal>>(entity, Mutex::new(terminal));
|
||||||
}
|
}
|
||||||
|
|
@ -1690,7 +1680,7 @@ impl App {
|
||||||
None => {
|
None => {
|
||||||
log::error!(
|
log::error!(
|
||||||
"failed to find terminal theme {:?}",
|
"failed to find terminal theme {:?}",
|
||||||
self.config.syntax_theme(color_scheme_kind, profile_id_opt)
|
self.config.syntax_theme(profile_id_opt)
|
||||||
);
|
);
|
||||||
//TODO: fall back to known good theme
|
//TODO: fall back to known good theme
|
||||||
}
|
}
|
||||||
|
|
@ -2485,7 +2475,7 @@ impl Application for App {
|
||||||
|
|
||||||
// Handle configurable keys
|
// Handle configurable keys
|
||||||
for (key_bind, action) in &self.key_binds {
|
for (key_bind, action) in &self.key_binds {
|
||||||
if key_bind.matches(modifiers, &key, Some(&physical)) {
|
if key_bind.matches(modifiers, &key, None) {
|
||||||
return self.update(action.message(None));
|
return self.update(action.message(None));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3140,7 +3130,7 @@ impl Application for App {
|
||||||
&& let Some(terminal) = tab_model.data::<Mutex<Terminal>>(entity)
|
&& let Some(terminal) = tab_model.data::<Mutex<Terminal>>(entity)
|
||||||
{
|
{
|
||||||
let terminal = terminal.lock().unwrap();
|
let terminal = terminal.lock().unwrap();
|
||||||
let rgb = terminal.effective_color(index);
|
let rgb = terminal.colors()[index].unwrap_or_default();
|
||||||
let text = f(rgb);
|
let text = f(rgb);
|
||||||
terminal.input_no_scroll(text.into_bytes());
|
terminal.input_no_scroll(text.into_bytes());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -208,8 +208,6 @@ pub fn menu_bar<'a>(
|
||||||
|
|
||||||
//TODO: what to do if there are no profiles?
|
//TODO: what to do if there are no profiles?
|
||||||
|
|
||||||
let color_scheme_kind = config.color_scheme_kind(core.system_theme());
|
|
||||||
|
|
||||||
responsive_menu_bar()
|
responsive_menu_bar()
|
||||||
.item_height(ItemHeight::Dynamic(40))
|
.item_height(ItemHeight::Dynamic(40))
|
||||||
.item_width(ItemWidth::Uniform(320))
|
.item_width(ItemWidth::Uniform(320))
|
||||||
|
|
@ -272,7 +270,7 @@ pub fn menu_bar<'a>(
|
||||||
MenuItem::Button(
|
MenuItem::Button(
|
||||||
fl!("menu-color-schemes"),
|
fl!("menu-color-schemes"),
|
||||||
None,
|
None,
|
||||||
Action::ColorSchemes(color_scheme_kind),
|
Action::ColorSchemes(config.color_scheme_kind()),
|
||||||
),
|
),
|
||||||
MenuItem::Button(
|
MenuItem::Button(
|
||||||
fl!("menu-keyboard-shortcuts"),
|
fl!("menu-keyboard-shortcuts"),
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,10 @@ use cosmic::{
|
||||||
iced::{Event, keyboard::Modifiers, mouse::Button},
|
iced::{Event, keyboard::Modifiers, mouse::Button},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::terminal::Terminal;
|
||||||
|
|
||||||
|
const SCROLL_SPEED: u32 = 3;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct MouseReporter {
|
pub struct MouseReporter {
|
||||||
last_movment_x: Option<u32>,
|
last_movment_x: Option<u32>,
|
||||||
|
|
@ -13,30 +17,6 @@ pub struct MouseReporter {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MouseReporter {
|
impl MouseReporter {
|
||||||
pub fn accumulate_scroll(
|
|
||||||
&mut self,
|
|
||||||
delta: ScrollDelta,
|
|
||||||
cell_width: f32,
|
|
||||||
cell_height: f32,
|
|
||||||
) -> (i32, i32) {
|
|
||||||
match delta {
|
|
||||||
ScrollDelta::Lines { x, y } => {
|
|
||||||
self.accumulated_scroll_x += x;
|
|
||||||
self.accumulated_scroll_y += y;
|
|
||||||
}
|
|
||||||
ScrollDelta::Pixels { x, y } => {
|
|
||||||
self.accumulated_scroll_x += x / cell_width;
|
|
||||||
self.accumulated_scroll_y += y / cell_height;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let lines_x = self.accumulated_scroll_x as i32;
|
|
||||||
let lines_y = self.accumulated_scroll_y as i32;
|
|
||||||
self.accumulated_scroll_x -= lines_x as f32;
|
|
||||||
self.accumulated_scroll_y -= lines_y as f32;
|
|
||||||
(lines_x, lines_y)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn button_number(button: Button) -> Option<u8> {
|
fn button_number(button: Button) -> Option<u8> {
|
||||||
match button {
|
match button {
|
||||||
Button::Left => Some(0),
|
Button::Left => Some(0),
|
||||||
|
|
@ -198,7 +178,24 @@ impl MouseReporter {
|
||||||
x: u32,
|
x: u32,
|
||||||
y: u32,
|
y: u32,
|
||||||
) -> impl Iterator<Item = Vec<u8>> {
|
) -> impl Iterator<Item = Vec<u8>> {
|
||||||
let (lines_x, lines_y) = self.accumulate_scroll(delta, term_cell_width, term_cell_height);
|
let (lines_x, lines_y) = match delta {
|
||||||
|
ScrollDelta::Lines { x, y } => (x as i32, y as i32),
|
||||||
|
ScrollDelta::Pixels { x, y } => {
|
||||||
|
//Accumulate change
|
||||||
|
self.accumulated_scroll_x += x / term_cell_width;
|
||||||
|
self.accumulated_scroll_y += y / term_cell_height;
|
||||||
|
|
||||||
|
//Resolve lines crossed
|
||||||
|
let lines_x = self.accumulated_scroll_x as i32;
|
||||||
|
let lines_y = self.accumulated_scroll_y as i32;
|
||||||
|
|
||||||
|
//Subtract accounted lines from accumulators
|
||||||
|
self.accumulated_scroll_x -= lines_x as f32;
|
||||||
|
self.accumulated_scroll_y -= lines_y as f32;
|
||||||
|
|
||||||
|
(lines_x, lines_y)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
//Resolve modifier flags
|
//Resolve modifier flags
|
||||||
let mut modifier_flags = 0;
|
let mut modifier_flags = 0;
|
||||||
|
|
@ -238,4 +235,26 @@ impl MouseReporter {
|
||||||
term_code.as_bytes().to_vec()
|
term_code.as_bytes().to_vec()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//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.
|
||||||
|
pub fn report_mouse_wheel_as_arrows(
|
||||||
|
terminal: &Terminal,
|
||||||
|
term_cell_width: f32,
|
||||||
|
term_cell_height: f32,
|
||||||
|
delta: ScrollDelta,
|
||||||
|
) {
|
||||||
|
let (_delta_x, delta_y) = match delta {
|
||||||
|
ScrollDelta::Lines { x, y } => (x, y),
|
||||||
|
ScrollDelta::Pixels { x, y } => (x / term_cell_width, y / term_cell_height),
|
||||||
|
};
|
||||||
|
//Send delta_y * SCROLL_SPEED number of Up/Down arrows
|
||||||
|
for _ in 0..(delta_y.abs() as u32 * SCROLL_SPEED) {
|
||||||
|
if delta_y > 0.0 {
|
||||||
|
terminal.input_no_scroll(b"\x1B[A".as_slice())
|
||||||
|
} else if delta_y < 0.0 {
|
||||||
|
terminal.input_no_scroll(b"\x1B[B".as_slice())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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, LineEnding, Shaping, Weight, Wrap,
|
Attrs, AttrsList, Buffer, BufferLine, CacheKeyFlags, Family, LineEnding, Metrics, Shaping,
|
||||||
|
Weight, Wrap,
|
||||||
};
|
};
|
||||||
use indexmap::IndexSet;
|
use indexmap::IndexSet;
|
||||||
use std::{
|
use std::{
|
||||||
|
|
@ -190,7 +191,7 @@ impl TerminalPaneGrid {
|
||||||
let entity = tab_model.active();
|
let entity = tab_model.active();
|
||||||
if let Some(terminal) = tab_model.data::<Mutex<Terminal>>(entity) {
|
if let Some(terminal) = tab_model.data::<Mutex<Terminal>>(entity) {
|
||||||
let mut terminal = terminal.lock().unwrap();
|
let mut terminal = terminal.lock().unwrap();
|
||||||
terminal.set_focused(self.focus == *pane);
|
terminal.is_focused = self.focus == *pane;
|
||||||
terminal.update();
|
terminal.update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -200,7 +201,7 @@ impl TerminalPaneGrid {
|
||||||
for entity in tab_model.iter() {
|
for entity in tab_model.iter() {
|
||||||
if let Some(terminal) = tab_model.data::<Mutex<Terminal>>(entity) {
|
if let Some(terminal) = tab_model.data::<Mutex<Terminal>>(entity) {
|
||||||
let mut terminal = terminal.lock().unwrap();
|
let mut terminal = terminal.lock().unwrap();
|
||||||
terminal.set_focused(false);
|
terminal.is_focused = false;
|
||||||
terminal.update();
|
terminal.update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -284,7 +285,7 @@ impl Terminal {
|
||||||
let bold_font_weight = app_config.bold_font_weight;
|
let bold_font_weight = app_config.bold_font_weight;
|
||||||
let use_bright_bold = app_config.use_bright_bold;
|
let use_bright_bold = app_config.use_bright_bold;
|
||||||
|
|
||||||
let metrics = app_config.metrics(0);
|
let metrics = Metrics::new(14.0, 21.0);
|
||||||
|
|
||||||
let default_bg = convert_color(&colors, Color::Named(NamedColor::Background));
|
let default_bg = convert_color(&colors, Color::Named(NamedColor::Background));
|
||||||
let default_fg = convert_color(&colors, Color::Named(NamedColor::Foreground));
|
let default_fg = convert_color(&colors, Color::Named(NamedColor::Foreground));
|
||||||
|
|
@ -387,19 +388,6 @@ impl Terminal {
|
||||||
&self.colors
|
&self.colors
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn effective_color(&self, index: usize) -> Rgb {
|
|
||||||
if index == NamedColor::Background as usize {
|
|
||||||
self.colors[index].unwrap_or_else(|| {
|
|
||||||
// Allow using an unset background
|
|
||||||
let [r, g, b, _] =
|
|
||||||
cosmic_text::Color(WINDOW_BG_COLOR.load(Ordering::SeqCst)).as_rgba();
|
|
||||||
Rgb { r, g, b }
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
self.colors[index].unwrap_or_default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn default_attrs(&self) -> &Attrs<'static> {
|
pub fn default_attrs(&self) -> &Attrs<'static> {
|
||||||
&self.default_attrs
|
&self.default_attrs
|
||||||
}
|
}
|
||||||
|
|
@ -416,22 +404,6 @@ impl Terminal {
|
||||||
self.zoom_adj = value;
|
self.zoom_adj = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_focused(&mut self, is_focused: bool) {
|
|
||||||
let focus_changed = self.is_focused != is_focused;
|
|
||||||
self.is_focused = is_focused;
|
|
||||||
|
|
||||||
if focus_changed {
|
|
||||||
let report_focus = self.term.lock().mode().contains(TermMode::FOCUS_IN_OUT);
|
|
||||||
if report_focus {
|
|
||||||
const FOCUS_IN: &[u8] = b"\x1b[I";
|
|
||||||
const FOCUS_OUT: &[u8] = b"\x1b[O";
|
|
||||||
|
|
||||||
let input = if is_focused { FOCUS_IN } else { FOCUS_OUT };
|
|
||||||
self.input_no_scroll(input);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn redraw(&self) -> bool {
|
pub fn redraw(&self) -> bool {
|
||||||
self.buffer.redraw()
|
self.buffer.redraw()
|
||||||
}
|
}
|
||||||
|
|
@ -643,7 +615,6 @@ impl Terminal {
|
||||||
pub fn set_config(
|
pub fn set_config(
|
||||||
&mut self,
|
&mut self,
|
||||||
config: &AppConfig,
|
config: &AppConfig,
|
||||||
color_scheme_kind: ColorSchemeKind,
|
|
||||||
themes: &HashMap<(String, ColorSchemeKind), Colors>,
|
themes: &HashMap<(String, ColorSchemeKind), Colors>,
|
||||||
) {
|
) {
|
||||||
let mut update_cell_size = false;
|
let mut update_cell_size = false;
|
||||||
|
|
@ -670,7 +641,7 @@ impl Terminal {
|
||||||
update_cell_size = true;
|
update_cell_size = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.bold_font_weight.0 != config.bold_font_weight {
|
if self.bold_font_weight.0 != config.font_weight {
|
||||||
self.bold_font_weight = Weight(config.bold_font_weight);
|
self.bold_font_weight = Weight(config.bold_font_weight);
|
||||||
update_cell_size = true;
|
update_cell_size = true;
|
||||||
}
|
}
|
||||||
|
|
@ -686,9 +657,7 @@ impl Terminal {
|
||||||
update_cell_size = true;
|
update_cell_size = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(colors) =
|
if let Some(colors) = themes.get(&config.syntax_theme(self.profile_id_opt)) {
|
||||||
themes.get(&config.syntax_theme(color_scheme_kind, self.profile_id_opt))
|
|
||||||
{
|
|
||||||
let mut changed = false;
|
let mut changed = false;
|
||||||
for i in 0..color::COUNT {
|
for i in 0..color::COUNT {
|
||||||
if self.colors[i] != colors[i] {
|
if self.colors[i] != colors[i] {
|
||||||
|
|
@ -1057,9 +1026,10 @@ impl Terminal {
|
||||||
x: u32,
|
x: u32,
|
||||||
y: u32,
|
y: u32,
|
||||||
) {
|
) {
|
||||||
let is_sgr = self.term.lock().mode().contains(TermMode::SGR_MOUSE);
|
let term_lock = self.term.lock();
|
||||||
|
let mode = term_lock.mode();
|
||||||
|
|
||||||
if is_sgr {
|
if mode.contains(TermMode::SGR_MOUSE) {
|
||||||
let codes = self.mouse_reporter.sgr_mouse_wheel_scroll(
|
let codes = self.mouse_reporter.sgr_mouse_wheel_scroll(
|
||||||
self.size().cell_width,
|
self.size().cell_width,
|
||||||
self.size().cell_height,
|
self.size().cell_height,
|
||||||
|
|
@ -1073,29 +1043,12 @@ impl Terminal {
|
||||||
self.notifier.notify(code);
|
self.notifier.notify(code);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.scroll_as_arrows(delta);
|
MouseReporter::report_mouse_wheel_as_arrows(
|
||||||
}
|
self,
|
||||||
}
|
self.size().cell_width,
|
||||||
|
self.size().cell_height,
|
||||||
pub fn scroll_as_arrows(&mut self, delta: ScrollDelta) {
|
delta,
|
||||||
let cell_width = self.size().cell_width;
|
);
|
||||||
let cell_height = self.size().cell_height;
|
|
||||||
let (_, lines_y) = self
|
|
||||||
.mouse_reporter
|
|
||||||
.accumulate_scroll(delta, cell_width, cell_height);
|
|
||||||
let is_app_cursor = self.term.lock().mode().contains(TermMode::APP_CURSOR);
|
|
||||||
let (up, down) = if is_app_cursor {
|
|
||||||
(&b"\x1BOA"[..], &b"\x1BOB"[..])
|
|
||||||
} else {
|
|
||||||
(&b"\x1B[A"[..], &b"\x1B[B"[..])
|
|
||||||
};
|
|
||||||
const SCROLL_SPEED: u32 = 3;
|
|
||||||
for _ in 0..(lines_y.unsigned_abs() * SCROLL_SPEED) {
|
|
||||||
if lines_y > 0 {
|
|
||||||
self.input_no_scroll(up)
|
|
||||||
} else if lines_y < 0 {
|
|
||||||
self.input_no_scroll(down)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,10 @@ use std::{
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{Action, Terminal, TerminalScroll, menu::MenuState, terminal::Metadata};
|
use crate::{
|
||||||
|
Action, Terminal, TerminalScroll, menu::MenuState, mouse_reporter::MouseReporter,
|
||||||
|
terminal::Metadata,
|
||||||
|
};
|
||||||
|
|
||||||
const AUTOSCROLL_INTERVAL: Duration = Duration::from_millis(100);
|
const AUTOSCROLL_INTERVAL: Duration = Duration::from_millis(100);
|
||||||
|
|
||||||
|
|
@ -940,7 +943,7 @@ where
|
||||||
..
|
..
|
||||||
}) if state.is_focused && named == modified_named => {
|
}) if state.is_focused && named == modified_named => {
|
||||||
for key_bind in self.key_binds.keys() {
|
for key_bind in self.key_binds.keys() {
|
||||||
if key_bind.matches(*modifiers, &Key::Named(*named), Some(physical_key)) {
|
if key_bind.matches(*modifiers, &Key::Named(*named), None) {
|
||||||
shell.capture_event();
|
shell.capture_event();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -1127,11 +1130,10 @@ where
|
||||||
modifiers,
|
modifiers,
|
||||||
key,
|
key,
|
||||||
physical_key,
|
physical_key,
|
||||||
modified_key,
|
|
||||||
..
|
..
|
||||||
}) if state.is_focused => {
|
}) if state.is_focused => {
|
||||||
for key_bind in self.key_binds.keys() {
|
for key_bind in self.key_binds.keys() {
|
||||||
if key_bind.matches(*modifiers, key, Some(physical_key)) {
|
if key_bind.matches(*modifiers, key, None) {
|
||||||
shell.capture_event();
|
shell.capture_event();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
@ -1174,10 +1176,11 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(false, true, _, true) => {
|
(false, true, _, true) => {
|
||||||
// Ctrl+Shift+<key>: send 0x1F (C-_) on '_', matching xterm/gnome-terminal.
|
//This is normally Ctrl+Minus, but since that
|
||||||
// Use `modified_key` so this works regardless of which physical key
|
//is taken by zoom, we send that code for
|
||||||
// produces '_' on the user's layout.
|
//Ctrl+Underline instead, like xterm and
|
||||||
if *modified_key == Key::Character("_".into()) {
|
//gnome-terminal
|
||||||
|
if *key == Key::Character("_".into()) {
|
||||||
terminal.input_scroll(b"\x1F".as_slice());
|
terminal.input_scroll(b"\x1F".as_slice());
|
||||||
shell.capture_event();
|
shell.capture_event();
|
||||||
}
|
}
|
||||||
|
|
@ -1548,27 +1551,26 @@ where
|
||||||
let row = y / terminal.size().cell_height;
|
let row = y / terminal.size().cell_height;
|
||||||
terminal.scroll_mouse(*delta, &state.modifiers, col as u32, row as u32);
|
terminal.scroll_mouse(*delta, &state.modifiers, col as u32, row as u32);
|
||||||
} else if terminal.term.lock().mode().contains(TermMode::ALT_SCREEN) {
|
} else if terminal.term.lock().mode().contains(TermMode::ALT_SCREEN) {
|
||||||
terminal.scroll_as_arrows(*delta);
|
MouseReporter::report_mouse_wheel_as_arrows(
|
||||||
|
&terminal,
|
||||||
|
terminal.size().cell_width,
|
||||||
|
terminal.size().cell_height,
|
||||||
|
*delta,
|
||||||
|
);
|
||||||
shell.capture_event();
|
shell.capture_event();
|
||||||
} else {
|
} else {
|
||||||
match delta {
|
match delta {
|
||||||
ScrollDelta::Lines { x: _, y } => {
|
ScrollDelta::Lines { x: _, y } => {
|
||||||
// High-resolution wheels deliver a notch as many
|
//TODO: this adjustment is just a guess!
|
||||||
// fractional deltas; accumulate them so nothing
|
|
||||||
// below one whole line is lost (see
|
|
||||||
// accumulate_wheel_lines).
|
|
||||||
state.scroll_pixels = 0.0;
|
state.scroll_pixels = 0.0;
|
||||||
let (lines, remainder) =
|
let lines = (-y * 6.0) as i32;
|
||||||
accumulate_wheel_lines(*y, state.scroll_lines);
|
|
||||||
state.scroll_lines = remainder;
|
|
||||||
if lines != 0 {
|
if lines != 0 {
|
||||||
terminal.scroll(TerminalScroll::Delta(lines));
|
terminal.scroll(TerminalScroll::Delta(-lines));
|
||||||
}
|
}
|
||||||
shell.capture_event();
|
shell.capture_event();
|
||||||
}
|
}
|
||||||
ScrollDelta::Pixels { x: _, y } => {
|
ScrollDelta::Pixels { x: _, y } => {
|
||||||
//TODO: this adjustment is just a guess!
|
//TODO: this adjustment is just a guess!
|
||||||
state.scroll_lines = 0.0;
|
|
||||||
state.scroll_pixels -= y * 6.0;
|
state.scroll_pixels -= y * 6.0;
|
||||||
let mut lines = 0;
|
let mut lines = 0;
|
||||||
let metrics = terminal.with_buffer(|buffer| buffer.metrics());
|
let metrics = terminal.with_buffer(|buffer| buffer.metrics());
|
||||||
|
|
@ -1734,26 +1736,6 @@ fn update_active_regex_match(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whole lines scrolled per unit of wheel `Lines` delta.
|
|
||||||
//TODO: this adjustment is just a guess!
|
|
||||||
const SCROLL_LINE_MULTIPLIER: f32 = 6.0;
|
|
||||||
|
|
||||||
/// Convert a wheel `Lines` delta into whole lines to scroll, accumulating the
|
|
||||||
/// fractional remainder across events.
|
|
||||||
///
|
|
||||||
/// High-resolution wheels deliver a single physical notch as many fractional
|
|
||||||
/// deltas (e.g. `y = 0.125`). Scaling by [`SCROLL_LINE_MULTIPLIER`] and
|
|
||||||
/// truncating per event discards anything below one whole line, so most of
|
|
||||||
/// those events would scroll nothing. Carrying the remainder forward means the
|
|
||||||
/// fractions add up and a full notch scrolls the intended amount.
|
|
||||||
///
|
|
||||||
/// Returns `(whole_lines, new_accumulator)`.
|
|
||||||
fn accumulate_wheel_lines(y: f32, accumulator: f32) -> (i32, f32) {
|
|
||||||
let total = accumulator + y * SCROLL_LINE_MULTIPLIER;
|
|
||||||
let lines = total.trunc() as i32;
|
|
||||||
(lines, total - lines as f32)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn shade(color: cosmic_text::Color, is_focused: bool) -> cosmic_text::Color {
|
fn shade(color: cosmic_text::Color, is_focused: bool) -> cosmic_text::Color {
|
||||||
if is_focused {
|
if is_focused {
|
||||||
color
|
color
|
||||||
|
|
@ -1955,7 +1937,6 @@ pub struct State {
|
||||||
dragging: Option<Dragging>,
|
dragging: Option<Dragging>,
|
||||||
is_focused: bool,
|
is_focused: bool,
|
||||||
scroll_pixels: f32,
|
scroll_pixels: f32,
|
||||||
scroll_lines: f32,
|
|
||||||
scrollbar_rect: Cell<Rectangle<f32>>,
|
scrollbar_rect: Cell<Rectangle<f32>>,
|
||||||
autoscroll: DragAutoscroll,
|
autoscroll: DragAutoscroll,
|
||||||
preedit: Option<input_method::Preedit>,
|
preedit: Option<input_method::Preedit>,
|
||||||
|
|
@ -1970,7 +1951,6 @@ impl State {
|
||||||
dragging: None,
|
dragging: None,
|
||||||
is_focused: false,
|
is_focused: false,
|
||||||
scroll_pixels: 0.0,
|
scroll_pixels: 0.0,
|
||||||
scroll_lines: 0.0,
|
|
||||||
scrollbar_rect: Cell::new(Rectangle::default()),
|
scrollbar_rect: Cell::new(Rectangle::default()),
|
||||||
autoscroll: DragAutoscroll::new(AUTOSCROLL_INTERVAL),
|
autoscroll: DragAutoscroll::new(AUTOSCROLL_INTERVAL),
|
||||||
preedit: None,
|
preedit: None,
|
||||||
|
|
@ -2050,38 +2030,7 @@ fn ss3(code: &str, modifiers: u8) -> Option<Vec<u8>> {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{EdgeScrollDirection, accumulate_wheel_lines, edge_scroll_adjustment};
|
use super::{EdgeScrollDirection, edge_scroll_adjustment};
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn wheel_lines_single_fractional_event_keeps_remainder() {
|
|
||||||
// A high-res wheel notch arrives as fractional deltas. A lone 0.125
|
|
||||||
// event is less than one whole line, but must not be discarded.
|
|
||||||
let (lines, remainder) = accumulate_wheel_lines(0.125, 0.0);
|
|
||||||
assert_eq!(lines, 0);
|
|
||||||
assert!((remainder - 0.75).abs() < f32::EPSILON);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn wheel_lines_accumulate_into_whole_lines() {
|
|
||||||
// Eight 0.125 deltas make up one physical notch and must scroll the
|
|
||||||
// full SCROLL_LINE_MULTIPLIER (6) lines, not be lost to truncation.
|
|
||||||
let mut accumulator = 0.0;
|
|
||||||
let mut total = 0;
|
|
||||||
for _ in 0..8 {
|
|
||||||
let (lines, remainder) = accumulate_wheel_lines(0.125, accumulator);
|
|
||||||
accumulator = remainder;
|
|
||||||
total += lines;
|
|
||||||
}
|
|
||||||
assert_eq!(total, 6);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn wheel_lines_preserve_direction() {
|
|
||||||
let (down, _) = accumulate_wheel_lines(0.25, 0.0);
|
|
||||||
let (up, _) = accumulate_wheel_lines(-0.25, 0.0);
|
|
||||||
assert_eq!(down, 1);
|
|
||||||
assert_eq!(up, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const BUFFER_HEIGHT: f32 = 200.0;
|
const BUFFER_HEIGHT: f32 = 200.0;
|
||||||
const CELL_HEIGHT: f32 = 20.0;
|
const CELL_HEIGHT: f32 = 20.0;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue