sup 0.8.1 → 0.9
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.
- data/CONTRIBUTORS +13 -6
- data/History.txt +19 -0
- data/ReleaseNotes +35 -0
- data/bin/sup +82 -77
- data/bin/sup-add +7 -7
- data/bin/sup-config +104 -85
- data/bin/sup-dump +4 -5
- data/bin/sup-recover-sources +9 -10
- data/bin/sup-sync +121 -100
- data/bin/sup-sync-back +18 -15
- data/bin/sup-tweak-labels +24 -21
- data/lib/sup.rb +53 -33
- data/lib/sup/account.rb +0 -2
- data/lib/sup/buffer.rb +47 -22
- data/lib/sup/colormap.rb +6 -6
- data/lib/sup/contact.rb +0 -2
- data/lib/sup/crypto.rb +34 -23
- data/lib/sup/draft.rb +6 -14
- data/lib/sup/ferret_index.rb +471 -0
- data/lib/sup/hook.rb +30 -43
- data/lib/sup/hook.rb.BACKUP.8625.rb +158 -0
- data/lib/sup/hook.rb.BACKUP.8681.rb +158 -0
- data/lib/sup/hook.rb.BASE.8625.rb +155 -0
- data/lib/sup/hook.rb.BASE.8681.rb +155 -0
- data/lib/sup/hook.rb.LOCAL.8625.rb +142 -0
- data/lib/sup/hook.rb.LOCAL.8681.rb +142 -0
- data/lib/sup/hook.rb.REMOTE.8625.rb +145 -0
- data/lib/sup/hook.rb.REMOTE.8681.rb +145 -0
- data/lib/sup/imap.rb +18 -8
- data/lib/sup/index.rb +70 -528
- data/lib/sup/interactive-lock.rb +74 -0
- data/lib/sup/keymap.rb +26 -26
- data/lib/sup/label.rb +2 -4
- data/lib/sup/logger.rb +54 -35
- data/lib/sup/maildir.rb +41 -6
- data/lib/sup/mbox.rb +1 -1
- data/lib/sup/mbox/loader.rb +18 -6
- data/lib/sup/mbox/ssh-file.rb +1 -7
- data/lib/sup/message-chunks.rb +36 -23
- data/lib/sup/message.rb +126 -46
- data/lib/sup/mode.rb +3 -2
- data/lib/sup/modes/console-mode.rb +108 -0
- data/lib/sup/modes/edit-message-mode.rb +15 -5
- data/lib/sup/modes/inbox-mode.rb +2 -4
- data/lib/sup/modes/label-list-mode.rb +1 -1
- data/lib/sup/modes/line-cursor-mode.rb +18 -18
- data/lib/sup/modes/log-mode.rb +29 -16
- data/lib/sup/modes/poll-mode.rb +7 -9
- data/lib/sup/modes/reply-mode.rb +5 -3
- data/lib/sup/modes/scroll-mode.rb +2 -2
- data/lib/sup/modes/search-results-mode.rb +9 -11
- data/lib/sup/modes/text-mode.rb +2 -2
- data/lib/sup/modes/thread-index-mode.rb +26 -16
- data/lib/sup/modes/thread-view-mode.rb +84 -39
- data/lib/sup/person.rb +6 -8
- data/lib/sup/poll.rb +46 -47
- data/lib/sup/rfc2047.rb +1 -5
- data/lib/sup/sent.rb +27 -20
- data/lib/sup/source.rb +90 -13
- data/lib/sup/textfield.rb +4 -4
- data/lib/sup/thread.rb +15 -13
- data/lib/sup/undo.rb +0 -1
- data/lib/sup/update.rb +0 -1
- data/lib/sup/util.rb +51 -43
- data/lib/sup/xapian_index.rb +566 -0
- metadata +57 -46
- data/lib/sup/suicide.rb +0 -36
@@ -0,0 +1,155 @@
|
|
1
|
+
module Redwood
|
2
|
+
|
3
|
+
class HookManager
|
4
|
+
## there's probably a better way to do this, but to evaluate a hook
|
5
|
+
## with a bunch of pre-set "local variables" i define a function
|
6
|
+
## per variable and then instance_evaluate the code.
|
7
|
+
##
|
8
|
+
## how does rails do it, when you pass :locals into a partial?
|
9
|
+
##
|
10
|
+
## i don't bother providing setters, since i'm pretty sure the
|
11
|
+
## charade will fall apart pretty quickly with respect to scoping.
|
12
|
+
## "fail-fast", we'll call it.
|
13
|
+
class HookContext
|
14
|
+
def initialize name
|
15
|
+
@__say_id = nil
|
16
|
+
@__name = name
|
17
|
+
@__locals = {}
|
18
|
+
end
|
19
|
+
|
20
|
+
attr_writer :__locals
|
21
|
+
|
22
|
+
def method_missing m, *a
|
23
|
+
case @__locals[m]
|
24
|
+
when Proc
|
25
|
+
@__locals[m] = @__locals[m].call(*a) # only call the proc once
|
26
|
+
when nil
|
27
|
+
super
|
28
|
+
else
|
29
|
+
@__locals[m]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def say s
|
34
|
+
if BufferManager.instantiated?
|
35
|
+
@__say_id = BufferManager.say s, @__say_id
|
36
|
+
BufferManager.draw_screen
|
37
|
+
else
|
38
|
+
log s
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def log s
|
43
|
+
Redwood::log "hook[#@__name]: #{s}"
|
44
|
+
end
|
45
|
+
|
46
|
+
def ask_yes_or_no q
|
47
|
+
if BufferManager.instantiated?
|
48
|
+
BufferManager.ask_yes_or_no q
|
49
|
+
else
|
50
|
+
print q
|
51
|
+
gets.chomp.downcase == 'y'
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def get tag
|
56
|
+
HookManager.tags[tag]
|
57
|
+
end
|
58
|
+
|
59
|
+
def set tag, value
|
60
|
+
HookManager.tags[tag] = value
|
61
|
+
end
|
62
|
+
|
63
|
+
def __binding
|
64
|
+
binding
|
65
|
+
end
|
66
|
+
|
67
|
+
def __cleanup
|
68
|
+
BufferManager.clear @__say_id if @__say_id
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
include Singleton
|
73
|
+
|
74
|
+
def initialize dir
|
75
|
+
@dir = dir
|
76
|
+
@hooks = {}
|
77
|
+
@descs = {}
|
78
|
+
@contexts = {}
|
79
|
+
@tags = {}
|
80
|
+
|
81
|
+
Dir.mkdir dir unless File.exists? dir
|
82
|
+
|
83
|
+
self.class.i_am_the_instance self
|
84
|
+
end
|
85
|
+
|
86
|
+
attr_reader :tags
|
87
|
+
|
88
|
+
def run name, locals={}
|
89
|
+
hook = hook_for(name) or return
|
90
|
+
context = @contexts[hook] ||= HookContext.new(name)
|
91
|
+
context.__locals = locals
|
92
|
+
|
93
|
+
result = nil
|
94
|
+
begin
|
95
|
+
result = context.instance_eval @hooks[name], fn_for(name)
|
96
|
+
rescue Exception => e
|
97
|
+
log "error running hook: #{e.message}"
|
98
|
+
log e.backtrace.join("\n")
|
99
|
+
@hooks[name] = nil # disable it
|
100
|
+
BufferManager.flash "Error running hook: #{e.message}" if BufferManager.instantiated?
|
101
|
+
end
|
102
|
+
context.__cleanup
|
103
|
+
result
|
104
|
+
end
|
105
|
+
|
106
|
+
def register name, desc
|
107
|
+
@descs[name] = desc
|
108
|
+
end
|
109
|
+
|
110
|
+
def print_hooks f=$stdout
|
111
|
+
puts <<EOS
|
112
|
+
Have #{@descs.size} registered hooks:
|
113
|
+
|
114
|
+
EOS
|
115
|
+
|
116
|
+
@descs.sort.each do |name, desc|
|
117
|
+
f.puts <<EOS
|
118
|
+
#{name}
|
119
|
+
#{"-" * name.length}
|
120
|
+
File: #{fn_for name}
|
121
|
+
#{desc}
|
122
|
+
EOS
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def enabled? name; !hook_for(name).nil? end
|
127
|
+
|
128
|
+
private
|
129
|
+
|
130
|
+
def hook_for name
|
131
|
+
unless @hooks.member? name
|
132
|
+
@hooks[name] =
|
133
|
+
begin
|
134
|
+
returning IO.read(fn_for(name)) do
|
135
|
+
log "read '#{name}' from #{fn_for(name)}"
|
136
|
+
end
|
137
|
+
rescue SystemCallError => e
|
138
|
+
#log "disabled hook for '#{name}': #{e.message}"
|
139
|
+
nil
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
@hooks[name]
|
144
|
+
end
|
145
|
+
|
146
|
+
def fn_for name
|
147
|
+
File.join @dir, "#{name}.rb"
|
148
|
+
end
|
149
|
+
|
150
|
+
def log m
|
151
|
+
Redwood::log("hook: " + m)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
@@ -0,0 +1,155 @@
|
|
1
|
+
module Redwood
|
2
|
+
|
3
|
+
class HookManager
|
4
|
+
## there's probably a better way to do this, but to evaluate a hook
|
5
|
+
## with a bunch of pre-set "local variables" i define a function
|
6
|
+
## per variable and then instance_evaluate the code.
|
7
|
+
##
|
8
|
+
## how does rails do it, when you pass :locals into a partial?
|
9
|
+
##
|
10
|
+
## i don't bother providing setters, since i'm pretty sure the
|
11
|
+
## charade will fall apart pretty quickly with respect to scoping.
|
12
|
+
## "fail-fast", we'll call it.
|
13
|
+
class HookContext
|
14
|
+
def initialize name
|
15
|
+
@__say_id = nil
|
16
|
+
@__name = name
|
17
|
+
@__locals = {}
|
18
|
+
end
|
19
|
+
|
20
|
+
attr_writer :__locals
|
21
|
+
|
22
|
+
def method_missing m, *a
|
23
|
+
case @__locals[m]
|
24
|
+
when Proc
|
25
|
+
@__locals[m] = @__locals[m].call(*a) # only call the proc once
|
26
|
+
when nil
|
27
|
+
super
|
28
|
+
else
|
29
|
+
@__locals[m]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def say s
|
34
|
+
if BufferManager.instantiated?
|
35
|
+
@__say_id = BufferManager.say s, @__say_id
|
36
|
+
BufferManager.draw_screen
|
37
|
+
else
|
38
|
+
log s
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def log s
|
43
|
+
Redwood::log "hook[#@__name]: #{s}"
|
44
|
+
end
|
45
|
+
|
46
|
+
def ask_yes_or_no q
|
47
|
+
if BufferManager.instantiated?
|
48
|
+
BufferManager.ask_yes_or_no q
|
49
|
+
else
|
50
|
+
print q
|
51
|
+
gets.chomp.downcase == 'y'
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def get tag
|
56
|
+
HookManager.tags[tag]
|
57
|
+
end
|
58
|
+
|
59
|
+
def set tag, value
|
60
|
+
HookManager.tags[tag] = value
|
61
|
+
end
|
62
|
+
|
63
|
+
def __binding
|
64
|
+
binding
|
65
|
+
end
|
66
|
+
|
67
|
+
def __cleanup
|
68
|
+
BufferManager.clear @__say_id if @__say_id
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
include Singleton
|
73
|
+
|
74
|
+
def initialize dir
|
75
|
+
@dir = dir
|
76
|
+
@hooks = {}
|
77
|
+
@descs = {}
|
78
|
+
@contexts = {}
|
79
|
+
@tags = {}
|
80
|
+
|
81
|
+
Dir.mkdir dir unless File.exists? dir
|
82
|
+
|
83
|
+
self.class.i_am_the_instance self
|
84
|
+
end
|
85
|
+
|
86
|
+
attr_reader :tags
|
87
|
+
|
88
|
+
def run name, locals={}
|
89
|
+
hook = hook_for(name) or return
|
90
|
+
context = @contexts[hook] ||= HookContext.new(name)
|
91
|
+
context.__locals = locals
|
92
|
+
|
93
|
+
result = nil
|
94
|
+
begin
|
95
|
+
result = context.instance_eval @hooks[name], fn_for(name)
|
96
|
+
rescue Exception => e
|
97
|
+
log "error running hook: #{e.message}"
|
98
|
+
log e.backtrace.join("\n")
|
99
|
+
@hooks[name] = nil # disable it
|
100
|
+
BufferManager.flash "Error running hook: #{e.message}" if BufferManager.instantiated?
|
101
|
+
end
|
102
|
+
context.__cleanup
|
103
|
+
result
|
104
|
+
end
|
105
|
+
|
106
|
+
def register name, desc
|
107
|
+
@descs[name] = desc
|
108
|
+
end
|
109
|
+
|
110
|
+
def print_hooks f=$stdout
|
111
|
+
puts <<EOS
|
112
|
+
Have #{@descs.size} registered hooks:
|
113
|
+
|
114
|
+
EOS
|
115
|
+
|
116
|
+
@descs.sort.each do |name, desc|
|
117
|
+
f.puts <<EOS
|
118
|
+
#{name}
|
119
|
+
#{"-" * name.length}
|
120
|
+
File: #{fn_for name}
|
121
|
+
#{desc}
|
122
|
+
EOS
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def enabled? name; !hook_for(name).nil? end
|
127
|
+
|
128
|
+
private
|
129
|
+
|
130
|
+
def hook_for name
|
131
|
+
unless @hooks.member? name
|
132
|
+
@hooks[name] =
|
133
|
+
begin
|
134
|
+
returning IO.read(fn_for(name)) do
|
135
|
+
log "read '#{name}' from #{fn_for(name)}"
|
136
|
+
end
|
137
|
+
rescue SystemCallError => e
|
138
|
+
#log "disabled hook for '#{name}': #{e.message}"
|
139
|
+
nil
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
@hooks[name]
|
144
|
+
end
|
145
|
+
|
146
|
+
def fn_for name
|
147
|
+
File.join @dir, "#{name}.rb"
|
148
|
+
end
|
149
|
+
|
150
|
+
def log m
|
151
|
+
Redwood::log("hook: " + m)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
module Redwood
|
2
|
+
|
3
|
+
class HookManager
|
4
|
+
class HookContext
|
5
|
+
def initialize name
|
6
|
+
@__say_id = nil
|
7
|
+
@__name = name
|
8
|
+
@__cache = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def say s
|
12
|
+
if BufferManager.instantiated?
|
13
|
+
@__say_id = BufferManager.say s, @__say_id
|
14
|
+
BufferManager.draw_screen
|
15
|
+
else
|
16
|
+
log s
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def log s
|
21
|
+
info "hook[#@__name]: #{s}"
|
22
|
+
end
|
23
|
+
|
24
|
+
def ask_yes_or_no q
|
25
|
+
if BufferManager.instantiated?
|
26
|
+
BufferManager.ask_yes_or_no q
|
27
|
+
else
|
28
|
+
print q
|
29
|
+
gets.chomp.downcase == 'y'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def get tag
|
34
|
+
HookManager.tags[tag]
|
35
|
+
end
|
36
|
+
|
37
|
+
def set tag, value
|
38
|
+
HookManager.tags[tag] = value
|
39
|
+
end
|
40
|
+
|
41
|
+
def __run __hook, __filename, __locals
|
42
|
+
__binding = binding
|
43
|
+
__lprocs, __lvars = __locals.partition { |k, v| v.is_a?(Proc) }
|
44
|
+
eval __lvars.map { |k, v| "#{k} = __locals[#{k.inspect}];" }.join, __binding
|
45
|
+
## we also support closures for delays evaluation. unfortunately
|
46
|
+
## we have to do this via method calls, so you don't get all the
|
47
|
+
## semantics of a regular variable. not ideal.
|
48
|
+
__lprocs.each do |k, v|
|
49
|
+
self.class.instance_eval do
|
50
|
+
define_method k do
|
51
|
+
@__cache[k] ||= v.call
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
ret = eval __hook, __binding, __filename
|
56
|
+
BufferManager.clear @__say_id if @__say_id
|
57
|
+
@__cache = {}
|
58
|
+
ret
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
include Singleton
|
63
|
+
|
64
|
+
def initialize dir
|
65
|
+
@dir = dir
|
66
|
+
@hooks = {}
|
67
|
+
@descs = {}
|
68
|
+
@contexts = {}
|
69
|
+
@tags = {}
|
70
|
+
|
71
|
+
Dir.mkdir dir unless File.exists? dir
|
72
|
+
end
|
73
|
+
|
74
|
+
attr_reader :tags
|
75
|
+
|
76
|
+
def run name, locals={}
|
77
|
+
hook = hook_for(name) or return
|
78
|
+
context = @contexts[hook] ||= HookContext.new(name)
|
79
|
+
|
80
|
+
result = nil
|
81
|
+
begin
|
82
|
+
result = context.__run hook, fn_for(name), locals
|
83
|
+
rescue Exception => e
|
84
|
+
log "error running hook: #{e.message}"
|
85
|
+
log e.backtrace.join("\n")
|
86
|
+
@hooks[name] = nil # disable it
|
87
|
+
BufferManager.flash "Error running hook: #{e.message}" if BufferManager.instantiated?
|
88
|
+
end
|
89
|
+
result
|
90
|
+
end
|
91
|
+
|
92
|
+
def register name, desc
|
93
|
+
@descs[name] = desc
|
94
|
+
end
|
95
|
+
|
96
|
+
def print_hooks f=$stdout
|
97
|
+
puts <<EOS
|
98
|
+
Have #{@descs.size} registered hooks:
|
99
|
+
|
100
|
+
EOS
|
101
|
+
|
102
|
+
@descs.sort.each do |name, desc|
|
103
|
+
f.puts <<EOS
|
104
|
+
#{name}
|
105
|
+
#{"-" * name.length}
|
106
|
+
File: #{fn_for name}
|
107
|
+
#{desc}
|
108
|
+
EOS
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def enabled? name; !hook_for(name).nil? end
|
113
|
+
|
114
|
+
def clear; @hooks.clear; end
|
115
|
+
|
116
|
+
private
|
117
|
+
|
118
|
+
def hook_for name
|
119
|
+
unless @hooks.member? name
|
120
|
+
@hooks[name] = begin
|
121
|
+
returning IO.read(fn_for(name)) do
|
122
|
+
debug "read '#{name}' from #{fn_for(name)}"
|
123
|
+
end
|
124
|
+
rescue SystemCallError => e
|
125
|
+
#debug "disabled hook for '#{name}': #{e.message}"
|
126
|
+
nil
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
@hooks[name]
|
131
|
+
end
|
132
|
+
|
133
|
+
def fn_for name
|
134
|
+
File.join @dir, "#{name}.rb"
|
135
|
+
end
|
136
|
+
|
137
|
+
def log m
|
138
|
+
info("hook: " + m)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|