Box style comments with yasnippet

I want to write a yasnippet template that will allow me to add a license header to the script buffer in Emacs. For example, this but improved a bit:

  • The header should include data for each user, such as the date name and email address of the copyright holder, which can be obtained using the built-in elisp extension from yasnippet.
  • The header should be commented out by the syntax depending on the programming mode in which the file is located. There is already the essence of the fragment that does it all . This basically means embedding (comment-region (point-min) (point)) at the end of your fragment.
  • Now I want to change the comment style on the field . See the emacs documentation for the comment-style variable, or if you want to see what a window-style comment looks like, just call Mx comment-box in the active region: it calls comment-region with the correct parameters.

The first approach for this is to set the style by changing the end of the previous snippet to:

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

Unfortunately, the padding is screwed, and my box is not rectangular . If I start with a 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)))` 

Extending this snippet "breaks the window" (I am debugging this snippet with ocaml comment syntax, not that it matters):

 (**************************************************************) (* Copyright (c) 2010 *) (* All rights reserved. *) (* *) (* Redistribution and use in source and binary forms, with or *) (* without modification, are permitted *) (**************************************************************) 
  • At first I thought that the second line was indented based on the size of the embedded code with the preliminary extension, but in this case it should make the final *) this line too soon 25, not 4.
  • If he is dismissed on the basis of the lack of text present at the point of implementation, the final *) must arrive at 4 spaces too late, and not too soon.
  • Finally, I donโ€™t understand what happens to the last line, in which there is no built-in code extension. Usually I have no problem getting the square comment field from the paragraph with the short last line (either using the comment-box or the elisp function in the first comment block of this question.

I tried to make a comment after expanding the fragment in order to avoid the side effect by adding it to yas/after-exit-snippet-hook , replacing the Last function of the fragment above:

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

But it did not help. Even if that were the case, it would leave me with an extension that commented on all the fragments that I would like to use in this buffer, which 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 fragment, but that didnโ€™t change anything. Any ideas on how to get a rectangle


Edit: We have a very good answer, as well as the proposed fix (kudos and thanks, Seiji!), But the question remains about how to adapt it to the case where you would need to reuse the field, for example, reusing $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 this case, the template mechanism copies the value (of variable length) obtained for the field $1 , namely 2011 , to the last line when expanding the template (after the indent), indicating the comment line of 2 characters is too wide. It is difficult to predict when writing a pattern that 4 characters should be deleted on this line. Perhaps the reuse of fields and the right margins are too many to require at the same time. Does anyone see a way to do this though?

+6
emacs elisp code-snippets
source share
2 answers

Changing your fragment on this 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 ("... allowed") and the emacs lisp inline code.

Regarding the second line, I will first explain why this happens and then offer a (ugly) fix. When your fragment is inserted into a file, lisp inline blocks are sequentially evaluated from the beginning of the buffer to the end. This means that (nth 5 (decode-time)) was replaced with 2011 when the next block is evaluated (comment-region ...) .

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

 Copyright (c) ${1:2011} 

So comment-region puts enough spaces for this line. The template engine then converts ${1:2011} to 2011 , and this conversion shortens the string by 5 characters. This explains the premature appearance *) 5 characters in the second line.

One way to fix this situation is to return 5 white spaces after evaluating comment-region --- Something along the 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)))`` (replace-string "@" " " nil (point-min) (point))`$0 
+5
source share

This may come in handy:

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

It uses a mirror with a function to create positioning gaps. So for you, this may 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 this seems deprecated. (oh, and I wanted to filter the text myself, the comment area that you already tried is smarter. Try the indent area?)

+1
source share

All Articles