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:
- 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.
- 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. - 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 callM-x comment-box
on an active region: It callscomment-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 ?
point-at-eol
suggestion, it completely fixed the issue of the last line. Great explanation, thanks. Your fix works, but it is painful to generalize to many fields on a line (where you have to manually count the boilerplate for each template) and impossible to extend to a reuse of the field $1 elsewhere in the template (where you would have to remove as many whitespaces as the evaluation of the embedded lisp created). I'll wait for a little while, and if no one comes up with a solution for that, I'll "accept" your answer. – Caracara