4

My setup

GNU Emacs GUI (version 24.4.51.1 (x86_64-w64-mingw32) compiled from Harroogan Emacs.) Package header2.el, which I use a lot. If you need more detail about header2, see the emacs wiki . It's a great package, I really recommend it.

Situation:

header2.el lets you define file headers for different types of file (C, shell, EmacsLisp, and so on). You can automatically insert a header when you open a new file buffer, and it modifies them whenever you're saving.

I made a code, that focused only on inserting the version number and incrementing it every time whenever you're saving the file.

The code below inserts the number 0 of version, when you're creating a new file.

 (defsubst my/header-update-count ()
   "Insert a count of the number of times the file has been saved."
   (insert (concat comment-start " Version     : 0\n")))

 (setq make-header-hook '(my/header-update-count))  

Configuring the update of the header whenever you're saving the file.

 (defvar file-header-update-alist ()
   "Used by `update-file-header' to know what to do in a file.
 Is a list of sets of cons cells where the car is a regexp string and the cdr is
 the function to call if the string is found near the start of the file.")

 (defvar header-prefix-string ""
   "Mode-specific comment prefix string for use in headers.")

 (defun register-file-header-action (regexp function-to-call)
   "Record FUNCTION-TO-CALL as the action to take if REGEXP is found
 in the file header when a file is written.  The function will be called
 with the cursor located just after the matched REGEXP.  Calling this twice
 with the same args overwrites the previous FUNCTION-TO-CALL."
   (let ((ml  (assoc regexp file-header-update-alist)))
     (if ml
         (setcdr ml function-to-call);; overwrite old defn
       ;; This entry is new to us.  Add to the master alist
       (setq file-header-update-alist  (cons (cons regexp function-to-call)
                                             file-header-update-alist)))))


 (register-file-header-action "Version   [ \t]*: " 'update-write-count) 
 (when (boundp 'libreq-file-header)
   (register-file-header-action libreq-file-header 'update-lib-requires))

;; To have Emacs update file headers automatically whenever you save a
;; file, put this in your init file (~/.emacs):
(autoload 'auto-update-file-header "header2")
(add-hook 'write-file-hooks 'auto-update-file-header)

;; To have Emacs add a file header whenever you create a new file in
;; some mode, put this in your init file (~/.emacs):
(autoload 'auto-make-header "header2")
(add-hook 'emacs-lisp-mode-hook 'auto-make-header)

Action:

Now the version numbering works like your version is 0. When you're saving, it increments it with 1. So if your header have the version 5, when saving, it will change to version 6. I would like to change the way of version numbering from one number to number dot number. For example, like when you're saving, it will update from 0.1 to 0.2 or from 3.12 to 3.13.

So in order to modify this, I changed the version numbering with adding a dot and number:

(insert (concat comment-start " Version     : 0.0\n"))

When I save the buffer, it updates from 0.0 to 1.0 to 2.0, which is not the intention.

In my setup the following line uses regexp to update the version numbering

(register-file-header-action "Version   [ \t]*: " 'update-write-count)

When I look into the source of the package header2.el, I noticed it uses regexp.

(register-file-header-action "\$VERSION[ \t]*=[ \t]*\"\\([0-9]+\\.\\)+"
                                   'update-write-count)

When I modified the regexp, it didn't gives me the desired behaviour. Notice that adding a file header and updating it are not done by a minor mode. They are done on hooks. Adding a file header is done, for example, on a major-mode hook, and updating is done, for example, on write-file-hooks. It's a fairly not a difficult modification, but I couldn't even figure it out.

Any suggestion would be appreciated.

8
  • @kaushalmodi, any suggestion? You're more experienced with header2 than me.
    – ReneFroger
    Jul 5, 2015 at 21:03
  • 1
    When do you expect the major version number to increment? If you want "3.9" to increment to "3.10", when should the major version increment from 3 to 4? Jul 8, 2015 at 16:50
  • @kaushalmodi Never. Even when the major version will change, I will manually change it. For my projects, I expect it will rarely change the major version. So the most will stay in 1.xx version. Some will have 2.xx version. When the major version changes, I will change the number before the dot. So it's all about the numbers behind the dot, that are incremented after saving hook, like header2 does already with the version numbers.
    – ReneFroger
    Jul 8, 2015 at 18:33
  • 1
    In that case, based on Drew's suggestion, you can use this snippet as reference to write your own my-update-version-count: (let* ((v-list (version-to-list "3.9")) (v-major (nth 0 v-list)) (v-minor (nth 1 v-list))) (format "%0d.%0d" v-major (1+ v-minor))) This snippet returns "3.10". Jul 8, 2015 at 18:41
  • 1
    That's correct, my snippet was a test snippet.. instead of "3.9", you will use the version string as input. And that's why I suggested using that snippet as a reference to write your own my-update-version-count. The crux of the snippet is to use version-to-list and to do 1+ only on v-minor. Jul 8, 2015 at 18:52

2 Answers 2

1

Based on the conversation in the comments to the question and suggestion by @Drew, below solution should work for you.

(register-file-header-action "Version[ \t]*: " 'my-update-version-count)

(defun my-update-version-count ()
  (let* ((v-str  (delete-and-forget-line))
         ;; `version-to-list' will also check if the version string is valid
         (v-list (version-to-list v-str)) 
         (v-major (nth 0 v-list))
         (v-minor (nth 1 v-list)))
    (insert (format "%0d.%0d" v-major (1+ v-minor)))))

I tested it out on this minimum working example file below with a 'header' and repeatedly calling M-x update-file-header.

// -----------------------------------------------------------------------------
// Version     : 0.0
// -----------------------------------------------------------------------------
1
  • Kaushalmodi, this works! I just noticed your comment now, sorry for that. I have still some difficulties to understand what's going on here in your code and Drew's examples, even there are good tutorials of Lisp. Sorry for my many questions.. I'm still trying to learn Elisp. Thanks for your help!
    – ReneFroger
    Jul 12, 2015 at 20:52
2

The problem is that you are using existing function update-write-count, which increments by 1 (integer). If you want something different (e.g. incrementing by 0.1) then you will need to use a different function here.

For example:

(register-file-header-action "Version   [ \t]*: " 'my-update-version-count)

(defun my-update-version-count ()
  (let* ((str  (delete-and-forget-line))
         (rem  (read-from-string str))
         (num  (car rem)))
    (if (numberp num)
        (insert (format "%s" (+ num 0.1)) (substring str (cdr rem)))
      (insert str)
      (error "Invalid number for update count `%s'" str))))
8
  • Drew, it worked nearly flawless, except there is a fault. When the update counter is on, for example 3.9 and I save, it updates to 4.0 instead 3.10. Is there any chance to change that? Nevertheless, I appreciate your contribution to the community!
    – ReneFroger
    Jul 1, 2015 at 15:00
  • You will need different code for that. Clearly, adding 0.1 doesn't do that kind of incrementing. You can break the version string into two (or more) pieces (e.g. "3", "9"), and increment just the piece you want to increment. You can use split-string to split, say, "3.9" into the list ("3" "9"). You might also find an existing version-string incrementor function out there somewhere.
    – Drew
    Jul 1, 2015 at 15:23
  • Thanks for your reply, I will look for a version-string incrementor. By the way, I noticed the script does weird things. When the version number is currently 0.2 and I save the buffer, the number will be updated to 0.30000000000000004. This happen with another numbers as well. Any idea why this could be happening?
    – ReneFroger
    Jul 1, 2015 at 19:53
  • Floating-point arithmetic. You can use function format, with %2.2f or some such. But really you are not dealing with numbers but with numerals and a dot notation. Try googling for Lisp version manipulator functions.
    – Drew
    Jul 1, 2015 at 22:08
  • 2
    See the various version* functions in Emacs: version-to-list, version-list-<, version<, etc., in standard library subr.el. If they don't help you directly (and they might), then perhaps their code will.
    – Drew
    Jul 2, 2015 at 15:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.