twterm 1.0.9 → 1.0.10
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 +4 -4
- data/.rspec +2 -0
- data/{LICENSE.txt → LICENSE} +0 -0
- data/README.md +24 -2
- data/lib/twterm/app.rb +14 -4
- data/lib/twterm/auth.rb +5 -5
- data/lib/twterm/client.rb +185 -142
- data/lib/twterm/color_manager.rb +15 -11
- data/lib/twterm/config.rb +22 -17
- data/lib/twterm/list.rb +9 -9
- data/lib/twterm/notifier.rb +7 -22
- data/lib/twterm/scheduler.rb +5 -8
- data/lib/twterm/screen.rb +25 -20
- data/lib/twterm/status.rb +84 -79
- data/lib/twterm/tab/base.rb +26 -11
- data/lib/twterm/tab/conversation_tab.rb +16 -16
- data/lib/twterm/tab/key_assignments_cheatsheet.rb +113 -0
- data/lib/twterm/tab/list_tab.rb +1 -1
- data/lib/twterm/tab/mentions_tab.rb +13 -13
- data/lib/twterm/tab/new/list.rb +51 -40
- data/lib/twterm/tab/new/search.rb +8 -5
- data/lib/twterm/tab/new/start.rb +26 -35
- data/lib/twterm/tab/new/user.rb +8 -5
- data/lib/twterm/tab/scroll_manager.rb +84 -0
- data/lib/twterm/tab/search_tab.rb +16 -16
- data/lib/twterm/tab/statuses_tab.rb +177 -128
- data/lib/twterm/tab/timeline_tab.rb +13 -15
- data/lib/twterm/tab/user_tab.rb +18 -18
- data/lib/twterm/tab_manager.rb +49 -44
- data/lib/twterm/tweetbox.rb +51 -25
- data/lib/twterm/user.rb +5 -8
- data/lib/twterm/version.rb +1 -1
- data/lib/twterm.rb +4 -2
- data/spec/resources/config +4 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/twterm/config_spec.rb +34 -0
- data/twterm.gemspec +2 -0
- metadata +25 -6
- data/lib/twterm/tab/scrollable.rb +0 -130
data/lib/twterm/list.rb
CHANGED
@@ -4,6 +4,10 @@ module Twterm
|
|
4
4
|
|
5
5
|
@@instances = {}
|
6
6
|
|
7
|
+
def ==(other)
|
8
|
+
other.is_a?(self.class) && id == other.id
|
9
|
+
end
|
10
|
+
|
7
11
|
def initialize(list)
|
8
12
|
@id = list.id
|
9
13
|
update!(list)
|
@@ -24,13 +28,8 @@ module Twterm
|
|
24
28
|
self
|
25
29
|
end
|
26
30
|
|
27
|
-
def
|
28
|
-
|
29
|
-
end
|
30
|
-
|
31
|
-
def self.new(list)
|
32
|
-
instance = find(list.id)
|
33
|
-
instance.nil? ? super : instance.update!(list)
|
31
|
+
def self.all
|
32
|
+
@@instances.values
|
34
33
|
end
|
35
34
|
|
36
35
|
def self.find(id)
|
@@ -44,8 +43,9 @@ module Twterm
|
|
44
43
|
Client.current.list(id) { |list| yield list }
|
45
44
|
end
|
46
45
|
|
47
|
-
def self.
|
48
|
-
|
46
|
+
def self.new(list)
|
47
|
+
instance = find(list.id)
|
48
|
+
instance.nil? ? super : instance.update!(list)
|
49
49
|
end
|
50
50
|
end
|
51
51
|
end
|
data/lib/twterm/notifier.rb
CHANGED
@@ -4,9 +4,8 @@ module Twterm
|
|
4
4
|
include Curses
|
5
5
|
|
6
6
|
def initialize
|
7
|
-
@window = stdscr.subwin(
|
7
|
+
@window = stdscr.subwin(1, stdscr.maxx, stdscr.maxy - 2, 0)
|
8
8
|
@queue = Queue.new
|
9
|
-
@help = ''
|
10
9
|
|
11
10
|
Thread.new do
|
12
11
|
while notification = @queue.pop
|
@@ -17,23 +16,16 @@ module Twterm
|
|
17
16
|
end
|
18
17
|
end
|
19
18
|
|
20
|
-
def show_message(message)
|
21
|
-
notification = Notification::Message.new(message)
|
22
|
-
@queue.push(notification)
|
23
|
-
self
|
24
|
-
end
|
25
|
-
|
26
19
|
def show_error(message)
|
27
20
|
notification = Notification::Error.new(message)
|
28
21
|
@queue.push(notification)
|
29
22
|
self
|
30
23
|
end
|
31
24
|
|
32
|
-
def
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
show
|
25
|
+
def show_message(message)
|
26
|
+
notification = Notification::Message.new(message)
|
27
|
+
@queue.push(notification)
|
28
|
+
self
|
37
29
|
end
|
38
30
|
|
39
31
|
def show(notification = nil)
|
@@ -46,22 +38,15 @@ module Twterm
|
|
46
38
|
|
47
39
|
if notification.is_a? Notification::Base
|
48
40
|
@window.with_color(notification.fg_color, notification.bg_color) do
|
49
|
-
@window.setpos(
|
41
|
+
@window.setpos(0, 0)
|
50
42
|
@window.addstr(' ' * @window.maxx)
|
51
|
-
@window.setpos(
|
43
|
+
@window.setpos(0, 1)
|
52
44
|
time = notification.time.strftime('[%H:%M:%S]')
|
53
45
|
message = notification.show_with_width(@window.maxx)
|
54
46
|
@window.addstr("#{time} #{message}")
|
55
47
|
end
|
56
48
|
end
|
57
49
|
|
58
|
-
@window.with_color(:black, :green) do
|
59
|
-
@window.setpos(0, 0)
|
60
|
-
@window.addstr(' ' * @window.maxx)
|
61
|
-
@window.setpos(0, 1)
|
62
|
-
@window.addstr(@help)
|
63
|
-
end
|
64
|
-
|
65
50
|
@window.refresh
|
66
51
|
end
|
67
52
|
end
|
data/lib/twterm/scheduler.rb
CHANGED
@@ -7,10 +7,7 @@ class Scheduler
|
|
7
7
|
@paused = false
|
8
8
|
|
9
9
|
@thread = Thread.new do
|
10
|
-
loop
|
11
|
-
sleep @interval
|
12
|
-
run
|
13
|
-
end
|
10
|
+
loop { sleep(@interval) && run }
|
14
11
|
end
|
15
12
|
end
|
16
13
|
|
@@ -22,11 +19,11 @@ class Scheduler
|
|
22
19
|
@paused = true
|
23
20
|
end
|
24
21
|
|
25
|
-
def
|
26
|
-
@
|
22
|
+
def resume
|
23
|
+
@paused = false
|
27
24
|
end
|
28
25
|
|
29
|
-
def
|
30
|
-
@
|
26
|
+
def run
|
27
|
+
@block.call unless @paused
|
31
28
|
end
|
32
29
|
end
|
data/lib/twterm/screen.rb
CHANGED
@@ -13,15 +13,6 @@ module Twterm
|
|
13
13
|
use_default_colors
|
14
14
|
end
|
15
15
|
|
16
|
-
def wait
|
17
|
-
@thread = Thread.new do
|
18
|
-
loop do
|
19
|
-
scan
|
20
|
-
end
|
21
|
-
end
|
22
|
-
@thread.join
|
23
|
-
end
|
24
|
-
|
25
16
|
def refresh
|
26
17
|
TabManager.instance.refresh_window
|
27
18
|
TabManager.instance.current_tab.refresh
|
@@ -29,6 +20,30 @@ module Twterm
|
|
29
20
|
Notifier.instance.show
|
30
21
|
end
|
31
22
|
|
23
|
+
def respond_to_key(key)
|
24
|
+
case key
|
25
|
+
when ?n
|
26
|
+
Tweetbox.instance.compose
|
27
|
+
return
|
28
|
+
when ?Q
|
29
|
+
App.instance.quit
|
30
|
+
when ??
|
31
|
+
tab = Tab::KeyAssignmentsCheatsheet.new
|
32
|
+
TabManager.instance.add_and_show tab
|
33
|
+
else
|
34
|
+
return false
|
35
|
+
end
|
36
|
+
|
37
|
+
true
|
38
|
+
end
|
39
|
+
|
40
|
+
def wait
|
41
|
+
@thread = Thread.new do
|
42
|
+
loop { scan }
|
43
|
+
end
|
44
|
+
@thread.join
|
45
|
+
end
|
46
|
+
|
32
47
|
private
|
33
48
|
|
34
49
|
def scan
|
@@ -38,17 +53,7 @@ module Twterm
|
|
38
53
|
|
39
54
|
return if TabManager.instance.current_tab.respond_to_key(key)
|
40
55
|
return if TabManager.instance.respond_to_key(key)
|
41
|
-
|
42
|
-
case key
|
43
|
-
when 'n'
|
44
|
-
Tweetbox.instance.compose
|
45
|
-
return
|
46
|
-
when 'Q'
|
47
|
-
App.instance.quit
|
48
|
-
when '/'
|
49
|
-
# filter
|
50
|
-
else
|
51
|
-
end
|
56
|
+
respond_to_key(key)
|
52
57
|
end
|
53
58
|
end
|
54
59
|
end
|
data/lib/twterm/status.rb
CHANGED
@@ -2,21 +2,57 @@ module Twterm
|
|
2
2
|
class Status
|
3
3
|
MAX_CACHED_TIME = 3600
|
4
4
|
|
5
|
-
attr_reader :
|
5
|
+
attr_reader :appeared_at, :created_at, :favorite_count, :favorited, :id,
|
6
|
+
:in_reply_to_status_id, :media, :retweet_count, :retweeted,
|
7
|
+
:retweeted_by_user_id, :text, :touched_at, :urls, :user_id
|
6
8
|
alias_method :favorited?, :favorited
|
7
9
|
alias_method :retweeted?, :retweeted
|
8
10
|
|
9
11
|
@@instances = {}
|
10
12
|
|
11
|
-
def
|
12
|
-
|
13
|
-
|
13
|
+
def ==(other)
|
14
|
+
other.is_a?(self.class) && id == other.id
|
15
|
+
end
|
16
|
+
|
17
|
+
def date
|
18
|
+
format = Time.now - @created_at < 86_400 ? '%H:%M:%S' : '%Y-%m-%d %H:%M:%S'
|
19
|
+
@created_at.strftime(format)
|
20
|
+
end
|
21
|
+
|
22
|
+
def expand_url!
|
23
|
+
sub = -> (x) { @text.sub!(x.url, x.display_url) }
|
24
|
+
(@media + @urls).each(&sub)
|
25
|
+
end
|
26
|
+
|
27
|
+
def favorite!
|
28
|
+
@favorite_count += 1
|
29
|
+
@favorited = true
|
30
|
+
end
|
31
|
+
|
32
|
+
def grepped_with?(query)
|
33
|
+
[text, user.screen_name, user.name]
|
34
|
+
.any? { |x| x.downcase.include?(query.downcase) }
|
35
|
+
end
|
36
|
+
|
37
|
+
def in_reply_to_status(&block)
|
38
|
+
if @in_reply_to_status_id.nil?
|
39
|
+
block.call(nil)
|
40
|
+
return
|
41
|
+
end
|
42
|
+
|
43
|
+
status = Status.find(@in_reply_to_status_id)
|
44
|
+
unless status.nil?
|
45
|
+
block.call(status)
|
46
|
+
return
|
47
|
+
end
|
48
|
+
|
49
|
+
Client.current.show_status(@in_reply_to_status_id, &block)
|
14
50
|
end
|
15
51
|
|
16
52
|
def initialize(tweet)
|
17
53
|
unless tweet.retweeted_status.is_a? Twitter::NullObject
|
18
54
|
@retweeted_by_user_id = tweet.user.id
|
19
|
-
User.
|
55
|
+
User.new(tweet.user)
|
20
56
|
retweeted_at = Status.parse_time(tweet.created_at)
|
21
57
|
tweet = tweet.retweeted_status
|
22
58
|
end
|
@@ -24,7 +60,7 @@ module Twterm
|
|
24
60
|
@id = tweet.id
|
25
61
|
@text = CGI.unescapeHTML(tweet.full_text.dup)
|
26
62
|
@created_at = Status.parse_time(tweet.created_at)
|
27
|
-
@
|
63
|
+
@appeared_at = retweeted_at || @created_at
|
28
64
|
@retweet_count = tweet.retweet_count
|
29
65
|
@favorite_count = tweet.favorite_count
|
30
66
|
@in_reply_to_status_id = tweet.in_reply_to_status_id
|
@@ -36,7 +72,7 @@ module Twterm
|
|
36
72
|
@urls = tweet.urls
|
37
73
|
|
38
74
|
@user_id = tweet.user.id
|
39
|
-
User.
|
75
|
+
User.new(tweet.user)
|
40
76
|
|
41
77
|
@splitted_text = {}
|
42
78
|
|
@@ -51,32 +87,8 @@ module Twterm
|
|
51
87
|
@@instances[id] = self
|
52
88
|
end
|
53
89
|
|
54
|
-
def
|
55
|
-
|
56
|
-
@favorite_count = tweet.favorite_count
|
57
|
-
@retweeted = tweet.retweeted?
|
58
|
-
@favorited = tweet.favorited?
|
59
|
-
self
|
60
|
-
end
|
61
|
-
|
62
|
-
def date
|
63
|
-
format = Time.now - @created_at < 86_400 ? '%H:%M:%S' : '%Y-%m-%d %H:%M:%S'
|
64
|
-
@created_at.strftime(format)
|
65
|
-
end
|
66
|
-
|
67
|
-
def expand_url!
|
68
|
-
sub = -> (x) { @text.sub!(x.url, x.display_url) }
|
69
|
-
(@media + @urls).each(&sub)
|
70
|
-
end
|
71
|
-
|
72
|
-
def favorite!
|
73
|
-
@favorite_count += 1
|
74
|
-
@favorited = true
|
75
|
-
end
|
76
|
-
|
77
|
-
def unfavorite!
|
78
|
-
@favorite_count -= 1
|
79
|
-
@favorited = false
|
90
|
+
def replies
|
91
|
+
Status.all.select { |s| s.in_reply_to_status_id == id }
|
80
92
|
end
|
81
93
|
|
82
94
|
def retweet!
|
@@ -84,74 +96,67 @@ module Twterm
|
|
84
96
|
@retweeted = true
|
85
97
|
end
|
86
98
|
|
87
|
-
def
|
88
|
-
|
99
|
+
def retweeted_by
|
100
|
+
User.find(@retweeted_by_user_id)
|
89
101
|
end
|
90
102
|
|
91
|
-
def
|
92
|
-
|
93
|
-
block.call(nil)
|
94
|
-
return
|
95
|
-
end
|
96
|
-
|
97
|
-
status = Status.find(@in_reply_to_status_id)
|
98
|
-
unless status.nil?
|
99
|
-
block.call(status)
|
100
|
-
return
|
101
|
-
end
|
102
|
-
|
103
|
-
Client.current.show_status(@in_reply_to_status_id, &block)
|
103
|
+
def split(width)
|
104
|
+
@splitted_text[:width] ||= @text.split_by_width(width)
|
104
105
|
end
|
105
106
|
|
106
|
-
def
|
107
|
-
|
107
|
+
def touch!
|
108
|
+
@touched_at = Time.now
|
108
109
|
end
|
109
110
|
|
110
|
-
def
|
111
|
-
|
111
|
+
def unfavorite!
|
112
|
+
@favorite_count -= 1
|
113
|
+
@favorited = false
|
112
114
|
end
|
113
115
|
|
114
|
-
def
|
115
|
-
@
|
116
|
+
def update!(tweet)
|
117
|
+
@retweet_count = tweet.retweet_count
|
118
|
+
@favorite_count = tweet.favorite_count
|
119
|
+
@retweeted = tweet.retweeted?
|
120
|
+
@favorited = tweet.favorited?
|
121
|
+
self
|
116
122
|
end
|
117
123
|
|
118
124
|
def user
|
119
125
|
User.find(user_id)
|
120
126
|
end
|
121
127
|
|
122
|
-
def
|
123
|
-
|
128
|
+
def self.all
|
129
|
+
@@instances.values
|
124
130
|
end
|
125
131
|
|
126
|
-
|
127
|
-
|
128
|
-
|
132
|
+
def self.cleanup
|
133
|
+
TabManager.instance.each_tab do |tab|
|
134
|
+
tab.touch_statuses if tab.is_a?(Tab::StatusesTab)
|
129
135
|
end
|
136
|
+
cond = -> (status) { status.touched_at > Time.now - MAX_CACHED_TIME }
|
137
|
+
statuses = all.select(&cond)
|
138
|
+
status_ids = statuses.map(&:id)
|
139
|
+
@@instances = status_ids.zip(statuses).to_h
|
140
|
+
end
|
130
141
|
|
131
|
-
|
132
|
-
|
133
|
-
|
142
|
+
def self.find(id)
|
143
|
+
@@instances[id]
|
144
|
+
end
|
134
145
|
|
135
|
-
|
136
|
-
|
137
|
-
|
146
|
+
def self.find_or_fetch(id)
|
147
|
+
instance = find(id)
|
148
|
+
(yield(instance) && return) if instance
|
138
149
|
|
139
|
-
|
140
|
-
|
150
|
+
Client.current.show_status(id) { |status| yield status }
|
151
|
+
end
|
141
152
|
|
142
|
-
|
143
|
-
|
144
|
-
|
153
|
+
def self.new(tweet)
|
154
|
+
instance = find(tweet.id)
|
155
|
+
instance.nil? ? super : instance.update!(tweet)
|
156
|
+
end
|
145
157
|
|
146
|
-
|
147
|
-
|
148
|
-
tab.touch_statuses if tab.is_a?(Tab::StatusesTab)
|
149
|
-
end
|
150
|
-
cond = -> (status) { status.touched_at > Time.now - MAX_CACHED_TIME }
|
151
|
-
statuses = all.select(&cond)
|
152
|
-
status_ids = statuses.map(&:id)
|
153
|
-
@@instances = status_ids.zip(statuses).to_h
|
154
|
-
end
|
158
|
+
def self.parse_time(time)
|
159
|
+
(time.is_a?(String) ? Time.parse(time) : time.dup).localtime
|
155
160
|
end
|
156
161
|
end
|
157
162
|
end
|
data/lib/twterm/tab/base.rb
CHANGED
@@ -3,35 +3,50 @@ module Twterm
|
|
3
3
|
module Base
|
4
4
|
include Curses
|
5
5
|
|
6
|
+
attr_reader :window
|
6
7
|
attr_accessor :title
|
7
8
|
|
9
|
+
def ==(other)
|
10
|
+
self.equal?(other)
|
11
|
+
end
|
12
|
+
|
13
|
+
def close
|
14
|
+
window.close
|
15
|
+
end
|
16
|
+
|
8
17
|
def initialize
|
9
18
|
@window = stdscr.subwin(stdscr.maxy - 5, stdscr.maxx - 30, 3, 0)
|
10
19
|
end
|
11
20
|
|
12
21
|
def refresh
|
13
|
-
return
|
22
|
+
return unless refreshable?
|
14
23
|
|
15
|
-
@refreshing = true
|
16
24
|
Thread.new do
|
17
|
-
|
18
|
-
|
25
|
+
refresh_mutex.synchronize do
|
26
|
+
window.clear
|
27
|
+
update
|
28
|
+
window.refresh
|
29
|
+
end
|
19
30
|
end
|
20
31
|
end
|
21
32
|
|
22
|
-
def close
|
23
|
-
@window.close
|
24
|
-
end
|
25
|
-
|
26
33
|
def respond_to_key(_)
|
27
34
|
fail NotImplementedError, 'respond_to_key method must be implemented'
|
28
35
|
end
|
29
36
|
|
30
|
-
|
31
|
-
|
37
|
+
private
|
38
|
+
|
39
|
+
def refresh_mutex
|
40
|
+
@refresh_mutex ||= Mutex.new
|
32
41
|
end
|
33
42
|
|
34
|
-
|
43
|
+
def refreshable?
|
44
|
+
!(
|
45
|
+
refresh_mutex.locked? ||
|
46
|
+
closed? ||
|
47
|
+
TabManager.instance.current_tab.object_id != object_id
|
48
|
+
)
|
49
|
+
end
|
35
50
|
|
36
51
|
def update
|
37
52
|
fail NotImplementedError, 'update method must be implemented'
|
@@ -6,18 +6,8 @@ module Twterm
|
|
6
6
|
|
7
7
|
attr_reader :status
|
8
8
|
|
9
|
-
def
|
10
|
-
|
11
|
-
super()
|
12
|
-
|
13
|
-
Status.find_or_fetch(status_id) do |status|
|
14
|
-
@status = status
|
15
|
-
|
16
|
-
append(status)
|
17
|
-
move_to_top
|
18
|
-
Thread.new { fetch_in_reply_to_status(status) }
|
19
|
-
Thread.new { fetch_replies(status) }
|
20
|
-
end
|
9
|
+
def ==(other)
|
10
|
+
other.is_a?(self.class) && status == other.status
|
21
11
|
end
|
22
12
|
|
23
13
|
def fetch_in_reply_to_status(status)
|
@@ -37,13 +27,23 @@ module Twterm
|
|
37
27
|
end
|
38
28
|
end
|
39
29
|
|
40
|
-
def ==(other)
|
41
|
-
other.is_a?(self.class) && status == other.status
|
42
|
-
end
|
43
|
-
|
44
30
|
def dump
|
45
31
|
@status.id
|
46
32
|
end
|
33
|
+
|
34
|
+
def initialize(status_id)
|
35
|
+
@title = 'Conversation'
|
36
|
+
super()
|
37
|
+
|
38
|
+
Status.find_or_fetch(status_id) do |status|
|
39
|
+
@status = status
|
40
|
+
|
41
|
+
append(status)
|
42
|
+
scroll_manager.move_to_top
|
43
|
+
Thread.new { fetch_in_reply_to_status(status) }
|
44
|
+
Thread.new { fetch_replies(status) }
|
45
|
+
end
|
46
|
+
end
|
47
47
|
end
|
48
48
|
end
|
49
49
|
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
module Twterm
|
2
|
+
module Tab
|
3
|
+
class KeyAssignmentsCheatsheet
|
4
|
+
include Base
|
5
|
+
|
6
|
+
def ==(other)
|
7
|
+
other.is_a?(self.class)
|
8
|
+
end
|
9
|
+
|
10
|
+
SHORTCUTS = {
|
11
|
+
'General' => {
|
12
|
+
'[d] [C-d]' => 'Scroll down',
|
13
|
+
'[g]' => 'Move to top',
|
14
|
+
'[G]' => 'Move to bottom',
|
15
|
+
'[j] [C-p] [DOWN]' => 'Move down',
|
16
|
+
'[k] [C-n] [UP]' => 'Move up',
|
17
|
+
'[u] [C-u]' => 'Scroll up',
|
18
|
+
'[Q]' => 'Quit twterm',
|
19
|
+
'[?]' => 'Open key assignments cheatsheet'
|
20
|
+
},
|
21
|
+
'Tabs' => {
|
22
|
+
'[h] [C-b] [LEFT]' => 'Show previous tab',
|
23
|
+
'[l] [C-f] [RIGHT]' => 'Show next tab',
|
24
|
+
'[N]' => 'Open new tab',
|
25
|
+
'[C-R]' => 'Reload',
|
26
|
+
'[w]' => 'Close tab',
|
27
|
+
'[q]' => 'Quit filtering mode',
|
28
|
+
'[/]' => 'Filter items in tab'
|
29
|
+
},
|
30
|
+
'Tweets' => {
|
31
|
+
'[D]' => 'Delete tweet',
|
32
|
+
'[F]' => 'Add to favorite',
|
33
|
+
'[n]' => 'Compose new tweet',
|
34
|
+
'[o]' => 'Open URLs in tweet',
|
35
|
+
'[r]' => 'Reply',
|
36
|
+
'[R]' => 'Retweet',
|
37
|
+
'[U]' => 'Show user'
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
def respond_to_key(key)
|
42
|
+
case key
|
43
|
+
when ?d, 4
|
44
|
+
10.times { scroll_manager.move_down }
|
45
|
+
when ?g
|
46
|
+
scroll_manager.move_to_top
|
47
|
+
when ?G
|
48
|
+
scroll_manager.move_to_bottom
|
49
|
+
when ?j, 14, Curses::Key::DOWN
|
50
|
+
scroll_manager.move_down
|
51
|
+
when ?k, 16, Curses::Key::UP
|
52
|
+
scroll_manager.move_up
|
53
|
+
when ?u, 21
|
54
|
+
10.times { scroll_manager.move_up }
|
55
|
+
else
|
56
|
+
return false
|
57
|
+
end
|
58
|
+
|
59
|
+
true
|
60
|
+
end
|
61
|
+
|
62
|
+
def title
|
63
|
+
'Key assignments'.freeze
|
64
|
+
end
|
65
|
+
|
66
|
+
def update
|
67
|
+
top = 2 # begin drawing from line 2
|
68
|
+
draw_cond = -> line { top <= line && line <= window.maxy - top }
|
69
|
+
|
70
|
+
current_line = top - scroll_manager.offset
|
71
|
+
|
72
|
+
window.setpos(current_line, 3)
|
73
|
+
window.bold { window.addstr('Key assignments') } if draw_cond[current_line]
|
74
|
+
|
75
|
+
SHORTCUTS.each do |category, shortcuts|
|
76
|
+
current_line += 3
|
77
|
+
window.setpos(current_line, 5)
|
78
|
+
window.bold { window.addstr("<#{category}>") } if draw_cond[current_line]
|
79
|
+
current_line += 1
|
80
|
+
|
81
|
+
shortcuts.each do |key, description|
|
82
|
+
current_line += 1
|
83
|
+
next unless draw_cond[current_line]
|
84
|
+
|
85
|
+
window.setpos(current_line, 7)
|
86
|
+
window.bold { window.addstr(key.rjust(17)) }
|
87
|
+
window.setpos(current_line, 25)
|
88
|
+
window.addstr(": #{description}")
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
def count
|
96
|
+
@count ||= SHORTCUTS.count * 4 + SHORTCUTS.map(&:count).reduce(0, :+) + 1
|
97
|
+
end
|
98
|
+
|
99
|
+
def offset_from_bottom
|
100
|
+
0
|
101
|
+
end
|
102
|
+
|
103
|
+
def scroll_manager
|
104
|
+
return @scroll_manager unless @scroll_manager.nil?
|
105
|
+
|
106
|
+
@scroll_manager = ScrollManager.new
|
107
|
+
@scroll_manager.delegate = self
|
108
|
+
@scroll_manager.after_move { refresh }
|
109
|
+
@scroll_manager
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
data/lib/twterm/tab/list_tab.rb
CHANGED
@@ -3,6 +3,18 @@ module Twterm
|
|
3
3
|
class MentionsTab
|
4
4
|
include StatusesTab
|
5
5
|
|
6
|
+
def close
|
7
|
+
fail NotClosableError
|
8
|
+
end
|
9
|
+
|
10
|
+
def fetch
|
11
|
+
@client.mentions do |statuses|
|
12
|
+
statuses.reverse.each(&method(:prepend))
|
13
|
+
sort
|
14
|
+
yield if block_given?
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
6
18
|
def initialize(client)
|
7
19
|
fail ArgumentError, 'argument must be an instance of Client class' unless client.is_a? Client
|
8
20
|
|
@@ -16,21 +28,9 @@ module Twterm
|
|
16
28
|
|
17
29
|
@title = 'Mentions'
|
18
30
|
|
19
|
-
fetch { move_to_top }
|
31
|
+
fetch { scroll_manager.move_to_top }
|
20
32
|
@auto_reloader = Scheduler.new(300) { fetch }
|
21
33
|
end
|
22
|
-
|
23
|
-
def fetch
|
24
|
-
@client.mentions do |statuses|
|
25
|
-
statuses.reverse.each(&method(:prepend))
|
26
|
-
sort
|
27
|
-
yield if block_given?
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def close
|
32
|
-
fail NotClosableError
|
33
|
-
end
|
34
34
|
end
|
35
35
|
end
|
36
36
|
end
|