Merge branch 'main' into jacob/zg

This commit is contained in:
Jacob Sandlund
2025-07-09 19:18:19 -04:00
69 changed files with 4858 additions and 1017 deletions

View File

@ -147,14 +147,16 @@ jobs:
- name: "Notarize app bundle"
env:
PROD_MACOS_NOTARIZATION_APPLE_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_APPLE_ID }}
PROD_MACOS_NOTARIZATION_TEAM_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_TEAM_ID }}
PROD_MACOS_NOTARIZATION_PWD: ${{ secrets.PROD_MACOS_NOTARIZATION_PWD }}
APPLE_NOTARIZATION_ISSUER: ${{ secrets.APPLE_NOTARIZATION_ISSUER }}
APPLE_NOTARIZATION_KEY_ID: ${{ secrets.APPLE_NOTARIZATION_KEY_ID }}
APPLE_NOTARIZATION_KEY: ${{ secrets.APPLE_NOTARIZATION_KEY }}
run: |
# Store the notarization credentials so that we can prevent a UI password dialog
# from blocking the CI
echo "Create keychain profile"
xcrun notarytool store-credentials "notarytool-profile" --apple-id "$PROD_MACOS_NOTARIZATION_APPLE_ID" --team-id "$PROD_MACOS_NOTARIZATION_TEAM_ID" --password "$PROD_MACOS_NOTARIZATION_PWD"
echo "$APPLE_NOTARIZATION_KEY" > notarization_key.p8
xcrun notarytool store-credentials "notarytool-profile" --key notarization_key.p8 --key-id "$APPLE_NOTARIZATION_KEY_ID" --issuer "$APPLE_NOTARIZATION_ISSUER"
rm notarization_key.p8
# We can't notarize an app bundle directly, but we need to compress it as an archive.
# Therefore, we create a zip file containing our app bundle, so that we can send it to the
@ -299,14 +301,16 @@ jobs:
- name: "Notarize app bundle"
env:
PROD_MACOS_NOTARIZATION_APPLE_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_APPLE_ID }}
PROD_MACOS_NOTARIZATION_TEAM_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_TEAM_ID }}
PROD_MACOS_NOTARIZATION_PWD: ${{ secrets.PROD_MACOS_NOTARIZATION_PWD }}
APPLE_NOTARIZATION_ISSUER: ${{ secrets.APPLE_NOTARIZATION_ISSUER }}
APPLE_NOTARIZATION_KEY_ID: ${{ secrets.APPLE_NOTARIZATION_KEY_ID }}
APPLE_NOTARIZATION_KEY: ${{ secrets.APPLE_NOTARIZATION_KEY }}
run: |
# Store the notarization credentials so that we can prevent a UI password dialog
# from blocking the CI
echo "Create keychain profile"
xcrun notarytool store-credentials "notarytool-profile" --apple-id "$PROD_MACOS_NOTARIZATION_APPLE_ID" --team-id "$PROD_MACOS_NOTARIZATION_TEAM_ID" --password "$PROD_MACOS_NOTARIZATION_PWD"
echo "$APPLE_NOTARIZATION_KEY" > notarization_key.p8
xcrun notarytool store-credentials "notarytool-profile" --key notarization_key.p8 --key-id "$APPLE_NOTARIZATION_KEY_ID" --issuer "$APPLE_NOTARIZATION_ISSUER"
rm notarization_key.p8
# We can't notarize an app bundle directly, but we need to compress it as an archive.
# Therefore, we create a zip file containing our app bundle, so that we can send it to the

View File

@ -229,14 +229,16 @@ jobs:
- name: "Notarize DMG"
env:
PROD_MACOS_NOTARIZATION_APPLE_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_APPLE_ID }}
PROD_MACOS_NOTARIZATION_TEAM_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_TEAM_ID }}
PROD_MACOS_NOTARIZATION_PWD: ${{ secrets.PROD_MACOS_NOTARIZATION_PWD }}
APPLE_NOTARIZATION_ISSUER: ${{ secrets.APPLE_NOTARIZATION_ISSUER }}
APPLE_NOTARIZATION_KEY_ID: ${{ secrets.APPLE_NOTARIZATION_KEY_ID }}
APPLE_NOTARIZATION_KEY: ${{ secrets.APPLE_NOTARIZATION_KEY }}
run: |
# Store the notarization credentials so that we can prevent a UI password dialog
# from blocking the CI
echo "Create keychain profile"
xcrun notarytool store-credentials "notarytool-profile" --apple-id "$PROD_MACOS_NOTARIZATION_APPLE_ID" --team-id "$PROD_MACOS_NOTARIZATION_TEAM_ID" --password "$PROD_MACOS_NOTARIZATION_PWD"
echo "$APPLE_NOTARIZATION_KEY" > notarization_key.p8
xcrun notarytool store-credentials "notarytool-profile" --key notarization_key.p8 --key-id "$APPLE_NOTARIZATION_KEY_ID" --issuer "$APPLE_NOTARIZATION_ISSUER"
rm notarization_key.p8
# Here we send the notarization request to the Apple's Notarization service, waiting for the result.
# This typically takes a few seconds inside a CI environment, but it might take more depending on the App

View File

@ -267,14 +267,16 @@ jobs:
- name: "Notarize DMG"
env:
PROD_MACOS_NOTARIZATION_APPLE_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_APPLE_ID }}
PROD_MACOS_NOTARIZATION_TEAM_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_TEAM_ID }}
PROD_MACOS_NOTARIZATION_PWD: ${{ secrets.PROD_MACOS_NOTARIZATION_PWD }}
APPLE_NOTARIZATION_ISSUER: ${{ secrets.APPLE_NOTARIZATION_ISSUER }}
APPLE_NOTARIZATION_KEY_ID: ${{ secrets.APPLE_NOTARIZATION_KEY_ID }}
APPLE_NOTARIZATION_KEY: ${{ secrets.APPLE_NOTARIZATION_KEY }}
run: |
# Store the notarization credentials so that we can prevent a UI password dialog
# from blocking the CI
echo "Create keychain profile"
xcrun notarytool store-credentials "notarytool-profile" --apple-id "$PROD_MACOS_NOTARIZATION_APPLE_ID" --team-id "$PROD_MACOS_NOTARIZATION_TEAM_ID" --password "$PROD_MACOS_NOTARIZATION_PWD"
echo "$APPLE_NOTARIZATION_KEY" > notarization_key.p8
xcrun notarytool store-credentials "notarytool-profile" --key notarization_key.p8 --key-id "$APPLE_NOTARIZATION_KEY_ID" --issuer "$APPLE_NOTARIZATION_ISSUER"
rm notarization_key.p8
# Here we send the notarization request to the Apple's Notarization service, waiting for the result.
# This typically takes a few seconds inside a CI environment, but it might take more depending on the App
@ -471,14 +473,16 @@ jobs:
- name: "Notarize app bundle"
env:
PROD_MACOS_NOTARIZATION_APPLE_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_APPLE_ID }}
PROD_MACOS_NOTARIZATION_TEAM_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_TEAM_ID }}
PROD_MACOS_NOTARIZATION_PWD: ${{ secrets.PROD_MACOS_NOTARIZATION_PWD }}
APPLE_NOTARIZATION_ISSUER: ${{ secrets.APPLE_NOTARIZATION_ISSUER }}
APPLE_NOTARIZATION_KEY_ID: ${{ secrets.APPLE_NOTARIZATION_KEY_ID }}
APPLE_NOTARIZATION_KEY: ${{ secrets.APPLE_NOTARIZATION_KEY }}
run: |
# Store the notarization credentials so that we can prevent a UI password dialog
# from blocking the CI
echo "Create keychain profile"
xcrun notarytool store-credentials "notarytool-profile" --apple-id "$PROD_MACOS_NOTARIZATION_APPLE_ID" --team-id "$PROD_MACOS_NOTARIZATION_TEAM_ID" --password "$PROD_MACOS_NOTARIZATION_PWD"
echo "$APPLE_NOTARIZATION_KEY" > notarization_key.p8
xcrun notarytool store-credentials "notarytool-profile" --key notarization_key.p8 --key-id "$APPLE_NOTARIZATION_KEY_ID" --issuer "$APPLE_NOTARIZATION_ISSUER"
rm notarization_key.p8
# We can't notarize an app bundle directly, but we need to compress it as an archive.
# Therefore, we create a zip file containing our app bundle, so that we can send it to the
@ -646,14 +650,16 @@ jobs:
- name: "Notarize app bundle"
env:
PROD_MACOS_NOTARIZATION_APPLE_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_APPLE_ID }}
PROD_MACOS_NOTARIZATION_TEAM_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_TEAM_ID }}
PROD_MACOS_NOTARIZATION_PWD: ${{ secrets.PROD_MACOS_NOTARIZATION_PWD }}
APPLE_NOTARIZATION_ISSUER: ${{ secrets.APPLE_NOTARIZATION_ISSUER }}
APPLE_NOTARIZATION_KEY_ID: ${{ secrets.APPLE_NOTARIZATION_KEY_ID }}
APPLE_NOTARIZATION_KEY: ${{ secrets.APPLE_NOTARIZATION_KEY }}
run: |
# Store the notarization credentials so that we can prevent a UI password dialog
# from blocking the CI
echo "Create keychain profile"
xcrun notarytool store-credentials "notarytool-profile" --apple-id "$PROD_MACOS_NOTARIZATION_APPLE_ID" --team-id "$PROD_MACOS_NOTARIZATION_TEAM_ID" --password "$PROD_MACOS_NOTARIZATION_PWD"
echo "$APPLE_NOTARIZATION_KEY" > notarization_key.p8
xcrun notarytool store-credentials "notarytool-profile" --key notarization_key.p8 --key-id "$APPLE_NOTARIZATION_KEY_ID" --issuer "$APPLE_NOTARIZATION_ISSUER"
rm notarization_key.p8
# We can't notarize an app bundle directly, but we need to compress it as an archive.
# Therefore, we create a zip file containing our app bundle, so that we can send it to the

View File

@ -561,7 +561,16 @@ jobs:
name: ghostty
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
- name: Test GTK Build
- name: Test
run: |
nix develop -c \
zig build \
-Dapp-runtime=gtk \
-Dgtk-x11=${{ matrix.x11 }} \
-Dgtk-wayland=${{ matrix.wayland }} \
test
- name: Build
run: |
nix develop -c \
zig build \

View File

@ -181,6 +181,7 @@
/po/zh_CN.UTF-8.po @ghostty-org/zh_CN
/po/ga_IE.UTF-8.po @ghostty-org/ga_IE
/po/ko_KR.UTF-8.po @ghostty-org/ko_KR
/po/he_IL.UTF-8.po @ghostty-org/he_IL
# Packaging - Snap
/snap/ @ghostty-org/snap

View File

@ -1,9 +1,12 @@
[Unit]
Description=@NAME@
After=graphical-session.target
After=dbus.socket
Requires=dbus.socket
[Service]
Type=dbus
Type=notify-reload
ReloadSignal=SIGUSR2
BusName=@APPID@
ExecStart=@GHOSTTY@ --launched-from=systemd

View File

@ -350,6 +350,11 @@ typedef struct {
const char* message;
} ghostty_diagnostic_s;
typedef struct {
const char* ptr;
uintptr_t len;
} ghostty_string_s;
typedef struct {
double tl_px_x;
double tl_px_y;
@ -797,6 +802,7 @@ int ghostty_init(uintptr_t, char**);
void ghostty_cli_try_action(void);
ghostty_info_s ghostty_info(void);
const char* ghostty_translate(const char*);
void ghostty_string_free(ghostty_string_s);
ghostty_config_t ghostty_config_new();
void ghostty_config_free(ghostty_config_t);
@ -811,7 +817,7 @@ ghostty_input_trigger_s ghostty_config_trigger(ghostty_config_t,
uintptr_t);
uint32_t ghostty_config_diagnostics_count(ghostty_config_t);
ghostty_diagnostic_s ghostty_config_get_diagnostic(ghostty_config_t, uint32_t);
void ghostty_config_open();
ghostty_string_s ghostty_config_open_path(void);
ghostty_app_t ghostty_app_new(const ghostty_runtime_config_s*,
ghostty_config_t);

View File

@ -14,6 +14,7 @@
9351BE8E3D22937F003B3499 /* nvim in Resources */ = {isa = PBXBuildFile; fileRef = 9351BE8E2D22937F003B3499 /* nvim */; };
A50297352DFA0F3400B4E924 /* Double+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A50297342DFA0F3300B4E924 /* Double+Extension.swift */; };
A505D21D2E1A2FA20018808F /* FileHandle+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A505D21C2E1A2F9E0018808F /* FileHandle+Extension.swift */; };
A505D21F2E1B6DE00018808F /* NSWorkspace+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A505D21E2E1B6DDC0018808F /* NSWorkspace+Extension.swift */; };
A511940F2E050595007258CC /* CloseTerminalIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = A511940E2E050590007258CC /* CloseTerminalIntent.swift */; };
A51194112E05A483007258CC /* QuickTerminalIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51194102E05A480007258CC /* QuickTerminalIntent.swift */; };
A51194132E05D006007258CC /* Optional+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51194122E05D003007258CC /* Optional+Extension.swift */; };
@ -160,6 +161,7 @@
9351BE8E2D22937F003B3499 /* nvim */ = {isa = PBXFileReference; lastKnownFileType = folder; name = nvim; path = "../zig-out/share/nvim"; sourceTree = "<group>"; };
A50297342DFA0F3300B4E924 /* Double+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Double+Extension.swift"; sourceTree = "<group>"; };
A505D21C2E1A2F9E0018808F /* FileHandle+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileHandle+Extension.swift"; sourceTree = "<group>"; };
A505D21E2E1B6DDC0018808F /* NSWorkspace+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSWorkspace+Extension.swift"; sourceTree = "<group>"; };
A511940E2E050590007258CC /* CloseTerminalIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloseTerminalIntent.swift; sourceTree = "<group>"; };
A51194102E05A480007258CC /* QuickTerminalIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickTerminalIntent.swift; sourceTree = "<group>"; };
A51194122E05D003007258CC /* Optional+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Optional+Extension.swift"; sourceTree = "<group>"; };
@ -531,6 +533,7 @@
AEE8B3442B9AA39600260C5E /* NSPasteboard+Extension.swift */,
C1F26EA62B738B9900404083 /* NSView+Extension.swift */,
A5874D9C2DAD785F00E83852 /* NSWindow+Extension.swift */,
A505D21E2E1B6DDC0018808F /* NSWorkspace+Extension.swift */,
A5985CD62C320C4500C57AD3 /* String+Extension.swift */,
A58636722DF4813000E04A10 /* UndoManager+Extension.swift */,
A5CC36142C9CDA03004D6760 /* View+Extension.swift */,
@ -819,6 +822,7 @@
A5CC36152C9CDA06004D6760 /* View+Extension.swift in Sources */,
A56D58892ACDE6CA00508D2C /* ServiceProvider.swift in Sources */,
A5CBD0602CA0C90A0017A1AE /* QuickTerminalWindow.swift in Sources */,
A505D21F2E1B6DE00018808F /* NSWorkspace+Extension.swift in Sources */,
A5CBD05E2CA0C5EC0017A1AE /* QuickTerminalController.swift in Sources */,
A5CF66D72D29DDB500139794 /* Ghostty.Event.swift in Sources */,
A511940F2E050595007258CC /* CloseTerminalIntent.swift in Sources */,

View File

@ -932,7 +932,7 @@ class AppDelegate: NSObject,
//MARK: - IB Actions
@IBAction func openConfig(_ sender: Any?) {
ghostty.openConfig()
Ghostty.App.openConfig()
}
@IBAction func reloadConfig(_ sender: Any?) {

View File

@ -40,4 +40,34 @@ extension Ghostty.Action {
self.amount = c.amount
}
}
struct OpenURL {
enum Kind {
case unknown
case text
init(_ c: ghostty_action_open_url_kind_e) {
switch c {
case GHOSTTY_ACTION_OPEN_URL_KIND_TEXT:
self = .text
default:
self = .unknown
}
}
}
let kind: Kind
let url: String
init(c: ghostty_action_open_url_s) {
self.kind = Kind(c.kind)
if let urlCString = c.url {
let data = Data(bytes: urlCString, count: Int(c.len))
self.url = String(data: data, encoding: .utf8) ?? ""
} else {
self.url = ""
}
}
}
}

View File

@ -114,9 +114,21 @@ extension Ghostty {
ghostty_app_tick(app)
}
func openConfig() {
guard let app = self.app else { return }
ghostty_app_open_config(app)
static func openConfig() {
let str = Ghostty.AllocatedString(ghostty_config_open_path()).string
guard !str.isEmpty else { return }
#if os(macOS)
let fileURL = URL(fileURLWithPath: str).absoluteString
var action = ghostty_action_open_url_s()
action.kind = GHOSTTY_ACTION_OPEN_URL_KIND_TEXT
fileURL.withCString { cStr in
action.url = cStr
action.len = UInt(fileURL.count)
_ = openURL(action)
}
#else
fatalError("Unsupported platform for opening config file")
#endif
}
/// Reload the configuration.
@ -488,7 +500,7 @@ extension Ghostty {
pwdChanged(app, target: target, v: action.action.pwd)
case GHOSTTY_ACTION_OPEN_CONFIG:
ghostty_config_open()
openConfig()
case GHOSTTY_ACTION_FLOAT_WINDOW:
toggleFloatWindow(app, target: target, mode: action.action.float_window)
@ -546,6 +558,9 @@ extension Ghostty {
case GHOSTTY_ACTION_CHECK_FOR_UPDATES:
checkForUpdates(app)
case GHOSTTY_ACTION_OPEN_URL:
return openURL(action.action.open_url)
case GHOSTTY_ACTION_UNDO:
return undo(app, target: target)
@ -598,6 +613,34 @@ extension Ghostty {
appDelegate.checkForUpdates(nil)
}
}
private static func openURL(
_ v: ghostty_action_open_url_s
) -> Bool {
let action = Ghostty.Action.OpenURL(c: v)
// Convert the URL string to a URL object
guard let url = URL(string: action.url) else {
Ghostty.logger.warning("invalid URL for open URL action: \(action.url)")
return false
}
switch action.kind {
case .text:
// Open with the default text editor
if let textEditor = NSWorkspace.shared.defaultTextEditor {
NSWorkspace.shared.open([url], withApplicationAt: textEditor, configuration: NSWorkspace.OpenConfiguration())
return true
}
case .unknown:
break
}
// Open with the default application for the URL
NSWorkspace.shared.open(url)
return true
}
private static func undo(_ app: ghostty_app_t, target: ghostty_target_s) -> Bool {
let undoManager: UndoManager?

View File

@ -73,6 +73,26 @@ extension Ghostty {
// MARK: Swift Types for C Types
extension Ghostty {
class AllocatedString {
private let cString: ghostty_string_s
init(_ c: ghostty_string_s) {
self.cString = c
}
var string: String {
guard let ptr = cString.ptr else { return "" }
let data = Data(bytes: ptr, count: Int(cString.len))
return String(data: data, encoding: .utf8) ?? ""
}
deinit {
ghostty_string_free(cString)
}
}
}
extension Ghostty {
enum SetFloatWIndow {
case on

View File

@ -0,0 +1,29 @@
import AppKit
import UniformTypeIdentifiers
extension NSWorkspace {
/// Returns the URL of the default text editor application.
/// - Returns: The URL of the default text editor, or nil if no default text editor is found.
var defaultTextEditor: URL? {
defaultApplicationURL(forContentType: UTType.plainText.identifier)
}
/// Returns the URL of the default application for opening files with the specified content type.
/// - Parameter contentType: The content type identifier (UTI) to find the default application for.
/// - Returns: The URL of the default application, or nil if no default application is found.
func defaultApplicationURL(forContentType contentType: String) -> URL? {
return LSCopyDefaultApplicationURLForContentType(
contentType as CFString,
.all,
nil
)?.takeRetainedValue() as? URL
}
/// Returns the URL of the default application for opening files with the specified file extension.
/// - Parameter ext: The file extension to find the default application for.
/// - Returns: The URL of the default application, or nil if no default application is found.
func defaultApplicationURL(forExtension ext: String) -> URL? {
guard let uti = UTType(filenameExtension: ext) else { return nil}
return defaultApplicationURL(forContentType: uti.identifier)
}
}

View File

@ -7,7 +7,7 @@ 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"
"POT-Creation-Date: 2025-07-08 15:13-0500\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"
@ -26,7 +26,8 @@ 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
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/ui/1.2/ccw-paste.blp:10
#: src/apprt/gtk/CloseDialog.zig:44
msgid "Cancel"
msgstr "Отказ"
@ -35,22 +36,28 @@ msgid "OK"
msgstr "ОК"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
msgid "Configuration Errors"
msgstr "Грешки в конфигурацията"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
#: src/apprt/gtk/ui/1.2/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 "Открити са една или повече грешки в конфигурацията. Моля, прегледайте грешките по-долу и или презаредете конфигурацията си, или ги игнорирайте."
"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
#: src/apprt/gtk/ui/1.2/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
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
msgid "Reload Configuration"
msgstr "Презареди конфигурацията"
@ -89,7 +96,7 @@ 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
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11 src/apprt/gtk/ui/1.2/ccw-paste.blp:11
msgid "Paste"
msgstr "Постави"
@ -119,7 +126,7 @@ 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
#: src/apprt/gtk/Window.zig:265
msgid "New Tab"
msgstr "Нов раздел"
@ -160,7 +167,7 @@ msgid "Terminal Inspector"
msgstr "Инспектор на терминала"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
#: src/apprt/gtk/Window.zig:1024
#: src/apprt/gtk/Window.zig:1038
msgid "About Ghostty"
msgstr "За Ghostty"
@ -170,69 +177,64 @@ 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
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
msgid "Authorize Clipboard Access"
msgstr "Разрешаване на достъп до клипборда"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:7
msgid ""
"An application is attempting to read from the clipboard. The current "
"clipboard contents are shown below."
msgstr "Приложение се опитва да чете от клипборда. Текущото съдържание на клипборда е показано по-долу."
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
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.2/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
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:11
msgid "Allow"
msgstr "Позволи"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
msgid "Remember choice for this split"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
msgid "Reload configuration to show this prompt again"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
msgid ""
"An application is attempting to write to the clipboard. The current "
"clipboard contents are shown below."
msgstr "Приложение се опитва да запише в клипборда. Текущото съдържание на клипборда е показано по-долу."
msgstr ""
"Приложение се опитва да запише в клипборда. Текущото съдържание на клипборда "
"е показано по-долу."
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
msgid "Warning: Potentially Unsafe Paste"
msgstr "Предупреждение: Потенциално опасно поставяне"
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/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: Инспектор на терминала"
msgstr ""
"Поставянето на този текст в терминала може да е опасно, тъй като изглежда, "
"че може да бъдат изпълнени някои команди."
#: src/apprt/gtk/CloseDialog.zig:47
msgid "Close"
@ -270,6 +272,36 @@ msgstr "Всички терминални сесии в този раздел щ
msgid "The currently running process in this split will be terminated."
msgstr "Текущият процес в това разделяне ще бъде прекратен."
#: src/apprt/gtk/Surface.zig:1243
#: src/apprt/gtk/Surface.zig:1257
msgid "Copied to clipboard"
msgstr "Копирано в клипборда"
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"
msgstr "Главно меню"
#: src/apprt/gtk/Window.zig:239
msgid "View Open Tabs"
msgstr "Преглед на отворените раздели"
#: src/apprt/gtk/Window.zig:266
msgid "New Split"
msgstr "Ново разделяне"
#: src/apprt/gtk/Window.zig:329
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr ""
"⚠️ Използвате дебъг версия на Ghostty! Производителността ще бъде намалена."
#: src/apprt/gtk/Window.zig:775
msgid "Reloaded the configuration"
msgstr "Конфигурацията е презаредена"
#: src/apprt/gtk/Window.zig:1019
msgid "Ghostty Developers"
msgstr "Разработчици на Ghostty"
#: src/apprt/gtk/inspector.zig:144
msgid "Ghostty: Terminal Inspector"
msgstr "Ghostty: Инспектор на терминала"

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
"POT-Creation-Date: 2025-04-22 08:57-0700\n"
"POT-Creation-Date: 2025-07-08 15:13-0500\n"
"PO-Revision-Date: 2025-03-20 08:07+0100\n"
"Last-Translator: Francesc Arpi <francesc.arpi@gmail.com>\n"
"Language-Team: \n"
@ -26,7 +26,8 @@ msgid "Leave blank to restore the default title."
msgstr "Deixa en blanc per restaurar el títol per defecte."
#: 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
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/ui/1.2/ccw-paste.blp:10
#: src/apprt/gtk/CloseDialog.zig:44
msgid "Cancel"
msgstr "Cancel·la"
@ -35,10 +36,12 @@ msgid "OK"
msgstr "D'acord"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
msgid "Configuration Errors"
msgstr "Errors de configuració"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
#: src/apprt/gtk/ui/1.2/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."
@ -47,12 +50,14 @@ msgstr ""
"a continuació i torna a carregar la configuració o ignora aquests errors."
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:9
msgid "Ignore"
msgstr "Ignora"
#: 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:95
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:100
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
msgid "Reload Configuration"
msgstr "Carrega la configuració"
@ -80,6 +85,10 @@ msgstr "Divideix a l'esquerra"
msgid "Split Right"
msgstr "Divideix a la dreta"
#: 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"
@ -87,7 +96,7 @@ msgstr "Copia"
#: 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
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11 src/apprt/gtk/ui/1.2/ccw-paste.blp:11
msgid "Paste"
msgstr "Enganxa"
@ -117,7 +126,7 @@ msgstr "Pestanya"
#: 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:248
#: src/apprt/gtk/Window.zig:265
msgid "New Tab"
msgstr "Nova pestanya"
@ -145,29 +154,36 @@ msgid "Config"
msgstr "Configuració"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:92
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
msgid "Open Configuration"
msgstr "Obre la configuració"
#: 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 "Inspector de terminal"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:102
#: src/apprt/gtk/Window.zig:1003
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
#: src/apprt/gtk/Window.zig:1038
msgid "About Ghostty"
msgstr "Sobre Ghostty"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:112
msgid "Quit"
msgstr "Surt"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:6
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
msgid "Authorize Clipboard Access"
msgstr "Autoritza l'accés al porta-retalls"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:7
msgid ""
"An application is attempting to read from the clipboard. The current "
"clipboard contents are shown below."
@ -177,15 +193,30 @@ 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
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:10
msgid "Deny"
msgstr "Denegar"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:11
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:11
msgid "Allow"
msgstr "Permet"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
msgid "Remember choice for this split"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
msgid "Reload configuration to show this prompt again"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
msgid ""
"An application is attempting to write to the clipboard. The current "
"clipboard contents are shown below."
@ -193,11 +224,11 @@ msgstr ""
"Una aplicació està intentant escriure al porta-retalls. El contingut actual "
"del porta-retalls es mostra a continuació."
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
msgid "Warning: Potentially Unsafe Paste"
msgstr "Avís: Enganxament potencialment insegur"
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/ccw-paste.blp:7
msgid ""
"Pasting this text into the terminal may be dangerous as it looks like some "
"commands may be executed."
@ -205,33 +236,6 @@ msgstr ""
"Enganxar aquest text al terminal pot ser perillós, ja que sembla que es "
"podrien executar algunes ordres."
#: src/apprt/gtk/Window.zig:201
msgid "Main Menu"
msgstr "Menú principal"
#: src/apprt/gtk/Window.zig:222
msgid "View Open Tabs"
msgstr "Mostra les pestanyes obertes"
#: src/apprt/gtk/Window.zig:249
msgid "New Split"
msgstr ""
#: src/apprt/gtk/Window.zig:312
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr ""
"⚠️ Estàs executant una versió de depuració de Ghostty! El rendiment es veurà "
"afectat."
#: src/apprt/gtk/Window.zig:744
msgid "Reloaded the configuration"
msgstr "S'ha tornat a carregar la configuració"
#: src/apprt/gtk/Window.zig:984
msgid "Ghostty Developers"
msgstr "Desenvolupadors de Ghostty"
#: src/apprt/gtk/CloseDialog.zig:47
msgid "Close"
msgstr "Tanca"
@ -268,10 +272,37 @@ msgstr "Totes les sessions del terminal en aquesta pestanya es tancaran."
msgid "The currently running process in this split will be terminated."
msgstr "El procés actualment en execució en aquesta divisió es tancarà."
#: src/apprt/gtk/Surface.zig:1243
#: src/apprt/gtk/Surface.zig:1257
msgid "Copied to clipboard"
msgstr "Copiat al porta-retalls"
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"
msgstr "Menú principal"
#: src/apprt/gtk/Window.zig:239
msgid "View Open Tabs"
msgstr "Mostra les pestanyes obertes"
#: src/apprt/gtk/Window.zig:266
msgid "New Split"
msgstr ""
#: src/apprt/gtk/Window.zig:329
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr ""
"⚠️ Estàs executant una versió de depuració de Ghostty! El rendiment es veurà "
"afectat."
#: src/apprt/gtk/Window.zig:775
msgid "Reloaded the configuration"
msgstr "S'ha tornat a carregar la configuració"
#: src/apprt/gtk/Window.zig:1019
msgid "Ghostty Developers"
msgstr "Desenvolupadors de Ghostty"
#: src/apprt/gtk/inspector.zig:144
msgid "Ghostty: Terminal Inspector"
msgstr "Ghostty: Inspector de terminal"

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
"POT-Creation-Date: 2025-06-28 17:01+0200\n"
"POT-Creation-Date: 2025-07-08 15:13-0500\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -124,7 +124,7 @@ 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:263
#: src/apprt/gtk/Window.zig:265
msgid "New Tab"
msgstr ""
@ -165,7 +165,7 @@ msgid "Terminal Inspector"
msgstr ""
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
#: src/apprt/gtk/Window.zig:1036
#: src/apprt/gtk/Window.zig:1038
msgid "About Ghostty"
msgstr ""
@ -228,35 +228,6 @@ msgid ""
"commands may be executed."
msgstr ""
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"
msgstr ""
#: src/apprt/gtk/Window.zig:238
msgid "View Open Tabs"
msgstr ""
#: src/apprt/gtk/Window.zig:264
msgid "New Split"
msgstr ""
#: src/apprt/gtk/Window.zig:327
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr ""
#: src/apprt/gtk/Window.zig:773
msgid "Reloaded the configuration"
msgstr ""
#: src/apprt/gtk/Window.zig:1017
msgid "Ghostty Developers"
msgstr ""
#: src/apprt/gtk/inspector.zig:144
msgid "Ghostty: Terminal Inspector"
msgstr ""
#: src/apprt/gtk/CloseDialog.zig:47
msgid "Close"
msgstr ""
@ -296,3 +267,32 @@ msgstr ""
#: src/apprt/gtk/Surface.zig:1257
msgid "Copied to clipboard"
msgstr ""
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"
msgstr ""
#: src/apprt/gtk/Window.zig:239
msgid "View Open Tabs"
msgstr ""
#: src/apprt/gtk/Window.zig:266
msgid "New Split"
msgstr ""
#: src/apprt/gtk/Window.zig:329
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr ""
#: src/apprt/gtk/Window.zig:775
msgid "Reloaded the configuration"
msgstr ""
#: src/apprt/gtk/Window.zig:1019
msgid "Ghostty Developers"
msgstr ""
#: src/apprt/gtk/inspector.zig:144
msgid "Ghostty: Terminal Inspector"
msgstr ""

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
"POT-Creation-Date: 2025-04-22 08:57-0700\n"
"POT-Creation-Date: 2025-07-08 15:13-0500\n"
"PO-Revision-Date: 2025-03-06 14:57+0100\n"
"Last-Translator: Robin <r@rpfaeffle.com>\n"
"Language-Team: German <translation-team-de@lists.sourceforge.net>\n"
@ -27,7 +27,8 @@ msgid "Leave blank to restore the default title."
msgstr "Leer lassen, um den Standardtitel wiederherzustellen."
#: 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
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/ui/1.2/ccw-paste.blp:10
#: src/apprt/gtk/CloseDialog.zig:44
msgid "Cancel"
msgstr "Abbrechen"
@ -36,22 +37,26 @@ msgid "OK"
msgstr "OK"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
msgid "Configuration Errors"
msgstr ""
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
#: src/apprt/gtk/ui/1.2/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
#: src/apprt/gtk/ui/1.2/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:95
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:100
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
msgid "Reload Configuration"
msgstr "Konfiguration neu laden"
@ -79,6 +84,10 @@ msgstr "Fenter nach links teilen"
msgid "Split Right"
msgstr "Fenster nach rechts teilen"
#: 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"
@ -86,7 +95,7 @@ msgstr "Kopieren"
#: 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
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11 src/apprt/gtk/ui/1.2/ccw-paste.blp:11
msgid "Paste"
msgstr "Einfügen"
@ -116,7 +125,7 @@ msgstr "Tab"
#: 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:248
#: src/apprt/gtk/Window.zig:265
msgid "New Tab"
msgstr "Neuer Tab"
@ -144,29 +153,36 @@ msgid "Config"
msgstr "Konfiguration"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:92
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
msgid "Open Configuration"
msgstr "Konfiguration öffnen"
#: 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 "Terminalinspektor"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:102
#: src/apprt/gtk/Window.zig:1003
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
#: src/apprt/gtk/Window.zig:1038
msgid "About Ghostty"
msgstr "Über Ghostty"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:112
msgid "Quit"
msgstr "Beenden"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:6
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
msgid "Authorize Clipboard Access"
msgstr "Zugriff auf die Zwischenablage gewähren"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:7
msgid ""
"An application is attempting to read from the clipboard. The current "
"clipboard contents are shown below."
@ -176,15 +192,30 @@ 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
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:10
msgid "Deny"
msgstr "Nicht erlauben"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:11
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:11
msgid "Allow"
msgstr "Erlauben"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
msgid "Remember choice for this split"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
msgid "Reload configuration to show this prompt again"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
msgid ""
"An application is attempting to write to the clipboard. The current "
"clipboard contents are shown below."
@ -192,11 +223,11 @@ msgstr ""
"Eine Anwendung versucht in die Zwischenablage zu schreiben. Der aktuelle "
"Inhalt der Zwischenablage wird unten angezeigt."
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
msgid "Warning: Potentially Unsafe Paste"
msgstr "Achtung: Möglicherweise unsicheres Einfügen"
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/ccw-paste.blp:7
msgid ""
"Pasting this text into the terminal may be dangerous as it looks like some "
"commands may be executed."
@ -204,33 +235,6 @@ msgstr ""
"Diesen Text in das Terminal einzufügen könnte möglicherweise gefährlich "
"sein. Es scheint, dass Anweisungen ausgeführt werden könnten."
#: src/apprt/gtk/Window.zig:201
msgid "Main Menu"
msgstr "Hauptmenü"
#: src/apprt/gtk/Window.zig:222
msgid "View Open Tabs"
msgstr "Offene Tabs einblenden"
#: src/apprt/gtk/Window.zig:249
msgid "New Split"
msgstr ""
#: src/apprt/gtk/Window.zig:312
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr ""
"⚠️ Du verwendest einen Debug Build von Ghostty! Die Leistung wird reduziert "
"sein."
#: src/apprt/gtk/Window.zig:744
msgid "Reloaded the configuration"
msgstr "Konfiguration wurde neu geladen"
#: src/apprt/gtk/Window.zig:984
msgid "Ghostty Developers"
msgstr "Ghostty-Entwickler"
#: src/apprt/gtk/CloseDialog.zig:47
msgid "Close"
msgstr "Schließen"
@ -267,10 +271,37 @@ msgstr "Alle Terminalsitzungen in diesem Tab werden beendet."
msgid "The currently running process in this split will be terminated."
msgstr "Der aktuell laufende Prozess in diesem geteilten Fenster wird beendet."
#: src/apprt/gtk/Surface.zig:1243
#: src/apprt/gtk/Surface.zig:1257
msgid "Copied to clipboard"
msgstr "In die Zwischenablage kopiert"
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"
msgstr "Hauptmenü"
#: src/apprt/gtk/Window.zig:239
msgid "View Open Tabs"
msgstr "Offene Tabs einblenden"
#: src/apprt/gtk/Window.zig:266
msgid "New Split"
msgstr ""
#: src/apprt/gtk/Window.zig:329
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr ""
"⚠️ Du verwendest einen Debug Build von Ghostty! Die Leistung wird reduziert "
"sein."
#: src/apprt/gtk/Window.zig:775
msgid "Reloaded the configuration"
msgstr "Konfiguration wurde neu geladen"
#: src/apprt/gtk/Window.zig:1019
msgid "Ghostty Developers"
msgstr "Ghostty-Entwickler"
#: src/apprt/gtk/inspector.zig:144
msgid "Ghostty: Terminal Inspector"
msgstr ""

View File

@ -7,7 +7,7 @@ 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"
"POT-Creation-Date: 2025-07-08 15:13-0500\n"
"PO-Revision-Date: 2025-05-19 20:17-0300\n"
"Last-Translator: Alan Moyano <alanmoyano203@gmail.com>\n"
"Language-Team: Argentinian <es@tp.org.es>\n"
@ -26,7 +26,8 @@ msgid "Leave blank to restore the default title."
msgstr "Dejar en blanco para restaurar el título predeterminado."
#: 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
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/ui/1.2/ccw-paste.blp:10
#: src/apprt/gtk/CloseDialog.zig:44
msgid "Cancel"
msgstr "Cancelar"
@ -35,10 +36,12 @@ msgid "OK"
msgstr "Aceptar"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
msgid "Configuration Errors"
msgstr "Errores de configuración"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
#: src/apprt/gtk/ui/1.2/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."
@ -47,12 +50,14 @@ msgstr ""
"errores a continuación, y recargá tu configuración o ignorá estos errores."
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:9
msgid "Ignore"
msgstr "Ignorar"
#: 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
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
msgid "Reload Configuration"
msgstr "Recargar configuración"
@ -91,7 +96,7 @@ msgstr "Copiar"
#: 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
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11 src/apprt/gtk/ui/1.2/ccw-paste.blp:11
msgid "Paste"
msgstr "Pegar"
@ -121,7 +126,7 @@ msgstr "Pestaña"
#: 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
#: src/apprt/gtk/Window.zig:265
msgid "New Tab"
msgstr "Nueva pestaña"
@ -162,7 +167,7 @@ msgid "Terminal Inspector"
msgstr "Inspector de la terminal"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
#: src/apprt/gtk/Window.zig:1024
#: src/apprt/gtk/Window.zig:1038
msgid "About Ghostty"
msgstr "Acerca de Ghostty"
@ -172,10 +177,13 @@ msgstr "Salir"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:6
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
msgid "Authorize Clipboard Access"
msgstr "Autorizar acceso al portapapeles"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:7
msgid ""
"An application is attempting to read from the clipboard. The current "
"clipboard contents are shown below."
@ -185,15 +193,30 @@ 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
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:10
msgid "Deny"
msgstr "Denegar"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:11
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:11
msgid "Allow"
msgstr "Permitir"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
msgid "Remember choice for this split"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
msgid "Reload configuration to show this prompt again"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
msgid ""
"An application is attempting to write to the clipboard. The current "
"clipboard contents are shown below."
@ -201,11 +224,11 @@ msgstr ""
"Una aplicación está intentando escribir en el portapapeles. El contenido "
"actual del portapapeles se muestra a continuación."
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
msgid "Warning: Potentially Unsafe Paste"
msgstr "Advertencia: Pegado potencialmente inseguro"
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/ccw-paste.blp:7
msgid ""
"Pasting this text into the terminal may be dangerous as it looks like some "
"commands may be executed."
@ -213,37 +236,6 @@ msgstr ""
"Pegar este texto en la terminal puede ser peligroso ya que parece que "
"algunos comandos podrían ejecutarse."
#: src/apprt/gtk/Window.zig:208
msgid "Main Menu"
msgstr "Menú principal"
#: src/apprt/gtk/Window.zig:229
msgid "View Open Tabs"
msgstr "Ver pestañas abiertas"
#: src/apprt/gtk/Window.zig:256
msgid "New Split"
msgstr "Nueva división"
#: src/apprt/gtk/Window.zig:319
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr ""
"⚠️ Estás ejecutando una versión de depuración de Ghostty. El rendimiento no "
"será óptimo."
#: src/apprt/gtk/Window.zig:765
msgid "Reloaded the configuration"
msgstr "Configuración recargada"
#: src/apprt/gtk/Window.zig:1005
msgid "Ghostty Developers"
msgstr "Desarrolladores de Ghostty"
#: src/apprt/gtk/inspector.zig:144
msgid "Ghostty: Terminal Inspector"
msgstr "Ghostty: Inspector de la terminal"
#: src/apprt/gtk/CloseDialog.zig:47
msgid "Close"
msgstr "Cerrar"
@ -280,6 +272,37 @@ msgstr "Todas las sesiones de terminal en esta pestaña serán terminadas."
msgid "The currently running process in this split will be terminated."
msgstr "El proceso actualmente en ejecución en esta división será terminado."
#: src/apprt/gtk/Surface.zig:1243
#: src/apprt/gtk/Surface.zig:1257
msgid "Copied to clipboard"
msgstr "Copiado al portapapeles"
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"
msgstr "Menú principal"
#: src/apprt/gtk/Window.zig:239
msgid "View Open Tabs"
msgstr "Ver pestañas abiertas"
#: src/apprt/gtk/Window.zig:266
msgid "New Split"
msgstr "Nueva división"
#: src/apprt/gtk/Window.zig:329
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr ""
"⚠️ Estás ejecutando una versión de depuración de Ghostty. El rendimiento no "
"será óptimo."
#: src/apprt/gtk/Window.zig:775
msgid "Reloaded the configuration"
msgstr "Configuración recargada"
#: src/apprt/gtk/Window.zig:1019
msgid "Ghostty Developers"
msgstr "Desarrolladores de Ghostty"
#: src/apprt/gtk/inspector.zig:144
msgid "Ghostty: Terminal Inspector"
msgstr "Ghostty: Inspector de la terminal"

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
"POT-Creation-Date: 2025-04-22 08:57-0700\n"
"POT-Creation-Date: 2025-07-08 15:13-0500\n"
"PO-Revision-Date: 2025-03-28 17:46+0200\n"
"Last-Translator: Miguel Peredo <miguelp@quientienemail.com>\n"
"Language-Team: Spanish <es@tp.org.es>\n"
@ -26,7 +26,8 @@ msgid "Leave blank to restore the default title."
msgstr "Dejar en blanco para restaurar el título predeterminado."
#: 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
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/ui/1.2/ccw-paste.blp:10
#: src/apprt/gtk/CloseDialog.zig:44
msgid "Cancel"
msgstr "Cancelar"
@ -35,10 +36,12 @@ msgid "OK"
msgstr "Aceptar"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
msgid "Configuration Errors"
msgstr "Errores de configuración"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
#: src/apprt/gtk/ui/1.2/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."
@ -47,12 +50,14 @@ msgstr ""
"errores a continuación, y recargue su configuración o ignore estos errores."
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:9
msgid "Ignore"
msgstr "Ignorar"
#: 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:95
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:100
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
msgid "Reload Configuration"
msgstr "Recargar configuración"
@ -80,6 +85,10 @@ msgstr "Dividir a la izquierda"
msgid "Split Right"
msgstr "Dividir a la derecha"
#: 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"
@ -87,7 +96,7 @@ msgstr "Copiar"
#: 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
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11 src/apprt/gtk/ui/1.2/ccw-paste.blp:11
msgid "Paste"
msgstr "Pegar"
@ -117,7 +126,7 @@ msgstr "Pestaña"
#: 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:248
#: src/apprt/gtk/Window.zig:265
msgid "New Tab"
msgstr "Nueva pestaña"
@ -145,29 +154,36 @@ msgid "Config"
msgstr "Configuración"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:92
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
msgid "Open Configuration"
msgstr "Abrir configuración"
#: 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 "Inspector de la terminal"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:102
#: src/apprt/gtk/Window.zig:1003
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
#: src/apprt/gtk/Window.zig:1038
msgid "About Ghostty"
msgstr "Acerca de Ghostty"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:112
msgid "Quit"
msgstr "Salir"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:6
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
msgid "Authorize Clipboard Access"
msgstr "Autorizar acceso al portapapeles"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:7
msgid ""
"An application is attempting to read from the clipboard. The current "
"clipboard contents are shown below."
@ -177,15 +193,30 @@ 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
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:10
msgid "Deny"
msgstr "Denegar"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:11
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:11
msgid "Allow"
msgstr "Permitir"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
msgid "Remember choice for this split"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
msgid "Reload configuration to show this prompt again"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
msgid ""
"An application is attempting to write to the clipboard. The current "
"clipboard contents are shown below."
@ -193,11 +224,11 @@ msgstr ""
"Una aplicación está intentando escribir en el portapapeles. El contenido "
"actual del portapapeles se muestra a continuación."
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
msgid "Warning: Potentially Unsafe Paste"
msgstr "Advertencia: Pegado potencialmente inseguro"
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/ccw-paste.blp:7
msgid ""
"Pasting this text into the terminal may be dangerous as it looks like some "
"commands may be executed."
@ -205,33 +236,6 @@ msgstr ""
"Pegar este texto en la terminal puede ser peligroso ya que parece que "
"algunos comandos podrían ejecutarse."
#: src/apprt/gtk/Window.zig:201
msgid "Main Menu"
msgstr "Menú principal"
#: src/apprt/gtk/Window.zig:222
msgid "View Open Tabs"
msgstr "Ver pestañas abiertas"
#: src/apprt/gtk/Window.zig:249
msgid "New Split"
msgstr ""
#: src/apprt/gtk/Window.zig:312
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr ""
"⚠️ Está ejecutando una versión de depuración de Ghostty. El rendimiento no "
"será óptimo."
#: src/apprt/gtk/Window.zig:744
msgid "Reloaded the configuration"
msgstr "Configuración recargada"
#: src/apprt/gtk/Window.zig:984
msgid "Ghostty Developers"
msgstr "Desarrolladores de Ghostty"
#: src/apprt/gtk/CloseDialog.zig:47
msgid "Close"
msgstr "Cerrar"
@ -268,10 +272,37 @@ msgstr "Todas las sesiones de terminal en esta pestaña serán terminadas."
msgid "The currently running process in this split will be terminated."
msgstr "El proceso actualmente en ejecución en esta división será terminado."
#: src/apprt/gtk/Surface.zig:1243
#: src/apprt/gtk/Surface.zig:1257
msgid "Copied to clipboard"
msgstr "Copiado al portapapeles"
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"
msgstr "Menú principal"
#: src/apprt/gtk/Window.zig:239
msgid "View Open Tabs"
msgstr "Ver pestañas abiertas"
#: src/apprt/gtk/Window.zig:266
msgid "New Split"
msgstr ""
#: src/apprt/gtk/Window.zig:329
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr ""
"⚠️ Está ejecutando una versión de depuración de Ghostty. El rendimiento no "
"será óptimo."
#: src/apprt/gtk/Window.zig:775
msgid "Reloaded the configuration"
msgstr "Configuración recargada"
#: src/apprt/gtk/Window.zig:1019
msgid "Ghostty Developers"
msgstr "Desarrolladores de Ghostty"
#: src/apprt/gtk/inspector.zig:144
msgid "Ghostty: Terminal Inspector"
msgstr "Ghostty: Inspector de la terminal"

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
"POT-Creation-Date: 2025-04-22 08:57-0700\n"
"POT-Creation-Date: 2025-07-08 15:13-0500\n"
"PO-Revision-Date: 2025-03-22 09:31+0100\n"
"Last-Translator: Kirwiisp <swiip__@hotmail.com>\n"
"Language-Team: French <traduc@traduc.org>\n"
@ -26,7 +26,8 @@ msgid "Leave blank to restore the default title."
msgstr "Laisser vide pour restaurer le titre par défaut."
#: 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
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/ui/1.2/ccw-paste.blp:10
#: src/apprt/gtk/CloseDialog.zig:44
msgid "Cancel"
msgstr "Annuler"
@ -35,10 +36,12 @@ msgid "OK"
msgstr "OK"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
msgid "Configuration Errors"
msgstr "Erreurs de configuration"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
#: src/apprt/gtk/ui/1.2/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."
@ -48,12 +51,14 @@ msgstr ""
"erreurs."
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:9
msgid "Ignore"
msgstr "Ignorer"
#: 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:95
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:100
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
msgid "Reload Configuration"
msgstr "Recharger la configuration"
@ -81,6 +86,10 @@ msgstr "Panneau à gauche"
msgid "Split Right"
msgstr "Panneau à droite"
#: 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"
@ -88,7 +97,7 @@ msgstr "Copier"
#: 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
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11 src/apprt/gtk/ui/1.2/ccw-paste.blp:11
msgid "Paste"
msgstr "Coller"
@ -118,7 +127,7 @@ msgstr "Onglet"
#: 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:248
#: src/apprt/gtk/Window.zig:265
msgid "New Tab"
msgstr "Nouvel onglet"
@ -146,29 +155,36 @@ msgid "Config"
msgstr "Config"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:92
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
msgid "Open Configuration"
msgstr "Ouvrir la configuration"
#: 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 "Inspecteur de terminal"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:102
#: src/apprt/gtk/Window.zig:1003
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
#: src/apprt/gtk/Window.zig:1038
msgid "About Ghostty"
msgstr "À propos de Ghostty"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:112
msgid "Quit"
msgstr "Quitter"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:6
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
msgid "Authorize Clipboard Access"
msgstr "Autoriser l'accès au presse-papiers"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:7
msgid ""
"An application is attempting to read from the clipboard. The current "
"clipboard contents are shown below."
@ -178,15 +194,30 @@ 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
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:10
msgid "Deny"
msgstr "Refuser"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:11
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:11
msgid "Allow"
msgstr "Autoriser"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
msgid "Remember choice for this split"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
msgid "Reload configuration to show this prompt again"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
msgid ""
"An application is attempting to write to the clipboard. The current "
"clipboard contents are shown below."
@ -194,11 +225,11 @@ msgstr ""
"Une application essaie d'écrire dans le presse-papiers.Le contenu actuel du "
"presse-papiers est affiché ci-dessous."
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
msgid "Warning: Potentially Unsafe Paste"
msgstr "Attention: Collage potentiellement dangereux"
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/ccw-paste.blp:7
msgid ""
"Pasting this text into the terminal may be dangerous as it looks like some "
"commands may be executed."
@ -206,33 +237,6 @@ msgstr ""
"Coller ce texte dans le terminal pourrait être dangereux, il semblerait que "
"certaines commandes pourraient être exécutées."
#: src/apprt/gtk/Window.zig:201
msgid "Main Menu"
msgstr "Menu principal"
#: src/apprt/gtk/Window.zig:222
msgid "View Open Tabs"
msgstr "Voir les onglets ouverts"
#: src/apprt/gtk/Window.zig:249
msgid "New Split"
msgstr ""
#: src/apprt/gtk/Window.zig:312
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr ""
"⚠️ Vous utilisez une version de débogage de Ghostty ! Les performances seront "
"dégradées."
#: src/apprt/gtk/Window.zig:744
msgid "Reloaded the configuration"
msgstr "Recharger la configuration"
#: src/apprt/gtk/Window.zig:984
msgid "Ghostty Developers"
msgstr "Les développeurs de Ghostty"
#: src/apprt/gtk/CloseDialog.zig:47
msgid "Close"
msgstr "Fermer"
@ -269,10 +273,37 @@ msgstr "Toutes les sessions de cet onglet vont être arrêtées."
msgid "The currently running process in this split will be terminated."
msgstr "Le processus en cours dans ce panneau va être arrêté."
#: src/apprt/gtk/Surface.zig:1243
#: src/apprt/gtk/Surface.zig:1257
msgid "Copied to clipboard"
msgstr "Copié dans le presse-papiers"
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"
msgstr "Menu principal"
#: src/apprt/gtk/Window.zig:239
msgid "View Open Tabs"
msgstr "Voir les onglets ouverts"
#: src/apprt/gtk/Window.zig:266
msgid "New Split"
msgstr ""
#: src/apprt/gtk/Window.zig:329
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr ""
"⚠️ Vous utilisez une version de débogage de Ghostty ! Les performances seront "
"dégradées."
#: src/apprt/gtk/Window.zig:775
msgid "Reloaded the configuration"
msgstr "Recharger la configuration"
#: src/apprt/gtk/Window.zig:1019
msgid "Ghostty Developers"
msgstr "Les développeurs de Ghostty"
#: src/apprt/gtk/inspector.zig:144
msgid "Ghostty: Terminal Inspector"
msgstr "Ghostty: Inspecteur"

View File

@ -7,7 +7,7 @@ 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"
"POT-Creation-Date: 2025-07-08 15:13-0500\n"
"PO-Revision-Date: 2025-06-29 21:15+0100\n"
"Last-Translator: Aindriú Mac Giolla Eoin <aindriu80@gmail.com>\n"
"Language-Team: Irish <gaeilge-gnulinux@lists.sourceforge.net>\n"
@ -27,7 +27,8 @@ msgid "Leave blank to restore the default title."
msgstr "Fág bán chun an teideal réamhshocraithe a athbhunú."
#: 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
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/ui/1.2/ccw-paste.blp:10
#: src/apprt/gtk/CloseDialog.zig:44
msgid "Cancel"
msgstr "Cealaigh"
@ -36,10 +37,12 @@ msgid "OK"
msgstr "Ceart go leor"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
msgid "Configuration Errors"
msgstr "Earráidí cumraíochta"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
#: src/apprt/gtk/ui/1.2/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."
@ -48,12 +51,14 @@ msgstr ""
"thíos, agus athlódáil do chumraíocht nó déan neamhaird de na hearráidí seo."
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:9
msgid "Ignore"
msgstr "Déan neamhaird de"
#: 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
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
msgid "Reload Configuration"
msgstr "Athlódáil cumraíocht"
@ -92,7 +97,7 @@ msgstr "Cóipeáil"
#: 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
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11 src/apprt/gtk/ui/1.2/ccw-paste.blp:11
msgid "Paste"
msgstr "Greamaigh"
@ -122,7 +127,7 @@ msgstr "Táb"
#: 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
#: src/apprt/gtk/Window.zig:265
msgid "New Tab"
msgstr "Táb nua"
@ -163,7 +168,7 @@ msgid "Terminal Inspector"
msgstr "Cigire teirminéil"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
#: src/apprt/gtk/Window.zig:1024
#: src/apprt/gtk/Window.zig:1038
msgid "About Ghostty"
msgstr "Maidir le Ghostty"
@ -173,10 +178,13 @@ msgstr "Scoir"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:6
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
msgid "Authorize Clipboard Access"
msgstr "Údarú rochtain ar an ngearrthaisce"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:7
msgid ""
"An application is attempting to read from the clipboard. The current "
"clipboard contents are shown below."
@ -186,15 +194,30 @@ 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
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:10
msgid "Deny"
msgstr "Diúltaigh"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:11
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:11
msgid "Allow"
msgstr "Ceadaigh"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
msgid "Remember choice for this split"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
msgid "Reload configuration to show this prompt again"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
msgid ""
"An application is attempting to write to the clipboard. The current "
"clipboard contents are shown below."
@ -202,11 +225,11 @@ msgstr ""
"Tá feidhmchlár ag iarraidh scríobh chuig an ngearrthaisce. Taispeántar ábhar "
"reatha an ghearrthaisce thíos."
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
msgid "Warning: Potentially Unsafe Paste"
msgstr "Rabhadh: Greamaigh a d'fhéadfadh a bheith neamhshábháilte"
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/ccw-paste.blp:7
msgid ""
"Pasting this text into the terminal may be dangerous as it looks like some "
"commands may be executed."
@ -214,36 +237,6 @@ msgstr ""
"Dfhéadfadh sé a bheith contúirteach an téacs seo a ghreamú isteach sa "
"teirminéal, toisc go d'fhéadfadh roinnt orduithe a fhorghníomhú."
#: src/apprt/gtk/Window.zig:208
msgid "Main Menu"
msgstr "Príomh-Roghchlár"
#: src/apprt/gtk/Window.zig:229
msgid "View Open Tabs"
msgstr "Féach ar na táib oscailte"
#: src/apprt/gtk/Window.zig:256
msgid "New Split"
msgstr "Scoilt nua"
#: src/apprt/gtk/Window.zig:319
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr ""
"⚠️ Tá leagan dífhabhtaithe de Ghostty á rith agat! Laghdófar an fheidhmíocht."
#: src/apprt/gtk/Window.zig:765
msgid "Reloaded the configuration"
msgstr "Tá an chumraíocht athlódáilte"
#: src/apprt/gtk/Window.zig:1005
msgid "Ghostty Developers"
msgstr "Forbróirí Ghostty"
#: src/apprt/gtk/inspector.zig:144
msgid "Ghostty: Terminal Inspector"
msgstr "Ghostty: Cigire teirminéil"
#: src/apprt/gtk/CloseDialog.zig:47
msgid "Close"
msgstr "Dún"
@ -281,6 +274,36 @@ msgid "The currently running process in this split will be terminated."
msgstr ""
"Cuirfear deireadh leis an bpróiseas atá ar siúl faoi láthair sa scoilt seo."
#: src/apprt/gtk/Surface.zig:1243
#: src/apprt/gtk/Surface.zig:1257
msgid "Copied to clipboard"
msgstr "Cóipeáilte chuig an ghearrthaisce"
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"
msgstr "Príomh-Roghchlár"
#: src/apprt/gtk/Window.zig:239
msgid "View Open Tabs"
msgstr "Féach ar na táib oscailte"
#: src/apprt/gtk/Window.zig:266
msgid "New Split"
msgstr "Scoilt nua"
#: src/apprt/gtk/Window.zig:329
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr ""
"⚠️ Tá leagan dífhabhtaithe de Ghostty á rith agat! Laghdófar an fheidhmíocht."
#: src/apprt/gtk/Window.zig:775
msgid "Reloaded the configuration"
msgstr "Tá an chumraíocht athlódáilte"
#: src/apprt/gtk/Window.zig:1019
msgid "Ghostty Developers"
msgstr "Forbróirí Ghostty"
#: src/apprt/gtk/inspector.zig:144
msgid "Ghostty: Terminal Inspector"
msgstr "Ghostty: Cigire teirminéil"

304
po/he_IL.UTF-8.po Normal file
View File

@ -0,0 +1,304 @@
# Hebrew translations for com.mitchellh.ghostty.
# Copyright (C) 2025 Mitchell Hashimoto
# This file is distributed under the same license as the com.mitchellh.ghostty package.
# Sl (Shahaf Levi), Sl's Repository Ltd <ghostty@slsrepo.com>, 2025.
#
msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
"POT-Creation-Date: 2025-07-08 15:13-0500\n"
"PO-Revision-Date: 2025-03-13 00:00+0000\n"
"Last-Translator: Sl (Shahaf Levi), Sl's Repository Ltd <ghostty@slsrepo."
"com>\n"
"Language-Team: Hebrew <he_IL@lists.sourceforge.net>\n"
"Language: he\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/ui/1.2/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
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
msgid "Configuration Errors"
msgstr "שגיאות בהגדרות"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
#: src/apprt/gtk/ui/1.2/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
#: src/apprt/gtk/ui/1.2/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
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
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 src/apprt/gtk/ui/1.2/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:265
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:1038
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
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
msgid "Authorize Clipboard Access"
msgstr "אשר/י גישה ללוח ההעתקה"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
#: src/apprt/gtk/ui/1.2/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
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.2/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
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:11
msgid "Allow"
msgstr "אישור"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
msgid "Remember choice for this split"
msgstr "זכור/י את הבחירה עבור פיצול זה"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
msgid "Reload configuration to show this prompt again"
msgstr "טען/י את ההגדרות מחדש כדי להציג את הבקשה הזו שוב"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
#: src/apprt/gtk/ui/1.2/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 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
msgid "Warning: Potentially Unsafe Paste"
msgstr "אזהרה: ההדבקה עלולה להיות מסוכנת"
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/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/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:1257
msgid "Copied to clipboard"
msgstr "הועתק ללוח ההעתקה"
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"
msgstr "תפריט ראשי"
#: src/apprt/gtk/Window.zig:239
msgid "View Open Tabs"
msgstr "הצג/י כרטיסיות פתוחות"
#: src/apprt/gtk/Window.zig:266
msgid "New Split"
msgstr "פיצול חדש"
#: src/apprt/gtk/Window.zig:329
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr "⚠️ את/ה מריץ/ה גרסת ניפוי שגיאות של Ghostty! הביצועים יהיו ירודים."
#: src/apprt/gtk/Window.zig:775
msgid "Reloaded the configuration"
msgstr "ההגדרות הוטענו מחדש"
#: src/apprt/gtk/Window.zig:1019
msgid "Ghostty Developers"
msgstr "המפתחים של Ghostty"
#: src/apprt/gtk/inspector.zig:144
msgid "Ghostty: Terminal Inspector"
msgstr "Ghostty: בודק המסוף"

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
"POT-Creation-Date: 2025-04-22 08:57-0700\n"
"POT-Creation-Date: 2025-07-08 15:13-0500\n"
"PO-Revision-Date: 2025-03-20 15:19+0700\n"
"Last-Translator: Satrio Bayu Aji <halosatrio@gmail.com>\n"
"Language-Team: Indonesian <translation-team-id@lists.sourceforge.net>\n"
@ -25,7 +25,8 @@ msgid "Leave blank to restore the default title."
msgstr "Biarkan kosong untuk mengembalikan judul bawaan."
#: 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
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/ui/1.2/ccw-paste.blp:10
#: src/apprt/gtk/CloseDialog.zig:44
msgid "Cancel"
msgstr "Batal"
@ -34,10 +35,12 @@ msgid "OK"
msgstr "OK"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
msgid "Configuration Errors"
msgstr "Kesalahan konfigurasi"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
#: src/apprt/gtk/ui/1.2/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."
@ -46,12 +49,14 @@ msgstr ""
"bawah ini, dan muat ulang konfigurasi anda atau abaikan kesalahan ini."
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:9
msgid "Ignore"
msgstr "Abaikan"
#: 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:95
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:100
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
msgid "Reload Configuration"
msgstr "Muat ulang konfigurasi"
@ -79,6 +84,10 @@ msgstr "Belah kiri"
msgid "Split Right"
msgstr "Belah kanan"
#: 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"
@ -86,7 +95,7 @@ msgstr "Salin"
#: 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
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11 src/apprt/gtk/ui/1.2/ccw-paste.blp:11
msgid "Paste"
msgstr "Tempel"
@ -116,7 +125,7 @@ msgstr "Tab"
#: 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:248
#: src/apprt/gtk/Window.zig:265
msgid "New Tab"
msgstr "Tab baru"
@ -144,29 +153,36 @@ msgid "Config"
msgstr "Konfigurasi"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:92
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
msgid "Open Configuration"
msgstr "Buka konfigurasi"
#: 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 "Inspektur terminal"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:102
#: src/apprt/gtk/Window.zig:1003
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
#: src/apprt/gtk/Window.zig:1038
msgid "About Ghostty"
msgstr "Tentang Ghostty"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:112
msgid "Quit"
msgstr "Keluar"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:6
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
msgid "Authorize Clipboard Access"
msgstr "Mengesahkan akses papan klip"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:7
msgid ""
"An application is attempting to read from the clipboard. The current "
"clipboard contents are shown below."
@ -176,15 +192,30 @@ 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
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:10
msgid "Deny"
msgstr "Menyangkal"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:11
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:11
msgid "Allow"
msgstr "Izinkan"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
msgid "Remember choice for this split"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
msgid "Reload configuration to show this prompt again"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
msgid ""
"An application is attempting to write to the clipboard. The current "
"clipboard contents are shown below."
@ -192,11 +223,11 @@ msgstr ""
"Aplikasi sedang mencoba menulis ke papan klip. Isi papan klip saat ini "
"ditampilkan di bawah ini."
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
msgid "Warning: Potentially Unsafe Paste"
msgstr "Peringatan: Tempelan yang berpotensi tidak aman"
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/ccw-paste.blp:7
msgid ""
"Pasting this text into the terminal may be dangerous as it looks like some "
"commands may be executed."
@ -204,32 +235,6 @@ msgstr ""
"Menempelkan teks ini ke terminal mungkin berbahaya karena sepertinya "
"beberapa perintah mungkin dijalankan."
#: src/apprt/gtk/Window.zig:201
msgid "Main Menu"
msgstr "Menu utama"
#: src/apprt/gtk/Window.zig:222
msgid "View Open Tabs"
msgstr "Lihat tab terbuka"
#: src/apprt/gtk/Window.zig:249
msgid "New Split"
msgstr ""
#: src/apprt/gtk/Window.zig:312
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr ""
"⚠️ Anda sedang menjalankan versi debug dari Ghostty! Performa akan menurun."
#: src/apprt/gtk/Window.zig:744
msgid "Reloaded the configuration"
msgstr "Memuat ulang konfigurasi"
#: src/apprt/gtk/Window.zig:984
msgid "Ghostty Developers"
msgstr "Pengembang Ghostty"
#: src/apprt/gtk/CloseDialog.zig:47
msgid "Close"
msgstr "Tutup"
@ -266,10 +271,36 @@ msgstr "Semua sesi terminal di tab ini akan diakhiri."
msgid "The currently running process in this split will be terminated."
msgstr "Proses yang sedang berjalan dalam belahan ini akan diakhiri."
#: src/apprt/gtk/Surface.zig:1243
#: src/apprt/gtk/Surface.zig:1257
msgid "Copied to clipboard"
msgstr "Disalin ke papan klip"
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"
msgstr "Menu utama"
#: src/apprt/gtk/Window.zig:239
msgid "View Open Tabs"
msgstr "Lihat tab terbuka"
#: src/apprt/gtk/Window.zig:266
msgid "New Split"
msgstr ""
#: src/apprt/gtk/Window.zig:329
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr ""
"⚠️ Anda sedang menjalankan versi debug dari Ghostty! Performa akan menurun."
#: src/apprt/gtk/Window.zig:775
msgid "Reloaded the configuration"
msgstr "Memuat ulang konfigurasi"
#: src/apprt/gtk/Window.zig:1019
msgid "Ghostty Developers"
msgstr "Pengembang Ghostty"
#: src/apprt/gtk/inspector.zig:144
msgid "Ghostty: Terminal Inspector"
msgstr "Ghostty: Inspektur terminal"

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
"POT-Creation-Date: 2025-04-22 08:57-0700\n"
"POT-Creation-Date: 2025-07-08 15:13-0500\n"
"PO-Revision-Date: 2025-03-21 00:08+0900\n"
"Last-Translator: Lon Sagisawa <lon@sagisawa.me>\n"
"Language-Team: Japanese\n"
@ -27,7 +27,8 @@ 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
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/ui/1.2/ccw-paste.blp:10
#: src/apprt/gtk/CloseDialog.zig:44
msgid "Cancel"
msgstr "キャンセル"
@ -36,10 +37,12 @@ msgid "OK"
msgstr "OK"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
msgid "Configuration Errors"
msgstr "設定ファイルにエラーがあります"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
#: src/apprt/gtk/ui/1.2/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."
@ -48,12 +51,14 @@ msgstr ""
"みをするか、無視してください。"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
#: src/apprt/gtk/ui/1.2/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:95
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:100
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
msgid "Reload Configuration"
msgstr "設定ファイルの再読み込み"
@ -81,6 +86,10 @@ msgstr "左に分割"
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"
@ -88,7 +97,7 @@ 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
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11 src/apprt/gtk/ui/1.2/ccw-paste.blp:11
msgid "Paste"
msgstr "貼り付け"
@ -118,7 +127,7 @@ 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:248
#: src/apprt/gtk/Window.zig:265
msgid "New Tab"
msgstr "新しいタブ"
@ -146,29 +155,36 @@ 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:90
#: 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:102
#: src/apprt/gtk/Window.zig:1003
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
#: src/apprt/gtk/Window.zig:1038
msgid "About Ghostty"
msgstr "Ghostty について"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
#: 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
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
msgid "Authorize Clipboard Access"
msgstr "クリップボードへのアクセスを承認"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:7
msgid ""
"An application is attempting to read from the clipboard. The current "
"clipboard contents are shown below."
@ -178,15 +194,30 @@ 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
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.2/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
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:11
msgid "Allow"
msgstr "許可"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
msgid "Remember choice for this split"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
msgid "Reload configuration to show this prompt again"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
msgid ""
"An application is attempting to write to the clipboard. The current "
"clipboard contents are shown below."
@ -194,11 +225,11 @@ msgstr ""
"アプリケーションがクリップボードに書き込もうとしています。現在のクリップボー"
"ドの内容は以下の通りです。"
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
msgid "Warning: Potentially Unsafe Paste"
msgstr "警告: 危険な可能性のある貼り付け"
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/ccw-paste.blp:7
msgid ""
"Pasting this text into the terminal may be dangerous as it looks like some "
"commands may be executed."
@ -206,32 +237,6 @@ msgstr ""
"このテキストには実行可能なコマンドが含まれており、ターミナルに貼り付けるのは"
"危険な可能性があります。"
#: src/apprt/gtk/Window.zig:201
msgid "Main Menu"
msgstr "メインメニュー"
#: src/apprt/gtk/Window.zig:222
msgid "View Open Tabs"
msgstr "開いているすべてのタブを表示"
#: src/apprt/gtk/Window.zig:249
msgid "New Split"
msgstr ""
#: src/apprt/gtk/Window.zig:312
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr ""
"⚠️ Ghostty のデバッグビルドを実行しています! パフォーマンスが低下しています。"
#: src/apprt/gtk/Window.zig:744
msgid "Reloaded the configuration"
msgstr "設定を再読み込みしました"
#: src/apprt/gtk/Window.zig:984
msgid "Ghostty Developers"
msgstr "Ghostty 開発者"
#: src/apprt/gtk/CloseDialog.zig:47
msgid "Close"
msgstr "閉じる"
@ -268,10 +273,36 @@ msgstr "タブ内のすべてのターミナルセッションが終了します
msgid "The currently running process in this split will be terminated."
msgstr "分割ウィンドウ内のすべてのプロセスが終了します。"
#: src/apprt/gtk/Surface.zig:1243
#: src/apprt/gtk/Surface.zig:1257
msgid "Copied to clipboard"
msgstr "クリップボードにコピーしました"
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"
msgstr "メインメニュー"
#: src/apprt/gtk/Window.zig:239
msgid "View Open Tabs"
msgstr "開いているすべてのタブを表示"
#: src/apprt/gtk/Window.zig:266
msgid "New Split"
msgstr ""
#: src/apprt/gtk/Window.zig:329
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr ""
"⚠️ Ghostty のデバッグビルドを実行しています! パフォーマンスが低下しています。"
#: src/apprt/gtk/Window.zig:775
msgid "Reloaded the configuration"
msgstr "設定を再読み込みしました"
#: src/apprt/gtk/Window.zig:1019
msgid "Ghostty Developers"
msgstr "Ghostty 開発者"
#: src/apprt/gtk/inspector.zig:144
msgid "Ghostty: Terminal Inspector"
msgstr "Ghostty: 端末インスペクター"

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
"POT-Creation-Date: 2025-03-19 08:54-0700\n"
"POT-Creation-Date: 2025-07-08 15:13-0500\n"
"PO-Revision-Date: 2025-03-31 03:08+0200\n"
"Last-Translator: Ruben Engelbrecht <hey@rme.gg>\n"
"Language-Team: Korean <translation-team-ko@googlegroups.com>\n"
@ -26,7 +26,8 @@ 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
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/ui/1.2/ccw-paste.blp:10
#: src/apprt/gtk/CloseDialog.zig:44
msgid "Cancel"
msgstr "취소"
@ -35,25 +36,59 @@ msgid "OK"
msgstr "확인"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
msgid "Configuration Errors"
msgstr "설정 오류"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
#: src/apprt/gtk/ui/1.2/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 "설정에 하나 이상의 문제가 발견되었습니다. 아래 오류(를)들을 확인한 후 설정을 다시 불러오거나 무시하세요."
msgstr ""
"설정에 하나 이상의 문제가 발견되었습니다. 아래 오류(를)들을 확인한 후 설정을 "
"다시 불러오거나 무시하세요."
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
#: src/apprt/gtk/ui/1.2/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:95
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:100
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
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"
@ -61,7 +96,7 @@ 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
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11 src/apprt/gtk/ui/1.2/ccw-paste.blp:11
msgid "Paste"
msgstr "붙여넣기"
@ -85,33 +120,13 @@ msgstr "나누기"
msgid "Change Title…"
msgstr "제목 변경…"
#: 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-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-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-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.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:246
#: src/apprt/gtk/Window.zig:265
msgid "New Tab"
msgstr "새 탭"
@ -139,67 +154,87 @@ 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:90
#: 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:102
#: src/apprt/gtk/Window.zig:960
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
#: src/apprt/gtk/Window.zig:1038
msgid "About Ghostty"
msgstr "Ghostty 정보"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
#: 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
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
msgid "Authorize Clipboard Access"
msgstr "클립보드 액세스 권한 부여"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:7
msgid ""
"An application is attempting to read from the clipboard. The current "
"clipboard contents are shown below."
msgstr "응용 프로그램이 클립보드에서 읽기를 시도하고 있습니다. 현재 클립보드 내용은 아래와 같습니다."
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
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.2/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
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:11
msgid "Allow"
msgstr "허용"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
msgid "Remember choice for this split"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
msgid "Reload configuration to show this prompt again"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
msgid ""
"An application is attempting to write to the clipboard. The current "
"clipboard contents are shown below."
msgstr "응용 프로그램이 클립보드에 쓰기를 시도하고 있습니다. 현재 클립보드 내용은 아래와 같습니다."
msgstr ""
"응용 프로그램이 클립보드에 쓰기를 시도하고 있습니다. 현재 클립보드 내용은 아"
"래와 같습니다."
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
msgid "Warning: Potentially Unsafe Paste"
msgstr "경고: 잠재적으로 안전하지 않은 붙여넣기"
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/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/inspector.zig:144
msgid "Ghostty: Terminal Inspector"
msgstr "Ghostty: 터미널 인스펙터"
#: src/apprt/gtk/Surface.zig:1243
msgid "Copied to clipboard"
msgstr "클립보드에 복사됨"
msgstr ""
"이 텍스트를 터미널에 붙여넣는 것은 위험할 수 있습니다. 일부 명령이 실행될 수 "
"있는 것으로 보입니다."
#: src/apprt/gtk/CloseDialog.zig:47
msgid "Close"
@ -237,23 +272,36 @@ msgstr "이 탭의 모든 터미널 세션이 종료됩니다."
msgid "The currently running process in this split will be terminated."
msgstr "이 분할에서 현재 실행 중인 프로세스가 종료됩니다."
#: src/apprt/gtk/Window.zig:200
#: src/apprt/gtk/Surface.zig:1257
msgid "Copied to clipboard"
msgstr "클립보드에 복사됨"
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"
msgstr "메인 메뉴"
#: src/apprt/gtk/Window.zig:221
#: src/apprt/gtk/Window.zig:239
msgid "View Open Tabs"
msgstr "열린 탭 보기"
#: src/apprt/gtk/Window.zig:295
#: src/apprt/gtk/Window.zig:266
#, fuzzy
msgid "New Split"
msgstr "나누기"
#: src/apprt/gtk/Window.zig:329
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr "⚠️ Ghostty 디버그 빌드로 실행 중입니다! 성능이 저하됩니다."
#: src/apprt/gtk/Window.zig:725
#: src/apprt/gtk/Window.zig:775
msgid "Reloaded the configuration"
msgstr "설정값을 다시 불러왔습니다"
#: src/apprt/gtk/Window.zig:941
#: src/apprt/gtk/Window.zig:1019
msgid "Ghostty Developers"
msgstr "Ghostty 개발자들"
#: src/apprt/gtk/inspector.zig:144
msgid "Ghostty: Terminal Inspector"
msgstr "Ghostty: 터미널 인스펙터"

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
"POT-Creation-Date: 2025-04-22 08:57-0700\n"
"POT-Creation-Date: 2025-07-08 15:13-0500\n"
"PO-Revision-Date: 2025-03-23 14:17+0100\n"
"Last-Translator: Andrej Daskalov <andrej.daskalov@gmail.com>\n"
"Language-Team: Macedonian\n"
@ -25,7 +25,8 @@ 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
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/ui/1.2/ccw-paste.blp:10
#: src/apprt/gtk/CloseDialog.zig:44
msgid "Cancel"
msgstr "Откажи"
@ -34,10 +35,12 @@ msgid "OK"
msgstr "Во ред"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
msgid "Configuration Errors"
msgstr "Грешки во конфигурацијата"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
#: src/apprt/gtk/ui/1.2/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."
@ -47,12 +50,14 @@ msgstr ""
"овие грешки."
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
#: src/apprt/gtk/ui/1.2/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:95
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:100
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
msgid "Reload Configuration"
msgstr "Одново вчитај конфигурација"
@ -80,6 +85,10 @@ msgstr "Подели налево"
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"
@ -87,7 +96,7 @@ 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
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11 src/apprt/gtk/ui/1.2/ccw-paste.blp:11
msgid "Paste"
msgstr "Вметни"
@ -117,7 +126,7 @@ 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:248
#: src/apprt/gtk/Window.zig:265
msgid "New Tab"
msgstr "Ново јазиче"
@ -145,29 +154,36 @@ 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:90
#: 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:102
#: src/apprt/gtk/Window.zig:1003
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
#: src/apprt/gtk/Window.zig:1038
msgid "About Ghostty"
msgstr "За Ghostty"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
#: 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
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
msgid "Authorize Clipboard Access"
msgstr "Авторизирај пристап до привремена меморија"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:7
msgid ""
"An application is attempting to read from the clipboard. The current "
"clipboard contents are shown below."
@ -177,15 +193,30 @@ 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
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.2/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
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:11
msgid "Allow"
msgstr "Дозволи"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
msgid "Remember choice for this split"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
msgid "Reload configuration to show this prompt again"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
msgid ""
"An application is attempting to write to the clipboard. The current "
"clipboard contents are shown below."
@ -193,11 +224,11 @@ msgstr ""
"Апликација се обидува да запише во привремената меморија. Содржината е "
"прикажана подолу."
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
msgid "Warning: Potentially Unsafe Paste"
msgstr "Предупредување: Потенцијално небезбедно вметнување"
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/ccw-paste.blp:7
msgid ""
"Pasting this text into the terminal may be dangerous as it looks like some "
"commands may be executed."
@ -205,32 +236,6 @@ msgstr ""
"Вметнувањето на овој текст во терминалот може да биде опасно, бидејќи "
"изгледа како да ќе се извршат одредени команди."
#: src/apprt/gtk/Window.zig:201
msgid "Main Menu"
msgstr "Главно мени"
#: src/apprt/gtk/Window.zig:222
msgid "View Open Tabs"
msgstr "Прегледај отворени јазичиња"
#: src/apprt/gtk/Window.zig:249
msgid "New Split"
msgstr ""
#: src/apprt/gtk/Window.zig:312
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr ""
"⚠️ Извршувате дебаг верзија на Ghostty! Перформансите ќе бидат намалени."
#: src/apprt/gtk/Window.zig:744
msgid "Reloaded the configuration"
msgstr "Конфигурацијата е одново вчитана"
#: src/apprt/gtk/Window.zig:984
msgid "Ghostty Developers"
msgstr "Развивачи на Ghostty"
#: src/apprt/gtk/CloseDialog.zig:47
msgid "Close"
msgstr "Затвори"
@ -267,10 +272,36 @@ msgstr "Сите сесии во ова јазиче ќе бидат преки
msgid "The currently running process in this split will be terminated."
msgstr "Процесот кој моментално се извршува во оваа поделба ќе биде прекинат."
#: src/apprt/gtk/Surface.zig:1243
#: src/apprt/gtk/Surface.zig:1257
msgid "Copied to clipboard"
msgstr "Копирано во привремена меморија"
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"
msgstr "Главно мени"
#: src/apprt/gtk/Window.zig:239
msgid "View Open Tabs"
msgstr "Прегледај отворени јазичиња"
#: src/apprt/gtk/Window.zig:266
msgid "New Split"
msgstr ""
#: src/apprt/gtk/Window.zig:329
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr ""
"⚠️ Извршувате дебаг верзија на Ghostty! Перформансите ќе бидат намалени."
#: src/apprt/gtk/Window.zig:775
msgid "Reloaded the configuration"
msgstr "Конфигурацијата е одново вчитана"
#: src/apprt/gtk/Window.zig:1019
msgid "Ghostty Developers"
msgstr "Развивачи на Ghostty"
#: src/apprt/gtk/inspector.zig:144
msgid "Ghostty: Terminal Inspector"
msgstr "Ghostty: Инспектор на терминал"

View File

@ -10,7 +10,7 @@ msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
"POT-Creation-Date: 2025-04-22 08:57-0700\n"
"POT-Creation-Date: 2025-07-08 15:13-0500\n"
"PO-Revision-Date: 2025-04-14 16:25+0200\n"
"Last-Translator: cryptocode <cryptocode@zolo.io>\n"
"Language-Team: Norwegian Bokmal <l10n-no@lister.huftis.org>\n"
@ -29,7 +29,8 @@ msgid "Leave blank to restore the default title."
msgstr "Blank verdi gjenoppretter standardtittelen."
#: 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
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/ui/1.2/ccw-paste.blp:10
#: src/apprt/gtk/CloseDialog.zig:44
msgid "Cancel"
msgstr "Avbryt"
@ -38,10 +39,12 @@ msgid "OK"
msgstr "OK"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
msgid "Configuration Errors"
msgstr "Konfigurasjonsfeil"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
#: src/apprt/gtk/ui/1.2/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."
@ -50,12 +53,14 @@ msgstr ""
"under, og enten last konfigurasjonen din på nytt eller ignorer disse feilene."
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:9
msgid "Ignore"
msgstr "Ignorer"
#: 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:95
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:100
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
msgid "Reload Configuration"
msgstr "Last konfigurasjon på nytt"
@ -83,6 +88,10 @@ msgstr "Del til venstre"
msgid "Split Right"
msgstr "Del til høyre"
#: 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"
@ -90,7 +99,7 @@ msgstr "Kopier"
#: 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
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11 src/apprt/gtk/ui/1.2/ccw-paste.blp:11
msgid "Paste"
msgstr "Lim inn"
@ -120,7 +129,7 @@ msgstr "Fane"
#: 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:248
#: src/apprt/gtk/Window.zig:265
msgid "New Tab"
msgstr "Ny fane"
@ -148,29 +157,36 @@ msgid "Config"
msgstr "Konfigurasjon"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:92
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
msgid "Open Configuration"
msgstr "Åpne konfigurasjon"
#: 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 "Terminalinspektør"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:102
#: src/apprt/gtk/Window.zig:1003
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
#: src/apprt/gtk/Window.zig:1038
msgid "About Ghostty"
msgstr "Om Ghostty"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:112
msgid "Quit"
msgstr "Avslutt"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:6
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
msgid "Authorize Clipboard Access"
msgstr "Gi tilgang til utklippstavlen"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:7
msgid ""
"An application is attempting to read from the clipboard. The current "
"clipboard contents are shown below."
@ -180,15 +196,30 @@ 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
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:10
msgid "Deny"
msgstr "Avslå"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:11
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:11
msgid "Allow"
msgstr "Tillat"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
msgid "Remember choice for this split"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
msgid "Reload configuration to show this prompt again"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
msgid ""
"An application is attempting to write to the clipboard. The current "
"clipboard contents are shown below."
@ -196,11 +227,11 @@ msgstr ""
"En applikasjon forsøker å skrive til utklippstavlen. Gjeldende "
"utklippstavleinnhold er vist nedenfor."
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
msgid "Warning: Potentially Unsafe Paste"
msgstr "Adarsel: Lim inn kan være utrygt"
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/ccw-paste.blp:7
msgid ""
"Pasting this text into the terminal may be dangerous as it looks like some "
"commands may be executed."
@ -208,31 +239,6 @@ msgstr ""
"Det ser ut som at kommandoer vil bli kjørt hvis du limer inn dette, vurder "
"om du mener det er trygt."
#: src/apprt/gtk/Window.zig:201
msgid "Main Menu"
msgstr "Hovedmeny"
#: src/apprt/gtk/Window.zig:222
msgid "View Open Tabs"
msgstr "Se åpne faner"
#: src/apprt/gtk/Window.zig:249
msgid "New Split"
msgstr "Del opp vindu"
#: src/apprt/gtk/Window.zig:312
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr "⚠️ Du kjører et debug-bygg av Ghostty. Debug-bygg har redusert ytelse."
#: src/apprt/gtk/Window.zig:744
msgid "Reloaded the configuration"
msgstr "Konfigurasjonen ble lastet på nytt"
#: src/apprt/gtk/Window.zig:984
msgid "Ghostty Developers"
msgstr "Ghostty-utviklere"
#: src/apprt/gtk/CloseDialog.zig:47
msgid "Close"
msgstr "Lukk"
@ -269,10 +275,35 @@ msgstr "Alle terminaløkter i denne fanen vil bli avsluttet."
msgid "The currently running process in this split will be terminated."
msgstr "Den kjørende prosessen for denne splitten vil bli avsluttet."
#: src/apprt/gtk/Surface.zig:1243
#: src/apprt/gtk/Surface.zig:1257
msgid "Copied to clipboard"
msgstr "Kopiert til utklippstavlen"
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"
msgstr "Hovedmeny"
#: src/apprt/gtk/Window.zig:239
msgid "View Open Tabs"
msgstr "Se åpne faner"
#: src/apprt/gtk/Window.zig:266
msgid "New Split"
msgstr "Del opp vindu"
#: src/apprt/gtk/Window.zig:329
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr "⚠️ Du kjører et debug-bygg av Ghostty. Debug-bygg har redusert ytelse."
#: src/apprt/gtk/Window.zig:775
msgid "Reloaded the configuration"
msgstr "Konfigurasjonen ble lastet på nytt"
#: src/apprt/gtk/Window.zig:1019
msgid "Ghostty Developers"
msgstr "Ghostty-utviklere"
#: src/apprt/gtk/inspector.zig:144
msgid "Ghostty: Terminal Inspector"
msgstr "Ghostty: Terminalinspektør"

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
"POT-Creation-Date: 2025-04-22 08:57-0700\n"
"POT-Creation-Date: 2025-07-08 15:13-0500\n"
"PO-Revision-Date: 2025-03-24 15:00+0100\n"
"Last-Translator: Nico Geesink <geesinknico@gmail.com>\n"
"Language-Team: Dutch <vertaling@vrijschrift.org>\n"
@ -26,7 +26,8 @@ msgid "Leave blank to restore the default title."
msgstr "Laat leeg om de standaard titel te herstellen."
#: 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
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/ui/1.2/ccw-paste.blp:10
#: src/apprt/gtk/CloseDialog.zig:44
msgid "Cancel"
msgstr "Annuleren"
@ -35,10 +36,12 @@ msgid "OK"
msgstr "OK"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
msgid "Configuration Errors"
msgstr "Configuratiefouten"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
#: src/apprt/gtk/ui/1.2/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."
@ -47,12 +50,14 @@ msgstr ""
"fouten en herlaad je configuratie of negeer deze fouten."
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:9
msgid "Ignore"
msgstr "Negeer"
#: 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:95
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:100
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
msgid "Reload Configuration"
msgstr "Herlaad configuratie"
@ -80,6 +85,10 @@ msgstr "Splits naar links"
msgid "Split Right"
msgstr "Splits naar rechts"
#: 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"
@ -87,7 +96,7 @@ msgstr "Kopiëren"
#: 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
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11 src/apprt/gtk/ui/1.2/ccw-paste.blp:11
msgid "Paste"
msgstr "Plakken"
@ -117,7 +126,7 @@ msgstr "Tabblad"
#: 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:248
#: src/apprt/gtk/Window.zig:265
msgid "New Tab"
msgstr "Nieuw tabblad"
@ -145,29 +154,36 @@ msgid "Config"
msgstr "Configuratie"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:92
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
msgid "Open Configuration"
msgstr "Open configuratie"
#: 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 "Terminal inspecteur"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:102
#: src/apprt/gtk/Window.zig:1003
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
#: src/apprt/gtk/Window.zig:1038
msgid "About Ghostty"
msgstr "Over Ghostty"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:112
msgid "Quit"
msgstr "Afsluiten"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:6
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
msgid "Authorize Clipboard Access"
msgstr "Verleen toegang tot klembord"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:7
msgid ""
"An application is attempting to read from the clipboard. The current "
"clipboard contents are shown below."
@ -177,15 +193,30 @@ 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
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:10
msgid "Deny"
msgstr "Weigeren"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:11
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:11
msgid "Allow"
msgstr "Toestaan"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
msgid "Remember choice for this split"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
msgid "Reload configuration to show this prompt again"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
msgid ""
"An application is attempting to write to the clipboard. The current "
"clipboard contents are shown below."
@ -193,11 +224,11 @@ msgstr ""
"Een applicatie probeert de inhoud van het klembord te wijzigen. De huidige "
"inhoud van het klembord wordt hieronder weergegeven."
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
msgid "Warning: Potentially Unsafe Paste"
msgstr "Waarschuwing: mogelijk onveilige plakactie"
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/ccw-paste.blp:7
msgid ""
"Pasting this text into the terminal may be dangerous as it looks like some "
"commands may be executed."
@ -205,33 +236,6 @@ msgstr ""
"Het plakken van deze tekst in de terminal is mogelijk gevaarlijk, omdat het "
"lijkt op een commando dat uitgevoerd kan worden."
#: src/apprt/gtk/Window.zig:201
msgid "Main Menu"
msgstr "Hoofdmenu"
#: src/apprt/gtk/Window.zig:222
msgid "View Open Tabs"
msgstr "Open tabbladen bekijken"
#: src/apprt/gtk/Window.zig:249
msgid "New Split"
msgstr ""
#: src/apprt/gtk/Window.zig:312
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr ""
"⚠️ Je draait een debug versie van Ghostty! Prestaties zullen minder zijn dan "
"normaal."
#: src/apprt/gtk/Window.zig:744
msgid "Reloaded the configuration"
msgstr "De configuratie is herladen"
#: src/apprt/gtk/Window.zig:984
msgid "Ghostty Developers"
msgstr "Ghostty ontwikkelaars"
#: src/apprt/gtk/CloseDialog.zig:47
msgid "Close"
msgstr "Afsluiten"
@ -269,10 +273,37 @@ msgid "The currently running process in this split will be terminated."
msgstr ""
"Alle processen die nu draaien in deze splitsing zullen worden beëindigd."
#: src/apprt/gtk/Surface.zig:1243
#: src/apprt/gtk/Surface.zig:1257
msgid "Copied to clipboard"
msgstr "Gekopieerd naar klembord"
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"
msgstr "Hoofdmenu"
#: src/apprt/gtk/Window.zig:239
msgid "View Open Tabs"
msgstr "Open tabbladen bekijken"
#: src/apprt/gtk/Window.zig:266
msgid "New Split"
msgstr ""
#: src/apprt/gtk/Window.zig:329
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr ""
"⚠️ Je draait een debug versie van Ghostty! Prestaties zullen minder zijn dan "
"normaal."
#: src/apprt/gtk/Window.zig:775
msgid "Reloaded the configuration"
msgstr "De configuratie is herladen"
#: src/apprt/gtk/Window.zig:1019
msgid "Ghostty Developers"
msgstr "Ghostty ontwikkelaars"
#: src/apprt/gtk/inspector.zig:144
msgid "Ghostty: Terminal Inspector"
msgstr "Ghostty: terminal inspecteur"

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
"POT-Creation-Date: 2025-04-22 08:57-0700\n"
"POT-Creation-Date: 2025-07-08 15:13-0500\n"
"PO-Revision-Date: 2025-03-17 12:15+0100\n"
"Last-Translator: Bartosz Sokorski <b.sokorski@gmail.com>\n"
"Language-Team: Polish <translation-team-pl@lists.sourceforge.net>\n"
@ -28,7 +28,8 @@ msgid "Leave blank to restore the default title."
msgstr "Pozostaw puste by przywrócić domyślny tytuł."
#: 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
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/ui/1.2/ccw-paste.blp:10
#: src/apprt/gtk/CloseDialog.zig:44
msgid "Cancel"
msgstr "Anuluj"
@ -37,10 +38,12 @@ msgid "OK"
msgstr "OK"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
msgid "Configuration Errors"
msgstr "Błędy konfiguracji"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
#: src/apprt/gtk/ui/1.2/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."
@ -49,12 +52,14 @@ msgstr ""
"poniżej i przeładuj konfigurację lub zignoruj je."
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:9
msgid "Ignore"
msgstr "Zignoruj"
#: 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:95
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:100
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
msgid "Reload Configuration"
msgstr "Przeładuj konfigurację"
@ -82,6 +87,10 @@ msgstr "Podziel w lewo"
msgid "Split Right"
msgstr "Podziel w prawo"
#: 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"
@ -89,7 +98,7 @@ msgstr "Kopiuj"
#: 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
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11 src/apprt/gtk/ui/1.2/ccw-paste.blp:11
msgid "Paste"
msgstr "Wklej"
@ -119,7 +128,7 @@ msgstr "Karta"
#: 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:248
#: src/apprt/gtk/Window.zig:265
msgid "New Tab"
msgstr "Nowa karta"
@ -147,29 +156,36 @@ msgid "Config"
msgstr "Konfiguracja"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:92
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
msgid "Open Configuration"
msgstr "Otwórz konfigurację"
#: 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 "Inspektor terminala"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:102
#: src/apprt/gtk/Window.zig:1003
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
#: src/apprt/gtk/Window.zig:1038
msgid "About Ghostty"
msgstr "O Ghostty"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:112
msgid "Quit"
msgstr "Zamknij"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:6
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
msgid "Authorize Clipboard Access"
msgstr "Udziel dostępu do schowka"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:7
msgid ""
"An application is attempting to read from the clipboard. The current "
"clipboard contents are shown below."
@ -179,15 +195,30 @@ 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
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:10
msgid "Deny"
msgstr "Odmów"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:11
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:11
msgid "Allow"
msgstr "Zezwól"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
msgid "Remember choice for this split"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
msgid "Reload configuration to show this prompt again"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
msgid ""
"An application is attempting to write to the clipboard. The current "
"clipboard contents are shown below."
@ -195,11 +226,11 @@ msgstr ""
"Aplikacja próbuje zapisać do schowka. Obecna zawartość schowka pokazana "
"poniżej."
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
msgid "Warning: Potentially Unsafe Paste"
msgstr "Uwaga: potencjalnie niebezpieczne wklejenie ze schowka"
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/ccw-paste.blp:7
msgid ""
"Pasting this text into the terminal may be dangerous as it looks like some "
"commands may be executed."
@ -207,31 +238,6 @@ msgstr ""
"Wklejenie tego tekstu do terminala może być niebezpieczne, ponieważ może "
"spowodować wykonanie komend."
#: src/apprt/gtk/Window.zig:201
msgid "Main Menu"
msgstr "Menu główne"
#: src/apprt/gtk/Window.zig:222
msgid "View Open Tabs"
msgstr "Zobacz otwarte karty"
#: src/apprt/gtk/Window.zig:249
msgid "New Split"
msgstr ""
#: src/apprt/gtk/Window.zig:312
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr "⚠️ Używasz wersji Ghostty do debugowania! Wydajność będzie obniżona."
#: src/apprt/gtk/Window.zig:744
msgid "Reloaded the configuration"
msgstr "Przeładowano konfigurację"
#: src/apprt/gtk/Window.zig:984
msgid "Ghostty Developers"
msgstr "Twórcy Ghostty"
#: src/apprt/gtk/CloseDialog.zig:47
msgid "Close"
msgstr "Zamknij"
@ -268,10 +274,35 @@ msgstr "Wszystkie sesje terminala w obecnej karcie zostaną zakończone."
msgid "The currently running process in this split will be terminated."
msgstr "Wszyskie trwające procesy w obecnym podziale zostaną zakończone."
#: src/apprt/gtk/Surface.zig:1243
#: src/apprt/gtk/Surface.zig:1257
msgid "Copied to clipboard"
msgstr "Skopiowano do schowka"
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"
msgstr "Menu główne"
#: src/apprt/gtk/Window.zig:239
msgid "View Open Tabs"
msgstr "Zobacz otwarte karty"
#: src/apprt/gtk/Window.zig:266
msgid "New Split"
msgstr ""
#: src/apprt/gtk/Window.zig:329
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr "⚠️ Używasz wersji Ghostty do debugowania! Wydajność będzie obniżona."
#: src/apprt/gtk/Window.zig:775
msgid "Reloaded the configuration"
msgstr "Przeładowano konfigurację"
#: src/apprt/gtk/Window.zig:1019
msgid "Ghostty Developers"
msgstr "Twórcy Ghostty"
#: src/apprt/gtk/inspector.zig:144
msgid "Ghostty: Terminal Inspector"
msgstr "Inspektor terminala Ghostty"

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
"POT-Creation-Date: 2025-04-22 08:57-0700\n"
"POT-Creation-Date: 2025-07-08 15:13-0500\n"
"PO-Revision-Date: 2025-06-20 10:19-0300\n"
"Last-Translator: Mário Victor Ribeiro Silva <mariovictorrs@gmail.com>\n"
"Language-Team: Brazilian Portuguese <ldpbr-translation@lists.sourceforge."
@ -28,7 +28,8 @@ msgid "Leave blank to restore the default title."
msgstr "Deixe em branco para restaurar o título original."
#: 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
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/ui/1.2/ccw-paste.blp:10
#: src/apprt/gtk/CloseDialog.zig:44
msgid "Cancel"
msgstr "Cancelar"
@ -37,10 +38,12 @@ msgid "OK"
msgstr "OK"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
msgid "Configuration Errors"
msgstr "Erros de configuração"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
#: src/apprt/gtk/ui/1.2/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."
@ -49,12 +52,14 @@ msgstr ""
"abaixo, e ou recarregue sua configuração, ou ignore esses erros."
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:9
msgid "Ignore"
msgstr "Ignorar"
#: 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:95
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:100
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
msgid "Reload Configuration"
msgstr "Recarregar configuração"
@ -82,6 +87,10 @@ msgstr "Dividir à esquerda"
msgid "Split Right"
msgstr "Dividir à direita"
#: 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"
@ -89,7 +98,7 @@ msgstr "Copiar"
#: 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
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11 src/apprt/gtk/ui/1.2/ccw-paste.blp:11
msgid "Paste"
msgstr "Colar"
@ -119,7 +128,7 @@ msgstr "Aba"
#: 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:248
#: src/apprt/gtk/Window.zig:265
msgid "New Tab"
msgstr "Nova aba"
@ -147,29 +156,36 @@ msgid "Config"
msgstr "Configurar"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:92
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
msgid "Open Configuration"
msgstr "Abrir configuração"
#: 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 "Inspetor de terminal"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:102
#: src/apprt/gtk/Window.zig:1003
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
#: src/apprt/gtk/Window.zig:1038
msgid "About Ghostty"
msgstr "Sobre o Ghostty"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:112
msgid "Quit"
msgstr "Sair"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:6
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
msgid "Authorize Clipboard Access"
msgstr "Autorizar acesso à área de transferência"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:7
msgid ""
"An application is attempting to read from the clipboard. The current "
"clipboard contents are shown below."
@ -179,15 +195,30 @@ 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
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:10
msgid "Deny"
msgstr "Negar"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:11
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:11
msgid "Allow"
msgstr "Permitir"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
msgid "Remember choice for this split"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
msgid "Reload configuration to show this prompt again"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
msgid ""
"An application is attempting to write to the clipboard. The current "
"clipboard contents are shown below."
@ -195,11 +226,11 @@ msgstr ""
"Uma aplicação está tentando escrever na área de transferência. O conteúdo "
"atual da área de transferência está aparecendo abaixo."
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
msgid "Warning: Potentially Unsafe Paste"
msgstr "Aviso: Conteúdo potencialmente inseguro"
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/ccw-paste.blp:7
msgid ""
"Pasting this text into the terminal may be dangerous as it looks like some "
"commands may be executed."
@ -207,32 +238,6 @@ msgstr ""
"Colar esse texto em um terminal pode ser perigoso, pois parece que alguns "
"comandos podem ser executados."
#: src/apprt/gtk/Window.zig:201
msgid "Main Menu"
msgstr "Menu Principal"
#: src/apprt/gtk/Window.zig:222
msgid "View Open Tabs"
msgstr "Visualizar abas abertas"
#: src/apprt/gtk/Window.zig:249
msgid "New Split"
msgstr "Nova divisão"
#: src/apprt/gtk/Window.zig:312
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr ""
"⚠️ Você está rodando uma build de debug do Ghostty! O desempenho será afetado."
#: src/apprt/gtk/Window.zig:744
msgid "Reloaded the configuration"
msgstr "Configuração recarregada"
#: src/apprt/gtk/Window.zig:984
msgid "Ghostty Developers"
msgstr "Desenvolvedores Ghostty"
#: src/apprt/gtk/CloseDialog.zig:47
msgid "Close"
msgstr "Fechar"
@ -269,10 +274,36 @@ msgstr "Todas as sessões de terminal nessa aba serão finalizadas."
msgid "The currently running process in this split will be terminated."
msgstr "O processo atual rodando nessa divisão será finalizado."
#: src/apprt/gtk/Surface.zig:1243
#: src/apprt/gtk/Surface.zig:1257
msgid "Copied to clipboard"
msgstr "Copiado para a área de transferência"
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"
msgstr "Menu Principal"
#: src/apprt/gtk/Window.zig:239
msgid "View Open Tabs"
msgstr "Visualizar abas abertas"
#: src/apprt/gtk/Window.zig:266
msgid "New Split"
msgstr "Nova divisão"
#: src/apprt/gtk/Window.zig:329
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr ""
"⚠️ Você está rodando uma build de debug do Ghostty! O desempenho será afetado."
#: src/apprt/gtk/Window.zig:775
msgid "Reloaded the configuration"
msgstr "Configuração recarregada"
#: src/apprt/gtk/Window.zig:1019
msgid "Ghostty Developers"
msgstr "Desenvolvedores Ghostty"
#: src/apprt/gtk/inspector.zig:144
msgid "Ghostty: Terminal Inspector"
msgstr "Ghostty: Inspetor de terminal"

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
"POT-Creation-Date: 2025-04-22 08:57-0700\n"
"POT-Creation-Date: 2025-07-08 15:13-0500\n"
"PO-Revision-Date: 2025-03-24 00:01+0500\n"
"Last-Translator: blackzeshi <sergey_zhuzhgov@mail.ru>\n"
"Language-Team: Russian <gnu@d07.ru>\n"
@ -28,7 +28,8 @@ 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
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/ui/1.2/ccw-paste.blp:10
#: src/apprt/gtk/CloseDialog.zig:44
msgid "Cancel"
msgstr "Отмена"
@ -37,10 +38,12 @@ msgid "OK"
msgstr "ОК"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
msgid "Configuration Errors"
msgstr "Ошибки конфигурации"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
#: src/apprt/gtk/ui/1.2/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."
@ -49,12 +52,14 @@ msgstr ""
"конфигурацию, либо проигнорируйте ошибки."
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
#: src/apprt/gtk/ui/1.2/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:95
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:100
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
msgid "Reload Configuration"
msgstr "Обновить конфигурацию"
@ -82,6 +87,10 @@ msgstr "Сплит влево"
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"
@ -89,7 +98,7 @@ 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
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11 src/apprt/gtk/ui/1.2/ccw-paste.blp:11
msgid "Paste"
msgstr "Вставить"
@ -119,7 +128,7 @@ 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:248
#: src/apprt/gtk/Window.zig:265
msgid "New Tab"
msgstr "Новая вкладка"
@ -147,29 +156,36 @@ 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:90
#: 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:102
#: src/apprt/gtk/Window.zig:1003
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
#: src/apprt/gtk/Window.zig:1038
msgid "About Ghostty"
msgstr "О Ghostty"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
#: 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
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
msgid "Authorize Clipboard Access"
msgstr "Разрешить доступ к буферу обмена"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:7
msgid ""
"An application is attempting to read from the clipboard. The current "
"clipboard contents are shown below."
@ -179,26 +195,41 @@ 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
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.2/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
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:11
msgid "Allow"
msgstr "Разрешить"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
msgid "Remember choice for this split"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
msgid "Reload configuration to show this prompt again"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
#: src/apprt/gtk/ui/1.2/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
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
msgid "Warning: Potentially Unsafe Paste"
msgstr "Внимание! Вставляемые данные могут нанести вред вашей системе"
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/ccw-paste.blp:7
msgid ""
"Pasting this text into the terminal may be dangerous as it looks like some "
"commands may be executed."
@ -206,33 +237,6 @@ msgstr ""
"Вставка этого текста в терминал может быть опасной. Это выглядит как "
"команды, которые могут быть исполнены."
#: src/apprt/gtk/Window.zig:201
msgid "Main Menu"
msgstr "Главное меню"
#: src/apprt/gtk/Window.zig:222
msgid "View Open Tabs"
msgstr "Просмотреть открытые вкладки"
#: src/apprt/gtk/Window.zig:249
msgid "New Split"
msgstr ""
#: src/apprt/gtk/Window.zig:312
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr ""
"⚠️ Вы запустили отладочную сборку Ghostty! Это может влиять на "
"производительность."
#: src/apprt/gtk/Window.zig:744
msgid "Reloaded the configuration"
msgstr "Конфигурация была обновлена"
#: src/apprt/gtk/Window.zig:984
msgid "Ghostty Developers"
msgstr "Разработчики Ghostty"
#: src/apprt/gtk/CloseDialog.zig:47
msgid "Close"
msgstr "Закрыть"
@ -269,10 +273,37 @@ msgstr "Все сессии терминала в этой вкладке буд
msgid "The currently running process in this split will be terminated."
msgstr "Процесс, работающий в этой сплит-области, будет остановлен."
#: src/apprt/gtk/Surface.zig:1243
#: src/apprt/gtk/Surface.zig:1257
msgid "Copied to clipboard"
msgstr "Скопировано в буфер обмена"
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"
msgstr "Главное меню"
#: src/apprt/gtk/Window.zig:239
msgid "View Open Tabs"
msgstr "Просмотреть открытые вкладки"
#: src/apprt/gtk/Window.zig:266
msgid "New Split"
msgstr ""
#: src/apprt/gtk/Window.zig:329
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr ""
"⚠️ Вы запустили отладочную сборку Ghostty! Это может влиять на "
"производительность."
#: src/apprt/gtk/Window.zig:775
msgid "Reloaded the configuration"
msgstr "Конфигурация была обновлена"
#: src/apprt/gtk/Window.zig:1019
msgid "Ghostty Developers"
msgstr "Разработчики Ghostty"
#: src/apprt/gtk/inspector.zig:144
msgid "Ghostty: Terminal Inspector"
msgstr "Ghostty: инспектор терминала"

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
"POT-Creation-Date: 2025-04-22 08:57-0700\n"
"POT-Creation-Date: 2025-07-08 15:13-0500\n"
"PO-Revision-Date: 2025-03-24 22:01+0300\n"
"Last-Translator: Emir SARI <emir_sari@icloud.com>\n"
"Language-Team: Turkish\n"
@ -26,7 +26,8 @@ msgid "Leave blank to restore the default title."
msgstr "Öntanımlı başlığı geri yüklemek için boş bırakın."
#: 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
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/ui/1.2/ccw-paste.blp:10
#: src/apprt/gtk/CloseDialog.zig:44
msgid "Cancel"
msgstr "İptal"
@ -35,10 +36,12 @@ msgid "OK"
msgstr "Tamam"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
msgid "Configuration Errors"
msgstr "Yapılandırma Hataları"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
#: src/apprt/gtk/ui/1.2/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."
@ -48,12 +51,14 @@ msgstr ""
"hataları yok sayın."
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:9
msgid "Ignore"
msgstr "Yok Say"
#: 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:95
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:100
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
msgid "Reload Configuration"
msgstr "Yapılandırmayı Yeniden Yükle"
@ -81,6 +86,10 @@ msgstr "Sola Doğru Böl"
msgid "Split Right"
msgstr "Sağa Doğru Böl"
#: 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"
@ -88,7 +97,7 @@ msgstr "Kopyala"
#: 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
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11 src/apprt/gtk/ui/1.2/ccw-paste.blp:11
msgid "Paste"
msgstr "Yapıştır"
@ -118,7 +127,7 @@ msgstr "Sekme"
#: 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:248
#: src/apprt/gtk/Window.zig:265
msgid "New Tab"
msgstr "Yeni Sekme"
@ -146,29 +155,36 @@ msgid "Config"
msgstr "Yapılandırma"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:92
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
msgid "Open Configuration"
msgstr "Yapılandırmayı Aç"
#: 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 "Uçbirim Denetçisi"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:102
#: src/apprt/gtk/Window.zig:1003
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
#: src/apprt/gtk/Window.zig:1038
msgid "About Ghostty"
msgstr "Ghostty Hakkında"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:112
msgid "Quit"
msgstr "Çık"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:6
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
msgid "Authorize Clipboard Access"
msgstr "Pano Erişimine İzin Ver"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:7
msgid ""
"An application is attempting to read from the clipboard. The current "
"clipboard contents are shown below."
@ -178,15 +194,30 @@ 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
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:10
msgid "Deny"
msgstr "Reddet"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:11
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:11
msgid "Allow"
msgstr "İzin Ver"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
msgid "Remember choice for this split"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
msgid "Reload configuration to show this prompt again"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
msgid ""
"An application is attempting to write to the clipboard. The current "
"clipboard contents are shown below."
@ -194,11 +225,11 @@ msgstr ""
"Bir uygulama panoya yazmaya çalışıyor. Geçerli pano içeriği aşağıda "
"gösterilmektedir."
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
msgid "Warning: Potentially Unsafe Paste"
msgstr "Uyarı: Tehlikeli Olabilecek Yapıştırma"
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/ccw-paste.blp:7
msgid ""
"Pasting this text into the terminal may be dangerous as it looks like some "
"commands may be executed."
@ -206,33 +237,6 @@ msgstr ""
"Bu metni uçbirime yapıştırmak tehlikeli olabilir; çünkü bir komut "
"yürütülebilecekmiş gibi duruyor."
#: src/apprt/gtk/Window.zig:201
msgid "Main Menu"
msgstr "Ana Menü"
#: src/apprt/gtk/Window.zig:222
msgid "View Open Tabs"
msgstr "Açık Sekmeleri Görüntüle"
#: src/apprt/gtk/Window.zig:249
msgid "New Split"
msgstr "Yeni Bölme"
#: src/apprt/gtk/Window.zig:312
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr ""
"⚠️ Ghosttynin hata ayıklama amaçlı yapılmış bir sürümünü kullanıyorsunuz! "
"Başarım normale göre daha düşük olacaktır."
#: src/apprt/gtk/Window.zig:744
msgid "Reloaded the configuration"
msgstr "Yapılandırma yeniden yüklendi"
#: src/apprt/gtk/Window.zig:984
msgid "Ghostty Developers"
msgstr "Ghostty Geliştiricileri"
#: src/apprt/gtk/CloseDialog.zig:47
msgid "Close"
msgstr "Kapat"
@ -269,10 +273,37 @@ msgstr "Bu sekmedeki tüm uçbirim oturumları sonlandırılacaktır."
msgid "The currently running process in this split will be terminated."
msgstr "Bu bölmedeki şu anda çalışan süreç sonlandırılacaktır."
#: src/apprt/gtk/Surface.zig:1243
#: src/apprt/gtk/Surface.zig:1257
msgid "Copied to clipboard"
msgstr "Panoya kopyalandı"
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"
msgstr "Ana Menü"
#: src/apprt/gtk/Window.zig:239
msgid "View Open Tabs"
msgstr "Açık Sekmeleri Görüntüle"
#: src/apprt/gtk/Window.zig:266
msgid "New Split"
msgstr "Yeni Bölme"
#: src/apprt/gtk/Window.zig:329
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr ""
"⚠️ Ghosttynin hata ayıklama amaçlı yapılmış bir sürümünü kullanıyorsunuz! "
"Başarım normale göre daha düşük olacaktır."
#: src/apprt/gtk/Window.zig:775
msgid "Reloaded the configuration"
msgstr "Yapılandırma yeniden yüklendi"
#: src/apprt/gtk/Window.zig:1019
msgid "Ghostty Developers"
msgstr "Ghostty Geliştiricileri"
#: src/apprt/gtk/inspector.zig:144
msgid "Ghostty: Terminal Inspector"
msgstr "Ghostty: Uçbirim Denetçisi"

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
"POT-Creation-Date: 2025-04-22 08:57-0700\n"
"POT-Creation-Date: 2025-07-08 15:13-0500\n"
"PO-Revision-Date: 2025-03-16 20:16+0200\n"
"Last-Translator: Danylo Zalizchuk <danilmail0110@gmail.com>\n"
"Language-Team: Ukrainian <trans-uk@lists.fedoraproject.org>\n"
@ -27,7 +27,8 @@ 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
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/ui/1.2/ccw-paste.blp:10
#: src/apprt/gtk/CloseDialog.zig:44
msgid "Cancel"
msgstr "Відмінити"
@ -36,10 +37,12 @@ msgid "OK"
msgstr "ОК"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
msgid "Configuration Errors"
msgstr "Помилки конфігурації"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
#: src/apprt/gtk/ui/1.2/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."
@ -49,12 +52,14 @@ msgstr ""
"ці помилки."
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
#: src/apprt/gtk/ui/1.2/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:95
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:100
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
msgid "Reload Configuration"
msgstr "Перезавантажити конфігурацію"
@ -82,6 +87,10 @@ msgstr "Розділити панель ліворуч"
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"
@ -89,7 +98,7 @@ 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
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11 src/apprt/gtk/ui/1.2/ccw-paste.blp:11
msgid "Paste"
msgstr "Вставити"
@ -119,7 +128,7 @@ 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:248
#: src/apprt/gtk/Window.zig:265
msgid "New Tab"
msgstr "Нова вкладка"
@ -147,29 +156,36 @@ 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:90
#: 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:102
#: src/apprt/gtk/Window.zig:1003
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
#: src/apprt/gtk/Window.zig:1038
msgid "About Ghostty"
msgstr "Про Ghostty"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
#: 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
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
msgid "Authorize Clipboard Access"
msgstr "Дозволити доступ до буфера обміну"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:7
msgid ""
"An application is attempting to read from the clipboard. The current "
"clipboard contents are shown below."
@ -179,15 +195,30 @@ 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
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.2/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
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:11
msgid "Allow"
msgstr "Дозволити"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
msgid "Remember choice for this split"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
msgid "Reload configuration to show this prompt again"
msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
msgid ""
"An application is attempting to write to the clipboard. The current "
"clipboard contents are shown below."
@ -195,11 +226,11 @@ msgstr ""
"Програма намагається записати дані до буфера обміну. Нижче показано поточний "
"вміст буфера обміну."
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
msgid "Warning: Potentially Unsafe Paste"
msgstr "Увага: потенційно небезпечна вставка"
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/ccw-paste.blp:7
msgid ""
"Pasting this text into the terminal may be dangerous as it looks like some "
"commands may be executed."
@ -207,32 +238,6 @@ msgstr ""
"Вставка цього тексту в термінал може бути небезпечною, оскільки виглядає "
"так, ніби деякі команди можуть бути виконані."
#: src/apprt/gtk/Window.zig:201
msgid "Main Menu"
msgstr "Головне меню"
#: src/apprt/gtk/Window.zig:222
msgid "View Open Tabs"
msgstr "Переглянути відкриті вкладки"
#: src/apprt/gtk/Window.zig:249
msgid "New Split"
msgstr ""
#: src/apprt/gtk/Window.zig:312
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr ""
"⚠️ Ви використовуєте відладочну збірку Ghostty! Продуктивність буде погіршено."
#: src/apprt/gtk/Window.zig:744
msgid "Reloaded the configuration"
msgstr "Конфігурацію перезавантажено"
#: src/apprt/gtk/Window.zig:984
msgid "Ghostty Developers"
msgstr "Розробники Ghostty"
#: src/apprt/gtk/CloseDialog.zig:47
msgid "Close"
msgstr "Закрити"
@ -270,10 +275,36 @@ msgid "The currently running process in this split will be terminated."
msgstr ""
"Поточний процес, що виконується в цій розділеній панелі, буде завершено."
#: src/apprt/gtk/Surface.zig:1243
#: src/apprt/gtk/Surface.zig:1257
msgid "Copied to clipboard"
msgstr "Скопійовано в буфер обміну"
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"
msgstr "Головне меню"
#: src/apprt/gtk/Window.zig:239
msgid "View Open Tabs"
msgstr "Переглянути відкриті вкладки"
#: src/apprt/gtk/Window.zig:266
msgid "New Split"
msgstr ""
#: src/apprt/gtk/Window.zig:329
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr ""
"⚠️ Ви використовуєте відладочну збірку Ghostty! Продуктивність буде погіршено."
#: src/apprt/gtk/Window.zig:775
msgid "Reloaded the configuration"
msgstr "Конфігурацію перезавантажено"
#: src/apprt/gtk/Window.zig:1019
msgid "Ghostty Developers"
msgstr "Розробники Ghostty"
#: src/apprt/gtk/inspector.zig:144
msgid "Ghostty: Terminal Inspector"
msgstr "Ghostty: Інспектор терміналу"

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
"POT-Creation-Date: 2025-06-28 17:01+0200\n"
"POT-Creation-Date: 2025-07-08 15:13-0500\n"
"PO-Revision-Date: 2025-02-27 09:16+0100\n"
"Last-Translator: Leah <hi@pluie.me>\n"
"Language-Team: Chinese (simplified) <i18n-zh@googlegroups.com>\n"
@ -125,7 +125,7 @@ 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:263
#: src/apprt/gtk/Window.zig:265
msgid "New Tab"
msgstr "新建标签页"
@ -166,7 +166,7 @@ msgid "Terminal Inspector"
msgstr "终端调试器"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
#: src/apprt/gtk/Window.zig:1036
#: src/apprt/gtk/Window.zig:1038
msgid "About Ghostty"
msgstr "关于 Ghostty"
@ -229,35 +229,6 @@ msgid ""
"commands may be executed."
msgstr "将以下内容粘贴至终端内将可能执行有害命令。"
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"
msgstr "主菜单"
#: src/apprt/gtk/Window.zig:238
msgid "View Open Tabs"
msgstr "浏览标签页"
#: src/apprt/gtk/Window.zig:264
msgid "New Split"
msgstr "新建分屏"
#: src/apprt/gtk/Window.zig:327
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr "⚠️ Ghostty 正在以调试模式运行!性能将大打折扣。"
#: src/apprt/gtk/Window.zig:773
msgid "Reloaded the configuration"
msgstr "已重新加载配置"
#: src/apprt/gtk/Window.zig:1017
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 "关闭"
@ -297,3 +268,32 @@ msgstr "分屏内正在运行中的进程将被终止。"
#: src/apprt/gtk/Surface.zig:1257
msgid "Copied to clipboard"
msgstr "已复制至剪贴板"
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"
msgstr "主菜单"
#: src/apprt/gtk/Window.zig:239
msgid "View Open Tabs"
msgstr "浏览标签页"
#: src/apprt/gtk/Window.zig:266
msgid "New Split"
msgstr "新建分屏"
#: src/apprt/gtk/Window.zig:329
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr "⚠️ Ghostty 正在以调试模式运行!性能将大打折扣。"
#: src/apprt/gtk/Window.zig:775
msgid "Reloaded the configuration"
msgstr "已重新加载配置"
#: src/apprt/gtk/Window.zig:1019
msgid "Ghostty Developers"
msgstr "Ghostty 开发团队"
#: src/apprt/gtk/inspector.zig:144
msgid "Ghostty: Terminal Inspector"
msgstr "Ghostty 终端调试器"

View File

@ -29,6 +29,7 @@ const apprt = @import("../../apprt.zig");
const configpkg = @import("../../config.zig");
const input = @import("../../input.zig");
const internal_os = @import("../../os/main.zig");
const systemd = @import("../../os/systemd.zig");
const terminal = @import("../../terminal/main.zig");
const Config = configpkg.Config;
const CoreApp = @import("../../App.zig");
@ -496,7 +497,7 @@ pub fn performAction(
.resize_split => self.resizeSplit(target, value),
.equalize_splits => self.equalizeSplits(target),
.goto_split => return self.gotoSplit(target, value),
.open_config => try configpkg.edit.open(self.core_app.alloc),
.open_config => return self.openConfig(),
.config_change => self.configChange(target, value.config),
.reload_config => try self.reloadConfig(target, value),
.inspector => self.controlInspector(target, value),
@ -1035,6 +1036,12 @@ pub fn reloadConfig(
target: apprt.action.Target,
opts: apprt.action.ReloadConfig,
) !void {
// Tell systemd that reloading has started.
systemd.notify.reloading();
// When we exit this function tell systemd that reloading has finished.
defer systemd.notify.ready();
if (opts.soft) {
switch (target) {
.app => try self.core_app.updateConfig(self, &self.config),
@ -1367,6 +1374,9 @@ pub fn run(self: *App) !void {
log.warn("error handling configuration changes err={}", .{err});
};
// Tell systemd that we are ready.
systemd.notify.ready();
while (self.running) {
_ = glib.MainContext.iteration(self.ctx, 1);
@ -1759,7 +1769,22 @@ fn initActions(self: *App) void {
}
}
pub fn openUrl(
fn openConfig(self: *App) !bool {
// Get the config file path
const alloc = self.core_app.alloc;
const path = configpkg.edit.openPath(alloc) catch |err| {
log.warn("error getting config file path: {}", .{err});
return false;
};
defer alloc.free(path);
// Open it using openURL. "path" isn't actually a URL but
// at the time of writing that works just fine for GTK.
self.openUrl(.{ .kind = .text, .url = path });
return true;
}
fn openUrl(
app: *App,
value: apprt.action.OpenUrl,
) void {

View File

@ -2333,6 +2333,7 @@ pub fn defaultTermioEnv(self: *Surface) !std.process.EnvMap {
env.remove("DBUS_STARTER_BUS_TYPE");
env.remove("INVOCATION_ID");
env.remove("JOURNAL_STREAM");
env.remove("NOTIFY_SOCKET");
// Unset environment varies set by snaps if we're running in a snap.
// This allows Ghostty to further launch additional snaps.

View File

@ -103,7 +103,7 @@ pub inline fn runtimeUntil(
test "atLeast" {
const testing = std.testing;
const funs = &.{ atLeast, runtimeAtLeast, runtimeUntil };
const funs = &.{ atLeast, runtimeAtLeast };
inline for (funs) |fun| {
try testing.expect(fun(c.GTK_MAJOR_VERSION, c.GTK_MINOR_VERSION, c.GTK_MICRO_VERSION));
@ -118,3 +118,23 @@ test "atLeast" {
try testing.expect(fun(c.GTK_MAJOR_VERSION, c.GTK_MINOR_VERSION - 1, c.GTK_MICRO_VERSION + 1));
}
}
test "runtimeUntil" {
const testing = std.testing;
// This is an array in case we add a comptime variant.
const funs = &.{runtimeUntil};
inline for (funs) |fun| {
try testing.expect(!fun(c.GTK_MAJOR_VERSION, c.GTK_MINOR_VERSION, c.GTK_MICRO_VERSION));
try testing.expect(fun(c.GTK_MAJOR_VERSION, c.GTK_MINOR_VERSION, c.GTK_MICRO_VERSION + 1));
try testing.expect(fun(c.GTK_MAJOR_VERSION, c.GTK_MINOR_VERSION + 1, c.GTK_MICRO_VERSION));
try testing.expect(fun(c.GTK_MAJOR_VERSION + 1, c.GTK_MINOR_VERSION, c.GTK_MICRO_VERSION));
try testing.expect(!fun(c.GTK_MAJOR_VERSION - 1, c.GTK_MINOR_VERSION, c.GTK_MICRO_VERSION));
try testing.expect(!fun(c.GTK_MAJOR_VERSION - 1, c.GTK_MINOR_VERSION + 1, c.GTK_MICRO_VERSION));
try testing.expect(!fun(c.GTK_MAJOR_VERSION - 1, c.GTK_MINOR_VERSION, c.GTK_MICRO_VERSION + 1));
try testing.expect(!fun(c.GTK_MAJOR_VERSION, c.GTK_MINOR_VERSION - 1, c.GTK_MICRO_VERSION + 1));
}
}

View File

@ -115,7 +115,8 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyDist {
// Capture stderr so it doesn't spew into the parent build.
// On the flip side, if the test fails we won't know why so
// that sucks but we should have already ran tests at this point.
_ = step.captureStdErr();
// NOTE(mitchellh): temporarily disabled to diagnose heisenbug
//_ = step.captureStdErr();
break :step step;
};

View File

@ -79,24 +79,38 @@ fn createUpdateStep(b: *std.Build) !*std.Build.Step {
xgettext.has_side_effects = true;
inline for (gresource.blueprint_files) |blp| {
// We avoid using addFileArg here since the full, absolute file path
// would be added to the file as its location, which differs for
// everyone's checkout of the repository.
// This comes at a cost of losing per-file caching, of course.
xgettext.addArg(std.fmt.comptimePrint(
const path = std.fmt.comptimePrint(
"src/apprt/gtk/ui/{[major]}.{[minor]}/{[name]s}.blp",
blp,
));
);
// The arguments to xgettext must be the relative path in the build root
// or the resulting files will contain the absolute path. This will cause
// a lot of churn because not everyone has the Ghostty code checked out in
// exactly the same location.
xgettext.addArg(path);
// Mark the file as an input so that the Zig build system caching will work.
xgettext.addFileInput(b.path(path));
}
{
var gtk_files = try b.build_root.handle.openDir(
// Iterate over all of the files underneath `src/apprt/gtk`. We store
// them in an array so that they can be sorted into a determininistic
// order. That will minimize code churn as directory walking is not
// guaranteed to happen in any particular order.
var gtk_files: std.ArrayListUnmanaged([]const u8) = .empty;
defer {
for (gtk_files.items) |item| b.allocator.free(item);
gtk_files.deinit(b.allocator);
}
var gtk_dir = try b.build_root.handle.openDir(
"src/apprt/gtk",
.{ .iterate = true },
);
defer gtk_files.close();
defer gtk_dir.close();
var walk = try gtk_files.walk(b.allocator);
var walk = try gtk_dir.walk(b.allocator);
defer walk.deinit();
while (try walk.next()) |src| {
switch (src.kind) {
@ -109,7 +123,29 @@ fn createUpdateStep(b: *std.Build) !*std.Build.Step {
else => continue,
}
xgettext.addArg((b.pathJoin(&.{ "src/apprt/gtk", src.path })));
try gtk_files.append(b.allocator, try b.allocator.dupe(u8, src.path));
}
std.mem.sort(
[]const u8,
gtk_files.items,
{},
struct {
fn lt(_: void, lhs: []const u8, rhs: []const u8) bool {
return std.mem.order(u8, lhs, rhs) == .lt;
}
}.lt,
);
for (gtk_files.items) |item| {
const path = b.pathJoin(&.{ "src/apprt/gtk", item });
// The arguments to xgettext must be the relative path in the build root
// or the resulting files will contain the absolute path. This will
// cause a lot of churn because not everyone has the Ghostty code
// checked out in exactly the same location.
xgettext.addArg(path);
// Mark the file as an input so that the Zig build system caching will work.
xgettext.addFileInput(b.path(path));
}
}
@ -120,7 +156,7 @@ fn createUpdateStep(b: *std.Build) !*std.Build.Step {
);
inline for (internal_os.i18n.locales) |locale| {
const msgmerge = b.addSystemCommand(&.{ "msgmerge", "-q" });
const msgmerge = b.addSystemCommand(&.{ "msgmerge", "--quiet", "--no-fuzzy-matching" });
msgmerge.addFileArg(b.path("po/" ++ locale ++ ".po"));
msgmerge.addFileArg(xgettext.captureStdOut());
usf.addCopyFileToSource(msgmerge.captureStdOut(), "po/" ++ locale ++ ".po");

View File

@ -767,6 +767,9 @@ pub fn gtkDistResources(
});
const resources_c = generate_c.addOutputFileArg("ghostty_resources.c");
generate_c.addFileArg(gresource_xml);
for (gresource.dependencies) |file| {
generate_c.addFileInput(b.path(file));
}
const generate_h = b.addSystemCommand(&.{
"glib-compile-resources",
@ -777,6 +780,9 @@ pub fn gtkDistResources(
});
const resources_h = generate_h.addOutputFileArg("ghostty_resources.h");
generate_h.addFileArg(gresource_xml);
for (gresource.dependencies) |file| {
generate_h.addFileInput(b.path(file));
}
return .{
.resources_c = .{

View File

@ -9,6 +9,7 @@ const list_keybinds = @import("list_keybinds.zig");
const list_themes = @import("list_themes.zig");
const list_colors = @import("list_colors.zig");
const list_actions = @import("list_actions.zig");
const ssh_cache = @import("ssh_cache.zig");
const edit_config = @import("edit_config.zig");
const show_config = @import("show_config.zig");
const validate_config = @import("validate_config.zig");
@ -41,6 +42,9 @@ pub const Action = enum {
/// List keybind actions
@"list-actions",
/// Manage SSH terminfo cache for automatic remote host setup
@"ssh-cache",
/// Edit the config file in the configured terminal editor.
@"edit-config",
@ -155,6 +159,7 @@ pub const Action = enum {
.@"list-themes" => try list_themes.run(alloc),
.@"list-colors" => try list_colors.run(alloc),
.@"list-actions" => try list_actions.run(alloc),
.@"ssh-cache" => try ssh_cache.run(alloc),
.@"edit-config" => try edit_config.run(alloc),
.@"show-config" => try show_config.run(alloc),
.@"validate-config" => try validate_config.run(alloc),
@ -192,6 +197,7 @@ pub const Action = enum {
.@"list-themes" => list_themes.Options,
.@"list-colors" => list_colors.Options,
.@"list-actions" => list_actions.Options,
.@"ssh-cache" => ssh_cache.Options,
.@"edit-config" => edit_config.Options,
.@"show-config" => show_config.Options,
.@"validate-config" => validate_config.Options,

View File

@ -0,0 +1,549 @@
/// An SSH terminfo entry cache that stores its cache data on
/// disk. The cache only stores metadata (hostname, terminfo value,
/// etc.) and does not store any sensitive data.
const DiskCache = @This();
const std = @import("std");
const assert = std.debug.assert;
const Allocator = std.mem.Allocator;
const xdg = @import("../../os/main.zig").xdg;
const TempDir = @import("../../os/main.zig").TempDir;
const Entry = @import("Entry.zig");
// 512KB - sufficient for approximately 10k entries
const MAX_CACHE_SIZE = 512 * 1024;
/// Path to a file where the cache is stored.
path: []const u8,
pub const DefaultPathError = Allocator.Error || error{
/// The general error that is returned for any filesystem error
/// that may have resulted in the XDG lookup failing.
XdgLookupFailed,
};
pub const Error = error{ CacheIsLocked, HostnameIsInvalid };
/// Returns the default path for the cache for a given program.
///
/// On all platforms, this is `${XDG_STATE_HOME}/ghostty/ssh_cache`.
///
/// The returned value is allocated and must be freed by the caller.
pub fn defaultPath(
alloc: Allocator,
program: []const u8,
) DefaultPathError![]const u8 {
const state_dir: []const u8 = xdg.state(
alloc,
.{ .subdir = program },
) catch |err| return switch (err) {
error.OutOfMemory => error.OutOfMemory,
else => error.XdgLookupFailed,
};
defer alloc.free(state_dir);
return try std.fs.path.join(alloc, &.{ state_dir, "ssh_cache" });
}
/// Clear all cache data stored in the disk cache.
/// This removes the cache file from disk, effectively clearing all cached
/// SSH terminfo entries.
pub fn clear(self: DiskCache) !void {
std.fs.cwd().deleteFile(self.path) catch |err| switch (err) {
error.FileNotFound => {},
else => return err,
};
}
pub const AddResult = enum { added, updated };
/// Add or update a hostname entry in the cache.
/// Returns AddResult.added for new entries or AddResult.updated for existing ones.
/// The cache file is created if it doesn't exist with secure permissions (0600).
pub fn add(
self: DiskCache,
alloc: Allocator,
hostname: []const u8,
) !AddResult {
if (!isValidCacheKey(hostname)) return error.HostnameIsInvalid;
// Create cache directory if needed
if (std.fs.path.dirname(self.path)) |dir| {
std.fs.makeDirAbsolute(dir) catch |err| switch (err) {
error.PathAlreadyExists => {},
else => return err,
};
}
// Open or create cache file with secure permissions
const file = std.fs.createFileAbsolute(self.path, .{
.read = true,
.truncate = false,
.mode = 0o600,
}) catch |err| switch (err) {
error.PathAlreadyExists => blk: {
const existing_file = try std.fs.openFileAbsolute(
self.path,
.{ .mode = .read_write },
);
errdefer existing_file.close();
try fixupPermissions(existing_file);
break :blk existing_file;
},
else => return err,
};
defer file.close();
// Lock
_ = file.tryLock(.exclusive) catch return error.CacheIsLocked;
defer file.unlock();
var entries = try readEntries(alloc, file);
defer deinitEntries(alloc, &entries);
// Add or update entry
const gop = try entries.getOrPut(hostname);
const result: AddResult = if (!gop.found_existing) add: {
const hostname_copy = try alloc.dupe(u8, hostname);
errdefer alloc.free(hostname_copy);
const terminfo_copy = try alloc.dupe(u8, "xterm-ghostty");
errdefer alloc.free(terminfo_copy);
gop.key_ptr.* = hostname_copy;
gop.value_ptr.* = .{
.hostname = gop.key_ptr.*,
.timestamp = std.time.timestamp(),
.terminfo_version = terminfo_copy,
};
break :add .added;
} else update: {
// Update timestamp for existing entry
gop.value_ptr.timestamp = std.time.timestamp();
break :update .updated;
};
try self.writeCacheFile(alloc, entries, null);
return result;
}
/// Remove a hostname entry from the cache.
/// No error is returned if the hostname doesn't exist or the cache file is missing.
pub fn remove(
self: DiskCache,
alloc: Allocator,
hostname: []const u8,
) !void {
if (!isValidCacheKey(hostname)) return error.HostnameIsInvalid;
// Open our file
const file = std.fs.openFileAbsolute(
self.path,
.{ .mode = .read_write },
) catch |err| switch (err) {
error.FileNotFound => return,
else => return err,
};
defer file.close();
try fixupPermissions(file);
// Acquire exclusive lock
_ = file.tryLock(.exclusive) catch return error.CacheIsLocked;
defer file.unlock();
// Read existing entries
var entries = try readEntries(alloc, file);
defer deinitEntries(alloc, &entries);
// Remove the entry if it exists and ensure we free the memory
if (entries.fetchRemove(hostname)) |kv| {
assert(kv.key.ptr == kv.value.hostname.ptr);
alloc.free(kv.value.hostname);
alloc.free(kv.value.terminfo_version);
}
try self.writeCacheFile(alloc, entries, null);
}
/// Check if a hostname exists in the cache.
/// Returns false if the cache file doesn't exist.
pub fn contains(
self: DiskCache,
alloc: Allocator,
hostname: []const u8,
) !bool {
if (!isValidCacheKey(hostname)) return error.HostnameIsInvalid;
// Open our file
const file = std.fs.openFileAbsolute(
self.path,
.{ .mode = .read_write },
) catch |err| switch (err) {
error.FileNotFound => return false,
else => return err,
};
defer file.close();
try fixupPermissions(file);
// Read existing entries
var entries = try readEntries(alloc, file);
defer deinitEntries(alloc, &entries);
return entries.contains(hostname);
}
fn fixupPermissions(file: std.fs.File) !void {
// Ensure file has correct permissions (readable/writable by
// owner only)
const stat = try file.stat();
if (stat.mode & 0o777 != 0o600) {
try file.chmod(0o600);
}
}
fn writeCacheFile(
self: DiskCache,
alloc: Allocator,
entries: std.StringHashMap(Entry),
expire_days: ?u32,
) !void {
var td: TempDir = try .init();
defer td.deinit();
const tmp_file = try td.dir.createFile("ssh-cache", .{ .mode = 0o600 });
defer tmp_file.close();
const tmp_path = try td.dir.realpathAlloc(alloc, "ssh-cache");
defer alloc.free(tmp_path);
const writer = tmp_file.writer();
var iter = entries.iterator();
while (iter.next()) |kv| {
// Only write non-expired entries
if (kv.value_ptr.isExpired(expire_days)) continue;
try kv.value_ptr.format(writer);
}
// Atomic replace
try std.fs.renameAbsolute(tmp_path, self.path);
}
/// List all entries in the cache.
/// The returned HashMap must be freed using `deinitEntries`.
/// Returns an empty map if the cache file doesn't exist.
pub fn list(
self: DiskCache,
alloc: Allocator,
) !std.StringHashMap(Entry) {
// Open our file
const file = std.fs.openFileAbsolute(
self.path,
.{},
) catch |err| switch (err) {
error.FileNotFound => return .init(alloc),
else => return err,
};
defer file.close();
return readEntries(alloc, file);
}
/// Free memory allocated by the `list` function.
/// This must be called to properly deallocate all entry data.
pub fn deinitEntries(
alloc: Allocator,
entries: *std.StringHashMap(Entry),
) void {
// All our entries we dupe the memory owned by the hostname and the
// terminfo, and we always match the hostname key and value.
var it = entries.iterator();
while (it.next()) |entry| {
assert(entry.key_ptr.*.ptr == entry.value_ptr.hostname.ptr);
alloc.free(entry.value_ptr.hostname);
alloc.free(entry.value_ptr.terminfo_version);
}
entries.deinit();
}
fn readEntries(
alloc: Allocator,
file: std.fs.File,
) !std.StringHashMap(Entry) {
const content = try file.readToEndAlloc(alloc, MAX_CACHE_SIZE);
defer alloc.free(content);
var entries = std.StringHashMap(Entry).init(alloc);
var lines = std.mem.tokenizeScalar(u8, content, '\n');
while (lines.next()) |line| {
const trimmed = std.mem.trim(u8, line, " \t\r");
const entry = Entry.parse(trimmed) orelse continue;
// Always allocate hostname first to avoid key pointer confusion
const hostname = try alloc.dupe(u8, entry.hostname);
errdefer alloc.free(hostname);
const gop = try entries.getOrPut(hostname);
if (!gop.found_existing) {
const terminfo_copy = try alloc.dupe(u8, entry.terminfo_version);
gop.value_ptr.* = .{
.hostname = hostname,
.timestamp = entry.timestamp,
.terminfo_version = terminfo_copy,
};
} else {
// Don't need the copy since entry already exists
alloc.free(hostname);
// Handle duplicate entries - keep newer timestamp
if (entry.timestamp > gop.value_ptr.timestamp) {
gop.value_ptr.timestamp = entry.timestamp;
if (!std.mem.eql(
u8,
gop.value_ptr.terminfo_version,
entry.terminfo_version,
)) {
alloc.free(gop.value_ptr.terminfo_version);
const terminfo_copy = try alloc.dupe(u8, entry.terminfo_version);
gop.value_ptr.terminfo_version = terminfo_copy;
}
}
}
}
return entries;
}
// Supports both standalone hostnames and user@hostname format
fn isValidCacheKey(key: []const u8) bool {
// 253 + 1 + 64 for user@hostname
if (key.len == 0 or key.len > 320) return false;
// Check for user@hostname format
if (std.mem.indexOf(u8, key, "@")) |at_pos| {
const user = key[0..at_pos];
const hostname = key[at_pos + 1 ..];
return isValidUser(user) and isValidHostname(hostname);
}
return isValidHostname(key);
}
// Basic hostname validation - accepts domains and IPs
// (including IPv6 in brackets)
fn isValidHostname(host: []const u8) bool {
if (host.len == 0 or host.len > 253) return false;
// Handle IPv6 addresses in brackets
if (host.len >= 4 and host[0] == '[' and host[host.len - 1] == ']') {
const ipv6_part = host[1 .. host.len - 1];
if (ipv6_part.len == 0) return false;
var has_colon = false;
for (ipv6_part) |c| {
switch (c) {
'a'...'f', 'A'...'F', '0'...'9' => {},
':' => has_colon = true,
else => return false,
}
}
return has_colon;
}
// Standard hostname/domain validation
for (host) |c| {
switch (c) {
'a'...'z', 'A'...'Z', '0'...'9', '.', '-' => {},
else => return false,
}
}
// No leading/trailing dots or hyphens, no consecutive dots
if (host[0] == '.' or host[0] == '-' or
host[host.len - 1] == '.' or host[host.len - 1] == '-')
{
return false;
}
return std.mem.indexOf(u8, host, "..") == null;
}
fn isValidUser(user: []const u8) bool {
if (user.len == 0 or user.len > 64) return false;
for (user) |c| {
switch (c) {
'a'...'z', 'A'...'Z', '0'...'9', '_', '-', '.' => {},
else => return false,
}
}
return true;
}
test "disk cache default path" {
const testing = std.testing;
const alloc = std.testing.allocator;
const path = try DiskCache.defaultPath(alloc, "ghostty");
defer alloc.free(path);
try testing.expect(path.len > 0);
}
test "disk cache clear" {
const testing = std.testing;
const alloc = testing.allocator;
// Create our path
var td: TempDir = try .init();
defer td.deinit();
{
var file = try td.dir.createFile("cache", .{});
defer file.close();
try file.writer().writeAll("HELLO!");
}
const path = try td.dir.realpathAlloc(alloc, "cache");
defer alloc.free(path);
// Setup our cache
const cache: DiskCache = .{ .path = path };
try cache.clear();
// Verify the file is gone
try testing.expectError(
error.FileNotFound,
td.dir.openFile("cache", .{}),
);
}
test "disk cache operations" {
const testing = std.testing;
const alloc = testing.allocator;
// Create our path
var td: TempDir = try .init();
defer td.deinit();
{
var file = try td.dir.createFile("cache", .{});
defer file.close();
try file.writer().writeAll("HELLO!");
}
const path = try td.dir.realpathAlloc(alloc, "cache");
defer alloc.free(path);
// Setup our cache
const cache: DiskCache = .{ .path = path };
try testing.expectEqual(
AddResult.added,
try cache.add(alloc, "example.com"),
);
try testing.expectEqual(
AddResult.updated,
try cache.add(alloc, "example.com"),
);
try testing.expect(
try cache.contains(alloc, "example.com"),
);
// List
var entries = try cache.list(alloc);
deinitEntries(alloc, &entries);
// Remove
try cache.remove(alloc, "example.com");
try testing.expect(
!(try cache.contains(alloc, "example.com")),
);
try testing.expectEqual(
AddResult.added,
try cache.add(alloc, "example.com"),
);
}
// Tests
test "hostname validation - valid cases" {
const testing = std.testing;
try testing.expect(isValidHostname("example.com"));
try testing.expect(isValidHostname("sub.example.com"));
try testing.expect(isValidHostname("host-name.domain.org"));
try testing.expect(isValidHostname("192.168.1.1"));
try testing.expect(isValidHostname("a"));
try testing.expect(isValidHostname("1"));
}
test "hostname validation - IPv6 addresses" {
const testing = std.testing;
try testing.expect(isValidHostname("[::1]"));
try testing.expect(isValidHostname("[2001:db8::1]"));
try testing.expect(!isValidHostname("[fe80::1%eth0]")); // Interface notation not supported
try testing.expect(!isValidHostname("[]")); // Empty IPv6
try testing.expect(!isValidHostname("[invalid]")); // No colons
}
test "hostname validation - invalid cases" {
const testing = std.testing;
try testing.expect(!isValidHostname(""));
try testing.expect(!isValidHostname("host\nname"));
try testing.expect(!isValidHostname(".example.com"));
try testing.expect(!isValidHostname("example.com."));
try testing.expect(!isValidHostname("host..domain"));
try testing.expect(!isValidHostname("-hostname"));
try testing.expect(!isValidHostname("hostname-"));
try testing.expect(!isValidHostname("host name"));
try testing.expect(!isValidHostname("host_name"));
try testing.expect(!isValidHostname("host@domain"));
try testing.expect(!isValidHostname("host:port"));
// Too long
const long_host = "a" ** 254;
try testing.expect(!isValidHostname(long_host));
}
test "user validation - valid cases" {
const testing = std.testing;
try testing.expect(isValidUser("user"));
try testing.expect(isValidUser("deploy"));
try testing.expect(isValidUser("test-user"));
try testing.expect(isValidUser("user_name"));
try testing.expect(isValidUser("user.name"));
try testing.expect(isValidUser("user123"));
try testing.expect(isValidUser("a"));
}
test "user validation - complex realistic cases" {
const testing = std.testing;
try testing.expect(isValidUser("git"));
try testing.expect(isValidUser("ubuntu"));
try testing.expect(isValidUser("root"));
try testing.expect(isValidUser("service.account"));
try testing.expect(isValidUser("user-with-dashes"));
}
test "user validation - invalid cases" {
const testing = std.testing;
try testing.expect(!isValidUser(""));
try testing.expect(!isValidUser("user name"));
try testing.expect(!isValidUser("user@domain"));
try testing.expect(!isValidUser("user:group"));
try testing.expect(!isValidUser("user\nname"));
// Too long
const long_user = "a" ** 65;
try testing.expect(!isValidUser(long_user));
}
test "cache key validation - hostname format" {
const testing = std.testing;
try testing.expect(isValidCacheKey("example.com"));
try testing.expect(isValidCacheKey("sub.example.com"));
try testing.expect(isValidCacheKey("192.168.1.1"));
try testing.expect(isValidCacheKey("[::1]"));
try testing.expect(!isValidCacheKey(""));
try testing.expect(!isValidCacheKey(".invalid.com"));
}
test "cache key validation - user@hostname format" {
const testing = std.testing;
try testing.expect(isValidCacheKey("user@example.com"));
try testing.expect(isValidCacheKey("deploy@prod.server.com"));
try testing.expect(isValidCacheKey("test-user@192.168.1.1"));
try testing.expect(isValidCacheKey("user_name@host.domain.org"));
try testing.expect(isValidCacheKey("git@github.com"));
try testing.expect(isValidCacheKey("ubuntu@[::1]"));
try testing.expect(!isValidCacheKey("@example.com"));
try testing.expect(!isValidCacheKey("user@"));
try testing.expect(!isValidCacheKey("user@@host"));
try testing.expect(!isValidCacheKey("user@.invalid.com"));
}

154
src/cli/ssh-cache/Entry.zig Normal file
View File

@ -0,0 +1,154 @@
/// A single entry within our SSH entry cache. Our SSH entry cache
/// stores which hosts we've sent our terminfo to so that we don't have
/// to send it again. It doesn't store any sensitive information.
const Entry = @This();
const std = @import("std");
hostname: []const u8,
timestamp: i64,
terminfo_version: []const u8,
pub fn parse(line: []const u8) ?Entry {
const trimmed = std.mem.trim(u8, line, " \t\r\n");
if (trimmed.len == 0) return null;
// Parse format: hostname|timestamp|terminfo_version
var iter = std.mem.tokenizeScalar(u8, trimmed, '|');
const hostname = iter.next() orelse return null;
const timestamp_str = iter.next() orelse return null;
const terminfo_version = iter.next() orelse "xterm-ghostty";
const timestamp = std.fmt.parseInt(i64, timestamp_str, 10) catch |err| {
std.log.warn(
"Invalid timestamp in cache entry: {s} err={}",
.{ timestamp_str, err },
);
return null;
};
return .{
.hostname = hostname,
.timestamp = timestamp,
.terminfo_version = terminfo_version,
};
}
pub fn format(self: Entry, writer: anytype) !void {
try writer.print(
"{s}|{d}|{s}\n",
.{ self.hostname, self.timestamp, self.terminfo_version },
);
}
pub fn isExpired(self: Entry, expire_days_: ?u32) bool {
const expire_days = expire_days_ orelse return false;
const now = std.time.timestamp();
const age_days = @divTrunc(now -| self.timestamp, std.time.s_per_day);
return age_days > expire_days;
}
test "cache entry expiration" {
const testing = std.testing;
const now = std.time.timestamp();
const fresh_entry: Entry = .{
.hostname = "test.com",
.timestamp = now - std.time.s_per_day, // 1 day old
.terminfo_version = "xterm-ghostty",
};
try testing.expect(!fresh_entry.isExpired(90));
const old_entry: Entry = .{
.hostname = "old.com",
.timestamp = now - (std.time.s_per_day * 100), // 100 days old
.terminfo_version = "xterm-ghostty",
};
try testing.expect(old_entry.isExpired(90));
// Test never-expire case
try testing.expect(!old_entry.isExpired(null));
}
test "cache entry expiration exact boundary" {
const testing = std.testing;
const now = std.time.timestamp();
// Exactly at expiration boundary
const boundary_entry: Entry = .{
.hostname = "example.com",
.timestamp = now - (std.time.s_per_day * 30),
.terminfo_version = "xterm-ghostty",
};
try testing.expect(!boundary_entry.isExpired(30));
try testing.expect(boundary_entry.isExpired(29));
}
test "cache entry expiration large timestamp" {
const testing = std.testing;
const now = std.time.timestamp();
const boundary_entry: Entry = .{
.hostname = "example.com",
.timestamp = now + (std.time.s_per_day * 30),
.terminfo_version = "xterm-ghostty",
};
try testing.expect(!boundary_entry.isExpired(30));
}
test "cache entry parsing valid formats" {
const testing = std.testing;
const entry = Entry.parse("example.com|1640995200|xterm-ghostty").?;
try testing.expectEqualStrings("example.com", entry.hostname);
try testing.expectEqual(@as(i64, 1640995200), entry.timestamp);
try testing.expectEqualStrings("xterm-ghostty", entry.terminfo_version);
// Test default terminfo version
const entry_no_version = Entry.parse("test.com|1640995200").?;
try testing.expectEqualStrings(
"xterm-ghostty",
entry_no_version.terminfo_version,
);
// Test complex hostnames
const complex_entry = Entry.parse("user@server.example.com|1640995200|xterm-ghostty").?;
try testing.expectEqualStrings(
"user@server.example.com",
complex_entry.hostname,
);
}
test "cache entry parsing invalid formats" {
const testing = std.testing;
try testing.expect(Entry.parse("") == null);
// Invalid format (no pipe)
try testing.expect(Entry.parse("v1") == null);
// Missing timestamp
try testing.expect(Entry.parse("example.com") == null);
// Invalid timestamp
try testing.expect(Entry.parse("example.com|invalid") == null);
// Empty terminfo should default
try testing.expect(Entry.parse("example.com|1640995200|") != null);
}
test "cache entry parsing malformed data resilience" {
const testing = std.testing;
// Extra pipes should not break parsing
try testing.expect(Entry.parse("host|123|term|extra") != null);
// Whitespace handling
try testing.expect(Entry.parse(" host|123|term ") != null);
try testing.expect(Entry.parse("\n") == null);
try testing.expect(Entry.parse(" \t \n") == null);
// Extremely large timestamp
try testing.expect(
Entry.parse("host|999999999999999999999999999999999999999999999999|xterm-ghostty") == null,
);
}

208
src/cli/ssh_cache.zig Normal file
View File

@ -0,0 +1,208 @@
const std = @import("std");
const fs = std.fs;
const Allocator = std.mem.Allocator;
const xdg = @import("../os/xdg.zig");
const args = @import("args.zig");
const Action = @import("action.zig").Action;
pub const Entry = @import("ssh-cache/Entry.zig");
pub const DiskCache = @import("ssh-cache/DiskCache.zig");
pub const Options = struct {
clear: bool = false,
add: ?[]const u8 = null,
remove: ?[]const u8 = null,
host: ?[]const u8 = null,
@"expire-days": ?u32 = null,
pub fn deinit(self: *Options) void {
_ = self;
}
pub fn help(self: Options) !void {
_ = self;
return Action.help_error;
}
};
/// Manage the SSH terminfo cache for automatic remote host setup.
///
/// When SSH integration is enabled with `shell-integration-features = ssh-terminfo`,
/// Ghostty automatically installs its terminfo on remote hosts. This command
/// manages the cache of successful installations to avoid redundant uploads.
///
/// The cache stores hostnames (or user@hostname combinations) along with timestamps.
/// Entries older than the expiration period are automatically removed during cache
/// operations. By default, entries never expire.
///
/// Only one of `--clear`, `--add`, `--remove`, or `--host` can be specified.
/// If multiple are specified, one of the actions will be executed but
/// it isn't guaranteed which one. This is entirely unsafe so you should split
/// multiple actions into separate commands.
///
/// Examples:
/// ghostty +ssh-cache # List all cached hosts
/// ghostty +ssh-cache --host=example.com # Check if host is cached
/// ghostty +ssh-cache --add=example.com # Manually add host to cache
/// ghostty +ssh-cache --add=user@example.com # Add user@host combination
/// ghostty +ssh-cache --remove=example.com # Remove host from cache
/// ghostty +ssh-cache --clear # Clear entire cache
/// ghostty +ssh-cache --expire-days=30 # Set custom expiration period
pub fn run(alloc_gpa: Allocator) !u8 {
var arena = std.heap.ArenaAllocator.init(alloc_gpa);
defer arena.deinit();
const alloc = arena.allocator();
var opts: Options = .{};
defer opts.deinit();
{
var iter = try args.argsIterator(alloc_gpa);
defer iter.deinit();
try args.parse(Options, alloc_gpa, &opts, &iter);
}
const stdout = std.io.getStdOut().writer();
const stderr = std.io.getStdErr().writer();
// Setup our disk cache to the standard location
const cache_path = try DiskCache.defaultPath(alloc, "ghostty");
const cache: DiskCache = .{ .path = cache_path };
if (opts.clear) {
try cache.clear();
try stdout.print("Cache cleared.\n", .{});
return 0;
}
if (opts.add) |host| {
const result = cache.add(alloc, host) catch |err| switch (err) {
DiskCache.Error.HostnameIsInvalid => {
try stderr.print("Error: Invalid hostname format '{s}'\n", .{host});
try stderr.print("Expected format: hostname or user@hostname\n", .{});
return 1;
},
DiskCache.Error.CacheIsLocked => {
try stderr.print("Error: Cache is busy, try again\n", .{});
return 1;
},
else => {
try stderr.print(
"Error: Unable to add '{s}' to cache. Error: {}\n",
.{ host, err },
);
return 1;
},
};
switch (result) {
.added => try stdout.print("Added '{s}' to cache.\n", .{host}),
.updated => try stdout.print("Updated '{s}' cache entry.\n", .{host}),
}
return 0;
}
if (opts.remove) |host| {
cache.remove(alloc, host) catch |err| switch (err) {
DiskCache.Error.HostnameIsInvalid => {
try stderr.print("Error: Invalid hostname format '{s}'\n", .{host});
try stderr.print("Expected format: hostname or user@hostname\n", .{});
return 1;
},
DiskCache.Error.CacheIsLocked => {
try stderr.print("Error: Cache is busy, try again\n", .{});
return 1;
},
else => {
try stderr.print(
"Error: Unable to remove '{s}' from cache. Error: {}\n",
.{ host, err },
);
return 1;
},
};
try stdout.print("Removed '{s}' from cache.\n", .{host});
return 0;
}
if (opts.host) |host| {
const cached = cache.contains(alloc, host) catch |err| switch (err) {
error.HostnameIsInvalid => {
try stderr.print("Error: Invalid hostname format '{s}'\n", .{host});
try stderr.print("Expected format: hostname or user@hostname\n", .{});
return 1;
},
else => {
try stderr.print(
"Error: Unable to check host '{s}' in cache. Error: {}\n",
.{ host, err },
);
return 1;
},
};
if (cached) {
try stdout.print(
"'{s}' has Ghostty terminfo installed.\n",
.{host},
);
return 0;
} else {
try stdout.print(
"'{s}' does not have Ghostty terminfo installed.\n",
.{host},
);
return 1;
}
}
// Default action: list all hosts
var entries = try cache.list(alloc);
defer DiskCache.deinitEntries(alloc, &entries);
try listEntries(alloc, &entries, stdout);
return 0;
}
fn listEntries(
alloc: Allocator,
entries: *const std.StringHashMap(Entry),
writer: anytype,
) !void {
if (entries.count() == 0) {
try writer.print("No hosts in cache.\n", .{});
return;
}
// Sort entries by hostname for consistent output
var items = std.ArrayList(Entry).init(alloc);
defer items.deinit();
var iter = entries.iterator();
while (iter.next()) |kv| {
try items.append(kv.value_ptr.*);
}
std.mem.sort(Entry, items.items, {}, struct {
fn lessThan(_: void, a: Entry, b: Entry) bool {
return std.mem.lessThan(u8, a.hostname, b.hostname);
}
}.lessThan);
try writer.print("Cached hosts ({d}):\n", .{items.items.len});
const now = std.time.timestamp();
for (items.items) |entry| {
const age_days = @divTrunc(now - entry.timestamp, std.time.s_per_day);
if (age_days == 0) {
try writer.print(" {s} (today)\n", .{entry.hostname});
} else if (age_days == 1) {
try writer.print(" {s} (yesterday)\n", .{entry.hostname});
} else {
try writer.print(" {s} ({d} days ago)\n", .{ entry.hostname, age_days });
}
}
}
test {
_ = DiskCache;
_ = Entry;
}

View File

@ -1,7 +1,9 @@
const std = @import("std");
const assert = std.debug.assert;
const cli = @import("../cli.zig");
const inputpkg = @import("../input.zig");
const global = &@import("../global.zig").state;
const state = &@import("../global.zig").state;
const c = @import("../main_c.zig");
const Config = @import("Config.zig");
const c_get = @import("c_get.zig");
@ -12,14 +14,14 @@ const log = std.log.scoped(.config);
/// Create a new configuration filled with the initial default values.
export fn ghostty_config_new() ?*Config {
const result = global.alloc.create(Config) catch |err| {
const result = state.alloc.create(Config) catch |err| {
log.err("error allocating config err={}", .{err});
return null;
};
result.* = Config.default(global.alloc) catch |err| {
result.* = Config.default(state.alloc) catch |err| {
log.err("error creating config err={}", .{err});
global.alloc.destroy(result);
state.alloc.destroy(result);
return null;
};
@ -29,20 +31,20 @@ export fn ghostty_config_new() ?*Config {
export fn ghostty_config_free(ptr: ?*Config) void {
if (ptr) |v| {
v.deinit();
global.alloc.destroy(v);
state.alloc.destroy(v);
}
}
/// Deep clone the configuration.
export fn ghostty_config_clone(self: *Config) ?*Config {
const result = global.alloc.create(Config) catch |err| {
const result = state.alloc.create(Config) catch |err| {
log.err("error allocating config err={}", .{err});
return null;
};
result.* = self.clone(global.alloc) catch |err| {
result.* = self.clone(state.alloc) catch |err| {
log.err("error cloning config err={}", .{err});
global.alloc.destroy(result);
state.alloc.destroy(result);
return null;
};
@ -51,7 +53,7 @@ export fn ghostty_config_clone(self: *Config) ?*Config {
/// Load the configuration from the CLI args.
export fn ghostty_config_load_cli_args(self: *Config) void {
self.loadCliArgs(global.alloc) catch |err| {
self.loadCliArgs(state.alloc) catch |err| {
log.err("error loading config err={}", .{err});
};
}
@ -60,7 +62,7 @@ export fn ghostty_config_load_cli_args(self: *Config) void {
/// is usually done first. The default file locations are locations
/// such as the home directory.
export fn ghostty_config_load_default_files(self: *Config) void {
self.loadDefaultFiles(global.alloc) catch |err| {
self.loadDefaultFiles(state.alloc) catch |err| {
log.err("error loading config err={}", .{err});
};
}
@ -69,7 +71,7 @@ export fn ghostty_config_load_default_files(self: *Config) void {
/// file locations in the previously loaded configuration. This will
/// recursively continue to load up to a built-in limit.
export fn ghostty_config_load_recursive_files(self: *Config) void {
self.loadRecursiveFiles(global.alloc) catch |err| {
self.loadRecursiveFiles(state.alloc) catch |err| {
log.err("error loading config err={}", .{err});
};
}
@ -122,10 +124,13 @@ export fn ghostty_config_get_diagnostic(self: *Config, idx: u32) Diagnostic {
return .{ .message = message.ptr };
}
export fn ghostty_config_open() void {
edit.open(global.alloc) catch |err| {
export fn ghostty_config_open_path() c.String {
const path = edit.openPath(state.alloc) catch |err| {
log.err("error opening config in editor err={}", .{err});
return .empty;
};
return .fromSlice(path);
}
/// Sync with ghostty_diagnostic_s

View File

@ -305,6 +305,7 @@ pub const compatibility = std.StaticStringMap(
///
/// * `cursor` - Break runs under the cursor.
///
/// Available since: 1.2.0
@"font-shaping-break": FontShapingBreak = .{},
/// What color space to use when performing alpha blending.
@ -329,6 +330,8 @@ pub const compatibility = std.StaticStringMap(
/// * `linear-corrected` - Same as `linear`, but with a correction step applied
/// for text that makes it look nearly or completely identical to `native`,
/// but without any of the darkening artifacts.
///
/// Available since: 1.1.0
@"alpha-blending": AlphaBlending =
if (builtin.os.tag == .macos)
.native
@ -396,6 +399,20 @@ pub const compatibility = std.StaticStringMap(
/// Thickness in pixels or percentage adjustment of box drawing characters.
/// See the notes about adjustments in `adjust-cell-width`.
@"adjust-box-thickness": ?MetricModifier = null,
/// Height in pixels or percentage adjustment of maximum height for nerd font icons.
///
/// Increasing this value will allow nerd font icons to be larger, but won't
/// necessarily force them to be. Decreasing this value will make nerd font
/// icons smaller.
///
/// The default value for the icon height is 1.2 times the height of capital
/// letters in your primary font, so something like -16.6% would make icons
/// roughly the same height as capital letters.
///
/// See the notes about adjustments in `adjust-cell-width`.
///
/// Available in: 1.2.0
@"adjust-icon-height": ?MetricModifier = null,
/// The method to use for calculating the cell width of a grapheme cluster.
/// The default value is `unicode` which uses the Unicode standard to determine
@ -503,7 +520,6 @@ pub const compatibility = std.StaticStringMap(
/// be fixed in a future update:
///
/// - macOS: titlebar tabs style is not updated when switching themes.
///
theme: ?Theme = null,
/// Background color for the window.
@ -527,6 +543,8 @@ foreground: Color = .{ .r = 0xFF, .g = 0xFF, .b = 0xFF },
/// For sufficiently large images, this could lead to a large increase in
/// memory usage (specifically VRAM usage). A future Ghostty improvement
/// will resolve this by sharing image textures across terminals.
///
/// Available since: 1.2.0
@"background-image": ?Path = null,
/// Background image opacity.
@ -546,6 +564,8 @@ foreground: Color = .{ .r = 0xFF, .g = 0xFF, .b = 0xFF },
/// configured `background-opacity` is `0.5` and `background-image-opacity`
/// is set to `1.5`, then the final opacity of the background image will be
/// `0.5 * 1.5 = 0.75`.
///
/// Available since: 1.2.0
@"background-image-opacity": f32 = 1.0,
/// Background image position.
@ -562,6 +582,8 @@ foreground: Color = .{ .r = 0xFF, .g = 0xFF, .b = 0xFF },
/// * `bottom-right`
///
/// The default value is `center`.
///
/// Available since: 1.2.0
@"background-image-position": BackgroundImagePosition = .center,
/// Background image fit.
@ -590,6 +612,8 @@ foreground: Color = .{ .r = 0xFF, .g = 0xFF, .b = 0xFF },
/// Don't scale the background image.
///
/// The default value is `contain`.
///
/// Available since: 1.2.0
@"background-image-fit": BackgroundImageFit = .contain,
/// Whether to repeat the background image or not.
@ -599,6 +623,8 @@ foreground: Color = .{ .r = 0xFF, .g = 0xFF, .b = 0xFF },
/// fill the terminal area.
///
/// The default value is `false`.
///
/// Available since: 1.2.0
@"background-image-repeat": bool = false,
/// The foreground and background color for selection. If this is not set, then
@ -624,6 +650,8 @@ foreground: Color = .{ .r = 0xFF, .g = 0xFF, .b = 0xFF },
///
/// If this is `false`, then the selection can still be manually
/// cleared by clicking once or by pressing `escape`.
///
/// Available since: 1.2.0
@"selection-clear-on-typing": bool = true,
/// The minimum contrast ratio between the foreground and background colors.
@ -661,11 +689,10 @@ palette: Palette = .{},
/// other colors at runtime:
///
/// * `cell-foreground` - Match the cell foreground color.
/// (Available since version 1.2.0)
/// (Available since: 1.2.0)
///
/// * `cell-background` - Match the cell background color.
/// (Available since version 1.2.0)
///
/// (Available since: 1.2.0)
@"cursor-color": ?TerminalColor = null,
/// The opacity level (opposite of transparency) of the cursor. A value of 1
@ -690,7 +717,6 @@ palette: Palette = .{},
/// * `bar`
/// * `underline`
/// * `block_hollow`
///
@"cursor-style": terminal.CursorStyle = .block,
/// Sets the default blinking state of the cursor. This is just the default
@ -710,7 +736,6 @@ palette: Palette = .{},
/// * ` ` (blank)
/// * `true`
/// * `false`
///
@"cursor-style-blink": ?bool = null,
/// The color of the text under the cursor. If this is not set, a default will
@ -767,7 +792,6 @@ palette: Palette = .{},
/// * `false`
/// * `always`
/// * `never`
///
@"mouse-shift-capture": MouseShiftCapture = .false,
/// Multiplier for scrolling distance with the mouse wheel. Any value less
@ -775,6 +799,8 @@ palette: Palette = .{},
/// value.
///
/// A value of "3" (default) scrolls 3 lines per tick.
///
/// Available since: 1.2.0
@"mouse-scroll-multiplier": f64 = 3.0,
/// The opacity level (opposite of transparency) of the background. A value of
@ -843,6 +869,8 @@ palette: Palette = .{},
/// The color of the split divider. If this is not set, a default will be chosen.
/// Specified as either hex (`#RRGGBB` or `RRGGBB`) or a named X11 color.
///
/// Available since: 1.1.0
@"split-divider-color": ?Color = null,
/// The command to run, usually a shell. If this is not an absolute path, it'll
@ -857,14 +885,14 @@ palette: Palette = .{},
/// arguments are provided, the command will be executed using `/bin/sh -c`
/// to offload shell argument expansion.
///
/// To avoid shell expansion altogether, prefix the command with `direct:`,
/// e.g. `direct:nvim foo`. This will avoid the roundtrip to `/bin/sh` but will
/// also not support any shell parsing such as arguments with spaces, filepaths
/// with `~`, globs, etc.
/// To avoid shell expansion altogether, prefix the command with `direct:`, e.g.
/// `direct:nvim foo`. This will avoid the roundtrip to `/bin/sh` but will also
/// not support any shell parsing such as arguments with spaces, filepaths with
/// `~`, globs, etc. (Available since: 1.2.0)
///
/// You can also explicitly prefix the command with `shell:` to always
/// wrap the command in a shell. This can be used to ensure our heuristics
/// to choose the right mode are not used in case they are wrong.
/// You can also explicitly prefix the command with `shell:` to always wrap the
/// command in a shell. This can be used to ensure our heuristics to choose the
/// right mode are not used in case they are wrong. (Available since: 1.2.0)
///
/// This command will be used for all new terminal surfaces, i.e. new windows,
/// tabs, etc. If you want to run a command only for the first terminal surface
@ -910,7 +938,6 @@ command: ?Command = null,
/// shell integration with a `-e`-executed command, you must either
/// name your binary appropriately or source the shell integration script
/// manually.
///
@"initial-command": ?Command = null,
/// Extra environment variables to pass to commands launched in a terminal
@ -947,6 +974,8 @@ command: ?Command = null,
/// These environment variables _will not_ be passed to commands run by Ghostty
/// for other purposes, like `open` or `xdg-open` used to open URLs in your
/// browser.
///
/// Available since: 1.2.0
env: RepeatableStringMap = .{},
/// Data to send as input to the command on startup.
@ -988,6 +1017,8 @@ env: RepeatableStringMap = .{},
///
/// Changing this configuration at runtime will only affect new
/// terminals.
///
/// Available since: 1.2.0
input: RepeatableReadableIO = .{},
/// If true, keep the terminal open after the command exits. Normally, the
@ -1056,11 +1087,15 @@ link: RepeatableLink = .{},
/// previews are never shown. When set to "osc8", link previews are only shown
/// for hyperlinks created with the OSC 8 sequence (in this case, the link text
/// can differ from the link destination).
///
/// Available since: 1.2.0
@"link-previews": LinkPreviews = .true,
/// Whether to start the window in a maximized state. This setting applies
/// to new windows and does not apply to tabs, splits, etc. However, this setting
/// will apply to all new windows, not just the first one.
///
/// Available since: 1.1.0
maximize: bool = false,
/// Start new windows in fullscreen. This setting applies to new windows and
@ -1285,6 +1320,8 @@ class: ?[:0]const u8 = null,
/// applies to actions that are surface-specific. For actions that
/// are already global (e.g. `quit`), this prefix has no effect.
///
/// Available since: 1.0.0
///
/// * `global:` - Make the keybind global. By default, keybinds only work
/// within Ghostty and under the right conditions (application focused,
/// sometimes terminal focused, etc.). If you want a keybind to work
@ -1293,6 +1330,9 @@ class: ?[:0]const u8 = null,
/// work in all environments; see the additional notes below for more
/// information.
///
/// Available since: 1.0.0 (on macOS)
/// Available since: 1.2.0 (on GTK)
///
/// * `unconsumed:` - Do not consume the input. By default, a keybind
/// will consume the input, meaning that the associated encoding (if
/// any) will not be sent to the running program in the terminal. If
@ -1303,6 +1343,8 @@ class: ?[:0]const u8 = null,
/// Since they are not associated with a specific terminal surface,
/// they're never encoded.
///
/// Available since: 1.0.0
///
/// * `performable:` - Only consume the input if the action is able to be
/// performed. For example, the `copy_to_clipboard` action will only
/// consume the input if there is a selection to copy. If there is no
@ -1318,6 +1360,8 @@ class: ?[:0]const u8 = null,
/// Performable keybinds will still work, they just won't appear as
/// a shortcut label in the menu.
///
/// Available since: 1.1.0
///
/// Keybind triggers are not unique per prefix combination. For example,
/// `ctrl+a` and `global:ctrl+a` are not two separate keybinds. The keybind
/// set later will overwrite the keybind set earlier. In this case, the
@ -1427,7 +1471,6 @@ keybind: Keybinds = .{},
/// do not look good extended.
/// * The nearest row contains a perfect fit powerline character. These
/// don't look good extended.
///
@"window-padding-color": WindowPaddingColor = .background,
/// Synchronize rendering with the screen refresh rate. If true, this will
@ -1474,6 +1517,8 @@ keybind: Keybinds = .{},
///
/// * `client` - Prefer client-side decorations.
///
/// Available since: 1.1.0
///
/// * `server` - Prefer server-side decorations. This is only relevant
/// on Linux with GTK, either on X11, or Wayland on a compositor that
/// supports the `org_kde_kwin_server_decoration` protocol (e.g. KDE Plasma,
@ -1482,6 +1527,8 @@ keybind: Keybinds = .{},
/// If `server` is set but the environment doesn't support server-side
/// decorations, client-side decorations will be used instead.
///
/// Available since: 1.1.0
///
/// The default value is `auto`.
///
/// For the sake of backwards compatibility and convenience, this setting also
@ -1504,6 +1551,8 @@ keybind: Keybinds = .{},
///
/// Note: any font available on the system may be used, this font is not
/// required to be a fixed-width font.
///
/// Available since: 1.1.0 (on GTK)
@"window-title-font-family": ?[:0]const u8 = null,
/// The text that will be displayed in the subtitle of the window. Valid values:
@ -1513,6 +1562,8 @@ keybind: Keybinds = .{},
/// surface.
///
/// This feature is only supported on GTK.
///
/// Available since: 1.1.0
@"window-subtitle": WindowSubtitle = .false,
/// The theme to use for the windows. Valid values:
@ -1656,6 +1707,8 @@ keybind: Keybinds = .{},
///
/// Always display the tab bar, even when there's only one tab.
///
/// Available since: 1.2.0
///
/// - `auto` *(default)*
///
/// Automatically show and hide the tab bar. The tab bar is only
@ -1740,6 +1793,8 @@ keybind: Keybinds = .{},
///
/// The maximum value is `584y 49w 23h 34m 33s 709ms 551µs 615ns`. Any
/// value larger than this will be clamped to the maximum value.
///
/// Available since 1.0.0
@"resize-overlay-duration": Duration = .{ .duration = 750 * std.time.ns_per_ms },
/// If true, when there are multiple split panes, the mouse selects the pane
@ -1785,6 +1840,8 @@ keybind: Keybinds = .{},
/// Warning: This can expose sensitive information at best and enable
/// arbitrary code execution at worst (with a maliciously crafted title
/// and a minor amount of user interaction).
///
/// Available since: 1.0.1
@"title-report": bool = false,
/// The total amount of bytes that can be used for image data (e.g. the Kitty
@ -1972,6 +2029,8 @@ keybind: Keybinds = .{},
/// This configuration is only supported on macOS. Linux doesn't
/// support undo operations at all so this configuration has no
/// effect.
///
/// Available since: 1.2.0
@"undo-timeout": Duration = .{ .duration = 5 * std.time.ns_per_s },
/// The position of the "quick" terminal window. To learn more about the
@ -2075,6 +2134,8 @@ keybind: Keybinds = .{},
///
/// Only implemented on macOS.
/// On Linux the behavior is always equivalent to `move`.
///
/// Available since: 1.1.0
@"quick-terminal-space-behavior": QuickTerminalSpaceBehavior = .move,
/// Determines under which circumstances that the quick terminal should receive
@ -2103,6 +2164,8 @@ keybind: Keybinds = .{},
///
/// Only has an effect on Linux Wayland.
/// On macOS the behavior is always equivalent to `on-demand`.
///
/// Available since: 1.2.0
@"quick-terminal-keyboard-interactivity": QuickTerminalKeyboardInteractivity = .@"on-demand",
/// Whether to enable shell integration auto-injection or not. Shell integration
@ -2139,6 +2202,8 @@ keybind: Keybinds = .{},
/// its default value is used, so you must explicitly disable features you don't
/// want. You can also use `true` or `false` to turn all features on or off.
///
/// Example: `cursor`, `no-cursor`, `sudo`, `no-sudo`, `title`, `no-title`
///
/// Available features:
///
/// * `cursor` - Set the cursor to a blinking bar at the prompt.
@ -2147,7 +2212,26 @@ keybind: Keybinds = .{},
///
/// * `title` - Set the window title via shell integration.
///
/// Example: `cursor`, `no-cursor`, `sudo`, `no-sudo`, `title`, `no-title`
/// * `ssh-env` - Enable SSH environment variable compatibility. Automatically
/// converts TERM from `xterm-ghostty` to `xterm-256color` when connecting to
/// remote hosts and propagates COLORTERM, TERM_PROGRAM, and TERM_PROGRAM_VERSION.
/// Whether or not these variables will be accepted by the remote host(s) will
/// depend on whether or not the variables are allowed in their sshd_config.
/// (Available since: 1.2.0)
///
/// * `ssh-terminfo` - Enable automatic terminfo installation on remote hosts.
/// Attempts to install Ghostty's terminfo entry using `infocmp` and `tic` when
/// connecting to hosts that lack it. Requires `infocmp` to be available locally
/// and `tic` to be available on remote hosts. Once terminfo is installed on a
/// remote host, it will be automatically "cached" to avoid repeat installations.
/// If desired, the `+ssh-cache` CLI action can be used to manage the installation
/// cache manually using various arguments.
/// (Available since: 1.2.0)
///
/// SSH features work independently and can be combined for optimal experience:
/// when both `ssh-env` and `ssh-terminfo` are enabled, Ghostty will install its
/// terminfo on remote hosts and use `xterm-ghostty` as TERM, falling back to
/// `xterm-256color` with environment variables if terminfo installation fails.
@"shell-integration-features": ShellIntegrationFeatures = .{},
/// Custom entries into the command palette.
@ -2170,6 +2254,8 @@ keybind: Keybinds = .{},
/// ```ini
/// command-palette-entry =
/// ```
///
/// Available since: 1.2.0
@"command-palette-entry": RepeatableCommand = .{},
/// Sets the reporting format for OSC sequences that request color information.
@ -2334,6 +2420,8 @@ keybind: Keybinds = .{},
/// Only implemented on macOS.
///
/// Example: `audio`, `no-audio`, `system`, `no-system`
///
/// Available since: 1.2.0
@"bell-features": BellFeatures = .{},
/// If `audio` is an enabled bell feature, this is a path to an audio file. If
@ -2341,12 +2429,16 @@ keybind: Keybinds = .{},
/// configuration file that it is referenced from, or from the current working
/// directory if this is used as a CLI flag. The path may be prefixed with `~/`
/// to reference the user's home directory. (GTK only)
///
/// Available since: 1.2.0
@"bell-audio-path": ?Path = null,
/// If `audio` is an enabled bell feature, this is the volume to play the audio
/// file at (relative to the system volume). This is a floating point number
/// ranging from 0.0 (silence) to 1.0 (as loud as possible). The default is 0.5.
/// (GTK only)
///
/// Available since: 1.2.0
@"bell-audio-volume": f64 = 0.5,
/// Control the in-app notifications that Ghostty shows.
@ -2372,6 +2464,8 @@ keybind: Keybinds = .{},
/// enable all notifications.
///
/// This configuration only applies to GTK.
///
/// Available since: 1.1.0
@"app-notifications": AppNotifications = .{},
/// If anything other than false, fullscreen mode on macOS will not use the
@ -2422,6 +2516,8 @@ keybind: Keybinds = .{},
/// The default value is `visible`.
///
/// Changing this option at runtime only applies to new windows.
///
/// Available since: 1.2.0
@"macos-window-buttons": MacWindowButtons = .visible,
/// The style of the macOS titlebar. Available values are: "native",
@ -2544,6 +2640,8 @@ keybind: Keybinds = .{},
///
/// Note: When the macOS application is hidden, keyboard layout changes
/// will no longer be automatic. This is a limitation of macOS.
///
/// Available since: 1.2.0
@"macos-hidden": MacHidden = .never,
/// If true, Ghostty on macOS will automatically enable the "Secure Input"
@ -2605,7 +2703,6 @@ keybind: Keybinds = .{},
/// This is because the update dialog is managed through a
/// separate framework and cannot be customized without significant
/// effort.
///
@"macos-icon": MacAppIcon = .official,
/// The material to use for the frame of the macOS app icon.
@ -2619,7 +2716,6 @@ keybind: Keybinds = .{},
///
/// Note: This configuration is required when `macos-icon` is set to
/// `custom-style`.
///
@"macos-icon-frame": MacAppIconFrame = .aluminum,
/// The color of the ghost in the macOS app icon.
@ -2640,7 +2736,6 @@ keybind: Keybinds = .{},
///
/// Note: This configuration is required when `macos-icon` is set to
/// `custom-style`.
///
@"macos-icon-screen-color": ?ColorList = null,
/// Whether macOS Shortcuts are allowed to control Ghostty.
@ -2664,6 +2759,7 @@ keybind: Keybinds = .{},
///
/// * `deny` - Deny Shortcuts from controlling Ghostty.
///
/// Available since: 1.2.0
@"macos-shortcuts": MacShortcuts = .ask,
/// Put every surface (tab, split, window) into a dedicated Linux cgroup.
@ -2691,7 +2787,6 @@ keybind: Keybinds = .{},
/// * `always` - Always use cgroups.
/// * `single-instance` - Enable cgroups only for Ghostty instances launched
/// as single-instance applications (see gtk-single-instance).
///
@"linux-cgroup": LinuxCgroup = if (builtin.os.tag == .linux)
.@"single-instance"
else
@ -2728,6 +2823,8 @@ else
/// Enable or disable GTK's OpenGL debugging logs. The default is `true` for
/// debug builds, `false` for all others.
///
/// Available since: 1.1.0
@"gtk-opengl-debug": bool = builtin.mode == .Debug,
/// If `true`, the Ghostty GTK application will run in single-instance mode:
@ -2765,6 +2862,8 @@ else
/// If this is `true`, the titlebar will be hidden when the window is maximized,
/// and shown when the titlebar is unmaximized. GTK only.
///
/// Available since: 1.1.0
@"gtk-titlebar-hide-when-maximized": bool = false,
/// Determines the appearance of the top and bottom bars tab bar.
@ -2802,6 +2901,8 @@ else
/// not exist. If you want to include a file that begins with a literal ?
/// character, surround the file path in double quotes (").
/// The file size limit for a single stylesheet is 5MiB.
///
/// Available since: 1.1.0
@"gtk-custom-css": RepeatablePath = .{},
/// If `true` (default), applications running in the terminal can show desktop
@ -2813,8 +2914,8 @@ else
/// This can be set to a specific color, using the same format as
/// `background` or `foreground` (e.g. `#RRGGBB` but other formats
/// are also supported; see the aforementioned documentation). If a
/// specific color is set, this color will always be used for all
/// bold text regardless of the terminal's color scheme.
/// specific color is set, this color will always be used for the default
/// bold text color. It will set the rest of the bold colors to `bright`.
///
/// This can also be set to `bright`, which uses the bright color palette
/// for bold text. For example, if the text is red, then the bold will
@ -2854,6 +2955,8 @@ term: []const u8 = "xterm-ghostty",
/// this isn't intended to be modified by users, the documentation is
/// lighter than the other configurations and users are expected to
/// refer to the code for details.
///
/// Available since: 1.2.0
@"launched-from": ?LaunchSource = null,
/// Configures the low-level API to use for async IO, eventing, etc.
@ -2882,6 +2985,8 @@ term: []const u8 = "xterm-ghostty",
///
/// This is only supported on Linux, since this is the only platform
/// where we have multiple options. On macOS, we always use `kqueue`.
///
/// Available since: 1.2.0
@"async-backend": AsyncBackend = .auto,
/// Control the auto-update functionality of Ghostty. This is only supported
@ -6552,6 +6657,8 @@ pub const ShellIntegrationFeatures = packed struct {
cursor: bool = true,
sudo: bool = false,
title: bool = true,
@"ssh-env": bool = false,
@"ssh-terminfo": bool = false,
};
pub const RepeatableCommand = struct {

View File

@ -5,18 +5,19 @@ const Allocator = std.mem.Allocator;
const ArenaAllocator = std.heap.ArenaAllocator;
const internal_os = @import("../os/main.zig");
/// Open the configuration in the OS default editor according to the default
/// paths the main config file could be in.
/// The path to the configuration that should be opened for editing.
///
/// On Linux, this will open the file at the XDG config path. This is the
/// On Linux, this will use the file at the XDG config path. This is the
/// only valid path for Linux so we don't need to check for other paths.
///
/// On macOS, both XDG and AppSupport paths are valid. Because Ghostty
/// prioritizes AppSupport over XDG, we will open AppSupport if it exists,
/// prioritizes AppSupport over XDG, we will use AppSupport if it exists,
/// followed by XDG if it exists, and finally AppSupport if neither exist.
/// For the existence check, we also prefer non-empty files over empty
/// files.
pub fn open(alloc_gpa: Allocator) !void {
///
/// The returned value is allocated using the provided allocator.
pub fn openPath(alloc_gpa: Allocator) ![:0]const u8 {
// Use an arena to make memory management easier in here.
var arena = ArenaAllocator.init(alloc_gpa);
defer arena.deinit();
@ -41,7 +42,7 @@ pub fn open(alloc_gpa: Allocator) !void {
}
};
try internal_os.open(alloc_gpa, .text, config_path);
return try alloc_gpa.dupeZ(u8, config_path);
}
/// Returns the config path to use for open for the current OS.

View File

@ -69,10 +69,14 @@ pub fn deinit(self: *Collection, alloc: Allocator) void {
if (self.load_options) |*v| v.deinit(alloc);
}
pub const AddError = Allocator.Error || error{
CollectionFull,
DeferredLoadingUnavailable,
};
pub const AddError =
Allocator.Error ||
AdjustSizeError ||
error{
CollectionFull,
DeferredLoadingUnavailable,
SetSizeFailed,
};
/// Add a face to the collection for the given style. This face will be added
/// next in priority if others exist already, i.e. it'll be the _last_ to be
@ -81,10 +85,9 @@ pub const AddError = Allocator.Error || error{
/// If no error is encountered then the collection takes ownership of the face,
/// in which case face will be deallocated when the collection is deallocated.
///
/// If a loaded face is added to the collection, it should be the same
/// size as all the other faces in the collection. This function will not
/// verify or modify the size until the size of the entire collection is
/// changed.
/// If a loaded face is added to the collection, its size will be changed to
/// match the size specified in load_options, adjusted for harmonization with
/// the primary face.
pub fn add(
self: *Collection,
alloc: Allocator,
@ -103,9 +106,107 @@ pub fn add(
return error.DeferredLoadingUnavailable;
try list.append(alloc, face);
var owned: *Entry = list.at(idx);
// If the face is already loaded, apply font size adjustment
// now, otherwise we'll apply it whenever we do load it.
if (owned.getLoaded()) |loaded| {
if (try self.adjustedSize(loaded)) |opts| {
loaded.setSize(opts.faceOptions()) catch return error.SetSizeFailed;
}
}
return .{ .style = style, .idx = @intCast(idx) };
}
pub const AdjustSizeError = font.Face.GetMetricsError;
// Calculate a size for the provided face that will match it with the primary
// font, metrically, to improve consistency with fallback fonts. Right now we
// match the font based on the ex height, or the ideograph width if the font
// has ideographs in it.
//
// This returns null if load options is null or if self.load_options is null.
//
// This is very much like the `font-size-adjust` CSS property in how it works.
// ref: https://developer.mozilla.org/en-US/docs/Web/CSS/font-size-adjust
//
// TODO: In the future, provide config options that allow the user to select
// which metric should be matched for fallback fonts, instead of hard
// coding it as ex height.
pub fn adjustedSize(
self: *Collection,
face: *Face,
) AdjustSizeError!?LoadOptions {
const load_options = self.load_options orelse return null;
// We silently do nothing if we can't get the primary
// face, because this might be the primary face itself.
const primary_face = self.getFace(.{ .idx = 0 }) catch return null;
// We do nothing if the primary face and this face are the same.
if (@intFromPtr(primary_face) == @intFromPtr(face)) return null;
const primary_metrics = try primary_face.getMetrics();
const face_metrics = try face.getMetrics();
// We use the ex height to match our font sizes, so that the height of
// lower-case letters matches between all fonts in the fallback chain.
//
// We estimate ex height as 0.75 * cap height if it's not specifically
// provided, and we estimate cap height as 0.75 * ascent in the same case.
//
// If the fallback font has an ic_width we prefer that, for normalization
// of CJK font sizes when mixed with latin fonts.
//
// We estimate the ic_width as twice the cell width if it isn't provided.
var primary_cap = primary_metrics.cap_height orelse 0.0;
if (primary_cap <= 0) primary_cap = primary_metrics.ascent * 0.75;
var primary_ex = primary_metrics.ex_height orelse 0.0;
if (primary_ex <= 0) primary_ex = primary_cap * 0.75;
var primary_ic = primary_metrics.ic_width orelse 0.0;
if (primary_ic <= 0) primary_ic = primary_metrics.cell_width * 2;
var face_cap = face_metrics.cap_height orelse 0.0;
if (face_cap <= 0) face_cap = face_metrics.ascent * 0.75;
var face_ex = face_metrics.ex_height orelse 0.0;
if (face_ex <= 0) face_ex = face_cap * 0.75;
var face_ic = face_metrics.ic_width orelse 0.0;
if (face_ic <= 0) face_ic = face_metrics.cell_width * 2;
// If the line height of the scaled font would be larger than
// the line height of the primary font, we don't want that, so
// we take the minimum between matching the ic/ex and the line
// height.
//
// NOTE: We actually allow the line height to be up to 1.2
// times the primary line height because empirically
// this is usually fine and is better for CJK.
//
// TODO: We should probably provide a config option that lets
// the user pick what metric to use for size adjustment.
const scale = @min(
1.2 * primary_metrics.lineHeight() / face_metrics.lineHeight(),
if (face_metrics.ic_width != null)
primary_ic / face_ic
else
primary_ex / face_ex,
);
// Make a copy of our load options, set the size to the size of
// the provided face, and then multiply that by our scaling factor.
var opts = load_options;
opts.size = face.size;
opts.size.points *= @as(f32, @floatCast(scale));
return opts;
}
/// Return the Face represented by a given Index. The returned pointer
/// is only valid as long as this collection is not modified.
///
@ -129,21 +230,38 @@ pub fn getFace(self: *Collection, index: Index) !*Face {
break :item item;
};
return try self.getFaceFromEntry(item);
const face = try self.getFaceFromEntry(
item,
// We only want to adjust the size if this isn't the primary face.
index.style != .regular or index.idx > 0,
);
return face;
}
/// Get the face from an entry.
///
/// This entry must not be an alias.
fn getFaceFromEntry(self: *Collection, entry: *Entry) !*Face {
fn getFaceFromEntry(
self: *Collection,
entry: *Entry,
/// Whether to adjust the font size to match the primary face after loading.
adjust: bool,
) !*Face {
assert(entry.* != .alias);
return switch (entry.*) {
inline .deferred, .fallback_deferred => |*d, tag| deferred: {
const opts = self.load_options orelse
return error.DeferredLoadingUnavailable;
const face = try d.load(opts.library, opts.faceOptions());
var face = try d.load(opts.library, opts.faceOptions());
d.deinit();
// If we need to adjust the size, do so.
if (adjust) if (try self.adjustedSize(&face)) |new_opts| {
try face.setSize(new_opts.faceOptions());
};
entry.* = switch (tag) {
.deferred => .{ .loaded = face },
.fallback_deferred => .{ .fallback_loaded = face },
@ -247,7 +365,7 @@ pub fn completeStyles(
while (it.next()) |entry| {
// Load our face. If we fail to load it, we just skip it and
// continue on to try the next one.
const face = self.getFaceFromEntry(entry) catch |err| {
const face = self.getFaceFromEntry(entry, false) catch |err| {
log.warn("error loading regular entry={d} err={}", .{
it.index - 1,
err,
@ -371,7 +489,7 @@ fn syntheticBold(self: *Collection, entry: *Entry) !Face {
const opts = self.load_options orelse return error.DeferredLoadingUnavailable;
// Try to bold it.
const regular = try self.getFaceFromEntry(entry);
const regular = try self.getFaceFromEntry(entry, false);
const face = try regular.syntheticBold(opts.faceOptions());
var buf: [256]u8 = undefined;
@ -391,7 +509,7 @@ fn syntheticItalic(self: *Collection, entry: *Entry) !Face {
const opts = self.load_options orelse return error.DeferredLoadingUnavailable;
// Try to italicize it.
const regular = try self.getFaceFromEntry(entry);
const regular = try self.getFaceFromEntry(entry, false);
const face = try regular.syntheticItalic(opts.faceOptions());
var buf: [256]u8 = undefined;
@ -420,9 +538,12 @@ pub fn setSize(self: *Collection, size: DesiredSize) !void {
while (it.next()) |array| {
var entry_it = array.value.iterator(0);
while (entry_it.next()) |entry| switch (entry.*) {
.loaded, .fallback_loaded => |*f| try f.setSize(
opts.faceOptions(),
),
.loaded,
.fallback_loaded,
=> |*f| {
const new_opts = try self.adjustedSize(f) orelse opts.*;
try f.setSize(new_opts.faceOptions());
},
// Deferred aren't loaded so we don't need to set their size.
// The size for when they're loaded is set since `opts` changed.
@ -549,6 +670,16 @@ pub const Entry = union(enum) {
}
}
/// If this face is loaded, or is an alias to a loaded face,
/// then this returns the `Face`, otherwise returns null.
pub fn getLoaded(self: *Entry) ?*Face {
return switch (self.*) {
.deferred, .fallback_deferred => null,
.loaded, .fallback_loaded => |*face| face,
.alias => |v| v.getLoaded(),
};
}
/// True if the entry is deferred.
fn isDeferred(self: Entry) bool {
return switch (self) {
@ -906,12 +1037,13 @@ test "metrics" {
var c = init();
defer c.deinit(alloc);
c.load_options = .{ .library = lib };
const size: DesiredSize = .{ .points = 12, .xdpi = 96, .ydpi = 96 };
c.load_options = .{ .library = lib, .size = size };
_ = try c.add(alloc, .regular, .{ .loaded = try .init(
lib,
testFont,
.{ .size = .{ .points = 12, .xdpi = 96, .ydpi = 96 } },
.{ .size = size },
) });
try c.updateMetrics();
@ -940,6 +1072,7 @@ test "metrics" {
.overline_thickness = 1,
.box_thickness = 1,
.cursor_height = 17,
.icon_height = 11,
}, c.metrics);
// Resize should change metrics
@ -956,5 +1089,65 @@ test "metrics" {
.overline_thickness = 2,
.box_thickness = 2,
.cursor_height = 34,
.icon_height = 23,
}, c.metrics);
}
// TODO: Also test CJK fallback sizing, we don't currently have a CJK test font.
test "adjusted sizes" {
const testing = std.testing;
const alloc = testing.allocator;
const testFont = font.embedded.inconsolata;
const fallback = font.embedded.monaspace_neon;
var lib = try Library.init(alloc);
defer lib.deinit();
var c = init();
defer c.deinit(alloc);
const size: DesiredSize = .{ .points = 12, .xdpi = 96, .ydpi = 96 };
c.load_options = .{ .library = lib, .size = size };
// Add our primary face.
_ = try c.add(alloc, .regular, .{ .loaded = try .init(
lib,
testFont,
.{ .size = size },
) });
try c.updateMetrics();
// Add the fallback face.
const fallback_idx = try c.add(alloc, .regular, .{ .loaded = try .init(
lib,
fallback,
.{ .size = size },
) });
// The ex heights should match.
{
const primary_metrics = try (try c.getFace(.{ .idx = 0 })).getMetrics();
const fallback_metrics = try (try c.getFace(fallback_idx)).getMetrics();
try std.testing.expectApproxEqAbs(
primary_metrics.ex_height.?,
fallback_metrics.ex_height.?,
// We accept anything within half a pixel.
0.5,
);
}
// Resize should keep that relationship.
try c.setSize(.{ .points = 37, .xdpi = 96, .ydpi = 96 });
{
const primary_metrics = try (try c.getFace(.{ .idx = 0 })).getMetrics();
const fallback_metrics = try (try c.getFace(fallback_idx)).getMetrics();
try std.testing.expectApproxEqAbs(
primary_metrics.ex_height.?,
fallback_metrics.ex_height.?,
// We accept anything within half a pixel.
0.5,
);
}
}

View File

@ -17,9 +17,3 @@ offset_y: i32,
/// be normalized to be between 0 and 1 prior to use in shaders.
atlas_x: u32,
atlas_y: u32,
/// horizontal position to increase drawing position for strings
advance_x: f32,
/// Whether we drew this glyph ourselves with the sprite font.
sprite: bool = false,

View File

@ -35,9 +35,8 @@ cursor_thickness: u32 = 1,
/// The height in pixels of the cursor sprite.
cursor_height: u32,
/// Original cell width in pixels. This is used to keep
/// glyphs centered if the cell width is adjusted wider.
original_cell_width: ?u32 = null,
/// The constraint height for nerd fonts icons.
icon_height: u32,
/// Minimum acceptable values for some fields to prevent modifiers
/// from being able to, for example, cause 0-thickness underlines.
@ -50,6 +49,7 @@ const Minimums = struct {
const box_thickness = 1;
const cursor_thickness = 1;
const cursor_height = 1;
const icon_height = 1;
};
/// Metrics extracted from a font face, based on
@ -107,6 +107,19 @@ pub const FaceMetrics = struct {
/// a provided ex height metric or measured from the height of the
/// lowercase x glyph.
ex_height: ?f64 = null,
/// The width of the character "" (CJK water ideograph, U+6C34),
/// if present. This is used for font size adjustment, to normalize
/// the width of CJK fonts mixed with latin fonts.
///
/// NOTE: IC = Ideograph Character
ic_width: ?f64 = null,
/// Convenience function for getting the line height
/// (ascent - descent + line_gap).
pub inline fn lineHeight(self: FaceMetrics) f64 {
return self.ascent - self.descent + self.line_gap;
}
};
/// Calculate our metrics based on values extracted from a font.
@ -120,7 +133,7 @@ pub fn calc(face: FaceMetrics) Metrics {
// that the cell is large enough for the provided size, since we cast
// it to an integer later.
const cell_width = @ceil(face.cell_width);
const cell_height = @ceil(face.ascent - face.descent + face.line_gap);
const cell_height = @ceil(face.lineHeight());
// We split our line gap in two parts, and put half of it on the top
// of the cell and the other half on the bottom, so that our text never
@ -164,6 +177,17 @@ pub fn calc(face: FaceMetrics) Metrics {
(face.strikethrough_position orelse
ex_height * 0.5 + strikethrough_thickness * 0.5));
// The calculation for icon height in the nerd fonts patcher
// is two thirds cap height to one third line height, but we
// use an opinionated default of 1.2 * cap height instead.
//
// Doing this prevents fonts with very large line heights
// from having excessively oversized icons, and allows fonts
// with very small line heights to still have roomy icons.
//
// We do cap it at `cell_height` though for obvious reasons.
const icon_height = @min(cell_height, cap_height * 1.2);
var result: Metrics = .{
.cell_width = @intFromFloat(cell_width),
.cell_height = @intFromFloat(cell_height),
@ -176,6 +200,7 @@ pub fn calc(face: FaceMetrics) Metrics {
.overline_thickness = @intFromFloat(underline_thickness),
.box_thickness = @intFromFloat(underline_thickness),
.cursor_height = @intFromFloat(cell_height),
.icon_height = @intFromFloat(icon_height),
};
// Ensure all metrics are within their allowable range.
@ -201,11 +226,6 @@ pub fn apply(self: *Metrics, mods: ModifierSet) void {
const new = @max(entry.value_ptr.apply(original), 1);
if (new == original) continue;
// Preserve the original cell width if not set.
if (self.original_cell_width == null) {
self.original_cell_width = self.cell_width;
}
// Set the new value
@field(self, @tagName(tag)) = new;
@ -419,6 +439,7 @@ fn init() Metrics {
.overline_thickness = 0,
.box_thickness = 0,
.cursor_height = 0,
.icon_height = 0,
};
}

View File

@ -449,6 +449,7 @@ pub const DerivedConfig = struct {
@"adjust-cursor-thickness": ?Metrics.Modifier,
@"adjust-cursor-height": ?Metrics.Modifier,
@"adjust-box-thickness": ?Metrics.Modifier,
@"adjust-icon-height": ?Metrics.Modifier,
@"freetype-load-flags": font.face.FreetypeLoadFlags,
/// Initialize a DerivedConfig. The config should be either a
@ -488,6 +489,7 @@ pub const DerivedConfig = struct {
.@"adjust-cursor-thickness" = config.@"adjust-cursor-thickness",
.@"adjust-cursor-height" = config.@"adjust-cursor-height",
.@"adjust-box-thickness" = config.@"adjust-box-thickness",
.@"adjust-icon-height" = config.@"adjust-icon-height",
.@"freetype-load-flags" = if (font.face.FreetypeLoadFlags != void) config.@"freetype-load-flags" else {},
// This must be last so the arena contains all our allocations
@ -634,6 +636,7 @@ pub const Key = struct {
if (config.@"adjust-cursor-thickness") |m| try set.put(alloc, .cursor_thickness, m);
if (config.@"adjust-cursor-height") |m| try set.put(alloc, .cursor_height, m);
if (config.@"adjust-box-thickness") |m| try set.put(alloc, .box_thickness, m);
if (config.@"adjust-icon-height") |m| try set.put(alloc, .icon_height, m);
break :set set;
};

View File

@ -144,12 +144,32 @@ pub const RenderOptions = struct {
/// Bottom padding when resizing.
pad_bottom: f64 = 0.0,
// This acts as a multiple of the provided width when applying
// constraints, so if this is 1.6 for example, then a width of
// 10 would be treated as though it were 16.
group_width: f64 = 1.0,
// This acts as a multiple of the provided height when applying
// constraints, so if this is 1.6 for example, then a height of
// 10 would be treated as though it were 16.
group_height: f64 = 1.0,
// This is an x offset for the actual width within the group width.
// If this is 0.5 then the glyph will be offset so that its left
// edge sits at the halfway point of the group width.
group_x: f64 = 0.0,
// This is a y offset for the actual height within the group height.
// If this is 0.5 then the glyph will be offset so that its bottom
// edge sits at the halfway point of the group height.
group_y: f64 = 0.0,
/// Maximum ratio of width to height when resizing.
max_xy_ratio: ?f64 = null,
/// Maximum number of cells horizontally to use.
max_constraint_width: u2 = 2,
/// What to use as the height metric when constraining the glyph.
height: Height = .cell,
pub const Size = enum {
/// Don't change the size of this glyph.
none,
@ -176,6 +196,13 @@ pub const RenderOptions = struct {
center,
};
pub const Height = enum {
/// Use the full height of the cell for constraining this glyph.
cell,
/// Use the "icon height" from the grid metrics as the height.
icon,
};
/// The size and position of a glyph.
pub const GlyphSize = struct {
width: f64,
@ -189,35 +216,55 @@ pub const RenderOptions = struct {
pub fn constrain(
self: Constraint,
glyph: GlyphSize,
/// Width of one cell.
cell_width: f64,
/// Height of one cell.
cell_height: f64,
metrics: Metrics,
/// Number of cells horizontally available for this glyph.
constraint_width: u2,
) GlyphSize {
var g = glyph;
const available_width =
cell_width * @as(f64, @floatFromInt(
@min(
self.max_constraint_width,
constraint_width,
),
));
var available_width: f64 = @floatFromInt(
metrics.cell_width * @min(
self.max_constraint_width,
constraint_width,
),
);
const available_height: f64 = @floatFromInt(switch (self.height) {
.cell => metrics.cell_height,
.icon => metrics.icon_height,
});
// We make the opinionated choice here to reduce the width
// of icon-height symbols by the same amount horizontally,
// since otherwise wide aspect ratio icons like folders end
// up far too wide.
//
// But we *only* do this if the constraint width is 2, since
// otherwise it would make them way too small when sized for
// a single cell.
const is_icon_width = self.height == .icon and @min(self.max_constraint_width, constraint_width) > 1;
const orig_avail_width = available_width;
if (is_icon_width) {
const cell_height: f64 = @floatFromInt(metrics.cell_height);
const ratio = available_height / cell_height;
available_width *= ratio;
}
const w = available_width -
self.pad_left * available_width -
self.pad_right * available_width;
const h = cell_height -
self.pad_top * cell_height -
self.pad_bottom * cell_height;
const h = available_height -
self.pad_top * available_height -
self.pad_bottom * available_height;
// Subtract padding from the bearings so that our
// alignment and sizing code works correctly. We
// re-add before returning.
g.x -= self.pad_left * available_width;
g.y -= self.pad_bottom * cell_height;
g.y -= self.pad_bottom * available_height;
// Multiply by group width and height for better sizing.
g.width *= self.group_width;
g.height *= self.group_height;
switch (self.size_horizontal) {
.none => {},
@ -297,6 +344,14 @@ pub const RenderOptions = struct {
},
}
// Add group-relative position
g.x += self.group_x * g.width;
g.y += self.group_y * g.height;
// Divide group width and height back out before we align.
g.width /= self.group_width;
g.height /= self.group_height;
if (self.max_xy_ratio) |ratio| if (g.width > g.height * ratio) {
const orig_width = g.width;
g.width = g.height * ratio;
@ -317,9 +372,23 @@ pub const RenderOptions = struct {
.center => g.y = (h - g.height) / 2,
}
// Add offset for icon width restriction, to keep it centered.
if (is_icon_width) {
g.x += (orig_avail_width - available_width) / 2;
}
// Re-add our padding before returning.
g.x += self.pad_left * available_width;
g.y += self.pad_bottom * cell_height;
g.y += self.pad_bottom * available_height;
// If the available height is less than the cell height, we
// add half of the difference to center it in the full height.
//
// If necessary, in the future, we can adjust this to account
// for alignment, but that isn't necessary with any of the nf
// icons afaict.
const cell_height: f64 = @floatFromInt(metrics.cell_height);
g.y += (cell_height - available_height) / 2;
return g;
}

View File

@ -31,6 +31,9 @@ pub const Face = struct {
/// tables).
color: ?ColorState = null,
/// The current size this font is set to.
size: font.face.DesiredSize,
/// True if our build is using Harfbuzz. If we're not, we can avoid
/// some Harfbuzz-specific code paths.
const harfbuzz_shaper = font.options.backend.hasHarfbuzz();
@ -106,6 +109,7 @@ pub const Face = struct {
.font = ct_font,
.hb_font = hb_font,
.color = color,
.size = opts.size,
};
result.quirks_disable_default_font_features = quirks.disableDefaultFontFeatures(&result);
@ -333,38 +337,99 @@ pub const Face = struct {
.offset_y = 0,
.atlas_x = 0,
.atlas_y = 0,
.advance_x = 0,
};
const metrics = opts.grid_metrics;
const cell_width: f64 = @floatFromInt(metrics.cell_width);
const cell_height: f64 = @floatFromInt(metrics.cell_height);
// const cell_height: f64 = @floatFromInt(metrics.cell_height);
const glyph_size = opts.constraint.constrain(
// We eliminate any negative vertical padding since these overlap
// values aren't needed under CoreText with how precisely we apply
// constraints, and they can lead to extra height that looks bad
// for things like powerline glyphs.
var constraint = opts.constraint;
constraint.pad_top = @max(0.0, constraint.pad_top);
constraint.pad_bottom = @max(0.0, constraint.pad_bottom);
const glyph_size = constraint.constrain(
.{
.width = rect.size.width,
.height = rect.size.height,
.x = rect.origin.x,
.y = rect.origin.y + @as(f64, @floatFromInt(metrics.cell_baseline)),
},
cell_width,
cell_height,
metrics,
opts.constraint_width,
);
const width = glyph_size.width;
const height = glyph_size.height;
const x = glyph_size.x;
const y = glyph_size.y;
// These calculations are an attempt to mostly imitate the effect of
// `shouldSubpixelQuantizeFonts`[^1], which helps maximize legibility
// at small pixel sizes (low DPI). We do this math ourselves instead
// of letting CoreText do it because it's not entirely clear how the
// math in CoreText works and we've run in to edge cases where glyphs
// have their bottom or left row cut off due to bad rounding.
//
// This math seems to have a mostly comparable result to whatever it
// is that CoreText does, and is even (in my opinion) better in some
// cases.
//
// I'm not entirely certain but I suspect that when you enable the
// CoreText option it also does some sort of rudimentary hinting,
// but it doesn't seem to make that big of a difference in terms
// of legibility in the end.
//
// [^1]: https://developer.apple.com/documentation/coregraphics/cgcontext/setshouldsubpixelquantizefonts(_:)?language=objc
// We have to include the fractional pixels that we won't be offsetting
// in our width and height calculations, that is, we offset by the floor
// of the bearings when we render the glyph, meaning there's still a bit
// of extra width to the area that's drawn in beyond just the width of
// the glyph itself, so we include that extra fraction of a pixel when
// calculating the width and height here.
const px_width: u32 = @intFromFloat(@ceil(width + rect.origin.x - @floor(rect.origin.x)));
const px_height: u32 = @intFromFloat(@ceil(height + rect.origin.y - @floor(rect.origin.y)));
// We only want to apply quantization if we don't have any
// constraints and this isn't a bitmap glyph, since CoreText
// doesn't seem to apply its quantization to bitmap glyphs.
//
// TODO: Maybe gate this so it only applies at small font sizes,
// or else offer a user config option that can disable it.
const should_quantize = !sbix and std.meta.eql(opts.constraint, .none);
// We offset our glyph by its bearings when we draw it, using `@floor`
// here rounds it *up* since we negate it right outside. Moving it by
// whole pixels ensures that we don't disturb the pixel alignment of
// the glyph, fractional pixels will still be drawn on all sides as
// necessary.
const draw_x = -@floor(rect.origin.x);
const draw_y = -@floor(rect.origin.y);
// We use `x` and `y` for our full pixel bearings post-raster.
// We need to subtract the fractional pixel of difference from
// the edge of the draw area to the edge of the actual glyph.
const frac_x = rect.origin.x + draw_x;
const frac_y = rect.origin.y + draw_y;
const x = glyph_size.x - frac_x;
const y = glyph_size.y - frac_y;
// We never modify the width.
//
// When using the CoreText option the widths do seem to be
// modified extremely subtly, but even at very small font
// sizes it's hardly a noticeable difference.
const width = glyph_size.width;
// If the top of the glyph (taking in to account the y position)
// is within half a pixel of an exact pixel edge, we round up the
// height, otherwise leave it alone.
//
// This seems to match what CoreText does.
const frac_top = (glyph_size.height + frac_y) - @floor(glyph_size.height + frac_y);
const height =
if (should_quantize)
if (frac_top >= 0.5)
glyph_size.height + 1 - frac_top
else
glyph_size.height
else
glyph_size.height;
// Add the fractional pixel to the width and height and take
// the ceiling to get a canvas size that will definitely fit
// our drawn glyph.
const px_width: u32 = @intFromFloat(@ceil(width + frac_x));
const px_height: u32 = @intFromFloat(@ceil(height + frac_y));
// Settings that are specific to if we are rendering text or emoji.
const color: struct {
@ -429,12 +494,23 @@ pub const Face = struct {
},
});
// "Font smoothing" is what we call "thickening", it's an attempt
// to compensate for optical thinning of fonts, but at this point
// it's just something that makes the text look closer to system
// applications if users want that.
context.setAllowsFontSmoothing(ctx, true);
context.setShouldSmoothFonts(ctx, opts.thicken); // The amadeus "enthicken"
context.setAllowsFontSubpixelQuantization(ctx, true);
context.setShouldSubpixelQuantizeFonts(ctx, true);
context.setShouldSmoothFonts(ctx, opts.thicken);
// Subpixel positioning allows glyphs to be placed at non-integer
// coordinates. We need this for our alignment.
context.setAllowsFontSubpixelPositioning(ctx, true);
context.setShouldSubpixelPositionFonts(ctx, true);
// See comments about quantization earlier in the function.
context.setAllowsFontSubpixelQuantization(ctx, false);
context.setShouldSubpixelQuantizeFonts(ctx, false);
// Anti-aliasing is self explanatory.
context.setAllowsAntialiasing(ctx, true);
context.setShouldAntialias(ctx, true);
@ -455,19 +531,16 @@ pub const Face = struct {
context.setLineWidth(ctx, line_width);
}
// Scale the drawing context so that when we draw
// our glyph it's stretched to the constrained size.
context.scaleCTM(
ctx,
width / rect.size.width,
height / rect.size.height,
);
// We want to render the glyphs at (0,0), but the glyphs themselves
// are offset by bearings, so we have to undo those bearings in order
// to get them to 0,0.
self.font.drawGlyphs(&glyphs, &.{.{
.x = -@floor(rect.origin.x),
.y = -@floor(rect.origin.y),
}}, ctx);
// Draw our glyph.
self.font.drawGlyphs(&glyphs, &.{.{ .x = draw_x, .y = draw_y }}, ctx);
// Write our rasterized glyph to the atlas.
const region = try atlas.reserve(alloc, px_width, px_height);
@ -475,33 +548,47 @@ pub const Face = struct {
// This should be the distance from the bottom of
// the cell to the top of the glyph's bounding box.
const offset_y: i32 =
@as(i32, @intFromFloat(@floor(y))) +
@as(i32, @intCast(px_height));
const offset_y: i32 = @as(i32, @intFromFloat(@round(y))) + @as(i32, @intCast(px_height));
// This should be the distance from the left of
// the cell to the left of the glyph's bounding box.
const offset_x: i32 = offset_x: {
var result: i32 = @intFromFloat(@round(x));
// If our cell was resized then we adjust our glyph's
// position relative to the new center. This keeps glyphs
// centered in the cell whether it was made wider or narrower.
if (metrics.original_cell_width) |original_width| {
const before: i32 = @intCast(original_width);
const after: i32 = @intCast(metrics.cell_width);
// Increase the offset by half of the difference
// between the widths to keep things centered.
result += @divTrunc(after - before, 2);
// If the glyph's advance is narrower than the cell width then we
// center the advance of the glyph within the cell width. At first
// I implemented this to proportionally scale the center position
// of the glyph but that messes up glyphs that are meant to align
// vertically with others, so this is a compromise.
//
// This makes it so that when the `adjust-cell-width` config is
// used, or when a fallback font with a different advance width
// is used, we don't get weirdly aligned glyphs.
//
// We don't do this if the constraint has a horizontal alignment,
// since in that case the position was already calculated with the
// new cell width in mind.
if (opts.constraint.align_horizontal == .none) {
const advance = self.font.getAdvancesForGlyphs(.horizontal, &glyphs, null);
const new_advance =
cell_width * @as(f64, @floatFromInt(opts.cell_width orelse 1));
// If the original advance is greater than the cell width then
// it's possible that this is a ligature or other glyph that is
// intended to overflow the cell to one side or the other, and
// adjusting the bearings could mess that up, so we just leave
// it alone if that's the case.
//
// We also don't want to do anything if the advance is zero or
// less, since this is used for stuff like combining characters.
if (advance > new_advance or advance <= 0.0) {
break :offset_x @intFromFloat(@round(x));
}
break :offset_x @intFromFloat(
@round(x + (new_advance - advance) / 2),
);
} else {
break :offset_x @intFromFloat(@round(x));
}
break :offset_x result;
};
// Get our advance
var advances: [glyphs.len]macos.graphics.Size = undefined;
_ = self.font.getAdvancesForGlyphs(.horizontal, &glyphs, &advances);
return .{
.width = px_width,
.height = px_height,
@ -509,7 +596,6 @@ pub const Face = struct {
.offset_y = offset_y,
.atlas_x = region.x,
.atlas_y = region.y,
.advance_x = @floatCast(advances[0].width),
};
}
@ -741,6 +827,20 @@ pub const Face = struct {
break :cell_width max;
};
// Measure "" (CJK water ideograph, U+6C34) for our ic width.
const ic_width: ?f64 = ic_width: {
const glyph = self.glyphIndex('水') orelse break :ic_width null;
var advances: [1]macos.graphics.Size = undefined;
_ = ct_font.getAdvancesForGlyphs(
.horizontal,
&.{@intCast(glyph)},
&advances,
);
break :ic_width advances[0].width;
};
return .{
.cell_width = cell_width,
.ascent = ascent,
@ -752,6 +852,7 @@ pub const Face = struct {
.strikethrough_thickness = strikethrough_thickness,
.cap_height = cap_height,
.ex_height = ex_height,
.ic_width = ic_width,
};
}

View File

@ -59,6 +59,9 @@ pub const Face = struct {
bold: bool = false,
} = .{},
/// The current size this font is set to.
size: font.face.DesiredSize,
/// Initialize a new font face with the given source in-memory.
pub fn initFile(
lib: Library,
@ -107,6 +110,7 @@ pub const Face = struct {
.hb_font = hb_font,
.ft_mutex = ft_mutex,
.load_flags = opts.freetype_load_flags,
.size = opts.size,
};
result.quirks_disable_default_font_features = quirks.disableDefaultFontFeatures(&result);
@ -203,6 +207,7 @@ pub const Face = struct {
/// for clearing any glyph caches, font atlas data, etc.
pub fn setSize(self: *Face, opts: font.face.Options) !void {
try setSize_(self.face, opts.size);
self.size = opts.size;
}
fn setSize_(face: freetype.Face, size: font.face.DesiredSize) !void {
@ -373,7 +378,6 @@ pub const Face = struct {
.offset_y = 0,
.atlas_x = 0,
.atlas_y = 0,
.advance_x = 0,
};
// For synthetic bold, we embolden the glyph.
@ -391,7 +395,7 @@ pub const Face = struct {
const metrics = opts.grid_metrics;
const cell_width: f64 = @floatFromInt(metrics.cell_width);
const cell_height: f64 = @floatFromInt(metrics.cell_height);
// const cell_height: f64 = @floatFromInt(metrics.cell_height);
const glyph_x: f64 = f26dot6ToF64(glyph.*.metrics.horiBearingX);
const glyph_y: f64 = f26dot6ToF64(glyph.*.metrics.horiBearingY) - glyph_height;
@ -403,8 +407,7 @@ pub const Face = struct {
.x = glyph_x,
.y = glyph_y + @as(f64, @floatFromInt(metrics.cell_baseline)),
},
cell_width,
cell_height,
metrics,
opts.constraint_width,
);
@ -639,20 +642,40 @@ pub const Face = struct {
// This should be the distance from the left of
// the cell to the left of the glyph's bounding box.
const offset_x: i32 = offset_x: {
var result: i32 = @intFromFloat(@floor(x));
// If our cell was resized then we adjust our glyph's
// position relative to the new center. This keeps glyphs
// centered in the cell whether it was made wider or narrower.
if (metrics.original_cell_width) |original_width| {
const before: i32 = @intCast(original_width);
const after: i32 = @intCast(metrics.cell_width);
// Increase the offset by half of the difference
// between the widths to keep things centered.
result += @divTrunc(after - before, 2);
// If the glyph's advance is narrower than the cell width then we
// center the advance of the glyph within the cell width. At first
// I implemented this to proportionally scale the center position
// of the glyph but that messes up glyphs that are meant to align
// vertically with others, so this is a compromise.
//
// This makes it so that when the `adjust-cell-width` config is
// used, or when a fallback font with a different advance width
// is used, we don't get weirdly aligned glyphs.
//
// We don't do this if the constraint has a horizontal alignment,
// since in that case the position was already calculated with the
// new cell width in mind.
if (opts.constraint.align_horizontal == .none) {
const advance = f26dot6ToFloat(glyph.*.advance.x);
const new_advance =
cell_width * @as(f64, @floatFromInt(opts.cell_width orelse 1));
// If the original advance is greater than the cell width then
// it's possible that this is a ligature or other glyph that is
// intended to overflow the cell to one side or the other, and
// adjusting the bearings could mess that up, so we just leave
// it alone if that's the case.
//
// We also don't want to do anything if the advance is zero or
// less, since this is used for stuff like combining characters.
if (advance > new_advance or advance <= 0.0) {
break :offset_x @intFromFloat(@floor(x));
}
break :offset_x @intFromFloat(
@floor(x + (new_advance - advance) / 2),
);
} else {
break :offset_x @intFromFloat(@floor(x));
}
break :offset_x result;
};
return Glyph{
@ -662,7 +685,6 @@ pub const Face = struct {
.offset_y = offset_y,
.atlas_x = region.x,
.atlas_y = region.y,
.advance_x = f26dot6ToFloat(glyph.*.advance.x),
};
}
@ -833,7 +855,7 @@ pub const Face = struct {
while (c < 127) : (c += 1) {
if (face.getCharIndex(c)) |glyph_index| {
if (face.loadGlyph(glyph_index, .{
.render = true,
.render = false,
.no_svg = true,
})) {
max = @max(
@ -871,7 +893,7 @@ pub const Face = struct {
defer self.ft_mutex.unlock();
if (face.getCharIndex('H')) |glyph_index| {
if (face.loadGlyph(glyph_index, .{
.render = true,
.render = false,
.no_svg = true,
})) {
break :cap f26dot6ToF64(face.handle.*.glyph.*.metrics.height);
@ -884,7 +906,7 @@ pub const Face = struct {
defer self.ft_mutex.unlock();
if (face.getCharIndex('x')) |glyph_index| {
if (face.loadGlyph(glyph_index, .{
.render = true,
.render = false,
.no_svg = true,
})) {
break :ex f26dot6ToF64(face.handle.*.glyph.*.metrics.height);
@ -895,6 +917,21 @@ pub const Face = struct {
};
};
// Measure "" (CJK water ideograph, U+6C34) for our ic width.
const ic_width: ?f64 = ic_width: {
self.ft_mutex.lock();
defer self.ft_mutex.unlock();
const glyph = face.getCharIndex('水') orelse break :ic_width null;
face.loadGlyph(glyph, .{
.render = false,
.no_svg = true,
}) catch break :ic_width null;
break :ic_width f26dot6ToF64(face.handle.*.glyph.*.advance.x);
};
return .{
.cell_width = cell_width,
@ -910,6 +947,7 @@ pub const Face = struct {
.cap_height = cap_height,
.ex_height = ex_height,
.ic_width = ic_width,
};
}
@ -1019,6 +1057,7 @@ test "color emoji" {
.overline_thickness = 0,
.box_thickness = 0,
.cursor_height = 0,
.icon_height = 0,
}, .constraint_width = 2, .constraint = .{
.size_horizontal = .cover,
.size_vertical = .cover,

View File

@ -235,7 +235,6 @@ pub const Face = struct {
.offset_y = 0,
.atlas_x = region.x,
.atlas_y = region.y,
.advance_x = 0,
};
}

View File

@ -25,6 +25,7 @@ pub fn getConstraint(cp: u21) Constraint {
=> .{
.size_horizontal = .cover,
.size_vertical = .fit,
.height = .icon,
.max_constraint_width = 1,
.align_horizontal = .center,
.align_vertical = .center,
@ -33,7 +34,35 @@ pub fn getConstraint(cp: u21) Constraint {
.pad_top = 0.1,
.pad_bottom = 0.1,
},
0x276c...0x2771,
0x276c...0x276d,
=> .{
.size_horizontal = .cover,
.size_vertical = .fit,
.max_constraint_width = 1,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.4028056112224450,
.group_height = 1.1222570532915361,
.group_x = 0.1428571428571428,
.group_y = 0.0349162011173184,
.pad_top = 0.15,
.pad_bottom = 0.15,
},
0x276e...0x276f,
=> .{
.size_horizontal = .cover,
.size_vertical = .fit,
.max_constraint_width = 1,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.0115606936416186,
.group_height = 1.1222570532915361,
.group_x = 0.0057142857142857,
.group_y = 0.0125698324022346,
.pad_top = 0.15,
.pad_bottom = 0.15,
},
0x2770...0x2771,
=> .{
.size_horizontal = .cover,
.size_vertical = .fit,
@ -285,7 +314,7 @@ pub fn getConstraint(cp: u21) Constraint {
0xe0d0...0xe0d1,
=> .{
.size_horizontal = .cover,
.size_vertical = .cover,
.size_vertical = .fit,
.align_horizontal = .start,
.align_vertical = .center,
},
@ -294,7 +323,7 @@ pub fn getConstraint(cp: u21) Constraint {
0xe0d5,
=> .{
.size_horizontal = .cover,
.size_vertical = .cover,
.size_vertical = .fit,
.align_horizontal = .center,
.align_vertical = .center,
},
@ -356,15 +385,689 @@ pub fn getConstraint(cp: u21) Constraint {
0x2b58,
0xe000...0xe0a9,
0xe4fa...0xe7ef,
0xea60...0xec1e,
0xed00...0xf847,
0xea60,
0xea62...0xea7c,
0xea7e...0xea98,
0xeaa3...0xeab3,
0xeab8...0xead3,
0xead7...0xeb42,
0xeb44...0xeb6d,
0xeb72...0xeb89,
0xeb8b...0xeb99,
0xeb9b...0xebd4,
0xebd6,
0xebd8...0xec06,
0xec08...0xec0a,
0xec0d...0xec1e,
0xed00...0xf018,
0xf01a...0xf02f,
0xf031...0xf03c,
0xf041...0xf043,
0xf045...0xf049,
0xf04b...0xf050,
0xf054...0xf059,
0xf05c...0xf070,
0xf072...0xf077,
0xf079...0xf07a,
0xf07c...0xf080,
0xf082...0xf08b,
0xf08d...0xf091,
0xf093...0xf09b,
0xf09d...0xf09e,
0xf0a0,
0xf0a5...0xf0a9,
0xf0ab...0xf0c9,
0xf0cb...0xf0d5,
0xf0d7...0xf0dd,
0xf0df...0xf0e6,
0xf0e8...0xf295,
0xf297...0xf2c1,
0xf2c6...0xf2ef,
0xf2f1...0xf305,
0xf307...0xf847,
0xf0001...0xf1af0,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
},
0xea61,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.3315669947009841,
.group_height = 1.0763840224246670,
.group_x = 0.0847072200113701,
.group_y = 0.0709635416666667,
},
0xea7d,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.1913145539906103,
.group_height = 1.1428571428571428,
.group_x = 0.0916256157635468,
.group_y = 0.0415039062500000,
},
0xea99,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.0639412997903563,
.group_height = 2.0940695296523519,
.group_x = 0.0295566502463054,
.group_y = 0.2270507812500000,
},
0xea9a,
0xeaa1,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.3029525032092426,
.group_height = 1.1729667812142039,
.group_x = 0.1527093596059113,
.group_y = 0.0751953125000000,
},
0xea9b,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.1639908256880733,
.group_height = 1.3128205128205128,
.group_x = 0.0719211822660099,
.group_y = 0.0869140625000000,
},
0xea9c,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.1639908256880733,
.group_height = 1.3195876288659794,
.group_x = 0.0719211822660099,
.group_y = 0.0830078125000000,
},
0xea9d,
0xeaa0,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 2.4457831325301207,
.group_height = 1.9692307692307693,
.group_x = 0.2857142857142857,
.group_y = 0.2763671875000000,
},
0xea9e...0xea9f,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.9556840077071291,
.group_height = 2.4674698795180725,
.group_x = 0.2137931034482759,
.group_y = 0.3066406250000000,
},
0xeaa2,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.2412121212121212,
.group_height = 1.0591799039527152,
.group_x = 0.0683593750000000,
.group_y = 0.0146484375000000,
},
0xeab4,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.0049115913555993,
.group_height = 1.8998144712430427,
.group_y = 0.2026367187500000,
},
0xeab5,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.8979591836734695,
.group_height = 1.0054000981836033,
.group_x = 0.2023460410557185,
.group_y = 0.0053710937500000,
},
0xeab6,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.8979591836734695,
.group_height = 1.0054000981836033,
.group_x = 0.2707722385141740,
},
0xeab7,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.0049115913555993,
.group_height = 1.8980537534754403,
.group_x = 0.0048875855327468,
.group_y = 0.2709960937500000,
},
0xead4...0xead5,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.4152542372881356,
.group_x = 0.1486118671747414,
},
0xead6,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_height = 1.1390433815350389,
.group_y = 0.0688476562500000,
},
0xeb43,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.3635153129161119,
.group_height = 1.0002360944082516,
.group_x = 0.1992187500000000,
.group_y = 0.0002360386808388,
},
0xeb6e,
0xeb71,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_height = 2.0197238658777121,
.group_y = 0.2524414062500000,
},
0xeb6f,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 2.0098619329388558,
.group_x = 0.2492639842983317,
},
0xeb70,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 2.0098619329388558,
.group_height = 1.0039215686274510,
.group_x = 0.2492639842983317,
.group_y = 0.0039062500000000,
},
0xeb8a,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 2.8826979472140764,
.group_height = 2.9804097167804766,
.group_x = 0.2634791454730417,
.group_y = 0.3314678485576923,
},
0xeb9a,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.1441340782122904,
.group_height = 1.0591799039527152,
.group_x = 0.0683593750000000,
.group_y = 0.0146484375000000,
},
0xebd5,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.0723270440251573,
.group_height = 1.0728129910948141,
.group_y = 0.0678710937500000,
},
0xebd7,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_height = 1.0000418544302916,
.group_y = 0.0000418526785714,
},
0xec07,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 2.8615369874243446,
.group_height = 2.9789458113505249,
.group_x = 0.2609446802539727,
.group_y = 0.3313029661016949,
},
0xec0b,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.0722513089005237,
.group_height = 1.0002360944082516,
.group_y = 0.0002360386808388,
},
0xec0c,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.2487804878048780,
.group_x = 0.1992187500000000,
},
0xf019,
0xf08c,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.0004882812500000,
},
0xf030,
0xf03e,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.0004882812500000,
.group_height = 1.1428571428571428,
.group_y = 0.0625000000000000,
},
0xf03d,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.0004882812500000,
.group_height = 1.5014662756598240,
.group_y = 0.1669921875000000,
},
0xf03f,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.6018762826150690,
.group_x = 0.1876220107369448,
},
0xf040,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.0006976906439684,
.group_height = 1.0001808776182035,
.group_x = 0.0006972042111134,
.group_y = 0.0001808449074074,
},
0xf044,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.1029147024980515,
.group_height = 1.1024142703367676,
.group_x = 0.0463592039005675,
.group_y = 0.0430325010461710,
},
0xf04a,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.0004882812500000,
.group_height = 1.3312975252838291,
.group_y = 0.1245571402616279,
},
0xf051,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.6007812500000000,
.group_height = 1.3312170271945341,
.group_x = 0.1874084919472914,
.group_y = 0.1245117187500000,
},
0xf052,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.1436671384194865,
.group_height = 1.1430165816326530,
.group_x = 0.0624629273607646,
.group_y = 0.0625610266424885,
},
0xf053,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.8765709864847797,
.group_height = 1.0707191397207079,
.group_x = 0.2332599943628554,
.group_y = 0.0332682382480123,
},
0xf05a...0xf05b,
0xf081,
0xf092,
0xf0aa,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.0005935142780173,
.group_height = 1.0001395089285714,
.group_y = 0.0000697447342726,
},
0xf071,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.0014662756598240,
.group_height = 1.1428571428571428,
.group_x = 0.0004880429477794,
.group_y = 0.0625000000000000,
},
0xf078,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.0717654378877508,
.group_height = 1.8757195185766613,
.group_x = 0.0331834301604062,
.group_y = 0.1670386385827870,
},
0xf07b,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_height = 1.1428571428571428,
.group_y = 0.0625000000000000,
},
0xf09c,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_height = 1.0810546875000000,
},
0xf09f,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.7506617925122907,
.group_height = 1.0810546875000000,
.group_x = 0.2143937211981567,
},
0xf0a1,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.0009775171065494,
.group_x = 0.0004882812500000,
},
0xf0a2,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.1433271023627367,
.group_height = 1.0001395089285714,
.group_x = 0.0624235731978609,
.group_y = 0.0000697447342726,
},
0xf0a3,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.0005760656161586,
.group_height = 1.0001220681837999,
.group_x = 0.0004792774839344,
.group_y = 0.0000610266424885,
},
0xf0a4,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.0005935142780173,
.group_height = 1.3335193452380951,
.group_y = 0.1250523085507044,
},
0xf0ca,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.0005935142780173,
.group_height = 1.1922501247297521,
.group_y = 0.0806249128190822,
},
0xf0d6,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_height = 1.5014662756598240,
.group_y = 0.1669921875000000,
},
0xf0de,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.2253421114919656,
.group_height = 2.5216400911161729,
.group_x = 0.0918898809523810,
.group_y = 0.6034327009936766,
},
0xf0e7,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.3336843856081169,
.group_x = 0.1247597299147187,
},
0xf296,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.0005148743038617,
.group_height = 1.0385966606705219,
.group_x = 0.0005146093447336,
.group_y = 0.0186218440507742,
},
0xf2c2...0xf2c3,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.0000770970394737,
.group_height = 1.2864321608040201,
.group_y = 0.1113281250000000,
},
0xf2c4,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.0344231791600214,
.group_x = 0.0166002826673519,
},
0xf2c5,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.0004538836055876,
.group_height = 1.4840579710144928,
.group_x = 0.0004536776887225,
.group_y = 0.1630859375000000,
},
0xf2f0,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.0005935142780173,
.group_height = 1.0334438518091393,
.group_y = 0.0161807783512345,
},
0xf306,
=> .{
.size_horizontal = .fit,
.size_vertical = .fit,
.height = .icon,
.align_horizontal = .center,
.align_vertical = .center,
.group_width = 1.2427184466019416,
.group_x = 0.0976562500000000,
},
else => .none,
};
}

View File

@ -7,11 +7,16 @@ attributes and scaling rules.
This does include an `eval` call! This is spooky, but we trust the nerd fonts code to
be safe and not malicious or anything.
This script requires Python 3.12 or greater.
This script requires Python 3.12 or greater, requires that the `fontTools`
python module is installed, and requires that the path to a copy of the
SymbolsNerdFontMono font is passed as the first argument to the script.
"""
import ast
import sys
import math
from fontTools.ttLib import TTFont
from fontTools.pens.boundsPen import BoundsPen
from collections import defaultdict
from contextlib import suppress
from pathlib import Path
@ -19,7 +24,18 @@ from types import SimpleNamespace
from typing import Literal, TypedDict, cast
type PatchSetAttributes = dict[Literal["default"] | int, PatchSetAttributeEntry]
type AttributeHash = tuple[str | None, str | None, str, float, float, float]
type AttributeHash = tuple[
str | None,
str | None,
str,
float,
float,
float,
float,
float,
float,
float,
]
type ResolvedSymbol = PatchSetAttributes | PatchSetScaleRules | int | None
@ -34,6 +50,11 @@ class PatchSetAttributeEntry(TypedDict):
stretch: str
params: dict[str, float | bool]
group_x: float
group_y: float
group_width: float
group_height: float
class PatchSet(TypedDict):
SymStart: int
@ -137,6 +158,10 @@ def attr_key(attr: PatchSetAttributeEntry) -> AttributeHash:
float(params.get("overlap", 0.0)),
float(params.get("xy-ratio", -1.0)),
float(params.get("ypadding", 0.0)),
float(attr.get("group_x", 0.0)),
float(attr.get("group_y", 0.0)),
float(attr.get("group_width", 1.0)),
float(attr.get("group_height", 1.0)),
)
@ -162,6 +187,11 @@ def emit_zig_entry_multikey(codepoints: list[int], attr: PatchSetAttributeEntry)
stretch = attr.get("stretch", "")
params = attr.get("params", {})
group_x = attr.get("group_x", 0.0)
group_y = attr.get("group_y", 0.0)
group_width = attr.get("group_width", 1.0)
group_height = attr.get("group_height", 1.0)
overlap = params.get("overlap", 0.0)
xy_ratio = params.get("xy-ratio", -1.0)
y_padding = params.get("ypadding", 0.0)
@ -180,16 +210,18 @@ def emit_zig_entry_multikey(codepoints: list[int], attr: PatchSetAttributeEntry)
if "xy" in stretch:
s += " .size_horizontal = .stretch,\n"
s += " .size_vertical = .stretch,\n"
elif "!" in stretch:
elif "!" in stretch or "^" in stretch:
s += " .size_horizontal = .cover,\n"
s += " .size_vertical = .fit,\n"
elif "^" in stretch:
s += " .size_horizontal = .cover,\n"
s += " .size_vertical = .cover,\n"
else:
s += " .size_horizontal = .fit,\n"
s += " .size_vertical = .fit,\n"
# `^` indicates that scaling should fill
# the whole cell, not just the icon height.
if "^" not in stretch:
s += " .height = .icon,\n"
# There are two cases where we want to limit the constraint width to 1:
# - If there's a `1` in the stretch mode string.
# - If the stretch mode is `xy` and there's not an explicit `2`.
@ -201,6 +233,15 @@ def emit_zig_entry_multikey(codepoints: list[int], attr: PatchSetAttributeEntry)
if valign is not None:
s += f" .align_vertical = {valign},\n"
if group_width != 1.0:
s += f" .group_width = {group_width:.16f},\n"
if group_height != 1.0:
s += f" .group_height = {group_height:.16f},\n"
if group_x != 0.0:
s += f" .group_x = {group_x:.16f},\n"
if group_y != 0.0:
s += f" .group_y = {group_y:.16f},\n"
# `overlap` and `ypadding` are mutually exclusive,
# this is asserted in the nerd fonts patcher itself.
if overlap:
@ -223,16 +264,53 @@ def emit_zig_entry_multikey(codepoints: list[int], attr: PatchSetAttributeEntry)
return s
def generate_zig_switch_arms(patch_sets: list[PatchSet]) -> str:
def generate_zig_switch_arms(
patch_sets: list[PatchSet],
nerd_font: TTFont,
) -> str:
cmap = nerd_font.getBestCmap()
glyphs = nerd_font.getGlyphSet()
entries: dict[int, PatchSetAttributeEntry] = {}
for entry in patch_sets:
attributes = entry["Attributes"]
for cp in range(entry["SymStart"], entry["SymEnd"] + 1):
entries[cp] = attributes["default"]
entries[cp] = attributes["default"].copy()
entries |= {k: v for k, v in attributes.items() if isinstance(k, int)}
if entry["ScaleRules"] is not None and "ScaleGroups" in entry["ScaleRules"]:
for group in entry["ScaleRules"]["ScaleGroups"]:
xMin = math.inf
yMin = math.inf
xMax = -math.inf
yMax = -math.inf
individual_bounds: dict[int, tuple[int, int, int ,int]] = {}
for cp in group:
if cp not in cmap:
continue
glyph = glyphs[cmap[cp]]
bounds = BoundsPen(glyphSet=glyphs)
glyph.draw(bounds)
individual_bounds[cp] = bounds.bounds
xMin = min(bounds.bounds[0], xMin)
yMin = min(bounds.bounds[1], yMin)
xMax = max(bounds.bounds[2], xMax)
yMax = max(bounds.bounds[3], yMax)
group_width = xMax - xMin
group_height = yMax - yMin
for cp in group:
if cp not in cmap or cp not in entries:
continue
this_bounds = individual_bounds[cp]
this_width = this_bounds[2] - this_bounds[0]
this_height = this_bounds[3] - this_bounds[1]
entries[cp]["group_width"] = group_width / this_width
entries[cp]["group_height"] = group_height / this_height
entries[cp]["group_x"] = (this_bounds[0] - xMin) / group_width
entries[cp]["group_y"] = (this_bounds[1] - yMin) / group_height
del entries[0]
# Group codepoints by attribute key
@ -253,6 +331,10 @@ def generate_zig_switch_arms(patch_sets: list[PatchSet]) -> str:
if __name__ == "__main__":
project_root = Path(__file__).resolve().parents[2]
nf_path = sys.argv[1]
nerd_font = TTFont(nf_path)
patcher_path = project_root / "vendor" / "nerd-fonts" / "font-patcher.py"
source = patcher_path.read_text(encoding="utf-8")
patch_set = extract_patch_set_values(source)
@ -272,5 +354,5 @@ const Constraint = @import("face.zig").RenderOptions.Constraint;
pub fn getConstraint(cp: u21) Constraint {
return switch (cp) {
""")
f.write(generate_zig_switch_arms(patch_set))
f.write(generate_zig_switch_arms(patch_set, nerd_font))
f.write("\n else => .none,\n };\n}\n")

View File

@ -195,7 +195,6 @@ pub fn renderGlyph(
.offset_y = 0,
.atlas_x = 0,
.atlas_y = 0,
.advance_x = 0,
};
const metrics = self.metrics;
@ -227,8 +226,6 @@ pub fn renderGlyph(
.offset_y = @as(i32, @intCast(region.height +| canvas.clip_bottom)) - @as(i32, @intCast(padding_y)),
.atlas_x = region.x,
.atlas_y = region.y,
.advance_x = @floatFromInt(width),
.sprite = true,
};
}

View File

@ -19,7 +19,12 @@ const internal_os = @import("os/main.zig");
// Some comptime assertions that our C API depends on.
comptime {
assert(apprt.runtime == apprt.embedded);
// We allow tests to reference this file because we unit test
// some of the C API. At runtime though we should never get these
// functions unless we are building libghostty.
if (!builtin.is_test) {
assert(apprt.runtime == apprt.embedded);
}
}
/// Global options so we can log. This is identical to main.
@ -29,7 +34,9 @@ comptime {
// These structs need to be referenced so the `export` functions
// are truly exported by the C API lib.
_ = @import("config.zig").CAPI;
_ = apprt.runtime.CAPI;
if (@hasDecl(apprt.runtime, "CAPI")) {
_ = apprt.runtime.CAPI;
}
}
/// ghostty_info_s
@ -46,6 +53,24 @@ const Info = extern struct {
};
};
/// ghostty_string_s
pub const String = extern struct {
ptr: ?[*]const u8,
len: usize,
pub const empty: String = .{
.ptr = null,
.len = 0,
};
pub fn fromSlice(slice: []const u8) String {
return .{
.ptr = slice.ptr,
.len = slice.len,
};
}
};
/// Initialize ghostty global state.
export fn ghostty_init(argc: usize, argv: [*][*:0]u8) c_int {
assert(builtin.link_libc);
@ -95,3 +120,8 @@ export fn ghostty_info() Info {
export fn ghostty_translate(msgid: [*:0]const u8) [*:0]const u8 {
return internal_os.i18n._(msgid);
}
/// Free a string allocated by Ghostty.
export fn ghostty_string_free(str: String) void {
state.alloc.free(str.ptr.?[0..str.len]);
}

View File

@ -49,6 +49,7 @@ pub const locales = [_][:0]const u8{
"ca_ES.UTF-8",
"bg_BG.UTF-8",
"ga_IE.UTF-8",
"he_IL.UTF-8",
};
/// Set for faster membership lookup of locales.

View File

@ -17,7 +17,7 @@ test "read /proc/sys/kernel/osrelease" {
if (comptime builtin.os.tag != .linux) return null;
const allocator = std.testing.allocator;
const kernel_info = try getKernelInfo(allocator);
const kernel_info = getKernelInfo(allocator).?;
defer allocator.free(kernel_info);
// Since we can't hardcode the info in tests, just check

View File

@ -2,6 +2,8 @@
//! system. These aren't restricted to syscalls or low-level operations, but
//! also OS-specific features and conventions.
const builtin = @import("builtin");
const dbus = @import("dbus.zig");
const desktop = @import("desktop.zig");
const env = @import("env.zig");
@ -14,7 +16,7 @@ const openpkg = @import("open.zig");
const pipepkg = @import("pipe.zig");
const resourcesdir = @import("resourcesdir.zig");
const systemd = @import("systemd.zig");
const kernelInfo = @import("kernel_info.zig");
const kernel_info = @import("kernel_info.zig");
// Namespaces
pub const args = @import("args.zig");
@ -59,8 +61,12 @@ pub const pipe = pipepkg.pipe;
pub const resourcesDir = resourcesdir.resourcesDir;
pub const ResourcesDir = resourcesdir.ResourcesDir;
pub const ShellEscapeWriter = shell.ShellEscapeWriter;
pub const getKernelInfo = kernelInfo.getKernelInfo;
pub const getKernelInfo = kernel_info.getKernelInfo;
test {
_ = i18n;
if (comptime builtin.os.tag == .linux) {
_ = kernel_info;
}
}

View File

@ -63,3 +63,136 @@ pub fn launchedBySystemd() bool {
else => false,
};
}
/// systemd notifications. Used by Ghostty to inform systemd of the state of the
/// process. Currently only used to notify systemd that we are ready and that
/// configuration reloading has started.
///
/// See: https://www.freedesktop.org/software/systemd/man/latest/sd_notify.html
///
/// These functions were re-implemented in Zig instead of using the `libsystemd`
/// library to avoid the complexity of another external dependency, as well as
/// to take advantage of Zig features like `comptime` to ensure minimal impact
/// on non-Linux systems (like FreeBSD) that will never support `systemd`.
///
/// Linux systems that do not use `systemd` should not be impacted as they
/// should never start Ghostty with the `NOTIFY_SOCKET` environment variable set
/// and these functions essentially become a no-op.
///
/// See `systemd`'s [Interface Portability and Stability Promise](https://systemd.io/PORTABILITY_AND_STABILITY/)
/// for assurances that the interfaces used here will be supported and stable for
/// the long term.
pub const notify = struct {
/// Send the given message to the UNIX socket specified in the NOTIFY_SOCKET
/// environment variable. If there NOTIFY_SOCKET environment variable does
/// not exist then no message is sent.
fn send(message: []const u8) void {
// systemd is Linux-only so this is a no-op anywhere else
if (comptime builtin.os.tag != .linux) return;
// Get the socket address that should receive notifications.
const socket_path = std.posix.getenv("NOTIFY_SOCKET") orelse return;
// If the socket address is an empty string return.
if (socket_path.len == 0) return;
// The socket address must be a path or an abstract socket.
if (socket_path[0] != '/' and socket_path[0] != '@') {
log.warn("only AF_UNIX sockets with path or abstract namespace addresses are supported!", .{});
return;
}
var socket_address: std.os.linux.sockaddr.un = undefined;
// Error out if the supplied socket path is too long.
if (socket_address.path.len < socket_path.len) {
log.warn("NOTIFY_SOCKET path is too long!", .{});
return;
}
socket_address.family = std.os.linux.AF.UNIX;
@memcpy(socket_address.path[0..socket_path.len], socket_path);
socket_address.path[socket_path.len] = 0;
const socket: std.os.linux.socket_t = socket: {
const rc = std.os.linux.socket(
std.os.linux.AF.UNIX,
std.os.linux.SOCK.DGRAM | std.os.linux.SOCK.CLOEXEC,
0,
);
switch (std.os.linux.E.init(rc)) {
.SUCCESS => break :socket @intCast(rc),
else => |e| {
log.warn("creating socket failed: {s}", .{@tagName(e)});
return;
},
}
};
defer _ = std.os.linux.close(socket);
connect: {
const rc = std.os.linux.connect(
socket,
&socket_address,
@offsetOf(std.os.linux.sockaddr.un, "path") + socket_address.path.len,
);
switch (std.os.linux.E.init(rc)) {
.SUCCESS => break :connect,
else => |e| {
log.warn("unable to connect to notify socket: {s}", .{@tagName(e)});
return;
},
}
}
write: {
const rc = std.os.linux.write(socket, message.ptr, message.len);
switch (std.os.linux.E.init(rc)) {
.SUCCESS => {
const written = rc;
if (written < message.len) {
log.warn("short write to notify socket: {d} < {d}", .{ rc, message.len });
return;
}
break :write;
},
else => |e| {
log.warn("unable to write to notify socket: {s}", .{@tagName(e)});
return;
},
}
}
}
/// Tell systemd that we are ready or that we are finished reloading.
/// See: https://www.freedesktop.org/software/systemd/man/latest/sd_notify.html#READY=1
pub fn ready() void {
if (comptime builtin.os.tag != .linux) return;
send("READY=1");
}
/// Tell systemd that we have started reloading our configuration.
/// See: https://www.freedesktop.org/software/systemd/man/latest/sd_notify.html#RELOADING=1
/// and: https://www.freedesktop.org/software/systemd/man/latest/sd_notify.html#MONOTONIC_USEC=%E2%80%A6
pub fn reloading() void {
if (comptime builtin.os.tag != .linux) return;
const ts = std.posix.clock_gettime(.MONOTONIC) catch |err| {
log.err("unable to get MONOTONIC clock: {}", .{err});
return;
};
const now = ts.sec * std.time.us_per_s + @divFloor(ts.nsec, std.time.ns_per_us);
var buffer: [64]u8 = undefined;
const message = std.fmt.bufPrint(&buffer, "RELOADING=1\nMONOTONIC_USEC={d}", .{now}) catch |err| {
log.err("unable to format reloading message: {}", .{err});
return;
};
send(message);
}
};

View File

@ -95,6 +95,76 @@ if [[ "$GHOSTTY_SHELL_FEATURES" == *"sudo"* && -n "$TERMINFO" ]]; then
}
fi
# SSH Integration
if [[ "$GHOSTTY_SHELL_FEATURES" == *ssh-* ]]; then
ssh() {
builtin local ssh_term ssh_opts
ssh_term="xterm-256color"
ssh_opts=()
# Configure environment variables for remote session
if [[ "$GHOSTTY_SHELL_FEATURES" == *ssh-env* ]]; then
ssh_opts+=(-o "SetEnv COLORTERM=truecolor")
ssh_opts+=(-o "SendEnv TERM_PROGRAM TERM_PROGRAM_VERSION")
fi
# Install terminfo on remote host if needed
if [[ "$GHOSTTY_SHELL_FEATURES" == *ssh-terminfo* ]]; then
builtin local ssh_user ssh_hostname
while IFS=' ' read -r ssh_key ssh_value; do
case "$ssh_key" in
user) ssh_user="$ssh_value" ;;
hostname) ssh_hostname="$ssh_value" ;;
esac
[[ -n "$ssh_user" && -n "$ssh_hostname" ]] && break
done < <(builtin command ssh -G "$@" 2>/dev/null)
if [[ -n "$ssh_hostname" ]]; then
builtin local ssh_target="${ssh_user}@${ssh_hostname}"
# Check if terminfo is already cached
if "$GHOSTTY_BIN_DIR/ghostty" +ssh-cache --host="$ssh_target" >/dev/null 2>&1; then
ssh_term="xterm-ghostty"
elif builtin command -v infocmp >/dev/null 2>&1; then
builtin local ssh_terminfo ssh_cpath_dir ssh_cpath
ssh_terminfo=$(infocmp -0 -x xterm-ghostty 2>/dev/null)
if [[ -n "$ssh_terminfo" ]]; then
builtin echo "Setting up xterm-ghostty terminfo on $ssh_hostname..." >&2
ssh_cpath_dir=$(mktemp -d "/tmp/ghostty-ssh-$ssh_user.XXXXXX" 2>/dev/null) || ssh_cpath_dir="/tmp/ghostty-ssh-$ssh_user.$$"
ssh_cpath="$ssh_cpath_dir/socket"
if builtin echo "$ssh_terminfo" | builtin command ssh -o ControlMaster=yes -o ControlPath="$ssh_cpath" -o ControlPersist=60s "$@" '
infocmp xterm-ghostty >/dev/null 2>&1 && exit 0
command -v tic >/dev/null 2>&1 || exit 1
mkdir -p ~/.terminfo 2>/dev/null && tic -x - 2>/dev/null && exit 0
exit 1
' 2>/dev/null; then
ssh_term="xterm-ghostty"
ssh_opts+=(-o "ControlPath=$ssh_cpath")
# Cache successful installation
"$GHOSTTY_BIN_DIR/ghostty" +ssh-cache --add="$ssh_target" >/dev/null 2>&1 || true
else
builtin echo "Warning: Failed to install terminfo." >&2
fi
else
builtin echo "Warning: Could not generate terminfo data." >&2
fi
else
builtin echo "Warning: ghostty command not available for cache management." >&2
fi
fi
fi
# Execute SSH with TERM environment variable
TERM="$ssh_term" builtin command ssh "${ssh_opts[@]}" "$@"
}
fi
# Import bash-preexec, safe to do multiple times
builtin source "$(dirname -- "${BASH_SOURCE[0]}")/bash-preexec.sh"

View File

@ -98,6 +98,95 @@
(external sudo) $@args
}
# SSH Integration
use str
if (str:contains $E:GHOSTTY_SHELL_FEATURES ssh-) {
fn ssh {|@args|
var ssh-term = "xterm-256color"
var ssh-opts = []
# Configure environment variables for remote session
if (str:contains $E:GHOSTTY_SHELL_FEATURES ssh-env) {
set ssh-opts = (conj $ssh-opts
-o "SetEnv COLORTERM=truecolor"
-o "SendEnv TERM_PROGRAM TERM_PROGRAM_VERSION"
)
}
# Install terminfo on remote host if needed
if (str:contains $E:GHOSTTY_SHELL_FEATURES ssh-terminfo) {
var ssh-user = ""
var ssh-hostname = ""
# Parse ssh config
var ssh-config = (external ssh -G $@args 2>/dev/null | slurp)
for line (str:split "\n" $ssh-config) {
var parts = (str:split " " $line)
if (> (count $parts) 1) {
var ssh-key = $parts[0]
var ssh-value = $parts[1]
if (eq $ssh-key user) {
set ssh-user = $ssh-value
} elif (eq $ssh-key hostname) {
set ssh-hostname = $ssh-value
}
if (and (not-eq $ssh-user "") (not-eq $ssh-hostname "")) {
break
}
}
}
if (not-eq $ssh-hostname "") {
var ssh-target = $ssh-user"@"$ssh-hostname
# Check if terminfo is already cached
if (and (has-external ghostty) (bool ?(external ghostty +ssh-cache --host=$ssh-target >/dev/null 2>&1))) {
set ssh-term = "xterm-ghostty"
} elif (has-external infocmp) {
var ssh-terminfo = (external infocmp -0 -x xterm-ghostty 2>/dev/null | slurp)
if (not-eq $ssh-terminfo "") {
echo "Setting up xterm-ghostty terminfo on "$ssh-hostname"..." >&2
var ssh-cpath-dir = ""
try {
set ssh-cpath-dir = (external mktemp -d "/tmp/ghostty-ssh-"$ssh-user".XXXXXX" 2>/dev/null | slurp)
} catch {
set ssh-cpath-dir = "/tmp/ghostty-ssh-"$ssh-user"."(randint 10000 99999)
}
var ssh-cpath = $ssh-cpath-dir"/socket"
if (bool ?(echo $ssh-terminfo | external ssh $@ssh-opts -o ControlMaster=yes -o ControlPath=$ssh-cpath -o ControlPersist=60s $@args '
infocmp xterm-ghostty >/dev/null 2>&1 && exit 0
command -v tic >/dev/null 2>&1 || exit 1
mkdir -p ~/.terminfo 2>/dev/null && tic -x - 2>/dev/null && exit 0
exit 1
' 2>/dev/null)) {
set ssh-term = "xterm-ghostty"
set ssh-opts = (conj $ssh-opts -o ControlPath=$ssh-cpath)
# Cache successful installation
if (has-external ghostty) {
external ghostty +ssh-cache --add=$ssh-target >/dev/null 2>&1
}
} else {
echo "Warning: Failed to install terminfo." >&2
}
} else {
echo "Warning: Could not generate terminfo data." >&2
}
} else {
echo "Warning: ghostty command not available for cache management." >&2
}
}
}
# Execute SSH with TERM environment variable
external E:TERM=$ssh-term ssh $@ssh-opts $@args
}
}
defer {
mark-prompt-start
report-pwd

View File

@ -86,6 +86,89 @@ function __ghostty_setup --on-event fish_prompt -d "Setup ghostty integration"
end
end
# SSH Integration
set -l features (string split ',' -- "$GHOSTTY_SHELL_FEATURES")
if contains ssh-env $features; or contains ssh-terminfo $features
function ssh --wraps=ssh --description "SSH wrapper with Ghostty integration"
set -l features (string split ',' -- "$GHOSTTY_SHELL_FEATURES")
set -l ssh_term "xterm-256color"
set -l ssh_opts
# Configure environment variables for remote session
if contains ssh-env $features
set -a ssh_opts -o "SetEnv COLORTERM=truecolor"
set -a ssh_opts -o "SendEnv TERM_PROGRAM TERM_PROGRAM_VERSION"
end
# Install terminfo on remote host if needed
if contains ssh-terminfo $features
set -l ssh_user
set -l ssh_hostname
for line in (command ssh -G $argv 2>/dev/null)
set -l parts (string split ' ' -- $line)
if test (count $parts) -ge 2
switch $parts[1]
case user
set ssh_user $parts[2]
case hostname
set ssh_hostname $parts[2]
end
if test -n "$ssh_user"; and test -n "$ssh_hostname"
break
end
end
end
if test -n "$ssh_hostname"
set -l ssh_target "$ssh_user@$ssh_hostname"
# Check if terminfo is already cached
if test -x "$GHOSTTY_BIN_DIR/ghostty"; and "$GHOSTTY_BIN_DIR/ghostty" +ssh-cache --host="$ssh_target" >/dev/null 2>&1
set ssh_term "xterm-ghostty"
else if command -q infocmp
set -l ssh_terminfo
set -l ssh_cpath_dir
set -l ssh_cpath
set ssh_terminfo (infocmp -0 -x xterm-ghostty 2>/dev/null)
if test -n "$ssh_terminfo"
echo "Setting up xterm-ghostty terminfo on $ssh_hostname..." >&2
set ssh_cpath_dir (mktemp -d "/tmp/ghostty-ssh-$ssh_user.XXXXXX" 2>/dev/null; or echo "/tmp/ghostty-ssh-$ssh_user."(random))
set ssh_cpath "$ssh_cpath_dir/socket"
if echo "$ssh_terminfo" | command ssh $ssh_opts -o ControlMaster=yes -o ControlPath="$ssh_cpath" -o ControlPersist=60s $argv '
infocmp xterm-ghostty >/dev/null 2>&1 && exit 0
command -v tic >/dev/null 2>&1 || exit 1
mkdir -p ~/.terminfo 2>/dev/null && tic -x - 2>/dev/null && exit 0
exit 1
' 2>/dev/null
set ssh_term "xterm-ghostty"
set -a ssh_opts -o "ControlPath=$ssh_cpath"
# Cache successful installation
if test -x "$GHOSTTY_BIN_DIR/ghostty"
"$GHOSTTY_BIN_DIR/ghostty" +ssh-cache --add="$ssh_target" >/dev/null 2>&1; or true
end
else
echo "Warning: Failed to install terminfo." >&2
end
else
echo "Warning: Could not generate terminfo data." >&2
end
else
echo "Warning: ghostty command not available for cache management." >&2
end
end
end
# Execute SSH with TERM environment variable
env TERM="$ssh_term" command ssh $ssh_opts $argv
end
end
# Setup prompt marking
function __ghostty_mark_prompt_start --on-event fish_prompt --on-event fish_cancel --on-event fish_posterror
# If we never got the output end event, then we need to send it now.

View File

@ -244,6 +244,79 @@ _ghostty_deferred_init() {
}
fi
# SSH Integration
if [[ "$GHOSTTY_SHELL_FEATURES" == *ssh-* ]]; then
ssh() {
emulate -L zsh
setopt local_options no_glob_subst
local ssh_term ssh_opts
ssh_term="xterm-256color"
ssh_opts=()
# Configure environment variables for remote session
if [[ "$GHOSTTY_SHELL_FEATURES" == *ssh-env* ]]; then
ssh_opts+=(-o "SetEnv COLORTERM=truecolor")
ssh_opts+=(-o "SendEnv TERM_PROGRAM TERM_PROGRAM_VERSION")
fi
# Install terminfo on remote host if needed
if [[ "$GHOSTTY_SHELL_FEATURES" == *ssh-terminfo* ]]; then
local ssh_user ssh_hostname
while IFS=' ' read -r ssh_key ssh_value; do
case "$ssh_key" in
user) ssh_user="$ssh_value" ;;
hostname) ssh_hostname="$ssh_value" ;;
esac
[[ -n "$ssh_user" && -n "$ssh_hostname" ]] && break
done < <(command ssh -G "$@" 2>/dev/null)
if [[ -n "$ssh_hostname" ]]; then
local ssh_target="${ssh_user}@${ssh_hostname}"
# Check if terminfo is already cached
if "$GHOSTTY_BIN_DIR/ghostty" +ssh-cache --host="$ssh_target" >/dev/null 2>&1; then
ssh_term="xterm-ghostty"
elif (( $+commands[infocmp] )); then
local ssh_terminfo ssh_cpath_dir ssh_cpath
ssh_terminfo=$(infocmp -0 -x xterm-ghostty 2>/dev/null)
if [[ -n "$ssh_terminfo" ]]; then
print "Setting up xterm-ghostty terminfo on $ssh_hostname..." >&2
ssh_cpath_dir=$(mktemp -d "/tmp/ghostty-ssh-$ssh_user.XXXXXX" 2>/dev/null) || ssh_cpath_dir="/tmp/ghostty-ssh-$ssh_user.$$"
ssh_cpath="$ssh_cpath_dir/socket"
if print "$ssh_terminfo" | command ssh "${ssh_opts[@]}" -o ControlMaster=yes -o ControlPath="$ssh_cpath" -o ControlPersist=60s "$@" '
infocmp xterm-ghostty >/dev/null 2>&1 && exit 0
command -v tic >/dev/null 2>&1 || exit 1
mkdir -p ~/.terminfo 2>/dev/null && tic -x - 2>/dev/null && exit 0
exit 1
' 2>/dev/null; then
ssh_term="xterm-ghostty"
ssh_opts+=(-o "ControlPath=$ssh_cpath")
# Cache successful installation
"$GHOSTTY_BIN_DIR/ghostty" +ssh-cache --add="$ssh_target" >/dev/null 2>&1 || true
else
print "Warning: Failed to install terminfo." >&2
fi
else
print "Warning: Could not generate terminfo data." >&2
fi
else
print "Warning: ghostty command not available for cache management." >&2
fi
fi
fi
# Execute SSH with TERM environment variable
TERM="$ssh_term" command ssh "${ssh_opts[@]}" "$@"
}
fi
# Some zsh users manually run `source ~/.zshrc` in order to apply rc file
# changes to the current shell. This is a terrible practice that breaks many
# things, including our shell integration. For example, Oh My Zsh and Prezto

View File

@ -154,15 +154,12 @@ pub const Style = struct {
.palette => |idx| palette: {
if (self.flags.bold) {
if (opts.bold) |bold| switch (bold) {
.color => |v| break :palette v.toTerminalRGB(),
.bright => {
const bright_offset = @intFromEnum(color.Name.bright_black);
if (idx < bright_offset) {
break :palette opts.palette[idx + bright_offset];
}
},
};
if (opts.bold) |_| {
const bright_offset = @intFromEnum(color.Name.bright_black);
if (idx < bright_offset) {
break :palette opts.palette[idx + bright_offset];
}
}
}
break :palette opts.palette[idx];

View File

@ -177,10 +177,28 @@ pub fn setupFeatures(
};
var buffer = try std.BoundedArray(u8, capacity).init(0);
inline for (fields) |field| {
if (@field(features, field.name)) {
// Sort the fields so that the output is deterministic. This is
// done at comptime so it has no runtime cost
const fields_sorted: [fields.len][]const u8 = comptime fields: {
var fields_sorted: [fields.len][]const u8 = undefined;
for (fields, 0..) |field, i| fields_sorted[i] = field.name;
std.mem.sortUnstable(
[]const u8,
&fields_sorted,
{},
(struct {
fn lessThan(_: void, lhs: []const u8, rhs: []const u8) bool {
return std.ascii.orderIgnoreCase(lhs, rhs) == .lt;
}
}).lessThan,
);
break :fields fields_sorted;
};
inline for (fields_sorted) |name| {
if (@field(features, name)) {
if (buffer.len > 0) try buffer.append(',');
try buffer.appendSlice(field.name);
try buffer.appendSlice(name);
}
}
@ -201,8 +219,8 @@ test "setup features" {
var env = EnvMap.init(alloc);
defer env.deinit();
try setupFeatures(&env, .{ .cursor = true, .sudo = true, .title = true });
try testing.expectEqualStrings("cursor,sudo,title", env.get("GHOSTTY_SHELL_FEATURES").?);
try setupFeatures(&env, .{ .cursor = true, .sudo = true, .title = true, .@"ssh-env" = true, .@"ssh-terminfo" = true });
try testing.expectEqualStrings("cursor,ssh-env,ssh-terminfo,sudo,title", env.get("GHOSTTY_SHELL_FEATURES").?);
}
// Test: all features disabled
@ -210,7 +228,7 @@ test "setup features" {
var env = EnvMap.init(alloc);
defer env.deinit();
try setupFeatures(&env, .{ .cursor = false, .sudo = false, .title = false });
try setupFeatures(&env, .{ .cursor = false, .sudo = false, .title = false, .@"ssh-env" = false, .@"ssh-terminfo" = false });
try testing.expect(env.get("GHOSTTY_SHELL_FEATURES") == null);
}
@ -219,8 +237,8 @@ test "setup features" {
var env = EnvMap.init(alloc);
defer env.deinit();
try setupFeatures(&env, .{ .cursor = false, .sudo = true, .title = false });
try testing.expectEqualStrings("sudo", env.get("GHOSTTY_SHELL_FEATURES").?);
try setupFeatures(&env, .{ .cursor = false, .sudo = true, .title = false, .@"ssh-env" = true, .@"ssh-terminfo" = false });
try testing.expectEqualStrings("ssh-env,sudo", env.get("GHOSTTY_SHELL_FEATURES").?);
}
}