emacs自动更新文件头


前面已经说过,可以使用auto-insert自动添加文件头,今天来说一说自动更新文件头,比如说每次保存时自动更新last updated字段

自动更新Last Updated

如果使用的是header2,直接设置相关的变量就可,假如使用的是auto-insert,同样也可以使用emacs内置的time-stamp对Last Updated进行自动更新

time-stamp默认使用Time-stamp:,如果要对Last Updated进行自动更新,只需要简单的设置

(setq time-stamp-active t)
(setq time-stamp-line-limit 11)
(setq time-stamp-start "[lL]ast[ -][uU]pdate[ \t]*:?")
(setq time-stamp-end "\n")
(setq time-stamp-format " %#A %Y-%02m-%02d %02H:%02M:%02S (%Z)")

然后添加

(add-hook 'before-save-hook 'time-stamp)

这样就能在每次保存时自动更新相应的字段了

自动更新Filename

之前遇到过,使用auto-insert在每次创建新文件时自动添加了文件头,但后面文件名被修改了,文件头里的文件名却不会自动更改,基于这个原因需要自己实现一个函数(我没有找到可以使用的已经存在的package)

先理一理逻辑: 只需要查找当前文件前几行信息,如果找到File Name:字段,获取字段信息,与当前文件名进行对比,如果不一致则替换为当前文件名,直接给出代码吧

  • 查找当前文件前几行
    (save-excursion
        (goto-char (point-min)) ;;跳转到开头
        (let ((lines 0))
        (while (< lines line-limit)
            ;; 查找
            (setq lines (1+ lines))
            (forward-line 1))))
    
  • 获取当前文件名
    (file-name-nondirectory (buffer-file-name))
    
  • 查找File Name
    (looking-at ".*\\(File Name:\\)\\(.*\\)")
    
  • 对文件名进行比对与替换
    (let ((beg (match-beginning 2))
          (end (match-end 2)))
      (when (not (string= 文件名 (string-trim-left (match-string 2))))
        (goto-char beg)
        (delete-region beg end)
        (insert " " name)))
    

    即可得到相关的完整函数(完整函数后面再讲)

自动更新Email

工作和平时使用的邮箱不一样,我虽然设置了at_home变量区分工作与平时的邮箱,但不是每次我都记得要更新这个变量,所以有了这个需要,自动将文件头里的email信息更改为平时所用的邮箱,大致逻辑与自动更新Filename相同,所以我写了一个macro来自动生成相关的代码

直接给出代码

(defun maple/header-update-action(name)
  "A."
  (let ((beg (match-beginning 2))
        (end (match-end 2)))
    (when (not (string= name (string-trim-left (match-string 2))))
      (goto-char beg)
      (delete-region beg end)
      (insert " " name))))
(defun maple/header-update(regex default line-limit)
  "B."
  (interactive)
  (save-excursion
    (goto-char (point-min))
    (let ((lines 0))
      (while (< lines line-limit)
        (when (and (looking-at regex))
          (maple/header-update-action default))
        (setq lines (1+ lines))
        (forward-line 1)))))
(defmacro maple/header-update-engine (name regex default &optional line-limit)
  "C."
  `(defun ,(intern (format "maple/header-update-%s" name)) ()
     ,(format "Update %s with regex." name)
     (interactive)
     (maple/header-update ,regex ,default ,(or line-limit 7))))

这样,我就可以调用macro来生成代码

  • 自动更新Filename
    (maple/header-update-engine "filename"
                                ".*\\(File Name:\\)\\(.*\\)"
                                (file-name-nondirectory (buffer-file-name)) 7)
    

    生成一个maple/header-update-filename的函数,只要调用它即可更新文件名信息

  • 自动更新email

    同样的

    (maple/header-update-engine "email"
                                ".*\\(Email:\\)\\(.*\\)"
                                "youemail@gmail.com" 7)
    

    生成一个可供调用的maple/header-update-email

如果想要添加其它功能,只要使用maple/header-update-engine即可

相关的配置可以在我的github上找到