flumtter 5.0.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 +7 -0
- data/.gitignore +10 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +41 -0
- data/Rakefile +2 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/flumtter +5 -0
- data/flumtter.gemspec +31 -0
- data/lib/flumtter.rb +2 -0
- data/lib/flumtter/app/core/account_selector.rb +88 -0
- data/lib/flumtter/app/core/client.rb +148 -0
- data/lib/flumtter/app/core/command.rb +24 -0
- data/lib/flumtter/app/core/command/dm.rb +12 -0
- data/lib/flumtter/app/core/command/tweet.rb +24 -0
- data/lib/flumtter/app/core/command/user.rb +52 -0
- data/lib/flumtter/app/core/command/userlist.rb +8 -0
- data/lib/flumtter/app/core/core.rb +58 -0
- data/lib/flumtter/app/core/curses.rb +90 -0
- data/lib/flumtter/app/core/hash.rb +29 -0
- data/lib/flumtter/app/core/initializer.rb +28 -0
- data/lib/flumtter/app/core/keyboard.rb +54 -0
- data/lib/flumtter/app/core/plugins.rb +27 -0
- data/lib/flumtter/app/core/string.rb +148 -0
- data/lib/flumtter/app/core/terminal.rb +13 -0
- data/lib/flumtter/app/core/thread.rb +29 -0
- data/lib/flumtter/app/core/toast.rb +26 -0
- data/lib/flumtter/app/core/util.rb +107 -0
- data/lib/flumtter/app/core/windows/base.rb +16 -0
- data/lib/flumtter/app/core/windows/buf_window.rb +194 -0
- data/lib/flumtter/app/core/windows/dialog.rb +62 -0
- data/lib/flumtter/app/core/windows/dmbase.rb +28 -0
- data/lib/flumtter/app/core/windows/dynamic_view.rb +43 -0
- data/lib/flumtter/app/core/windows/favorite.rb +31 -0
- data/lib/flumtter/app/core/windows/follower.rb +20 -0
- data/lib/flumtter/app/core/windows/following.rb +20 -0
- data/lib/flumtter/app/core/windows/mention.rb +29 -0
- data/lib/flumtter/app/core/windows/popup.rb +35 -0
- data/lib/flumtter/app/core/windows/tweet.rb +31 -0
- data/lib/flumtter/app/core/windows/tweetbase.rb +24 -0
- data/lib/flumtter/app/core/windows/userbase.rb +43 -0
- data/lib/flumtter/app/main.rb +3 -0
- data/lib/flumtter/app/plugins/commands.rb +15 -0
- data/lib/flumtter/app/plugins/commands/account_changer.rb +9 -0
- data/lib/flumtter/app/plugins/commands/change_profile.rb +69 -0
- data/lib/flumtter/app/plugins/commands/conversation.rb +39 -0
- data/lib/flumtter/app/plugins/commands/delete.rb +26 -0
- data/lib/flumtter/app/plugins/commands/directmessage.rb +35 -0
- data/lib/flumtter/app/plugins/commands/directmessages.rb +33 -0
- data/lib/flumtter/app/plugins/commands/favorite.rb +22 -0
- data/lib/flumtter/app/plugins/commands/mention.rb +7 -0
- data/lib/flumtter/app/plugins/commands/new_tweet.rb +17 -0
- data/lib/flumtter/app/plugins/commands/reply.rb +26 -0
- data/lib/flumtter/app/plugins/commands/retweet.rb +30 -0
- data/lib/flumtter/app/plugins/commands/unfavorite.rb +26 -0
- data/lib/flumtter/app/plugins/commands/user.rb +77 -0
- data/lib/flumtter/app/plugins/commands/utility.rb +17 -0
- data/lib/flumtter/app/plugins/load.rb +16 -0
- data/lib/flumtter/app/plugins/pry.rb +12 -0
- data/lib/flumtter/app/plugins/timeline.rb +42 -0
- data/lib/flumtter/app/plugins/timeline/base.rb +74 -0
- data/lib/flumtter/app/plugins/timeline/deleted_tweet.rb +23 -0
- data/lib/flumtter/app/plugins/timeline/dm.rb +23 -0
- data/lib/flumtter/app/plugins/timeline/event.rb +11 -0
- data/lib/flumtter/app/plugins/timeline/fav.rb +43 -0
- data/lib/flumtter/app/plugins/timeline/tweet.rb +51 -0
- data/lib/flumtter/app/plugins/toast.rb +45 -0
- data/lib/flumtter/version.rb +3 -0
- metadata +213 -0
@@ -0,0 +1,29 @@
|
|
1
|
+
=begin
|
2
|
+
module Flumtter
|
3
|
+
class FThread < Thread
|
4
|
+
extend Util
|
5
|
+
|
6
|
+
EXCEPTION = proc do |e|
|
7
|
+
exit
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.new_with_report
|
11
|
+
Thread.new do
|
12
|
+
error_handler do
|
13
|
+
yield
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.new_with_restart
|
19
|
+
Thread.new do
|
20
|
+
loop do
|
21
|
+
error_handler(EXCEPTION,EXCEPTION) do
|
22
|
+
yield
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
=end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'terminal-notifier'
|
2
|
+
|
3
|
+
module Flumtter
|
4
|
+
class Toast
|
5
|
+
def initialize(msg)
|
6
|
+
@msg = msg
|
7
|
+
@options = {title: TITLE}
|
8
|
+
if block_given?
|
9
|
+
yield(self)
|
10
|
+
show
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def show
|
15
|
+
TerminalNotifier.notify(@msg, @options) if Setting[:toast?]
|
16
|
+
end
|
17
|
+
|
18
|
+
def method_missing(method, *args)
|
19
|
+
if args.size == 1
|
20
|
+
@options[method] = args.first
|
21
|
+
else
|
22
|
+
super
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
module Flumtter
|
2
|
+
class UnSupportError < ArgumentError; end
|
3
|
+
class NoContentError < ArgumentError; end
|
4
|
+
class ExecutedError < StandardError; end
|
5
|
+
|
6
|
+
module Util
|
7
|
+
def error(e)
|
8
|
+
print <<~EOF.color(Setting[:color][:error])
|
9
|
+
#{e.backtrace.shift}: #{e.message} (#{e.class})
|
10
|
+
#{e.backtrace.join("\n")}
|
11
|
+
EOF
|
12
|
+
end
|
13
|
+
|
14
|
+
def parse_index(text, with_screen_name=false)
|
15
|
+
if m = text.match(index_regexp)
|
16
|
+
obj = id2obj(m[1])
|
17
|
+
return obj, m[2]
|
18
|
+
end
|
19
|
+
if with_screen_name && m = text.match(screen_name_regexp)
|
20
|
+
return m[1], m[2]
|
21
|
+
end
|
22
|
+
raise IndexError
|
23
|
+
end
|
24
|
+
|
25
|
+
def id2obj(id)
|
26
|
+
obj = TimeLine::Base[id.to_i]
|
27
|
+
raise IndexError if obj.nil?
|
28
|
+
obj
|
29
|
+
end
|
30
|
+
|
31
|
+
def dialog_for_index(title, body, with_screen_name=false)
|
32
|
+
dialog = Window::Dialog.new(title, body)
|
33
|
+
dialog.command(index_regexp) do |m|
|
34
|
+
[id2obj(m[1]), m[2]]
|
35
|
+
end
|
36
|
+
if with_screen_name
|
37
|
+
dialog.command(screen_name_regexp) do |m|
|
38
|
+
[m[1], m[2]]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
dialog.show(true, false)
|
42
|
+
end
|
43
|
+
|
44
|
+
def index_with_dialog(m, title, body, with_screen_name=false)
|
45
|
+
if m.empty?
|
46
|
+
dialog_for_index(title, body, with_screen_name)
|
47
|
+
else
|
48
|
+
parse_index(m, with_screen_name)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def index_regexp
|
53
|
+
/^(\d+)[ | ]*(.*)/
|
54
|
+
end
|
55
|
+
|
56
|
+
def screen_name_regexp
|
57
|
+
/^([@|@]*[A-Za-z0-9_]{1,15})[ | ]*(.*)/
|
58
|
+
end
|
59
|
+
|
60
|
+
def command_value_regexp(command)
|
61
|
+
/^#{command}[ | ]*(.*)/
|
62
|
+
end
|
63
|
+
|
64
|
+
def error_handler
|
65
|
+
begin
|
66
|
+
yield
|
67
|
+
rescue IndexError
|
68
|
+
Window::Popup::Error.new("Please select correct index.").show
|
69
|
+
rescue UnSupportError
|
70
|
+
puts "This object is unsupported.".color
|
71
|
+
rescue ExecutedError => e
|
72
|
+
text = e.message.empty? ? "The operation is already executed." : e.message
|
73
|
+
print text.dnl.color(:cyan)
|
74
|
+
rescue NoContentError
|
75
|
+
puts "Please input content.".color
|
76
|
+
rescue Twitter::Error::NotFound => e
|
77
|
+
puts e.message.color
|
78
|
+
rescue Twitter::Error::Unauthorized => e
|
79
|
+
puts e.message.color
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def if_tweet(obj, twitter)
|
84
|
+
case obj
|
85
|
+
when Twitter::Tweet
|
86
|
+
yield(obj)
|
87
|
+
when Twitter::Streaming::Event
|
88
|
+
type = obj.type(twitter)
|
89
|
+
if type.include?(:favorite) || type.include?(:unfavorite)
|
90
|
+
yield(obj.target_object)
|
91
|
+
else
|
92
|
+
raise UnSupportError
|
93
|
+
end
|
94
|
+
else
|
95
|
+
raise UnSupportError
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def sarastire(*args)
|
100
|
+
Flumtter.sarastire(*args)
|
101
|
+
end
|
102
|
+
|
103
|
+
def on_event(*args,&blk)
|
104
|
+
Flumtter.on_event(*args,&blk)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Flumtter
|
2
|
+
module Window
|
3
|
+
class Base
|
4
|
+
include Dispel::Util
|
5
|
+
|
6
|
+
def initialize(title, body,
|
7
|
+
hight=body.size_of_lines,
|
8
|
+
width=body.max_char_of_lines+2)
|
9
|
+
@title = title
|
10
|
+
@body = body
|
11
|
+
@hight = hight + 8
|
12
|
+
@width = [width,title.title.exact_size+2].max
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,194 @@
|
|
1
|
+
require_relative 'dialog'
|
2
|
+
|
3
|
+
module Flumtter
|
4
|
+
module Window
|
5
|
+
module Buf
|
6
|
+
class Buf
|
7
|
+
class NoMoreData < StandardError; end
|
8
|
+
|
9
|
+
attr_accessor :cursor
|
10
|
+
def initialize(base_cls=Element)
|
11
|
+
@base_cls = base_cls
|
12
|
+
@buf = []
|
13
|
+
@cursor = 0
|
14
|
+
end
|
15
|
+
|
16
|
+
def cursor=(n)
|
17
|
+
if n <= 0
|
18
|
+
@cursor = 0
|
19
|
+
else
|
20
|
+
@cursor = n
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def size
|
25
|
+
@buf.size
|
26
|
+
end
|
27
|
+
|
28
|
+
def [](key)
|
29
|
+
elem = @buf[key]
|
30
|
+
raise NoMoreData unless elem
|
31
|
+
elem
|
32
|
+
end
|
33
|
+
|
34
|
+
def adds(objects)
|
35
|
+
objects.each do |obj|
|
36
|
+
@buf << @base_cls.new(obj, @buf.size)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def add(object)
|
41
|
+
@buf << @base_cls.new(object, @buf.size)
|
42
|
+
end
|
43
|
+
|
44
|
+
def get
|
45
|
+
if @buf[@cursor].nil?
|
46
|
+
prefetch
|
47
|
+
end
|
48
|
+
elem = @buf[@cursor]
|
49
|
+
@cursor += 1
|
50
|
+
raise NoMoreData unless elem
|
51
|
+
elem
|
52
|
+
end
|
53
|
+
|
54
|
+
def prev
|
55
|
+
@cursor -= 1
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class Element
|
60
|
+
attr_reader :object
|
61
|
+
def initialize(object, index)
|
62
|
+
@object = object
|
63
|
+
@index = index
|
64
|
+
end
|
65
|
+
|
66
|
+
def element
|
67
|
+
@text ||= <<~EOF
|
68
|
+
#{header}
|
69
|
+
#{user}
|
70
|
+
#{body.split_num(width - 1)}
|
71
|
+
#{footer}
|
72
|
+
EOF
|
73
|
+
end
|
74
|
+
|
75
|
+
def width
|
76
|
+
Terminal.x-2
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
def header
|
81
|
+
"#{@index} ".ljust(width, ?-)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
class Screen < Dialog
|
86
|
+
include Util
|
87
|
+
EnableKey = %i(left right up down)
|
88
|
+
|
89
|
+
def initialize(buf, title, body="")
|
90
|
+
@title, @body = title, body
|
91
|
+
@commands = []
|
92
|
+
@buf = buf
|
93
|
+
@range = 0...0
|
94
|
+
end
|
95
|
+
|
96
|
+
def call(str)
|
97
|
+
if str == "?"
|
98
|
+
Window::Popup.new("Command List", <<~EOF).show
|
99
|
+
#{Command.list(@commands)}
|
100
|
+
EOF
|
101
|
+
move(:keep)
|
102
|
+
raise Dispel::Recall
|
103
|
+
elsif str == :left
|
104
|
+
move(:page)
|
105
|
+
raise Dispel::Recall
|
106
|
+
elsif str == :right
|
107
|
+
raise Dispel::Recall
|
108
|
+
elsif str == :up || str == :down
|
109
|
+
move(str)
|
110
|
+
raise Dispel::Recall
|
111
|
+
else
|
112
|
+
move(:keep)
|
113
|
+
@commands.each do |command|
|
114
|
+
if m = str.match(command.command)
|
115
|
+
command.call(m)
|
116
|
+
raise Dispel::Recall
|
117
|
+
end
|
118
|
+
end
|
119
|
+
raise Dispel::NoCommandError
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def id2obj(id)
|
124
|
+
obj = @buf[id.to_i]
|
125
|
+
raise IndexError if obj.nil?
|
126
|
+
obj.object
|
127
|
+
end
|
128
|
+
|
129
|
+
def move(type)
|
130
|
+
case type
|
131
|
+
when :up
|
132
|
+
@buf.cursor = @range.min - 1
|
133
|
+
when :down
|
134
|
+
@buf.cursor = @range.min + 1
|
135
|
+
when :page
|
136
|
+
i, count = 0, 0
|
137
|
+
begin
|
138
|
+
elem = @buf[@range.min-i].element
|
139
|
+
while (count += elem.size_of_lines + 2) < @lines
|
140
|
+
i -= 1
|
141
|
+
elem = @buf[@range.min-i].element
|
142
|
+
end
|
143
|
+
@buf.cursor = @range.min+i
|
144
|
+
rescue Buf::NoMoreData
|
145
|
+
@buf.cursor = @buf.size - 1
|
146
|
+
end
|
147
|
+
when :keep
|
148
|
+
@buf.cursor = @range.min
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def show
|
153
|
+
Dispel::Screen.open do |screen|
|
154
|
+
Dispel::Window.open(screen.lines, screen.columns, 0, 0) do |win|
|
155
|
+
win.box(?|,?-,?*)
|
156
|
+
win.setpos(win.cury+2, win.curx+1)
|
157
|
+
win.addstr @title.title
|
158
|
+
win.setpos(win.cury+1, 1)
|
159
|
+
win.addstr "¯"*(@title.title.size+2)
|
160
|
+
|
161
|
+
add_multiline_str(win, @body)
|
162
|
+
|
163
|
+
start = @buf.cursor
|
164
|
+
begin
|
165
|
+
loop do
|
166
|
+
elem = @buf.get.element
|
167
|
+
if (@lines = screen.lines) > win.cury + elem.size_of_lines + 4
|
168
|
+
add_multiline_str(win, elem)
|
169
|
+
win.setpos(win.cury+1,1)
|
170
|
+
else
|
171
|
+
@buf.prev
|
172
|
+
break
|
173
|
+
end
|
174
|
+
end
|
175
|
+
rescue Buf::NoMoreData
|
176
|
+
end
|
177
|
+
@range = start...@buf.cursor
|
178
|
+
|
179
|
+
win.setpos(win.cury+2, 1)
|
180
|
+
win.addstr "help: ?".rjust(win.maxx - 2)
|
181
|
+
win.setpos(win.cury+1, 1)
|
182
|
+
call getstr(win, EnableKey)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
rescue Dispel::Recall
|
186
|
+
show
|
187
|
+
rescue Dispel::NoCommandError => e
|
188
|
+
Window::Popup::Error.new(e.class.to_s).show
|
189
|
+
show
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
|
3
|
+
module Flumtter
|
4
|
+
module Window
|
5
|
+
class Dialog < Base
|
6
|
+
def initialize(*args)
|
7
|
+
super
|
8
|
+
@commands = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def command(command, help="", &blk)
|
12
|
+
@commands << Command.new(command, help, &blk)
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(str)
|
16
|
+
if str == "?"
|
17
|
+
Window::Popup.new("Command List", <<~EOF).show
|
18
|
+
#{Command.list(@commands)}
|
19
|
+
EOF
|
20
|
+
raise Dispel::Recall
|
21
|
+
else
|
22
|
+
@commands.each do |command|
|
23
|
+
if m = str.match(command.command)
|
24
|
+
return command.call(m)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
raise Dispel::NoCommandError
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def show(recall=false, help=true)
|
32
|
+
Dispel::Screen.open do |screen|
|
33
|
+
Dispel::Window.open(@hight, @width, 0, 0) do |win|
|
34
|
+
win.box(?|,?-,?*)
|
35
|
+
win.setpos(win.cury+2, win.curx+1)
|
36
|
+
win.addstr @title.title
|
37
|
+
win.setpos(win.cury+1, 1)
|
38
|
+
win.addstr "¯"*(@title.title.size+2)
|
39
|
+
|
40
|
+
add_multiline_str(win, @body)
|
41
|
+
|
42
|
+
if block_given?
|
43
|
+
yield win
|
44
|
+
else
|
45
|
+
win.setpos(win.cury+2, 1)
|
46
|
+
if help
|
47
|
+
win.addstr "help: ?".rjust(win.maxx - 2)
|
48
|
+
win.setpos(win.cury+1, 1)
|
49
|
+
end
|
50
|
+
call getstr(win)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
rescue Dispel::Recall
|
55
|
+
show(recall, help)
|
56
|
+
rescue Dispel::NoCommandError => e
|
57
|
+
Window::Popup::Error.new(e.class.to_s).show
|
58
|
+
show(recall, help) if recall
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|