]> git.notmuchmail.org Git - sup/blob - lib/sup/hook.rb
Merge branch 'hook-local-vars' into next
[sup] / lib / sup / hook.rb
1 module Redwood
2
3 class HookManager
4   class HookContext
5     def initialize name
6       @__say_id = nil
7       @__name = name
8     end
9
10     def say s
11       if BufferManager.instantiated?
12         @__say_id = BufferManager.say s, @__say_id
13         BufferManager.draw_screen
14       else
15         log s
16       end
17     end
18
19     def log s
20       info "hook[#@__name]: #{s}"
21     end
22
23     def ask_yes_or_no q
24       if BufferManager.instantiated?
25         BufferManager.ask_yes_or_no q
26       else
27         print q
28         gets.chomp.downcase == 'y'
29       end
30     end
31
32     def get tag
33       HookManager.tags[tag]
34     end
35
36     def set tag, value
37       HookManager.tags[tag] = value
38     end
39
40     def __run __hook, __filename, __locals
41       __binding = binding
42       eval __locals.map { |k, v| "#{k} = __locals[#{k.inspect}];" }.join, __binding
43       ret = eval __hook, __binding, __filename
44       BufferManager.clear @__say_id if @__say_id
45       ret
46     end
47   end
48
49   include Singleton
50
51   def initialize dir
52     @dir = dir
53     @hooks = {}
54     @descs = {}
55     @contexts = {}
56     @tags = {}
57
58     Dir.mkdir dir unless File.exists? dir
59   end
60
61   attr_reader :tags
62
63   def run name, locals={}
64     hook = hook_for(name) or return
65     context = @contexts[hook] ||= HookContext.new(name)
66
67     result = nil
68     begin
69       result = context.__run hook, fn_for(name), locals
70     rescue Exception => e
71       log "error running hook: #{e.message}"
72       log e.backtrace.join("\n")
73       @hooks[name] = nil # disable it
74       BufferManager.flash "Error running hook: #{e.message}" if BufferManager.instantiated?
75     end
76     result
77   end
78
79   def register name, desc
80     @descs[name] = desc
81   end
82
83   def print_hooks f=$stdout
84 puts <<EOS
85 Have #{@descs.size} registered hooks:
86
87 EOS
88
89     @descs.sort.each do |name, desc|
90       f.puts <<EOS
91 #{name}
92 #{"-" * name.length}
93 File: #{fn_for name}
94 #{desc}
95 EOS
96     end
97   end
98
99   def enabled? name; !hook_for(name).nil? end
100
101   def clear; @hooks.clear; end
102
103 private
104
105   def hook_for name
106     unless @hooks.member? name
107       @hooks[name] = begin
108         returning IO.read(fn_for(name)) do
109           log "read '#{name}' from #{fn_for(name)}"
110         end
111       rescue SystemCallError => e
112         #log "disabled hook for '#{name}': #{e.message}"
113         nil
114       end
115     end
116
117     @hooks[name]
118   end
119
120   def fn_for name
121     File.join @dir, "#{name}.rb"
122   end
123
124   def log m
125     info("hook: " + m)
126   end
127 end
128
129 end