sup 0.14.1.1 → 0.15.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.
- data/CONTRIBUTORS +14 -11
- data/History.txt +44 -0
- data/README.md +9 -4
- data/ReleaseNotes +8 -0
- data/bin/sup +1 -0
- data/bin/sup-add +2 -1
- data/bin/sup-config +3 -0
- data/bin/sup-sync-back-maildir +127 -0
- data/bin/{sup-sync-back → sup-sync-back-mbox} +3 -3
- data/lib/sup.rb +75 -3
- data/lib/sup/index.rb +54 -16
- data/lib/sup/label.rb +2 -2
- data/lib/sup/maildir.rb +120 -47
- data/lib/sup/mbox.rb +1 -1
- data/lib/sup/message.rb +65 -2
- data/lib/sup/modes/edit_message_mode.rb +16 -8
- data/lib/sup/modes/forward_mode.rb +13 -4
- data/lib/sup/modes/reply_mode.rb +6 -0
- data/lib/sup/modes/search_list_mode.rb +12 -0
- data/lib/sup/modes/thread_index_mode.rb +30 -0
- data/lib/sup/modes/thread_view_mode.rb +15 -5
- data/lib/sup/poll.rb +62 -17
- data/lib/sup/search.rb +18 -0
- data/lib/sup/sent.rb +1 -1
- data/lib/sup/source.rb +32 -4
- data/lib/sup/thread.rb +6 -0
- data/lib/sup/util.rb +12 -2
- data/lib/sup/util/query.rb +5 -2
- data/lib/sup/version.rb +1 -1
- metadata +17 -16
@@ -197,7 +197,15 @@ EOS
|
|
197
197
|
@file = Tempfile.new ["sup.#{self.class.name.gsub(/.*::/, '').camel_to_hyphy}", ".eml"]
|
198
198
|
@file.puts format_headers(@header - NON_EDITABLE_HEADERS).first
|
199
199
|
@file.puts
|
200
|
-
|
200
|
+
|
201
|
+
begin
|
202
|
+
text = @body.join("\n")
|
203
|
+
rescue Encoding::CompatibilityError
|
204
|
+
text = @body.map { |x| x.fix_encoding! }.join("\n")
|
205
|
+
debug "encoding problem while writing message, trying to rescue, but expect errors: #{text}"
|
206
|
+
end
|
207
|
+
|
208
|
+
@file.puts text
|
201
209
|
@file.puts sig if ($config[:edit_signature] and !@sig_edited)
|
202
210
|
@file.close
|
203
211
|
end
|
@@ -205,13 +213,13 @@ EOS
|
|
205
213
|
def set_sig_edit_flag
|
206
214
|
sig = sig_lines.join("\n")
|
207
215
|
if $config[:edit_signature]
|
208
|
-
pbody = @body.join("\n")
|
216
|
+
pbody = @body.map { |x| x.fix_encoding! }.join("\n").fix_encoding!
|
209
217
|
blen = pbody.length
|
210
218
|
slen = sig.length
|
211
219
|
|
212
220
|
if blen > slen and pbody[blen-slen..blen] == sig
|
213
221
|
@sig_edited = false
|
214
|
-
@body = pbody[0..blen-slen].split("\n")
|
222
|
+
@body = pbody[0..blen-slen].fix_encoding!.split("\n")
|
215
223
|
else
|
216
224
|
@sig_edited = true
|
217
225
|
end
|
@@ -319,7 +327,7 @@ EOS
|
|
319
327
|
end
|
320
328
|
|
321
329
|
def delete_attachment
|
322
|
-
i = curpos - @attachment_lines_offset - DECORATION_LINES -
|
330
|
+
i = curpos - @attachment_lines_offset - (@selectors.empty? ? 0 : DECORATION_LINES) - @selectors.size
|
323
331
|
if i >= 0 && i < @attachments.size && BufferManager.ask_yes_or_no("Delete attachment #{@attachment_names[i]}?")
|
324
332
|
@attachments.delete_at i
|
325
333
|
@attachment_names.delete_at i
|
@@ -551,9 +559,9 @@ protected
|
|
551
559
|
m.header[k] =
|
552
560
|
case v
|
553
561
|
when String
|
554
|
-
(k.match(/subject/i) ? mime_encode_subject(v) : mime_encode_address(v)).fix_encoding!
|
562
|
+
(k.match(/subject/i) ? mime_encode_subject(v).dup.fix_encoding! : mime_encode_address(v)).dup.fix_encoding!
|
555
563
|
when Array
|
556
|
-
(v.map { |v| mime_encode_address v }.join ", ").fix_encoding!
|
564
|
+
(v.map { |v| mime_encode_address v }.join ", ").dup.fix_encoding!
|
557
565
|
end
|
558
566
|
end
|
559
567
|
|
@@ -635,12 +643,12 @@ private
|
|
635
643
|
if HookManager.enabled? "mentions-attachments"
|
636
644
|
HookManager.run "mentions-attachments", :header => @header, :body => @body
|
637
645
|
else
|
638
|
-
@body.any? { |l| l =~ /^[^>]/ && l =~ /\battach(ment|ed|ing|)\b/i }
|
646
|
+
@body.any? { |l| l.fix_encoding! =~ /^[^>]/ && l.fix_encoding! =~ /\battach(ment|ed|ing|)\b/i }
|
639
647
|
end
|
640
648
|
end
|
641
649
|
|
642
650
|
def top_posting?
|
643
|
-
@body.join("\n") =~ /(\S+)\s*Excerpts from.*\n(>.*\n)+\s*\Z/
|
651
|
+
@body.map { |x| x.fix_encoding! }.join("\n").fix_encoding! =~ /(\S+)\s*Excerpts from.*\n(>.*\n)+\s*\Z/
|
644
652
|
end
|
645
653
|
|
646
654
|
def sig_lines
|
@@ -7,9 +7,10 @@ class ForwardMode < EditMessageMode
|
|
7
7
|
"From" => AccountManager.default_account.full_address,
|
8
8
|
}
|
9
9
|
|
10
|
+
@m = opts[:message]
|
10
11
|
header["Subject"] =
|
11
|
-
if
|
12
|
-
"Fwd: " +
|
12
|
+
if @m
|
13
|
+
"Fwd: " + @m.subj
|
13
14
|
elsif opts[:attachments]
|
14
15
|
"Fwd: " + opts[:attachments].keys.join(", ")
|
15
16
|
end
|
@@ -19,8 +20,8 @@ class ForwardMode < EditMessageMode
|
|
19
20
|
header["Bcc"] = opts[:bcc].map { |p| p.full_address }.join(", ") if opts[:bcc]
|
20
21
|
|
21
22
|
body =
|
22
|
-
if
|
23
|
-
forward_body_lines
|
23
|
+
if @m
|
24
|
+
forward_body_lines @m
|
24
25
|
elsif opts[:attachments]
|
25
26
|
["Note: #{opts[:attachments].size.pluralize 'attachment'}."]
|
26
27
|
end
|
@@ -68,6 +69,14 @@ protected
|
|
68
69
|
m.quotable_header_lines + [""] + m.quotable_body_lines +
|
69
70
|
["--- End forwarded message ---"]
|
70
71
|
end
|
72
|
+
|
73
|
+
def send_message
|
74
|
+
return unless super # super returns true if the mail has been sent
|
75
|
+
if @m
|
76
|
+
@m.add_label :forwarded
|
77
|
+
Index.save_message @m
|
78
|
+
end
|
79
|
+
end
|
71
80
|
end
|
72
81
|
|
73
82
|
end
|
data/lib/sup/modes/reply_mode.rb
CHANGED
@@ -145,6 +145,12 @@ protected
|
|
145
145
|
def rename_selected_search
|
146
146
|
old_name, num_unread = @searches[curpos]
|
147
147
|
return unless old_name
|
148
|
+
|
149
|
+
if SearchManager.predefined_searches.has_key? old_name
|
150
|
+
BufferManager.flash "Cannot be edited: predefined search."
|
151
|
+
return
|
152
|
+
end
|
153
|
+
|
148
154
|
new_name = BufferManager.ask :save_search, "Rename this saved search: ", old_name
|
149
155
|
return unless new_name && new_name !~ /^\s*$/ && new_name != old_name
|
150
156
|
new_name.strip!
|
@@ -163,6 +169,12 @@ protected
|
|
163
169
|
def edit_selected_search
|
164
170
|
name, num_unread = @searches[curpos]
|
165
171
|
return unless name
|
172
|
+
|
173
|
+
if SearchManager.predefined_searches.has_key? name
|
174
|
+
BufferManager.flash "Cannot be edited: predefined search."
|
175
|
+
return
|
176
|
+
end
|
177
|
+
|
166
178
|
old_search_string = SearchManager.search_string_for name
|
167
179
|
new_search_string = BufferManager.ask :search, "Edit this saved search: ", (old_search_string + " ")
|
168
180
|
return unless new_search_string && new_search_string !~ /^\s*$/ && new_search_string != old_search_string
|
@@ -200,6 +200,26 @@ EOS
|
|
200
200
|
BufferManager.draw_screen
|
201
201
|
end
|
202
202
|
|
203
|
+
def handle_updated_update sender, m
|
204
|
+
t = thread_containing(m) or return
|
205
|
+
l = @lines[t] or return
|
206
|
+
@ts_mutex.synchronize do
|
207
|
+
@ts.delete_message m
|
208
|
+
@ts.add_message m
|
209
|
+
end
|
210
|
+
Index.save_thread t
|
211
|
+
update_text_for_line l
|
212
|
+
end
|
213
|
+
|
214
|
+
def handle_location_deleted_update sender, m
|
215
|
+
t = thread_containing(m)
|
216
|
+
delete_thread t if t and t.first.id == m.id
|
217
|
+
@ts_mutex.synchronize do
|
218
|
+
@ts.delete_message m if t
|
219
|
+
end
|
220
|
+
update
|
221
|
+
end
|
222
|
+
|
203
223
|
def handle_single_message_deleted_update sender, m
|
204
224
|
@ts_mutex.synchronize do
|
205
225
|
return unless @ts.contains? m
|
@@ -755,6 +775,16 @@ protected
|
|
755
775
|
update
|
756
776
|
end
|
757
777
|
|
778
|
+
def delete_thread t
|
779
|
+
@mutex.synchronize do
|
780
|
+
i = @threads.index(t) or return
|
781
|
+
@threads.delete_at i
|
782
|
+
@size_widgets.delete_at i
|
783
|
+
@date_widgets.delete_at i
|
784
|
+
@tags.drop_tag_for t
|
785
|
+
end
|
786
|
+
end
|
787
|
+
|
758
788
|
def hide_thread t
|
759
789
|
@mutex.synchronize do
|
760
790
|
i = @threads.index(t) or return
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'shellwords'
|
2
|
+
|
1
3
|
module Redwood
|
2
4
|
|
3
5
|
class ThreadViewMode < LineCursorMode
|
@@ -246,6 +248,8 @@ EOS
|
|
246
248
|
sm.puts m.raw_message
|
247
249
|
end
|
248
250
|
raise SendmailCommandFailed, "Couldn't execute #{cmd}" unless $? == 0
|
251
|
+
m.add_label :forwarded
|
252
|
+
Index.save_message m
|
249
253
|
rescue SystemCallError, SendmailCommandFailed => e
|
250
254
|
warn "problem sending mail: #{e.message}"
|
251
255
|
BufferManager.flash "Problem sending mail: #{e.message}"
|
@@ -359,8 +363,14 @@ EOS
|
|
359
363
|
when Chunk::Attachment
|
360
364
|
default_dir = $config[:default_attachment_save_dir]
|
361
365
|
default_dir = ENV["HOME"] if default_dir.nil? || default_dir.empty?
|
362
|
-
default_fn = File.expand_path File.join(default_dir, chunk.filename)
|
363
|
-
fn = BufferManager.ask_for_filename :filename, "Save attachment to file: ", default_fn
|
366
|
+
default_fn = File.expand_path File.join(default_dir, Shellwords.escape(chunk.filename))
|
367
|
+
fn = BufferManager.ask_for_filename :filename, "Save attachment to file or directory: ", default_fn, true
|
368
|
+
|
369
|
+
# if user selects directory use file name from message
|
370
|
+
if fn and File.directory? fn
|
371
|
+
fn = File.join(fn, Shellwords.escape(chunk.filename))
|
372
|
+
end
|
373
|
+
|
364
374
|
save_to_file(fn) { |f| f.print chunk.raw_content } if fn
|
365
375
|
else
|
366
376
|
m = @message_lines[curpos]
|
@@ -382,7 +392,7 @@ EOS
|
|
382
392
|
num_errors = 0
|
383
393
|
m.chunks.each do |chunk|
|
384
394
|
next unless chunk.is_a?(Chunk::Attachment)
|
385
|
-
fn = File.join(folder, chunk.filename)
|
395
|
+
fn = File.join(folder, Shellwords.escape(chunk.filename))
|
386
396
|
num_errors += 1 unless save_to_file(fn, false) { |f| f.print chunk.raw_content }
|
387
397
|
num += 1
|
388
398
|
end
|
@@ -780,13 +790,13 @@ private
|
|
780
790
|
@person_lines[start] = m.from
|
781
791
|
[[prefix_widget, open_widget, new_widget, attach_widget, starred_widget,
|
782
792
|
[color,
|
783
|
-
"#{m.from ? m.from.mediumname : '?'} to #{m.recipients.map { |l| l.shortname }.join(', ')} #{m.date.to_nice_s} (#{m.date.to_nice_distance_s})"]]]
|
793
|
+
"#{m.from ? m.from.mediumname.fix_encoding! : '?'} to #{m.recipients.map { |l| l.shortname.fix_encoding! }.join(', ')} #{m.date.to_nice_s.fix_encoding!} (#{m.date.to_nice_distance_s.fix_encoding!})"]]]
|
784
794
|
|
785
795
|
when :closed
|
786
796
|
@person_lines[start] = m.from
|
787
797
|
[[prefix_widget, open_widget, new_widget, attach_widget, starred_widget,
|
788
798
|
[color,
|
789
|
-
"#{m.from ? m.from.mediumname : '?'}, #{m.date.to_nice_s} (#{m.date.to_nice_distance_s}) #{m.snippet}"]]]
|
799
|
+
"#{m.from ? m.from.mediumname.fix_encoding! : '?'}, #{m.date.to_nice_s.fix_encoding!} (#{m.date.to_nice_distance_s.fix_encoding!}) #{m.snippet ? m.snippet.fix_encoding! : ''}"]]]
|
790
800
|
|
791
801
|
when :detailed
|
792
802
|
@person_lines[start] = m.from
|
data/lib/sup/poll.rb
CHANGED
@@ -25,6 +25,9 @@ Variables:
|
|
25
25
|
num_total: the total number of messages
|
26
26
|
num_inbox_total: the total number of new messages in the inbox.
|
27
27
|
num_inbox_total_unread: the total number of unread messages in the inbox
|
28
|
+
num_updated: the total number of updated messages
|
29
|
+
num_deleted: the total number of deleted messages
|
30
|
+
labels: the labels that were applied
|
28
31
|
from_and_subj: an array of (from email address, subject) pairs
|
29
32
|
from_and_subj_inbox: an array of (from email address, subject) pairs for
|
30
33
|
only those messages appearing in the inbox
|
@@ -52,23 +55,32 @@ EOS
|
|
52
55
|
BufferManager.flash "Polling for new messages..."
|
53
56
|
end
|
54
57
|
|
55
|
-
num, numi, from_and_subj, from_and_subj_inbox, loaded_labels = @mode.poll
|
58
|
+
num, numi, numu, numd, from_and_subj, from_and_subj_inbox, loaded_labels = @mode.poll
|
56
59
|
clear_running_totals if @should_clear_running_totals
|
57
60
|
@running_totals[:num] += num
|
58
61
|
@running_totals[:numi] += numi
|
62
|
+
@running_totals[:numu] += numu
|
63
|
+
@running_totals[:numd] += numd
|
59
64
|
@running_totals[:loaded_labels] += loaded_labels || []
|
60
65
|
|
61
66
|
|
62
67
|
if HookManager.enabled? "after-poll"
|
63
68
|
hook_args = { :num => num, :num_inbox => numi,
|
64
69
|
:num_total => @running_totals[:num], :num_inbox_total => @running_totals[:numi],
|
70
|
+
:num_updated => @running_totals[:numu],
|
71
|
+
:num_deleted => @running_totals[:numd],
|
72
|
+
:labels => @running_totals[:loaded_labels],
|
65
73
|
:from_and_subj => from_and_subj, :from_and_subj_inbox => from_and_subj_inbox,
|
66
74
|
:num_inbox_total_unread => lambda { Index.num_results_for :labels => [:inbox, :unread] } }
|
67
75
|
|
68
76
|
HookManager.run("after-poll", hook_args)
|
69
77
|
else
|
70
78
|
if @running_totals[:num] > 0
|
71
|
-
|
79
|
+
flash_msg = "Loaded #{@running_totals[:num].pluralize 'new message'}, #{@running_totals[:numi]} to inbox. " if @running_totals[:num] > 0
|
80
|
+
flash_msg += "Updated #{@running_totals[:numu].pluralize 'message'}. " if @running_totals[:numu] > 0
|
81
|
+
flash_msg += "Deleted #{@running_totals[:numd].pluralize 'message'}. " if @running_totals[:numd] > 0
|
82
|
+
flash_msg += "Labels: #{@running_totals[:loaded_labels].map{|l| l.to_s}.join(', ')}." if @running_totals[:loaded_labels].size > 0
|
83
|
+
BufferManager.flash flash_msg
|
72
84
|
else
|
73
85
|
BufferManager.flash "No new messages."
|
74
86
|
end
|
@@ -115,7 +127,7 @@ EOS
|
|
115
127
|
end
|
116
128
|
|
117
129
|
def do_poll
|
118
|
-
total_num = total_numi = 0
|
130
|
+
total_num = total_numi = total_numu = total_numd = 0
|
119
131
|
from_and_subj = []
|
120
132
|
from_and_subj_inbox = []
|
121
133
|
loaded_labels = Set.new
|
@@ -129,16 +141,23 @@ EOS
|
|
129
141
|
next
|
130
142
|
end
|
131
143
|
|
132
|
-
|
133
|
-
numi = 0
|
144
|
+
msg = ""
|
145
|
+
num = numi = numu = numd = 0
|
134
146
|
poll_from source do |action,m,old_m,progress|
|
135
147
|
if action == :delete
|
136
148
|
yield "Deleting #{m.id}"
|
149
|
+
loaded_labels.merge m.labels
|
150
|
+
numd += 1
|
151
|
+
elsif action == :update
|
152
|
+
yield "Message at #{m.source_info} is an update of an old message. Updating labels from #{old_m.labels.to_a * ','} => #{m.labels.to_a * ','}"
|
153
|
+
loaded_labels.merge m.labels
|
154
|
+
numu += 1
|
137
155
|
elsif action == :add
|
138
156
|
if old_m
|
139
157
|
new_locations = (m.locations - old_m.locations)
|
140
158
|
if not new_locations.empty?
|
141
|
-
yield "Message at #{new_locations[0].info}
|
159
|
+
yield "Message at #{new_locations[0].info} has changed its source location. Updating labels from #{old_m.labels.to_a * ','} => #{m.labels.to_a * ','}"
|
160
|
+
numu += 1
|
142
161
|
else
|
143
162
|
yield "Skipping already-imported message at #{m.locations[-1].info}"
|
144
163
|
end
|
@@ -155,25 +174,29 @@ EOS
|
|
155
174
|
else fail
|
156
175
|
end
|
157
176
|
end
|
158
|
-
|
177
|
+
msg += "Found #{num} messages, #{numi} to inbox. " unless num == 0
|
178
|
+
msg += "Updated #{numu} messages. " unless numu == 0
|
179
|
+
msg += "Deleted #{numd} messages." unless numd == 0
|
180
|
+
yield msg unless msg == ""
|
159
181
|
total_num += num
|
160
182
|
total_numi += numi
|
183
|
+
total_numu += numu
|
184
|
+
total_numd += numd
|
161
185
|
end
|
162
186
|
|
163
187
|
loaded_labels = loaded_labels - LabelManager::HIDDEN_RESERVED_LABELS - [:inbox, :killed]
|
164
188
|
yield "Done polling; loaded #{total_num} new messages total"
|
165
189
|
@last_poll = Time.now
|
166
190
|
end
|
167
|
-
[total_num, total_numi, from_and_subj, from_and_subj_inbox, loaded_labels]
|
191
|
+
[total_num, total_numi, total_numu, total_numd, from_and_subj, from_and_subj_inbox, loaded_labels]
|
168
192
|
end
|
169
193
|
|
170
194
|
## like Source#poll, but yields successive Message objects, which have their
|
171
195
|
## labels and locations set correctly. The Messages are saved to or removed
|
172
196
|
## from the index after being yielded.
|
173
197
|
def poll_from source, opts={}
|
174
|
-
debug "trying to acquire poll lock for: #{source}
|
175
|
-
if source.
|
176
|
-
debug "lock acquired for: #{source}."
|
198
|
+
debug "trying to acquire poll lock for: #{source}..."
|
199
|
+
if source.try_lock
|
177
200
|
begin
|
178
201
|
source.poll do |sym, args|
|
179
202
|
case sym
|
@@ -191,18 +214,40 @@ EOS
|
|
191
214
|
yield :add, m, old_m, args[:progress] if block_given?
|
192
215
|
Index.sync_message m, true
|
193
216
|
|
217
|
+
if Index.message_joining_killed? m
|
218
|
+
m.labels += [:killed]
|
219
|
+
Index.sync_message m, true
|
220
|
+
end
|
221
|
+
|
194
222
|
## We need to add or unhide the message when it either did not exist
|
195
223
|
## before at all or when it was updated. We do *not* add/unhide when
|
196
224
|
## the same message was found at a different location
|
197
|
-
if
|
225
|
+
if old_m
|
226
|
+
UpdateManager.relay self, :updated, m
|
227
|
+
elsif !old_m or not old_m.locations.member? m.location
|
198
228
|
UpdateManager.relay self, :added, m
|
199
229
|
end
|
200
230
|
when :delete
|
201
|
-
Index.each_message
|
231
|
+
Index.each_message({:location => [source.id, args[:info]]}, false) do |m|
|
202
232
|
m.locations.delete Location.new(source, args[:info])
|
203
|
-
yield :delete, m, [source,args[:info]], args[:progress] if block_given?
|
204
233
|
Index.sync_message m, false
|
205
|
-
|
234
|
+
if m.locations.size == 0
|
235
|
+
yield :delete, m, [source,args[:info]], args[:progress] if block_given?
|
236
|
+
Index.delete m.id
|
237
|
+
UpdateManager.relay self, :location_deleted, m
|
238
|
+
end
|
239
|
+
end
|
240
|
+
when :update
|
241
|
+
Index.each_message({:location => [source.id, args[:old_info]]}, false) do |m|
|
242
|
+
old_m = Index.build_message m.id
|
243
|
+
m.locations.delete Location.new(source, args[:old_info])
|
244
|
+
m.locations.push Location.new(source, args[:new_info])
|
245
|
+
## Update labels that might have been modified remotely
|
246
|
+
m.labels -= source.supported_labels?
|
247
|
+
m.labels += args[:labels]
|
248
|
+
yield :update, m, old_m if block_given?
|
249
|
+
Index.sync_message m, true
|
250
|
+
UpdateManager.relay self, :updated, m
|
206
251
|
end
|
207
252
|
end
|
208
253
|
end
|
@@ -212,7 +257,7 @@ EOS
|
|
212
257
|
|
213
258
|
ensure
|
214
259
|
source.go_idle
|
215
|
-
source.
|
260
|
+
source.unlock
|
216
261
|
end
|
217
262
|
else
|
218
263
|
debug "source #{source} is already being polled."
|
@@ -221,7 +266,7 @@ EOS
|
|
221
266
|
|
222
267
|
def handle_idle_update sender, idle_since; @should_clear_running_totals = false; end
|
223
268
|
def handle_unidle_update sender, idle_since; @should_clear_running_totals = true; clear_running_totals; end
|
224
|
-
def clear_running_totals; @running_totals = {:num => 0, :numi => 0, :loaded_labels => Set.new}; end
|
269
|
+
def clear_running_totals; @running_totals = {:num => 0, :numi => 0, :numu => 0, :numd => 0, :loaded_labels => Set.new}; end
|
225
270
|
end
|
226
271
|
|
227
272
|
end
|
data/lib/sup/search.rb
CHANGED
@@ -7,6 +7,8 @@ class SearchManager
|
|
7
7
|
|
8
8
|
class ExpansionError < StandardError; end
|
9
9
|
|
10
|
+
attr_reader :predefined_searches
|
11
|
+
|
10
12
|
def initialize fn
|
11
13
|
@fn = fn
|
12
14
|
@searches = {}
|
@@ -43,24 +45,40 @@ class SearchManager
|
|
43
45
|
|
44
46
|
def add name, search_string
|
45
47
|
return unless valid_name? name
|
48
|
+
if @predefined_searches.has_key? name
|
49
|
+
warn "cannot add search: #{name} is already taken by a predefined search"
|
50
|
+
return
|
51
|
+
end
|
46
52
|
@searches[name] = search_string
|
47
53
|
@modified = true
|
48
54
|
end
|
49
55
|
|
50
56
|
def rename old, new
|
51
57
|
return unless @searches.has_key? old
|
58
|
+
if [old, new].any? { |x| @predefined_searches.has_key? x }
|
59
|
+
warn "cannot rename search: #{old} or #{new} is already taken by a predefined search"
|
60
|
+
return
|
61
|
+
end
|
52
62
|
search_string = @searches[old]
|
53
63
|
delete old if add new, search_string
|
54
64
|
end
|
55
65
|
|
56
66
|
def edit name, search_string
|
57
67
|
return unless @searches.has_key? name
|
68
|
+
if @predefined_searches.has_key? name
|
69
|
+
warn "cannot edit predefined search: #{name}."
|
70
|
+
return
|
71
|
+
end
|
58
72
|
@searches[name] = search_string
|
59
73
|
@modified = true
|
60
74
|
end
|
61
75
|
|
62
76
|
def delete name
|
63
77
|
return unless @searches.has_key? name
|
78
|
+
if @predefined_searches.has_key? name
|
79
|
+
warn "cannot delete predefined search: #{name}."
|
80
|
+
return
|
81
|
+
end
|
64
82
|
@searches.delete name
|
65
83
|
@modified = true
|
66
84
|
end
|