sup 0.10.2 → 0.11

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.

@@ -35,6 +35,14 @@ Return value:
35
35
  which will be appended by sup.
36
36
  EOS
37
37
 
38
+ HookManager.register "publish", <<EOS
39
+ Executed when a message or a chunk is requested to be published.
40
+ Variables:
41
+ chunk: Redwood::Message or Redwood::Chunk::* to be published.
42
+ Return value:
43
+ None.
44
+ EOS
45
+
38
46
  register_keymap do |k|
39
47
  k.add :toggle_detailed_header, "Toggle detailed header", 'h'
40
48
  k.add :show_header, "Show full message header", 'H'
@@ -59,6 +67,7 @@ EOS
59
67
  k.add :edit_as_new, "Edit message as new", 'D'
60
68
  k.add :save_to_disk, "Save message/attachment to disk", 's'
61
69
  k.add :save_all_to_disk, "Save all attachments to disk", 'A'
70
+ k.add :publish, "Publish message/attachment using publish-hook", 'P'
62
71
  k.add :search, "Search for messages from particular people", 'S'
63
72
  k.add :compose, "Compose message to person", 'm'
64
73
  k.add :subscribe_to_list, "Subscribe to/unsubscribe from mailing list", "("
@@ -74,6 +83,7 @@ EOS
74
83
  kk.add :delete_and_kill, "Delete this thread and kill buffer", 'd'
75
84
  kk.add :spam_and_kill, "Mark this thread as spam and kill buffer", 's'
76
85
  kk.add :unread_and_kill, "Mark this thread as unread and kill buffer", 'N'
86
+ kk.add :do_nothing_and_kill, "Just kill this buffer", '.'
77
87
  end
78
88
 
79
89
  k.add_multi "(a)rchive/(d)elete/mark as (s)pam/mark as u(N)read/do (n)othing:", ',' do |kk|
@@ -81,7 +91,7 @@ EOS
81
91
  kk.add :delete_and_next, "Delete this thread, kill buffer, and view next", 'd'
82
92
  kk.add :spam_and_next, "Mark this thread as spam, kill buffer, and view next", 's'
83
93
  kk.add :unread_and_next, "Mark this thread as unread, kill buffer, and view next", 'N'
84
- kk.add :do_nothing_and_next, "Kill buffer, and view next", 'n'
94
+ kk.add :do_nothing_and_next, "Kill buffer, and view next", 'n', ','
85
95
  end
86
96
 
87
97
  k.add_multi "(a)rchive/(d)elete/mark as (s)pam/mark as u(N)read/do (n)othing:", ']' do |kk|
@@ -89,7 +99,7 @@ EOS
89
99
  kk.add :delete_and_prev, "Delete this thread, kill buffer, and view previous", 'd'
90
100
  kk.add :spam_and_prev, "Mark this thread as spam, kill buffer, and view previous", 's'
91
101
  kk.add :unread_and_prev, "Mark this thread as unread, kill buffer, and view previous", 'N'
92
- kk.add :do_nothing_and_prev, "Kill buffer, and view previous", 'n'
102
+ kk.add :do_nothing_and_prev, "Kill buffer, and view previous", 'n', ']'
93
103
  end
94
104
  end
95
105
 
@@ -330,7 +340,7 @@ EOS
330
340
  elsif chunk.viewable?
331
341
  view chunk
332
342
  end
333
- if chunk.is_a?(Message)
343
+ if chunk.is_a?(Message) && $config[:jump_to_open_message]
334
344
  jump_to_message chunk
335
345
  jump_to_next_open if layout.state == :closed
336
346
  end
@@ -388,6 +398,15 @@ EOS
388
398
  end
389
399
  end
390
400
 
401
+ def publish
402
+ chunk = @chunk_lines[curpos] or return
403
+ if HookManager.enabled? "publish"
404
+ HookManager.run "publish", :chunk => chunk
405
+ else
406
+ BufferManager.flash "Publishing hook not defined."
407
+ end
408
+ end
409
+
391
410
  def edit_draft
392
411
  m = @message_lines[curpos] or return
393
412
  if m.is_draft?
@@ -508,6 +527,7 @@ EOS
508
527
  def spam_and_kill; spam_and_then :kill end
509
528
  def delete_and_kill; delete_and_then :kill end
510
529
  def unread_and_kill; unread_and_then :kill end
530
+ def do_nothing_and_kill; do_nothing_and_then :kill end
511
531
 
512
532
  def archive_and_next; archive_and_then :next end
513
533
  def spam_and_next; spam_and_then :next end
@@ -792,7 +812,12 @@ private
792
812
  if chunk.inlineable?
793
813
  lines = chunk.lines
794
814
  if @wrap
795
- width = buffer.content_width
815
+ config_width = $config[:wrap_width]
816
+ if config_width and config_width != 0
817
+ width = [config_width, buffer.content_width].min
818
+ else
819
+ width = buffer.content_width
820
+ end
796
821
  lines = lines.map { |l| l.chomp.wrap width }.flatten
797
822
  end
798
823
  lines.map { |line| [[chunk.color, "#{prefix}#{line}"]] }
@@ -37,6 +37,9 @@ EOS
37
37
  @polling = false
38
38
  @poll_sources = nil
39
39
  @mode = nil
40
+ @should_clear_running_totals = false
41
+ clear_running_totals # defines @running_totals
42
+ UpdateManager.register self
40
43
  end
41
44
 
42
45
  def poll_with_sources
@@ -45,8 +48,12 @@ EOS
45
48
 
46
49
  BufferManager.flash "Polling for new messages..."
47
50
  num, numi, from_and_subj, from_and_subj_inbox, loaded_labels = @mode.poll
48
- if num > 0
49
- BufferManager.flash "Loaded #{num.pluralize 'new message'}, #{numi} to inbox. Labels: #{loaded_labels.map{|l| l.to_s}.join(', ')}"
51
+ clear_running_totals if @should_clear_running_totals
52
+ @running_totals[:num] += num
53
+ @running_totals[:numi] += numi
54
+ @running_totals[:loaded_labels] += loaded_labels || []
55
+ if @running_totals[:num] > 0
56
+ BufferManager.flash "Loaded #{@running_totals[:num].pluralize 'new message'}, #{@running_totals[:numi]} to inbox. Labels: #{@running_totals[:loaded_labels].map{|l| l.to_s}.join(', ')}"
50
57
  else
51
58
  BufferManager.flash "No new messages."
52
59
  end
@@ -183,6 +190,10 @@ EOS
183
190
  Index.add_message m
184
191
  UpdateManager.relay self, :added, m
185
192
  end
193
+
194
+ def handle_idle_update sender, idle_since; @should_clear_running_totals = false; end
195
+ def handle_unidle_update sender, idle_since; @should_clear_running_totals = true; clear_running_totals; end
196
+ def clear_running_totals; @running_totals = {:num => 0, :numi => 0, :loaded_labels => Set.new}; end
186
197
  end
187
198
 
188
199
  end
@@ -0,0 +1,73 @@
1
+ module Redwood
2
+
3
+ class SearchManager
4
+ include Singleton
5
+
6
+ class ExpansionError < StandardError; end
7
+
8
+ def initialize fn
9
+ @fn = fn
10
+ @searches = {}
11
+ if File.exists? fn
12
+ IO.foreach(fn) do |l|
13
+ l =~ /^([^:]*): (.*)$/ or raise "can't parse #{fn} line #{l.inspect}"
14
+ @searches[$1] = $2
15
+ end
16
+ end
17
+ @modified = false
18
+ end
19
+
20
+ def all_searches; return @searches.keys.sort; end
21
+ def search_string_for name; return @searches[name]; end
22
+ def valid_name? name; name =~ /^[\w-]+$/; end
23
+ def name_format_hint; "letters, numbers, underscores and dashes only"; end
24
+
25
+ def add name, search_string
26
+ return unless valid_name? name
27
+ @searches[name] = search_string
28
+ @modified = true
29
+ end
30
+
31
+ def rename old, new
32
+ return unless @searches.has_key? old
33
+ search_string = @searches[old]
34
+ delete old if add new, search_string
35
+ end
36
+
37
+ def edit name, search_string
38
+ return unless @searches.has_key? name
39
+ @searches[name] = search_string
40
+ @modified = true
41
+ end
42
+
43
+ def delete name
44
+ return unless @searches.has_key? name
45
+ @searches.delete name
46
+ @modified = true
47
+ end
48
+
49
+ def expand search_string
50
+ expanded = search_string.dup
51
+ until (matches = expanded.scan(/\{([\w-]+)\}/).flatten).empty?
52
+ if !(unknown = matches - @searches.keys).empty?
53
+ error_message = "Unknown \"#{unknown.join('", "')}\" when expanding \"#{search_string}\""
54
+ elsif expanded.size >= 2048
55
+ error_message = "Check for infinite recursion in \"#{search_string}\""
56
+ end
57
+ if error_message
58
+ warn error_message
59
+ raise ExpansionError, error_message
60
+ end
61
+ matches.each { |n| expanded.gsub! "{#{n}}", "(#{@searches[n]})" if @searches.has_key? n }
62
+ end
63
+ return expanded
64
+ end
65
+
66
+ def save
67
+ return unless @modified
68
+ File.open(@fn, "w") { |f| @searches.sort.each { |(n, s)| f.puts "#{n}: #{s}" } }
69
+ @modified = false
70
+ end
71
+ end
72
+
73
+ end
@@ -33,7 +33,11 @@ class TextField
33
33
  @w, @y, @x, @width = window, y, x, width
34
34
  @question = question
35
35
  @completion_block = block
36
- @field = Ncurses::Form.new_field 1, @width - question.length, @y, @x + question.length, 256, 0
36
+ @field = Ncurses::Form.new_field 1, @width - question.length, @y, @x + question.length, 0, 0
37
+ if @field.respond_to? :opts_off
38
+ @field.opts_off Ncurses::Form::O_STATIC
39
+ @field.opts_off Ncurses::Form::O_BLANK
40
+ end
37
41
  @form = Ncurses::Form.new_form [@field]
38
42
  @value = default || ''
39
43
  Ncurses::Form.post_form @form
@@ -63,6 +67,7 @@ class TextField
63
67
  when Ncurses::KEY_ENTER # submit!
64
68
  @value = get_cursed_value
65
69
  @history.push @value unless @value =~ /^\s*$/
70
+ @i = @history.size
66
71
  return false
67
72
  when Ncurses::KEY_CANCEL # cancel
68
73
  @value = nil
@@ -102,29 +107,29 @@ class TextField
102
107
  Ncurses::Form::REQ_DEL_CHAR
103
108
  when Ncurses::KEY_BACKSPACE, 127 # 127 is also a backspace keysym
104
109
  Ncurses::Form::REQ_DEL_PREV
105
- when ?\C-a
110
+ when ?\C-a.ord, Ncurses::KEY_HOME
106
111
  nop
107
112
  Ncurses::Form::REQ_BEG_FIELD
108
- when ?\C-e
113
+ when ?\C-e.ord, Ncurses::KEY_END
109
114
  Ncurses::Form::REQ_END_FIELD
110
- when ?\C-k
115
+ when ?\C-k.ord
111
116
  Ncurses::Form::REQ_CLR_EOF
112
- when ?\C-u
117
+ when ?\C-u.ord
113
118
  set_cursed_value cursed_value_after_point
114
119
  Ncurses::Form.form_driver @form, Ncurses::Form::REQ_END_FIELD
115
120
  nop
116
121
  Ncurses::Form::REQ_BEG_FIELD
117
- when ?\C-w
122
+ when ?\C-w.ord
118
123
  Ncurses::Form.form_driver @form, Ncurses::Form::REQ_PREV_CHAR
119
124
  Ncurses::Form.form_driver @form, Ncurses::Form::REQ_DEL_WORD
120
125
  when Ncurses::KEY_UP, Ncurses::KEY_DOWN
121
- unless @history.empty?
126
+ unless !@i || @history.empty?
122
127
  value = get_cursed_value
123
- @i ||= @history.size
124
128
  #debug "history before #{@history.inspect}"
125
- @history[@i] = value #unless value =~ /^\s*$/
126
- @i = (@i + (c == Ncurses::KEY_UP ? -1 : 1)) % @history.size
127
- @value = @history[@i]
129
+ @i = @i + (c == Ncurses::KEY_UP ? -1 : 1)
130
+ @i = 0 if @i < 0
131
+ @i = @history.size if @i > @history.size
132
+ @value = @history[@i] || ''
128
133
  #debug "history after #{@history.inspect}"
129
134
  set_cursed_value @value
130
135
  Ncurses::Form::REQ_END_FIELD
@@ -174,7 +179,7 @@ private
174
179
  ## this is almost certainly unnecessary, but it's the only way
175
180
  ## i could get ncurses to remember my form's value
176
181
  def nop
177
- Ncurses::Form.form_driver @form, " "[0]
182
+ Ncurses::Form.form_driver @form, " ".ord
178
183
  Ncurses::Form.form_driver @form, Ncurses::Form::REQ_DEL_PREV
179
184
  end
180
185
  end
@@ -132,6 +132,10 @@ class Object
132
132
  ## "k combinator"
133
133
  def returning x; yield x; x; end
134
134
 
135
+ unless method_defined? :tap
136
+ def tap; yield self; self; end
137
+ end
138
+
135
139
  ## clone of java-style whole-method synchronization
136
140
  ## assumes a @mutex variable
137
141
  ## TODO: clean up, try harder to avoid namespace collisions
@@ -329,6 +333,13 @@ class String
329
333
  def transcode src_encoding=$encoding
330
334
  Iconv.easy_decode $encoding, src_encoding, self
331
335
  end
336
+
337
+ unless method_defined? :ascii_only?
338
+ def ascii_only?
339
+ size.times { |i| return false if self[i] & 128 != 0 }
340
+ return true
341
+ end
342
+ end
332
343
  end
333
344
 
334
345
  class Numeric
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sup
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.2
4
+ version: "0.11"
5
5
  platform: ruby
6
6
  authors:
7
7
  - William Morgan
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-01-26 08:56:01 -05:00
12
+ date: 2010-03-07 16:07:55 -08:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -23,7 +23,7 @@ dependencies:
23
23
  version: 1.1.3.1
24
24
  version:
25
25
  - !ruby/object:Gem::Dependency
26
- name: ncursesw
26
+ name: ncurses
27
27
  type: :runtime
28
28
  version_requirement:
29
29
  version_requirements: !ruby/object:Gem::Requirement
@@ -113,7 +113,6 @@ executables:
113
113
  - sup-sync
114
114
  - sup-sync-back
115
115
  - sup-tweak-labels
116
- - sup-convert-ferret-index
117
116
  extensions: []
118
117
 
119
118
  extra_rdoc_files: []
@@ -132,64 +131,64 @@ files:
132
131
  - bin/sup-sync
133
132
  - bin/sup-sync-back
134
133
  - bin/sup-tweak-labels
135
- - bin/sup-convert-ferret-index
136
134
  - lib/sup.rb
137
- - lib/ncurses.rb
138
- - lib/sup/poll.rb
139
- - lib/sup/source.rb
140
- - lib/sup/crypto.rb
141
- - lib/sup/horizontal-selector.rb
142
- - lib/sup/mode.rb
143
- - lib/sup/interactive-lock.rb
144
135
  - lib/sup/account.rb
145
- - lib/sup/imap.rb
146
- - lib/sup/maildir.rb
147
- - lib/sup/contact.rb
136
+ - lib/sup/interactive-lock.rb
148
137
  - lib/sup/message.rb
149
- - lib/sup/label.rb
150
- - lib/sup/index.rb
151
- - lib/sup/keymap.rb
152
138
  - lib/sup/rfc2047.rb
153
- - lib/sup/tagger.rb
154
- - lib/sup/util.rb
139
+ - lib/sup/buffer.rb
155
140
  - lib/sup/textfield.rb
156
- - lib/sup/xapian_index.rb
157
141
  - lib/sup/sent.rb
158
- - lib/sup/undo.rb
142
+ - lib/sup/colormap.rb
143
+ - lib/sup/logger.rb
159
144
  - lib/sup/mbox.rb
160
- - lib/sup/person.rb
161
- - lib/sup/ferret_index.rb
145
+ - lib/sup/draft.rb
146
+ - lib/sup/contact.rb
162
147
  - lib/sup/thread.rb
148
+ - lib/sup/mode.rb
149
+ - lib/sup/keymap.rb
150
+ - lib/sup/person.rb
151
+ - lib/sup/connection.rb
152
+ - lib/sup/message-chunks.rb
153
+ - lib/sup/source.rb
154
+ - lib/sup/tagger.rb
155
+ - lib/sup/undo.rb
156
+ - lib/sup/label.rb
157
+ - lib/sup/search.rb
158
+ - lib/sup/util.rb
163
159
  - lib/sup/update.rb
160
+ - lib/sup/idle.rb
164
161
  - lib/sup/hook.rb
165
- - lib/sup/message-chunks.rb
166
- - lib/sup/colormap.rb
167
- - lib/sup/buffer.rb
168
- - lib/sup/logger.rb
169
- - lib/sup/draft.rb
170
- - lib/sup/modes/label-search-results-mode.rb
162
+ - lib/sup/index.rb
163
+ - lib/sup/maildir.rb
164
+ - lib/sup/crypto.rb
165
+ - lib/sup/imap.rb
166
+ - lib/sup/horizontal-selector.rb
167
+ - lib/sup/poll.rb
168
+ - lib/sup/modes/person-search-results-mode.rb
169
+ - lib/sup/modes/file-browser-mode.rb
171
170
  - lib/sup/modes/completion-mode.rb
171
+ - lib/sup/modes/resume-mode.rb
172
+ - lib/sup/modes/console-mode.rb
173
+ - lib/sup/modes/help-mode.rb
174
+ - lib/sup/modes/label-search-results-mode.rb
175
+ - lib/sup/modes/label-list-mode.rb
172
176
  - lib/sup/modes/thread-index-mode.rb
173
- - lib/sup/modes/reply-mode.rb
174
- - lib/sup/modes/forward-mode.rb
177
+ - lib/sup/modes/line-cursor-mode.rb
178
+ - lib/sup/modes/text-mode.rb
175
179
  - lib/sup/modes/compose-mode.rb
176
- - lib/sup/modes/thread-view-mode.rb
177
- - lib/sup/modes/person-search-results-mode.rb
178
- - lib/sup/modes/help-mode.rb
179
- - lib/sup/modes/file-browser-mode.rb
180
+ - lib/sup/modes/log-mode.rb
180
181
  - lib/sup/modes/edit-message-mode.rb
181
- - lib/sup/modes/console-mode.rb
182
- - lib/sup/modes/contact-list-mode.rb
183
- - lib/sup/modes/poll-mode.rb
184
182
  - lib/sup/modes/inbox-mode.rb
185
- - lib/sup/modes/log-mode.rb
183
+ - lib/sup/modes/poll-mode.rb
184
+ - lib/sup/modes/reply-mode.rb
185
+ - lib/sup/modes/forward-mode.rb
186
+ - lib/sup/modes/buffer-list-mode.rb
186
187
  - lib/sup/modes/scroll-mode.rb
187
- - lib/sup/modes/text-mode.rb
188
- - lib/sup/modes/label-list-mode.rb
189
- - lib/sup/modes/resume-mode.rb
190
- - lib/sup/modes/line-cursor-mode.rb
191
188
  - lib/sup/modes/search-results-mode.rb
192
- - lib/sup/modes/buffer-list-mode.rb
189
+ - lib/sup/modes/search-list-mode.rb
190
+ - lib/sup/modes/thread-view-mode.rb
191
+ - lib/sup/modes/contact-list-mode.rb
193
192
  - lib/sup/mbox/ssh-file.rb
194
193
  - lib/sup/mbox/loader.rb
195
194
  - lib/sup/mbox/ssh-loader.rb
@@ -217,7 +216,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
217
216
  requirements: []
218
217
 
219
218
  rubyforge_project:
220
- rubygems_version: 1.3.5
219
+ rubygems_version: 1.3.3
221
220
  signing_key:
222
221
  specification_version: 3
223
222
  summary: A console-based email client with the best features of GMail, mutt, and emacs. Features full text search, labels, tagged operations, multiple buffers, recent contacts, and more.
@@ -1,84 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'rubygems'
4
- require 'trollop'
5
- require "sup"; Redwood::check_library_version_against "0.10.2"
6
-
7
- STATE_BACKUP_FN = "/tmp/sup-state.txt"
8
- SOURCE_BACKUP_FN = "sources.yaml-before-xapian-upgrade"
9
- BIN_DIR = File.dirname __FILE__
10
-
11
- $opts = Trollop::options do
12
- version "sup-convert-ferret-index (sup #{Redwood::VERSION})"
13
- banner <<EOS
14
- Convert an Sup Ferret index to a Xapian index.
15
-
16
- This will be a very slow process, but it will be lossless.
17
-
18
- If you interrupt it, nothing bad will happen. However, you will have to
19
- restart it from scratch.
20
-
21
- Usage:
22
- sup-convert-ferret-index
23
-
24
- Options:
25
- EOS
26
- opt :verbose, "Be verbose", :short => "-v"
27
- opt :dry_run, "Don't actually do anything, just print out what would happen.", :short => "-n"
28
- opt :force, "Force overwrite of an old Xapian index"
29
- opt :version, "Show version information", :short => :none
30
- end
31
-
32
- def build_cmd cmd
33
- (ENV["RUBY_INVOCATION"] ? ENV["RUBY_INVOCATION"] + " " : "") + File.join(BIN_DIR, cmd)
34
- end
35
-
36
- def run cmd
37
- puts cmd
38
- unless $opts[:dry_run]
39
- startt = Time.now
40
- system cmd or abort
41
- printf "(completed in %.1fs)\n", (Time.now - startt)
42
- end
43
- puts
44
- end
45
-
46
- begin
47
- require 'xapian'
48
- rescue LoadError
49
- Trollop::die "you don't have the xapian gem installed, so this script won't do much for you--`gem install xapian` (or xapian-full) first"
50
- end
51
-
52
- Redwood::start
53
- index = Redwood::Index.init
54
- Trollop::die "you appear to already have a Xapian index--delete #{File.join(Redwood::BASE_DIR, "xapian")} or use --force if you really want to do this" unless Redwood::Index.is_a_deprecated_ferret_index? || $opts[:force]
55
-
56
- puts "## Step one: back up all message state to #{STATE_BACKUP_FN}"
57
- run "#{build_cmd 'sup-dump'} --index ferret > #{STATE_BACKUP_FN}"
58
- puts "## message state saved to #{STATE_BACKUP_FN}"
59
-
60
- source_backup_fn = File.join Redwood::BASE_DIR, SOURCE_BACKUP_FN
61
- puts "## Step two: back up sources.yaml file to #{source_backup_fn}"
62
- run "cp #{Redwood::SOURCE_FN} #{source_backup_fn}"
63
-
64
- puts "## Step three: build the Xapian index"
65
- run "#{build_cmd 'sup-sync'} --all --all-sources --index xapian --restore #{STATE_BACKUP_FN} #{$opts[:verbose] ? '--verbose' : ''}"
66
- puts "## xapian index successfully built!"
67
-
68
- puts <<EOS
69
-
70
- Congratulations, your index has been upgraded to the Xapian backend.
71
- From now on, running sup should detect this index automatically.
72
-
73
- If you want to revert to the Ferret index:
74
- 1. overwrite #{Redwood::SOURCE_FN} with #{source_backup_fn}
75
- 2. use sup --index ferret, OR delete your #{Redwood::BASE_DIR}/xapian directory"
76
- Note that the Ferret index will not be supported as of the next Sup release, so
77
- you probably shouldn't do this.
78
-
79
- If you are happy with Xapian and want to reclaim precious hard drive space:
80
- 1. rm #{source_backup_fn}
81
- 2. rm -r #{Redwood::BASE_DIR}/ferret
82
-
83
- Happy supping!
84
- EOS