Emacs bulk indent for Python
Working with Python in Emacs if I want to add a try/except to a block of code, I often find that I am having to indent the whole block, line by line. In Emacs, how do you indent the whole block at once.
I am not an experienced Emacs user, but just find it is the best tool for working through ssh. I am using Emacs on the command line(Ubuntu), not as a gui, if that makes any diff开发者_StackOverflowerence.
If you are programming Python using Emacs, then you should probably be using python-mode. With python-mode, after marking the block of code,
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 you need to shift code by two levels of indention, or some arbitary amount you can prefix the command with an argument:
C-u 8 C-c >
shifts the region 8 spaces to the right
C-u 8 C-c <
shifts the region 8 spaces to the left
Another alternative is to use M-x indent-rigidly
which is bound to C-x TAB
:
C-u 8 C-x TAB
shifts the region 8 spaces to the right
C-u -8 C-x TAB
shifts the region 8 spaces to the left
Also useful are the rectangle commands that operate on rectangles of text instead of lines of text.
For example, after marking a rectangular region,
C-x r o
inserts blank space to fill the rectangular region (effectively shifting code to the right)
C-x r k
kills the rectangular region (effectively shifting code to the left)
C-x r t
prompts for a string to replace the rectangle with. Entering C-u 8 <space>
will then enter 8 spaces.
PS. With Ubuntu, to make python-mode the default mode for all .py files, simply install the python-mode
package.
In addition to indent-region
, which is mapped to C-M-\
by default, the rectangle edit commands are very useful for Python. Mark a region as normal, then:
C-x r t
(string-rectangle
): will prompt you for characters you'd like to insert into each line; great for inserting a certain number of spacesC-x r k
(kill-rectangle
): remove a rectangle region; great for removing indentation
You can also C-x r y
(yank-rectangle
), but that's only rarely useful.
indent-region
mapped to C-M-\
should do the trick.
Do indentation interactively.
- Select the region to be indented.
- C-x TAB.
- Use arrows (<- and ->) to indent interactively.
- Press Esc three times when you are done with the required indentation.
Copied from my post in: Indent several lines in Emacs
I've been using this function to handle my indenting and unindenting:
(defun unindent-dwim (&optional count-arg)
"Keeps relative spacing in the region. Unindents to the next multiple of the current tab-width"
(interactive)
(let ((deactivate-mark nil)
(beg (or (and mark-active (region-beginning)) (line-beginning-position)))
(end (or (and mark-active (region-end)) (line-end-position)))
(min-indentation)
(count (or count-arg 1)))
(save-excursion
(goto-char beg)
(while (< (point) end)
(add-to-list 'min-indentation (current-indentation))
(forward-line)))
(if (< 0 count)
(if (not (< 0 (apply 'min min-indentation)))
(error "Can't indent any more. Try `indent-rigidly` with a negative arg.")))
(if (> 0 count)
(indent-rigidly beg end (* (- 0 tab-width) count))
(let (
(indent-amount
(apply 'min (mapcar (lambda (x) (- 0 (mod x tab-width))) min-indentation))))
(indent-rigidly beg end (or
(and (< indent-amount 0) indent-amount)
(* (or count 1) (- 0 tab-width))))))))
And then I assign it to a keyboard shortcut:
(global-set-key (kbd "s-[") 'unindent-dwim)
(global-set-key (kbd "s-]") (lambda () (interactive) (unindent-dwim -1)))
I'm an Emacs newb, so this answer it probably bordering on useless.
None of the answers mentioned so far cover re-indentation of literals like dict
or list
. E.g. M-x indent-region
or M-x python-indent-shift-right
and company aren't going to help if you've cut-and-pasted the following literal and need it to be re-indented sensibly:
foo = {
'bar' : [
1,
2,
3 ],
'baz' : {
'asdf' : {
'banana' : 1,
'apple' : 2 } } }
It feels like M-x indent-region
should do something sensibly in python-mode
, but that's not (yet) the case.
For the specific case where your literals are bracketed, using TAB on the lines in question gets what you want (because whitespace doesn't play a role).
So what I've been doing in such cases is quickly recording a keyboard macro like <f3> C-n TAB <f4>
as in F3, Ctrl-n (or down arrow), TAB, F4, and then using F4 repeatedly to apply the macro can save a couple of keystrokes. Or you can do C-u 10 C-x e
to apply it 10 times.
(I know it doesn't sound like much, but try re-indenting 100 lines of garbage literal without missing down-arrow, and then having to go up 5 lines and repeat things ;) ).
I use the following snippet. On tab when the selection is inactive, it indents the current line (as it normally does); when the selection is inactive, it indents the whole region to the right.
(defun my-python-tab-command (&optional _)
"If the region is active, shift to the right; otherwise, indent current line."
(interactive)
(if (not (region-active-p))
(indent-for-tab-command)
(let ((lo (min (region-beginning) (region-end)))
(hi (max (region-beginning) (region-end))))
(goto-char lo)
(beginning-of-line)
(set-mark (point))
(goto-char hi)
(end-of-line)
(python-indent-shift-right (mark) (point)))))
(define-key python-mode-map [remap indent-for-tab-command] 'my-python-tab-command)
I do something like this universally
;; intent whole buffer
(defun iwb ()
"indent whole buffer"
(interactive)
;;(delete-trailing-whitespace)
(indent-region (point-min) (point-max) nil)
(untabify (point-min) (point-max)))
精彩评论