使用 yasnippet 进行框式注释

发布于 2024-10-09 21:47:57 字数 3537 浏览 0 评论 0原文

我希望编写一个 yasnippet 模板,该模板允许我添加许可证标头Emacs 中的脚本缓冲区。有点像 this,但有一点改进:

  1. 标头需要包含每个用户的数据,例如作为版权所有者的日期姓名和电子邮件, 可以通过嵌入式 elisp 扩展获得 来自 yasnippet。
  2. 需要根据文件当前所处的编程模式使用语法对标头进行注释。已经有 一个要点完成这一切的代码片段。基本上,它相当于在代码片段的末尾嵌入 (comment-region (point-min) (point))
  3. 现在,我想将评论样式更改为方框。请参阅 emacs 文档以了解 comment-style 变量,或者,如果您想查看框式注释的外观,只需在活动的对象上调用 Mx comment-box区域:它使用正确的选项调用 comment-region

第一种方法是通过将上一个代码片段的末尾修改为来设置样式:

(let ((comment-style 'box))
            (comment-region (point-min) (point)))

不幸的是,缩进搞砸了,并且我的盒子不是矩形。如果我从片段开始:

Copyright (c) ${1:`(nth 5 (decode-time))`}
All rights reserved.

Redistribution and use in source and binary forms, with or
without modification, are permitted`
      (let ((comment-style 'box))
            (comment-region (point-min) (point)))`

该片段的扩展“打破了盒子”(我正在使用 ocaml 注释语法调试此片段,但这并不重要):

(**************************************************************)
(* Copyright (c) 2010                                    *)
(* All rights reserved.                                       *)
(*                                                            *)
(* Redistribution and use in source and binary forms, with or *)
(* without modification, are permitted     *)
(**************************************************************)
  • 起初我认为第二行是根据预扩展嵌入代码,但在这种情况下,它应该使该行的最后一个 *) 过早出现 25 个空格,而不是 4 个。
  • 如果它基于 no 缩进如果文本出现在嵌入点,则最终的*) 应该到达 4 个空格,晚了,而不是很快
  • 最后,我不明白最后一行发生了什么,其中没有嵌入代码扩展:通常我从带有短句的段落中获取方形注释框没有任何问题最后一行(使用 comment-box 或本问题第一个注释块中的 elisp 函数。

我尝试在代码片段扩展后进行注释,以避免任何副作用,通过添加它到 yas/after-exit-snippet-hook,将上面代码片段的最后一个函数替换为:

(add-hook 'yas/after-exit-snippet-hook
      (let ((comment-style 'box))
            (comment-region (point-min) (point))) nil t)

但这也没有帮助,它会给我留下一个扩展钩子,它可以注释所有我想在该缓冲区中使用的片段,我当然不希望

添加一些我试图设置的 东西。 /indent-line 到 fixed,通过

# expand-env: ((yas/indent-line 'fixed))

在我的代码片段的开头添加,但这并没有改变任何东西。关于如何获得矩形盒子有什么想法吗?


编辑:我们有一个非常好的答案,以及提议的修复,(荣誉和感谢,Seiji!)但仍然存在一个问题,即如何使其适应想要重用字段的情况,例如重用 $1 in:

Copyright (c) ${1:`(nth 5 (decode-time))`}
All rights reserved.

Redistribution and use in $1, in source and binary forms
`(let ((comment-style 'box))
        (comment-region (point-min) (point-at-eol 0)))`

在这种情况下,模板引擎将在模板扩展时将字段 $1 获得的(可变长度)值(即 2011)复制到最后一行(缩进后),注释行 2 个字符太宽。在编写模板时很难预测应该删除这一行的4个字符。也许字段重用和正确缩进同时要求太多。有没有人看到一种方法可以做到这一点?

I'm looking to write a yasnippet template that would allow me to add a license header to a script buffer in Emacs. Kinda like this, but a bit improved:

  1. The header needs to include per-user data, such as the date name and email of the copyright holder,
    which can be obtained with embedded elisp expansion from yasnippet.
  2. The header needs to be commented with a syntax depending on the programming mode the file is currently in. There's already a gist of a snippet that does all that. Basically it amounts to embedding (comment-region (point-min) (point)) at the end of your snippet.
  3. Now, I want to change the comment-style to a box. See the emacs documentation for the comment-style variable, or, if you want to see what a box-style comment looks like, just call M-x comment-box on an active region: It calls comment-region with the right options.

A first approach to do that is to setup the style by modifying the end of the previous snippet to:

(let ((comment-style 'box))
            (comment-region (point-min) (point)))

Unfortunately, the indentation gets screwed up, and my box isn't rectangular. If I start from snippet:

Copyright (c) ${1:`(nth 5 (decode-time))`}
All rights reserved.

Redistribution and use in source and binary forms, with or
without modification, are permitted`
      (let ((comment-style 'box))
            (comment-region (point-min) (point)))`

The expansion of that snippet "breaks the box" (I'm debugging this snippet with ocaml comment syntax, not that it should matter):

(**************************************************************)
(* Copyright (c) 2010                                    *)
(* All rights reserved.                                       *)
(*                                                            *)
(* Redistribution and use in source and binary forms, with or *)
(* without modification, are permitted     *)
(**************************************************************)
  • At first I thought the second line was indented based on the size of the pre-expansion embedded code, but in that case, it should make the final *) of that line come 25 spaces too soon, not 4.
  • If it indented based on no text being present at embedding point, the final *) should arrive 4 spaces too late, not too soon.
  • Finally, I don't understand what's going on with the last line, in which there is no embedded code expansion: Usually I don't have any problem getting a square comment box from a paragraph with a short last line (either using comment-box, or the elisp function in the 1st comment-block of this question.

I tried making the comment happen after snippet expansion, to avoid any side-effect, by adding it to yas/after-exit-snippet-hook, replacing the last function of the snippet above with:

(add-hook 'yas/after-exit-snippet-hook
      (let ((comment-style 'box))
            (comment-region (point-min) (point))) nil t)

But that didn't help. Even if it did, it would leave me with an expansion hook that would comment all the snippets I would want to use in that buffer, something I certainly do not want.

I should also add that I tried to set yas/indent-line to fixed, by adding

# expand-env: ((yas/indent-line 'fixed))

at the beginning of my snippet but that didn't change anything. Any ideas on how to get a rectangular box ?


Edit : We have a very nice answer, along with a proposed fix, (kudos & thanks, Seiji !) but a question remains on how to adapt it to the case where one would want to reuse a field, say like the reuse of $1 in:

Copyright (c) ${1:`(nth 5 (decode-time))`}
All rights reserved.

Redistribution and use in $1, in source and binary forms
`(let ((comment-style 'box))
        (comment-region (point-min) (point-at-eol 0)))`

In that case, the template engine copies the (variable-length) value obtained for the field $1, namely 2011, to the last line, at template expansion (after indentation), giving a comment line 2 characters too wide. It becomes hard to predict when writing the template that one should remove 4 characters at this line. Perhaps field reuse and correct indentation are too much to ask for simultaneously. Does any one see a way to do this, though ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

紙鸢 2024-10-16 21:47:57

将您的代码片段更改为此代码可以修复最后一行。

Copyright (c) ${1:`(nth 5 (decode-time))`}
All rights reserved.

Redistribution and use in source and binary forms, with or
without modification, are permitted
`(let ((comment-style 'box))(comment-region (point-min) (point-at-eol 0)))`

请注意,许可证(“...被允许”)和嵌入的 emacs lisp 代码之间有一个换行符。

至于第二行,我将首先解释为什么会发生这种情况,然后提供(丑陋的)修复。当您的代码片段插入到文件中时,嵌入的 Lisp 块将从缓冲区的开头到结尾按顺序求值。这在您的代码片段中意味着当下一个块 (comment-region .. .),被评估。

因此,comment-region 将第二行视为

Copyright (c) ${1:2011}

So, comment-region 为此字符串添加了足够的空格。然后,模板引擎将 ${1:2011} 转换为 2011,此转换将字符串缩短 5 个字符。这解释了第二行中过早出现 5 个字符的 *)

解决这种情况的一种方法是在评估 comment-region 后放回 5 个空格 --- 类似于:

Copyright (c) ${1:`(nth 5 (decode-time))`} @
All rights reserved.

Redistribution and use in source and binary forms, with or
without modification, are permitted.
`(let ((comment-style 'box))(comment-region (point-min) (point-at-eol 0)))``
(replace-string "@" "      " nil (point-min) (point))`$0

Changing your snippet to this one fixes the last line.

Copyright (c) ${1:`(nth 5 (decode-time))`}
All rights reserved.

Redistribution and use in source and binary forms, with or
without modification, are permitted
`(let ((comment-style 'box))(comment-region (point-min) (point-at-eol 0)))`

Note that there is a line break between the license ("... are permitted") and embedded emacs lisp code.

As for the second line, I'll first explain why this occurs and then offer an (ugly) fix. When your snippet is inserted into a file, embedded blocks of lisp are sequentially evaluated from the beginning of buffer to the end. What this means in your snippet is that (nth 5 (decode-time)) has been replaced by 2011 when the next block, (comment-region ...), is evaluated.

As a result, comment-region sees the second line as

Copyright (c) ${1:2011}

So, comment-region puts enough white spaces for this string. Then, the template engine transforms ${1:2011} into 2011, and this transformation shortens the string by 5 characters. This explains the premature appearance of *) by 5 characters in the second line.

One way to fix this situation is putting 5 white spaces back after comment-region is evaluated --- Something along the line of:

Copyright (c) ${1:`(nth 5 (decode-time))`} @
All rights reserved.

Redistribution and use in source and binary forms, with or
without modification, are permitted.
`(let ((comment-style 'box))(comment-region (point-min) (point-at-eol 0)))``
(replace-string "@" "      " nil (point-min) (point))`$0
倾城花音 2024-10-16 21:47:57

这可能对您有用:

# -*- mode: snippet -*-
# name: param
# key:  param
# --
m.parameter :${1:arg},${1:$(make-string (- 14 (string-width text)) ?\ 
                         )}:${2:type}
gt;

它使用带有功能的镜子来创建定位空白。因此,对您来说,这可能意味着这样的事情:

(* Copyright (c) ${1:2011}${1:$(make-string (- 72 (string-width text)) ?\ )} *)
(* ${2}${2:$(make-string (- 72 (string-width text)))}*)

另一种选择可能是使用 yas/after-exit-snippet-hook,但这似乎已被弃用。 (哦,我的意思是自己过滤文本,你已经尝试过的注释区域更聪明。尝试缩进区域?)

This might be of some use to you:

# -*- mode: snippet -*-
# name: param
# key:  param
# --
m.parameter :${1:arg},${1:$(make-string (- 14 (string-width text)) ?\ 
                         )}:${2:type}
gt;

It uses a mirror with a function to create the positioning whitespace. So, for you, this might mean something like this:

(* Copyright (c) ${1:2011}${1:$(make-string (- 72 (string-width text)) ?\ )} *)
(* ${2}${2:$(make-string (- 72 (string-width text)))}*)

Another option might be to use yas/after-exit-snippet-hook, but that seems to be deprecated. (oh, and I meant to filter the text yourself, the comment-region you already tried is cleverer. Try indent-region?)

尴尬癌患者 2024-10-16 21:47:57

这对我有用:

# -*- mode: snippet -*-
# name: box comment block
# key: bbox
# expand-env: ((yas-after-exit-snippet-hook (lambda () (if (buffer-substring yas-snippet-beg yas-snippet-end) (comment-box yas-snippet-beg yas-snippet-end 1)))))
# --
Copyright (c) ${1:`(nth 5 (decode-time))`}
All rights reserved.

Redistribution and use in source and binary forms, with or
without modification, are permitted
$0

我参考了这个问题中的信息在特定片段之后运行函数

This worked for me:

# -*- mode: snippet -*-
# name: box comment block
# key: bbox
# expand-env: ((yas-after-exit-snippet-hook (lambda () (if (buffer-substring yas-snippet-beg yas-snippet-end) (comment-box yas-snippet-beg yas-snippet-end 1)))))
# --
Copyright (c) ${1:`(nth 5 (decode-time))`}
All rights reserved.

Redistribution and use in source and binary forms, with or
without modification, are permitted
$0

I referred to info in this question Run function after specific snippet

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文