sup 0.0.8 → 0.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of sup might be problematic. Click here for more details.

Files changed (57) hide show
  1. data/HACKING +6 -36
  2. data/History.txt +11 -0
  3. data/Manifest.txt +5 -0
  4. data/README.txt +13 -31
  5. data/Rakefile +3 -3
  6. data/bin/sup +167 -89
  7. data/bin/sup-add +39 -29
  8. data/bin/sup-config +57 -31
  9. data/bin/sup-sync +60 -54
  10. data/bin/sup-sync-back +143 -0
  11. data/doc/FAQ.txt +56 -19
  12. data/doc/Philosophy.txt +34 -33
  13. data/doc/TODO +76 -46
  14. data/doc/UserGuide.txt +142 -122
  15. data/lib/sup.rb +76 -36
  16. data/lib/sup/account.rb +27 -19
  17. data/lib/sup/buffer.rb +130 -44
  18. data/lib/sup/contact.rb +1 -1
  19. data/lib/sup/draft.rb +1 -2
  20. data/lib/sup/imap.rb +64 -19
  21. data/lib/sup/index.rb +95 -16
  22. data/lib/sup/keymap.rb +1 -1
  23. data/lib/sup/label.rb +31 -5
  24. data/lib/sup/maildir.rb +7 -5
  25. data/lib/sup/mbox.rb +34 -15
  26. data/lib/sup/mbox/loader.rb +30 -12
  27. data/lib/sup/mbox/ssh-loader.rb +7 -5
  28. data/lib/sup/message.rb +93 -44
  29. data/lib/sup/modes/buffer-list-mode.rb +1 -1
  30. data/lib/sup/modes/completion-mode.rb +55 -0
  31. data/lib/sup/modes/compose-mode.rb +6 -25
  32. data/lib/sup/modes/contact-list-mode.rb +1 -1
  33. data/lib/sup/modes/edit-message-mode.rb +119 -29
  34. data/lib/sup/modes/file-browser-mode.rb +108 -0
  35. data/lib/sup/modes/forward-mode.rb +3 -20
  36. data/lib/sup/modes/inbox-mode.rb +9 -12
  37. data/lib/sup/modes/label-list-mode.rb +28 -46
  38. data/lib/sup/modes/label-search-results-mode.rb +1 -16
  39. data/lib/sup/modes/line-cursor-mode.rb +44 -5
  40. data/lib/sup/modes/person-search-results-mode.rb +1 -16
  41. data/lib/sup/modes/reply-mode.rb +18 -31
  42. data/lib/sup/modes/resume-mode.rb +6 -6
  43. data/lib/sup/modes/scroll-mode.rb +6 -5
  44. data/lib/sup/modes/search-results-mode.rb +6 -17
  45. data/lib/sup/modes/thread-index-mode.rb +70 -28
  46. data/lib/sup/modes/thread-view-mode.rb +65 -29
  47. data/lib/sup/person.rb +71 -30
  48. data/lib/sup/poll.rb +13 -4
  49. data/lib/sup/rfc2047.rb +61 -0
  50. data/lib/sup/sent.rb +7 -5
  51. data/lib/sup/source.rb +12 -9
  52. data/lib/sup/suicide.rb +36 -0
  53. data/lib/sup/tagger.rb +6 -6
  54. data/lib/sup/textfield.rb +76 -14
  55. data/lib/sup/thread.rb +97 -123
  56. data/lib/sup/util.rb +167 -1
  57. metadata +30 -5
data/HACKING CHANGED
@@ -4,47 +4,17 @@ Invoke it like this:
4
4
 
5
5
  ruby -I lib -w bin/sup
6
6
 
7
+ You'll have to install all gems mentioned in the Rakefile (look for the line
8
+ setting p.extra_deps). If you're on a Debian or Debian-based system (e.g.
9
+ Ubuntu), you'll have to make sure you have a complete Ruby installation,
10
+ especially libssl-ruby.
11
+
7
12
  Coding standards
8
13
  ----------------
9
14
 
10
15
  - Don't wrap code unless it really benefits from it. The days of
11
16
  80-column displays are long over. But do wrap comments and other
12
17
  text at whatever Emacs meta-Q does.
13
- - Use as few parentheses as possible.
18
+ - I like poetry mode.
14
19
  - Use {} for one-liner blocks and do/end for multi-line blocks.
15
20
 
16
- How messages are updated in the index
17
- -------------------------------------
18
-
19
- Ferret doesn't have any concept of updating; to change message state
20
- it must be deleted then re-added to the index.
21
-
22
- Thus there are a couple situations where we'll have a message to be
23
- "added", but it already exists in the index, and we need to decide
24
- which parts of which version to keep:
25
-
26
- 1. The user has changed the state of the message, e.g. read it or
27
- added a user label. In this case we want to use the state of the
28
- version in memory, but keep everything else on disk.
29
-
30
- This is the behavior of Index#update_message
31
-
32
- 2. We've received a new copy of the message. Crucially, this can
33
- happen for two different reasons:
34
-
35
- a. The message was sent to a mailing list to which the user is
36
- subscribed, and we're now getting that message back, possibly
37
- with altered content (subject mangling, signature adding, etc.)
38
-
39
- b. The user has moved the message between sources. E.g. if the
40
- primary inbox has a quota, and other sources are on local,
41
- quota-less disk, the user may regularly move messages from the
42
- inbox to the sources on disk.
43
-
44
- In both of these cases, the solution is to keep the state from the
45
- index, but use the new message contents.
46
-
47
- This is the behavior of Index#update_or_add_message, which can be
48
- also be called for new message.
49
-
50
-
data/History.txt CHANGED
@@ -1,3 +1,14 @@
1
+ == 0.1 / 2007-07-17
2
+ * MIME attachment creation.
3
+ * i18n support: character set conversion and rfc2047 header decoding.
4
+ * Better MIME handling.
5
+ * Multiple account support.
6
+ * Locking and concurrent Sup process detection and killation.
7
+ * Thread autoloading when you scroll down.
8
+ * Batch deletion of messages marked deleted or spam from message
9
+ sources via sup-sync-back tool (mbox only).
10
+ * Millions of bugfixes.
11
+
1
12
  == 0.0.8 / 2007-04-01
2
13
 
3
14
  * Maildir support!
data/Manifest.txt CHANGED
@@ -10,6 +10,7 @@ bin/sup-config
10
10
  bin/sup-dump
11
11
  bin/sup-recover-sources
12
12
  bin/sup-sync
13
+ bin/sup-sync-back
13
14
  doc/FAQ.txt
14
15
  doc/Philosophy.txt
15
16
  doc/TODO
@@ -33,9 +34,11 @@ lib/sup/mbox/ssh-loader.rb
33
34
  lib/sup/message.rb
34
35
  lib/sup/mode.rb
35
36
  lib/sup/modes/buffer-list-mode.rb
37
+ lib/sup/modes/completion-mode.rb
36
38
  lib/sup/modes/compose-mode.rb
37
39
  lib/sup/modes/contact-list-mode.rb
38
40
  lib/sup/modes/edit-message-mode.rb
41
+ lib/sup/modes/file-browser-mode.rb
39
42
  lib/sup/modes/forward-mode.rb
40
43
  lib/sup/modes/help-mode.rb
41
44
  lib/sup/modes/inbox-mode.rb
@@ -54,8 +57,10 @@ lib/sup/modes/thread-index-mode.rb
54
57
  lib/sup/modes/thread-view-mode.rb
55
58
  lib/sup/person.rb
56
59
  lib/sup/poll.rb
60
+ lib/sup/rfc2047.rb
57
61
  lib/sup/sent.rb
58
62
  lib/sup/source.rb
63
+ lib/sup/suicide.rb
59
64
  lib/sup/tagger.rb
60
65
  lib/sup/textfield.rb
61
66
  lib/sup/thread.rb
data/README.txt CHANGED
@@ -4,9 +4,10 @@ sup
4
4
 
5
5
  == DESCRIPTION:
6
6
 
7
- Sup is a console-based email client that combines the best
8
- features of GMail, mutt, and emacs. Sup matches the power of GMail
9
- with the speed and simplicity of a console interface.
7
+ Sup is a console-based email client for people with a lot of email.
8
+ It supports tagging, very fast full-text search, automatic contact-
9
+ list management, and more. If you're the type of person who treats
10
+ email as an extension of your long-term memory, Sup is for you.
10
11
 
11
12
  Sup makes it easy to:
12
13
  - Handle massive amounts of email.
@@ -84,24 +85,15 @@ Current limitations which will be fixed:
84
85
 
85
86
  == SYNOPSYS:
86
87
 
87
- 1. sup-import <source>+
88
- 2. sup
89
- 3. edit ~/.sup/config.yaml for the (very few) settings sup has
90
-
91
- Where <source> is a filename (for mbox files), an imap or imaps URI,
92
- or a mbox+ssh URI (for remote mbox files). You will be prompted for
93
- a username and password if required.
94
-
95
- sup-import has several options which control whether you want
96
- messages from particular mailboxes not to be added to the inbox, or
97
- not to be marked as new, so run it with -h for help.
88
+ 0. sup-config
89
+ 1. sup
98
90
 
99
91
  Note that Sup never changes the contents of any mailboxes; it only
100
92
  indexes in to them. So it shouldn't ever corrupt your mail. The flip
101
93
  side is that if you change a mailbox (e.g. delete messages, or, in
102
94
  the case of mbox files, read an unread message) then Sup will be
103
95
  unable to load messages from that source and will ask you to run
104
- sup-import --rebuild.
96
+ sup-sync --changed.
105
97
 
106
98
  == REQUIREMENTS:
107
99
 
@@ -109,28 +101,18 @@ Current limitations which will be fixed:
109
101
  * ncurses
110
102
  * rmail
111
103
  * highline
112
- * trollop
113
104
  * net-ssh
105
+ * trollop >= 1.7
106
+ * lockfile
107
+ * mime-types
114
108
 
115
109
  == INSTALL:
116
110
 
117
111
  * gem install sup -y
118
112
 
119
- == KNOWN BUGS IN OTHER PACKAGES:
120
-
121
- * If you get an error about frozen strings in RubyMail when importing
122
- certain messages with attachments, in rmail, change line 159 of
123
- multipart.rb to:
124
- chunk = chunk[0..start]
125
- This is because RubyMail hasn't been updated since like Ruby 1.8.2.
126
- Please bug Matt Lickey.
127
- * Occasionally Ferret produces something the Ruby GC doesn't like
128
- (particularly when importing messages from very large sources).
129
- No worries, just re-run sup-import. (This is unresolved atm.)
130
- * If you are using IMAP or Maildir and see this error:
131
- /usr/local/lib/ruby/1.8/yaml.rb:133:in `transfer': allocator undefined for Bignum (TypeError)
132
- then you need to upgrade to Ruby 1.8.5. YAML in earlier versions
133
- can't parse BigNums.
113
+ == PROBLEMS:
114
+
115
+ See FAQ.txt for some common problems and their solutions.
134
116
 
135
117
  == LICENSE:
136
118
 
data/Rakefile CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'rubygems'
4
4
  require 'hoe'
5
- require './lib/sup.rb'
5
+ require 'sup'
6
6
 
7
7
  class Hoe
8
8
  def extra_deps; @extra_deps.reject { |x| Array(x).first == "hoe" } end
@@ -16,14 +16,14 @@ Hoe.new('sup', Redwood::VERSION) do |p|
16
16
  p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[2].gsub(/^\s+/, "")
17
17
  p.changes = p.paragraphs_of('History.txt', 0..0).join("\n\n")
18
18
  p.email = "wmorgan-sup@masanjin.net"
19
- p.extra_deps = [['ferret', '>= 0.10.13'], ['ncurses', '>= 0.9.1'], ['rmail', '>= 0.17'], 'highline', 'net-ssh', ['trollop', '>= 1.5']]
19
+ p.extra_deps = [['ferret', '>= 0.10.13'], ['ncurses', '>= 0.9.1'], ['rmail', '>= 0.17'], 'highline', 'net-ssh', ['trollop', '>= 1.7'], 'lockfile', 'mime-types']
20
20
  end
21
21
 
22
22
  rule 'ss?.png' => 'ss?-small.png' do |t|
23
23
  end
24
24
 
25
25
  ## is there really no way to make a rule for this?
26
- WWW_FILES = %w(www/index.html README.txt doc/Philosophy.txt doc/FAQ.txt doc/UserGuide.txt)
26
+ WWW_FILES = %w(www/index.html README.txt doc/Philosophy.txt doc/FAQ.txt doc/UserGuide.txt www/main.css)
27
27
 
28
28
  SCREENSHOTS = FileList["www/ss?.png"]
29
29
  SCREENSHOTS_SMALL = []
data/bin/sup CHANGED
@@ -2,8 +2,23 @@
2
2
 
3
3
  require 'rubygems'
4
4
  require 'ncurses'
5
+ require 'fileutils'
6
+ require 'trollop'
5
7
  require "sup"
6
8
 
9
+ $opts = Trollop::options do
10
+ version "sup v#{Redwood::VERSION}"
11
+ banner <<EOS
12
+ Sup is a curses-based email client.
13
+
14
+ Usage:
15
+ sup [options]
16
+
17
+ Options are:
18
+ EOS
19
+ opt :no_threads, "Turn of threading. Helps with debugging. (Necessarily disables background polling for new messages.)"
20
+ end
21
+
7
22
  Thread.abort_on_exception = true # make debugging possible
8
23
 
9
24
  module Redwood
@@ -31,31 +46,60 @@ def start_cursing
31
46
  Ncurses.stdscr.keypad 1
32
47
  Ncurses.curs_set 0
33
48
  Ncurses.start_color
49
+ $cursing = true
34
50
  end
35
51
 
36
52
  def stop_cursing
53
+ return unless $cursing
37
54
  Ncurses.curs_set 1
38
55
  Ncurses.echo
39
56
  Ncurses.endwin
40
57
  end
41
58
  module_function :start_cursing, :stop_cursing
42
59
 
43
- Redwood::start
44
- Index.new.load
60
+ Index.new
61
+ begin
62
+ Index.lock
63
+ rescue Index::LockError => e
64
+ require 'highline'
45
65
 
46
- if(s = Index.source_for DraftManager.source_name)
47
- DraftManager.source = s
48
- else
49
- Index.add_source DraftManager.new_source
50
- end
66
+ h = HighLine.new
67
+ h.wrap_at = :auto
68
+ h.say Index.fancy_lock_error_message_for(e)
51
69
 
52
- if(s = Index.source_for SentManager.source_name)
53
- SentManager.source = s
54
- else
55
- Index.add_source SentManager.new_source
70
+ case h.ask("Should I ask that process to kill itself? ")
71
+ when /^\s*y\s*$/i
72
+ h.say "Ok, suggesting sepuku..."
73
+ FileUtils.touch Redwood::SUICIDE_FN
74
+ sleep SuicideManager::DELAY * 2
75
+ FileUtils.rm_f Redwood::SUICIDE_FN
76
+ h.say "Let's try that again."
77
+ retry
78
+ else
79
+ h.say <<EOS
80
+ Ok, giving up. If the process crashed and left a stale lockfile, you
81
+ can fix this by manually deleting #{Index.lockfile}.
82
+ EOS
83
+ exit
84
+ end
56
85
  end
57
86
 
58
87
  begin
88
+ Redwood::start
89
+ Index.load
90
+
91
+ if(s = Index.source_for DraftManager.source_name)
92
+ DraftManager.source = s
93
+ else
94
+ Index.add_source DraftManager.new_source
95
+ end
96
+
97
+ if(s = Index.source_for SentManager.source_name)
98
+ SentManager.source = s
99
+ else
100
+ Index.add_source SentManager.new_source
101
+ end
102
+
59
103
  log "starting curses"
60
104
  start_cursing
61
105
 
@@ -65,6 +109,8 @@ begin
65
109
  c.add :index_old_color, Ncurses::COLOR_WHITE, Ncurses::COLOR_BLACK
66
110
  c.add :index_new_color, Ncurses::COLOR_WHITE, Ncurses::COLOR_BLACK,
67
111
  Ncurses::A_BOLD
112
+ c.add :index_starred_color, Ncurses::COLOR_YELLOW, Ncurses::COLOR_BLACK,
113
+ Ncurses::A_BOLD
68
114
  c.add :labellist_old_color, Ncurses::COLOR_WHITE, Ncurses::COLOR_BLACK
69
115
  c.add :labellist_new_color, Ncurses::COLOR_WHITE, Ncurses::COLOR_BLACK,
70
116
  Ncurses::A_BOLD
@@ -73,7 +119,7 @@ begin
73
119
  c.add :message_patina_color, Ncurses::COLOR_BLACK, Ncurses::COLOR_GREEN
74
120
  c.add :alternate_patina_color, Ncurses::COLOR_BLACK, Ncurses::COLOR_BLUE
75
121
  c.add :missing_message_color, Ncurses::COLOR_BLACK, Ncurses::COLOR_RED
76
- c.add :mime_color, Ncurses::COLOR_CYAN, Ncurses::COLOR_BLACK
122
+ c.add :attachment_color, Ncurses::COLOR_CYAN, Ncurses::COLOR_BLACK
77
123
  c.add :quote_patina_color, Ncurses::COLOR_YELLOW, Ncurses::COLOR_BLACK
78
124
  c.add :sig_patina_color, Ncurses::COLOR_YELLOW, Ncurses::COLOR_BLACK
79
125
  c.add :quote_color, Ncurses::COLOR_YELLOW, Ncurses::COLOR_BLACK
@@ -91,6 +137,8 @@ begin
91
137
  Ncurses::A_BOLD
92
138
  c.add :draft_notification_color, Ncurses::COLOR_RED, Ncurses::COLOR_BLACK,
93
139
  Ncurses::A_BOLD
140
+ c.add :completion_character_color, Ncurses::COLOR_WHITE,
141
+ Ncurses::COLOR_BLACK, Ncurses::A_BOLD
94
142
  end
95
143
 
96
144
  log "initializing buffer manager"
@@ -98,7 +146,7 @@ begin
98
146
 
99
147
  log "initializing mail index buffer"
100
148
  imode = InboxMode.new
101
- ibuf = bm.spawn "inbox", imode
149
+ ibuf = bm.spawn "Inbox", imode
102
150
 
103
151
  log "ready for interaction!"
104
152
  Logger.make_buf
@@ -122,99 +170,129 @@ begin
122
170
  end if s.respond_to? :connect
123
171
  end
124
172
 
125
- imode.load_threads :num => ibuf.content_height, :when_done => lambda { reporting_thread { sleep 1; PollManager.poll } }
173
+ imode.load_threads :num => ibuf.content_height, :when_done => lambda { reporting_thread { sleep 1; PollManager.poll } unless $opts[:no_threads] }
126
174
 
127
- PollManager.start_thread
175
+ unless $opts[:no_threads]
176
+ PollManager.start
177
+ SuicideManager.start
178
+ Index.start_lock_update_thread
179
+ end
128
180
 
129
- until $exception
130
- bm.draw_screen
181
+ until $exception || SuicideManager.die?
131
182
  c = Ncurses.nonblocking_getch
183
+ next unless c
132
184
  bm.erase_flash
133
185
 
134
- if c == Ncurses::KEY_RESIZE
135
- bm.handle_resize
136
- elsif c
137
- unless bm.handle_input(c)
138
- x = global_keymap.action_for c
139
- case x
140
- when :quit
141
- break if bm.kill_all_buffers_safely
142
- when :help
143
- curmode = bm.focus_buf.mode
144
- bm.spawn_unless_exists("<help for #{curmode.name}>") { HelpMode.new curmode, global_keymap }
145
- when :roll_buffers
146
- bm.roll_buffers
147
- when :roll_buffers_backwards
148
- bm.roll_buffers_backwards
149
- when :kill_buffer
150
- bm.kill_buffer_safely bm.focus_buf
151
- when :list_buffers
152
- bm.spawn_unless_exists("Buffer List") { BufferListMode.new }
153
- when :list_contacts
154
- b = bm.spawn_unless_exists("Contact List") { ContactListMode.new }
155
- b.mode.load_in_background
156
- when :search
157
- text = bm.ask :search, "query: "
158
- next unless text && text !~ /^\s*$/
159
-
160
- begin
161
- qobj = Index.parse_user_query_string text
162
- short_text = text.length < 20 ? text : text[0 ... 20] + "..."
163
- log "built query from #{text.inspect}: #{qobj}"
164
- mode = SearchResultsMode.new qobj
165
- bm.spawn "search: \"#{short_text}\"", mode
166
- mode.load_threads :num => mode.buffer.content_height
167
- rescue Ferret::QueryParser::QueryParseException => e
168
- bm.flash "Couldn't parse query."
169
- end
170
- when :list_labels
171
- b = bm.spawn_unless_exists("Label List") { LabelListMode.new }
172
- b.mode.load_in_background
173
- when :compose
174
- mode = ComposeMode.new
175
- bm.spawn "New Message", mode
176
- mode.edit
177
- when :poll
178
- bm.raise_to_front PollManager.buffer
179
- reporting_thread { PollManager.poll }
180
- when :recall_draft
181
- case Index.num_results_for :label => :draft
182
- when 0
183
- bm.flash "No draft messages."
184
- when 1
185
- m = nil
186
- Index.each_id_by_date(:label => :draft) { |mid, builder| m = builder.call }
187
- r = ResumeMode.new(m)
188
- BufferManager.spawn "Edit message", r
189
- r.edit
190
- else
191
- b = BufferManager.spawn_unless_exists(:draft) do
192
- mode = LabelSearchResultsMode.new [:draft]
193
- end
194
- b.mode.load_threads :num => b.content_height
186
+ unless bm.handle_input(c)
187
+ x = global_keymap.action_for c
188
+ case x
189
+ when :quit
190
+ break if bm.kill_all_buffers_safely
191
+ when :help
192
+ curmode = bm.focus_buf.mode
193
+ bm.spawn_unless_exists("<help for #{curmode.name}>") { HelpMode.new curmode, global_keymap }
194
+ when :roll_buffers
195
+ bm.roll_buffers
196
+ when :roll_buffers_backwards
197
+ bm.roll_buffers_backwards
198
+ when :kill_buffer
199
+ bm.kill_buffer_safely bm.focus_buf
200
+ when :list_buffers
201
+ bm.spawn_unless_exists("Buffer List") { BufferListMode.new }
202
+ when :list_contacts
203
+ b = bm.spawn_unless_exists("Contact List") { ContactListMode.new }
204
+ b.mode.load_in_background
205
+ when :search
206
+ text = bm.ask :search, "query: "
207
+ next unless text && text !~ /^\s*$/
208
+
209
+ begin
210
+ qobj = Index.parse_user_query_string text
211
+ short_text = text.length < 20 ? text : text[0 ... 20] + "..."
212
+ log "built query from #{text.inspect}: #{qobj}"
213
+ mode = SearchResultsMode.new qobj
214
+ bm.spawn "search: \"#{short_text}\"", mode
215
+ mode.load_threads :num => mode.buffer.content_height
216
+ rescue Ferret::QueryParser::QueryParseException => e
217
+ bm.flash "Couldn't parse query."
218
+ end
219
+ when :list_labels
220
+ labels = LabelManager.listable_label_strings
221
+ user_label = bm.ask_with_completions :label, "Show threads with label (enter for listing): ", labels
222
+ user_label = bm.spawn_modal("Label list", LabelListMode.new) if user_label && user_label.empty?
223
+
224
+ label = LabelManager.label_for user_label if user_label
225
+ case label
226
+ when nil
227
+ when :inbox
228
+ BufferManager.raise_to_front InboxMode.instance.buffer
229
+ else
230
+ b = BufferManager.spawn_unless_exists("All threads with label '#{user_label}'") do
231
+ mode = LabelSearchResultsMode.new([label])
195
232
  end
196
- when :nothing
197
- when :redraw
198
- bm.completely_redraw_screen
233
+ b.mode.load_threads :num => b.content_height
234
+ end
235
+
236
+ when :compose
237
+ mode = ComposeMode.new
238
+ bm.spawn "New Message", mode
239
+ mode.edit
240
+ when :poll
241
+ # bm.raise_to_front PollManager.buffer
242
+ reporting_thread { PollManager.poll }
243
+ when :recall_draft
244
+ case Index.num_results_for :label => :draft
245
+ when 0
246
+ bm.flash "No draft messages."
247
+ when 1
248
+ m = nil
249
+ Index.each_id_by_date(:label => :draft) { |mid, builder| m = builder.call }
250
+ r = ResumeMode.new(m)
251
+ BufferManager.spawn "Edit message", r
252
+ r.edit
199
253
  else
200
- bm.flash "Unknown key press '#{c.to_character}' for #{bm.focus_buf.mode.name}."
254
+ b = BufferManager.spawn_unless_exists("All drafts") do
255
+ mode = LabelSearchResultsMode.new [:draft]
256
+ end
257
+ b.mode.load_threads :num => b.content_height
201
258
  end
259
+ when :nothing
260
+ when :redraw
261
+ bm.completely_redraw_screen
262
+ else
263
+ bm.flash "Unknown key press '#{c.to_character}' for #{bm.focus_buf.mode.name}."
202
264
  end
203
265
  end
266
+
267
+ bm.draw_screen
204
268
  end
205
269
  rescue Exception => e
206
270
  $exception ||= e
207
271
  ensure
272
+ unless $opts[:no_threads]
273
+ PollManager.stop if PollManager.instantiated?
274
+ SuicideManager.stop if PollManager.instantiated?
275
+ Index.stop_lock_update_thread
276
+ end
277
+
208
278
  Redwood::finish
209
279
  stop_cursing
210
- if $exception
211
- Redwood::log "oh crap, an exception"
280
+ Redwood::log "stopped cursing"
281
+
282
+ if SuicideManager.instantiated? && SuicideManager.die?
283
+ Redwood::log "I've been ordered to commit sepuku. I obey!"
284
+ end
285
+
286
+ case $exception
287
+ when nil
288
+ Redwood::log "no fatal errors. good job, william."
289
+ Index.save
212
290
  else
213
- Redwood::log "good night, sweet prince!"
291
+ Redwood::log "oh crap, an exception"
214
292
  end
215
- end
216
293
 
217
- Index.save unless $exception # TODO: think about this
294
+ Index.unlock
295
+ end
218
296
 
219
297
  if $exception
220
298
  $stderr.puts <<EOS
@@ -222,14 +300,14 @@ if $exception
222
300
  I'm very sorry, but it seems that an error occurred in Sup.
223
301
  Please accept my sincere apologies. If you don't mind, please
224
302
  send the backtrace below and a brief report of the circumstances
225
- to wmorgan-sup at masanjin dot nets so that I might address this
303
+ to sup-talk at rubyforge dot orgs so that I might address this
226
304
  problem. Thank you!
227
305
 
228
306
  Sincerely,
229
307
  William
230
308
  ----------------------------------------------------------------
231
309
 
232
- The problem was: #{$exception.message} (error type #{$exception.class.name})
310
+ The problem was: '#{$exception.message}' (error type #{$exception.class.name})
233
311
  A backtrace follows:
234
312
  EOS
235
313
  raise $exception