Emacs 批量缩进 Python 代码

146

当我在Emacs中使用Python编写代码时,如果需要给一段代码添加try/except语句,我通常会发现自己需要逐行缩进整个代码块。 在Emacs中,如何一次性缩进整个代码块。

我不是一个经验丰富的Emacs用户,但我发现它是通过ssh进行工作的最好工具。 我在命令行上(Ubuntu)使用Emacs,而不是GUI界面,如果这有任何区别的话。


8
"将光标向右移动,请使用 C-c >。将光标向左移动,请使用 C-c <。" - Thamme Gowda
8个回答

237
如果您使用Emacs编程Python,那么您应该使用python-mode。使用python-mode后,标记代码块后,C-c >C-c C-l将把区域向右移动4个空格,C-c <C-c C-r将把区域向左移动4个空格。如果您需要将代码向右缩进两个级别或任意数量,可以在命令前加上参数:C-u 8 C-c >将区域向右移动8个空格,C-u 8 C-c <将区域向左移动8个空格。另一种选择是使用绑定到C-x TABM-x indent-rigidlyC-u 8 C-x TAB将区域向右移动8个空格,C-u -8 C-x TAB将区域向左移动8个空格。还有一些矩形命令对文本矩形而不是文本行进行操作很有用。例如,在标记矩形区域后,C-x r o插入空格以填充矩形区域(有效地向右移动代码),C-x r k删除矩形区域(有效地向左移动代码)。

C-x r t提示输入一个字符串,用于替换矩形区域。输入 C-u 8 <space> 将输入8个空格。

PS. 在Ubuntu下,将python-mode设置为所有.py文件的默认模式,只需安装python-mode软件包即可。


谢谢,那个完美地运作。在Emacs22里不是自动启用所有.py文件的python-mode吗?无论如何,C-c >非常好用。 - Vernon
1
在Emacs 23.2中,C-c >可以正常工作,无需安装python-mode,因为它可以与提供的python.el一起使用。 - codeasone
只是补充一下,C-c > 和 C-c < 也绑定到了 C-c C-l 和 C-C-c C-r(左和右)。在我看来,这些更容易输入。请问您能否更新答案以反映这一点?(谢谢) - rkachach
2
@redobot:C-c C-lC-c C-r必须是您自己设置的自定义绑定。如果您运行emacs -q(以不加载初始化文件的方式运行emacs),则会发现在Python模式下没有为C-c C-lC-c C-r绑定任何键位。 - unutbu
不,可能它们只在最新版本的模式中可用。如果您查看文件https://github.com/emacsmirror/python-mode/blob/master/python-mode.el,您可以找到它们(只需查找py-shift-left和py-shift-right)。 - rkachach
显示剩余4条评论

11
除了默认映射为C-M-\indent-region之外,矩形编辑命令对Python非常有用。将区域标记为普通后,然后:
  • C-x r t (string-rectangle):提示您要插入每行的字符;非常适合插入一定数量的空格
  • C-x r k (kill-rectangle):删除矩形区域;非常适合删除缩进

您还可以使用C-x r y (yank-rectangle),但这只在极少数情况下有用。


4

indent-region 映射到 C-M-\ 应该可以解决问题。


7
这是可怕的建议。Python缩进不能被推断出来(因为它是语法!)所以ident-region是无用的。 - Sam Clearman

4

交互式地进行缩进。

  1. 选择要进行缩进的区域。
  2. 按下 C-x TAB
  3. 使用箭头(<-->)进行交互式缩进。
  4. 在所需的缩进完成后按下 Esc 键三次。

摘自我的帖子:Indent several lines in Emacs


2
我使用以下代码片段。在未选择文本时,按Tab键会将当前行缩进(与通常情况下相同);当选择文本时,会将整个区域向右缩进。
(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)

2

我是Emacs的新手,所以我的答案可能没有多大用处。

到目前为止,还没有任何答案提到重新缩进字面量(如dictlist)。例如,如果您剪切并粘贴以下文字,并需要使其重新缩进,则M-x indent-regionM-x python-indent-shift-right等命令无法帮助您:

    foo = {
  'bar' : [
     1,
    2,
        3 ],
      'baz' : {
     'asdf' : {
        'banana' : 1,
        'apple' : 2 } } }

感觉在python-mode下,M-x indent-region应该能做出合理的事情,但实际上(目前)并不是这样。

对于特定情况,如果你的文字是用括号括起来的,那么在相关行上使用TAB键就可以得到你想要的结果(因为空格不起作用)。

所以在这种情况下,我通常会快速记录一个键盘宏,例如<f3> C-n TAB <f4>,然后使用F4重复应用宏可以节省一些按键。或者你可以使用C-u 10 C-x e来重复应用10次宏。

(我知道这听起来不算什么,但试着重新缩进100行垃圾文字而不错过向下箭头,然后又必须返回5行重复这个过程;)


2

我一直在使用这个函数来处理我的缩进和取消缩进:

(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))))))))

然后我将其分配给一个键盘快捷键:

(global-set-key (kbd "s-[") 'unindent-dwim)
(global-set-key (kbd "s-]") (lambda () (interactive) (unindent-dwim -1)))

-4

我普遍地做类似这样的事情

;; intent whole buffer 
(defun iwb ()
  "indent whole buffer"
  (interactive)
  ;;(delete-trailing-whitespace)
  (indent-region (point-min) (point-max) nil)
  (untabify (point-min) (point-max)))

3
因为在Python中,空白符是语法的一部分,所以对整个文件进行缩进处理并不是一个好主意。 - Daniel Stutzbach

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接