]> git.cworth.org Git - sup/blob - lib/sup/mode.rb
add multi-key sequence support
[sup] / lib / sup / mode.rb
1 module Redwood
2
3 class Mode
4   attr_accessor :buffer
5   @@keymaps = {}
6
7   def self.register_keymap keymap=nil, &b
8     keymap = Keymap.new(&b) if keymap.nil?
9     @@keymaps[self] = keymap
10   end
11
12   def initialize
13     @buffer = nil
14   end
15
16   def self.make_name s; s.gsub(/.*::/, "").camel_to_hyphy; end
17   def name; Mode.make_name self.class.name; end
18
19   def self.load_all_modes dir
20     Dir[File.join(dir, "*.rb")].each do |f|
21       $stderr.puts "## loading mode #{f}"
22       require f
23     end
24   end
25
26   def killable?; true; end
27   def draw; end
28   def focus; end
29   def blur; end
30   def cancel_search!; end
31   def in_search?; false end
32   def status; ""; end
33   def resize rows, cols; end
34   def cleanup
35     @buffer = nil
36   end
37
38   def resolve_input c
39     ancestors.each do |klass| # try all keymaps in order of ancestry
40       next unless @@keymaps.member?(klass)
41       action = BufferManager.resolve_input_with_keymap c, @@keymaps[klass]
42       return action if action
43     end
44     nil
45   end
46
47   def handle_input c
48     action = resolve_input(c) or return false
49     send action
50     true
51   end
52
53   def help_text
54     used_keys = {}
55     ancestors.map do |klass|
56       km = @@keymaps[klass] or next
57       title = "Keybindings from #{Mode.make_name klass.name}"
58       s = <<EOS
59 #{title}
60 #{'-' * title.length}
61
62 #{km.help_text used_keys}
63 EOS
64       begin
65         used_keys.merge! km.keysyms.to_boolean_h
66       rescue ArgumentError
67         raise km.keysyms.inspect
68       end
69       s
70     end.compact.join "\n"
71   end
72
73 ### helper functions
74
75   def save_to_file fn
76     if File.exists? fn
77       return unless BufferManager.ask_yes_or_no "File exists. Overwrite?"
78     end
79     begin
80       File.open(fn, "w") { |f| yield f }
81       BufferManager.flash "Successfully wrote #{fn}."
82     rescue SystemCallError, IOError => e
83       BufferManager.flash "Error writing to file: #{e.message}"
84     end
85   end
86
87   def pipe_to_process command
88     Open3.popen3(command) do |input, output, error|
89       err, data, * = IO.select [error], [input], nil
90
91       unless err.empty?
92         message = err.first.read
93         if message =~ /^\s*$/
94           Redwood::log "error running #{command} (but no error message)"
95           BufferManager.flash "Error running #{command}!"
96         else
97           Redwood::log "error running #{command}: #{message}"
98           BufferManager.flash "Error: #{message}"
99         end
100         return
101       end
102
103       data = data.first
104       data.sync = false # buffer input
105
106       yield data
107       data.close # output will block unless input is closed
108
109       ## BUG?: shows errors or output but not both....
110       data, * = IO.select [output, error], nil, nil
111       data = data.first
112
113       if data.eof
114         BufferManager.flash "'#{command}' done!"
115         nil
116       else
117         data.read
118       end
119     end
120   end
121 end
122
123 end