twterm 2.6.0 → 2.10.1
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/.circleci/config.yml +62 -0
- data/.gitignore +1 -0
- data/Gemfile +7 -0
- data/Makefile +21 -0
- data/README.md +52 -6
- data/bin/twterm +1 -3
- data/default.nix +21 -0
- data/gemset.nix +5130 -0
- data/lib/twterm/app.rb +13 -24
- data/lib/twterm/client.rb +1 -4
- data/lib/twterm/color_manager.rb +8 -9
- data/lib/twterm/image.rb +31 -0
- data/lib/twterm/image/attr.rb +42 -0
- data/lib/twterm/image/bold.rb +7 -21
- data/lib/twterm/image/color.rb +9 -15
- data/lib/twterm/image/dim.rb +13 -0
- data/lib/twterm/image/underlined.rb +17 -0
- data/lib/twterm/image_builder/user_name_image_builder.rb +1 -0
- data/lib/twterm/key_mapper.rb +6 -8
- data/lib/twterm/key_mapper/abstract_key_mapper.rb +2 -2
- data/lib/twterm/list.rb +36 -1
- data/lib/twterm/message_window.rb +4 -13
- data/lib/twterm/persistable_configuration_proxy.rb +6 -6
- data/lib/twterm/preferences.rb +8 -1
- data/lib/twterm/rest_client.rb +0 -33
- data/lib/twterm/screen.rb +103 -25
- data/lib/twterm/search_query_window.rb +5 -13
- data/lib/twterm/status.rb +10 -0
- data/lib/twterm/tab/abstract_tab.rb +30 -16
- data/lib/twterm/tab/new/index.rb +0 -10
- data/lib/twterm/tab/new/search.rb +2 -2
- data/lib/twterm/tab/new/user.rb +2 -2
- data/lib/twterm/tab/preferences/control.rb +77 -0
- data/lib/twterm/tab/preferences/index.rb +6 -0
- data/lib/twterm/tab/scrollable.rb +1 -1
- data/lib/twterm/tab/searchable.rb +6 -4
- data/lib/twterm/tab/status_tab.rb +10 -0
- data/lib/twterm/tab/statuses/abstract_statuses_tab.rb +11 -6
- data/lib/twterm/tab/user_tab.rb +0 -9
- data/lib/twterm/tab_manager.rb +77 -10
- data/lib/twterm/tweetbox.rb +2 -3
- data/lib/twterm/user.rb +1 -0
- data/lib/twterm/version.rb +1 -1
- data/nix/Gemfile +3 -0
- data/nix/Gemfile.lock +77 -0
- data/nix/gemset.nix +325 -0
- data/shell.nix +40 -0
- data/spec/twterm/image/bold_spec.rb +30 -0
- data/spec/twterm/image/color_spec.rb +16 -0
- data/spec/twterm/image/dim_spec.rb +30 -0
- data/twterm.gemspec +7 -14
- metadata +31 -113
- data/.travis.yml +0 -12
- data/lib/twterm/direct_message.rb +0 -60
- data/lib/twterm/direct_message_composer.rb +0 -80
- data/lib/twterm/direct_message_manager.rb +0 -51
- data/lib/twterm/event/direct_message/fetched.rb +0 -10
- data/lib/twterm/event/notification/direct_message.rb +0 -30
- data/lib/twterm/event/screen/resize.rb +0 -13
- data/lib/twterm/repository/direct_message_repository.rb +0 -14
- data/lib/twterm/tab/direct_message/conversation.rb +0 -104
- data/lib/twterm/tab/direct_message/conversation_list.rb +0 -100
- data/spec/twterm/event/screen/resize_spec.rb +0 -11
data/lib/twterm/tab/new/index.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'twterm/tab/abstract_tab'
|
2
|
-
require 'twterm/tab/direct_message/conversation_list'
|
3
2
|
require 'twterm/tab/rate_limit_status'
|
4
3
|
require 'twterm/tab/preferences/index'
|
5
4
|
|
@@ -19,7 +18,6 @@ module Twterm
|
|
19
18
|
|
20
19
|
def items
|
21
20
|
%i(
|
22
|
-
direct_messages
|
23
21
|
list_tab
|
24
22
|
search_tab
|
25
23
|
user_tab
|
@@ -60,8 +58,6 @@ module Twterm
|
|
60
58
|
|
61
59
|
desc =
|
62
60
|
case item
|
63
|
-
when :direct_messages
|
64
|
-
'Direct messages'
|
65
61
|
when :list_tab
|
66
62
|
'List tab'
|
67
63
|
when :search_tab
|
@@ -82,10 +78,6 @@ module Twterm
|
|
82
78
|
.reduce(Image.empty, :|)
|
83
79
|
end
|
84
80
|
|
85
|
-
def open_direct_messages
|
86
|
-
switch(Tab::DirectMessage::ConversationList.new(app, client))
|
87
|
-
end
|
88
|
-
|
89
81
|
def open_list_tab
|
90
82
|
switch(Tab::New::List.new(app, client))
|
91
83
|
end
|
@@ -114,8 +106,6 @@ module Twterm
|
|
114
106
|
|
115
107
|
def perform_selected_action
|
116
108
|
case current_item
|
117
|
-
when :direct_messages
|
118
|
-
open_direct_messages
|
119
109
|
when :list_tab
|
120
110
|
open_list_tab
|
121
111
|
when :search_tab
|
@@ -32,13 +32,13 @@ module Twterm
|
|
32
32
|
|
33
33
|
def invoke_input
|
34
34
|
resetter = proc do
|
35
|
-
reset_prog_mode
|
35
|
+
Curses.reset_prog_mode
|
36
36
|
sleep 0.1
|
37
37
|
publish(Event::Screen::Refresh.new)
|
38
38
|
end
|
39
39
|
|
40
40
|
input_thread = Thread.new do
|
41
|
-
close_screen
|
41
|
+
Curses.close_screen
|
42
42
|
app.completion_manager.set_search_mode!
|
43
43
|
puts "\ninput search query"
|
44
44
|
query = (readline('> ', true) || '').strip
|
data/lib/twterm/tab/new/user.rb
CHANGED
@@ -16,7 +16,7 @@ module Twterm
|
|
16
16
|
|
17
17
|
def invoke_input
|
18
18
|
resetter = proc do
|
19
|
-
reset_prog_mode
|
19
|
+
Curses.reset_prog_mode
|
20
20
|
sleep 0.1
|
21
21
|
publish(Event::Screen::Refresh.new)
|
22
22
|
end
|
@@ -24,7 +24,7 @@ module Twterm
|
|
24
24
|
app.completion_manager.set_screen_name_mode!
|
25
25
|
|
26
26
|
input_thread = Thread.new do
|
27
|
-
close_screen
|
27
|
+
Curses.close_screen
|
28
28
|
puts "\nSearch user"
|
29
29
|
screen_name = (readline('> @', true) || '').strip
|
30
30
|
resetter.call
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'twterm/image'
|
2
|
+
require 'twterm/preferences'
|
3
|
+
require 'twterm/publisher'
|
4
|
+
require 'twterm/tab/abstract_tab'
|
5
|
+
require 'twterm/tab/scrollable'
|
6
|
+
|
7
|
+
module Twterm
|
8
|
+
module Tab
|
9
|
+
module Preferences
|
10
|
+
class Control < AbstractTab
|
11
|
+
include Scrollable
|
12
|
+
include Publisher
|
13
|
+
|
14
|
+
def drawable_item_count
|
15
|
+
1
|
16
|
+
end
|
17
|
+
|
18
|
+
def image
|
19
|
+
drawable_items.map.with_index do |item, i|
|
20
|
+
curr = scroller.current_index?(i)
|
21
|
+
cursor = Image.cursor(2, curr)
|
22
|
+
options = Image.toggle_switch(['traditional', 'natural'], app.preferences[:control, item])
|
23
|
+
desc =
|
24
|
+
case item
|
25
|
+
when :scroll_direction
|
26
|
+
header = Image.string('Scroll direction')
|
27
|
+
body = Image.string(' ') - options
|
28
|
+
cursor - Image.whitespace - (header | body)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
.intersperse(Image.blank_line)
|
32
|
+
.reduce(Image.empty) { |acc, x| acc | x }
|
33
|
+
end
|
34
|
+
|
35
|
+
def items
|
36
|
+
[
|
37
|
+
:scroll_direction,
|
38
|
+
]
|
39
|
+
end
|
40
|
+
|
41
|
+
def respond_to_key(key)
|
42
|
+
return true if scroller.respond_to_key(key)
|
43
|
+
|
44
|
+
case key
|
45
|
+
when 10
|
46
|
+
perform_selected_action
|
47
|
+
end
|
48
|
+
|
49
|
+
false
|
50
|
+
end
|
51
|
+
|
52
|
+
def title
|
53
|
+
'Control preferences'
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def perform_selected_action
|
59
|
+
item = scroller.current_item
|
60
|
+
|
61
|
+
case item
|
62
|
+
when :scroll_direction
|
63
|
+
app.preferences[:control, :scroll_direction] =
|
64
|
+
case app.preferences[:control, :scroll_direction]
|
65
|
+
when 'natural'
|
66
|
+
'traditional'
|
67
|
+
when 'traditional'
|
68
|
+
'natural'
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
render
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'twterm/image'
|
2
|
+
require 'twterm/tab/preferences/control'
|
2
3
|
require 'twterm/tab/preferences/notification_backend'
|
3
4
|
require 'twterm/tab/preferences/photo_viewer_backend'
|
4
5
|
require 'twterm/preferences'
|
@@ -26,6 +27,8 @@ module Twterm
|
|
26
27
|
cursor = Image.cursor(1, curr)
|
27
28
|
desc =
|
28
29
|
case item
|
30
|
+
when :control
|
31
|
+
'Control preferences'
|
29
32
|
when :notification_backend
|
30
33
|
'Notification backend preferences'
|
31
34
|
when :photo_viewer_backend
|
@@ -40,6 +43,7 @@ module Twterm
|
|
40
43
|
|
41
44
|
def items
|
42
45
|
[
|
46
|
+
:control,
|
43
47
|
:notification_backend,
|
44
48
|
:photo_viewer_backend,
|
45
49
|
]
|
@@ -67,6 +71,8 @@ module Twterm
|
|
67
71
|
def open
|
68
72
|
tab =
|
69
73
|
case scroller.current_item
|
74
|
+
when :control
|
75
|
+
Tab::Preferences::Control.new(app, client)
|
70
76
|
when :notification_backend
|
71
77
|
Tab::Preferences::NotificationBackend.new(app, client)
|
72
78
|
when :photo_viewer_backend
|
@@ -27,7 +27,7 @@ module Twterm
|
|
27
27
|
attr_reader :index, :offset
|
28
28
|
|
29
29
|
attr_accessor :delegate
|
30
|
-
def_delegators :delegate, :items, :total_item_count, :drawable_item_count
|
30
|
+
def_delegators :delegate, :items, :total_item_count, :drawable_item_count, :search_query_window
|
31
31
|
|
32
32
|
def after_move(&block)
|
33
33
|
add_hook(:after_move, &block)
|
@@ -14,6 +14,12 @@ module Twterm
|
|
14
14
|
raise NotImplementedError, '`matches?` method must be implemented'
|
15
15
|
end
|
16
16
|
|
17
|
+
# @abstract
|
18
|
+
# @return [Twterm::SearchQueryWindow]
|
19
|
+
def search_query_window
|
20
|
+
raise NotImplementedError, '`search_query_window` method must be implemented'
|
21
|
+
end
|
22
|
+
|
17
23
|
class Scroller < Scrollable::Scroller
|
18
24
|
extend Forwardable
|
19
25
|
include Publisher
|
@@ -122,10 +128,6 @@ module Twterm
|
|
122
128
|
end
|
123
129
|
end
|
124
130
|
|
125
|
-
def search_query_window
|
126
|
-
SearchQueryWindow.instance
|
127
|
-
end
|
128
|
-
|
129
131
|
alias_method :count, :total_item_count
|
130
132
|
end
|
131
133
|
end
|
@@ -67,6 +67,7 @@ module Twterm
|
|
67
67
|
|
68
68
|
def items
|
69
69
|
[
|
70
|
+
:show_conversation,
|
70
71
|
:reply,
|
71
72
|
:favorite,
|
72
73
|
:retweet,
|
@@ -135,6 +136,8 @@ module Twterm
|
|
135
136
|
Image.string('Quote this tweet')
|
136
137
|
when :destroy
|
137
138
|
Image.string('Delete this tweet')
|
139
|
+
when :show_conversation
|
140
|
+
Image.string("Show conversation")
|
138
141
|
when :show_user
|
139
142
|
Image.string("Show user (@#{user.screen_name})")
|
140
143
|
when :open_in_browser
|
@@ -172,6 +175,8 @@ module Twterm
|
|
172
175
|
quote!
|
173
176
|
when :destroy
|
174
177
|
destroy!
|
178
|
+
when :show_conversation
|
179
|
+
show_conversation!
|
175
180
|
when :show_user
|
176
181
|
show_user!
|
177
182
|
when :open_in_browser
|
@@ -209,6 +214,11 @@ module Twterm
|
|
209
214
|
.then { render }
|
210
215
|
end
|
211
216
|
|
217
|
+
def show_conversation!
|
218
|
+
tab = Tab::Statuses::Conversation.new(app, client, status_id)
|
219
|
+
app.tab_manager.add_and_show(tab)
|
220
|
+
end
|
221
|
+
|
212
222
|
def show_user!
|
213
223
|
user_id = status.user_id
|
214
224
|
user_tab = Tab::UserTab.new(app, client, user_id)
|
@@ -27,7 +27,7 @@ module Twterm
|
|
27
27
|
return if @status_ids.include?(status.id)
|
28
28
|
|
29
29
|
@status_ids.push(status.id)
|
30
|
-
status.split(window.maxx -
|
30
|
+
status.split(window.maxx - 2)
|
31
31
|
scroller.item_appended!
|
32
32
|
render
|
33
33
|
end
|
@@ -46,7 +46,7 @@ module Twterm
|
|
46
46
|
|
47
47
|
def drawable_item_count
|
48
48
|
statuses.drop(scroller.offset).lazy
|
49
|
-
.map { |s| s.split(window.maxx -
|
49
|
+
.map { |s| s.split(window.maxx - 2).count + 2 }
|
50
50
|
.scan(0, :+)
|
51
51
|
.each_cons(2)
|
52
52
|
.select { |_, l| l < window.maxy }
|
@@ -113,7 +113,7 @@ module Twterm
|
|
113
113
|
return if @status_ids.include?(status.id)
|
114
114
|
|
115
115
|
@status_ids.unshift(status.id)
|
116
|
-
status.split(window.maxx -
|
116
|
+
status.split(window.maxx - 2)
|
117
117
|
scroller.item_prepended!
|
118
118
|
render
|
119
119
|
end
|
@@ -177,6 +177,11 @@ module Twterm
|
|
177
177
|
.then { render }
|
178
178
|
end
|
179
179
|
|
180
|
+
# for the sake of Twterm::Tab::Searchable
|
181
|
+
def search_query_window
|
182
|
+
app.search_query_window
|
183
|
+
end
|
184
|
+
|
180
185
|
def show_conversation
|
181
186
|
status = highlighted_original_status
|
182
187
|
|
@@ -226,16 +231,16 @@ module Twterm
|
|
226
231
|
|
227
232
|
header = [
|
228
233
|
ImageBuilder::UserNameImageBuilder.new(user).build,
|
229
|
-
Image.string(original.date.to_s).brackets,
|
234
|
+
Image.string(original.date.to_s).brackets.dim,
|
230
235
|
(Image.whitespace.color(:black, :red) if original.favorited?),
|
231
236
|
(Image.whitespace.color(:black, :green) if original.retweeted?),
|
232
|
-
((Image.string('retweeted by ') - !Image.string("@#{retweeted_by.screen_name}")).parens if status.retweet?),
|
237
|
+
((Image.string('retweeted by ') - !Image.string("@#{retweeted_by.screen_name}")).parens.dim if status.retweet?),
|
233
238
|
((Image.number(original.favorite_count) - Image.plural(original.favorite_count, 'like')).color(:red) if original.favorite_count.positive?),
|
234
239
|
((Image.number(original.retweet_count) - Image.plural(original.retweet_count, 'RT')).color(:green) if original.retweet_count.positive?),
|
235
240
|
].compact.intersperse(Image.whitespace).reduce(Image.empty, :-)
|
236
241
|
|
237
242
|
body = original
|
238
|
-
.split(window.maxx -
|
243
|
+
.split(window.maxx - 2)
|
239
244
|
.map(&Image.method(:string))
|
240
245
|
.reduce(Image.empty, :|)
|
241
246
|
|
data/lib/twterm/tab/user_tab.rb
CHANGED
@@ -53,7 +53,6 @@ module Twterm
|
|
53
53
|
:profile_image,
|
54
54
|
(:profile_background_image unless user.profile_background_image.nil?),
|
55
55
|
:manage_lists,
|
56
|
-
(:compose_direct_message unless myself?),
|
57
56
|
(:open_website unless user.website.nil?),
|
58
57
|
(:toggle_follow unless myself?),
|
59
58
|
(:toggle_mute unless myself?),
|
@@ -96,10 +95,6 @@ module Twterm
|
|
96
95
|
app.friendship_repository.blocking?(client.user_id, user_id)
|
97
96
|
end
|
98
97
|
|
99
|
-
def compose_direct_message
|
100
|
-
app.direct_message_composer.compose(user)
|
101
|
-
end
|
102
|
-
|
103
98
|
def follow
|
104
99
|
client.follow(user_id).then do |users|
|
105
100
|
render
|
@@ -176,8 +171,6 @@ module Twterm
|
|
176
171
|
|
177
172
|
def perform_selected_action
|
178
173
|
case scroller.current_item
|
179
|
-
when :compose_direct_message
|
180
|
-
compose_direct_message
|
181
174
|
when :manage_lists
|
182
175
|
open_list_management_tab
|
183
176
|
when :open_in_browser
|
@@ -294,8 +287,6 @@ module Twterm
|
|
294
287
|
curr = scroller.current_index?(i)
|
295
288
|
Image.cursor(1, curr) - Image.whitespace -
|
296
289
|
case item
|
297
|
-
when :compose_direct_message
|
298
|
-
Image.string('Compose direct message')
|
299
290
|
when :toggle_block
|
300
291
|
if blocking?
|
301
292
|
Image.string('Unblock this user')
|
data/lib/twterm/tab_manager.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'twterm/event/screen/resize'
|
2
1
|
require 'twterm/publisher'
|
3
2
|
require 'twterm/subscriber'
|
4
3
|
require 'twterm/utils'
|
@@ -6,7 +5,6 @@ require 'twterm/view'
|
|
6
5
|
|
7
6
|
module Twterm
|
8
7
|
class TabManager
|
9
|
-
include Curses
|
10
8
|
include Publisher
|
11
9
|
include Subscriber
|
12
10
|
include Utils
|
@@ -69,16 +67,70 @@ module Twterm
|
|
69
67
|
end
|
70
68
|
end
|
71
69
|
|
72
|
-
|
70
|
+
# Returns if the given coordinate is enclosed by the window
|
71
|
+
#
|
72
|
+
# @param x [Integer]
|
73
|
+
# @param y [Integer]
|
74
|
+
# @return [Boolean]
|
75
|
+
def enclose?(x, y)
|
76
|
+
left = @window.begx
|
77
|
+
top = @window.begy
|
78
|
+
right = left + @window.maxx
|
79
|
+
bottom = top + @window.maxy
|
80
|
+
|
81
|
+
left <= x && x < right && top <= y && y < bottom
|
82
|
+
end
|
83
|
+
|
84
|
+
# @param app [Twterm::App]
|
85
|
+
# @param client [Twterm::Client]
|
86
|
+
# @param window [Curses::Window]
|
87
|
+
def initialize(app, client, window)
|
73
88
|
@app, @client = app, client
|
74
89
|
|
75
90
|
@tabs = []
|
76
91
|
@index = 0
|
77
92
|
@history = []
|
78
93
|
|
79
|
-
@window =
|
94
|
+
@window = window
|
95
|
+
end
|
96
|
+
|
97
|
+
# Open the clicked tab
|
98
|
+
#
|
99
|
+
# @param x [Integer]
|
100
|
+
# @param _y [Integer]
|
101
|
+
#
|
102
|
+
# @return [nil]
|
103
|
+
def handle_left_click(x, _y)
|
104
|
+
n = find_tab_index_on_x(x)
|
105
|
+
return if n.nil?
|
106
|
+
|
107
|
+
show_nth_tab(n)
|
108
|
+
|
109
|
+
nil
|
110
|
+
end
|
111
|
+
|
112
|
+
# Open next tab
|
113
|
+
#
|
114
|
+
# @param _x [Integer]
|
115
|
+
# @param _y [Integer]
|
116
|
+
#
|
117
|
+
# @return [nil]
|
118
|
+
def handle_scroll_down(_x, _y)
|
119
|
+
show_next
|
80
120
|
|
81
|
-
|
121
|
+
nil
|
122
|
+
end
|
123
|
+
|
124
|
+
# Open previous tab
|
125
|
+
#
|
126
|
+
# @param _x [Integer]
|
127
|
+
# @param _y [Integer]
|
128
|
+
#
|
129
|
+
# @return [nil]
|
130
|
+
def handle_scroll_up(_x, _y)
|
131
|
+
show_previous
|
132
|
+
|
133
|
+
nil
|
82
134
|
end
|
83
135
|
|
84
136
|
def open_my_profile
|
@@ -120,10 +172,10 @@ module Twterm
|
|
120
172
|
|
121
173
|
image = @tabs
|
122
174
|
.map { |t| [t, Image.string(t.title)] }
|
123
|
-
.map { |t, r| t.equal?(current_tab) ? !r : r }
|
175
|
+
.map { |t, r| t.equal?(current_tab) ? !r._ : r }
|
124
176
|
.reduce(pipe) { |acc, x| acc - wss - x - wss - pipe }
|
125
177
|
|
126
|
-
View.new(@window, image)
|
178
|
+
View.new(@window, image)
|
127
179
|
end
|
128
180
|
|
129
181
|
def respond_to_key(key)
|
@@ -195,9 +247,24 @@ module Twterm
|
|
195
247
|
|
196
248
|
attr_reader :app, :client
|
197
249
|
|
198
|
-
|
199
|
-
|
200
|
-
|
250
|
+
# @param x [Integer]
|
251
|
+
#
|
252
|
+
# @return [Integer, nil]
|
253
|
+
def find_tab_index_on_x(x)
|
254
|
+
pos = 0
|
255
|
+
|
256
|
+
@tabs.each.with_index do |tab, index|
|
257
|
+
title = tab.title
|
258
|
+
len = title.length
|
259
|
+
left = pos + 1
|
260
|
+
right = left + len + 4 # each tab has 2 whitespaces on the both side
|
261
|
+
|
262
|
+
return index if left <= x && x < right
|
263
|
+
|
264
|
+
pos = right
|
265
|
+
end
|
266
|
+
|
267
|
+
nil
|
201
268
|
end
|
202
269
|
end
|
203
270
|
end
|