4

这个月我花了一些时间与 Emacs Lisp 进行斗争,试图获得更好地满足我需求的自动缩进。令人惊讶的是,大多数缩进代码是多么低级。我只看到了很少的抽象,例如

  • 搜索不在字符串或注释中的正则表达式的第一个实例

我怀疑还有更多有用的抽象可以帮助编写更易于理解和修改的缩进代码。(甚至我引用的抽象也可以改进为“重复将此函数应用于这些参数,直到函数返回 nil 或点不在字符串或注释中”。)

我正在使用 emacs,但我也用 vim 标记了这个问题,因为我会从任何地方汲取好主意。

如果你想编写干净的、设计良好的、模块化的、自定义的缩进函数,你会使用什么抽象? (我也很高兴看到指向您认为使用良好抽象或设计良好的代码的指针。)

4

3 回答 3

4

听起来您正在寻找更高级别的东西,但是 macs 23 带有SMIE,它旨在一般地解决这个问题。但它适用于主要模式的开发人员,而不是修改现有的缩进行为。

编辑:主要的抽象似乎是

  • 一个相当弱的运算符优先级解析器,辅以一个肮脏的技巧词法分析器

  • 每个标记都有一个“虚拟缩进”的概念,如果开始一行,它就会出现在这个位置

  • 每个标记都有一个“父”,它是封闭句法结构的开始。

进入成本似乎相当大,并且该软件附有此免责声明:

在实践中,[the] 默认缩进样式可能不够好。您将需要在许多不同的情况下对其进行调整。

(编辑结束)


你说的话:

搜索不在字符串或注释中的正则表达式的第一个实例

很容易通过调用syntax-ppssand来完成re-search-backward

于 2012-07-07T12:19:11.197 回答
2

以编程方式在缓冲区中导航的不错的语言无关抽象是 sexp 和语法表:如果您的模式的语法表构建得很好,您可以使用forward-sexpand移动scan-sexps。我会说只在这些不起作用的情况下使用正则表达式,即使你最终确实使用了它们提供的值re-search-forward(见它的BOUND论点)。

也可以syntax-ppss用来轻松辨别是否在注释或字符串文字中,或处理字符转义情况。请参阅 Emacs Lisp 信息节点语法表

诚然,sexp 可能对缩进 Lisp 很有效,因为一切都是一个列表,并且可以很容易地(syntax-ppss)提出诸如“深度是多少级(point)?”之类的问题。使用像 Ruby 这样的块分隔符beginend你会进入疯狂的正则表达式领域。

因此,要(syntax-ppss)在其他语言中获得类似优点,您需要专门为它编写一个解析器。例如ruby-mode,实现了一个解析器,并查看nxml-mode了一个令人难以置信的例子。

另请注意,您可以做很多事情,with-syntax-table因为它允许您暂时从不同的角度查看缓冲区。它不是缩进,但考虑一下http://github.com/joaotavora/autopair中的这个例子,它允许我忽略一些括号类型

(defvar autopair-empty-syntax-table
  (let ((empty (make-syntax-table)))
    (dotimes (char 256)
      (let ((syntax-entry (aref empty char)))
        (when (and (consp syntax-entry)
                   (or (eq (car (string-to-syntax "("))
                           (car syntax-entry))
                       (eq (car (string-to-syntax ")"))
                           (car syntax-entry))))
          (modify-syntax-entry char "w" empty))))
    empty)
  "A syntax table no \"(\" or \")\" syntaxes")
 
(defun autopair-just-for-delim-syntax-table (delim)
  "A syntax table that has \"parenthesis\" syntax just for DELIM."
  (let* ((syntax-entry (aref (syntax-table) delim))
         (other-syntax-entry (and syntax-entry
                                  (cdr syntax-entry)
                                  (aref (syntax-table) (cdr syntax-entry)))))
    (when (consp other-syntax-entry)
      (let ((retval (make-syntax-table autopair-empty-syntax-table)))
        (aset retval delim syntax-entry)
        (aset retval (cdr syntax-entry) other-syntax-entry)
        retval))))

现在,在混合[],(){}情况的缓冲区中,要求(syntax-ppss)(with-syntax-table (autopair-just-for-delim-syntax-table ?{ ) (syntax-ppss))后者只计算的地方是完全不同的{}。我不知道您要缩进哪种语言,但这可以帮助您在缩进 C 块方面做合理的工作,例如。

于 2012-07-08T15:14:56.483 回答
1

我知道一些有用的内置原语:

  • 缩进到
  • 当前缩进

据我所知,有用的原语不是 emacs 的一部分:

  • 转到上一个非空白行
  • 行匹配-p(正则表达式)
  • inside-p(开始字符串关闭字符串)

随意完成这个列表 - 我没有找到很多关于 emacs 缩进的资源。

于 2012-07-07T20:48:50.190 回答