2

I have the habit when creating larger projects to make files called skeleton.typ with all the standard boilerplate for a file of that type (e.g. copyright notices, licenses, the standard html/head/title/body/etc. tags for a web page, #includes for a .c, etc.) and places to fill in marked. Then when I create a new file with C-x C-f and get a blank page, I C-x C-i the relevant skeleton file. And, if one doesn't exist in that dir when in a deep part of a project, it's relatively easy to do M-b over the sk I tried to complete and keep trying M-backspace TAB until it finds one, or the top of the project is reached (in which case it's time to create one, starting from a personal dir of skeleton skeleton files).

I've been thinking about automating this for a while (by writing something to go on find-file-not-found-functions). Then I saw this question and it inspired me to action. I realized that this seemed such an obviously useful thing that I should see if I could just find an existing piece of code I can use. That might well find code with added features I like but wouldn't have written in my own version. It would also save me the time of actually writing it (and the search, etc. was a completely effective "avoidance mechanism" to put off writing it for another day, at least I recognize them after-the-fact now, hopefully I'll eventually spot them ahead of time and avoid them :-).

Having spent a couple of hours using emacs' built in help to look at things that almost do what I want, looking at SE and finding Q&A's that are close, and collating all these things for this Q; I figured the next step before actually buckling down to write the code, is to ask this august assemblage for references to existing things that might help (probably inspired slightly by the fact that the trigger was here). So, my question is: does anyone have or know of code that would do this? Unlike other questions asking about slight variations, I'm not expecting anyone else to write the whole thing. If no useful pointers arise, I'll write it and then answer this question.

Things I've looked at:

  • This question is actually the one that inspired me to start thinking about this again. But the existing answer is too simple and specific to that question. If I'd already written the tool I'm thinking of, it might have made a good answer as well, and after I find/write it, I may think about adding it.

  • auto-insert is really almost the right thing, but it searches in the wrong way. With this each user would have a unique set of templates. I really need this the other way. For my paradigm the template is a per-project thing (for example, every C project has different standard #includes possibly different in different parts of the project, and as a consultant, the copyright may need to be to the client), and that's why my search in the local dir and parents to root of project. If nobody comes up with a better resource, I may read through auto-insert and either make a variant that does it the way I want, or try adding some options to it to do that. I did realize, however, that auto-insert might be just the right thing for the skeleton skeleton files.

  • skeleton-insert seems like it might be a great part of a really elaborate solution. But, it needs to be primed with a large complex LISP expression (which would then be a per-user setting, see previous bullet on that) and does not seem to be suited to the template file style I use. I might be able to leverage this by having the file-not-found hook look for a file of elisp that sets this locally, but that seems like it'd still be 50% of the work solving only 25% of the problem. And then I need to write the hairy lisp structure rather than just creating a file that looks like what's wanted.

  • I also did searches around https://emacs.stackexchange.com/ for all the relevant keywords I could think of and didn't find anything exactly right. I kept coming across the question that inspired me, but none of the others were actually any more relevant. I have tried to mention any keyword that seemed relevant in this question so future searchers can find this.

So, that's the relevant background. If I write something myself, here are what I'll target as features (and some constraints I still haven't figured out):

  • a function to go on find-file-not-found-functions. It does an insert to get the relevant template (or skeleton) file, searching up the tree to find it.

  • There should (probably) be some way to limit the search, although in my case the top of the project is usually only a couple of layers down from /, so it wouldn't be painful to search all the way to the top.

  • Maybe use skeleton-insert to do the interactive fill-in or leverage some of its internals. If not, I'll probably just continue my current convention where three square brackets are used to mark fill ins, with text inside to say what. And have the function find relevant entries.

MAP
  • 582
  • 4
  • 11
  • Did you try pairing `auto-insert-mode` with directory-local variables to configure it on a per-project basis? – phils May 21 '17 at 06:49

2 Answers2

1

Library header2.el is generally for file headers, which use only code comments (see automatic file headers).

But it really is about adding and updating (including automatically) boilerplate text that you define. That text need not be comment text. And it can be mode-specific or be applied conditionally in any other way.

Drew
  • 75,699
  • 9
  • 109
  • 225
0

auto-insert is really almost the right thing, but it searches in the wrong way. With this each user would have a unique set of templates. I really need this the other way. For my paradigm the template is a per-project thing

If you pair auto-insert-mode with directory-local variables, you can configure it on a per-project basis.

Due to the constraints of the auto-insert variables we need to be a bit tricky and eval the values we need, but the following is an example .dir-locals.el file for a project which overrides the C/C++ templates, using a template directory named ".templates" in the project root. In this instance the file .templates/c-header will be inserted in relevant files, and a similar rule for C/C++ program files.

Obviously you could add any number of auto-insert-alist overrides to this .dir-locals.el file, and use dir-local features like sub-directory-specific vars if you needed to vary the behaviour in different places, or simply place different .templates directories in different parts of the project.

((nil . ((eval . (let ((dir (file-name-as-directory ".templates")))
                   (setq-local auto-insert-directory
                               (expand-file-name
                                dir (locate-dominating-file
                                     default-directory dir)))))
         (eval . (setq-local auto-insert-alist
                             (append '((("\\.\\([Hh]\\|hh\\|hpp\\|hxx\\|h\\+\\+\\)\\'"
                                         . "C / C++ header")
                                        . "c-header")
                                       (("\\.\\([Cc]\\|cc\\|cpp\\|cxx\\|c\\+\\+\\)\\'"
                                         . "C / C++ program")
                                        . "c-program"))
                                     auto-insert-alist)))
         )
      ))
phils
  • 48,657
  • 3
  • 76
  • 115