多线python缩进emacs [英] multi lines python indentation on emacs

查看:128
本文介绍了多线python缩进emacs的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  egg = spam.foooooo(我想要一个emacs新手,我想要emacs能够缩进我的代码, 'viviviviviviviviv')\ 
.foooooo('emacs','emacs','emacs','emacs')

默认情况下,不需要自动执行 (不需要手动插入空格或Cc>),因为emacs总是缩进4个空格(除非我将多个参数分割成多行)



最好的做法是什么?



PS:如果是一个坏主意(对于PEP 8或某事)请告诉我

解决方案

我同意Aaron关于你的风格选择,但由于我也同意Emacs Lisp的乐趣,我将介绍如何实现这一点。



Emacs python -mode 计算函数 python-calculate-indentation ,处理连续行的相关部分埋在函数内部,没有简单的方法来配置。



所以我们有两个选择:


  1. 替换整个 python-calculate-缩进与我们自己的版本(每当 python-mode 更改时的维护噩梦);或

  2. 建议函数 python-calculate-indentation :就是将它包装在我们自己的函数中,处理我们感兴趣的情况,否则会延迟原来的。

选项(2)在这种情况下似乎是可行的。所以让我们去吧!首先要做的是阅读建议手册这表明我们的建议应该如下所示:

 (defadvice python-calculate-indentation(around continue-with-点)
处理从点开始的连续行,尝试
将它们与他们继续的行中的一个点对齐。
(除非
(此行) -i-a-dot-continuation-line);(TODO)
ad-do-it))

这里 ad-do-it 是一个魔术令牌, defadvice 替换原来的功能。来自Python背景,你可能会问:为什么不做这个装饰风格?设计Emacs建议机制(1)保持建议与原来的分离;和(2)为不需要合作的单个功能提供多个意见; (3)允许您个人控制哪些建议被打开和关闭。您可以想象在Python中编写类似的东西。



以下是如何判断当前行是否为虚线的连续行:


$ b $
(当(和(python-continuation-line-p))
(look-at\\ (TODO)
...)

这里有一个问题:调用开始行实际上移动到线。哎呀。我们不想在仅仅计算缩影时移动点。所以我们最好在打电话给 save-excursion ,以确保该点不会徘徊。



我们可以找到我们需要通过向后跳过令牌或括号表达式(Lisp称为S表达式或sexps),直到找到点,否则我们到达语句的开头。在缓冲区的限制部分进行搜索的好的Emacs成语是 narrow 缓冲区只包含我们想要的部分:

 (narrow-to-region(point) 
(save-excursion
(行结束-1)
(python-begin-of-statement)
(point)))

然后继续跳过sexps直到找到点,或直到 backward-sexp 停止进行:

 (let((p -1))
(while(/ = p点))
(setq p(point))
(when(look-back\\。)
;;找到要匹配的点
(setq ad-return-value(1-(current-column)))
;;停止向后搜索并报告成功(TODO)
...)
(backward-sexp)) )

这里 ad-return-value 是一个魔术变量, defadvice 用于从建议的函数返回值。丑陋但实用。



现在有两个问题。第一个是 backward-sexp 可以在某些情况下发出错误信号,所以我们最好抓住这个错误:

 (ignore-errors(backward-sexp))

其他问题是打破循环,也表明成功。我们可以通过声明一个命名的然后调用返回来同时执行。 阻止和退出是Common Lisp功能所以我们需要(require'cl)



让我们把它们放在一起:

 (require'cl)

(defadvice python-calculate-indentation(around continue-with-dot)
处理从点开始的连续行,尝试
将它们与他们继续的行中的点对齐。
(除非
(块'found-dot
(save-excursion
(行首)
(当(和(python-continuation-line-p))
(look-at\\s- * \\\。))
(保存限制
;;处理点连续行
(窄到区域(点)
(save-excursion
(行尾-1)
(python-begin-of-statement)
(point)))
;;向后移动,直到找到一个点或不能向后移动
;;
(let((p -1))
(while(/ = p(point))
(setq p(point))$
(返回\\。)
(setq ad-return-value(1-(current-column)))
t))
(ignore-errors(backward-sexp)))))))))
;;使用原始缩进。
ad-do-it))

(ad-activate'python-calculate-indentation)

我不会声称这是最好的方法,但它说明了一堆适度棘手的Emacs和Lisp功能:建议短途旅行缩小移动超过性别错误处理阻止和退出。享受!


Im an emacs newbie, I want emacs to be able to indent my code like this

egg = spam.foooooo('vivivivivivivivivi')\
          .foooooo('emacs', 'emacs', 'emacs', 'emacs')

It's not possible to do this automatically by default (without manually inserting spaces or C-c >), since emacs always indents 4 spaces (unless Im splitting multiple arguments over multiple lines).

Whats the best approach to do this?

PS: If this is a bad idea (against PEP 8 or something) please do tell me

解决方案

I agree with Aaron about the desirability of your stylistic choice, but since I also agree with him that Emacs Lisp is fun, I'll describe how you might go about implementing this.

Emacs python-mode computes the indentation of a line in the function python-calculate-indentation and the relevant section for handling continuation lines is buried deep inside the function, with no easy way to configure it.

So we have two options:

  1. Replace the whole of python-calculate-indentation with our own version (a maintenance nightmare whenever python-mode changes); or
  2. "Advise" the function python-calculate-indentation: that is, wrap it in our own function that handles the case we're interested in, and otherwise defers to the original.

Option (2) seems just about doable in this case. So let's go for it! The first thing to do is to read the manual on advice which suggests that our advice should look like this:

(defadvice python-calculate-indentation (around continuation-with-dot)
  "Handle continuation lines that start with a dot and try to
line them up with a dot in the line they continue from."
  (unless 
      (this-line-is-a-dotted-continuation-line) ; (TODO)
    ad-do-it))

Here ad-do-it is a magic token that defadvice substitutes with the original function. Coming from a Python background you might well ask, "why not do this decorator-style?" The Emacs advice mechanism is designed (1) to keep advice well separated from the original; and (2) to have multiple pieces of advice for a single function that don't need to co-operate; (3) to allow you individual control over which pieces of advice are turned on and off. You could certainly imagine writing something similar in Python.

Here's how to tell if the current line is a dotted continuation line:

(beginning-of-line)
(when (and (python-continuation-line-p)
           (looking-at "\\s-*\\."))
    ;; Yup, it's a dotted continuation line. (TODO)
    ...)

There's one problem with this: that call to beginning-of-line actually moves point to the beginning of the line. Oops. We don't want to move point around when merely calculating indention. So we better wrap this up in a call to save-excursion to make sure that point doesn't go a-wandering.

We can find the dot that we need to line up with by skipping backwards over tokens or parenthesized expressions (what Lisp calls "S-expressions" or "sexps") until either we find the dot, or else we get to the start of the statement. A good Emacs idiom for doing a search in a restricted part of the buffer is to narrow the buffer to contain just the part we want:

(narrow-to-region (point)
                  (save-excursion
                    (end-of-line -1)
                    (python-beginning-of-statement)
                    (point)))

and then keep skipping sexps backwards until we find the dot, or until backward-sexp stops making progress:

(let ((p -1))
  (while (/= p (point))
    (setq p (point))
    (when (looking-back "\\.")
      ;; Found the dot to line up with.
      (setq ad-return-value (1- (current-column)))
      ;; Stop searching backward and report success (TODO)
      ...)
    (backward-sexp)))

Here ad-return-value is a magic variable that defadvice uses for the return value from the advised function. Ugly but practical.

Now there are two problems with this. The first is that backward-sexp can signal an error in certain circumstances, so we better catch that error:

(ignore-errors (backward-sexp))

The other problem is that of breaking out of the loop and also indicating success. We can do both at once by declaring a named block and then calling return-from. Blocks and exits are Common Lisp features so we'll need to (require 'cl)

Let's put it all together:

(require 'cl)

(defadvice python-calculate-indentation (around continuation-with-dot)
  "Handle continuation lines that start with a dot and try to
line them up with a dot in the line they continue from."
  (unless 
      (block 'found-dot
        (save-excursion
          (beginning-of-line)
          (when (and (python-continuation-line-p)
                     (looking-at "\\s-*\\."))
            (save-restriction
              ;; Handle dotted continuation line.
              (narrow-to-region (point)
                                (save-excursion
                                  (end-of-line -1)
                                  (python-beginning-of-statement)
                                  (point)))
              ;; Move backwards until we find a dot or can't move backwards
              ;; any more (e.g. because we hit a containing bracket)
              (let ((p -1))
                (while (/= p (point))
                  (setq p (point))
                  (when (looking-back "\\.")
                    (setq ad-return-value (1- (current-column)))
                    (return-from 'found-dot t))
                  (ignore-errors (backward-sexp))))))))
    ;; Use original indentation.
    ad-do-it))

(ad-activate 'python-calculate-indentation)

I won't claim that this is the best way to do this, but it illustrates a bunch of moderately tricky Emacs and Lisp features: advice, excursions, narrowing, moving over sexps, error handling, blocks and exits. Enjoy!

这篇关于多线python缩进emacs的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆