I have two suggestions, one, not using any non-default packages, very closely based on the definition of text-scale-adjust
and one using hydra
.
Self-contained
;; -*- lexical-binding: t -*-
;; the previous line needs to be the first in the given file.
(require 'python) ;; alternatively use an appropriate use-package
declaration
(defun python-indent-adjust (count)
"Shift relevant lines by COUNT columns to the right or left.
If the region is active, then the `relevant' lines are those in
the region. Otherwise, it's just the current line.
COUNT may be passed as a numeric prefix argument. It defaults to
‘python-indent-offset’.
The actual adjustment made depends on the final component of the
key-binding used to invoke the command, with all modifiers removed:
< Shift the indendation to the left
> Shift the indendation to the right
After adjusting, continue to read input events and further adjust
the indentation as long as the input event read (with all
modifiers removed) is one of the above characters.
This command is a special-purpose wrapper around the
python-indent-shift-right' and
python-indent-shift-left' commands."
(interactive "P")
(let ((start (if mark-active (region-beginning) (line-beginning-position)))
(end (if mark-active (region-end) (line-end-position)))
(count (if count count python-indent-offset)))
(let ((ev last-command-event)
(echo-keystrokes nil))
(let* ((base (event-basic-type ev))
(func
(pcase base
((or ?> ?.) 'python-indent-shift-right)
((or ?< ?,) 'python-indent-shift-left))))
(funcall func start end count)
(message "Use <,> for further adjustment")
(set-transient-map
(let ((map (make-sparse-keymap)))
(dolist (mods '(() (control)))
(dolist (key '(?> ?< ?, ?.)) ;; ,. are often unshifted <,>.
(define-key map (vector (append mods (list key)))
(lambda () (interactive)
(python-indent-adjust count)))))
map))))))
(define-key python-mode-map (kbd "C-c >") 'python-indent-adjust)
(define-key python-mode-map (kbd "C-c <") 'python-indent-adjust)
Hydra
You need to install hydra
first.
(require 'python) ;; alternatively use an appropriate `use-package` declaration
(defhydra python-indent (python-mode-map "C-c")
"Adjust python indentation."
(">" python-indent-shift-right "right")
("<" python-indent-shift-left "left"))
The hydra solution has the tiny disadvantage that if you explicitly specify the number of columns by which to indent (e.g. with a prefix argument (e.g. C-u N
where N
is an integer)), then that will only apply to the first indentation. Hence, if you wish to continue adjusting by, say 5 columns, you need to do something like C-u 5 C-c > 5 > 5 >
etc. Normally, though, you'll want to adjust the indentation by the default amount, so you won't need to worry about this.
Global bindings
If you want to use the bindings both globally and within python mode, as suggested in the comments, in addition to the previous defhydra
you also need:
(defhydra python-indent (global-map "C-c")
"Adjust python indentation."
(">" python-indent-shift-right "right")
("<" python-indent-shift-left "left"))
(If you wanted to use the stand-alone solution, you'd similarly need two extra define-key
s with global-map
(or global-set-key
s).)
Regarding globabl use: I don't think it's a bad idea, as such but it's possible that the indent functions used for python-mode
might not necessarily play well with all other possible language modes, though I can't currently think of any specific incompatibilities.
"C-c >"
apply for all the language modes? // First solutions says:Symbol’s value as variable is void: count
but second solution works – alper Nov 06 '20 at 15:53python-mode-map
withglobal-map
? – alper Nov 06 '20 at 16:10*scratch*
buffer, since lexical binding is turned on there, by default. I think that I've fixed the problem, though. – aplaice Nov 06 '20 at 19:03global-map
. However, in order for it to be set both for the global and python maps, I think that you'll need two have twodefhydra
s (or two sets ofdefine-key
s) — otherwise the defaultpython-mode-map
definition will override your customglobal-map
one. – aplaice Nov 06 '20 at 19:11shell-mode
or orher modes as well? – alper Jun 29 '21 at 14:51shell-mode
or most other modes. (It won't work too well with term mode and the like, since there most keybindings are passed directly tobash
etc.) – aplaice Jun 30 '21 at 20:28(defhydra python-indent (global-map "C-c")
does not overwrite to global bindings and in shell-mode its bind tosh-learn-line-indent
. Is there any way to force to overwrite the keybinding – alper Jul 03 '21 at 14:11shell-mode
the "local" (mode-specific) binding takes precedence over the global binding.) – aplaice Jul 03 '21 at 20:25