From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: "Philip K." Newsgroups: gmane.emacs.bugs Subject: bug#41438: [PATCH] Allow windmove keys to be bound without prefix or modifiers Date: Fri, 07 Aug 2020 12:53:10 +0200 Message-ID: <87mu36enhl.fsf@posteo.net> References: <87imgpw7k3.fsf@warpmail.net> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="19692"; mail-complaints-to="usenet@ciao.gmane.io" Cc: 41438@debbugs.gnu.org, larsi@gnus.org To: Juri Linkov Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Fri Aug 07 12:54:39 2020 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1k401G-00050m-V7 for geb-bug-gnu-emacs@m.gmane-mx.org; Fri, 07 Aug 2020 12:54:39 +0200 Original-Received: from localhost ([::1]:37258 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1k401G-0007vG-1D for geb-bug-gnu-emacs@m.gmane-mx.org; Fri, 07 Aug 2020 06:54:38 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:49316) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1k400g-0007AU-GN for bug-gnu-emacs@gnu.org; Fri, 07 Aug 2020 06:54:02 -0400 Original-Received: from debbugs.gnu.org ([209.51.188.43]:44336) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1k400g-0004UO-2q for bug-gnu-emacs@gnu.org; Fri, 07 Aug 2020 06:54:02 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1k400g-0008LO-2F for bug-gnu-emacs@gnu.org; Fri, 07 Aug 2020 06:54:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: "Philip K." Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Fri, 07 Aug 2020 10:54:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 41438 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch Original-Received: via spool by 41438-submit@debbugs.gnu.org id=B41438.159679760532027 (code B ref 41438); Fri, 07 Aug 2020 10:54:02 +0000 Original-Received: (at 41438) by debbugs.gnu.org; 7 Aug 2020 10:53:25 +0000 Original-Received: from localhost ([127.0.0.1]:55882 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1k4004-0008KU-HD for submit@debbugs.gnu.org; Fri, 07 Aug 2020 06:53:25 -0400 Original-Received: from mout02.posteo.de ([185.67.36.66]:50443) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1k3zzy-0008K4-LM for 41438@debbugs.gnu.org; Fri, 07 Aug 2020 06:53:22 -0400 Original-Received: from submission (posteo.de [89.146.220.130]) by mout02.posteo.de (Postfix) with ESMTPS id 105782400FB for <41438@debbugs.gnu.org>; Fri, 7 Aug 2020 12:53:11 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=posteo.net; s=2017; t=1596797592; bh=ce/HR1cXx8WrxL93uN11xXEMWNrJSe2fHh6O9YiCHfg=; h=From:To:Cc:Subject:Date:From; b=W7nFdzTlM80XPA9GgeGNeVkw+c6Pl/NyGKAd4McBskk0gljn8J4Ffbrqj+6Wvn2jz 2Nwocfs5e+PbMp/UG3qGUEgDXsV9FtBC1R1e01vo3mOy0cBMT7yjGeQ1R7CSRRBdJB ZxoU8MxAnzixm8MeN6PikpUsGZ4DbSAq2eEGEtxtZPKkK2oarPMjm42GrFRo1dXTAx 5+h3raRRGNjDThA5jMOgszcUhgfkeLpRq+1K7shT2Lpi23gJtidoYRpOpk0rWae3O1 sme+A1I9Do2M7IAEPy3lh44I5SF7rKOiYQKwPN3q8IQ4Sui35fbdDZqTflUKkzpXdU tvIy9snvet9xw== Original-Received: from customer (localhost [127.0.0.1]) by submission (posteo.de) with ESMTPSA id 4BNMdz1c4Sz9rxX; Fri, 7 Aug 2020 12:53:11 +0200 (CEST) In-Reply-To: <87a6z78gqw.fsf@mail.linkov.net> (message from Juri Linkov on Fri, 07 Aug 2020 02:43:03 +0300) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.io gmane.emacs.bugs:184254 Archived-At: --=-=-= Content-Type: text/plain Juri Linkov 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. --=-=-= Content-Type: text/x-diff Content-Disposition: inline; filename=0001-Allow-windmove-keys-to-be-bound-without-prefix-or-mo.patch >From f87d057b72f0cc374c132100664c5b8553bd58e2 Mon Sep 17 00:00:00 2001 From: Philip K 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 --=-=-= Content-Type: text/x-diff Content-Disposition: inline; filename=0001-Add-user-options-to-bind-windmove-commands.patch >From c009311887372e1e822739edc050a802bfa4d1d8 Mon Sep 17 00:00:00 2001 From: Philip K 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 --=-=-=--