3

I am using following answer to handle indentations Emacs bulk indent for Python

C-c > or C-c C-l shifts the region 4 spaces to the right

C-c < or C-c C-r shifts the region 4 spaces to the left


If I do C-c > and >; the selected text becomes >; or if I do C-c < and <; the selected text becomes <.

I was wondering can we do following:

=> C-c > , > , > to continue to indent 4 space to right one after another

=> C-c < , < , < to continue to indent 4 space to left one after another

0

1 Answer 1

1

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-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.

9
  • 1
    Can "C-c >" apply for all the language modes? // First solutions says: Symbol’s value as variable is void: count but second solution works
    – alper
    Commented Nov 6, 2020 at 15:53
  • 1
    For make it global should I replace python-mode-map with global-map ?
    – alper
    Commented Nov 6, 2020 at 16:10
  • I'm sorry about the first solution. It was caused by an issue with how Iexical binding works — it worked in the *scratch* buffer, since lexical binding is turned on there, by default. I think that I've fixed the problem, though.
    – aplaice
    Commented Nov 6, 2020 at 19:03
  • To make it global, you indeed need to use the global-map. However, in order for it to be set both for the global and python maps, I think that you'll need two have two defhydras (or two sets of define-keys) — otherwise the default python-mode-map definition will override your custom global-map one.
    – aplaice
    Commented Nov 6, 2020 at 19:11
  • 1
    Please see: emacs.stackexchange.com/questions/66587/…
    – alper
    Commented Jul 4, 2021 at 12:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.