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 inden
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 ;) ).
indent-region
mapped to C-M-\
should do the trick.
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.
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 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)
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 indentationYou can also C-x r y
(yank-rectangle
), but that's only rarely useful.