mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
Merge branch 'ghostty-org:main' into invertCursor
This commit is contained in:
14
.github/workflows/test.yml
vendored
14
.github/workflows/test.yml
vendored
@ -353,15 +353,19 @@ jobs:
|
|||||||
os:
|
os:
|
||||||
[namespace-profile-ghostty-snap, namespace-profile-ghostty-snap-arm64]
|
[namespace-profile-ghostty-snap, namespace-profile-ghostty-snap-arm64]
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
needs: test
|
needs: [test, build-dist]
|
||||||
env:
|
env:
|
||||||
ZIG_LOCAL_CACHE_DIR: /zig/local-cache
|
ZIG_LOCAL_CACHE_DIR: /zig/local-cache
|
||||||
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
|
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- name: Download Source Tarball Artifacts
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
name: source-tarball
|
||||||
fetch-tags: true
|
- name: Extract tarball
|
||||||
|
run: |
|
||||||
|
mkdir dist
|
||||||
|
tar --verbose --extract --strip-components 1 --directory dist --file ghostty-source.tar.gz
|
||||||
- name: Setup Cache
|
- name: Setup Cache
|
||||||
uses: namespacelabs/nscloud-cache-action@v1.2.0
|
uses: namespacelabs/nscloud-cache-action@v1.2.0
|
||||||
with:
|
with:
|
||||||
@ -371,6 +375,8 @@ jobs:
|
|||||||
- run: sudo apt install -y udev
|
- run: sudo apt install -y udev
|
||||||
- run: sudo systemctl start systemd-udevd
|
- run: sudo systemctl start systemd-udevd
|
||||||
- uses: snapcore/action-build@v1
|
- uses: snapcore/action-build@v1
|
||||||
|
with:
|
||||||
|
path: dist
|
||||||
|
|
||||||
build-windows:
|
build-windows:
|
||||||
runs-on: windows-2022
|
runs-on: windows-2022
|
||||||
|
2
.github/workflows/update-colorschemes.yml
vendored
2
.github/workflows/update-colorschemes.yml
vendored
@ -50,6 +50,8 @@ jobs:
|
|||||||
if ! git diff --exit-code build.zig.zon; then
|
if ! git diff --exit-code build.zig.zon; then
|
||||||
nix develop -c ./nix/build-support/check-zig-cache.sh --update
|
nix develop -c ./nix/build-support/check-zig-cache.sh --update
|
||||||
nix develop -c ./nix/build-support/check-zig-cache.sh
|
nix develop -c ./nix/build-support/check-zig-cache.sh
|
||||||
|
nix develop -c ./flatpak/build-support/check-zig-cache.sh --update
|
||||||
|
nix develop -c ./flatpak/build-support/check-zig-cache.sh
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Verify the build still works. We choose an arbitrary build type
|
# Verify the build still works. We choose an arbitrary build type
|
||||||
|
@ -20,8 +20,8 @@
|
|||||||
},
|
},
|
||||||
.z2d = .{
|
.z2d = .{
|
||||||
// vancluever/z2d
|
// vancluever/z2d
|
||||||
.url = "https://github.com/vancluever/z2d/archive/1e89605a624940c310c7a1d81b46a7c5c05919e3.tar.gz",
|
.url = "https://github.com/vancluever/z2d/archive/1bf4bc81819385f4b24596445c9a7cf3b3592b08.tar.gz",
|
||||||
.hash = "z2d-0.6.0-j5P_HvLdCABu-dXpCeRM7Uk4m16vULg1980lMNCQj4_C",
|
.hash = "z2d-0.6.1-j5P_HlerCgBokMgrkl9QhJUKXuZWBGdPnH7cSXwv_ScW",
|
||||||
.lazy = true,
|
.lazy = true,
|
||||||
},
|
},
|
||||||
.zig_objc = .{
|
.zig_objc = .{
|
||||||
@ -103,8 +103,8 @@
|
|||||||
// Other
|
// Other
|
||||||
.apple_sdk = .{ .path = "./pkg/apple-sdk" },
|
.apple_sdk = .{ .path = "./pkg/apple-sdk" },
|
||||||
.iterm2_themes = .{
|
.iterm2_themes = .{
|
||||||
.url = "https://github.com/mbadolato/iTerm2-Color-Schemes/archive/c5e4212e763d652a422c22955cbd13038de1a356.tar.gz",
|
.url = "https://github.com/mbadolato/iTerm2-Color-Schemes/archive/5233095e442645995e8af1fcb7b011478ee86f32.tar.gz",
|
||||||
.hash = "N-V-__8AAIVuNwQhgzy1gME091DLGpUf4kDPd5zVEbxg-NVC",
|
.hash = "N-V-__8AAA38OASk6VOHVXwuyGVAeYu0nghqa1RSIliXV5ym",
|
||||||
.lazy = true,
|
.lazy = true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
12
build.zig.zon.json
generated
12
build.zig.zon.json
generated
@ -54,10 +54,10 @@
|
|||||||
"url": "https://deps.files.ghostty.org/imgui-1220bc6b9daceaf7c8c60f3c3998058045ba0c5c5f48ae255ff97776d9cd8bfc6402.tar.gz",
|
"url": "https://deps.files.ghostty.org/imgui-1220bc6b9daceaf7c8c60f3c3998058045ba0c5c5f48ae255ff97776d9cd8bfc6402.tar.gz",
|
||||||
"hash": "sha256-oF/QHgTPEat4Hig4fGIdLkIPHmBEyOJ6JeYD6pnveGA="
|
"hash": "sha256-oF/QHgTPEat4Hig4fGIdLkIPHmBEyOJ6JeYD6pnveGA="
|
||||||
},
|
},
|
||||||
"N-V-__8AAIVuNwQhgzy1gME091DLGpUf4kDPd5zVEbxg-NVC": {
|
"N-V-__8AAA38OASk6VOHVXwuyGVAeYu0nghqa1RSIliXV5ym": {
|
||||||
"name": "iterm2_themes",
|
"name": "iterm2_themes",
|
||||||
"url": "https://github.com/mbadolato/iTerm2-Color-Schemes/archive/c5e4212e763d652a422c22955cbd13038de1a356.tar.gz",
|
"url": "https://github.com/mbadolato/iTerm2-Color-Schemes/archive/5233095e442645995e8af1fcb7b011478ee86f32.tar.gz",
|
||||||
"hash": "sha256-SVvSI8gp1ANAUwIMp/v+/ZUiOZ4mPy4nQHlxzThI2fs="
|
"hash": "sha256-Vy5muiJ3hJXcOvmFHLhqc+Dvdh74GG6+u/L+EsavDb0="
|
||||||
},
|
},
|
||||||
"N-V-__8AAJrvXQCqAT8Mg9o_tk6m0yf5Fz-gCNEOKLyTSerD": {
|
"N-V-__8AAJrvXQCqAT8Mg9o_tk6m0yf5Fz-gCNEOKLyTSerD": {
|
||||||
"name": "libpng",
|
"name": "libpng",
|
||||||
@ -124,10 +124,10 @@
|
|||||||
"url": "https://deps.files.ghostty.org/wuffs-122037b39d577ec2db3fd7b2130e7b69ef6cc1807d68607a7c232c958315d381b5cd.tar.gz",
|
"url": "https://deps.files.ghostty.org/wuffs-122037b39d577ec2db3fd7b2130e7b69ef6cc1807d68607a7c232c958315d381b5cd.tar.gz",
|
||||||
"hash": "sha256-nkzSCr6W5sTG7enDBXEIhgEm574uLD41UVR2wlC+HBM="
|
"hash": "sha256-nkzSCr6W5sTG7enDBXEIhgEm574uLD41UVR2wlC+HBM="
|
||||||
},
|
},
|
||||||
"z2d-0.6.0-j5P_HvLdCABu-dXpCeRM7Uk4m16vULg1980lMNCQj4_C": {
|
"z2d-0.6.1-j5P_HlerCgBokMgrkl9QhJUKXuZWBGdPnH7cSXwv_ScW": {
|
||||||
"name": "z2d",
|
"name": "z2d",
|
||||||
"url": "https://github.com/vancluever/z2d/archive/1e89605a624940c310c7a1d81b46a7c5c05919e3.tar.gz",
|
"url": "https://github.com/vancluever/z2d/archive/1bf4bc81819385f4b24596445c9a7cf3b3592b08.tar.gz",
|
||||||
"hash": "sha256-PEKVSUZ6teRbDyhFPWSiuBSe40pgr0kVRivIY8Cn8HQ="
|
"hash": "sha256-wiJs6/LUiy+ApC5s7VPypbBukjBr4vjx3v/l9OrT70U="
|
||||||
},
|
},
|
||||||
"zf-0.10.3-OIRy8aiIAACLrBllz0zjxaH0aOe5oNm3KtEMyCntST-9": {
|
"zf-0.10.3-OIRy8aiIAACLrBllz0zjxaH0aOe5oNm3KtEMyCntST-9": {
|
||||||
"name": "zf",
|
"name": "zf",
|
||||||
|
12
build.zig.zon.nix
generated
12
build.zig.zon.nix
generated
@ -170,11 +170,11 @@ in
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
name = "N-V-__8AAIVuNwQhgzy1gME091DLGpUf4kDPd5zVEbxg-NVC";
|
name = "N-V-__8AAA38OASk6VOHVXwuyGVAeYu0nghqa1RSIliXV5ym";
|
||||||
path = fetchZigArtifact {
|
path = fetchZigArtifact {
|
||||||
name = "iterm2_themes";
|
name = "iterm2_themes";
|
||||||
url = "https://github.com/mbadolato/iTerm2-Color-Schemes/archive/c5e4212e763d652a422c22955cbd13038de1a356.tar.gz";
|
url = "https://github.com/mbadolato/iTerm2-Color-Schemes/archive/5233095e442645995e8af1fcb7b011478ee86f32.tar.gz";
|
||||||
hash = "sha256-SVvSI8gp1ANAUwIMp/v+/ZUiOZ4mPy4nQHlxzThI2fs=";
|
hash = "sha256-Vy5muiJ3hJXcOvmFHLhqc+Dvdh74GG6+u/L+EsavDb0=";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
@ -282,11 +282,11 @@ in
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
name = "z2d-0.6.0-j5P_HvLdCABu-dXpCeRM7Uk4m16vULg1980lMNCQj4_C";
|
name = "z2d-0.6.1-j5P_HlerCgBokMgrkl9QhJUKXuZWBGdPnH7cSXwv_ScW";
|
||||||
path = fetchZigArtifact {
|
path = fetchZigArtifact {
|
||||||
name = "z2d";
|
name = "z2d";
|
||||||
url = "https://github.com/vancluever/z2d/archive/1e89605a624940c310c7a1d81b46a7c5c05919e3.tar.gz";
|
url = "https://github.com/vancluever/z2d/archive/1bf4bc81819385f4b24596445c9a7cf3b3592b08.tar.gz";
|
||||||
hash = "sha256-PEKVSUZ6teRbDyhFPWSiuBSe40pgr0kVRivIY8Cn8HQ=";
|
hash = "sha256-wiJs6/LUiy+ApC5s7VPypbBukjBr4vjx3v/l9OrT70U=";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
4
build.zig.zon.txt
generated
4
build.zig.zon.txt
generated
@ -27,8 +27,8 @@ https://deps.files.ghostty.org/ziglyph-b89d43d1e3fb01b6074bc1f7fc980324b04d26a5.
|
|||||||
https://deps.files.ghostty.org/zlib-1220fed0c74e1019b3ee29edae2051788b080cd96e90d56836eea857b0b966742efb.tar.gz
|
https://deps.files.ghostty.org/zlib-1220fed0c74e1019b3ee29edae2051788b080cd96e90d56836eea857b0b966742efb.tar.gz
|
||||||
https://github.com/glfw/glfw/archive/e7ea71be039836da3a98cea55ae5569cb5eb885c.tar.gz
|
https://github.com/glfw/glfw/archive/e7ea71be039836da3a98cea55ae5569cb5eb885c.tar.gz
|
||||||
https://github.com/jcollie/ghostty-gobject/releases/download/0.14.0-2025-03-18-21-1/ghostty-gobject-0.14.0-2025-03-18-21-1.tar.zst
|
https://github.com/jcollie/ghostty-gobject/releases/download/0.14.0-2025-03-18-21-1/ghostty-gobject-0.14.0-2025-03-18-21-1.tar.zst
|
||||||
https://github.com/mbadolato/iTerm2-Color-Schemes/archive/c5e4212e763d652a422c22955cbd13038de1a356.tar.gz
|
https://github.com/mbadolato/iTerm2-Color-Schemes/archive/5233095e442645995e8af1fcb7b011478ee86f32.tar.gz
|
||||||
https://github.com/mitchellh/libxev/archive/3df9337a9e84450a58a2c4af434ec1a036f7b494.tar.gz
|
https://github.com/mitchellh/libxev/archive/3df9337a9e84450a58a2c4af434ec1a036f7b494.tar.gz
|
||||||
https://github.com/mitchellh/zig-objc/archive/3ab0d37c7d6b933d6ded1b3a35b6b60f05590a98.tar.gz
|
https://github.com/mitchellh/zig-objc/archive/3ab0d37c7d6b933d6ded1b3a35b6b60f05590a98.tar.gz
|
||||||
https://github.com/natecraddock/zf/archive/7aacbe6d155d64d15937ca95ca6c014905eb531f.tar.gz
|
https://github.com/natecraddock/zf/archive/7aacbe6d155d64d15937ca95ca6c014905eb531f.tar.gz
|
||||||
https://github.com/vancluever/z2d/archive/1e89605a624940c310c7a1d81b46a7c5c05919e3.tar.gz
|
https://github.com/vancluever/z2d/archive/1bf4bc81819385f4b24596445c9a7cf3b3592b08.tar.gz
|
||||||
|
@ -67,9 +67,9 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "archive",
|
"type": "archive",
|
||||||
"url": "https://github.com/mbadolato/iTerm2-Color-Schemes/archive/c5e4212e763d652a422c22955cbd13038de1a356.tar.gz",
|
"url": "https://github.com/mbadolato/iTerm2-Color-Schemes/archive/5233095e442645995e8af1fcb7b011478ee86f32.tar.gz",
|
||||||
"dest": "vendor/p/N-V-__8AAIVuNwQhgzy1gME091DLGpUf4kDPd5zVEbxg-NVC",
|
"dest": "vendor/p/N-V-__8AAA38OASk6VOHVXwuyGVAeYu0nghqa1RSIliXV5ym",
|
||||||
"sha256": "495bd223c829d4034053020ca7fbfefd9522399e263f2e27407971cd3848d9fb"
|
"sha256": "572e66ba22778495dc3af9851cb86a73e0ef761ef8186ebebbf2fe12c6af0dbd"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "archive",
|
"type": "archive",
|
||||||
@ -151,9 +151,9 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "archive",
|
"type": "archive",
|
||||||
"url": "https://github.com/vancluever/z2d/archive/1e89605a624940c310c7a1d81b46a7c5c05919e3.tar.gz",
|
"url": "https://github.com/vancluever/z2d/archive/1bf4bc81819385f4b24596445c9a7cf3b3592b08.tar.gz",
|
||||||
"dest": "vendor/p/z2d-0.6.0-j5P_HvLdCABu-dXpCeRM7Uk4m16vULg1980lMNCQj4_C",
|
"dest": "vendor/p/z2d-0.6.1-j5P_HlerCgBokMgrkl9QhJUKXuZWBGdPnH7cSXwv_ScW",
|
||||||
"sha256": "3c429549467ab5e45b0f28453d64a2b8149ee34a60af4915462bc863c0a7f074"
|
"sha256": "c2226cebf2d48b2f80a42e6ced53f2a5b06e92306be2f8f1deffe5f4ead3ef45"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "archive",
|
"type": "archive",
|
||||||
|
@ -357,6 +357,11 @@ typedef struct {
|
|||||||
size_t len;
|
size_t len;
|
||||||
} ghostty_config_color_list_s;
|
} ghostty_config_color_list_s;
|
||||||
|
|
||||||
|
// config.Palette
|
||||||
|
typedef struct {
|
||||||
|
ghostty_config_color_s colors[256];
|
||||||
|
} ghostty_config_palette_s;
|
||||||
|
|
||||||
// apprt.Target.Key
|
// apprt.Target.Key
|
||||||
typedef enum {
|
typedef enum {
|
||||||
GHOSTTY_TARGET_APP,
|
GHOSTTY_TARGET_APP,
|
||||||
|
@ -4,7 +4,7 @@ struct CommandOption: Identifiable, Hashable {
|
|||||||
let id = UUID()
|
let id = UUID()
|
||||||
let title: String
|
let title: String
|
||||||
let description: String?
|
let description: String?
|
||||||
let shortcut: String?
|
let symbols: [String]?
|
||||||
let action: () -> Void
|
let action: () -> Void
|
||||||
|
|
||||||
static func == (lhs: CommandOption, rhs: CommandOption) -> Bool {
|
static func == (lhs: CommandOption, rhs: CommandOption) -> Bool {
|
||||||
@ -21,8 +21,8 @@ struct CommandPaletteView: View {
|
|||||||
var backgroundColor: Color = Color(nsColor: .windowBackgroundColor)
|
var backgroundColor: Color = Color(nsColor: .windowBackgroundColor)
|
||||||
var options: [CommandOption]
|
var options: [CommandOption]
|
||||||
@State private var query = ""
|
@State private var query = ""
|
||||||
@State private var selectedIndex: UInt = 0
|
@State private var selectedIndex: UInt?
|
||||||
@State private var hoveredOptionID: UUID? = nil
|
@State private var hoveredOptionID: UUID?
|
||||||
|
|
||||||
// The options that we should show, taking into account any filtering from
|
// The options that we should show, taking into account any filtering from
|
||||||
// the query.
|
// the query.
|
||||||
@ -35,7 +35,8 @@ struct CommandPaletteView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var selectedOption: CommandOption? {
|
var selectedOption: CommandOption? {
|
||||||
if selectedIndex < filteredOptions.count {
|
guard let selectedIndex else { return nil }
|
||||||
|
return if selectedIndex < filteredOptions.count {
|
||||||
filteredOptions[Int(selectedIndex)]
|
filteredOptions[Int(selectedIndex)]
|
||||||
} else {
|
} else {
|
||||||
filteredOptions.last
|
filteredOptions.last
|
||||||
@ -43,6 +44,12 @@ struct CommandPaletteView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
let scheme: ColorScheme = if OSColor(backgroundColor).isLightColor {
|
||||||
|
.light
|
||||||
|
} else {
|
||||||
|
.dark
|
||||||
|
}
|
||||||
|
|
||||||
VStack(alignment: .leading, spacing: 0) {
|
VStack(alignment: .leading, spacing: 0) {
|
||||||
CommandPaletteQuery(query: $query) { event in
|
CommandPaletteQuery(query: $query) { event in
|
||||||
switch (event) {
|
switch (event) {
|
||||||
@ -54,23 +61,40 @@ struct CommandPaletteView: View {
|
|||||||
selectedOption?.action()
|
selectedOption?.action()
|
||||||
|
|
||||||
case .move(.up):
|
case .move(.up):
|
||||||
if selectedIndex > 0 {
|
if filteredOptions.isEmpty { break }
|
||||||
selectedIndex -= 1
|
let current = selectedIndex ?? UInt(filteredOptions.count)
|
||||||
}
|
selectedIndex = (current == 0)
|
||||||
|
? UInt(filteredOptions.count - 1)
|
||||||
|
: current - 1
|
||||||
|
|
||||||
case .move(.down):
|
case .move(.down):
|
||||||
if selectedIndex < filteredOptions.count - 1 {
|
if filteredOptions.isEmpty { break }
|
||||||
selectedIndex += 1
|
let current = selectedIndex ?? UInt.max
|
||||||
}
|
selectedIndex = (current >= UInt(filteredOptions.count - 1))
|
||||||
|
? 0
|
||||||
|
: current + 1
|
||||||
|
|
||||||
case .move(_):
|
case .move(_):
|
||||||
// Unknown, ignore
|
// Unknown, ignore
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.onChange(of: query) { newValue in
|
||||||
|
// If the user types a query then we want to make sure the first
|
||||||
|
// value is selected. If the user clears the query and we were selecting
|
||||||
|
// the first, we unset any selection.
|
||||||
|
if !newValue.isEmpty {
|
||||||
|
if selectedIndex == nil {
|
||||||
|
selectedIndex = 0
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if let selectedIndex, selectedIndex == 0 {
|
||||||
|
self.selectedIndex = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Divider()
|
Divider()
|
||||||
.padding(.bottom, 4)
|
|
||||||
|
|
||||||
CommandTable(
|
CommandTable(
|
||||||
options: filteredOptions,
|
options: filteredOptions,
|
||||||
@ -82,15 +106,23 @@ struct CommandPaletteView: View {
|
|||||||
}
|
}
|
||||||
.frame(maxWidth: 500)
|
.frame(maxWidth: 500)
|
||||||
.background(
|
.background(
|
||||||
RoundedRectangle(cornerRadius: 12)
|
ZStack {
|
||||||
.fill(backgroundColor)
|
Rectangle()
|
||||||
.shadow(color: .black.opacity(0.4), radius: 10, x: 0, y: 10)
|
.fill(.ultraThinMaterial)
|
||||||
.overlay(
|
Rectangle()
|
||||||
RoundedRectangle(cornerRadius: 12)
|
.fill(backgroundColor)
|
||||||
.stroke(Color.black.opacity(0.1), lineWidth: 1)
|
.blendMode(.color)
|
||||||
)
|
}
|
||||||
|
.compositingGroup()
|
||||||
)
|
)
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: 10))
|
||||||
|
.overlay(
|
||||||
|
RoundedRectangle(cornerRadius: 10)
|
||||||
|
.stroke(Color(nsColor: .tertiaryLabelColor).opacity(0.75))
|
||||||
|
)
|
||||||
|
.shadow(radius: 32, x: 0, y: 12)
|
||||||
.padding()
|
.padding()
|
||||||
|
.environment(\.colorScheme, scheme)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,8 +160,9 @@ fileprivate struct CommandPaletteQuery: View {
|
|||||||
|
|
||||||
TextField("Execute a command…", text: $query)
|
TextField("Execute a command…", text: $query)
|
||||||
.padding()
|
.padding()
|
||||||
.font(.system(size: 14))
|
.font(.system(size: 20, weight: .light))
|
||||||
.textFieldStyle(PlainTextFieldStyle())
|
.frame(height: 48)
|
||||||
|
.textFieldStyle(.plain)
|
||||||
.focused($isTextFieldFocused)
|
.focused($isTextFieldFocused)
|
||||||
.onAppear {
|
.onAppear {
|
||||||
isTextFieldFocused = true
|
isTextFieldFocused = true
|
||||||
@ -148,7 +181,7 @@ fileprivate struct CommandPaletteQuery: View {
|
|||||||
|
|
||||||
fileprivate struct CommandTable: View {
|
fileprivate struct CommandTable: View {
|
||||||
var options: [CommandOption]
|
var options: [CommandOption]
|
||||||
@Binding var selectedIndex: UInt
|
@Binding var selectedIndex: UInt?
|
||||||
@Binding var hoveredOptionID: UUID?
|
@Binding var hoveredOptionID: UUID?
|
||||||
var action: (CommandOption) -> Void
|
var action: (CommandOption) -> Void
|
||||||
|
|
||||||
@ -159,29 +192,34 @@ fileprivate struct CommandTable: View {
|
|||||||
.padding()
|
.padding()
|
||||||
} else {
|
} else {
|
||||||
ScrollViewReader { proxy in
|
ScrollViewReader { proxy in
|
||||||
ScrollView(showsIndicators: false) {
|
ScrollView {
|
||||||
VStack(alignment: .leading, spacing: 0) {
|
VStack(alignment: .leading, spacing: 0) {
|
||||||
ForEach(Array(options.enumerated()), id: \.1.id) { index, option in
|
ForEach(Array(options.enumerated()), id: \.1.id) { index, option in
|
||||||
CommandRow(
|
CommandRow(
|
||||||
option: option,
|
option: option,
|
||||||
isSelected: selectedIndex == index ||
|
isSelected: {
|
||||||
(selectedIndex >= options.count &&
|
if let selected = selectedIndex {
|
||||||
index == options.count - 1),
|
return selected == index ||
|
||||||
|
(selected >= options.count &&
|
||||||
|
index == options.count - 1)
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}(),
|
||||||
hoveredID: $hoveredOptionID
|
hoveredID: $hoveredOptionID
|
||||||
) {
|
) {
|
||||||
action(option)
|
action(option)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.padding(10)
|
||||||
}
|
}
|
||||||
.frame(maxHeight: 200)
|
.frame(maxHeight: 200)
|
||||||
.onChange(of: selectedIndex) { _ in
|
.onChange(of: selectedIndex) { _ in
|
||||||
guard selectedIndex < options.count else { return }
|
guard let selectedIndex,
|
||||||
withAnimation {
|
selectedIndex < options.count else { return }
|
||||||
proxy.scrollTo(
|
proxy.scrollTo(
|
||||||
options[Int(selectedIndex)].id,
|
options[Int(selectedIndex)].id)
|
||||||
anchor: .center)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -200,20 +238,12 @@ fileprivate struct CommandRow: View {
|
|||||||
HStack {
|
HStack {
|
||||||
Text(option.title)
|
Text(option.title)
|
||||||
Spacer()
|
Spacer()
|
||||||
if let shortcut = option.shortcut {
|
if let symbols = option.symbols {
|
||||||
Text(shortcut)
|
ShortcutSymbolsView(symbols: symbols)
|
||||||
.font(.system(.body, design: .monospaced))
|
.foregroundStyle(.secondary)
|
||||||
.kerning(1.5)
|
|
||||||
.padding(.horizontal, 6)
|
|
||||||
.padding(.vertical, 2)
|
|
||||||
.background(
|
|
||||||
RoundedRectangle(cornerRadius: 6)
|
|
||||||
.fill(Color.gray.opacity(0.2))
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.horizontal, 6)
|
.padding(8)
|
||||||
.padding(.vertical, 8)
|
|
||||||
.background(
|
.background(
|
||||||
isSelected
|
isSelected
|
||||||
? Color.accentColor.opacity(0.2)
|
? Color.accentColor.opacity(0.2)
|
||||||
@ -221,14 +251,26 @@ fileprivate struct CommandRow: View {
|
|||||||
? Color.secondary.opacity(0.2)
|
? Color.secondary.opacity(0.2)
|
||||||
: Color.clear)
|
: Color.clear)
|
||||||
)
|
)
|
||||||
.cornerRadius(6)
|
.cornerRadius(5)
|
||||||
}
|
}
|
||||||
.help(option.description ?? "")
|
.help(option.description ?? "")
|
||||||
.buttonStyle(PlainButtonStyle())
|
.buttonStyle(.plain)
|
||||||
.onHover { hovering in
|
.onHover { hovering in
|
||||||
hoveredID = hovering ? option.id : nil
|
hoveredID = hovering ? option.id : nil
|
||||||
}
|
}
|
||||||
.padding(.horizontal, 4)
|
}
|
||||||
.padding(.vertical, 1)
|
}
|
||||||
|
|
||||||
|
/// A row of Text representing a shortcut.
|
||||||
|
fileprivate struct ShortcutSymbolsView: View {
|
||||||
|
let symbols: [String]
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
HStack(spacing: 1) {
|
||||||
|
ForEach(symbols, id: \.self) { symbol in
|
||||||
|
Text(symbol)
|
||||||
|
.frame(minWidth: 13)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ struct TerminalCommandPaletteView: View {
|
|||||||
return CommandOption(
|
return CommandOption(
|
||||||
title: String(cString: c.title),
|
title: String(cString: c.title),
|
||||||
description: String(cString: c.description),
|
description: String(cString: c.description),
|
||||||
shortcut: ghosttyConfig.keyboardShortcut(for: action)?.description
|
symbols: ghosttyConfig.keyboardShortcut(for: action)?.keyList
|
||||||
) {
|
) {
|
||||||
onAction(action)
|
onAction(action)
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
extension KeyboardShortcut: @retroactive CustomStringConvertible {
|
extension KeyboardShortcut: @retroactive CustomStringConvertible {
|
||||||
public var description: String {
|
public var keyList: [String] {
|
||||||
var result = ""
|
var result: [String] = []
|
||||||
|
|
||||||
if modifiers.contains(.command) {
|
|
||||||
result.append("⌘")
|
|
||||||
}
|
|
||||||
if modifiers.contains(.control) {
|
if modifiers.contains(.control) {
|
||||||
result.append("⌃")
|
result.append("⌃")
|
||||||
}
|
}
|
||||||
@ -16,6 +13,9 @@ extension KeyboardShortcut: @retroactive CustomStringConvertible {
|
|||||||
if modifiers.contains(.shift) {
|
if modifiers.contains(.shift) {
|
||||||
result.append("⇧")
|
result.append("⇧")
|
||||||
}
|
}
|
||||||
|
if modifiers.contains(.command) {
|
||||||
|
result.append("⌘")
|
||||||
|
}
|
||||||
|
|
||||||
let keyString: String
|
let keyString: String
|
||||||
switch key {
|
switch key {
|
||||||
@ -24,10 +24,14 @@ extension KeyboardShortcut: @retroactive CustomStringConvertible {
|
|||||||
case .delete: keyString = "⌫"
|
case .delete: keyString = "⌫"
|
||||||
case .space: keyString = "␣"
|
case .space: keyString = "␣"
|
||||||
case .tab: keyString = "⇥"
|
case .tab: keyString = "⇥"
|
||||||
case .upArrow: keyString = "↑"
|
case .upArrow: keyString = "▲"
|
||||||
case .downArrow: keyString = "↓"
|
case .downArrow: keyString = "▼"
|
||||||
case .leftArrow: keyString = "←"
|
case .leftArrow: keyString = "◀"
|
||||||
case .rightArrow: keyString = "→"
|
case .rightArrow: keyString = "▶"
|
||||||
|
case .pageUp: keyString = "↑"
|
||||||
|
case .pageDown: keyString = "↓"
|
||||||
|
case .home: keyString = "⤒"
|
||||||
|
case .end: keyString = "⤓"
|
||||||
default:
|
default:
|
||||||
keyString = String(key.character.uppercased())
|
keyString = String(key.character.uppercased())
|
||||||
}
|
}
|
||||||
@ -35,6 +39,10 @@ extension KeyboardShortcut: @retroactive CustomStringConvertible {
|
|||||||
result.append(keyString)
|
result.append(keyString)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public var description: String {
|
||||||
|
return self.keyList.joined()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is available in macOS 14 so this only applies to early macOS versions.
|
// This is available in macOS 14 so this only applies to early macOS versions.
|
||||||
|
@ -70,7 +70,6 @@ parts:
|
|||||||
plugin: nil
|
plugin: nil
|
||||||
build-attributes: [enable-patchelf]
|
build-attributes: [enable-patchelf]
|
||||||
build-packages:
|
build-packages:
|
||||||
- blueprint-compiler
|
|
||||||
- libgtk-4-dev
|
- libgtk-4-dev
|
||||||
- libadwaita-1-dev
|
- libadwaita-1-dev
|
||||||
# TODO: Add when the Snap is updated to Ubuntu 24.10+
|
# TODO: Add when the Snap is updated to Ubuntu 24.10+
|
||||||
@ -80,7 +79,7 @@ parts:
|
|||||||
- patchelf
|
- patchelf
|
||||||
- gettext
|
- gettext
|
||||||
override-build: |
|
override-build: |
|
||||||
craftctl set version=$(git describe --abbrev=8)
|
craftctl set version=$(cat VERSION)
|
||||||
$CRAFT_PART_SRC/../../zig/src/zig build -Dpatch-rpath=\$ORIGIN/../usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR:/snap/core24/current/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR -Doptimize=ReleaseFast
|
$CRAFT_PART_SRC/../../zig/src/zig build -Dpatch-rpath=\$ORIGIN/../usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR:/snap/core24/current/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR -Doptimize=ReleaseFast
|
||||||
cp -rp zig-out/* $CRAFT_PART_INSTALL/
|
cp -rp zig-out/* $CRAFT_PART_INSTALL/
|
||||||
sed -i 's|Icon=com.mitchellh.ghostty|Icon=/snap/ghostty/current/share/icons/hicolor/512x512/apps/com.mitchellh.ghostty.png|g' $CRAFT_PART_INSTALL/share/applications/com.mitchellh.ghostty.desktop
|
sed -i 's|Icon=com.mitchellh.ghostty|Icon=/snap/ghostty/current/share/icons/hicolor/512x512/apps/com.mitchellh.ghostty.png|g' $CRAFT_PART_INSTALL/share/applications/com.mitchellh.ghostty.desktop
|
||||||
|
@ -36,6 +36,17 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyDist {
|
|||||||
"--format=tgz",
|
"--format=tgz",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// embed the Ghostty version in the tarball
|
||||||
|
{
|
||||||
|
const version = b.addWriteFiles().add("VERSION", b.fmt("{}", .{cfg.version}));
|
||||||
|
// --add-file uses the most recent --prefix to determine the path
|
||||||
|
// in the archive to copy the file (the directory only).
|
||||||
|
git_archive.addArg(b.fmt("--prefix=ghostty-{}/", .{
|
||||||
|
cfg.version,
|
||||||
|
}));
|
||||||
|
git_archive.addPrefixedFileArg("--add-file=", version);
|
||||||
|
}
|
||||||
|
|
||||||
// Add all of our resources into the tarball.
|
// Add all of our resources into the tarball.
|
||||||
for (resources.items) |resource| {
|
for (resources.items) |resource| {
|
||||||
// Our dist path basename may not match our generated file basename,
|
// Our dist path basename may not match our generated file basename,
|
||||||
|
@ -3934,6 +3934,24 @@ pub const Palette = struct {
|
|||||||
/// The actual value that is updated as we parse.
|
/// The actual value that is updated as we parse.
|
||||||
value: terminal.color.Palette = terminal.color.default,
|
value: terminal.color.Palette = terminal.color.default,
|
||||||
|
|
||||||
|
/// ghostty_config_palette_s
|
||||||
|
pub const C = extern struct {
|
||||||
|
colors: [265]Color.C,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn cval(self: Self) Palette.C {
|
||||||
|
var result: Palette.C = undefined;
|
||||||
|
for (self.value, 0..) |color, i| {
|
||||||
|
result.colors[i] = Color.C{
|
||||||
|
.r = color.r,
|
||||||
|
.g = color.g,
|
||||||
|
.b = color.b,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parseCLI(
|
pub fn parseCLI(
|
||||||
self: *Self,
|
self: *Self,
|
||||||
input: ?[]const u8,
|
input: ?[]const u8,
|
||||||
|
@ -2239,7 +2239,7 @@ fn draw_branch_node(
|
|||||||
@min(float_width - cx, float_height - cy),
|
@min(float_width - cx, float_height - cy),
|
||||||
);
|
);
|
||||||
|
|
||||||
var ctx = canvas.getContext() catch return;
|
var ctx = canvas.getContext();
|
||||||
defer ctx.deinit();
|
defer ctx.deinit();
|
||||||
ctx.setSource(.{ .opaque_pattern = .{
|
ctx.setSource(.{ .opaque_pattern = .{
|
||||||
.pixel = .{ .alpha8 = .{ .a = @intFromEnum(Shade.on) } },
|
.pixel = .{ .alpha8 = .{ .a = @intFromEnum(Shade.on) } },
|
||||||
@ -2290,7 +2290,7 @@ fn draw_circle(
|
|||||||
};
|
};
|
||||||
const r: f64 = 0.5 * @min(float_width, float_height);
|
const r: f64 = 0.5 * @min(float_width, float_height);
|
||||||
|
|
||||||
var ctx = canvas.getContext() catch return;
|
var ctx = canvas.getContext();
|
||||||
defer ctx.deinit();
|
defer ctx.deinit();
|
||||||
ctx.setSource(.{ .opaque_pattern = .{
|
ctx.setSource(.{ .opaque_pattern = .{
|
||||||
.pixel = .{ .alpha8 = .{ .a = @intFromEnum(Shade.on) } },
|
.pixel = .{ .alpha8 = .{ .a = @intFromEnum(Shade.on) } },
|
||||||
@ -2680,7 +2680,7 @@ fn draw_arc(
|
|||||||
// Fraction away from the center to place the middle control points,
|
// Fraction away from the center to place the middle control points,
|
||||||
const s: f64 = 0.25;
|
const s: f64 = 0.25;
|
||||||
|
|
||||||
var ctx = try canvas.getContext();
|
var ctx = canvas.getContext();
|
||||||
defer ctx.deinit();
|
defer ctx.deinit();
|
||||||
ctx.setSource(.{ .opaque_pattern = .{
|
ctx.setSource(.{ .opaque_pattern = .{
|
||||||
.pixel = .{ .alpha8 = .{ .a = @intFromEnum(Shade.on) } },
|
.pixel = .{ .alpha8 = .{ .a = @intFromEnum(Shade.on) } },
|
||||||
@ -2974,7 +2974,7 @@ fn draw_separated_block_quadrant(self: Box, canvas: *font.sprite.Canvas, comptim
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var ctx = try canvas.getContext();
|
var ctx = canvas.getContext();
|
||||||
defer ctx.deinit();
|
defer ctx.deinit();
|
||||||
ctx.setSource(.{ .opaque_pattern = .{
|
ctx.setSource(.{ .opaque_pattern = .{
|
||||||
.pixel = .{ .alpha8 = .{ .a = @intFromEnum(Shade.on) } },
|
.pixel = .{ .alpha8 = .{ .a = @intFromEnum(Shade.on) } },
|
||||||
|
@ -149,8 +149,8 @@ pub const Canvas = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Acquires a z2d drawing context, caller MUST deinit context.
|
/// Acquires a z2d drawing context, caller MUST deinit context.
|
||||||
pub fn getContext(self: *Canvas) Allocator.Error!z2d.Context {
|
pub fn getContext(self: *Canvas) z2d.Context {
|
||||||
return try z2d.Context.init(self.alloc, &self.sfc);
|
return z2d.Context.init(self.alloc, &self.sfc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draw and fill a single pixel
|
/// Draw and fill a single pixel
|
||||||
|
Reference in New Issue
Block a user