bug-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

bug#41438: [PATCH] Allow windmove keys to be bound without prefix or mod


From: Philip K.
Subject: bug#41438: [PATCH] Allow windmove keys to be bound without prefix or modifiers
Date: Fri, 07 Aug 2020 12:53:10 +0200

Juri Linkov <juri@linkov.net> writes:

>>> (I see there were some unfinished parts in your previous patch).
>>
>> It's been a while since I submitted it, so I had to re-read the thread,
>> but I'm not quite sure what the "unfinished" parts were, aside from the
>> missing autoload cookies. Sorry if I missed something :/
>
> I don't know, my impression seems to suggest the first version was not
> completely tested, for example, windmove-modifiers defcustom called
> windmove-swap-states-default-keybindings, not windmove-default-keybindings.
> But maybe you already fixed this.

You're right, I still had a few local changes. A noteworthy addition is
that the user options unbind their previous bindings, before binding the
new ones. This should lead to more consistent behaviour when updating
the option a few times in the same session.

>> Also, the second patch (the one with the user options) depended on the
>> previous one in this thread[0], that introduced the "none" prefix. Is
>> that fine, or should I just merge both patches into one.
>
> This is perfectly fine - better to commit two separate patches.

Ok. I added both below.

But there are a few general issues I noticed:

1. windmove-display-{same-window,new-{frame,tab}} can disturb regular
   input when the modifier is set to shift or none. Possible solutions
   could be to prohibit using these modifiers or to add a prefix key and
   generate a warning when eg. "S-t" or "t" would be rebound.
2. The new function windmove--unbind works with the global-map, so when
   someone sets a prefix to none, and then changes it to something else,
   the arrow keys are left undefined. I could either see this being
   fixed by using a separate map or by somehow memorising what the
   previous key was (eg. by using the property list of the windmove
   command's symbol).

These are the only edge-cases I found, but I didn't fix them yet, as I'm
not sure what would be preferred. So the patches should not be applies yet.

-- 
        Philip K.

>From f87d057b72f0cc374c132100664c5b8553bd58e2 Mon Sep 17 00:00:00 2001
From: Philip K <philip@warpmail.net>
Date: Thu, 21 May 2020 18:44:10 +0200
Subject: [PATCH] Allow windmove keys to be bound without prefix or modifiers

---
 lisp/windmove.el | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/lisp/windmove.el b/lisp/windmove.el
index 6557960064..613727f8ed 100644
--- a/lisp/windmove.el
+++ b/lisp/windmove.el
@@ -431,9 +431,12 @@ windmove-default-keybindings
   "Set up keybindings for `windmove'.
 Keybindings are of the form MODIFIERS-{left,right,up,down},
 where MODIFIERS is either a list of modifiers or a single modifier.
+If MODIFIERS is `none', the keybindings will be directly bound to
+the arrow keys.
 Default value of MODIFIERS is `shift'."
   (interactive)
   (unless modifiers (setq modifiers 'shift))
+  (when (eq modifiers 'none) (setq modifiers nil))
   (unless (listp modifiers) (setq modifiers (list modifiers)))
   (global-set-key (vector (append modifiers '(left)))  'windmove-left)
   (global-set-key (vector (append modifiers '(right))) 'windmove-right)
@@ -546,9 +549,12 @@ windmove-display-default-keybindings
 Keys are bound to commands that display the next buffer in the specified
 direction.  Keybindings are of the form MODIFIERS-{left,right,up,down},
 where MODIFIERS is either a list of modifiers or a single modifier.
+If MODIFIERS is `none', the keybindings will be directly bound to
+the arrow keys.
 Default value of MODIFIERS is `shift-meta'."
   (interactive)
   (unless modifiers (setq modifiers '(shift meta)))
+  (when (eq modifiers 'none) (setq modifiers nil))
   (unless (listp modifiers) (setq modifiers (list modifiers)))
   (global-set-key (vector (append modifiers '(left)))  'windmove-display-left)
   (global-set-key (vector (append modifiers '(right))) 'windmove-display-right)
@@ -618,11 +624,16 @@ windmove-delete-default-keybindings
 Keys are bound to commands that delete windows in the specified
 direction.  Keybindings are of the form PREFIX MODIFIERS-{left,right,up,down},
 where PREFIX is a prefix key and MODIFIERS is either a list of modifiers or
-a single modifier.  Default value of PREFIX is `C-x' and MODIFIERS is `shift'."
+a single modifier.
+If PREFIX is `none', no prefix is used. If MODIFIERS is `none', the keybindings
+are directly bound to the arrow keys.
+Default value of PREFIX is `C-x' and MODIFIERS is `shift'."
   (interactive)
   (unless prefix (setq prefix '(?\C-x)))
+  (when (eq prefix 'none) (setq prefix nil))
   (unless (listp prefix) (setq prefix (list prefix)))
   (unless modifiers (setq modifiers '(shift)))
+  (when (eq modifiers 'none) (setq modifiers nil))
   (unless (listp modifiers) (setq modifiers (list modifiers)))
   (global-set-key (vector prefix (append modifiers '(left)))  
'windmove-delete-left)
   (global-set-key (vector prefix (append modifiers '(right))) 
'windmove-delete-right)
@@ -673,9 +684,13 @@ windmove-swap-states-default-keybindings
 Keys are bound to commands that swap the states of the selected window
 with the window in the specified direction.  Keybindings are of the form
 MODIFIERS-{left,right,up,down}, where MODIFIERS is either a list of modifiers
-or a single modifier.  Default value of MODIFIERS is `shift-super'."
+or a single modifier.
+If MODIFIERS is `none', the keybindings will be directly bound to the
+arrow keys.
+Default value of MODIFIERS is `shift-super'."
   (interactive)
   (unless modifiers (setq modifiers '(shift super)))
+  (when (eq modifiers 'none) (setq modifiers nil))
   (unless (listp modifiers) (setq modifiers (list modifiers)))
   (global-set-key (vector (append modifiers '(left)))  
'windmove-swap-states-left)
   (global-set-key (vector (append modifiers '(right))) 
'windmove-swap-states-right)
-- 
2.20.1

>From c009311887372e1e822739edc050a802bfa4d1d8 Mon Sep 17 00:00:00 2001
From: Philip K <philipk@posteo.net>
Date: Fri, 7 Aug 2020 12:35:49 +0200
Subject: [PATCH] Add user options to bind windmove commands

* windmove.el (windmove-modifier-type): Create
(windmove--unbind): New constant
(windmove-modifiers): New user option
(windmove-default-keybindings): Use windmove-modifiers
(windmove-display-modifiers): New user option
(windmove-display-default-keybindings): Use windmove-display-modifiers
(windmove-delete-prefix): New user option
(windmove-delete-modifiers): New user option
(windmove-delete-default-keybindings): Use windmove-delete-prefix and
windmove-delete-modifiers
(windmove-swap-states-modifiers): New user option
(windmove-swap-states-default-keybindings): Use windmove-swap-states-modifiers
---
 lisp/windmove.el | 154 ++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 145 insertions(+), 9 deletions(-)

diff --git a/lisp/windmove.el b/lisp/windmove.el
index 613727f8ed..9b68f9a5b9 100644
--- a/lisp/windmove.el
+++ b/lisp/windmove.el
@@ -162,6 +162,40 @@ windmove-window-distance-delta
 (make-obsolete-variable 'windmove-window-distance-delta
                         "no longer used." "27.1")
 
+(defconst windmove-modifier-type
+  '(choice (set :tag "Modifier Symbols"
+                :greedy t
+                ;; See `(elisp) Keyboard Events'
+                (const :tag "Meta" meta)
+                (const :tag "Control" control)
+                (const :tag "Shift" shift)
+                (const :tag "Hyper" hyper)
+                (const :tag "Super" super)
+                (const :tag "Alt" alt))
+           (const :tag "No modifier" none)
+           (const :tag "Not bound" nil))
+  "Customisation type for windmove modifiers")
+
+(defun windmove--unbind (prefix modifiers fns &optional extra)
+  "Unbind windmove commands, bound by PREFIX and MODIFIER.
+To ensure that only windmove functions are unbound, the command
+must be member of the list FNS.
+By default only the left, right, up and down keys are unbound,
+but further keys can be added via EXTRA."
+  (setq prefix
+        (cond ((eq prefix 'none) nil)
+              ((not (listp prefix)) (list prefix))
+              (t prefix)))
+  (setq modifiers
+        (cond ((eq modifiers 'none) nil)
+              ((not (listp modifiers)) (list modifiers))
+              (t modifiers)))
+  (dolist (dir (append '(left right up down) extra))
+    (let* ((key (append modifiers (list dir)))
+           (key (vconcat prefix (list key))))
+      (when (memq (lookup-key global-map key) fns)
+        (global-set-key key nil)))))
+
 
 ;; Note:
 ;;
@@ -419,6 +453,7 @@ windmove-down
   (interactive "P")
   (windmove-do-window-select 'down (and arg (prefix-numeric-value arg))))
 
+(defvar windmove-modifiers)
 
 ;;; set up keybindings
 ;; Idea for this function is from iswitchb.el, by Stephen Eglen
@@ -433,16 +468,41 @@ windmove-default-keybindings
 where MODIFIERS is either a list of modifiers or a single modifier.
 If MODIFIERS is `none', the keybindings will be directly bound to
 the arrow keys.
-Default value of MODIFIERS is `shift'."
+Default value of MODIFIERS is stored in `windmove-modifiers'."
   (interactive)
-  (unless modifiers (setq modifiers 'shift))
   (when (eq modifiers 'none) (setq modifiers nil))
+  (unless modifiers
+    (setq modifiers windmove-modifiers))
   (unless (listp modifiers) (setq modifiers (list modifiers)))
   (global-set-key (vector (append modifiers '(left)))  'windmove-left)
   (global-set-key (vector (append modifiers '(right))) 'windmove-right)
   (global-set-key (vector (append modifiers '(up)))    'windmove-up)
   (global-set-key (vector (append modifiers '(down)))  'windmove-down))
 
+;; has to be declared AFTER windmove-default-keybindings, or else
+;; windmove is recursivly loaded
+;;;###autoload
+(defcustom windmove-modifiers '(shift super)
+  "Modifiers for `windmove-default-keybindings'.
+Can either be a symbol or list of modifier symbols,
+i.e. `meta',`control', `shift', `hyper', `super', or `alt'
+representing modifier keys to use with the arrow keys.
+
+If the value is just `none', the arrow keys will be directly
+bound to the windmove functions."
+  :type windmove-modifier-type
+  :require 'windmove
+  :initialize #'custom-initialize-changed
+  :set (lambda (sym val)
+         (windmove--unbind nil (default-value sym)
+                           '(windmove-left
+                             windmove-right
+                             windmove-up
+                             windmove-down))
+         (when val
+           (windmove-default-keybindings val))
+         (set-default sym val)))
+
 
 ;;; Directional window display and selection
 
@@ -543,6 +603,8 @@ windmove-display-new-tab
   (interactive "P")
   (windmove-display-in-direction 'new-tab arg))
 
+(defvar windmove-display-modifiers)
+
 ;;;###autoload
 (defun windmove-display-default-keybindings (&optional modifiers)
   "Set up keybindings for directional buffer display.
@@ -551,9 +613,10 @@ windmove-display-default-keybindings
 where MODIFIERS is either a list of modifiers or a single modifier.
 If MODIFIERS is `none', the keybindings will be directly bound to
 the arrow keys.
-Default value of MODIFIERS is `shift-meta'."
+Default value of MODIFIERS is stored in `windmove-display-modifiers'."
   (interactive)
-  (unless modifiers (setq modifiers '(shift meta)))
+  (unless modifiers
+    (setq modifiers windmove-display-modifiers))
   (when (eq modifiers 'none) (setq modifiers nil))
   (unless (listp modifiers) (setq modifiers (list modifiers)))
   (global-set-key (vector (append modifiers '(left)))  'windmove-display-left)
@@ -564,6 +627,27 @@ windmove-display-default-keybindings
   (global-set-key (vector (append modifiers '(?f)))    
'windmove-display-new-frame)
   (global-set-key (vector (append modifiers '(?t)))    
'windmove-display-new-tab))
 
+;;;###autoload
+(defcustom windmove-display-modifiers '(shift meta)
+  "Modifiers for `windmove-display-default-keybindings'.
+Analogous to `windmove-modifiers'."
+  :type windmove-modifier-type
+  :require 'windmove
+  :initialize #'custom-initialize-changed
+  :set (lambda (sym val)
+         (windmove--unbind nil (default-value sym)
+                           '(windmove-display-left
+                             windmove-display-right
+                             windmove-display-up
+                             windmove-display-down
+                             windmove-display-same-window
+                             windmove-display-new-frame
+                             windmove-display-new-tab)
+                           '(?0 ?f ?t))
+         (when val
+           (windmove-display-default-keybindings val))
+         (set-default sym val)))
+
 
 ;;; Directional window deletion
 
@@ -618,6 +702,9 @@ windmove-delete-down
   (interactive "P")
   (windmove-delete-in-direction 'down arg))
 
+(defvar windmove-delete-prefix)
+(defvar windmove-delete-modifiers)
+
 ;;;###autoload
 (defun windmove-delete-default-keybindings (&optional prefix modifiers)
   "Set up keybindings for directional window deletion.
@@ -627,12 +714,15 @@ windmove-delete-default-keybindings
 a single modifier.
 If PREFIX is `none', no prefix is used. If MODIFIERS is `none', the keybindings
 are directly bound to the arrow keys.
-Default value of PREFIX is `C-x' and MODIFIERS is `shift'."
+The default values for PREFIX and MODIFIERS are stored in 
`windmove-delete-prefix'
+and `windmove-delete-modifiers' respectively."
   (interactive)
-  (unless prefix (setq prefix '(?\C-x)))
+  (unless prefix
+    (setq prefix (list windmove-delete-prefix)))
   (when (eq prefix 'none) (setq prefix nil))
   (unless (listp prefix) (setq prefix (list prefix)))
-  (unless modifiers (setq modifiers '(shift)))
+  (unless modifiers
+    (setq modifiers windmove-delete-modifiers))
   (when (eq modifiers 'none) (setq modifiers nil))
   (unless (listp modifiers) (setq modifiers (list modifiers)))
   (global-set-key (vector prefix (append modifiers '(left)))  
'windmove-delete-left)
@@ -640,6 +730,32 @@ windmove-delete-default-keybindings
   (global-set-key (vector prefix (append modifiers '(up)))    
'windmove-delete-up)
   (global-set-key (vector prefix (append modifiers '(down)))  
'windmove-delete-down))
 
+(defcustom windmove-delete-prefix (kbd "C-x")
+  "Prefix for `windmove-delete-default-keybindings'."
+  :type 'key-sequence
+  :require 'windmove
+  :initialize #'custom-initialize-changed)
+
+;;;###autoload
+(defcustom windmove-delete-modifiers '(shift)
+  "Modifiers for `windmove-delete-default-keybindings'.
+See `windmove-modifiers' for more details"
+  :type windmove-modifier-type
+  :require 'windmove
+  :initialize #'custom-initialize-changed
+  :set-after '(windmove-delete-prefix)
+  :set (lambda (sym val)
+         (windmove--unbind windmove-delete-prefix
+                           (default-value sym)
+                           '(windmove-delete-left
+                             windmove-delete-right
+                             windmove-delete-up
+                             windmove-delete-down))
+         (when val
+           (windmove-delete-default-keybindings
+            windmove-delete-prefix val))
+         (set-default sym val)))
+
 
 ;;; Directional window swap states
 
@@ -678,6 +794,8 @@ windmove-swap-states-right
   (interactive)
   (windmove-swap-states-in-direction 'right))
 
+(defvar windmove-swap-states-modifiers)
+
 ;;;###autoload
 (defun windmove-swap-states-default-keybindings (&optional modifiers)
   "Set up keybindings for directional window swap states.
@@ -687,9 +805,10 @@ windmove-swap-states-default-keybindings
 or a single modifier.
 If MODIFIERS is `none', the keybindings will be directly bound to the
 arrow keys.
-Default value of MODIFIERS is `shift-super'."
+Default value of MODIFIERS is stored in `windmove-swap-states-modifiers'."
   (interactive)
-  (unless modifiers (setq modifiers '(shift super)))
+  (unless modifiers
+    (setq modifiers windmove-swap-states-modifiers))
   (when (eq modifiers 'none) (setq modifiers nil))
   (unless (listp modifiers) (setq modifiers (list modifiers)))
   (global-set-key (vector (append modifiers '(left)))  
'windmove-swap-states-left)
@@ -697,6 +816,23 @@ windmove-swap-states-default-keybindings
   (global-set-key (vector (append modifiers '(up)))    
'windmove-swap-states-up)
   (global-set-key (vector (append modifiers '(down)))  
'windmove-swap-states-down))
 
+;;;###autoload
+(defcustom windmove-swap-states-modifiers '(shift super)
+  "Modifiers for `windmove-swap-states-default-keybindings'.
+Analogous to `windmove-modifiers'."
+  :type windmove-modifier-type
+  :require 'windmove
+  :initialize #'custom-initialize-changed
+  :set (lambda (sym val)
+         (windmove--unbind nil (default-value sym)
+                           '(windmove-swap-states-left
+                             windmove-swap-states-right
+                             windmove-swap-states-up
+                             windmove-swap-states-downp))
+         (when val
+           (windmove-swap-states-default-keybindings val))
+         (set-default sym val)))
+
 
 (provide 'windmove)
 
-- 
2.20.1


reply via email to

[Prev in Thread] Current Thread [Next in Thread]