jugyo-termtter 0.7.7 → 0.8.0

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.
Files changed (68) hide show
  1. data/Manifest.txt +10 -0
  2. data/Rakefile +25 -0
  3. data/bin/kill_termtter +22 -0
  4. data/lib/filter/en2ja.rb +2 -0
  5. data/lib/filter/expand-tinyurl.rb +2 -0
  6. data/lib/filter/fib.rb +2 -0
  7. data/lib/filter/ignore.rb +2 -0
  8. data/lib/filter/reverse.rb +2 -0
  9. data/lib/plugin/april_fool.rb +15 -0
  10. data/lib/plugin/bomb.rb +11 -8
  11. data/lib/plugin/confirm.rb +9 -24
  12. data/lib/plugin/cool.rb +8 -10
  13. data/lib/plugin/english.rb +2 -0
  14. data/lib/plugin/erb.rb +9 -9
  15. data/lib/plugin/favorite.rb +2 -0
  16. data/lib/plugin/fib.rb +2 -0
  17. data/lib/plugin/filter.rb +41 -36
  18. data/lib/plugin/follow.rb +36 -20
  19. data/lib/plugin/graduatter.rb +2 -0
  20. data/lib/plugin/group.rb +32 -34
  21. data/lib/plugin/growl.rb +3 -1
  22. data/lib/plugin/hatebu.rb +46 -44
  23. data/lib/plugin/history.rb +16 -4
  24. data/lib/plugin/keyword.rb +2 -0
  25. data/lib/plugin/log.rb +32 -32
  26. data/lib/plugin/modify_arg_hook_sample.rb +7 -0
  27. data/lib/plugin/msagent.rb +2 -0
  28. data/lib/plugin/multi_reply.rb +2 -0
  29. data/lib/plugin/notify-send.rb +2 -0
  30. data/lib/plugin/otsune.rb +17 -13
  31. data/lib/plugin/outputz.rb +2 -0
  32. data/lib/plugin/pause.rb +3 -0
  33. data/lib/plugin/plugin.rb +29 -24
  34. data/lib/plugin/post_exec_hook_sample.rb +9 -0
  35. data/lib/plugin/pre_exec_hook_sample.rb +9 -0
  36. data/lib/plugin/primes.rb +2 -0
  37. data/lib/plugin/quicklook.rb +2 -0
  38. data/lib/plugin/reblog.rb +27 -25
  39. data/lib/plugin/reload.rb +3 -3
  40. data/lib/plugin/say.rb +2 -0
  41. data/lib/plugin/scrape.rb +35 -37
  42. data/lib/plugin/screen.rb +2 -0
  43. data/lib/plugin/shell.rb +12 -2
  44. data/lib/plugin/sl.rb +42 -25
  45. data/lib/plugin/spam.rb +2 -0
  46. data/lib/plugin/standard_plugins.rb +99 -49
  47. data/lib/plugin/stdout.rb +2 -0
  48. data/lib/plugin/system_status.rb +7 -15
  49. data/lib/plugin/translation.rb +2 -0
  50. data/lib/plugin/update_editor.rb +21 -21
  51. data/lib/plugin/uri-open.rb +2 -0
  52. data/lib/plugin/wassr_post.rb +10 -9
  53. data/lib/plugin/yhara.rb +16 -25
  54. data/lib/plugin/yonda.rb +2 -0
  55. data/lib/termtter.rb +44 -24
  56. data/lib/termtter/api.rb +2 -0
  57. data/lib/termtter/client.rb +140 -56
  58. data/lib/termtter/command.rb +15 -5
  59. data/lib/termtter/connection.rb +3 -1
  60. data/lib/termtter/hook.rb +18 -0
  61. data/lib/termtter/status.rb +2 -0
  62. data/lib/termtter/task.rb +16 -0
  63. data/lib/termtter/task_manager.rb +116 -0
  64. data/lib/termtter/twitter.rb +15 -4
  65. data/lib/termtter/user.rb +13 -0
  66. data/run_termtter.rb +1 -0
  67. data/test/test_termtter.rb +2 -0
  68. metadata +14 -3
data/lib/plugin/stdout.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # -*- coding: utf-8 -*-
2
+
1
3
  require 'highline'
2
4
  require 'erb'
3
5
 
@@ -1,3 +1,5 @@
1
+ # -*- coding: utf-8 -*-
2
+
1
3
  require 'erb'
2
4
 
3
5
  configatron.plugins.system_status.set_default(:default_status_proc, proc { Time.now.strftime("%x %X") })
@@ -13,20 +15,11 @@ def out_put_status(status, color)
13
15
  end
14
16
 
15
17
  module Termtter::Client
16
- Thread.new do
17
- loop do
18
- begin
19
- status = public_storage[:system_status] ||
20
- configatron.plugins.system_status.default_status_proc.call
21
- color = public_storage[:system_status_color] ||
22
- configatron.plugins.system_status.default_color
23
- rescue => e
24
- status = e.message
25
- color = :on_red
26
- end
27
- out_put_status(status, color)
28
- sleep configatron.plugins.system_status.interval
29
- end
18
+ add_task(:name => :system_status, :interval => configatron.plugins.system_status.interval) do
19
+ status = (@@task_manager.get_task(:update_timeline).exec_at - Time.now).to_i.to_s
20
+ color = public_storage[:system_status_color] ||
21
+ configatron.plugins.system_status.default_color
22
+ out_put_status(status, color)
30
23
  end
31
24
  end
32
25
 
@@ -38,4 +31,3 @@ end
38
31
  # configatron.plugins.system_status.interval = 1
39
32
  # configatron.plugins.system_status.default_color = :on_blue
40
33
  # configatron.plugins.system_status.format = '<%= status %>'
41
-
@@ -1,3 +1,5 @@
1
+ # -*- coding: utf-8 -*-
2
+
1
3
  require 'nokogiri'
2
4
  require 'net/http'
3
5
  require 'kconv'
@@ -1,3 +1,5 @@
1
+ # -*- coding: utf-8 -*-
2
+
1
3
  require 'tempfile'
2
4
 
3
5
  module Termtter::Client
@@ -22,27 +24,25 @@ module Termtter::Client
22
24
  result
23
25
  end
24
26
 
25
- add_command /^(update_editor|ue)\s*$/ do |m, t|
26
- pause
27
- text = input_editor
28
- unless text.empty?
29
- text = ERB.new(text).result(binding)
30
- text.split("\n").each do |post|
31
- break if post =~ /^__END__$/
32
- unless post.empty?
33
- t.update_status(post)
34
- puts "=> #{post}"
35
- end
36
- end
37
- end
38
- resume
39
- end
40
-
41
- add_help 'update_editor,ue', 'Update status from editor.'
42
-
43
- add_completion do |input|
44
- %w[ update_editor ].grep(/^#{Regexp.quote input}/)
45
- end
27
+ register_command(
28
+ :name => :update_editor, :aliases => [:ue],
29
+ :exec_proc => proc{|arg|
30
+ pause
31
+ text = input_editor
32
+ unless text.empty?
33
+ text = ERB.new(text).result(binding)
34
+ text.split("\n").each do |post|
35
+ break if post =~ /^__END__$/
36
+ unless post.empty?
37
+ Termtter::API.twitter.update_status(post)
38
+ puts "=> #{post}"
39
+ end
40
+ end
41
+ end
42
+ resume
43
+ },
44
+ :help => ["update_editor,ue", "Update status from editor."]
45
+ )
46
46
  end
47
47
 
48
48
  # update_editor.rb
@@ -1,3 +1,5 @@
1
+ # -*- coding: utf-8 -*-
2
+
1
3
  module Termtter::Client
2
4
  public_storage[:uris] = []
3
5
 
@@ -1,21 +1,22 @@
1
+ # -*- coding: utf-8 -*-
2
+
1
3
  require 'uri'
2
4
  require 'net/http'
3
5
 
4
- module Termtter::Client
5
- # NOTE: overwrite original update command
6
- add_command /^(update|u)\s+(.*)/ do |m, t|
7
- text = ERB.new(m[2]).result(binding).gsub(/\n/, ' ')
8
- t.update_status(text)
9
- puts "=> #{text}"
6
+ Termtter::Client.register_hook(
7
+ :name => :wassr_post,
8
+ :points => [:modify_arg_for_update],
9
+ :exec_proc => proc {|cmd, arg|
10
10
  begin
11
11
  Net::HTTP.version_1_2
12
12
  req = Net::HTTP::Post.new("/statuses/update.json?")
13
13
  req.basic_auth configatron.plugins.wassr_post.username, configatron.plugins.wassr_post.password
14
14
  Net::HTTP.start('api.wassr.jp', 80) do |http|
15
- res = http.request(req, "status=#{URI.escape(text)}&source=Termtter")
15
+ res = http.request(req, "status=#{URI.escape(arg.strip)}&source=Termtter")
16
16
  end
17
17
  rescue
18
18
  puts "RuntimeError: #{$!}"
19
19
  end
20
- end
21
- end
20
+ return arg
21
+ }
22
+ )
data/lib/plugin/yhara.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # -*- coding: utf-8 -*-
2
+
1
3
  if RUBY_VERSION < "1.8.7"
2
4
  class Array
3
5
  def choice
@@ -123,31 +125,20 @@ module Yharian
123
125
  end
124
126
 
125
127
  module Termtter::Client
126
-
127
- add_help 'yhara', 'Post a new Yharian sentence'
128
- add_help 'yhara USER', 'Speak to the user in Yharian'
129
-
130
- add_command /^(yhara)\s*$/ do |m, t|
131
- text = Yharian::text
132
- t.update_status(text)
133
- puts "=> #{text}"
134
- end
135
-
136
- add_command /^(yhara)\s+(\w+)/ do |m, t|
137
- text = "@#{m[2]} #{Yharian::text}"
138
- t.update_status(text)
139
- puts "=> #{text}"
140
- end
141
-
142
- add_completion do |input|
143
- case input
144
- when /^(yhara)\s+(.*)/
145
- find_user_candidates $2, "#{$1} %s"
146
- else
147
- %w[ yhara ].grep(/^#{Regexp.quote input}/)
148
- end
149
- end
150
-
128
+ register_command(
129
+ :name => :yhara,
130
+ :exec_proc => proc{|arg|
131
+ text = "#{'@' if arg[0..0] != '@'}#{arg} #{Yharian::text}"
132
+ Termtter::API.twitter.update_status(text)
133
+ puts "=> #{text}"
134
+ },
135
+ :completion_proc => proc {|cmd, args|
136
+ if /(.*)@([^\s]*)$/ =~ args
137
+ find_user_candidates $2, "#{cmd} #{$1}@%s"
138
+ end
139
+ },
140
+ :help => ["yhara (USER)", 'Post a new Yharian sentence']
141
+ )
151
142
  end
152
143
 
153
144
  # yhara.rb
data/lib/plugin/yonda.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # -*- coding: utf-8 -*-
2
+
1
3
  module Termtter::Client
2
4
  public_storage[:unread_count] = 0
3
5
 
data/lib/termtter.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # -*- coding: utf-8 -*-
2
+
1
3
  $:.unshift(File.dirname(__FILE__)) unless
2
4
  $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
5
 
@@ -8,7 +10,6 @@ require 'open-uri'
8
10
  require 'cgi'
9
11
  require 'readline'
10
12
  require 'enumerator'
11
- require 'parsedate'
12
13
  require 'configatron'
13
14
 
14
15
  Thread.abort_on_exception = true
@@ -21,12 +22,16 @@ configatron.proxy.set_default(:port, '8080')
21
22
  require 'termtter/twitter'
22
23
  require 'termtter/connection'
23
24
  require 'termtter/status'
25
+ require 'termtter/user'
24
26
  require 'termtter/command'
27
+ require 'termtter/hook'
28
+ require 'termtter/task'
29
+ require 'termtter/task_manager'
25
30
  require 'termtter/client'
26
31
  require 'termtter/api'
27
32
 
28
33
  module Termtter
29
- VERSION = '0.7.7'
34
+ VERSION = '0.8.0'
30
35
  APP_NAME = 'termtter'
31
36
  CONF_FILE = '~/.termtterrc' # still does not use
32
37
  CONF_DIR = '~/.termtter' # still does not use
@@ -78,22 +83,34 @@ if win?
78
83
  $oldColor = lpBuffer.unpack('SSSSSssssSS')[4]
79
84
 
80
85
  $colorMap = {
81
- 0 => 7, # black/white
82
- 37 => 8, # white/intensity
83
- 31 => 4 + 8, # red/red
84
- 32 => 2 + 8, # green/green
85
- 33 => 6 + 8, # yellow/yellow
86
- 34 => 1 + 8, # blue/blue
87
- 35 => 5 + 8, # magenta/purple
88
- 36 => 3 + 8, # cyan/aqua
89
- 90 => 7, # erase/white
86
+ 0 => 0x07|0x00|0x00|0x00, # black/white
87
+ 37 => 0x08|0x00|0x00|0x00, # white/intensity
88
+ 31 => 0x04|0x08|0x00|0x00, # red/red
89
+ 32 => 0x02|0x08|0x00|0x00, # green/green
90
+ 33 => 0x06|0x08|0x00|0x00, # yellow/yellow
91
+ 34 => 0x01|0x08|0x00|0x00, # blue/blue
92
+ 35 => 0x05|0x08|0x00|0x00, # magenta/purple
93
+ 36 => 0x03|0x08|0x00|0x00, # cyan/aqua
94
+ 39 => 0x07, # default
95
+ 40 => 0x00|0x00|0xf0|0x00, # background:white
96
+ 41 => 0x07|0x00|0x40|0x00, # background:red
97
+ 42 => 0x07|0x00|0x20|0x00, # background:green
98
+ 43 => 0x07|0x00|0x60|0x00, # background:yellow
99
+ 44 => 0x07|0x00|0x10|0x00, # background:blue
100
+ 45 => 0x07|0x00|0x50|0x80, # background:magenta
101
+ 46 => 0x07|0x00|0x30|0x80, # background:cyan
102
+ 47 => 0x07|0x00|0x70|0x80, # background:gray
103
+ 49 => 0x70, # default
104
+ 90 => 0x07|0x00|0x00|0x00, # erase/white
90
105
  }
91
106
  $iconv_u8_to_sj = Iconv.new("CP#{$wGetACP.call()}", 'UTF-8')
92
- def puts(str)
93
- #str.to_s.tosjis.split(/(\e\[\d+m)/).each do |token|
94
- str.to_s.gsub("\xef\xbd\x9e", "\xe3\x80\x9c").split(/(\e\[\d+m)/).each do |token|
95
- if token =~ /\e\[(\d+)m/
107
+ def print(str)
108
+ str.to_s.gsub("\xef\xbd\x9e", "\xe3\x80\x9c").split(/(\e\[\d*[a-zA-Z])/).each do |token|
109
+ case token
110
+ when /\e\[(\d+)m/
96
111
  $wSetConsoleTextAttribute.call $hStdOut, $colorMap[$1.to_i].to_i
112
+ when /\e\[\d*[a-zA-Z]/
113
+ # do nothing
97
114
  else
98
115
  loop do
99
116
  begin
@@ -107,26 +124,29 @@ if win?
107
124
  end
108
125
  end
109
126
  $wSetConsoleTextAttribute.call $hStdOut, $oldColor
110
- STDOUT.puts
111
127
  $iconv_u8_to_sj.iconv(nil)
112
128
  end
129
+ def puts(str)
130
+ print str
131
+ STDOUT.puts
132
+ end
113
133
  end
114
134
 
115
- def handle_error(e)
116
- puts "Error: #{e}"
117
- puts e.backtrace.join("\n")
118
- end
119
-
120
- def plugin(s)
135
+ def plugin(s, init = {})
136
+ unless init.empty?
137
+ init.each do |key, value|
138
+ eval("configatron.plugins.#{s}").__send__("#{key}=", value)
139
+ end
140
+ end
121
141
  require "plugin/#{s}"
122
142
  rescue => e
123
- handle_error(e)
143
+ Termtter::Client.handle_error(e)
124
144
  end
125
145
 
126
146
  def filter(s)
127
147
  load "filter/#{s}.rb"
128
148
  rescue => e
129
- handle_error(e)
149
+ Termtter::Client.handle_error(e)
130
150
  else
131
151
  Termtter::Client.public_storage[:filters] ||= []
132
152
  Termtter::Client.public_storage[:filters] << s
data/lib/termtter/api.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # -*- coding: utf-8 -*-
2
+
1
3
  module Termtter
2
4
  module API
3
5
  class << self
@@ -1,16 +1,26 @@
1
+ # -*- coding: utf-8 -*-
2
+
1
3
  module Termtter
2
4
  class CommandNotFound < StandardError; end
3
5
 
4
6
  module Client
5
7
 
6
- @@hooks = []
7
- @@commands = {}
8
- @@new_commands = {}
9
- @@completions = []
10
- @@filters = []
11
- @@helps = []
12
-
13
8
  class << self
9
+
10
+ def init
11
+ @@hooks = []
12
+ @@new_hooks = {}
13
+ @@commands = {}
14
+ @@new_commands = {}
15
+ @@completions = []
16
+ @@filters = []
17
+ @@helps = []
18
+ @@since_id = nil
19
+ @@main_thread = nil
20
+ @@input_thread = nil
21
+ @@task_manager = Termtter::TaskManager.new
22
+ end
23
+
14
24
  def public_storage
15
25
  @@public_storage ||= {}
16
26
  end
@@ -23,10 +33,35 @@ module Termtter
23
33
  EOF
24
34
  end
25
35
 
36
+ # Deprecated
37
+ # FIXME: delete when become unnecessary
26
38
  def add_command(regex, &block)
39
+ warn "Termtter:Client.add_command method will be removed. Use Termtter::Client.register_command() instead. (#{caller.first})"
27
40
  @@commands[regex] = block
28
41
  end
29
42
 
43
+ def register_hook(arg)
44
+ hook = case arg
45
+ when Hook
46
+ arg
47
+ when Hash
48
+ Hook.new(arg)
49
+ else
50
+ raise ArgumentError, 'must be given Termtter::Hook or Hash'
51
+ end
52
+ @@new_hooks[hook.name] = hook
53
+ end
54
+
55
+ def get_hook(name)
56
+ @@new_hooks[name]
57
+ end
58
+
59
+ def get_hooks(point)
60
+ @@new_hooks.values.select do |hook|
61
+ hook.match?(point)
62
+ end
63
+ end
64
+
30
65
  def register_command(arg)
31
66
  command = case arg
32
67
  when Command
@@ -43,10 +78,12 @@ module Termtter
43
78
  @@new_commands[name]
44
79
  end
45
80
 
46
- def add_macro(r, s)
47
- add_command(r) do |m, t|
48
- call_commands(s % m.to_a[1..-1])
49
- end
81
+ def register_macro(name, macro, options = {})
82
+ arg = {
83
+ :name => name.to_sym,
84
+ :exec_proc => proc {|arg| call_commands(macro % arg)}
85
+ }.merge(options)
86
+ register_command(arg)
50
87
  end
51
88
 
52
89
  def add_help(name, desc)
@@ -83,6 +120,22 @@ module Termtter
83
120
  end
84
121
  end
85
122
 
123
+ # return last hook return value
124
+ def call_new_hooks(point, *args)
125
+ result = nil
126
+ get_hooks(point).each {|hook|
127
+ break if result == false # interrupt if hook return false
128
+ result = hook.exec_proc.call(*args)
129
+ }
130
+ return result
131
+ rescue => e
132
+ if point.to_sym == :on_error
133
+ raise
134
+ else
135
+ handle_error(e)
136
+ end
137
+ end
138
+
86
139
  # TODO: delete argument "tw" when unnecessary
87
140
  def call_hooks(statuses, event, tw = nil)
88
141
  do_hooks(statuses, :pre_filter)
@@ -96,22 +149,29 @@ module Termtter
96
149
  @@commands.each do |key, command|
97
150
  if key =~ text
98
151
  command_found = true
99
- begin
152
+ @@task_manager.invoke_and_wait do
100
153
  command.call($~, Termtter::API.twitter)
101
- rescue => e
102
- handle_error(e)
103
154
  end
104
155
  end
105
156
  end
106
157
 
107
158
  @@new_commands.each do |key, command|
108
159
  command_info = command.match?(text)
109
- # TODO: call hook for before command here.
110
160
  if command_info
111
161
  command_found = true
112
- result = command.execute(command_info[1])
113
- if result
114
- # TODO: call hook for after command with result.
162
+ input_command, arg = *command_info
163
+
164
+ modified_arg = call_new_hooks("modify_arg_for_#{command.name.to_s}", input_command, arg) || arg || ''
165
+
166
+ @@task_manager.invoke_and_wait do
167
+ pre_exec_hook_result = call_new_hooks("pre_exec_#{command.name.to_s}", input_command, modified_arg)
168
+ next if pre_exec_hook_result == false
169
+
170
+ # exec command
171
+ result = command.execute(modified_arg)
172
+ if result
173
+ call_new_hooks("post_exec_#{command.name.to_s}", input_command, modified_arg, result)
174
+ end
115
175
  end
116
176
  end
117
177
  end
@@ -120,19 +180,25 @@ module Termtter
120
180
  end
121
181
 
122
182
  def pause
123
- @@pause = true
183
+ @@task_manager.pause
124
184
  end
125
185
 
126
186
  def resume
127
- @@pause = false
128
- @@update_thread.run
187
+ @@task_manager.resume
188
+ end
189
+
190
+ def add_task(*arg, &block)
191
+ @@task_manager.add_task(*arg, &block)
129
192
  end
130
193
 
131
194
  def exit
195
+ puts 'finalizing...'
196
+
132
197
  call_hooks([], :exit)
133
- @@main_thread.kill
134
- @@update_thread.kill
135
- @@input_thread.kill
198
+ call_new_hooks(:exit)
199
+ @@task_manager.kill
200
+ @@main_thread.kill if @@main_thread
201
+ @@input_thread.kill if @@input_thread
136
202
  end
137
203
 
138
204
  def load_default_plugins
@@ -202,35 +268,17 @@ module Termtter
202
268
  end
203
269
  end
204
270
 
205
- def setup_api()
206
- Termtter::API.setup()
207
- end
208
-
209
- def run
210
- load_default_plugins()
211
- load_config()
212
- setup_readline()
213
- setup_api()
214
-
215
- puts 'initializing...'
216
- initialized = false
217
- @@pause = false
218
- call_hooks([], :initialize)
219
-
220
- @@input_thread = nil
221
- @@update_thread = Thread.new do
222
- since_id = nil
223
- loop do
271
+ def setup_update_timeline_task()
272
+ register_command(
273
+ :name => :_update_timeline,
274
+ :exec_proc => proc {|arg|
224
275
  begin
225
- Thread.stop if @@pause
226
-
227
- statuses = Termtter::API.twitter.get_friends_timeline(since_id)
276
+ statuses = Termtter::API.twitter.get_friends_timeline(@@since_id)
228
277
  unless statuses.empty?
229
- since_id = statuses[0].id
278
+ @@since_id = statuses[0].id
230
279
  end
231
280
  print "\e[1K\e[0G" if !statuses.empty? && !win?
232
281
  call_hooks(statuses, :update_friends_timeline)
233
- initialized = true
234
282
  @@input_thread.kill if @@input_thread && !statuses.empty?
235
283
  rescue OpenURI::HTTPError => e
236
284
  if e.message == '401 Unauthorized'
@@ -238,20 +286,32 @@ module Termtter
238
286
  puts 'plese check your account settings'
239
287
  exit!
240
288
  end
241
- ensure
242
- sleep configatron.update_interval
243
289
  end
244
- end
245
- end
290
+ }
291
+ )
246
292
 
247
- until initialized; end
293
+ add_task(:name => :update_timeline, :interval => configatron.update_interval) do
294
+ call_commands('_update_timeline')
295
+ end
296
+ end
248
297
 
298
+ def trap_setting()
249
299
  begin
250
300
  stty_save = `stty -g`.chomp
251
- trap("INT") { system "stty", stty_save; exit }
301
+ trap("INT") do
302
+ begin
303
+ system "stty", stty_save
304
+ ensure
305
+ exit
306
+ end
307
+ end
252
308
  rescue Errno::ENOENT
253
309
  end
310
+ end
254
311
 
312
+ def start_input_thread
313
+ setup_readline()
314
+ trap_setting()
255
315
  @@main_thread = Thread.new do
256
316
  loop do
257
317
  @@input_thread = create_input_thread()
@@ -261,10 +321,26 @@ module Termtter
261
321
  @@main_thread.join
262
322
  end
263
323
 
324
+ def run
325
+ puts 'initializing...'
326
+
327
+ load_default_plugins()
328
+ load_config()
329
+ Termtter::API.setup()
330
+
331
+ call_hooks([], :initialize)
332
+ call_new_hooks(:initialize)
333
+
334
+ setup_update_timeline_task()
335
+ call_commands('_update_timeline')
336
+
337
+ @@task_manager.run()
338
+ start_input_thread()
339
+ end
340
+
264
341
  def create_input_thread()
265
342
  Thread.new do
266
- erb = ERB.new(configatron.prompt)
267
- while buf = Readline.readline(erb.result(Termtter::API.twitter.__send__(:binding)), true)
343
+ while buf = Readline.readline(ERB.new(configatron.prompt).result(API.twitter.__send__(:binding)), true)
268
344
  Readline::HISTORY.pop if /^(u|update)\s+(.+)$/ =~ buf
269
345
  begin
270
346
  call_commands(buf)
@@ -277,6 +353,13 @@ module Termtter
277
353
  end
278
354
  end
279
355
 
356
+ def handle_error(e)
357
+ call_new_hooks("on_error", e)
358
+ rescue => e
359
+ puts "Error: #{e}"
360
+ puts e.backtrace.join("\n")
361
+ end
362
+
280
363
  def wrap_require
281
364
  # FIXME: delete this method after the major version up
282
365
  alias original_require require
@@ -296,3 +379,4 @@ module Termtter
296
379
  end
297
380
  end
298
381
 
382
+ Termtter::Client.init