termtter 1.0.3 → 1.0.4

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 (40) hide show
  1. data/Rakefile +1 -1
  2. data/lib/plugins/bomb.rb +9 -12
  3. data/lib/plugins/expand-tinyurl.rb +12 -3
  4. data/lib/plugins/group.rb +10 -6
  5. data/lib/plugins/history.rb +21 -10
  6. data/lib/plugins/log.rb +10 -10
  7. data/lib/plugins/msagent.rb +23 -11
  8. data/lib/plugins/notify-send.rb +17 -12
  9. data/lib/plugins/say.rb +8 -6
  10. data/lib/plugins/scrape.rb +1 -1
  11. data/lib/plugins/screen-notify.rb +17 -10
  12. data/lib/plugins/standard_plugins.rb +29 -17
  13. data/lib/plugins/stdout.rb +35 -54
  14. data/lib/plugins/storage.rb +17 -23
  15. data/lib/plugins/storage/status.rb +23 -20
  16. data/lib/plugins/update_editor.rb +1 -1
  17. data/lib/plugins/uri-open.rb +7 -5
  18. data/lib/plugins/url_addspace.rb +2 -2
  19. data/lib/termtter/api.rb +2 -1
  20. data/lib/termtter/client.rb +88 -108
  21. data/lib/termtter/command.rb +1 -0
  22. data/lib/termtter/hook.rb +5 -0
  23. data/lib/termtter/system_extensions.rb +13 -3
  24. data/lib/termtter/version.rb +1 -1
  25. data/spec/{plugin → plugins}/cool_spec.rb +0 -0
  26. data/spec/{plugin → plugins}/english_spec.rb +0 -0
  27. data/spec/{plugin → plugins}/favorite_spec.rb +0 -0
  28. data/spec/{plugin → plugins}/fib_spec.rb +0 -0
  29. data/spec/{plugin → plugins}/filter_spec.rb +0 -0
  30. data/spec/{plugin → plugins}/pause_spec.rb +0 -0
  31. data/spec/{plugin → plugins}/plugin_spec.rb +0 -0
  32. data/spec/{plugin → plugins}/primes_spec.rb +0 -0
  33. data/spec/{plugin → plugins}/shell_spec.rb +0 -0
  34. data/spec/{plugin → plugins}/sl_spec.rb +0 -0
  35. data/spec/{plugin → plugins}/spam_spec.rb +0 -0
  36. data/spec/{plugin → plugins}/standard_plugins_spec.rb +0 -0
  37. data/spec/{plugin → plugins}/storage/DB_spec.rb +0 -0
  38. data/spec/{plugin → plugins}/storage/status_spec.rb +1 -1
  39. data/spec/termtter/client_spec.rb +1 -4
  40. metadata +17 -17
@@ -11,68 +11,49 @@ config.plugins.stdout.set_default(
11
11
  '<90><%=time%></90> <<%=status_color%>><%=status%></<%=status_color%>> <90><%=id%></90>')
12
12
  config.plugins.stdout.set_default(:search_highlihgt_format, '<on_magenta><white>\1</white></on_magenta>')
13
13
 
14
- $highline = HighLine.new
15
-
16
- def color(str, value)
17
- return str if value == :none
18
- case value
19
- when String, Symbol
20
- $highline.color(str, value)
21
- else
22
- "\e[#{value}m#{str}\e[0m"
23
- end
24
- end
25
-
26
- module Termtter::Client
27
-
28
- def self.print_statuses(statuses, sort = true, time_format = '%H:%M:%S')
29
- (sort ? statuses.sort_by{ |s| s.id} : statuses).each do |s|
30
- text = s.text
31
- status_color = config.plugins.stdout.colors[s.user.screen_name.hash % config.plugins.stdout.colors.size]
32
- status = "#{s.user.screen_name}: #{text}"
33
- if s.in_reply_to_status_id
34
- status += " (repl. to #{s.in_reply_to_status_id})"
35
- end
36
-
37
- time = "(#{Time.parse(s.created_at).strftime(time_format)})"
38
- id = s.id
39
- erbed_text = ERB.new(config.plugins.stdout.timeline_format).result(binding)
40
- puts TermColor.parse(erbed_text)
14
+ module Termtter
15
+ class StdOut < Hook
16
+ def initialize
17
+ super(:name => :stdout, :points => [:output])
41
18
  end
42
- end
43
-
44
- def self.print_statuses_with_date(statuses, sort = true)
45
- print_statuses(statuses, sort, '%m-%d %H:%M')
46
- end
47
19
 
48
- def self.print_search_results(result, time_format = '%H:%M:%S')
49
- result.results.sort_by{|r| r.created_at}.each do |r|
50
- text = r.text.
51
- gsub(/(\n|\r)/, '').
52
- gsub(/(#{Regexp.escape(result.query)})/i, config.plugins.stdout.search_highlihgt_format)
53
- status_color = config.plugins.stdout.colors[r.from_user_id.to_i.hash % config.plugins.stdout.colors.size]
54
- status = "#{r.from_user}: #{text}"
55
- time = "(#{Time.parse(r.created_at).strftime(time_format)})"
56
- id = r.id
57
- erbed_text = ERB.new(config.plugins.stdout.timeline_format).result(binding)
58
- puts TermColor.parse(erbed_text)
20
+ def execute(statuses, event)
21
+ print_statuses(statuses)
59
22
  end
60
- end
61
23
 
62
- add_hook do |result, event|
63
- case event
64
- when :update_friends_timeline, :list_friends_timeline
65
- print_statuses(result) unless result.empty?
66
- when :list_user_timeline, :replies
67
- print_statuses_with_date(result) unless result.empty?
68
- when :show
69
- print_statuses_with_date([result])
70
- when :search
71
- print_search_results(result)
24
+ def print_statuses(statuses, sort = true, time_format = nil)
25
+ return unless statuses
26
+ unless time_format
27
+ # 最初と最後の日付がちがうとき日付も出す
28
+ t1 = Time.parse(statuses.first[:created_at])
29
+ t2 = Time.parse(statuses.last[:created_at])
30
+ time_format =
31
+ if [t1.year, t1.month, t1.day] == [t2.year, t2.month, t2.day]
32
+ '%H:%M:%S'
33
+ else
34
+ '%y/%m/%d %H:%M'
35
+ end
36
+ end
37
+
38
+ statuses.each do |s|
39
+ text = s.text
40
+ status_color = config.plugins.stdout.colors[s.user.id.hash % config.plugins.stdout.colors.size]
41
+ status = "#{s.user.screen_name}: #{text}"
42
+ if s.in_reply_to_status_id
43
+ status += " (repl. to #{s.in_reply_to_status_id})"
44
+ end
45
+
46
+ time = "(#{Time.parse(s.created_at).strftime(time_format)})"
47
+ id = s.id
48
+ erbed_text = ERB.new(config.plugins.stdout.timeline_format).result(binding)
49
+ puts TermColor.parse(erbed_text)
50
+ end
72
51
  end
73
52
  end
74
53
 
54
+ Client.register_hook(StdOut.new)
75
55
  end
56
+
76
57
  # stdout.rb
77
58
  # output statuses to stdout
78
59
  # example config
@@ -8,40 +8,34 @@ require File.dirname(__FILE__) + '/storage/status'
8
8
  module Termtter::Client
9
9
  public_storage[:log] = []
10
10
 
11
- add_hook do |statuses, event|
12
- case event
13
- when :pre_filter
11
+ register_hook(
12
+ :name => :storage,
13
+ :points => [:pre_filter],
14
+ :exec_proc => lambda {|statuses, event|
14
15
  statuses.each do |s|
15
16
  Termtter::Storage::Status.insert(
16
17
  :post_id => s.id,
17
18
  :created_at => Time.parse(s.created_at).to_i,
18
19
  :in_reply_to_status_id => s.in_reply_to_status_id,
19
20
  :in_reply_to_user_id => s.in_reply_to_user_id,
20
- :post_text => s.text,
21
+ :post => s.text,
21
22
  :user_id => s.user.id,
22
- :screen_name => s.user.screen_name)
23
+ :screen_name => s.user.screen_name
24
+ )
23
25
  end
24
- end
25
- end
26
+ }
27
+ )
26
28
 
27
29
  register_command(
28
- :name => :search_storage, :aliases => [:ss],
30
+ :name => :search_storage,
31
+ :aliases => [:ss],
29
32
  :exec_proc => lambda {|arg|
30
33
  unless arg.strip.empty?
31
34
  key = arg.strip
32
- Termtter::Storage::Status.search({ :post_text => key})
33
- =begin
34
- statuses = public_storage[:storage].search({ :post_text => key})
35
-
36
- statuses.each do |s|
37
- p s
38
- end
39
- call_hooks(statuses, :search)
40
- =end
41
- end
42
-
43
- },
44
-
45
- :help => [ 'search_storage WORD', 'Search storage for WORD' ]
46
- )
35
+ statuses = Termtter::Storage::Status.search({:text => key})
36
+ output(statuses, :search)
37
+ end
38
+ },
39
+ :help => [ 'search_storage WORD', 'Search storage for WORD' ]
40
+ )
47
41
  end
@@ -7,42 +7,45 @@ module Termtter::Storage
7
7
  class Status
8
8
  KEYS = %w[post_id created_at in_reply_to_status_id in_reply_to_user_id post_text user_id screen_name]
9
9
 
10
- def size
10
+ def self.size
11
11
  DB.instance.db.get_first_value("select count(*) from post").to_i
12
12
  end
13
13
 
14
14
  def self.search(query)
15
15
  raise "query must be Hash(#{query}, #{query.class})" unless query.kind_of? Hash
16
-
17
- DB.instance.db.execute("select created_at, screen_name, post_text, in_reply_to_status_id, post_id from post inner join user on post.user_id = user.id where post_text like '%' || ? || '%' ", query[:post_text]) do |created_at, screen_name, post_text, in_reply_to_status_id, post_id|
18
-
19
- # DB.instance.db.execute("select created_at, screen_name, post_text, in_reply_to_status_id, post_id from post inner join user on post.user_id = user.id where post_text like '%of%' ", query[:post_text]) do |created_at, screen_name, post_text, in_reply_to_status_id, post_id|
20
- p [created_at, screen_name, post_text, in_reply_to_status_id, post_id]
16
+ result = []
17
+ DB.instance.db.execute("select created_at, screen_name, post_text, in_reply_to_status_id, post_id, user_id from post inner join user on post.user_id = user.id where post_text like '%' || ? || '%' ",
18
+ query[:text]) do |created_at, screen_name, post_text, in_reply_to_status_id, post_id, user_id|
19
+ created_at = Time.at(created_at).to_s
20
+ result << {
21
+ :id => post_id,
22
+ :created_at => created_at,
23
+ :text => post_text,
24
+ :in_reply_to_status_id => in_reply_to_status_id,
25
+ :in_reply_to_user_id => nil,
26
+ :user => {
27
+ :id => user_id,
28
+ :screen_name => screen_name
29
+ }
30
+ }
21
31
  end
32
+ Rubytter.json_to_struct(result)
22
33
  end
23
34
 
24
35
  def self.insert(data)
25
- raise "data must be Hash(#{data}, #{data.class})" unless data.kind_of? Hash
26
- # 条件しぼりたいけどやりかたがうまくわからない
27
- # raise "unko" unless data.keys.all?{|c| KEYS.include? c}
28
- begin
29
36
  DB.instance.db.execute(
30
37
  "insert into post values(?,?,?,?,?,?)",
31
38
  data[:post_id],
32
39
  data[:created_at],
33
40
  data[:in_reply_to_status_id],
34
41
  data[:in_reply_to_user_id],
35
- data[:post_text],
42
+ data[:text],
36
43
  data[:user_id])
37
- begin
38
- DB.instance.db.execute(
39
- "insert into user values(?,?)",
40
- data[:user_id],
41
- data[:screen_name])
42
- rescue # FIXME: specify exceptions here
43
- end
44
- rescue # FIXME: specify exceptions here
45
- end
44
+ DB.instance.db.execute(
45
+ "insert into user values(?,?)",
46
+ data[:user_id],
47
+ data[:screen_name])
48
+ rescue SQLite3::SQLException
46
49
  end
47
50
  end
48
51
  end
@@ -8,7 +8,7 @@ module Termtter::Client
8
8
  else
9
9
  config.plugins.update_editor.set_default('editor', 'vi')
10
10
  end
11
- config.plugins.update_editor.set_default('add_completion', false)
11
+ config.plugins.update_editor.set_default('add_completion', true)
12
12
 
13
13
 
14
14
  def self.input_editor
@@ -3,13 +3,15 @@
3
3
  module Termtter::Client
4
4
  public_storage[:uris] = []
5
5
 
6
- add_hook do |statuses, event, t|
7
- if event == :update_friends_timeline
6
+ register_hook(
7
+ :name => :uri_open,
8
+ :points => [:post_filter],
9
+ :exec_proc => lambda {|statuses, event|
8
10
  statuses.each do |s|
9
- public_storage[:uris] += s.text.scan(%r|https?://[^\s]+|)
11
+ public_storage[:uris] += s[:post_text].scan(%r|https?://[^\s]+|)
10
12
  end
11
- end
12
- end
13
+ }
14
+ )
13
15
 
14
16
  def self.open_uri(uri)
15
17
  unless config.plugins.uri_open.browser.empty?
@@ -1,9 +1,9 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
3
  module Termtter::Client
4
- add_filter do |statuses|
4
+ add_filter do |statuses, event|
5
5
  statuses.each do |s|
6
- s.text.gsub!(/(\S)(https?:\/\/)/, '\1 \2')
6
+ s[:post_text].gsub!(/(\S)(https?:\/\/)/, '\1 \2')
7
7
  end
8
8
  statuses
9
9
  end
data/lib/termtter/api.rb CHANGED
@@ -19,12 +19,13 @@ module Termtter
19
19
  config.user_name,
20
20
  config.password,
21
21
  {
22
+ :app_name => Termtter::APP_NAME,
22
23
  :host => config.host,
23
24
  :header => {
24
25
  'User-Agent' => 'Termtter http://github.com/jugyo/termtter',
25
26
  'X-Twitter-Client' => 'Termtter',
26
27
  'X-Twitter-Client-URL' => 'http://github.com/jugyo/termtter',
27
- 'X-Twitter-Client-Version' => '0.1'
28
+ 'X-Twitter-Client-Version' => Termtter::VERSION
28
29
  },
29
30
  :enable_ssl => config.enable_ssl,
30
31
  :proxy_host => config.proxy.host,
@@ -1,5 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  require 'fileutils'
3
+ require 'logger'
3
4
 
4
5
  module Termtter
5
6
  APP_NAME = 'termtter'
@@ -18,15 +19,14 @@ module Termtter
18
19
  class << self
19
20
 
20
21
  def init
21
- @@hooks = []
22
- @@new_hooks = {}
23
- @@new_commands = {}
24
- @@completions = []
25
- @@filters = []
26
- @@helps = []
27
- @@since_id = nil
28
- @@input_thread = nil
29
- @@task_manager = Termtter::TaskManager.new
22
+ @hooks = {}
23
+ @commands = {}
24
+ @filters = []
25
+ @since_id = nil
26
+ @input_thread = nil
27
+ @task_manager = Termtter::TaskManager.new
28
+ config.log.set_default(:logger, nil)
29
+ config.log.set_default(:level, nil)
30
30
  config.set_default(:update_interval, 300)
31
31
  config.set_default(:prompt, '> ')
32
32
  config.set_default(:devel, false)
@@ -34,15 +34,15 @@ module Termtter
34
34
  end
35
35
 
36
36
  def public_storage
37
- @@public_storage ||= {}
37
+ @public_storage ||= {}
38
38
  end
39
39
 
40
- %w[hook completion filter].each do |n|
41
- eval <<-EOF
42
- def add_#{n}(&b)
43
- @@#{n}s << b
44
- end
45
- EOF
40
+ def add_filter(&b)
41
+ filters << b
42
+ end
43
+
44
+ def clear_filter
45
+ filters.clear
46
46
  end
47
47
 
48
48
  def register_hook(arg)
@@ -54,15 +54,15 @@ module Termtter
54
54
  else
55
55
  raise ArgumentError, 'must be given Termtter::Hook or Hash'
56
56
  end
57
- @@new_hooks[hook.name] = hook
57
+ @hooks[hook.name] = hook
58
58
  end
59
59
 
60
60
  def get_hook(name)
61
- @@new_hooks[name]
61
+ @hooks[name]
62
62
  end
63
63
 
64
64
  def get_hooks(point)
65
- @@new_hooks.values.select do |hook|
65
+ @hooks.values.select do |hook|
66
66
  hook.match?(point)
67
67
  end
68
68
  end
@@ -76,11 +76,11 @@ module Termtter
76
76
  else
77
77
  raise ArgumentError, 'must be given Termtter::Command or Hash'
78
78
  end
79
- @@new_commands[command.name] = command
79
+ @commands[command.name] = command
80
80
  end
81
81
 
82
82
  def get_command(name)
83
- @@new_commands[name]
83
+ @commands[name]
84
84
  end
85
85
 
86
86
  def register_macro(name, macro, options = {})
@@ -91,58 +91,44 @@ module Termtter
91
91
  register_command(command)
92
92
  end
93
93
 
94
- def add_help(name, desc)
95
- @@helps << [name, desc]
96
- end
97
-
98
- %w[hooks completions helps filters].each do |n|
99
- eval <<-EOF
100
- def clear_#{n}
101
- @@#{n}.clear
102
- end
103
- EOF
94
+ # statuses => [status, status, ...]
95
+ # status => {
96
+ # :id => status id,
97
+ # :created_at => created time,
98
+ # :user_id => user id,
99
+ # :name => user name,
100
+ # :screen_name => user screen_name,
101
+ # :source => source,
102
+ # :reply_to => reply_to status id,
103
+ # :text => status,
104
+ # :original_data => original data,
105
+ # }
106
+ def output(statuses, event)
107
+ return if statuses.nil? || statuses.empty?
108
+
109
+ statuses = statuses.sort_by{|s|s.id}
110
+ call_hooks(:pre_filter, statuses, event)
111
+ filtered = apply_filters(statuses, event)
112
+ call_hooks(:post_filter, filtered, event)
113
+ call_hooks(:output, filtered, event)
104
114
  end
105
115
 
106
- # memo: each filter must return Array of Status
107
- def apply_filters(result, event = nil)
108
- case event
109
- when :show
110
- result
111
- when :search
112
- filtered = result.results.map(&:dup)
113
- @@filters.each do |f|
114
- filtered = f.call(filtered, event)
115
- end
116
- result.results = filtered
117
- result
118
- else
119
- filtered = result.map(&:dup)
120
- @@filters.each do |f|
116
+ def apply_filters(statuses, event)
117
+ filtered = statuses.map(&:dup)
118
+ @filters.each do |f|
121
119
  filtered = f.call(filtered, event)
122
120
  end
123
121
  filtered
124
- end
125
- rescue => e
126
- handle_error(e)
127
- result
128
- end
129
-
130
- def do_hooks(statuses, event)
131
- @@hooks.each do |h|
132
- begin
133
- h.call(statuses.dup, event, Termtter::API.twitter)
134
- rescue => e
135
- handle_error(e)
136
- end
137
- end
122
+ rescue => e
123
+ handle_error(e)
138
124
  end
139
125
 
140
126
  # return last hook return value
141
- def call_new_hooks(point, *args)
127
+ def call_hooks(point, *args)
142
128
  result = nil
143
129
  get_hooks(point).each {|hook|
144
130
  break if result == false # interrupt if hook return false
145
- result = hook.exec_proc.call(*args)
131
+ result = hook.execute(*args)
146
132
  }
147
133
  result
148
134
  rescue => e
@@ -153,36 +139,29 @@ module Termtter
153
139
  end
154
140
  end
155
141
 
156
- # TODO: delete argument "tw" when unnecessary
157
- def call_hooks(statuses, event, tw = nil)
158
- do_hooks(statuses, :pre_filter)
159
- filtered = apply_filters(statuses, event)
160
- do_hooks(filtered, :post_filter)
161
- do_hooks(filtered, event)
162
- end
163
-
164
142
  def call_commands(text, tw = nil)
165
143
  return if text.empty?
166
144
 
167
145
  command_found = false
168
- @@new_commands.each do |key, command|
146
+ @commands.each do |key, command|
147
+ # match? メソッドがなんかきもちわるいので変える予定
169
148
  command_str, command_arg = command.match?(text)
170
149
  if command_str
171
150
  command_found = true
172
151
 
173
- modified_arg = call_new_hooks(
152
+ modified_arg = call_hooks(
174
153
  "modify_arg_for_#{command.name.to_s}",
175
154
  command_str,
176
155
  command_arg) || command_arg || ''
177
156
 
178
- @@task_manager.invoke_and_wait do
157
+ @task_manager.invoke_and_wait do
179
158
 
180
- pre_exec_hook_result = call_new_hooks("pre_exec_#{command.name.to_s}", command_str, modified_arg)
159
+ pre_exec_hook_result = call_hooks("pre_exec_#{command.name.to_s}", command_str, modified_arg)
181
160
  next if pre_exec_hook_result == false
182
161
  # exec command
183
162
  result = command.execute(modified_arg)
184
163
  if result
185
- call_new_hooks("post_exec_#{command.name.to_s}", command_str, modified_arg, result)
164
+ call_hooks("post_exec_#{command.name.to_s}", command_str, modified_arg, result)
186
165
  end
187
166
 
188
167
  end
@@ -193,24 +172,23 @@ module Termtter
193
172
  end
194
173
 
195
174
  def pause
196
- @@task_manager.pause
175
+ @task_manager.pause
197
176
  end
198
177
 
199
178
  def resume
200
- @@task_manager.resume
179
+ @task_manager.resume
201
180
  end
202
181
 
203
182
  def add_task(*arg, &block)
204
- @@task_manager.add_task(*arg, &block)
183
+ @task_manager.add_task(*arg, &block)
205
184
  end
206
185
 
207
186
  def exit
208
187
  puts 'finalizing...'
209
188
 
210
- call_hooks([], :exit)
211
- call_new_hooks(:exit)
212
- @@task_manager.kill
213
- @@input_thread.kill if @@input_thread
189
+ call_hooks(:exit)
190
+ @task_manager.kill
191
+ @input_thread.kill if @input_thread
214
192
  end
215
193
 
216
194
  def load_default_plugins
@@ -246,7 +224,7 @@ module Termtter
246
224
  Termtter::CONF_FILE)
247
225
  end
248
226
 
249
- def pre_config_load()
227
+ def post_config_load()
250
228
  if config.system.devel
251
229
  plugin 'devel'
252
230
  end
@@ -258,14 +236,7 @@ module Termtter
258
236
  end
259
237
  Readline.completion_proc = lambda {|input|
260
238
  begin
261
- # FIXME: when migrate to Termtter::Command
262
- completions = @@completions.map {|completion|
263
- completion.call(input)
264
- }
265
- completions += @@new_commands.map {|name, command|
266
- command.complement(input)
267
- }
268
- completions.flatten.compact
239
+ @commands.map {|name, command| command.complement(input) }.flatten.compact
269
240
  rescue => e
270
241
  handle_error(e)
271
242
  end
@@ -276,19 +247,20 @@ module Termtter
276
247
  end
277
248
  end
278
249
 
250
+ # TODO: Make pluggable
279
251
  def setup_update_timeline_task()
280
252
  register_command(
281
253
  :name => :_update_timeline,
282
254
  :exec_proc => lambda {|arg|
283
255
  begin
284
- args = @@since_id ? [{:since_id => @@since_id}] : []
256
+ args = @since_id ? [{:since_id => @since_id}] : []
285
257
  statuses = Termtter::API.twitter.friends_timeline(*args)
286
258
  unless statuses.empty?
287
- @@since_id = statuses[0].id
259
+ print "\e[1K\e[0G" unless win?
260
+ @since_id = statuses[0].id
261
+ output(statuses, :update_friends_timeline)
262
+ Readline.refresh_line
288
263
  end
289
- call_hooks(statuses, :update_friends_timeline)
290
- Readline.refresh_line
291
- statuses
292
264
  rescue OpenURI::HTTPError => e
293
265
  if e.message == '401 Unauthorized'
294
266
  puts 'Could not login'
@@ -299,9 +271,11 @@ module Termtter
299
271
  }
300
272
  )
301
273
 
302
- add_task(:name => :update_timeline, :interval => config.update_interval) do
274
+ add_task(:name => :update_timeline, :interval => config.update_interval, :after => config.update_interval) do
303
275
  call_commands('_update_timeline')
304
276
  end
277
+
278
+ call_commands('_update_timeline')
305
279
  end
306
280
 
307
281
  def trap_setting()
@@ -321,9 +295,9 @@ module Termtter
321
295
  def start_input_thread
322
296
  setup_readline()
323
297
  trap_setting()
324
- @@input_thread = Thread.new do
298
+ @input_thread = Thread.new do
325
299
  while buf = Readline.readline(ERB.new(config.prompt).result(API.twitter.__send__(:binding)), true)
326
- Readline::HISTORY.pop if /^(u|update)\s+(.+)$/ =~ buf
300
+ Readline::HISTORY.pop if buf.empty?
327
301
  begin
328
302
  call_commands(buf)
329
303
  rescue CommandNotFound => e
@@ -334,29 +308,35 @@ module Termtter
334
308
  end
335
309
  end
336
310
  end
337
- @@input_thread.join
311
+ @input_thread.join
338
312
  end
339
313
 
340
- def run
341
- puts 'initializing...'
314
+ def logger
315
+ @logger
316
+ end
342
317
 
318
+ def setup_logger
319
+ @logger = config.log.logger || Logger.new(STDOUT)
320
+ @logger.level = config.log.level || Logger::WARN
321
+ end
322
+
323
+ def run
343
324
  load_default_plugins()
344
325
  load_config()
345
326
  Termtter::API.setup()
346
- pre_config_load()
327
+ setup_logger()
328
+ post_config_load()
347
329
 
348
- call_hooks([], :initialize)
349
- call_new_hooks(:initialize)
330
+ call_hooks(:initialize)
350
331
 
351
332
  setup_update_timeline_task()
352
- call_commands('_update_timeline')
353
333
 
354
- @@task_manager.run()
334
+ @task_manager.run()
355
335
  start_input_thread()
356
336
  end
357
337
 
358
338
  def handle_error(e)
359
- call_new_hooks("on_error", e)
339
+ call_hooks("on_error", e)
360
340
  rescue => e
361
341
  puts "Error: #{e}"
362
342
  puts e.backtrace.join("\n")