Skip to content

Commit f7ab9bb

Browse files
committed
Add Ghostty terminal hyperlink support
1 parent 28ae207 commit f7ab9bb

File tree

5 files changed

+138
-0
lines changed

5 files changed

+138
-0
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Change log
22

3+
## Unreleased
4+
5+
### Added
6+
7+
* Add hyperlink support detection in Ghostty terminal
8+
by Akshay Birajdar (@the-spectator).
9+
310
## [v0.2.0] - 2024-11-03
411

512
### Added

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,7 @@ The **TTY::Link** supports hyperlink generation in the following terminals:
279279
* `Contour`
280280
* `DomTerm`
281281
* `foot`
282+
* `Ghostty`
282283
* `Hyper`
283284
* `iTerm2`
284285
* `JediTerm`

lib/tty/link/terminals/ghostty.rb

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# frozen_string_literal: true
2+
3+
require_relative "abstract"
4+
5+
module TTY
6+
class Link
7+
module Terminals
8+
# Responsible for detecting hyperlink support in the Ghostty terminal
9+
#
10+
# @api private
11+
class Ghostty < Abstract
12+
# The Ghostty terminal name pattern
13+
#
14+
# @return [Regexp]
15+
#
16+
# @api private
17+
GHOSTTY = /ghostty/i.freeze
18+
private_constant :GHOSTTY
19+
20+
private
21+
22+
# Detect Ghostty terminal
23+
#
24+
# @example
25+
# ghostty.name?
26+
# # => true
27+
#
28+
# @return [Boolean]
29+
#
30+
# @api private
31+
def name?
32+
!(term_program =~ GHOSTTY).nil?
33+
end
34+
35+
# Detect any Ghostty terminal version to support terminal hyperlinks
36+
#
37+
# @example
38+
# ghostty.version?
39+
# # => true
40+
#
41+
# @return [Boolean]
42+
#
43+
# @api private
44+
def version?
45+
return false unless term_program_version
46+
47+
current_semantic_version = semantic_version(term_program_version)
48+
49+
current_semantic_version >= semantic_version(1, 0, 0)
50+
end
51+
end # Ghostty
52+
end # Terminals
53+
end # Link
54+
end # TTY

spec/unit/link_spec.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,15 @@
8484
end
8585
end
8686

87+
context "when Ghostty" do
88+
it "supports links above the 1.0.0 version" do
89+
env = {"TERM_PROGRAM" => "ghostty", "TERM_PROGRAM_VERSION" => "1.0.1"}
90+
link = described_class.new(env: env, output: output)
91+
92+
expect(link.link?).to eq(true)
93+
end
94+
end
95+
8796
context "when Hyper" do
8897
it "supports links above the 2.0.0 version" do
8998
env = {
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# frozen_string_literal: true
2+
3+
RSpec.describe TTY::Link::Terminals::Ghostty, "#link?" do
4+
let(:env_with_name) { {"TERM_PROGRAM" => "ghostty"} }
5+
let(:semantic_version) { TTY::Link::SemanticVersion }
6+
7+
it "doesn't support links without the term program environment variable" do
8+
ghostty = described_class.new(semantic_version, {})
9+
10+
expect(ghostty.link?).to eq(false)
11+
end
12+
13+
it "doesn't support links without a terminal program name" do
14+
env = {"TERM_PROGRAM" => nil}
15+
ghostty = described_class.new(semantic_version, env)
16+
17+
expect(ghostty.link?).to eq(false)
18+
end
19+
20+
it "doesn't support links with a non-Ghostty program name" do
21+
env = {"TERM_PROGRAM" => "other-terminal", "TERM_PROGRAM_VERSION" => "1.0.0"}
22+
ghostty = described_class.new(semantic_version, env)
23+
24+
expect(ghostty.link?).to eq(false)
25+
end
26+
27+
it "supports links with the Ghostty program name" do
28+
env = env_with_name.merge({"TERM_PROGRAM_VERSION" => "1.0.0"})
29+
ghostty = described_class.new(semantic_version, env)
30+
31+
expect(ghostty.link?).to eq(true)
32+
end
33+
34+
it "supports links with the Ghostty program name in mixed case" do
35+
env = {"TERM_PROGRAM" => "GhosTTY", "TERM_PROGRAM_VERSION" => "1.0.0"}
36+
ghostty = described_class.new(semantic_version, env)
37+
38+
expect(ghostty.link?).to eq(true)
39+
end
40+
41+
it "doesn't supports links without the term program version env variable" do
42+
ghostty = described_class.new(semantic_version, env_with_name)
43+
44+
expect(ghostty.link?).to eq(false)
45+
end
46+
47+
it "doesn't supports links without a version" do
48+
env = env_with_name.merge({"TERM_PROGRAM_VERSION" => nil})
49+
ghostty = described_class.new(semantic_version, env)
50+
51+
expect(ghostty.link?).to eq(false)
52+
end
53+
54+
it "doesn't supports links below version 1.0.0" do
55+
env = env_with_name.merge({"TERM_PROGRAM_VERSION" => "0.9.0"})
56+
ghostty = described_class.new(semantic_version, env)
57+
58+
expect(ghostty.link?).to eq(false)
59+
end
60+
61+
it "supports links above the 1.0.0 version" do
62+
env = env_with_name.merge({"TERM_PROGRAM_VERSION" => "1.1.0"})
63+
ghostty = described_class.new(semantic_version, env)
64+
65+
expect(ghostty.link?).to eq(true)
66+
end
67+
end

0 commit comments

Comments
 (0)