sup

A curses threads-with-tags style email client

sup.git

git clone https://supmua.dev/git/sup/
commit 90d39a30e3a2062450e09b274c0a00a4c6293e87
parent 85623fbde9e42e8d404870ddb70fd90e5dadda7c
Author: Rich Lane <rlane@club.cc.cmu.edu>
Date:   Sun,  7 Mar 2010 13:17:54 -0800

Merge branch 'keybindings'

Diffstat:
M bin/sup | 9 ++++++++-
M lib/sup/hook.rb | 1 +
M lib/sup/keymap.rb | 44 +++++++++++++++++++++++++++++++++++++++++---
M lib/sup/mode.rb | 8 ++++++++
4 files changed, 58 insertions(+), 4 deletions(-)
diff --git a/bin/sup b/bin/sup
@@ -89,10 +89,13 @@ global_keymap = Keymap.new do |k|
   k.add :show_console, "Show the Console buffer", '~'
 
   ## Submap for less often used keybindings
-  k.add_multi "reload (c)olors", 'O' do |kk|
+  k.add_multi "reload (c)olors, rerun (k)eybindings hook", 'O' do |kk|
     kk.add :reload_colors, "Reload colors", 'c'
+    kk.add :run_keybindings_hook, "Rerun keybindings hook", 'k'
   end
 end
+  
+Redwood::Keymap.run_hook global_keymap
 
 ## the following magic enables wide characters when used with a ruby
 ## ncurses.so that's been compiled against libncursesw. (note the w.) why
@@ -355,6 +358,10 @@ EOS
       Colormap.populate_colormap
       bm.completely_redraw_screen
       bm.flash "reloaded colors"
+    when :run_keybindings_hook
+      HookManager.clear_one 'keybindings'
+      Keymap.run_hook global_keymap
+      bm.flash "keybindings hook run"
     when :nothing, InputSequenceAborted
     when :redraw
       bm.completely_redraw_screen
diff --git a/lib/sup/hook.rb b/lib/sup/hook.rb
@@ -113,6 +113,7 @@ EOS
   def enabled? name; !hook_for(name).nil? end
 
   def clear; @hooks.clear; end
+  def clear_one k; @hooks.delete k; end
 
 private
 
diff --git a/lib/sup/keymap.rb b/lib/sup/keymap.rb
@@ -1,6 +1,14 @@
 module Redwood
 
 class Keymap
+
+  HookManager.register "keybindings", <<EOS
+Add custom keybindings.
+Methods:
+  modes: Hash from mode names to mode classes.
+  global_keymap: The top-level keymap.
+EOS
+
   def initialize
     @map = {}
     @order = []
@@ -60,10 +68,31 @@ class Keymap
     end
   end
 
+  def delete k
+    kc = Keymap.keysym_to_keycode(k)
+    return unless @map.member? kc
+    entry = @map.delete kc
+    keys = entry[2]
+    keys.delete k
+    @order.delete entry if keys.empty?
+  end
+
+  def add! action, help, *keys
+    keys.each { |k| delete k }
+    add action, help, *keys
+  end
+
   def add_multi prompt, key
-    submap = Keymap.new
-    add submap, prompt, key
-    yield submap
+    kc = Keymap.keysym_to_keycode(key)
+    if @map.member? kc
+      action = @map[kc].first
+      raise "existing action is not a keymap" unless action.is_a?(Keymap)
+      yield action
+    else
+      submap = Keymap.new
+      add submap, prompt, key
+      yield submap
+    end
   end
 
   def action_for kc
@@ -95,6 +124,15 @@ class Keymap
     llen = lines.max_of { |a, b| a.length }
     lines.map { |a, b| sprintf " %#{llen}s : %s", a, b }.join("\n")
   end
+
+  def self.run_hook global_keymap
+    modes = Hash[Mode.keymaps.map { |klass,keymap| [Mode.make_name(klass.name),klass] }]
+    locals = {
+      :modes => modes,
+      :global_keymap => global_keymap,
+    }
+    HookManager.run 'keybindings', locals
+  end
 end
 
 end
diff --git a/lib/sup/mode.rb b/lib/sup/mode.rb
@@ -10,6 +10,14 @@ class Mode
     @@keymaps[self] = keymap
   end
 
+  def self.keymap
+    @@keymaps[self] || register_keymap
+  end
+
+  def self.keymaps
+    @@keymaps
+  end
+
   def initialize
     @buffer = nil
   end