Automatically lock RCS-controlled Org files when capturing/refiling


I use RCS for various version control tasks where I only control a single file or I have a directory of files whose histories will be unrelated. The directory which contains my notes and agenda in "Org":http://orgmode.org/ format is like that. With RCS, when you commit your changes, i.e. check-in in RCS lingo, the file becomes "unlocked", that is, it's write bits are disabled. If you want to make further changes, you will need to "lock" the file, after "checking it out" if necessary (see rcs(1) manual for detail on how it operates). Conveniently, in Emacs, when you use the VC mode, the file is always checked out, and only locked and unlocked. But when my Org files are unlocked, I cannot seamlessly capture or refile my entries because the files are read-only, and I have to manually lock them first. The following bit of code advices some Org-mode functions so that they try to detect RCS controlled files and ask to lock them if necessary.

I use RCS for various version control tasks where I only control a single file or I have a directory of files whose histories will be unrelated. The directory which contains my notes and agenda in Org format is like that. With RCS, when you commit your changes, i.e. check-in in RCS lingo, the file becomes "unlocked", that is, it’s write bits are disabled. If you want to make further changes, you will need to "lock" the file, after "checking it out" if necessary (see rcs(1) manual for detail on how it operates). Conveniently, in Emacs, when you use the VC mode, the file is always checked out, and only locked and unlocked. But when my Org files are unlocked, I cannot seamlessly capture or refile my entries because the files are read-only, and I have to manually lock them first. The following bit of code advices some Org-mode functions so that they try to detect RCS controlled files and ask to lock them if necessary.

(defun gk-rcs-maybe-unlock (file)
  "Check to see if FILE is controlled by RCS and is
unlocked, offer to lock it before pasting."
  (let ((default-directory (file-name-directory file)))
    (when
        (and
         (fboundp 'vc-backend)
         (eq 'RCS (vc-backend file))
         (eq 'up-to-date (vc-rcs-state file))
         (y-or-n-p
          "File is controlled by RCS and not locked by you, lock?"))
      (with-current-buffer (find-file-noselect file)
        (vc-next-action nil)))))

(define-advice org-paste-subtree (:before (&rest args) check-rcs-lock)
  "Check to see if this file is controlled by RCS and is
unlocked, offer to lock it before pasting."
  (ignore args)
  (let ((f (buffer-file-name)))
    (gk-rcs-maybe-unlock f)))

(define-advice org-capture-fill-template (:before (&rest args) check-rcs-lock)
  "Check to see if this file is controlled by RCS and is
unlocked, offer to lock it before pasting."
  (ignore args)
  (let* ((buffer (org-capture-get :buffer))
         (file (buffer-file-name buffer)))
    (gk-rcs-maybe-unlock file)))

These advices depend on the implementation of org-capture and org-refile, and I’ve written them against version 9.1 of Org. You may want to keep an eye on those functions if you want to keep an eye on them, but I doubt they’ll change in a way that invalidates these customisation.

Advices are an incredibly powerful tool that enables you to fit other programs to your way of working without patching them. Combined with hooks and other means Emacs provides for modifying behaviour of Elisp programmes, they allow for a truly personalised experience.