claude-inbox 0.14.3 → 0.14.4

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 20f415de1f5b57baa5330a96c70bb10545c1b1885e419f4174e9a938c0d3c59f
4
- data.tar.gz: 1a989c77cbb0553c63ace2b341c95a988eb1028e103c09c173bc28d14023cd14
3
+ metadata.gz: ed40b9c11c703427940ad961d9f114e815c8af02090d8dd2b614971a1a578f4b
4
+ data.tar.gz: 21e8cbb5fac27662d14cf77dd40673c36b9f254618fcb029cef73b8cbee56dfb
5
5
  SHA512:
6
- metadata.gz: 251df40e737ea85313ceefc9d8dc401f61fed6af73f9d26b0b2767737c66dec57e1fd02fbc46bd057384b17475b3e76dd2de669d77c4ab534df3a2bfe1e6b67c
7
- data.tar.gz: c3368aa2027a9947e09e2d29a642d6ad4884a1c77392298db820b73b69a06c5970f9a30a916224f8786664d5588b307189edcbe960d9634ea1d93d4cff06ac6d
6
+ metadata.gz: 5a464b6c6d6e97943dc66e66e2f3b6ed42eb4e839e878a54afb8fca8e8b5d46a51176180dd3231e178f92ce1b63cca49c755a1e36731b6740acb1d370143cb7f
7
+ data.tar.gz: 4e959e5f8b45042c7d19b40616865fa62830fca5b788313392eae6e006cbcf780e3549f253c6086913eecbd344f4d8e9e6480f13c75ae25efe6b34825d98468d
@@ -13,6 +13,9 @@ module ClaudeInbox
13
13
  # is taken as Option held with it.
14
14
  ALT = /\A\e([a-z])\z/
15
15
 
16
+ # A nonblocking read can end partway through a mouse report.
17
+ UNFINISHED_REPORT = /\e\[<[\d;]*\z/
18
+
16
19
  def self.alt?(name) = name.to_s.start_with?("alt_")
17
20
 
18
21
  # An Option chord as the quick Esc-then-letter it may also have been.
@@ -22,6 +25,7 @@ module ClaudeInbox
22
25
  @input = input
23
26
  @reader = TTY::Reader.new(input: input, output: out, interrupt: :noop)
24
27
  @paste = Paste.new
28
+ @held = +""
25
29
  end
26
30
 
27
31
  def pasting? = @paste.pasting?
@@ -33,13 +37,17 @@ module ClaudeInbox
33
37
 
34
38
  # `[:paste, text]`, `[:mouse, event]` and `[:key, name, raw]`, in the
35
39
  # order they arrived; `name` is the reader's symbol for a key it knows,
36
- # else the raw string.
40
+ # else the raw string. The head of a report cut off at the end of a read
41
+ # waits for the rest instead of being typed.
37
42
  def events(raw)
38
43
  @paste.feed(raw).flat_map do |kind, text|
39
44
  next [[:paste, text]] if kind == :paste
40
- mouse = Mouse.events(text)
41
- next mouse.map { |e| [:mouse, e] } if mouse.any?
42
- split_keys(text).map { |k| [:key, key_name(k), k] }
45
+ text = @held + text
46
+ @held = text[UNFINISHED_REPORT] || +""
47
+ Mouse.split(text.delete_suffix(@held)).flat_map do |piece|
48
+ next [[:mouse, piece]] if piece.is_a?(Mouse::Event)
49
+ split_keys(piece).map { |k| [:key, key_name(k), k] }
50
+ end
43
51
  end
44
52
  end
45
53
 
@@ -10,14 +10,21 @@ module ClaudeInbox
10
10
 
11
11
  Event = Struct.new(:kind, :row, :col)
12
12
 
13
- # A raw keypress can glue several reports together the same way a fast
14
- # "esc gg" glues onto one read (see Input#split_keys), so this scans
15
- # rather than matching once.
16
- def self.events(raw)
17
- raw.scan(SEQUENCE).filter_map do |cb, col, row, type|
13
+ # The read cut at its reports, in order: an Event per report acted on,
14
+ # the keys between as strings. An ignored report still cuts, so the keys
15
+ # either side of it never join into one.
16
+ def self.split(raw)
17
+ out = []
18
+ rest = raw
19
+ while (m = SEQUENCE.match(rest))
20
+ out << m.pre_match unless m.pre_match.empty?
21
+ cb, col, row, type = m.captures
18
22
  kind = kind_for(cb.to_i, type)
19
- Event.new(kind, row.to_i, col.to_i) if kind
23
+ out << Event.new(kind, row.to_i, col.to_i) if kind
24
+ rest = m.post_match
20
25
  end
26
+ out << rest unless rest.empty?
27
+ out
21
28
  end
22
29
 
23
30
  # Bit 6 (0x40) marks a wheel tick, direction in bit 0. Otherwise bits
@@ -14,9 +14,12 @@ module ClaudeInbox
14
14
  # The same frame for a terminal drawn without color.
15
15
  def plain = self.class.new(lines.map { |l| l.gsub(Text::CSI, "") }, items, top)
16
16
 
17
+ # Only the row under the pointer is scanned: every keystroke paints a
18
+ # frame, and scanning the whole screen for links each time cost more
19
+ # than the key repeat interval.
17
20
  def link_at(row, col)
18
- @links ||= lines.map { |l| Text.links(l) }
19
- @links.fetch(row - 1, []).find { |link| link.columns.cover?(col - 1) }
21
+ line = lines[row - 1] if row >= 1
22
+ Text.links(line).find { |link| link.columns.cover?(col - 1) } if line
20
23
  end
21
24
  end
22
25
 
@@ -25,6 +25,7 @@ module ClaudeInbox
25
25
  Link = Data.define(:columns, :url, :text)
26
26
 
27
27
  def links(s)
28
+ return [] unless s.include?("\e]8;")
28
29
  found = []
29
30
  col = 0
30
31
  start = url = text = nil
data/lib/claude_inbox.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ClaudeInbox
4
- VERSION = "0.14.3"
4
+ VERSION = "0.14.4"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: claude-inbox
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.14.3
4
+ version: 0.14.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jordan Byron