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' andpython-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-keys with global-map (or global-set-keys).)
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: countbut second solution works – alper Nov 06 '20 at 15:53python-mode-mapwithglobal-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 twodefhydras (or two sets ofdefine-keys) — otherwise the defaultpython-mode-mapdefinition will override your customglobal-mapone. – aplaice Nov 06 '20 at 19:11shell-modeor orher modes as well? – alper Jun 29 '21 at 14:51shell-modeor most other modes. (It won't work too well with term mode and the like, since there most keybindings are passed directly tobashetc.) – 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-modethe "local" (mode-specific) binding takes precedence over the global binding.) – aplaice Jul 03 '21 at 20:25