为Common Lisp定制Vim的自动格式化/自动缩进的最佳方法

9
我想知道在vim中自定义Common Lisp的自动格式化/自动缩进的最佳方法。对于基本的lisp语言,如defmacro、defun、lambda、if、with-output-to-string等,在命令模式下敲入“==”可以很好地进行自动格式化(我通常这样做),但是每当定义新的语言结构(例如使用宏)时,我发现新结构的格式通常不是我想要的。例如,下面是vim如何格式化“when”(标准lisp结构)和“awhen”(常用的“when”的类比版本;不是lisp标准的一部分)。
(when 'this
  (process 'this))

(awhen 'this
       (process it))

我希望“awhen”在自动格式化时能像“when”一样。有什么办法可以做到这一点吗?
编辑:感谢Gilligan和Tamas推荐Slimv。作为测试,我下载了MacVim(需要在终端vim中使用),然后下载了slimv,并将其rsync到~/.vim中,启动MacVim并加载一个.lisp文件。
然后我启动了Lisp服务器(通过MacVim的GUI完成),它加载了我的默认Lisp可执行文件和核心文件。
由于我的核心文件已经加载了我常用的语言扩展(其中之一是awhen),因此awhen正确地格式化了出来。
我真的很喜欢这个解决方案。不需要学习如何告诉vim正确缩进特定函数,也不需要为我定义的每个语言扩展显式编写执行此操作的代码,并且每次添加新的语言构造时都要更新该代码。相反,我利用Slimv来为我进行格式化。只要那些宏已经加载到服务器会话正在使用的Lisp核心中,Slimv就可以“学习”新的语言扩展。非常棒!
我发现这对于一类特定的语言扩展非常有效。通常是使用&body关键字定义的宏。大多数情况下,这似乎都做得很好,但我使用的某些宏仍然无法正确自动格式化。尽管我认为这更有可能是由于宏的编写方式(非标准语言扩展)而不是其他原因。
因此,对于大多数情况,这个解决方案对我来说很有效,而且我不需要编写(和维护)任何东西。太棒了!

1
很高兴你喜欢 slimv。如果你发现任何缩进问题,请向我报告(我是 slimv 的作者,你可以在文档中找到我的电子邮件地址)。 - Tamas Kovacs
Slimv的答案对于那些想要更好地缩进不是Common Lisp方言的标准形式的人来说并不是很有用。 - Kaz
4个回答

7
这可能不是对你问题的直接回答,但我强烈建议你安装 slimv 插件:http://www.vim.org/scripts/script.php?script_id=2531 这是一个很棒的插件,可以将 SLIME 功能集成到 vim 中,此外,它还为 clisp&clojure 提供了改进的缩进。虽然它不会按照你想要的方式进行缩进。

2
Slimv连接到Swank服务器并且当前REPL中定义了awhen时,也会正确缩进。缩进基于从Swank服务器获取的运行时信息,就像在Emacs中使用Slime一样。 - Tamas Kovacs
啊,更好的是 - 所以长话短说,@claytonstanely:你应该安装slimv :) - gilligan

5

对于那些寻找这个主题但不想运行Slimv的人,因为他们不使用Common Lisp或其他原因,这里是消息。

Vim的Lisp缩进不像其他语言的缩进方式,它有一个特殊的“Lisp模式”。该模式可以通过以下方式打开:

:set lisp

这是为.lisp文件自动完成的操作。Lisp模式并不是Vim的发明,经典的Vi实现在:set lisp中开启了Lisp模式(遗憾的是它没有被POSIX描述)。

Vim的Lisp模式有一个简单的机制来识别需要运算符风格缩进的形式:即,有一个名为lispwords的参数,其中包含逗号分隔的标识符列表。

你可以证明这就是使用的标识符列表,即使你正在编辑带有语法高亮和所有内容的Common Lisp .lisp文件。只需执行:set listwords[TAB]并编辑列表以删除其中的某些内容,比如defun。然后尝试重新缩进defun:您将看到函数样式缩进而不是运算符样式。

Common Lisp的语法高亮支持与Lisp模式的lispwords参数分开;它有其自己的标识符列表。例如,在Vim 7.3中,如果您输入以下内容:

(symbol-macrolet ((foo bar))
                 you get indented out to here!)

尽管“symbol-macrolet”被识别和着色,但仍然存在问题。为什么?这是因为“symbol-macrolet”未出现在相当有限的“lispwords”列表中,而它确实出现在“lisp.vim”语法突出显示定义文件中。
总之,您可以拼凑一些脚本,扫描您的“。lisp”文件目录以获取宏,并生成一个“set lispwords = ...”命令,该命令放置在目录“.vimrc”中。
或者,如果您正在使用自定义Lisp方言,则可以在加载时使其Vim语法突出显示文件自定义“lispwords”。
这里存在一个实现疏忽:选项“lispwords”没有本地值;您不能使用“setlocal lispwords ...”为其提供缓冲区特定值。换句话说,在我使用的Ubuntu下的Vim 7.3中,似乎您无法打开两个或更多包含具有不同缩进标识符的Lisp不同方言的缓冲区。默认的“lispwords”内容包含一些Lisp和Scheme符号,以尝试成为一种“一种大小几乎适合所有”的解决方案。

1
如果您的文件类型是'lisp',那么我认为您需要在'/ vim7x / indent'目录中的'lisp.vim'文件中添加缩进规则以处理您的特定情况。您可以在:h indent-expr:h indentexpr 中的帮助中找到更多信息。
有人可能能够给您提供更好的建议,但我认为默认的'lisp.vim'缩进文件基本上什么都不做,因为使用内置函数'lispindent()'来获取缩进值。您需要:
(1)将用于获取缩进值(即indentexpr)的函数设置为您自己的indent / lisp.vim文件中的函数,例如GetLispIndent()。 (2)在您的GetLispIndent()函数中,除了您的特殊情况外,您将使用lispindent()获取缩进值并返回所有行。请参阅其他语言的缩进文件并阅读文档,以了解indentexpr的工作原理,例如java.vim。

indent 目录中的 lisp.vim 文件几乎没有任何内容。这是因为 Lisp 缩进是由特殊的“Lisp 模式”执行的,这可以追溯到经典 Vi 的一个特性。 - Kaz

1

@Kaz的回答完全正确,但是他们没有完全回答原始问题。 Vim的lispwords配置字符串是一个逗号分隔的单词列表; 当在S表达式的开头找到lispwords中的任何单词时,Vim将更改S表达式缩进的方式。换句话说,它定义了OP所指的“标准Lisp构造”。 如果您使用:set lispwords命令查看当前的lispwords配置,则会看到包含“when”,但不包含“awhen”,因此会产生以下缩进:

(when 'this
  (process 'this))

(awhen 'this
       (process it))

要解决这个问题,只需在配置文件中的任何位置添加 "awhen" 到配置字符串中,像这样:
set lispwords+=awhen,

尾随逗号并不是必须的,但默认值包括它,并且在你或其他插件修改器的情况下可能是明智的。这将把原始格式转换为以下内容:
(when 'this
  (process 'this))

(awhen 'this
  (process it))

(在我的Vim 9.0上进行了测试)

请注意,正如@Kaz所指出的那样,此配置字符串是通用的,因此如果您有不同方言的lisp,则它们的缩进都将受到此设置的控制。 Vim在自动检测lisp方面非常出色,但如果它无法识别您的文件类型或方言,则可能需要使用:set lisp


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