tty-link 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +29 -0
  3. data/LICENSE.txt +1 -1
  4. data/README.md +278 -27
  5. data/lib/tty/link/ansi_link.rb +105 -0
  6. data/lib/tty/link/errors.rb +77 -0
  7. data/lib/tty/link/hyperlink_parameter.rb +95 -0
  8. data/lib/tty/link/plain_link.rb +52 -0
  9. data/lib/tty/link/semantic_version.rb +204 -0
  10. data/lib/tty/link/terminals/abstract.rb +189 -0
  11. data/lib/tty/link/terminals/alacritty.rb +50 -0
  12. data/lib/tty/link/terminals/contour.rb +96 -0
  13. data/lib/tty/link/terminals/domterm.rb +107 -0
  14. data/lib/tty/link/terminals/foot.rb +50 -0
  15. data/lib/tty/link/terminals/hyper.rb +54 -0
  16. data/lib/tty/link/terminals/iterm.rb +54 -0
  17. data/lib/tty/link/terminals/jediterm.rb +71 -0
  18. data/lib/tty/link/terminals/kitty.rb +48 -0
  19. data/lib/tty/link/terminals/konsole.rb +65 -0
  20. data/lib/tty/link/terminals/mintty.rb +54 -0
  21. data/lib/tty/link/terminals/rio.rb +54 -0
  22. data/lib/tty/link/terminals/tabby.rb +50 -0
  23. data/lib/tty/link/terminals/terminology.rb +54 -0
  24. data/lib/tty/link/terminals/vscode.rb +54 -0
  25. data/lib/tty/link/terminals/vte.rb +65 -0
  26. data/lib/tty/link/terminals/wezterm.rb +71 -0
  27. data/lib/tty/link/terminals/wt.rb +63 -0
  28. data/lib/tty/link/terminals.rb +71 -0
  29. data/lib/tty/link/version.rb +2 -2
  30. data/lib/tty/link.rb +279 -40
  31. data/lib/tty-link.rb +2 -0
  32. metadata +44 -44
  33. data/.gitignore +0 -12
  34. data/.rspec +0 -3
  35. data/.travis.yml +0 -23
  36. data/CODE_OF_CONDUCT.md +0 -74
  37. data/Gemfile +0 -12
  38. data/ISSUE_TEMPLATE.md +0 -23
  39. data/PULL_REQUEST_TEMPLATE.md +0 -18
  40. data/Rakefile +0 -8
  41. data/appveyor.yml +0 -28
  42. data/bin/console +0 -14
  43. data/bin/setup +0 -8
  44. data/tasks/console.rake +0 -11
  45. data/tasks/coverage.rake +0 -11
  46. data/tasks/spec.rake +0 -29
  47. data/tty-link.gemspec +0 -36
@@ -0,0 +1,71 @@
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 WezTerm terminal
9
+ #
10
+ # @api private
11
+ class Wezterm < Abstract
12
+ # The WezTerm terminal name pattern
13
+ #
14
+ # @return [Regexp]
15
+ #
16
+ # @api private
17
+ WEZTERM = /WezTerm/i.freeze
18
+ private_constant :WEZTERM
19
+
20
+ # The version release
21
+ #
22
+ # @return [String]
23
+ #
24
+ # @api private
25
+ VERSION_RELEASE = "20180218"
26
+ private_constant :VERSION_RELEASE
27
+
28
+ # The version separator
29
+ #
30
+ # @return [String]
31
+ #
32
+ # @api private
33
+ VERSION_SEPARATOR = "-"
34
+ private_constant :VERSION_SEPARATOR
35
+
36
+ private
37
+
38
+ # Detect WezTerm terminal
39
+ #
40
+ # @example
41
+ # wezterm.name?
42
+ # # => true
43
+ #
44
+ # @return [Boolean]
45
+ #
46
+ # @api private
47
+ def name?
48
+ !(term_program =~ WEZTERM).nil?
49
+ end
50
+
51
+ # Detect whether the WezTerm version supports terminal hyperlinks
52
+ #
53
+ # @example
54
+ # wezterm.version?
55
+ # # => true
56
+ #
57
+ # @return [Boolean]
58
+ #
59
+ # @api private
60
+ def version?
61
+ return false unless term_program_version
62
+
63
+ current_semantic_version =
64
+ semantic_version(term_program_version, separator: VERSION_SEPARATOR)
65
+
66
+ current_semantic_version >= semantic_version(VERSION_RELEASE, 0, 0)
67
+ end
68
+ end # Wezterm
69
+ end # Terminals
70
+ end # Link
71
+ end # TTY
@@ -0,0 +1,63 @@
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 Windows Terminal
9
+ #
10
+ # @api private
11
+ class Wt < Abstract
12
+ # The wt session environment variable name
13
+ #
14
+ # @return [String]
15
+ #
16
+ # @api private
17
+ WT_SESSION = "WT_SESSION"
18
+ private_constant :WT_SESSION
19
+
20
+ private
21
+
22
+ # Detect Windows Terminal
23
+ #
24
+ # @example
25
+ # wt.name?
26
+ # # => true
27
+ #
28
+ # @return [Boolean]
29
+ #
30
+ # @api private
31
+ def name?
32
+ !wt_session.nil?
33
+ end
34
+
35
+ # Detect any Windows Terminal version to support terminal hyperlinks
36
+ #
37
+ # @example
38
+ # wt.version?
39
+ # # => true
40
+ #
41
+ # @return [Boolean]
42
+ #
43
+ # @api private
44
+ def version?
45
+ true
46
+ end
47
+
48
+ # Read the wt session environment variable
49
+ #
50
+ # @example
51
+ # wt.wt_session
52
+ # # => "the-unique-identifier"
53
+ #
54
+ # @return [String, nil]
55
+ #
56
+ # @api private
57
+ def wt_session
58
+ env[WT_SESSION]
59
+ end
60
+ end # Wt
61
+ end # Terminals
62
+ end # Link
63
+ end # TTY
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TTY
4
+ class Link
5
+ # Responsible for loading terminals
6
+ #
7
+ # @api private
8
+ module Terminals
9
+ # The directory name for terminals
10
+ #
11
+ # @return [String]
12
+ #
13
+ # @api private
14
+ DIR_NAME = "terminals"
15
+ private_constant :DIR_NAME
16
+
17
+ # The Ruby file pattern
18
+ #
19
+ # @return [String]
20
+ #
21
+ # @api private
22
+ RUBY_FILE = "*.rb"
23
+ private_constant :RUBY_FILE
24
+
25
+ # The registered terminal classes
26
+ #
27
+ # @example
28
+ # TTY::Link::Terminals.registered
29
+ #
30
+ # @return [Array<TTY::Link::Terminals::Abstract>]
31
+ #
32
+ # @api private
33
+ def self.registered
34
+ @registered ||= []
35
+ end
36
+
37
+ # Register a terminal class
38
+ #
39
+ # @example
40
+ # TTY::Link::Terminals.register(TTY::Link::Terminals::Iterm)
41
+ #
42
+ # @param [TTY::Link::Terminals::Abstract] terminal_class
43
+ # the terminal class to register
44
+ #
45
+ # @return [void]
46
+ #
47
+ # @api private
48
+ def self.register(terminal_class)
49
+ registered << terminal_class
50
+ end
51
+
52
+ # Require all terminal files from the terminals directory
53
+ #
54
+ # @example
55
+ # TTY::Link::Terminals.require_terminals
56
+ #
57
+ # @return [void]
58
+ #
59
+ # @api private
60
+ def self.require_terminals
61
+ terminals_dir = ::File.join(__dir__, DIR_NAME, RUBY_FILE)
62
+ ::Dir.glob(terminals_dir).sort.each do |terminal_path|
63
+ require_relative ::File.join(DIR_NAME, ::File.basename(terminal_path))
64
+ end
65
+ end
66
+ private_class_method :require_terminals
67
+
68
+ require_terminals
69
+ end
70
+ end # Link
71
+ end # TTY
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TTY
4
- module Link
5
- VERSION = "0.1.0"
4
+ class Link
5
+ VERSION = "0.2.0"
6
6
  end # Link
7
7
  end # TTY
data/lib/tty/link.rb CHANGED
@@ -1,74 +1,313 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "link/ansi_link"
4
+ require_relative "link/errors"
5
+ require_relative "link/hyperlink_parameter"
6
+ require_relative "link/plain_link"
7
+ require_relative "link/semantic_version"
8
+ require_relative "link/terminals"
3
9
  require_relative "link/version"
4
10
 
5
11
  module TTY
6
- module Link
7
- class Error < StandardError; end
12
+ # Responsible for detecting and generating terminal hyperlinks
13
+ #
14
+ # @api public
15
+ class Link
16
+ # The default plain URL template
17
+ #
18
+ # @return [String]
19
+ #
20
+ # @api private
21
+ DEFAULT_TEMPLATE = ":name -> :url"
22
+ private_constant :DEFAULT_TEMPLATE
8
23
 
9
- ESC = "\u001B["
10
- OSC = "\u001B]"
11
- BEL = "\u0007"
12
- SEP = ";"
24
+ # The hyperlink environment variable name
25
+ #
26
+ # @return [String]
27
+ #
28
+ # @api private
29
+ HYPERLINK_ENV = "TTY_LINK_HYPERLINK"
30
+ private_constant :HYPERLINK_ENV
13
31
 
14
- ITERM = /iTerm(\s*\d+){0,1}.app/x.freeze
32
+ # Generate terminal hyperlink
33
+ #
34
+ # @example
35
+ # TTY::Link.link_to("TTY Toolkit", "https://ttytoolkit.org")
36
+ #
37
+ # @example
38
+ # TTY::Link.link_to("https://ttytoolkit.org")
39
+ #
40
+ # @example
41
+ # TTY::Link.link_to("TTY Toolkit", "https://ttytoolkit.org",
42
+ # attrs: {id: "tty-toolkit"})
43
+ #
44
+ # @example
45
+ # TTY::Link.link_to("TTY Toolkit", "https://ttytoolkit.org",
46
+ # env: {"VTE_VERSION" => "7603"})
47
+ #
48
+ # @example
49
+ # TTY::Link.link_to("TTY Toolkit", "https://ttytoolkit.org",
50
+ # hyperlink: :always)
51
+ #
52
+ # @example
53
+ # TTY::Link.link_to("TTY Toolkit", "https://ttytoolkit.org",
54
+ # output: $stderr)
55
+ #
56
+ # @example
57
+ # TTY::Link.link_to("TTY Toolkit", "https://ttytoolkit.org",
58
+ # plain: ":name (:url)")
59
+ #
60
+ # @param [String] name
61
+ # the name for the URL
62
+ # @param [String, nil] url
63
+ # the URL target
64
+ # @param [Hash{Symbol => String}] attrs
65
+ # the URL attributes
66
+ # @param [ENV, Hash{String => String}] env
67
+ # the environment variables
68
+ # @param [String, Symbol] hyperlink
69
+ # the hyperlink detection out of always, auto or never
70
+ # @param [IO] output
71
+ # the output stream, defaults to $stdout
72
+ # @param [String] plain
73
+ # the plain URL template
74
+ #
75
+ # @return [String]
76
+ #
77
+ # @see #link_to
78
+ #
79
+ # @api public
80
+ def self.link_to(name, url = nil, attrs: {}, env: ENV, hyperlink: :auto,
81
+ output: $stdout, plain: DEFAULT_TEMPLATE)
82
+ new(env: env, hyperlink: hyperlink, output: output, plain: plain)
83
+ .link_to(name, url, attrs: attrs)
84
+ end
15
85
 
16
- # Parse version number
86
+ # Detect terminal hyperlink support
17
87
  #
18
- # @param [String] version
88
+ # @example
89
+ # TTY::Link.link?
90
+ # # => true
19
91
  #
20
- # @api private
21
- def parse_version(version)
22
- if (matches = version.match(/^(\d{1,2})(\d{2})$/))
23
- major, minor, patch = 0, matches[1].to_i, matches[2].to_i
92
+ # @example
93
+ # TTY::Link.link?(env: {"VTE_VERSION" => "7603"})
94
+ # # => true
95
+ #
96
+ # @example
97
+ # TTY::Link.link?(output: $stderr)
98
+ # # => false
99
+ #
100
+ # @param [ENV, Hash{String => String}] env
101
+ # the environment variables
102
+ # @param [IO] output
103
+ # the output stream, defaults to $stdout
104
+ #
105
+ # @return [Boolean]
106
+ #
107
+ # @see #link?
108
+ #
109
+ # @api public
110
+ def self.link?(env: ENV, output: $stdout)
111
+ new(env: env, output: output).link?
112
+ end
113
+
114
+ # Create a {TTY::Link} instance
115
+ #
116
+ # @example
117
+ # link = TTY::Link.new
118
+ #
119
+ # @example
120
+ # link = TTY::Link.new(env: {"VTE_VERSION" => "7603"})
121
+ #
122
+ # @example
123
+ # link = TTY::Link.new(hyperlink: :always)
124
+ #
125
+ # @example
126
+ # link = TTY::Link.new(output: $stderr)
127
+ #
128
+ # @example
129
+ # link = TTY::Link.new(plain: ":name (:url)")
130
+ #
131
+ # @param [ENV, Hash{String => String}] env
132
+ # the environment variables
133
+ # @param [String, Symbol] hyperlink
134
+ # the hyperlink detection out of always, auto or never
135
+ # @param [IO] output
136
+ # the output stream, defaults to $stdout
137
+ # @param [String] plain
138
+ # the plain URL template
139
+ #
140
+ # @api public
141
+ def initialize(env: ENV, hyperlink: :auto, output: $stdout,
142
+ plain: DEFAULT_TEMPLATE)
143
+ @env = env
144
+ @hyperlink_parameter = hyperlink_parameter(hyperlink_env || hyperlink)
145
+ @output = output
146
+ @plain = plain
147
+ end
148
+
149
+ # Generate terminal hyperlink
150
+ #
151
+ # @example
152
+ # link.link_to("TTY Toolkit", "https://ttytoolkit.org")
153
+ #
154
+ # @example
155
+ # link.link_to("https://ttytoolkit.org")
156
+ #
157
+ # @example
158
+ # link.link_to("TTY Toolkit", "https://ttytoolkit.org",
159
+ # attrs: {id: "tty-toolkit"})
160
+ #
161
+ # @example
162
+ # link.link_to("https://ttytoolkit.org",
163
+ # attrs: {id: "tty-toolkit", title: "TTY Toolkit"})
164
+ #
165
+ # @param [String] name
166
+ # the name for the URL
167
+ # @param [String, nil] url
168
+ # the URL target
169
+ # @param [Hash{Symbol => String}] attrs
170
+ # the URL attributes
171
+ #
172
+ # @return [String]
173
+ #
174
+ # @api public
175
+ def link_to(name, url = nil, attrs: {})
176
+ url ||= name
177
+
178
+ if ansi_link?
179
+ ansi_link(name, url, attrs).to_s
24
180
  else
25
- major, minor, patch = version.split(".").map(&:to_i)
181
+ plain_link(name, url).to_s
26
182
  end
27
- { major: major, minor: minor, patch: patch }
28
183
  end
29
- module_function :parse_version
30
184
 
31
- # Check if link is supported
185
+ # Detect terminal hyperlink support
186
+ #
187
+ # @example
188
+ # link.link?
189
+ # # => true
32
190
  #
33
191
  # @return [Boolean]
34
192
  #
35
193
  # @api public
36
- def support_link?(output: $stdout)
37
- return false unless output.tty?
194
+ def link?
195
+ return false unless tty?
38
196
 
39
- if ENV["TERM_PROGRAM"] =~ ITERM
40
- version = parse_version(ENV["TERM_PROGRAM_VERSION"])
197
+ terminals.any?(&:link?)
198
+ end
41
199
 
42
- return version[:major] > 3 || version[:major] == 3 && version[:minor] > 0
43
- end
200
+ private
44
201
 
45
- # uses VTE terminal
46
- if ENV["VTE_VERSION"]
47
- version = parse_version(ENV["VTE_VERSION"])
202
+ # Whether to create an {TTY::Link::ANSILink} or a {TTY::Link::PlainLink}
203
+ #
204
+ # @example
205
+ # link.ansi_link?
206
+ # # => true
207
+ #
208
+ # @return [Boolean]
209
+ #
210
+ # @api private
211
+ def ansi_link?
212
+ @hyperlink_parameter.always? || (@hyperlink_parameter.auto? && link?)
213
+ end
48
214
 
49
- return version[:major] > 0 || version[:minor] > 50 ||
50
- version[:minor] == 50 && version[:patch] > 0
51
- end
215
+ # Create an {TTY::Link::ANSILink} instance
216
+ #
217
+ # @example
218
+ # ansi_link("TTY Toolkit", "https://ttytoolkit.org", {id: "tty-tookit"})
219
+ #
220
+ # @param [String] name
221
+ # the URL name
222
+ # @param [String] url
223
+ # the URL target
224
+ # @param [Hash{Symbol => String}] attrs
225
+ # the URL attributes
226
+ #
227
+ # @return [TTY::Link::ANSILink]
228
+ #
229
+ # @see ANSILink#new
230
+ #
231
+ # @api private
232
+ def ansi_link(name, url, attrs)
233
+ ANSILink.new(name, url, attrs)
234
+ end
235
+
236
+ # Read the hyperlink environment variable
237
+ #
238
+ # @example
239
+ # link.hyperlink_env
240
+ # # => "always"
241
+ #
242
+ # @return [String, nil]
243
+ #
244
+ # @api private
245
+ def hyperlink_env
246
+ @env[HYPERLINK_ENV]
247
+ end
52
248
 
53
- return false
249
+ # Create a {TTY::Link::HyperlinkParameter} instance
250
+ #
251
+ # @example
252
+ # link.hyperlink_parameter(:always)
253
+ #
254
+ # @param [String, Symbol] hyperlink
255
+ # the hyperlink detection out of always, auto or never
256
+ #
257
+ # @return [TTY::Link::HyperlinkParameter]
258
+ #
259
+ # @raise [TTY::Link::ValueError]
260
+ # the value isn't always, auto or never
261
+ #
262
+ # @api private
263
+ def hyperlink_parameter(hyperlink)
264
+ HyperlinkParameter.new(hyperlink)
54
265
  end
55
- module_function :support_link?
56
266
 
57
- # Render terminal link
267
+ # Create a {TTY::Link::PlainLink} instance
268
+ #
269
+ # @example
270
+ # plain_link("TTY Toolkit", "https://ttytoolkit.org")
58
271
  #
59
272
  # @param [String] name
273
+ # the URL name
60
274
  # @param [String] url
275
+ # the URL target
61
276
  #
62
- # @return [String]
277
+ # @return [TTY::Link::PlainLink]
63
278
  #
64
- # @api public
65
- def link_to(name, url)
66
- if support_link?
67
- [ OSC, "8", SEP, SEP, url, BEL, name, OSC, "8", SEP, SEP, BEL ].join("")
68
- else
69
- "#{name} -> #{url}"
279
+ # @see PlainLink#new
280
+ #
281
+ # @api private
282
+ def plain_link(name, url)
283
+ PlainLink.new(name, url, @plain)
284
+ end
285
+
286
+ # Terminals for detecting hyperlink support
287
+ #
288
+ # @example
289
+ # link.terminals
290
+ #
291
+ # @return [Array<TTY::Link::Terminals::Abstract>]
292
+ #
293
+ # @api private
294
+ def terminals
295
+ @terminals ||= Terminals.registered.map do |terminal_class|
296
+ terminal_class.new(SemanticVersion, @env)
70
297
  end
71
298
  end
72
- module_function :link_to
299
+
300
+ # Detect the terminal device
301
+ #
302
+ # @example
303
+ # link.tty?
304
+ # # => true
305
+ #
306
+ # @return [Boolean]
307
+ #
308
+ # @api private
309
+ def tty?
310
+ @output.tty?
311
+ end
73
312
  end # Link
74
313
  end # TTY
data/lib/tty-link.rb CHANGED
@@ -1 +1,3 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative "tty/link"