【问题标题】:What are good *abstractions* for writing custom functions to autoindent code?为自动缩进代码编写自定义函数有什么好的*抽象*?
【发布时间】:2012-07-07 11:20:25
【问题描述】:

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

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

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

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

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

【问题讨论】:

    标签: emacs elisp indentation vim


    【解决方案1】:

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

    编辑:主要的抽象似乎是

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

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

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

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

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

    (编辑结束)


    你说什么:

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

    通过调用syntax-ppssre-search-backward 可以轻松完成。

    【讨论】:

      【解决方案2】:

      以编程方式在缓冲区中导航的很好的与语言无关的抽象是 sexp 和语法表:如果您的模式的语法表构建良好,您可以使用 forward-sexpscan-sexps 移动。我会说只在这些不起作用时才使用正则表达式,如果你最终确实有re-search-forward(请参阅它的BOUND 参数),即使那样使用它们提供的值。

      还可以使用syntax-ppss 轻松辨别是否在 cmets 或字符串文字中,或处理字符转义情况。查看 Emacs Lisp 信息节点Syntax Tables

      当然,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))))
      

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

      【讨论】:

      • 我的模式的语法表可以理解各种括号、字符串、cmets。它对控制缩进的任何关键字一无所知。此外,语法表还不够强大,无法知道有两种“单词”(字母数字或符号)。所以我认为我对事情的理解不够好,无法跟进你的建议。无论如何+1 :-)
      • 我基本上是说你必须编写自己的解析器,但是语法表 syntax-ppssscan-sexps 有很大帮助。还编辑了答案以阐明with-syntax-table 的用处
      【解决方案3】:

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

      • 缩进一行
      • 当前缩进

      据我所知,有用的原语不属于 emacs:

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

      请随意填写此列表 - 我没有找到很多关于 emacs 缩进的资源。

      【讨论】:

      • 我正在寻找 更高抽象级别的想法。
      • 我不确定你是否能获得更高的水平,因为与语言无关。我考虑过嵌套级别,但这通常可以从上一行的缩进和内容中推断出来
      • 如果您询问一般如何进行缩进,您可能需要确定多个上下文(例如块体、参数列表、字符串、注释等),一个确定哪个上下文的函数apply 和函数将为它们中的每一个进行缩进。不要急于将现有代码视为低级或肮脏的技巧。您是否希望每次按 TAB 时都解析和验证整个文件?可能不会。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-26
      • 1970-01-01
      • 2023-02-10
      • 1970-01-01
      • 2019-03-14
      • 2013-08-28
      相关资源
      最近更新 更多