Emacs bulk indent for Python

前端 未结 8 1239
星月不相逢
星月不相逢 2021-01-29 17:37

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

相关标签:
8条回答
  • 2021-01-29 18:07

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

    0 讨论(0)
  • 2021-01-29 18:09

    indent-region mapped to C-M-\ should do the trick.

    0 讨论(0)
  • 2021-01-29 18:15

    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.

    0 讨论(0)
  • 2021-01-29 18:16

    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)))
    
    0 讨论(0)
  • 2021-01-29 18:23

    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)
    
    0 讨论(0)
  • 2021-01-29 18:28

    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 spaces
    • C-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.

    0 讨论(0)
提交回复
热议问题