twterm 1.3.0 → 2.0.0.beta1
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/README.md +14 -18
- data/bin/twterm +1 -1
- data/lib/twterm/app.rb +120 -30
- data/lib/twterm/client.rb +10 -13
- data/lib/twterm/completion_mamanger.rb +11 -6
- data/lib/twterm/direct_message.rb +6 -28
- data/lib/twterm/direct_message_composer.rb +10 -5
- data/lib/twterm/direct_message_manager.rb +5 -6
- data/lib/twterm/event/notification/abstract_notification.rb +27 -0
- data/lib/twterm/event/notification/error.rb +13 -0
- data/lib/twterm/event/notification/info.rb +13 -0
- data/lib/twterm/event/notification/success.rb +13 -0
- data/lib/twterm/event/notification/warning.rb +13 -0
- data/lib/twterm/event_dispatcher.rb +1 -1
- data/lib/twterm/extensions/array.rb +5 -0
- data/lib/twterm/extensions/enumerator/lazy.rb +3 -0
- data/lib/twterm/extensions/string.rb +0 -4
- data/lib/twterm/friendship.rb +1 -85
- data/lib/twterm/image/between.rb +31 -0
- data/lib/twterm/image/blank_line.rb +21 -0
- data/lib/twterm/image/bold.rb +31 -0
- data/lib/twterm/image/brackets.rb +21 -0
- data/lib/twterm/image/color.rb +45 -0
- data/lib/twterm/image/empty.rb +21 -0
- data/lib/twterm/image/horizontal_sequential_image.rb +48 -0
- data/lib/twterm/image/parens.rb +21 -0
- data/lib/twterm/image/string_image.rb +38 -0
- data/lib/twterm/image/vertical_sequential_image.rb +43 -0
- data/lib/twterm/image.rb +107 -0
- data/lib/twterm/key_mapper/abstract_key_mapper.rb +51 -0
- data/lib/twterm/key_mapper/app_key_mapper.rb +13 -0
- data/lib/twterm/key_mapper/cursor_key_mapper.rb +13 -0
- data/lib/twterm/key_mapper/general_key_mapper.rb +18 -0
- data/lib/twterm/key_mapper/no_such_command.rb +20 -0
- data/lib/twterm/key_mapper/no_such_key.rb +16 -0
- data/lib/twterm/key_mapper/status_key_mapper.rb +18 -0
- data/lib/twterm/key_mapper/tab_key_mapper.rb +31 -0
- data/lib/twterm/key_mapper.rb +127 -0
- data/lib/twterm/list.rb +0 -31
- data/lib/twterm/notifier.rb +7 -7
- data/lib/twterm/repository/abstract_entity_repository.rb +41 -0
- data/lib/twterm/repository/abstract_expirable_entity_repository.rb +35 -0
- data/lib/twterm/repository/abstract_repository.rb +64 -0
- data/lib/twterm/repository/direct_message_repository.rb +14 -0
- data/lib/twterm/repository/friendship_repository.rb +108 -0
- data/lib/twterm/repository/hashtag_repository.rb +39 -0
- data/lib/twterm/repository/list_repository.rb +14 -0
- data/lib/twterm/repository/status_repository.rb +36 -0
- data/lib/twterm/repository/user_repository.rb +22 -0
- data/lib/twterm/rest_client.rb +107 -63
- data/lib/twterm/screen.rb +21 -15
- data/lib/twterm/search_query_window.rb +139 -0
- data/lib/twterm/status.rb +14 -108
- data/lib/twterm/streaming_client.rb +13 -12
- data/lib/twterm/tab/base.rb +48 -8
- data/lib/twterm/tab/direct_message/conversation.rb +53 -52
- data/lib/twterm/tab/direct_message/conversation_list.rb +46 -45
- data/lib/twterm/tab/dumpable.rb +3 -3
- data/lib/twterm/tab/key_assignments_cheatsheet.rb +58 -57
- data/lib/twterm/tab/loadable.rb +20 -0
- data/lib/twterm/tab/new/list.rb +32 -43
- data/lib/twterm/tab/new/search.rb +31 -44
- data/lib/twterm/tab/new/start.rb +44 -55
- data/lib/twterm/tab/new/user.rb +15 -12
- data/lib/twterm/tab/rate_limit_status.rb +84 -0
- data/lib/twterm/tab/scrollable.rb +39 -19
- data/lib/twterm/tab/searchable.rb +133 -0
- data/lib/twterm/tab/statuses/base.rb +139 -129
- data/lib/twterm/tab/statuses/conversation.rb +26 -15
- data/lib/twterm/tab/statuses/favorites.rb +10 -8
- data/lib/twterm/tab/statuses/home.rb +10 -9
- data/lib/twterm/tab/statuses/list_timeline.rb +12 -8
- data/lib/twterm/tab/statuses/mentions.rb +17 -11
- data/lib/twterm/tab/statuses/search.rb +8 -5
- data/lib/twterm/tab/statuses/user_timeline.rb +11 -8
- data/lib/twterm/tab/user_list_management.rb +109 -0
- data/lib/twterm/tab/user_tab.rb +125 -126
- data/lib/twterm/tab/users/base.rb +39 -41
- data/lib/twterm/tab/users/followers.rb +9 -6
- data/lib/twterm/tab/users/friends.rb +9 -6
- data/lib/twterm/tab_manager.rb +64 -40
- data/lib/twterm/tweetbox.rb +18 -13
- data/lib/twterm/uri_opener.rb +2 -1
- data/lib/twterm/user.rb +2 -110
- data/lib/twterm/version.rb +1 -1
- data/lib/twterm/view.rb +30 -0
- data/lib/twterm.rb +3 -9
- data/spec/fixtures/status.json +107 -0
- data/spec/fixtures/user.json +102 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/supports/shared_examples/abstract_key_mapper.rb +17 -0
- data/spec/twterm/extension/enumerator/lazy_spec.rb +11 -0
- data/spec/twterm/friendship_spec.rb +0 -102
- data/spec/twterm/image/blank_line_spec.rb +11 -0
- data/spec/twterm/image/brackets_spec.rb +12 -0
- data/spec/twterm/image/color_spec.rb +22 -0
- data/spec/twterm/image/empry_spec.rb +11 -0
- data/spec/twterm/image/horizontal_sequential_image_spec.rb +15 -0
- data/spec/twterm/image/parens_spec.rb +12 -0
- data/spec/twterm/image/string_image_spec.rb +12 -0
- data/spec/twterm/image/vertical_sequential_image_spec.rb +14 -0
- data/spec/twterm/image_spec.rb +65 -0
- data/spec/twterm/key_mapper/abstract_key_mapper_spec.rb +21 -0
- data/spec/twterm/key_mapper/app_key_mapper_spec.rb +7 -0
- data/spec/twterm/key_mapper/status_key_mapper_spec.rb +7 -0
- data/spec/twterm/key_mapper/tab_key_mapper_spec.rb +7 -0
- data/spec/twterm/repository/friendship_repository_spec.rb +108 -0
- data/spec/twterm/status_spec.rb +58 -0
- data/spec/twterm/user_spec.rb +94 -0
- data/twterm.gemspec +13 -10
- metadata +129 -35
- data/lib/twterm/event/notification.rb +0 -33
- data/lib/twterm/extensions/integer.rb +0 -5
- data/lib/twterm/filter_query_window.rb +0 -91
- data/lib/twterm/filterable_list.rb +0 -41
- data/lib/twterm/history/base.rb +0 -21
- data/lib/twterm/history/hashtag.rb +0 -13
- data/lib/twterm/history/savable.rb +0 -37
- data/lib/twterm/history/screen_name.rb +0 -11
- data/lib/twterm/promise.rb +0 -143
data/lib/twterm/rest_client.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
+
require 'concurrent'
|
1
2
|
require 'twterm/direct_message'
|
2
3
|
require 'twterm/direct_message_manager'
|
3
4
|
require 'twterm/publisher'
|
4
|
-
require 'twterm/event/notification'
|
5
|
+
require 'twterm/event/notification/success'
|
5
6
|
|
6
7
|
module Twterm
|
7
8
|
module RESTClient
|
@@ -10,12 +11,16 @@ module Twterm
|
|
10
11
|
CONSUMER_KEY = 'vLNSVFgXclBJQJRZ7VLMxL9lA'.freeze
|
11
12
|
CONSUMER_SECRET = 'OFLKzrepRG2p1hq0nUB9j2S9ndFQoNTPheTpmOY0GYw55jGgS5'.freeze
|
12
13
|
|
14
|
+
def add_list_member(list_id, user_id)
|
15
|
+
send_request { rest_client.add_list_member(list_id, user_id) }
|
16
|
+
end
|
17
|
+
|
13
18
|
def block(*user_ids)
|
14
19
|
send_request do
|
15
20
|
rest_client.block(*user_ids)
|
16
21
|
end.then do |users|
|
17
22
|
users.each do |user|
|
18
|
-
|
23
|
+
friendship_repository.block(self.user_id, user.id)
|
19
24
|
end
|
20
25
|
end
|
21
26
|
end
|
@@ -24,10 +29,10 @@ module Twterm
|
|
24
29
|
send_request do
|
25
30
|
rest_client.create_direct_message(recipient.id, text)
|
26
31
|
end.then do |message|
|
27
|
-
msg =
|
32
|
+
msg = direct_message_repository.create(message)
|
28
33
|
direct_message_manager.add(msg.recipient, msg)
|
29
34
|
publish(Event::DirectMessage::Fetched.new)
|
30
|
-
publish(Event::Notification.new(
|
35
|
+
publish(Event::Notification::Success.new('Your message to @%s has been sent' % msg.recipient.screen_name))
|
31
36
|
end
|
32
37
|
end
|
33
38
|
|
@@ -37,13 +42,13 @@ module Twterm
|
|
37
42
|
|
38
43
|
def direct_messages_received
|
39
44
|
send_request do
|
40
|
-
rest_client.direct_messages(count: 200).map
|
45
|
+
rest_client.direct_messages(count: 200).map { |dm| direct_message_repository.create(dm) }
|
41
46
|
end
|
42
47
|
end
|
43
48
|
|
44
49
|
def direct_messages_sent
|
45
50
|
send_request do
|
46
|
-
rest_client.direct_messages_sent(count: 200).map
|
51
|
+
rest_client.direct_messages_sent(count: 200).map { |dm| direct_message_repository.create(dm) }
|
47
52
|
end
|
48
53
|
end
|
49
54
|
|
@@ -51,11 +56,11 @@ module Twterm
|
|
51
56
|
send_request_without_catch do
|
52
57
|
rest_client.destroy_status(status.id)
|
53
58
|
publish(Event::Status::Delete.new(status.id))
|
54
|
-
publish(Event::Notification.new(
|
59
|
+
publish(Event::Notification::Success.new('Your tweet has been deleted'))
|
55
60
|
end.catch do |reason|
|
56
61
|
case reason
|
57
62
|
when Twitter::Error::NotFound, Twitter::Error::Forbidden
|
58
|
-
publish(Event::Notification.new(
|
63
|
+
publish(Event::Notification::Error.new('You cannot destroy that status'))
|
59
64
|
else
|
60
65
|
raise reason
|
61
66
|
end
|
@@ -67,10 +72,11 @@ module Twterm
|
|
67
72
|
|
68
73
|
send_request do
|
69
74
|
rest_client.favorite(status.id)
|
70
|
-
end.then do
|
71
|
-
|
72
|
-
|
73
|
-
|
75
|
+
end.then do |tweet, *_|
|
76
|
+
status_repository.create(tweet)
|
77
|
+
|
78
|
+
publish(Event::Notification::Success.new('Successfully liked: @%s "%s"' % [
|
79
|
+
tweet.user.screen_name, status.text
|
74
80
|
]))
|
75
81
|
end
|
76
82
|
end
|
@@ -81,7 +87,7 @@ module Twterm
|
|
81
87
|
send_request do
|
82
88
|
rest_client.favorites(user_id, count: 200)
|
83
89
|
end.then do |tweets|
|
84
|
-
tweets.map
|
90
|
+
tweets.map { |tweet| status_repository.create(tweet) }
|
85
91
|
end
|
86
92
|
end
|
87
93
|
|
@@ -97,9 +103,9 @@ module Twterm
|
|
97
103
|
end.then do |users|
|
98
104
|
users.each do |user|
|
99
105
|
if user.protected?
|
100
|
-
|
106
|
+
friendship_repository.following_requested(self.user_id, user.id)
|
101
107
|
else
|
102
|
-
|
108
|
+
friendship_repository.follow(self.user_id, user.id)
|
103
109
|
end
|
104
110
|
end
|
105
111
|
end
|
@@ -113,9 +119,9 @@ module Twterm
|
|
113
119
|
send_request do
|
114
120
|
rest_client.follower_ids(user_id).each_slice(100) do |user_ids|
|
115
121
|
m.synchronize do
|
116
|
-
users = rest_client.users(*user_ids).map
|
122
|
+
users = rest_client.users(*user_ids).map { |u| user_repository.create(u) }
|
117
123
|
users.each do |user|
|
118
|
-
|
124
|
+
friendship_repository.follow(user.id, self.user_id)
|
119
125
|
end if user_id == self.user_id
|
120
126
|
yield users
|
121
127
|
end
|
@@ -131,7 +137,7 @@ module Twterm
|
|
131
137
|
send_request do
|
132
138
|
rest_client.friend_ids(user_id).each_slice(100) do |user_ids|
|
133
139
|
m.synchronize do
|
134
|
-
yield rest_client.users(*user_ids).map
|
140
|
+
yield rest_client.users(*user_ids).map { |u| user_repository.create(u) }
|
135
141
|
end
|
136
142
|
end
|
137
143
|
end
|
@@ -140,10 +146,10 @@ module Twterm
|
|
140
146
|
def home_timeline
|
141
147
|
send_request do
|
142
148
|
rest_client.home_timeline(count: 200)
|
143
|
-
end.then do |
|
144
|
-
|
149
|
+
end.then do |tweets|
|
150
|
+
tweets
|
145
151
|
.select(&@mute_filter)
|
146
|
-
.map
|
152
|
+
.map { |tweet| status_repository.create(tweet) }
|
147
153
|
end
|
148
154
|
end
|
149
155
|
|
@@ -151,7 +157,7 @@ module Twterm
|
|
151
157
|
send_request do
|
152
158
|
rest_client.list(list_id)
|
153
159
|
end.then do |list|
|
154
|
-
|
160
|
+
list_repository.create(list)
|
155
161
|
end
|
156
162
|
end
|
157
163
|
|
@@ -163,7 +169,7 @@ module Twterm
|
|
163
169
|
end.then do |statuses|
|
164
170
|
statuses
|
165
171
|
.select(&@mute_filter)
|
166
|
-
.map
|
172
|
+
.map { |tweet| status_repository.create(tweet) }
|
167
173
|
end
|
168
174
|
end
|
169
175
|
|
@@ -171,12 +177,13 @@ module Twterm
|
|
171
177
|
send_request do
|
172
178
|
rest_client.lists
|
173
179
|
end.then do |lists|
|
174
|
-
lists.map { |list|
|
180
|
+
lists.map { |list| list_repository.create(list) }
|
175
181
|
end
|
176
182
|
end
|
177
183
|
|
178
184
|
def lookup_friendships
|
179
|
-
|
185
|
+
repo = friendship_repository
|
186
|
+
user_ids = user_repository.ids.reject { |id| repo.already_looked_up?(id) }
|
180
187
|
send_request_without_catch do
|
181
188
|
user_ids.each_slice(100) do |chunked_user_ids|
|
182
189
|
friendships = rest_client.friendships(*chunked_user_ids)
|
@@ -185,13 +192,13 @@ module Twterm
|
|
185
192
|
client_id = user_id
|
186
193
|
|
187
194
|
conn = friendship.connections
|
188
|
-
conn.include?('blocking') ?
|
189
|
-
conn.include?('following') ?
|
190
|
-
conn.include?('following_requested') ?
|
191
|
-
conn.include?('followed_by') ?
|
192
|
-
conn.include?('muting') ?
|
195
|
+
conn.include?('blocking') ? repo.block(client_id, id) : repo.unblock(client_id, id)
|
196
|
+
conn.include?('following') ? repo.follow(client_id, id) : repo.unfollow(client_id, id)
|
197
|
+
conn.include?('following_requested') ? repo.following_requested(client_id, id) : repo.following_not_requested(client_id, id)
|
198
|
+
conn.include?('followed_by') ? repo.follow(id, client_id) : repo.unfollow(id, client_id)
|
199
|
+
conn.include?('muting') ? repo.mute(client_id, id) : repo.unmute(client_id, id)
|
193
200
|
|
194
|
-
|
201
|
+
repo.looked_up!(id)
|
195
202
|
end
|
196
203
|
end
|
197
204
|
end.catch do |e|
|
@@ -204,13 +211,21 @@ module Twterm
|
|
204
211
|
end.catch(&show_error)
|
205
212
|
end
|
206
213
|
|
214
|
+
def memberships(user_id, options = {})
|
215
|
+
send_request do
|
216
|
+
user_id.nil? ? rest_client.memberships(options) : rest_client.memberships(user_id, options)
|
217
|
+
end.then do |cursor|
|
218
|
+
cursor.map { |list| list_repository.create(list) }
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
207
222
|
def mentions
|
208
223
|
send_request do
|
209
224
|
rest_client.mentions(count: 200)
|
210
225
|
end.then do |statuses|
|
211
226
|
statuses
|
212
227
|
.select(&@mute_filter)
|
213
|
-
.map
|
228
|
+
.map { |tweet| status_repository.create(tweet) }
|
214
229
|
end
|
215
230
|
end
|
216
231
|
|
@@ -219,11 +234,19 @@ module Twterm
|
|
219
234
|
rest_client.mute(*user_ids)
|
220
235
|
end.then do |users|
|
221
236
|
users.each do |user|
|
222
|
-
|
237
|
+
friendship_repository.mute(self.user_id, user.id)
|
223
238
|
end
|
224
239
|
end
|
225
240
|
end
|
226
241
|
|
242
|
+
def owned_lists
|
243
|
+
send_request do
|
244
|
+
rest_client.owned_lists
|
245
|
+
end.then do |lists|
|
246
|
+
lists.map { |list| list_repository.create(list) }
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
227
250
|
def post(text, in_reply_to = nil)
|
228
251
|
send_request do
|
229
252
|
if in_reply_to.is_a? Status
|
@@ -232,20 +255,29 @@ module Twterm
|
|
232
255
|
else
|
233
256
|
rest_client.update(text)
|
234
257
|
end
|
235
|
-
publish(Event::Notification.new(
|
258
|
+
publish(Event::Notification::Success.new('Your tweet has been posted'))
|
236
259
|
end
|
237
260
|
end
|
238
261
|
|
262
|
+
def rate_limit_status
|
263
|
+
send_request { Twitter::REST::Request.new(rest_client, :get, '/1.1/application/rate_limit_status.json').perform }
|
264
|
+
end
|
265
|
+
|
266
|
+
def remove_list_member(list_id, user_id)
|
267
|
+
send_request { rest_client.remove_list_member(list_id, user_id) }
|
268
|
+
end
|
269
|
+
|
239
270
|
def retweet(status)
|
240
271
|
fail ArgumentError,
|
241
272
|
'argument must be an instance of Status class' unless status.is_a? Status
|
242
273
|
|
243
274
|
send_request_without_catch do
|
244
275
|
rest_client.retweet!(status.id)
|
245
|
-
end.then do
|
246
|
-
|
247
|
-
|
248
|
-
|
276
|
+
end.then do |tweet, *_|
|
277
|
+
status_repository.create(tweet)
|
278
|
+
|
279
|
+
publish(Event::Notification::Success.new('Successfully retweeted: @%s "%s"' % [
|
280
|
+
tweet.user.screen_name, status.text
|
249
281
|
]))
|
250
282
|
end.catch do |reason|
|
251
283
|
message =
|
@@ -255,15 +287,11 @@ module Twterm
|
|
255
287
|
when Twitter::Error::NotFound
|
256
288
|
'The status is not found'
|
257
289
|
when Twitter::Error::Forbidden
|
258
|
-
|
259
|
-
'You cannot retweet your own status'
|
260
|
-
else # when the status is not mine
|
261
|
-
'The status is protected'
|
262
|
-
end
|
290
|
+
'The status is protected'
|
263
291
|
else
|
264
292
|
raise e
|
265
293
|
end
|
266
|
-
publish(Event::Notification.new(
|
294
|
+
publish(Event::Notification::Error.new("Retweet attempt failed: #{message}"))
|
267
295
|
end.catch(&show_error)
|
268
296
|
end
|
269
297
|
|
@@ -279,7 +307,7 @@ module Twterm
|
|
279
307
|
end.then do |statuses|
|
280
308
|
statuses
|
281
309
|
.map(&Twitter::Tweet.method(:new))
|
282
|
-
.map
|
310
|
+
.map { |tweet| status_repository.create(tweet) }
|
283
311
|
end
|
284
312
|
end
|
285
313
|
|
@@ -287,7 +315,7 @@ module Twterm
|
|
287
315
|
send_request do
|
288
316
|
rest_client.status(status_id)
|
289
317
|
end.then do |status|
|
290
|
-
|
318
|
+
status_repository.create(status)
|
291
319
|
end
|
292
320
|
end
|
293
321
|
|
@@ -302,7 +330,7 @@ module Twterm
|
|
302
330
|
raise reason
|
303
331
|
end
|
304
332
|
end.catch(&show_error).then do |user|
|
305
|
-
user.nil? ? nil :
|
333
|
+
user.nil? ? nil : user_repository.create(user)
|
306
334
|
end
|
307
335
|
end
|
308
336
|
|
@@ -311,7 +339,7 @@ module Twterm
|
|
311
339
|
rest_client.unblock(*user_ids)
|
312
340
|
end.then do |users|
|
313
341
|
users.each do |user|
|
314
|
-
|
342
|
+
friendship_repository.unblock(self.user_id, user.id)
|
315
343
|
end
|
316
344
|
end
|
317
345
|
end
|
@@ -322,10 +350,11 @@ module Twterm
|
|
322
350
|
|
323
351
|
send_request do
|
324
352
|
rest_client.unfavorite(status.id)
|
325
|
-
end.then do
|
326
|
-
|
327
|
-
|
328
|
-
|
353
|
+
end.then do |tweet, *_|
|
354
|
+
status_repository.create(tweet)
|
355
|
+
|
356
|
+
publish(Event::Notification::Success.new('Successfully unliked: @%s "%s"' % [
|
357
|
+
tweet.user.screen_name, status.text
|
329
358
|
]))
|
330
359
|
end
|
331
360
|
end
|
@@ -335,7 +364,7 @@ module Twterm
|
|
335
364
|
rest_client.unfollow(*user_ids)
|
336
365
|
end.then do |users|
|
337
366
|
users.each do |user|
|
338
|
-
|
367
|
+
friendship_repository.unfollow(self.user_id, user.id)
|
339
368
|
end
|
340
369
|
end
|
341
370
|
end
|
@@ -345,18 +374,39 @@ module Twterm
|
|
345
374
|
rest_client.unmute(*user_ids)
|
346
375
|
end.then do |users|
|
347
376
|
users.each do |user|
|
348
|
-
|
377
|
+
friendship_repository.unmute(self.user_id, user.id)
|
349
378
|
end
|
350
379
|
end
|
351
380
|
end
|
352
381
|
|
382
|
+
def unretweet(status)
|
383
|
+
send_request do
|
384
|
+
Twitter::REST::Request.new(rest_client, :post, "/1.1/statuses/unretweet/#{status.id}.json").perform
|
385
|
+
end
|
386
|
+
.then do |json, *_|
|
387
|
+
json[:retweet_count] -= 1
|
388
|
+
json[:retweeted] = false
|
389
|
+
|
390
|
+
Twitter::Tweet.new(json)
|
391
|
+
end
|
392
|
+
.then do |tweet|
|
393
|
+
status = status_repository.create(tweet)
|
394
|
+
|
395
|
+
publish(Event::Notification::Success.new('Successfully unretweeted: @%s "%s"' % [
|
396
|
+
tweet.user.screen_name, status.text
|
397
|
+
]))
|
398
|
+
|
399
|
+
status
|
400
|
+
end
|
401
|
+
end
|
402
|
+
|
353
403
|
def user_timeline(user_id)
|
354
404
|
send_request do
|
355
405
|
rest_client.user_timeline(user_id, count: 200)
|
356
406
|
end.then do |statuses|
|
357
407
|
statuses
|
358
408
|
.select(&@mute_filter)
|
359
|
-
.map
|
409
|
+
.map { |tweet| status_repository.create(tweet) }
|
360
410
|
end
|
361
411
|
end
|
362
412
|
|
@@ -374,13 +424,7 @@ module Twterm
|
|
374
424
|
end
|
375
425
|
|
376
426
|
def send_request_without_catch(&block)
|
377
|
-
Promise.
|
378
|
-
begin
|
379
|
-
resolve.(block.call)
|
380
|
-
rescue Twitter::Error => reason
|
381
|
-
reject.(reason)
|
382
|
-
end
|
383
|
-
end
|
427
|
+
Concurrent::Promise.execute { block.call }
|
384
428
|
end
|
385
429
|
|
386
430
|
private
|
@@ -393,7 +437,7 @@ module Twterm
|
|
393
437
|
proc do |e|
|
394
438
|
case e
|
395
439
|
when Twitter::Error
|
396
|
-
publish(Event::Notification.new(
|
440
|
+
publish(Event::Notification::Error.new("Failed to send request: #{e.message}"))
|
397
441
|
else
|
398
442
|
raise e
|
399
443
|
end
|
data/lib/twterm/screen.rb
CHANGED
@@ -1,16 +1,18 @@
|
|
1
1
|
require 'twterm/event/screen/resize'
|
2
|
+
require 'twterm/key_mapper'
|
2
3
|
require 'twterm/subscriber'
|
3
4
|
|
4
5
|
module Twterm
|
5
6
|
class Screen
|
6
|
-
include Singleton
|
7
7
|
include Subscriber
|
8
8
|
include Curses
|
9
9
|
|
10
|
-
def initialize
|
10
|
+
def initialize(app, client)
|
11
|
+
@app, @client = app, client
|
12
|
+
|
11
13
|
@screen = init_screen
|
12
14
|
noecho
|
13
|
-
|
15
|
+
raw
|
14
16
|
curs_set(0)
|
15
17
|
stdscr.keypad(true)
|
16
18
|
start_color
|
@@ -20,21 +22,23 @@ module Twterm
|
|
20
22
|
end
|
21
23
|
|
22
24
|
def refresh
|
23
|
-
|
24
|
-
|
25
|
+
app.tab_manager.refresh_window
|
26
|
+
app.tab_manager.current_tab.render
|
25
27
|
Notifier.instance.show
|
26
28
|
end
|
27
29
|
|
28
30
|
def respond_to_key(key)
|
31
|
+
k = KeyMapper.instance
|
32
|
+
|
29
33
|
case key
|
30
|
-
when
|
31
|
-
|
34
|
+
when k[:status, :compose]
|
35
|
+
app.tweetbox.compose
|
32
36
|
return
|
33
|
-
when
|
34
|
-
|
35
|
-
when
|
36
|
-
tab = Tab::KeyAssignmentsCheatsheet.new
|
37
|
-
|
37
|
+
when k[:app, :quit], 3
|
38
|
+
app.quit
|
39
|
+
when k[:app, :cheatsheet]
|
40
|
+
tab = Tab::KeyAssignmentsCheatsheet.new(app, client)
|
41
|
+
app.tab_manager.add_and_show tab
|
38
42
|
else
|
39
43
|
return false
|
40
44
|
end
|
@@ -51,6 +55,8 @@ module Twterm
|
|
51
55
|
|
52
56
|
private
|
53
57
|
|
58
|
+
attr_reader :app, :client
|
59
|
+
|
54
60
|
def resize(event)
|
55
61
|
return if closed?
|
56
62
|
|
@@ -62,12 +68,12 @@ module Twterm
|
|
62
68
|
end
|
63
69
|
|
64
70
|
def scan
|
65
|
-
|
71
|
+
app.reset_interruption_handler
|
66
72
|
|
67
73
|
key = getch
|
68
74
|
|
69
|
-
return if
|
70
|
-
return if
|
75
|
+
return if app.tab_manager.current_tab.respond_to_key(key)
|
76
|
+
return if app.tab_manager.respond_to_key(key)
|
71
77
|
respond_to_key(key)
|
72
78
|
end
|
73
79
|
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
require 'twterm/event/screen/resize'
|
2
|
+
require 'twterm/subscriber'
|
3
|
+
|
4
|
+
module Twterm
|
5
|
+
class SearchQueryWindow
|
6
|
+
include Curses
|
7
|
+
include Singleton
|
8
|
+
include Subscriber
|
9
|
+
|
10
|
+
class CancelInput < StandardError; end
|
11
|
+
|
12
|
+
attr_reader :last_query
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@window = stdscr.subwin(1, stdscr.maxx, stdscr.maxy - 1, 0)
|
16
|
+
@searching_down = true
|
17
|
+
@str = ''
|
18
|
+
@last_query = ''
|
19
|
+
|
20
|
+
subscribe(Event::Screen::Resize, :resize)
|
21
|
+
end
|
22
|
+
|
23
|
+
def input
|
24
|
+
@str = ''
|
25
|
+
render_current_string
|
26
|
+
|
27
|
+
Curses.timeout = 10
|
28
|
+
|
29
|
+
chars = []
|
30
|
+
|
31
|
+
loop do
|
32
|
+
char = getch
|
33
|
+
|
34
|
+
if char.nil?
|
35
|
+
case chars.first
|
36
|
+
when 3, 27 # cancel with <C-c> / Esc
|
37
|
+
raise CancelInput
|
38
|
+
when 4 # cancel with <C-d> when query is empty
|
39
|
+
raise CancelInput if @str.empty?
|
40
|
+
when 10 # submit with <C-j>
|
41
|
+
@str = last_query.to_s if @str.empty?
|
42
|
+
break
|
43
|
+
when 127 # backspace
|
44
|
+
raise CancelInput if @str.empty?
|
45
|
+
|
46
|
+
@str.chop!
|
47
|
+
render_current_string
|
48
|
+
when 0..31
|
49
|
+
# ignore control codes (\x00 - \x1f)
|
50
|
+
else
|
51
|
+
next if chars.empty?
|
52
|
+
@str << chars
|
53
|
+
.map { |x| x.is_a?(String) ? x.ord : x }
|
54
|
+
.pack('c*')
|
55
|
+
.force_encoding('utf-8')
|
56
|
+
render_current_string
|
57
|
+
end
|
58
|
+
|
59
|
+
chars = []
|
60
|
+
else
|
61
|
+
chars << char
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
@last_query = @str unless @str.empty?
|
66
|
+
last_query
|
67
|
+
rescue CancelInput
|
68
|
+
@str = ''
|
69
|
+
clear
|
70
|
+
ensure
|
71
|
+
Curses.timeout = -1
|
72
|
+
end
|
73
|
+
|
74
|
+
def clear
|
75
|
+
window.clear
|
76
|
+
window.refresh
|
77
|
+
end
|
78
|
+
|
79
|
+
def render_last_query
|
80
|
+
render(last_query) unless last_query.empty?
|
81
|
+
end
|
82
|
+
|
83
|
+
def searching_backward!
|
84
|
+
@searching_forward = false
|
85
|
+
end
|
86
|
+
|
87
|
+
def searching_backward?
|
88
|
+
!@searching_forward
|
89
|
+
end
|
90
|
+
|
91
|
+
def searching_down!
|
92
|
+
@searching_down = true
|
93
|
+
end
|
94
|
+
|
95
|
+
def searching_down?
|
96
|
+
@searching_down
|
97
|
+
end
|
98
|
+
|
99
|
+
def searching_forward!
|
100
|
+
@searching_forward = true
|
101
|
+
end
|
102
|
+
|
103
|
+
def searching_forward?
|
104
|
+
@searching_forward
|
105
|
+
end
|
106
|
+
|
107
|
+
def searching_up!
|
108
|
+
@searching_down = false
|
109
|
+
end
|
110
|
+
|
111
|
+
def searching_up?
|
112
|
+
!@searching_down
|
113
|
+
end
|
114
|
+
|
115
|
+
private
|
116
|
+
|
117
|
+
attr_reader :window
|
118
|
+
|
119
|
+
def resize(event)
|
120
|
+
window.resize(1, stdscr.maxx)
|
121
|
+
window.move(stdscr.maxy - 1, 0)
|
122
|
+
end
|
123
|
+
|
124
|
+
def render(str)
|
125
|
+
window.clear
|
126
|
+
window.setpos(0, 0)
|
127
|
+
window.addstr("#{symbol}#{str}")
|
128
|
+
window.refresh
|
129
|
+
end
|
130
|
+
|
131
|
+
def render_current_string
|
132
|
+
render(@str)
|
133
|
+
end
|
134
|
+
|
135
|
+
def symbol
|
136
|
+
searching_down? ^ searching_forward? ? '?' : '/'
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|