tempest-rb 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,7 +5,7 @@ module Tempest
5
5
  Command = Data.define(:name, :args)
6
6
 
7
7
  class Dispatcher
8
- KNOWN_COMMANDS = %i[timeline quit help stream open relogin].freeze
8
+ KNOWN_COMMANDS = %i[timeline quit help stream open relogin fav].freeze
9
9
  DOLLAR_ID = /\A\$[A-Z]{2}\z/.freeze
10
10
 
11
11
  def dispatch(input)
@@ -18,6 +18,7 @@ module Tempest
18
18
  :timeline Fetch and print the home timeline
19
19
  :stream on|off Toggle the Jetstream live feed
20
20
  :open $LX Open the URL with id $LX in the browser
21
+ :fav $XX Like the post with id $XX
21
22
  :relogin Re-authenticate when the cached session is dead
22
23
  :help Show this help
23
24
  :quit Exit tempest (or Ctrl-D)
@@ -108,6 +109,8 @@ module Tempest
108
109
  handle_reply(command.args[0], command.args[1])
109
110
  when :open
110
111
  handle_open(command.args.first)
112
+ when :fav
113
+ handle_fav(command.args.first)
111
114
  when :relogin
112
115
  handle_relogin
113
116
  when :unknown
@@ -182,6 +185,29 @@ module Tempest
182
185
  @output.puts "error: #{e.message}"
183
186
  end
184
187
 
188
+ def handle_fav(var)
189
+ if var.nil? || var.empty?
190
+ @output.puts "usage: :fav $XX"
191
+ return
192
+ end
193
+ target = @registry.find_post(var)
194
+ if target.nil?
195
+ @output.puts "unknown id: #{var}"
196
+ return
197
+ end
198
+ response = Post.like(
199
+ @client,
200
+ did: @session.did,
201
+ subject_uri: reply_uri_for(target),
202
+ subject_cid: target.cid,
203
+ )
204
+ @output.puts "liked: #{response["uri"]}"
205
+ rescue Tempest::AuthenticationError => e
206
+ @output.puts "error: #{e.message} (#{RELOGIN_HINT})"
207
+ rescue Tempest::Error => e
208
+ @output.puts "error: #{e.message}"
209
+ end
210
+
185
211
  def handle_open(var)
186
212
  if var.nil? || var.empty?
187
213
  @output.puts "usage: :open $LX"
@@ -20,6 +20,7 @@ module Tempest
20
20
  @cols = cols
21
21
  @enabled = false
22
22
  @mutex = Mutex.new
23
+ @pending_resize = nil
23
24
  end
24
25
 
25
26
  def enable
@@ -33,10 +34,12 @@ module Tempest
33
34
  @io.print "\e[#{rows};1H" # park cursor on the final row (prompt)
34
35
  @io.flush if @io.respond_to?(:flush)
35
36
  @enabled = true
37
+ install_resize_trap
36
38
  end
37
39
 
38
40
  def disable
39
41
  return unless @enabled
42
+ uninstall_resize_trap
40
43
  @io.print "\e_Ga=d,q=2\e\\"
41
44
  @io.print "\e[r"
42
45
  @io.flush if @io.respond_to?(:flush)
@@ -47,8 +50,18 @@ module Tempest
47
50
  @enabled
48
51
  end
49
52
 
53
+ # SIGWINCH hook. Trap handlers in Ruby are restricted (can't reliably
54
+ # acquire mutexes or drive Reline), so we only stash the new dimensions
55
+ # here and apply them on the next mutex-protected write. If rows/cols
56
+ # are omitted (the production path), they're read from IO.console at
57
+ # apply time so coalesced WINCHes still pick up the latest size.
58
+ def notify_resize(rows: nil, cols: nil)
59
+ @pending_resize = { rows: rows, cols: cols }
60
+ end
61
+
50
62
  def puts(*lines)
51
63
  @mutex.synchronize do
64
+ apply_pending_resize
52
65
  if @enabled
53
66
  flat = lines.empty? ? [""] : lines.flat_map { |l| l.to_s.split("\n") }
54
67
  flat.each { |line| insert_above_prompt(line) }
@@ -92,6 +105,50 @@ module Tempest
92
105
 
93
106
  private
94
107
 
108
+ # Caller must hold @mutex. Re-issues DECSTBM and re-parks the cursor on
109
+ # the new prompt row when winsize actually changed; cheap no-op when it
110
+ # didn't (some terminals send spurious WINCHes on focus changes).
111
+ def apply_pending_resize
112
+ pending = @pending_resize
113
+ return unless pending
114
+ @pending_resize = nil
115
+
116
+ new_rows = pending[:rows] || detect_rows
117
+ new_cols = pending[:cols] || detect_cols
118
+ return unless new_rows && new_rows >= 4
119
+ return if new_rows == @rows && new_cols == @cols
120
+
121
+ @rows = new_rows
122
+ @cols = new_cols
123
+ return unless @enabled
124
+
125
+ @io.print "\e[1;#{@rows - 1}r"
126
+ @io.print "\e[#{@rows};1H"
127
+ @io.flush if @io.respond_to?(:flush)
128
+ end
129
+
130
+ # Install a SIGWINCH trap that only flips a flag. Ruby's trap context
131
+ # forbids most blocking work (mutexes, IO that might re-enter Reline),
132
+ # so the actual DECSTBM reissue happens later when puts/print pick up
133
+ # the pending resize. The previous handler is saved so disable can
134
+ # restore it cleanly.
135
+ def install_resize_trap
136
+ return unless Signal.list.key?("WINCH")
137
+ screen = self
138
+ @previous_winch_trap = Signal.trap("WINCH") { screen.notify_resize }
139
+ rescue ArgumentError
140
+ # Some embedded Rubies refuse to trap WINCH; nothing to do.
141
+ @previous_winch_trap = nil
142
+ end
143
+
144
+ def uninstall_resize_trap
145
+ return unless Signal.list.key?("WINCH")
146
+ Signal.trap("WINCH", @previous_winch_trap || "DEFAULT")
147
+ @previous_winch_trap = nil
148
+ rescue ArgumentError
149
+ @previous_winch_trap = nil
150
+ end
151
+
95
152
  def detect_rows
96
153
  return nil unless defined?(IO) && IO.respond_to?(:console)
97
154
  console = IO.console
@@ -1,3 +1,3 @@
1
1
  module Tempest
2
- VERSION = "0.1.1"
2
+ VERSION = "0.1.3"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tempest-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yuya Fujiwara
@@ -94,11 +94,19 @@ files:
94
94
  - lib/tempest.rb
95
95
  - lib/tempest/avatar_store.rb
96
96
  - lib/tempest/cli.rb
97
+ - lib/tempest/commands.rb
98
+ - lib/tempest/commands/base.rb
99
+ - lib/tempest/commands/feed.rb
100
+ - lib/tempest/commands/post.rb
101
+ - lib/tempest/commands/tui.rb
102
+ - lib/tempest/commands/whoami.rb
97
103
  - lib/tempest/config.rb
98
104
  - lib/tempest/cursor_store.rb
105
+ - lib/tempest/date_filter.rb
99
106
  - lib/tempest/debug_log.rb
100
107
  - lib/tempest/facet.rb
101
108
  - lib/tempest/follows.rb
109
+ - lib/tempest/handle_lookup.rb
102
110
  - lib/tempest/handle_resolver.rb
103
111
  - lib/tempest/http.rb
104
112
  - lib/tempest/id_var.rb
@@ -108,7 +116,10 @@ files:
108
116
  - lib/tempest/jetstream/subscription.rb
109
117
  - lib/tempest/jetstream/watchdog.rb
110
118
  - lib/tempest/kitty.rb
119
+ - lib/tempest/output/json_writer.rb
120
+ - lib/tempest/output/line_writer.rb
111
121
  - lib/tempest/post.rb
122
+ - lib/tempest/post_view.rb
112
123
  - lib/tempest/repl/async_output.rb
113
124
  - lib/tempest/repl/dispatcher.rb
114
125
  - lib/tempest/repl/formatter.rb