]> git.cworth.org Git - sup/blob - lib/sup/mode.rb
209ca45e44bb36333159627335bd64dd7f8b50ea
[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 unsaved?; false end
28   def draw; end
29   def focus; end
30   def blur; end
31   def cancel_search!; end
32   def in_search?; false end
33   def status; ""; end
34   def resize rows, cols; end
35   def cleanup
36     @buffer = nil
37   end
38
39   def resolve_input c
40     ancestors.each do |klass| # try all keymaps in order of ancestry
41       next unless @@keymaps.member?(klass)
42       action = BufferManager.resolve_input_with_keymap c, @@keymaps[klass]
43       return action if action
44     end
45     nil
46   end
47
48   def handle_input c
49     action = resolve_input(c) or return false
50     send action
51     true
52   end
53
54   def help_text
55     used_keys = {}
56     ancestors.map do |klass|
57       km = @@keymaps[klass] or next
58       title = "Keybindings from #{Mode.make_name klass.name}"
59       s = <<EOS
60 #{title}
61 #{'-' * title.display_length}
62
63 #{km.help_text used_keys}
64 EOS
65       begin
66         used_keys.merge! km.keysyms.to_boolean_h
67       rescue ArgumentError
68         raise km.keysyms.inspect
69       end
70       s
71     end.compact.join "\n"
72   end
73
74 ### helper functions
75
76   def save_to_file fn
77     if File.exists? fn
78       return unless BufferManager.ask_yes_or_no "File exists. Overwrite?"
79     end
80     begin
81       File.open(fn, "w") { |f| yield f }
82       BufferManager.flash "Successfully wrote #{fn}."
83     rescue SystemCallError, IOError => e
84       BufferManager.flash "Error writing to file: #{e.message}"
85     end
86   end
87
88   def pipe_to_process command
89     Open3.popen3(command) do |input, output, error|
90       err, data, * = IO.select [error], [input], nil
91
92       unless err.empty?
93         message = err.first.read
94         if message =~ /^\s*$/
95           warn "error running #{command} (but no error message)"
96           BufferManager.flash "Error running #{command}!"
97         else
98           warn "error running #{command}: #{message}"
99           BufferManager.flash "Error: #{message}"
100         end
101         return
102       end
103
104       data = data.first
105       data.sync = false # buffer input
106
107       yield data
108       data.close # output will block unless input is closed
109
110       ## BUG?: shows errors or output but not both....
111       data, * = IO.select [output, error], nil, nil
112       data = data.first
113
114       if data.eof
115         BufferManager.flash "'#{command}' done!"
116         nil
117       else
118         data.read
119       end
120     end
121   end
122 end
123
124 end