Thank you Nicolas for letting me borrow (again) your blog to talk about my work. This time, this will not only be my work, but the one of Matus Goljer too (aka Fuco1). Let me present beginend.

Genesis

Four years ago, I started being really annoyed by the fact that M-< would go to the beginning of the dired buffer instead of the first file as shown in this picture:

img

I then wrote these lines of Emacs-lisp code to fix this.

(defun dired-back-to-top ()
  (interactive)
  (beginning-of-buffer)
  (dired-next-line (if dired-omit-mode 2 4)))
(define-key dired-mode-map
  (vector 'remap 'beginning-of-buffer) 'dired-back-to-top)

At this time, I took the same approach to bind M-< so that point would go to the beginning of an email body instead of before headers:

(defun mu4e-compose-goto-top ()
  (interactive)
  (let ((old-position (point)))
    (message-goto-body)
    (when (equal (point) old-position)
      (beginning-of-buffer))))

(define-key mu4e-compose-mode-map
  (vector 'remap 'beginning-of-buffer) 'mu4e-compose-goto-top)

You can see that this one is a bit smarter. The function moves point to the beginning of a message’s body, but if point is already there, the point is moved to the buffer’s real beginning instead. This makes it possible to press M-< several times to switch between the real buffer beginning and the meaningful one. I called this feature double-tap.

I did the same for M-> and this served me well for the next two years.

Start of the beginend project

Two years ago, I started cleaning my init.el file and decided to extract useful bits of Emacs Lisp code into separate packages. That was the beginning of the beginend project.

I also took the opportunity to improve the code to avoid duplication by introducing a macro:

(defun beginend-message-goto-beginning ()
  "Go to the beginning of an email, after the headers."
  (interactive)
  (beginend--double-tap-begin
   (message-goto-body)))

(defmacro beginend--double-tap-begin (&rest body)
  "Evaluate &BODY and goto real beginning if that did not change point."
  (let ((tempvar (make-symbol "old-position")))
    `(let ((,tempvar (point)))
       ,@body
       (when (equal ,tempvar (point))
         (call-interactively #'beginning-of-buffer)))))

The function beginend-message-goto-beginning is equivalent to the function mu4e-compose-goto-top defined above except it is shorter. The macro beginend--double-tap-begin implements double-tap in a way independent of the kind of buffer being visited. The code handling dired buffers used the same macro.

I released version 1 of the project.

Matus blog post and beginend on steroids

The project did not change for the next two years even though I was using it extensively. One day, I read Matus’ blog post titled:

Enhanced beginning- and end-of-buffer in special mode buffers (dired etc.)

This gave me energy to work on the package again. With Matus, we released version 2 featuring many changes:

  • User visible:
    • Add missing space to the mode lighter
    • Add support for many major modes (magit-status, prog, occur, org-agenda, compilation, notmuch-search, elfeed, prodigy, …)
    • Add a global minor mode
    • Push mark when beginend moves point
    • Make sure beginend is reasonable when buffer is narrowed
    • Update README and include screencasts
    • Make the end position coherent across modes
  • Build process:
    • Add Emacs-25.2 as build target
    • Remove compiler warnings
    • Add automated linting
  • Implementation:
    • Factor out common code into new macro making it easy to support more modes
  • Testing:
    • 84% of the code base is now covered by tests
    • Convert tests to buttercup

Adding support for a new mode is a matter of a few lines of code now. Here is how beginend supports going to the meaningful beginning and end of message buffers now:

(beginend-define-mode message-mode
  (progn
    (message-goto-body))
  (progn
    (when (re-search-backward "^-- $" nil t)
      (beginend--goto-nonwhitespace))))

The first progn specifies how to go to the meaningful beginning (i.e., after message headers) and the second one specifies how to go to the meaningful end (i.e., before the signature). These six lines of code also support double-tap, bind M-< and M->, take care of buffer narrowing and set the mark appropriately.

Here are some screencasts demonstrating the behavior of beginend in some major modes.

Dired mode

The following shows how beginend reacts in dired mode when dired-hide-details or dired-omit is activated.

img

Message mode

This screencast shows how beginend allows ignoring both a message headers and signature.

img

Programming mode

This shows how beginend moves point at start and end of the code block in programming buffers, ignoring comments and blank lines.

img

Conclusion

I hope you enjoy using beginend as much as I enjoyed writing it.