mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-25 13:16:11 +03:00
Merge branch 'ghostty-org:main' into hu_HU_localization
This commit is contained in:
@ -26,8 +26,8 @@
|
|||||||
},
|
},
|
||||||
.zig_objc = .{
|
.zig_objc = .{
|
||||||
// mitchellh/zig-objc
|
// mitchellh/zig-objc
|
||||||
.url = "https://github.com/mitchellh/zig-objc/archive/3ab0d37c7d6b933d6ded1b3a35b6b60f05590a98.tar.gz",
|
.url = "https://github.com/mitchellh/zig-objc/archive/c9e917a4e15a983b672ca779c7985d738a2d517c.tar.gz",
|
||||||
.hash = "zig_objc-0.0.0-Ir_Sp3TyAADEVRTxXlScq3t_uKAM91MYNerZkHfbD0yt",
|
.hash = "zig_objc-0.0.0-Ir_SpwsPAQBJgi9YRm2ubJMfdoysSq5gKpsIj3izQ8Zk",
|
||||||
.lazy = true,
|
.lazy = true,
|
||||||
},
|
},
|
||||||
.zig_js = .{
|
.zig_js = .{
|
||||||
|
6
build.zig.zon.json
generated
6
build.zig.zon.json
generated
@ -144,10 +144,10 @@
|
|||||||
"url": "https://deps.files.ghostty.org/zig_js-12205a66d423259567764fa0fc60c82be35365c21aeb76c5a7dc99698401f4f6fefc.tar.gz",
|
"url": "https://deps.files.ghostty.org/zig_js-12205a66d423259567764fa0fc60c82be35365c21aeb76c5a7dc99698401f4f6fefc.tar.gz",
|
||||||
"hash": "sha256-fyNeCVbC9UAaKJY6JhAZlT0A479M/AKYMPIWEZbDWD0="
|
"hash": "sha256-fyNeCVbC9UAaKJY6JhAZlT0A479M/AKYMPIWEZbDWD0="
|
||||||
},
|
},
|
||||||
"zig_objc-0.0.0-Ir_Sp3TyAADEVRTxXlScq3t_uKAM91MYNerZkHfbD0yt": {
|
"zig_objc-0.0.0-Ir_SpwsPAQBJgi9YRm2ubJMfdoysSq5gKpsIj3izQ8Zk": {
|
||||||
"name": "zig_objc",
|
"name": "zig_objc",
|
||||||
"url": "https://github.com/mitchellh/zig-objc/archive/3ab0d37c7d6b933d6ded1b3a35b6b60f05590a98.tar.gz",
|
"url": "https://github.com/mitchellh/zig-objc/archive/c9e917a4e15a983b672ca779c7985d738a2d517c.tar.gz",
|
||||||
"hash": "sha256-zn1tR6xhSmDla4UJ3t+Gni4Ni3R8deSK3tEe7DGzNXw="
|
"hash": "sha256-o3vl7qfkSi0bKXa6JWuF92qMEGP8Af/shcip5nRo5Nw="
|
||||||
},
|
},
|
||||||
"wayland-0.4.0-dev-lQa1kjfIAQCmhhQu3xF0KH-94-TzeMXOqfnP0-Dg6Wyy": {
|
"wayland-0.4.0-dev-lQa1kjfIAQCmhhQu3xF0KH-94-TzeMXOqfnP0-Dg6Wyy": {
|
||||||
"name": "zig_wayland",
|
"name": "zig_wayland",
|
||||||
|
6
build.zig.zon.nix
generated
6
build.zig.zon.nix
generated
@ -314,11 +314,11 @@ in
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
name = "zig_objc-0.0.0-Ir_Sp3TyAADEVRTxXlScq3t_uKAM91MYNerZkHfbD0yt";
|
name = "zig_objc-0.0.0-Ir_SpwsPAQBJgi9YRm2ubJMfdoysSq5gKpsIj3izQ8Zk";
|
||||||
path = fetchZigArtifact {
|
path = fetchZigArtifact {
|
||||||
name = "zig_objc";
|
name = "zig_objc";
|
||||||
url = "https://github.com/mitchellh/zig-objc/archive/3ab0d37c7d6b933d6ded1b3a35b6b60f05590a98.tar.gz";
|
url = "https://github.com/mitchellh/zig-objc/archive/c9e917a4e15a983b672ca779c7985d738a2d517c.tar.gz";
|
||||||
hash = "sha256-zn1tR6xhSmDla4UJ3t+Gni4Ni3R8deSK3tEe7DGzNXw=";
|
hash = "sha256-o3vl7qfkSi0bKXa6JWuF92qMEGP8Af/shcip5nRo5Nw=";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
2
build.zig.zon.txt
generated
2
build.zig.zon.txt
generated
@ -29,6 +29,6 @@ https://github.com/glfw/glfw/archive/e7ea71be039836da3a98cea55ae5569cb5eb885c.ta
|
|||||||
https://github.com/jcollie/ghostty-gobject/releases/download/0.14.0-2025-03-18-21-1/ghostty-gobject-0.14.0-2025-03-18-21-1.tar.zst
|
https://github.com/jcollie/ghostty-gobject/releases/download/0.14.0-2025-03-18-21-1/ghostty-gobject-0.14.0-2025-03-18-21-1.tar.zst
|
||||||
https://github.com/mbadolato/iTerm2-Color-Schemes/archive/6fa671fdc1daf1fcfa025cb960ffa3e7373a2ed8.tar.gz
|
https://github.com/mbadolato/iTerm2-Color-Schemes/archive/6fa671fdc1daf1fcfa025cb960ffa3e7373a2ed8.tar.gz
|
||||||
https://github.com/mitchellh/libxev/archive/75a10d0fb374e8eb84948dcfc68d865e755e59c2.tar.gz
|
https://github.com/mitchellh/libxev/archive/75a10d0fb374e8eb84948dcfc68d865e755e59c2.tar.gz
|
||||||
https://github.com/mitchellh/zig-objc/archive/3ab0d37c7d6b933d6ded1b3a35b6b60f05590a98.tar.gz
|
https://github.com/mitchellh/zig-objc/archive/c9e917a4e15a983b672ca779c7985d738a2d517c.tar.gz
|
||||||
https://github.com/natecraddock/zf/archive/7aacbe6d155d64d15937ca95ca6c014905eb531f.tar.gz
|
https://github.com/natecraddock/zf/archive/7aacbe6d155d64d15937ca95ca6c014905eb531f.tar.gz
|
||||||
https://github.com/vancluever/z2d/archive/8bbd035f4101f02b1d27947def0d7da3215df7fe.tar.gz
|
https://github.com/vancluever/z2d/archive/8bbd035f4101f02b1d27947def0d7da3215df7fe.tar.gz
|
||||||
|
@ -175,9 +175,9 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "archive",
|
"type": "archive",
|
||||||
"url": "https://github.com/mitchellh/zig-objc/archive/3ab0d37c7d6b933d6ded1b3a35b6b60f05590a98.tar.gz",
|
"url": "https://github.com/mitchellh/zig-objc/archive/c9e917a4e15a983b672ca779c7985d738a2d517c.tar.gz",
|
||||||
"dest": "vendor/p/zig_objc-0.0.0-Ir_Sp3TyAADEVRTxXlScq3t_uKAM91MYNerZkHfbD0yt",
|
"dest": "vendor/p/zig_objc-0.0.0-Ir_SpwsPAQBJgi9YRm2ubJMfdoysSq5gKpsIj3izQ8Zk",
|
||||||
"sha256": "ce7d6d47ac614a60e56b8509dedf869e2e0d8b747c75e48aded11eec31b3357c"
|
"sha256": "a37be5eea7e44a2d1b2976ba256b85f76a8c1063fc01ffec85c8a9e67468e4dc"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "archive",
|
"type": "archive",
|
||||||
|
@ -148,6 +148,18 @@ const locales = [_][]const u8{
|
|||||||
|
|
||||||
You should then be able to run `zig build` and see your translations in action.
|
You should then be able to run `zig build` and see your translations in action.
|
||||||
|
|
||||||
|
Before opening a pull request with the new translation file, you should also add
|
||||||
|
your locale to the `CODEOWNERS` file. Find the `# Localization` section near the
|
||||||
|
bottom and add a line like so (where `xx_YY` is your locale):
|
||||||
|
|
||||||
|
```diff
|
||||||
|
# Localization
|
||||||
|
/po/README_TRANSLATORS.md @ghostty-org/localization
|
||||||
|
/po/com.mitchellh.ghostty.pot @ghostty-org/localization
|
||||||
|
/po/zh_CN.UTF-8.po @ghostty-org/zh_CN
|
||||||
|
+/po/xx_YY.UTF-8.po @ghostty-org/xx_YY
|
||||||
|
```
|
||||||
|
|
||||||
## Style Guide
|
## Style Guide
|
||||||
|
|
||||||
These are general style guidelines for translations. Naturally, the specific
|
These are general style guidelines for translations. Naturally, the specific
|
||||||
|
275
po/bg_BG.UTF-8.po
Normal file
275
po/bg_BG.UTF-8.po
Normal file
@ -0,0 +1,275 @@
|
|||||||
|
# Bulgarian translations for com.mitchellh.ghostty package.
|
||||||
|
# Copyright (C) 2025 Mitchell Hashimoto
|
||||||
|
# This file is distributed under the same license as the com.mitchellh.ghostty package.
|
||||||
|
# Damyan Bogoev <damyan.bogoev@gmail.com>, 2025.
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: com.mitchellh.ghostty\n"
|
||||||
|
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
|
||||||
|
"POT-Creation-Date: 2025-04-23 16:58+0800\n"
|
||||||
|
"PO-Revision-Date: 2025-05-19 11:34+0300\n"
|
||||||
|
"Last-Translator: Damyan Bogoev <damyan.bogoev@gmail.com>\n"
|
||||||
|
"Language-Team: Bulgarian <dict@ludost.net>\n"
|
||||||
|
"Language: bg\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:5
|
||||||
|
msgid "Change Terminal Title"
|
||||||
|
msgstr "Промяна на заглавието на терминала"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:6
|
||||||
|
msgid "Leave blank to restore the default title."
|
||||||
|
msgstr "Оставете празно за възстановяване на заглавието по подразбиране."
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:9
|
||||||
|
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/CloseDialog.zig:44
|
||||||
|
msgid "Cancel"
|
||||||
|
msgstr "Отказ"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:10
|
||||||
|
msgid "OK"
|
||||||
|
msgstr "ОК"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
|
||||||
|
msgid "Configuration Errors"
|
||||||
|
msgstr "Грешки в конфигурацията"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
|
||||||
|
msgid ""
|
||||||
|
"One or more configuration errors were found. Please review the errors "
|
||||||
|
"below, and either reload your configuration or ignore these errors."
|
||||||
|
msgstr "Открити са една или повече грешки в конфигурацията. Моля, прегледайте грешките по-долу и или презаредете конфигурацията си, или ги игнорирайте."
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
|
||||||
|
msgid "Ignore"
|
||||||
|
msgstr "Игнорирай"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:10
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:97
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:100
|
||||||
|
msgid "Reload Configuration"
|
||||||
|
msgstr "Презареди конфигурацията"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-headerbar-split_menu.blp:6
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:38
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:50
|
||||||
|
msgid "Split Up"
|
||||||
|
msgstr "Раздели нагоре"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-headerbar-split_menu.blp:11
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:43
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:55
|
||||||
|
msgid "Split Down"
|
||||||
|
msgstr "Раздели надолу"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-headerbar-split_menu.blp:16
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:48
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:60
|
||||||
|
msgid "Split Left"
|
||||||
|
msgstr "Раздели наляво"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-headerbar-split_menu.blp:21
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:53
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:65
|
||||||
|
msgid "Split Right"
|
||||||
|
msgstr "Раздели надясно"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.5/command-palette.blp:16
|
||||||
|
msgid "Execute a command…"
|
||||||
|
msgstr "Изпълни команда…"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:6
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:6
|
||||||
|
msgid "Copy"
|
||||||
|
msgstr "Копирай"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:11
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:11
|
||||||
|
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11
|
||||||
|
msgid "Paste"
|
||||||
|
msgstr "Постави"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:18
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:73
|
||||||
|
msgid "Clear"
|
||||||
|
msgstr "Изчисти"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:23
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:78
|
||||||
|
msgid "Reset"
|
||||||
|
msgstr "Нулирай"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:30
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:42
|
||||||
|
msgid "Split"
|
||||||
|
msgstr "Раздели"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:33
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:45
|
||||||
|
msgid "Change Title…"
|
||||||
|
msgstr "Промени заглавие…"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:59
|
||||||
|
msgid "Tab"
|
||||||
|
msgstr "Раздел"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:62
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:30
|
||||||
|
#: src/apprt/gtk/Window.zig:255
|
||||||
|
msgid "New Tab"
|
||||||
|
msgstr "Нов раздел"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:67
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:35
|
||||||
|
msgid "Close Tab"
|
||||||
|
msgstr "Затвори раздел"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:73
|
||||||
|
msgid "Window"
|
||||||
|
msgstr "Прозорец"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:76
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:18
|
||||||
|
msgid "New Window"
|
||||||
|
msgstr "Нов прозорец"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:81
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:23
|
||||||
|
msgid "Close Window"
|
||||||
|
msgstr "Затвори прозорец"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:89
|
||||||
|
msgid "Config"
|
||||||
|
msgstr "Конфигурация"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:92
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
|
||||||
|
msgid "Open Configuration"
|
||||||
|
msgstr "Отвори конфигурацията"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:85
|
||||||
|
msgid "Command Palette"
|
||||||
|
msgstr "Командна палитра"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
|
||||||
|
msgid "Terminal Inspector"
|
||||||
|
msgstr "Инспектор на терминала"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
|
||||||
|
#: src/apprt/gtk/Window.zig:1024
|
||||||
|
msgid "About Ghostty"
|
||||||
|
msgstr "За Ghostty"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:112
|
||||||
|
msgid "Quit"
|
||||||
|
msgstr "Изход"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:6
|
||||||
|
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:6
|
||||||
|
msgid "Authorize Clipboard Access"
|
||||||
|
msgstr "Разрешаване на достъп до клипборда"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
|
||||||
|
msgid ""
|
||||||
|
"An application is attempting to read from the clipboard. The current "
|
||||||
|
"clipboard contents are shown below."
|
||||||
|
msgstr "Приложение се опитва да чете от клипборда. Текущото съдържание на клипборда е показано по-долу."
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:10
|
||||||
|
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:10
|
||||||
|
msgid "Deny"
|
||||||
|
msgstr "Откажи"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:11
|
||||||
|
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:11
|
||||||
|
msgid "Allow"
|
||||||
|
msgstr "Позволи"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
|
||||||
|
msgid ""
|
||||||
|
"An application is attempting to write to the clipboard. The current "
|
||||||
|
"clipboard contents are shown below."
|
||||||
|
msgstr "Приложение се опитва да запише в клипборда. Текущото съдържание на клипборда е показано по-долу."
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6
|
||||||
|
msgid "Warning: Potentially Unsafe Paste"
|
||||||
|
msgstr "Предупреждение: Потенциално опасно поставяне"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7
|
||||||
|
msgid ""
|
||||||
|
"Pasting this text into the terminal may be dangerous as it looks like some "
|
||||||
|
"commands may be executed."
|
||||||
|
msgstr "Поставянето на този текст в терминала може да е опасно, тъй като изглежда, че може да бъдат изпълнени някои команди."
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Window.zig:208
|
||||||
|
msgid "Main Menu"
|
||||||
|
msgstr "Главно меню"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Window.zig:229
|
||||||
|
msgid "View Open Tabs"
|
||||||
|
msgstr "Преглед на отворените раздели"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Window.zig:256
|
||||||
|
msgid "New Split"
|
||||||
|
msgstr "Ново разделяне"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Window.zig:319
|
||||||
|
msgid ""
|
||||||
|
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
|
||||||
|
msgstr "⚠️ Използвате дебъг версия на Ghostty! Производителността ще бъде намалена."
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Window.zig:765
|
||||||
|
msgid "Reloaded the configuration"
|
||||||
|
msgstr "Конфигурацията е презаредена"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Window.zig:1005
|
||||||
|
msgid "Ghostty Developers"
|
||||||
|
msgstr "Разработчици на Ghostty"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/inspector.zig:144
|
||||||
|
msgid "Ghostty: Terminal Inspector"
|
||||||
|
msgstr "Ghostty: Инспектор на терминала"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/CloseDialog.zig:47
|
||||||
|
msgid "Close"
|
||||||
|
msgstr "Затвори"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/CloseDialog.zig:87
|
||||||
|
msgid "Quit Ghostty?"
|
||||||
|
msgstr "Изход от Ghostty?"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/CloseDialog.zig:88
|
||||||
|
msgid "Close Window?"
|
||||||
|
msgstr "Затваряне на прозореца?"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/CloseDialog.zig:89
|
||||||
|
msgid "Close Tab?"
|
||||||
|
msgstr "Затваряне на раздела?"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/CloseDialog.zig:90
|
||||||
|
msgid "Close Split?"
|
||||||
|
msgstr "Затваряне на разделянето?"
|
||||||
|
|
||||||
|
#: src/apprt/gtk/CloseDialog.zig:96
|
||||||
|
msgid "All terminal sessions will be terminated."
|
||||||
|
msgstr "Всички терминални сесии ще бъдат прекратени."
|
||||||
|
|
||||||
|
#: src/apprt/gtk/CloseDialog.zig:97
|
||||||
|
msgid "All terminal sessions in this window will be terminated."
|
||||||
|
msgstr "Всички терминални сесии в този прозорец ще бъдат прекратени."
|
||||||
|
|
||||||
|
#: src/apprt/gtk/CloseDialog.zig:98
|
||||||
|
msgid "All terminal sessions in this tab will be terminated."
|
||||||
|
msgstr "Всички терминални сесии в този раздел ще бъдат прекратени."
|
||||||
|
|
||||||
|
#: src/apprt/gtk/CloseDialog.zig:99
|
||||||
|
msgid "The currently running process in this split will be terminated."
|
||||||
|
msgstr "Текущият процес в това разделяне ще бъде прекратен."
|
||||||
|
|
||||||
|
#: src/apprt/gtk/Surface.zig:1243
|
||||||
|
msgid "Copied to clipboard"
|
||||||
|
msgstr "Копирано в клипборда"
|
@ -188,10 +188,31 @@ fn startPosix(self: *Command, arena: Allocator) !void {
|
|||||||
// Finally, replace our process.
|
// Finally, replace our process.
|
||||||
// Note: we must use the "p"-variant of exec here because we
|
// Note: we must use the "p"-variant of exec here because we
|
||||||
// do not guarantee our command is looked up already in the path.
|
// do not guarantee our command is looked up already in the path.
|
||||||
_ = posix.execvpeZ(self.path, argsZ, envp) catch null;
|
const err = posix.execvpeZ(self.path, argsZ, envp);
|
||||||
|
|
||||||
// If we are executing this code, the exec failed. In that scenario,
|
// If we are executing this code, the exec failed. We're in the
|
||||||
// we return a very specific error that can be detected to determine
|
// child process so there isn't much we can do. We try to output
|
||||||
|
// something reasonable. Its important to note we MUST NOT return
|
||||||
|
// any other error condition from here on out.
|
||||||
|
const stderr = std.io.getStdErr().writer();
|
||||||
|
switch (err) {
|
||||||
|
error.FileNotFound => stderr.print(
|
||||||
|
\\Requested executable not found. Please verify the command is on
|
||||||
|
\\the PATH and try again.
|
||||||
|
\\
|
||||||
|
,
|
||||||
|
.{},
|
||||||
|
) catch {},
|
||||||
|
|
||||||
|
else => stderr.print(
|
||||||
|
\\exec syscall failed with unexpected error: {}
|
||||||
|
\\
|
||||||
|
,
|
||||||
|
.{err},
|
||||||
|
) catch {},
|
||||||
|
}
|
||||||
|
|
||||||
|
// We return a very specific error that can be detected to determine
|
||||||
// we're in the child.
|
// we're in the child.
|
||||||
return error.ExecFailedInChild;
|
return error.ExecFailedInChild;
|
||||||
}
|
}
|
||||||
|
@ -62,6 +62,13 @@ pub const compatibility = std.StaticStringMap(
|
|||||||
// Ghostty 1.2 removed the `hidden` value from `gtk-tabs-location` and
|
// Ghostty 1.2 removed the `hidden` value from `gtk-tabs-location` and
|
||||||
// moved it to `window-show-tab-bar`.
|
// moved it to `window-show-tab-bar`.
|
||||||
.{ "gtk-tabs-location", compatGtkTabsLocation },
|
.{ "gtk-tabs-location", compatGtkTabsLocation },
|
||||||
|
|
||||||
|
// Ghostty 1.2 lets you set `cell-foreground` and `cell-background`
|
||||||
|
// to match the cell foreground and background colors, respectively.
|
||||||
|
// This can be used with `cursor-color` and `cursor-text` to recreate
|
||||||
|
// this behavior. This applies to selection too.
|
||||||
|
.{ "cursor-invert-fg-bg", compatCursorInvertFgBg },
|
||||||
|
.{ "selection-invert-fg-bg", compatSelectionInvertFgBg },
|
||||||
});
|
});
|
||||||
|
|
||||||
/// The font families to use.
|
/// The font families to use.
|
||||||
@ -591,16 +598,11 @@ foreground: Color = .{ .r = 0xFF, .g = 0xFF, .b = 0xFF },
|
|||||||
/// the selection color is just the inverted window background and foreground
|
/// the selection color is just the inverted window background and foreground
|
||||||
/// (note: not to be confused with the cell bg/fg).
|
/// (note: not to be confused with the cell bg/fg).
|
||||||
/// Specified as either hex (`#RRGGBB` or `RRGGBB`) or a named X11 color.
|
/// Specified as either hex (`#RRGGBB` or `RRGGBB`) or a named X11 color.
|
||||||
@"selection-foreground": ?Color = null,
|
/// Since version 1.2.0, this can also be set to `cell-foreground` to match
|
||||||
@"selection-background": ?Color = null,
|
/// the cell foreground color, or `cell-background` to match the cell
|
||||||
|
/// background color.
|
||||||
/// Swap the foreground and background colors of cells for selection. This
|
@"selection-foreground": ?TerminalColor = null,
|
||||||
/// option overrides the `selection-foreground` and `selection-background`
|
@"selection-background": ?TerminalColor = null,
|
||||||
/// options.
|
|
||||||
///
|
|
||||||
/// If you select across cells with differing foregrounds and backgrounds, the
|
|
||||||
/// selection color will vary across the selection.
|
|
||||||
@"selection-invert-fg-bg": bool = false,
|
|
||||||
|
|
||||||
/// Whether to clear selected text when typing. This defaults to `true`.
|
/// Whether to clear selected text when typing. This defaults to `true`.
|
||||||
/// This is typical behavior for most terminal emulators as well as
|
/// This is typical behavior for most terminal emulators as well as
|
||||||
@ -644,12 +646,20 @@ foreground: Color = .{ .r = 0xFF, .g = 0xFF, .b = 0xFF },
|
|||||||
palette: Palette = .{},
|
palette: Palette = .{},
|
||||||
|
|
||||||
/// The color of the cursor. If this is not set, a default will be chosen.
|
/// The color of the cursor. If this is not set, a default will be chosen.
|
||||||
/// Specified as either hex (`#RRGGBB` or `RRGGBB`) or a named X11 color.
|
///
|
||||||
@"cursor-color": ?Color = null,
|
/// Direct colors can be specified as either hex (`#RRGGBB` or `RRGGBB`)
|
||||||
|
/// or a named X11 color.
|
||||||
/// Swap the foreground and background colors of the cell under the cursor. This
|
///
|
||||||
/// option overrides the `cursor-color` and `cursor-text` options.
|
/// Additionally, special values can be used to set the color to match
|
||||||
@"cursor-invert-fg-bg": bool = false,
|
/// other colors at runtime:
|
||||||
|
///
|
||||||
|
/// * `cell-foreground` - Match the cell foreground color.
|
||||||
|
/// (Available since version 1.2.0)
|
||||||
|
///
|
||||||
|
/// * `cell-background` - Match the cell background color.
|
||||||
|
/// (Available since version 1.2.0)
|
||||||
|
///
|
||||||
|
@"cursor-color": ?TerminalColor = null,
|
||||||
|
|
||||||
/// The opacity level (opposite of transparency) of the cursor. A value of 1
|
/// The opacity level (opposite of transparency) of the cursor. A value of 1
|
||||||
/// is fully opaque and a value of 0 is fully transparent. A value less than 0
|
/// is fully opaque and a value of 0 is fully transparent. A value less than 0
|
||||||
@ -699,7 +709,10 @@ palette: Palette = .{},
|
|||||||
/// The color of the text under the cursor. If this is not set, a default will
|
/// The color of the text under the cursor. If this is not set, a default will
|
||||||
/// be chosen.
|
/// be chosen.
|
||||||
/// Specified as either hex (`#RRGGBB` or `RRGGBB`) or a named X11 color.
|
/// Specified as either hex (`#RRGGBB` or `RRGGBB`) or a named X11 color.
|
||||||
@"cursor-text": ?Color = null,
|
/// Since version 1.2.0, this can also be set to `cell-foreground` to match
|
||||||
|
/// the cell foreground color, or `cell-background` to match the cell
|
||||||
|
/// background color.
|
||||||
|
@"cursor-text": ?TerminalColor = null,
|
||||||
|
|
||||||
/// Enables the ability to move the cursor at prompts by using `alt+click` on
|
/// Enables the ability to move the cursor at prompts by using `alt+click` on
|
||||||
/// Linux and `option+click` on macOS.
|
/// Linux and `option+click` on macOS.
|
||||||
@ -2761,14 +2774,14 @@ else
|
|||||||
///
|
///
|
||||||
/// GTK CSS documentation can be found at the following links:
|
/// GTK CSS documentation can be found at the following links:
|
||||||
///
|
///
|
||||||
/// * <https://docs.gtk.org/gtk4/css-overview.html> - An overview of GTK CSS.
|
/// * https://docs.gtk.org/gtk4/css-overview.html - An overview of GTK CSS.
|
||||||
/// * <https://docs.gtk.org/gtk4/css-properties.html> - A comprehensive list
|
/// * https://docs.gtk.org/gtk4/css-properties.html - A comprehensive list
|
||||||
/// of supported CSS properties.
|
/// of supported CSS properties.
|
||||||
///
|
///
|
||||||
/// Launch Ghostty with `env GTK_DEBUG=interactive ghostty` to tweak Ghostty's
|
/// Launch Ghostty with `env GTK_DEBUG=interactive ghostty` to tweak Ghostty's
|
||||||
/// CSS in real time using the GTK Inspector. Errors in your CSS files would
|
/// CSS in real time using the GTK Inspector. Errors in your CSS files would
|
||||||
/// also be reported in the terminal you started Ghostty from. See
|
/// also be reported in the terminal you started Ghostty from. See
|
||||||
/// <https://developer.gnome.org/documentation/tools/inspector.html> for more
|
/// https://developer.gnome.org/documentation/tools/inspector.html for more
|
||||||
/// information about the GTK Inspector.
|
/// information about the GTK Inspector.
|
||||||
///
|
///
|
||||||
/// This configuration can be repeated multiple times to load multiple files.
|
/// This configuration can be repeated multiple times to load multiple files.
|
||||||
@ -3826,10 +3839,6 @@ pub fn parseManuallyHook(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// parseFieldManuallyFallback is a fallback called only when
|
|
||||||
/// parsing the field directly failed. It can be used to implement
|
|
||||||
/// backward compatibility. Since this is only called when parsing
|
|
||||||
/// fails, it doesn't impact happy-path performance.
|
|
||||||
fn compatGtkTabsLocation(
|
fn compatGtkTabsLocation(
|
||||||
self: *Config,
|
self: *Config,
|
||||||
alloc: Allocator,
|
alloc: Allocator,
|
||||||
@ -3847,6 +3856,51 @@ fn compatGtkTabsLocation(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn compatCursorInvertFgBg(
|
||||||
|
self: *Config,
|
||||||
|
alloc: Allocator,
|
||||||
|
key: []const u8,
|
||||||
|
value_: ?[]const u8,
|
||||||
|
) bool {
|
||||||
|
_ = alloc;
|
||||||
|
assert(std.mem.eql(u8, key, "cursor-invert-fg-bg"));
|
||||||
|
|
||||||
|
// We don't do anything if the value is unset, which is technically
|
||||||
|
// not EXACTLY the same as prior behavior since it would fallback
|
||||||
|
// to doing whatever cursor-color/cursor-text were set to, but
|
||||||
|
// I don't want to store what that is separately so this is close
|
||||||
|
// enough.
|
||||||
|
//
|
||||||
|
// Realistically, these fields were mutually exclusive so anyone
|
||||||
|
// relying on that behavior should just upgrade to the new
|
||||||
|
// cursor-color/cursor-text fields.
|
||||||
|
const set = cli.args.parseBool(value_ orelse "t") catch return false;
|
||||||
|
if (set) {
|
||||||
|
self.@"cursor-color" = .@"cell-foreground";
|
||||||
|
self.@"cursor-text" = .@"cell-background";
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compatSelectionInvertFgBg(
|
||||||
|
self: *Config,
|
||||||
|
alloc: Allocator,
|
||||||
|
key: []const u8,
|
||||||
|
value_: ?[]const u8,
|
||||||
|
) bool {
|
||||||
|
_ = alloc;
|
||||||
|
assert(std.mem.eql(u8, key, "selection-invert-fg-bg"));
|
||||||
|
|
||||||
|
const set = cli.args.parseBool(value_ orelse "t") catch return false;
|
||||||
|
if (set) {
|
||||||
|
self.@"selection-foreground" = .@"cell-background";
|
||||||
|
self.@"selection-background" = .@"cell-foreground";
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a shallow copy of this config. This will share all the memory
|
/// Create a shallow copy of this config. This will share all the memory
|
||||||
/// allocated with the previous config but will have a new arena for
|
/// allocated with the previous config but will have a new arena for
|
||||||
/// any changes or new allocations. The config should have `deinit`
|
/// any changes or new allocations. The config should have `deinit`
|
||||||
@ -4409,6 +4463,65 @@ pub const Color = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Represents color values that can also reference special color
|
||||||
|
/// values such as "cell-foreground" or "cell-background".
|
||||||
|
pub const TerminalColor = union(enum) {
|
||||||
|
color: Color,
|
||||||
|
@"cell-foreground",
|
||||||
|
@"cell-background",
|
||||||
|
|
||||||
|
pub fn parseCLI(input_: ?[]const u8) !TerminalColor {
|
||||||
|
const input = input_ orelse return error.ValueRequired;
|
||||||
|
if (std.mem.eql(u8, input, "cell-foreground")) return .@"cell-foreground";
|
||||||
|
if (std.mem.eql(u8, input, "cell-background")) return .@"cell-background";
|
||||||
|
return .{ .color = try Color.parseCLI(input) };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Used by Formatter
|
||||||
|
pub fn formatEntry(self: TerminalColor, formatter: anytype) !void {
|
||||||
|
switch (self) {
|
||||||
|
.color => try self.color.formatEntry(formatter),
|
||||||
|
|
||||||
|
.@"cell-foreground",
|
||||||
|
.@"cell-background",
|
||||||
|
=> try formatter.formatEntry([:0]const u8, @tagName(self)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "parseCLI" {
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
try testing.expectEqual(
|
||||||
|
TerminalColor{ .color = Color{ .r = 78, .g = 42, .b = 132 } },
|
||||||
|
try TerminalColor.parseCLI("#4e2a84"),
|
||||||
|
);
|
||||||
|
try testing.expectEqual(
|
||||||
|
TerminalColor{ .color = Color{ .r = 0, .g = 0, .b = 0 } },
|
||||||
|
try TerminalColor.parseCLI("black"),
|
||||||
|
);
|
||||||
|
try testing.expectEqual(
|
||||||
|
TerminalColor.@"cell-foreground",
|
||||||
|
try TerminalColor.parseCLI("cell-foreground"),
|
||||||
|
);
|
||||||
|
try testing.expectEqual(
|
||||||
|
TerminalColor.@"cell-background",
|
||||||
|
try TerminalColor.parseCLI("cell-background"),
|
||||||
|
);
|
||||||
|
|
||||||
|
try testing.expectError(error.InvalidValue, TerminalColor.parseCLI("a"));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "formatConfig" {
|
||||||
|
const testing = std.testing;
|
||||||
|
var buf = std.ArrayList(u8).init(testing.allocator);
|
||||||
|
defer buf.deinit();
|
||||||
|
|
||||||
|
var sc: TerminalColor = .@"cell-foreground";
|
||||||
|
try sc.formatEntry(formatterpkg.entryFormatter("a", buf.writer()));
|
||||||
|
try testing.expectEqualSlices(u8, "a = cell-foreground\n", buf.items);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
pub const ColorList = struct {
|
pub const ColorList = struct {
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
@ -5342,7 +5455,14 @@ pub const Keybinds = struct {
|
|||||||
.mods = mods,
|
.mods = mods,
|
||||||
},
|
},
|
||||||
.{ .goto_tab = (i - start) + 1 },
|
.{ .goto_tab = (i - start) + 1 },
|
||||||
.{ .performable = true },
|
.{
|
||||||
|
// On macOS we keep this not performable so that the
|
||||||
|
// keyboard shortcuts in tabs work. In the future the
|
||||||
|
// correct fix is to fix the reverse mapping lookup
|
||||||
|
// to allow us to lookup performable keybinds
|
||||||
|
// conditionally.
|
||||||
|
.performable = !builtin.target.os.tag.isDarwin(),
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
try self.set.putFlags(
|
try self.set.putFlags(
|
||||||
@ -5352,7 +5472,10 @@ pub const Keybinds = struct {
|
|||||||
.mods = mods,
|
.mods = mods,
|
||||||
},
|
},
|
||||||
.{ .last_tab = {} },
|
.{ .last_tab = {} },
|
||||||
.{ .performable = true },
|
.{
|
||||||
|
// See comment above with the numeric goto_tab
|
||||||
|
.performable = !builtin.target.os.tag.isDarwin(),
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -8042,3 +8165,51 @@ test "theme specifying light/dark sets theme usage in conditional state" {
|
|||||||
try testing.expect(cfg._conditional_set.contains(.theme));
|
try testing.expect(cfg._conditional_set.contains(.theme));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "compatibility: removed cursor-invert-fg-bg" {
|
||||||
|
const testing = std.testing;
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
|
||||||
|
{
|
||||||
|
var cfg = try Config.default(alloc);
|
||||||
|
defer cfg.deinit();
|
||||||
|
var it: TestIterator = .{ .data = &.{
|
||||||
|
"--cursor-invert-fg-bg",
|
||||||
|
} };
|
||||||
|
try cfg.loadIter(alloc, &it);
|
||||||
|
try cfg.finalize();
|
||||||
|
|
||||||
|
try testing.expectEqual(
|
||||||
|
TerminalColor.@"cell-foreground",
|
||||||
|
cfg.@"cursor-color",
|
||||||
|
);
|
||||||
|
try testing.expectEqual(
|
||||||
|
TerminalColor.@"cell-background",
|
||||||
|
cfg.@"cursor-text",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "compatibility: removed selection-invert-fg-bg" {
|
||||||
|
const testing = std.testing;
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
|
||||||
|
{
|
||||||
|
var cfg = try Config.default(alloc);
|
||||||
|
defer cfg.deinit();
|
||||||
|
var it: TestIterator = .{ .data = &.{
|
||||||
|
"--selection-invert-fg-bg",
|
||||||
|
} };
|
||||||
|
try cfg.loadIter(alloc, &it);
|
||||||
|
try cfg.finalize();
|
||||||
|
|
||||||
|
try testing.expectEqual(
|
||||||
|
TerminalColor.@"cell-background",
|
||||||
|
cfg.@"selection-foreground",
|
||||||
|
);
|
||||||
|
try testing.expectEqual(
|
||||||
|
TerminalColor.@"cell-foreground",
|
||||||
|
cfg.@"selection-background",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -831,6 +831,9 @@ pub const CoreText = struct {
|
|||||||
i: usize,
|
i: usize,
|
||||||
|
|
||||||
pub fn deinit(self: *DiscoverIterator) void {
|
pub fn deinit(self: *DiscoverIterator) void {
|
||||||
|
for (self.list) |desc| {
|
||||||
|
desc.release();
|
||||||
|
}
|
||||||
self.alloc.free(self.list);
|
self.alloc.free(self.list);
|
||||||
self.* = undefined;
|
self.* = undefined;
|
||||||
}
|
}
|
||||||
|
@ -109,7 +109,8 @@ pub const Shaper = struct {
|
|||||||
/// settings the font features of a CoreText font.
|
/// settings the font features of a CoreText font.
|
||||||
fn makeFeaturesDict(feats: []const Feature) !*macos.foundation.Dictionary {
|
fn makeFeaturesDict(feats: []const Feature) !*macos.foundation.Dictionary {
|
||||||
const list = try macos.foundation.MutableArray.create();
|
const list = try macos.foundation.MutableArray.create();
|
||||||
errdefer list.release();
|
// The list will be retained by the dict once we add it to it.
|
||||||
|
defer list.release();
|
||||||
|
|
||||||
for (feats) |feat| {
|
for (feats) |feat| {
|
||||||
const value_num: c_int = @intCast(feat.value);
|
const value_num: c_int = @intCast(feat.value);
|
||||||
|
@ -47,6 +47,7 @@ pub const locales = [_][:0]const u8{
|
|||||||
"es_AR.UTF-8",
|
"es_AR.UTF-8",
|
||||||
"pt_BR.UTF-8",
|
"pt_BR.UTF-8",
|
||||||
"ca_ES.UTF-8",
|
"ca_ES.UTF-8",
|
||||||
|
"bg_BG.UTF-8",
|
||||||
"ga_IE.UTF-8",
|
"ga_IE.UTF-8",
|
||||||
"hu_HU.UTF-8",
|
"hu_HU.UTF-8",
|
||||||
};
|
};
|
||||||
|
@ -133,12 +133,7 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
|
|||||||
/// This is cursor color as set in the user's config, if any. If no cursor color
|
/// This is cursor color as set in the user's config, if any. If no cursor color
|
||||||
/// is set in the user's config, then the cursor color is determined by the
|
/// is set in the user's config, then the cursor color is determined by the
|
||||||
/// current foreground color.
|
/// current foreground color.
|
||||||
default_cursor_color: ?terminal.color.RGB,
|
default_cursor_color: ?configpkg.Config.TerminalColor,
|
||||||
|
|
||||||
/// When `cursor_color` is null, swap the foreground and background colors of
|
|
||||||
/// the cell under the cursor for the cursor color. Otherwise, use the default
|
|
||||||
/// foreground color as the cursor color.
|
|
||||||
cursor_invert: bool,
|
|
||||||
|
|
||||||
/// The current set of cells to render. This is rebuilt on every frame
|
/// The current set of cells to render. This is rebuilt on every frame
|
||||||
/// but we keep this around so that we don't reallocate. Each set of
|
/// but we keep this around so that we don't reallocate. Each set of
|
||||||
@ -514,16 +509,14 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
|
|||||||
font_features: std.ArrayListUnmanaged([:0]const u8),
|
font_features: std.ArrayListUnmanaged([:0]const u8),
|
||||||
font_styles: font.CodepointResolver.StyleStatus,
|
font_styles: font.CodepointResolver.StyleStatus,
|
||||||
font_shaping_break: configpkg.FontShapingBreak,
|
font_shaping_break: configpkg.FontShapingBreak,
|
||||||
cursor_color: ?terminal.color.RGB,
|
cursor_color: ?configpkg.Config.TerminalColor,
|
||||||
cursor_invert: bool,
|
|
||||||
cursor_opacity: f64,
|
cursor_opacity: f64,
|
||||||
cursor_text: ?terminal.color.RGB,
|
cursor_text: ?configpkg.Config.TerminalColor,
|
||||||
background: terminal.color.RGB,
|
background: terminal.color.RGB,
|
||||||
background_opacity: f64,
|
background_opacity: f64,
|
||||||
foreground: terminal.color.RGB,
|
foreground: terminal.color.RGB,
|
||||||
selection_background: ?terminal.color.RGB,
|
selection_background: ?configpkg.Config.TerminalColor,
|
||||||
selection_foreground: ?terminal.color.RGB,
|
selection_foreground: ?configpkg.Config.TerminalColor,
|
||||||
invert_selection_fg_bg: bool,
|
|
||||||
bold_is_bright: bool,
|
bold_is_bright: bool,
|
||||||
min_contrast: f32,
|
min_contrast: f32,
|
||||||
padding_color: configpkg.WindowPaddingColor,
|
padding_color: configpkg.WindowPaddingColor,
|
||||||
@ -571,8 +564,6 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
|
|||||||
config.link.links.items,
|
config.link.links.items,
|
||||||
);
|
);
|
||||||
|
|
||||||
const cursor_invert = config.@"cursor-invert-fg-bg";
|
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.background_opacity = @max(0, @min(1, config.@"background-opacity")),
|
.background_opacity = @max(0, @min(1, config.@"background-opacity")),
|
||||||
.font_thicken = config.@"font-thicken",
|
.font_thicken = config.@"font-thicken",
|
||||||
@ -581,36 +572,18 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
|
|||||||
.font_styles = font_styles,
|
.font_styles = font_styles,
|
||||||
.font_shaping_break = config.@"font-shaping-break",
|
.font_shaping_break = config.@"font-shaping-break",
|
||||||
|
|
||||||
.cursor_color = if (!cursor_invert and config.@"cursor-color" != null)
|
.cursor_color = config.@"cursor-color",
|
||||||
config.@"cursor-color".?.toTerminalRGB()
|
.cursor_text = config.@"cursor-text",
|
||||||
else
|
|
||||||
null,
|
|
||||||
|
|
||||||
.cursor_invert = cursor_invert,
|
|
||||||
|
|
||||||
.cursor_text = if (config.@"cursor-text") |txt|
|
|
||||||
txt.toTerminalRGB()
|
|
||||||
else
|
|
||||||
null,
|
|
||||||
|
|
||||||
.cursor_opacity = @max(0, @min(1, config.@"cursor-opacity")),
|
.cursor_opacity = @max(0, @min(1, config.@"cursor-opacity")),
|
||||||
|
|
||||||
.background = config.background.toTerminalRGB(),
|
.background = config.background.toTerminalRGB(),
|
||||||
.foreground = config.foreground.toTerminalRGB(),
|
.foreground = config.foreground.toTerminalRGB(),
|
||||||
.invert_selection_fg_bg = config.@"selection-invert-fg-bg",
|
|
||||||
.bold_is_bright = config.@"bold-is-bright",
|
.bold_is_bright = config.@"bold-is-bright",
|
||||||
.min_contrast = @floatCast(config.@"minimum-contrast"),
|
.min_contrast = @floatCast(config.@"minimum-contrast"),
|
||||||
.padding_color = config.@"window-padding-color",
|
.padding_color = config.@"window-padding-color",
|
||||||
|
|
||||||
.selection_background = if (config.@"selection-background") |bg|
|
.selection_background = config.@"selection-background",
|
||||||
bg.toTerminalRGB()
|
.selection_foreground = config.@"selection-foreground",
|
||||||
else
|
|
||||||
null,
|
|
||||||
|
|
||||||
.selection_foreground = if (config.@"selection-foreground") |bg|
|
|
||||||
bg.toTerminalRGB()
|
|
||||||
else
|
|
||||||
null,
|
|
||||||
|
|
||||||
.custom_shaders = custom_shaders,
|
.custom_shaders = custom_shaders,
|
||||||
.bg_image = bg_image,
|
.bg_image = bg_image,
|
||||||
@ -703,7 +676,6 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
|
|||||||
.default_background_color = options.config.background,
|
.default_background_color = options.config.background,
|
||||||
.cursor_color = null,
|
.cursor_color = null,
|
||||||
.default_cursor_color = options.config.cursor_color,
|
.default_cursor_color = options.config.cursor_color,
|
||||||
.cursor_invert = options.config.cursor_invert,
|
|
||||||
|
|
||||||
// Render state
|
// Render state
|
||||||
.cells = .{},
|
.cells = .{},
|
||||||
@ -2079,8 +2051,7 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
|
|||||||
// Set our new colors
|
// Set our new colors
|
||||||
self.default_background_color = config.background;
|
self.default_background_color = config.background;
|
||||||
self.default_foreground_color = config.foreground;
|
self.default_foreground_color = config.foreground;
|
||||||
self.default_cursor_color = if (!config.cursor_invert) config.cursor_color else null;
|
self.default_cursor_color = config.cursor_color;
|
||||||
self.cursor_invert = config.cursor_invert;
|
|
||||||
|
|
||||||
const bg_image_config_changed =
|
const bg_image_config_changed =
|
||||||
self.config.bg_image_fit != config.bg_image_fit or
|
self.config.bg_image_fit != config.bg_image_fit or
|
||||||
@ -2577,28 +2548,31 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
|
|||||||
else
|
else
|
||||||
false;
|
false;
|
||||||
|
|
||||||
|
// The `_style` suffixed values are the colors based on
|
||||||
|
// the cell style (SGR), before applying any additional
|
||||||
|
// configuration, inversions, selections, etc.
|
||||||
const bg_style = style.bg(cell, color_palette);
|
const bg_style = style.bg(cell, color_palette);
|
||||||
const fg_style = style.fg(color_palette, self.config.bold_is_bright) orelse self.foreground_color orelse self.default_foreground_color;
|
const fg_style = style.fg(
|
||||||
|
color_palette,
|
||||||
|
self.config.bold_is_bright,
|
||||||
|
) orelse self.foreground_color orelse self.default_foreground_color;
|
||||||
|
|
||||||
// The final background color for the cell.
|
// The final background color for the cell.
|
||||||
const bg = bg: {
|
const bg = bg: {
|
||||||
if (selected) {
|
if (selected) {
|
||||||
break :bg if (self.config.invert_selection_fg_bg)
|
// If we have an explicit selection background color
|
||||||
if (style.flags.inverse)
|
// specified int he config, use that
|
||||||
// Cell is selected with invert selection fg/bg
|
if (self.config.selection_background) |v| {
|
||||||
// enabled, and the cell has the inverse style
|
break :bg switch (v) {
|
||||||
// flag, so they cancel out and we get the normal
|
.color => |color| color.toTerminalRGB(),
|
||||||
// bg color.
|
.@"cell-foreground" => if (style.flags.inverse) bg_style else fg_style,
|
||||||
bg_style
|
.@"cell-background" => if (style.flags.inverse) fg_style else bg_style,
|
||||||
else
|
};
|
||||||
// If it doesn't have the inverse style
|
}
|
||||||
// flag then we use the fg color instead.
|
|
||||||
fg_style
|
// If no configuration, then our selection background
|
||||||
else
|
// is our foreground color.
|
||||||
// If we don't have invert selection fg/bg set then we
|
break :bg self.foreground_color orelse self.default_foreground_color;
|
||||||
// just use the selection background if set, otherwise
|
|
||||||
// the default fg color.
|
|
||||||
break :bg self.config.selection_background orelse self.foreground_color orelse self.default_foreground_color;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not selected
|
// Not selected
|
||||||
@ -2618,20 +2592,31 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const fg = fg: {
|
const fg = fg: {
|
||||||
if (selected and !self.config.invert_selection_fg_bg) {
|
// Our happy-path non-selection background color
|
||||||
// If we don't have invert selection fg/bg set
|
// is our style or our configured defaults.
|
||||||
// then we just use the selection foreground if
|
const final_bg = bg_style orelse
|
||||||
// set, otherwise the default bg color.
|
self.background_color orelse
|
||||||
break :fg self.config.selection_foreground orelse self.background_color orelse self.default_background_color;
|
self.default_background_color;
|
||||||
}
|
|
||||||
|
|
||||||
// Whether we need to use the bg color as our fg color:
|
// Whether we need to use the bg color as our fg color:
|
||||||
|
// - Cell is selected, inverted, and set to cell-foreground
|
||||||
|
// - Cell is selected, not inverted, and set to cell-background
|
||||||
// - Cell is inverted and not selected
|
// - Cell is inverted and not selected
|
||||||
// - Cell is selected and not inverted
|
if (selected) {
|
||||||
// Note: if selected then invert sel fg / bg must be
|
// Use the selection foreground if set
|
||||||
// false since we separately handle it if true above.
|
if (self.config.selection_foreground) |v| {
|
||||||
break :fg if (style.flags.inverse != selected)
|
break :fg switch (v) {
|
||||||
bg_style orelse self.background_color orelse self.default_background_color
|
.color => |color| color.toTerminalRGB(),
|
||||||
|
.@"cell-foreground" => if (style.flags.inverse) final_bg else fg_style,
|
||||||
|
.@"cell-background" => if (style.flags.inverse) fg_style else final_bg,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
break :fg self.background_color orelse self.default_background_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
break :fg if (style.flags.inverse)
|
||||||
|
final_bg
|
||||||
else
|
else
|
||||||
fg_style;
|
fg_style;
|
||||||
};
|
};
|
||||||
@ -2817,18 +2802,35 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
|
|||||||
|
|
||||||
// Prepare the cursor cell contents.
|
// Prepare the cursor cell contents.
|
||||||
const style = cursor_style_ orelse break :cursor;
|
const style = cursor_style_ orelse break :cursor;
|
||||||
const cursor_color = self.cursor_color orelse self.default_cursor_color orelse color: {
|
const cursor_color = cursor_color: {
|
||||||
if (self.cursor_invert) {
|
// If an explicit cursor color was set by OSC 12, use that.
|
||||||
// Use the foreground color from the cell under the cursor, if any.
|
if (self.cursor_color) |v| break :cursor_color v;
|
||||||
const sty = screen.cursor.page_pin.style(screen.cursor.page_cell);
|
|
||||||
break :color if (sty.flags.inverse)
|
// Use our configured color if specified
|
||||||
// If the cell is reversed, use background color instead.
|
if (self.default_cursor_color) |v| switch (v) {
|
||||||
(sty.bg(screen.cursor.page_cell, color_palette) orelse self.background_color orelse self.default_background_color)
|
.color => |color| break :cursor_color color.toTerminalRGB(),
|
||||||
else
|
inline .@"cell-foreground",
|
||||||
(sty.fg(color_palette, self.config.bold_is_bright) orelse self.foreground_color orelse self.default_foreground_color);
|
.@"cell-background",
|
||||||
} else {
|
=> |_, tag| {
|
||||||
break :color self.foreground_color orelse self.default_foreground_color;
|
const sty = screen.cursor.page_pin.style(screen.cursor.page_cell);
|
||||||
}
|
const fg_style = sty.fg(
|
||||||
|
color_palette,
|
||||||
|
self.config.bold_is_bright,
|
||||||
|
) orelse self.foreground_color orelse self.default_foreground_color;
|
||||||
|
const bg_style = sty.bg(
|
||||||
|
screen.cursor.page_cell,
|
||||||
|
color_palette,
|
||||||
|
) orelse self.background_color orelse self.default_background_color;
|
||||||
|
|
||||||
|
break :cursor_color switch (tag) {
|
||||||
|
.color => unreachable,
|
||||||
|
.@"cell-foreground" => if (sty.flags.inverse) bg_style else fg_style,
|
||||||
|
.@"cell-background" => if (sty.flags.inverse) fg_style else bg_style,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
break :cursor_color self.foreground_color orelse self.default_foreground_color;
|
||||||
};
|
};
|
||||||
|
|
||||||
self.addCursor(screen, style, cursor_color);
|
self.addCursor(screen, style, cursor_color);
|
||||||
@ -2853,18 +2855,25 @@ pub fn Renderer(comptime GraphicsAPI: type) type {
|
|||||||
.wide, .spacer_tail => true,
|
.wide, .spacer_tail => true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const uniform_color = if (self.cursor_invert) blk: {
|
const uniform_color = if (self.config.cursor_text) |txt| blk: {
|
||||||
// Use the background color from the cell under the cursor, if any.
|
// If cursor-text is set, then compute the correct color.
|
||||||
|
// Otherwise, use the background color.
|
||||||
|
if (txt == .color) {
|
||||||
|
// Use the color set by cursor-text, if any.
|
||||||
|
break :blk txt.color.toTerminalRGB();
|
||||||
|
}
|
||||||
|
|
||||||
const sty = screen.cursor.page_pin.style(screen.cursor.page_cell);
|
const sty = screen.cursor.page_pin.style(screen.cursor.page_cell);
|
||||||
break :blk if (sty.flags.inverse)
|
const fg_style = sty.fg(color_palette, self.config.bold_is_bright) orelse self.foreground_color orelse self.default_foreground_color;
|
||||||
// If the cell is reversed, use foreground color instead.
|
const bg_style = sty.bg(screen.cursor.page_cell, color_palette) orelse self.background_color orelse self.default_background_color;
|
||||||
(sty.fg(color_palette, self.config.bold_is_bright) orelse self.foreground_color orelse self.default_foreground_color)
|
|
||||||
else
|
break :blk switch (txt) {
|
||||||
(sty.bg(screen.cursor.page_cell, color_palette) orelse self.background_color orelse self.default_background_color);
|
// If the cell is reversed, use the opposite cell color instead.
|
||||||
} else if (self.config.cursor_text) |txt|
|
.@"cell-foreground" => if (sty.flags.inverse) bg_style else fg_style,
|
||||||
txt
|
.@"cell-background" => if (sty.flags.inverse) fg_style else bg_style,
|
||||||
else
|
else => unreachable,
|
||||||
self.background_color orelse self.default_background_color;
|
};
|
||||||
|
} else self.background_color orelse self.default_background_color;
|
||||||
|
|
||||||
self.uniforms.cursor_color = .{
|
self.uniforms.cursor_color = .{
|
||||||
uniform_color.r,
|
uniform_color.r,
|
||||||
|
@ -28,7 +28,7 @@ pub const Options = struct {
|
|||||||
/// MTLCommandBuffer
|
/// MTLCommandBuffer
|
||||||
buffer: objc.Object,
|
buffer: objc.Object,
|
||||||
|
|
||||||
block: CompletionBlock,
|
block: CompletionBlock.Context,
|
||||||
|
|
||||||
/// Begin encoding a frame.
|
/// Begin encoding a frame.
|
||||||
pub fn begin(
|
pub fn begin(
|
||||||
@ -47,7 +47,7 @@ pub fn begin(
|
|||||||
|
|
||||||
// Create our block to register for completion updates.
|
// Create our block to register for completion updates.
|
||||||
// The block is deallocated by the objC runtime on success.
|
// The block is deallocated by the objC runtime on success.
|
||||||
const block = try CompletionBlock.init(
|
const block = CompletionBlock.init(
|
||||||
.{
|
.{
|
||||||
.renderer = renderer,
|
.renderer = renderer,
|
||||||
.target = target,
|
.target = target,
|
||||||
@ -55,7 +55,6 @@ pub fn begin(
|
|||||||
},
|
},
|
||||||
&bufferCompleted,
|
&bufferCompleted,
|
||||||
);
|
);
|
||||||
errdefer block.deinit();
|
|
||||||
|
|
||||||
return .{ .buffer = buffer, .block = block };
|
return .{ .buffer = buffer, .block = block };
|
||||||
}
|
}
|
||||||
@ -114,24 +113,23 @@ pub inline fn complete(self: *Self, sync: bool) void {
|
|||||||
// If we don't need to complete synchronously,
|
// If we don't need to complete synchronously,
|
||||||
// we add our block as a completion handler.
|
// we add our block as a completion handler.
|
||||||
//
|
//
|
||||||
// It will be deallocated by the objc runtime on success.
|
// It will be copied when we add the handler, and then the
|
||||||
|
// copy will be deallocated by the objc runtime on success.
|
||||||
if (!sync) {
|
if (!sync) {
|
||||||
self.buffer.msgSend(
|
self.buffer.msgSend(
|
||||||
void,
|
void,
|
||||||
objc.sel("addCompletedHandler:"),
|
objc.sel("addCompletedHandler:"),
|
||||||
.{self.block.context},
|
.{&self.block},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.buffer.msgSend(void, objc.sel("commit"), .{});
|
self.buffer.msgSend(void, objc.sel("commit"), .{});
|
||||||
|
|
||||||
// If we need to complete synchronously, we wait until
|
// If we need to complete synchronously, we wait until
|
||||||
// the buffer is completed and call the callback directly,
|
// the buffer is completed and invoke the block directly.
|
||||||
// deiniting the block after we're done.
|
|
||||||
if (sync) {
|
if (sync) {
|
||||||
self.buffer.msgSend(void, "waitUntilCompleted", .{});
|
self.buffer.msgSend(void, "waitUntilCompleted", .{});
|
||||||
self.block.context.sync = true;
|
self.block.sync = true;
|
||||||
bufferCompleted(self.block.context, self.buffer.value);
|
CompletionBlock.invoke(&self.block, .{self.buffer.value});
|
||||||
self.block.deinit();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,13 +54,11 @@ pub inline fn setSurface(self: *IOSurfaceLayer, surface: *IOSurface) !void {
|
|||||||
//
|
//
|
||||||
// We release in the callback after setting the contents.
|
// We release in the callback after setting the contents.
|
||||||
surface.retain();
|
surface.retain();
|
||||||
// We also need to retain the layer itself to make sure it
|
// NOTE: Since `self.layer` is passed as an `objc.c.id`, it's
|
||||||
// isn't destroyed before the callback completes, since if
|
// automatically retained when the block is copied, so we
|
||||||
// that happens it will try to interact with a deallocated
|
// don't need to retain it ourselves like with the surface.
|
||||||
// object.
|
|
||||||
_ = self.layer.retain();
|
|
||||||
|
|
||||||
var block = try SetSurfaceBlock.init(.{
|
var block = SetSurfaceBlock.init(.{
|
||||||
.layer = self.layer.value,
|
.layer = self.layer.value,
|
||||||
.surface = surface,
|
.surface = surface,
|
||||||
}, &setSurfaceCallback);
|
}, &setSurfaceCallback);
|
||||||
@ -68,15 +66,15 @@ pub inline fn setSurface(self: *IOSurfaceLayer, surface: *IOSurface) !void {
|
|||||||
// We check if we're on the main thread and run the block directly if so.
|
// We check if we're on the main thread and run the block directly if so.
|
||||||
const NSThread = objc.getClass("NSThread").?;
|
const NSThread = objc.getClass("NSThread").?;
|
||||||
if (NSThread.msgSend(bool, "isMainThread", .{})) {
|
if (NSThread.msgSend(bool, "isMainThread", .{})) {
|
||||||
setSurfaceCallback(block.context);
|
setSurfaceCallback(&block);
|
||||||
block.deinit();
|
|
||||||
} else {
|
} else {
|
||||||
// NOTE: The block will automatically be deallocated by the objc
|
// NOTE: The block will be copied when we pass it to dispatch_async,
|
||||||
// runtime once it's executed, so there's no need to deinit it.
|
// and then automatically be deallocated by the objc runtime
|
||||||
|
// once it's executed.
|
||||||
|
|
||||||
macos.dispatch.dispatch_async(
|
macos.dispatch.dispatch_async(
|
||||||
@ptrCast(macos.dispatch.queue.getMain()),
|
@ptrCast(macos.dispatch.queue.getMain()),
|
||||||
@ptrCast(block.context),
|
@ptrCast(&block),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -100,10 +98,7 @@ fn setSurfaceCallback(
|
|||||||
const surface: *IOSurface = block.surface;
|
const surface: *IOSurface = block.surface;
|
||||||
|
|
||||||
// See explanation of why we retain and release in `setSurface`.
|
// See explanation of why we retain and release in `setSurface`.
|
||||||
defer {
|
defer surface.release();
|
||||||
surface.release();
|
|
||||||
layer.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
// We check to see if the surface is the appropriate size for
|
// We check to see if the surface is the appropriate size for
|
||||||
// the layer, if it's not then we discard it. This is because
|
// the layer, if it's not then we discard it. This is because
|
||||||
|
@ -68,7 +68,7 @@ pub fn init(opts: Options) !Self {
|
|||||||
const id_init = id_alloc.msgSend(objc.Object, objc.sel("init"), .{});
|
const id_init = id_alloc.msgSend(objc.Object, objc.sel("init"), .{});
|
||||||
break :init id_init;
|
break :init id_init;
|
||||||
};
|
};
|
||||||
errdefer desc.msgSend(void, objc.sel("release"), .{});
|
defer desc.release();
|
||||||
|
|
||||||
// Set our properties
|
// Set our properties
|
||||||
desc.setProperty("width", @as(c_ulong, @intCast(opts.width)));
|
desc.setProperty("width", @as(c_ulong, @intCast(opts.width)));
|
||||||
|
@ -50,7 +50,7 @@ pub fn init(
|
|||||||
const id_init = id_alloc.msgSend(objc.Object, objc.sel("init"), .{});
|
const id_init = id_alloc.msgSend(objc.Object, objc.sel("init"), .{});
|
||||||
break :init id_init;
|
break :init id_init;
|
||||||
};
|
};
|
||||||
errdefer desc.msgSend(void, objc.sel("release"), .{});
|
defer desc.release();
|
||||||
|
|
||||||
// Set our properties
|
// Set our properties
|
||||||
desc.setProperty("pixelFormat", @intFromEnum(opts.pixel_format));
|
desc.setProperty("pixelFormat", @intFromEnum(opts.pixel_format));
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#include "common.glsl"
|
#include "common.glsl"
|
||||||
|
|
||||||
// Position the origin to the upper left
|
// Position the origin to the upper left
|
||||||
layout(origin_upper_left, pixel_center_integer) in vec4 gl_FragCoord;
|
layout(origin_upper_left) in vec4 gl_FragCoord;
|
||||||
|
|
||||||
// Must declare this output for some versions of OpenGL.
|
// Must declare this output for some versions of OpenGL.
|
||||||
layout(location = 0) out vec4 out_FragColor;
|
layout(location = 0) out vec4 out_FragColor;
|
||||||
|
@ -90,15 +90,13 @@ pub fn threadEnter(
|
|||||||
// Start our subprocess
|
// Start our subprocess
|
||||||
const pty_fds = self.subprocess.start(alloc) catch |err| {
|
const pty_fds = self.subprocess.start(alloc) catch |err| {
|
||||||
// If we specifically got this error then we are in the forked
|
// If we specifically got this error then we are in the forked
|
||||||
// process and our child failed to execute. In that case
|
// process and our child failed to execute. If we DIDN'T
|
||||||
if (err != error.Termio) return err;
|
// get this specific error then we're in the parent and
|
||||||
|
// we need to bubble it up.
|
||||||
|
if (err != error.ExecFailedInChild) return err;
|
||||||
|
|
||||||
// Output an error message about the exec faililng and exit.
|
// We're in the child. Nothing more we can do but abnormal exit.
|
||||||
// This generally should NOT happen because we always wrap
|
// The Command will output some additional information.
|
||||||
// our command execution either in login (macOS) or /bin/sh
|
|
||||||
// (Linux) which are usually guaranteed to exist. Still, we
|
|
||||||
// want to handle this scenario.
|
|
||||||
execFailedInChild() catch {};
|
|
||||||
posix.exit(1);
|
posix.exit(1);
|
||||||
};
|
};
|
||||||
errdefer self.subprocess.stop();
|
errdefer self.subprocess.stop();
|
||||||
@ -272,25 +270,6 @@ pub fn resize(
|
|||||||
return try self.subprocess.resize(grid_size, screen_size);
|
return try self.subprocess.resize(grid_size, screen_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This outputs an error message when exec failed and we are the
|
|
||||||
/// child process. This returns so the caller should probably exit
|
|
||||||
/// after calling this.
|
|
||||||
///
|
|
||||||
/// Note that this usually is only called under very very rare
|
|
||||||
/// circumstances because we wrap our command execution in login
|
|
||||||
/// (macOS) or /bin/sh (Linux). So this output can be pretty crude
|
|
||||||
/// because it should never happen. Notably, this is not the error
|
|
||||||
/// users see when `command` is invalid.
|
|
||||||
fn execFailedInChild() !void {
|
|
||||||
const stderr = std.io.getStdErr().writer();
|
|
||||||
try stderr.writeAll("exec failed\n");
|
|
||||||
try stderr.writeAll("press any key to exit\n");
|
|
||||||
|
|
||||||
var buf: [1]u8 = undefined;
|
|
||||||
var reader = std.io.getStdIn().reader();
|
|
||||||
_ = try reader.read(&buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn processExitCommon(td: *termio.Termio.ThreadData, exit_code: u32) void {
|
fn processExitCommon(td: *termio.Termio.ThreadData, exit_code: u32) void {
|
||||||
assert(td.backend == .exec);
|
assert(td.backend == .exec);
|
||||||
const execdata = &td.backend.exec;
|
const execdata = &td.backend.exec;
|
||||||
@ -847,6 +826,15 @@ const Subprocess = struct {
|
|||||||
else
|
else
|
||||||
null;
|
null;
|
||||||
|
|
||||||
|
// Propagate the current working directory (CWD) to the shell, enabling
|
||||||
|
// the shell to display the current directory name rather than the
|
||||||
|
// resolved path for symbolic links. This is important and based
|
||||||
|
// on the same behavior in Konsole and Kitty (see the linked issues):
|
||||||
|
// https://bugs.kde.org/show_bug.cgi?id=242114
|
||||||
|
// https://github.com/kovidgoyal/kitty/issues/1595
|
||||||
|
// https://github.com/ghostty-org/ghostty/discussions/7769
|
||||||
|
if (cwd) |pwd| try env.put("PWD", pwd);
|
||||||
|
|
||||||
// If we have a cgroup, then we copy that into our arena so the
|
// If we have a cgroup, then we copy that into our arena so the
|
||||||
// memory remains valid when we start.
|
// memory remains valid when we start.
|
||||||
const linux_cgroup: Command.LinuxCgroup = cgroup: {
|
const linux_cgroup: Command.LinuxCgroup = cgroup: {
|
||||||
@ -886,6 +874,12 @@ const Subprocess = struct {
|
|||||||
} {
|
} {
|
||||||
assert(self.pty == null and self.command == null);
|
assert(self.pty == null and self.command == null);
|
||||||
|
|
||||||
|
// This function is funny because on POSIX systems it can
|
||||||
|
// fail in the forked process. This is flipped to true if
|
||||||
|
// we're in an error state in the forked process (child
|
||||||
|
// process).
|
||||||
|
var in_child: bool = false;
|
||||||
|
|
||||||
// Create our pty
|
// Create our pty
|
||||||
var pty = try Pty.open(.{
|
var pty = try Pty.open(.{
|
||||||
.ws_row = @intCast(self.grid_size.rows),
|
.ws_row = @intCast(self.grid_size.rows),
|
||||||
@ -894,14 +888,14 @@ const Subprocess = struct {
|
|||||||
.ws_ypixel = @intCast(self.screen_size.height),
|
.ws_ypixel = @intCast(self.screen_size.height),
|
||||||
});
|
});
|
||||||
self.pty = pty;
|
self.pty = pty;
|
||||||
errdefer {
|
errdefer if (!in_child) {
|
||||||
if (comptime builtin.os.tag != .windows) {
|
if (comptime builtin.os.tag != .windows) {
|
||||||
_ = posix.close(pty.slave);
|
_ = posix.close(pty.slave);
|
||||||
}
|
}
|
||||||
|
|
||||||
pty.deinit();
|
pty.deinit();
|
||||||
self.pty = null;
|
self.pty = null;
|
||||||
}
|
};
|
||||||
|
|
||||||
log.debug("starting command command={s}", .{self.args});
|
log.debug("starting command command={s}", .{self.args});
|
||||||
|
|
||||||
@ -1004,7 +998,22 @@ const Subprocess = struct {
|
|||||||
.data = self,
|
.data = self,
|
||||||
.linux_cgroup = self.linux_cgroup,
|
.linux_cgroup = self.linux_cgroup,
|
||||||
};
|
};
|
||||||
try cmd.start(alloc);
|
|
||||||
|
cmd.start(alloc) catch |err| {
|
||||||
|
// We have to do this because start on Windows can't
|
||||||
|
// ever return ExecFailedInChild
|
||||||
|
const StartError = error{ExecFailedInChild} || @TypeOf(err);
|
||||||
|
switch (@as(StartError, err)) {
|
||||||
|
// If we fail in our child we need to flag it so our
|
||||||
|
// errdefers don't run.
|
||||||
|
error.ExecFailedInChild => {
|
||||||
|
in_child = true;
|
||||||
|
return err;
|
||||||
|
},
|
||||||
|
|
||||||
|
else => return err,
|
||||||
|
}
|
||||||
|
};
|
||||||
errdefer killCommand(&cmd) catch |err| {
|
errdefer killCommand(&cmd) catch |err| {
|
||||||
log.warn("error killing command during cleanup err={}", .{err});
|
log.warn("error killing command during cleanup err={}", .{err});
|
||||||
};
|
};
|
||||||
|
@ -163,8 +163,7 @@ pub const DerivedConfig = struct {
|
|||||||
image_storage_limit: usize,
|
image_storage_limit: usize,
|
||||||
cursor_style: terminalpkg.CursorStyle,
|
cursor_style: terminalpkg.CursorStyle,
|
||||||
cursor_blink: ?bool,
|
cursor_blink: ?bool,
|
||||||
cursor_color: ?configpkg.Config.Color,
|
cursor_color: ?configpkg.Config.TerminalColor,
|
||||||
cursor_invert: bool,
|
|
||||||
foreground: configpkg.Config.Color,
|
foreground: configpkg.Config.Color,
|
||||||
background: configpkg.Config.Color,
|
background: configpkg.Config.Color,
|
||||||
osc_color_report_format: configpkg.Config.OSCColorReportFormat,
|
osc_color_report_format: configpkg.Config.OSCColorReportFormat,
|
||||||
@ -185,7 +184,6 @@ pub const DerivedConfig = struct {
|
|||||||
.cursor_style = config.@"cursor-style",
|
.cursor_style = config.@"cursor-style",
|
||||||
.cursor_blink = config.@"cursor-style-blink",
|
.cursor_blink = config.@"cursor-style-blink",
|
||||||
.cursor_color = config.@"cursor-color",
|
.cursor_color = config.@"cursor-color",
|
||||||
.cursor_invert = config.@"cursor-invert-fg-bg",
|
|
||||||
.foreground = config.foreground,
|
.foreground = config.foreground,
|
||||||
.background = config.background,
|
.background = config.background,
|
||||||
.osc_color_report_format = config.@"osc-color-report-format",
|
.osc_color_report_format = config.@"osc-color-report-format",
|
||||||
@ -265,10 +263,16 @@ pub fn init(self: *Termio, alloc: Allocator, opts: termio.Options) !void {
|
|||||||
// Create our stream handler. This points to memory in self so it
|
// Create our stream handler. This points to memory in self so it
|
||||||
// isn't safe to use until self.* is set.
|
// isn't safe to use until self.* is set.
|
||||||
const handler: StreamHandler = handler: {
|
const handler: StreamHandler = handler: {
|
||||||
const default_cursor_color = if (!opts.config.cursor_invert and opts.config.cursor_color != null)
|
const default_cursor_color: ?terminalpkg.color.RGB = color: {
|
||||||
opts.config.cursor_color.?.toTerminalRGB()
|
if (opts.config.cursor_color) |color| switch (color) {
|
||||||
else
|
.color => break :color color.color.toTerminalRGB(),
|
||||||
null;
|
.@"cell-foreground",
|
||||||
|
.@"cell-background",
|
||||||
|
=> {},
|
||||||
|
};
|
||||||
|
|
||||||
|
break :color null;
|
||||||
|
};
|
||||||
|
|
||||||
break :handler .{
|
break :handler .{
|
||||||
.alloc = alloc,
|
.alloc = alloc,
|
||||||
|
@ -121,10 +121,16 @@ pub const StreamHandler = struct {
|
|||||||
self.default_background_color = config.background.toTerminalRGB();
|
self.default_background_color = config.background.toTerminalRGB();
|
||||||
self.default_cursor_style = config.cursor_style;
|
self.default_cursor_style = config.cursor_style;
|
||||||
self.default_cursor_blink = config.cursor_blink;
|
self.default_cursor_blink = config.cursor_blink;
|
||||||
self.default_cursor_color = if (!config.cursor_invert and config.cursor_color != null)
|
self.default_cursor_color = color: {
|
||||||
config.cursor_color.?.toTerminalRGB()
|
if (config.cursor_color) |color| switch (color) {
|
||||||
else
|
.color => break :color color.color.toTerminalRGB(),
|
||||||
null;
|
.@"cell-foreground",
|
||||||
|
.@"cell-background",
|
||||||
|
=> {},
|
||||||
|
};
|
||||||
|
|
||||||
|
break :color null;
|
||||||
|
};
|
||||||
|
|
||||||
// If our cursor is the default, then we update it immediately.
|
// If our cursor is the default, then we update it immediately.
|
||||||
if (self.default_cursor) self.setCursorStyle(.default) catch |err| {
|
if (self.default_cursor) self.setCursorStyle(.default) catch |err| {
|
||||||
|
Reference in New Issue
Block a user