I'm trying to implement «effective append» for log buffer, e.g. if a point is at point-max position then insert text and move point to new point-max, otherwise append text and preserve point position. I though this will be very trivial code:

  (get-buffer-create "*scratch*")
  (if (eq (point) (point-max))
      (insert "\n;; ===\n")
      (goto-char (point-max))
      (insert "\n;; ===\n"))))

However, this works as expected only if invoked in *scratch* buffer:

  • having point somewhere in the middle => text appended, point not moved
  • having point at the end of buffer => text appended, point at the end

Now if I change buffer and invoke this command again, point never goes to new point-max and always stays where it was.

Simple tests showed that if statement gives correct results always, thus it is correct branch selected. I also tried explicitly move point or do scroll in true-branch, but nothing helped:

(if (eq (point) (point-max))
      (insert "\n;; ===\n")
      (View-scroll-to-buffer-end)  ;; not works
      (goto-char (point-max)))     ;; so does it too

Am I missing something?

  • 3
    You're probably missing the existence of a "window-point". To test your code, make sure scratch is not shown in any window (i.e (get-buffer-window "scratch") returns nil), then run your code and go to scratch again.
    – YoungFrog
    May 12, 2015 at 11:52
  • @YoungFrog well, if *scratch* buffer is not visible in any window I have same behaviour: point does not move to the end of buffer even if it should. Maybe I misunderstood you? May 12, 2015 at 13:34
  • I can't reproduce, then. Please try gist.github.com/YoungFrog/d7db1fb00e30ef93e9d7 and report output.
    – YoungFrog
    May 12, 2015 at 13:59
  • @YoungFrog same things: if I eval M-: your code with *scratch* as current buffer it works as expected. If I have other buffer as current with/without visible scratch buffer point does not moves all the time. There is also window-point-insertion-type but I need to learn about it and make some tests. May 12, 2015 at 14:15
  • I don't understand why you have that problem, but I have proposed an answer anyway because I still think I'm right ;)
    – YoungFrog
    May 12, 2015 at 15:06

2 Answers 2


I think the following code will help. It is modified from an example in the emacs-lisp intro at https://www.gnu.org/software/emacs/manual/html_node/eintr/append_002dto_002dbuffer-overview.html.

(defun append-string-to-buffer (buffer string)
  ;; Modified from append-to-buffer, defined in the emacs-lisp intro
  "Append to specified buffer the specified text.
It is inserted into that buffer at end of buffer.

When calling from a program, give two arguments:
BUFFER (or buffer name), and the STRING to be copied."
   (list (read-buffer "Append to buffer: " (other-buffer
                                            (current-buffer) t))
         (read-string "String to append: ")))

  (let* ((append-to (get-buffer-create buffer))
         (windows (get-buffer-window-list append-to t t))
    (with-current-buffer append-to
      ;; record in which windows we should keep point at eob.
      (dolist (window windows)
        (when (= (window-point window) (point-max))
          (push window move-point-in-windows)))
      (let (return-to-position)
        ;; decide whether we should reset point to return-to-position
        ;; or leave it at eob.
        (unless (= (point) (point-max))
          (setq return-to-position (point))
          (goto-char (point-max)))
        (insert string)
        (when return-to-position
          (goto-char return-to-position)))
      ;; advance to point-max in windows where it is needed
      (dolist (window move-point-in-windows)
        (set-window-point window (point-max))))))
  • Thanks! It works even better than expected! For example, if I have two windows with target buffer viewed it behaves correctly and independently for both of them. May 12, 2015 at 19:57
(with-current-buffer (get-buffer-create "MY-BUF")
  (let ((orig (point)))
    (if (eq (point) (point-max))
    (insert "\n;; ===\n")
      (goto-char (point-max))
      (insert "\n;; ===\n")
      (goto-char orig))))

BTW I'd not use save-excursion inside with-current-buffer, as save-excursion is a complex funciton, while goto-char orig looks cleaner.

  • Let me check. Did you missed progn for else-branch, didn't you? Also save excursion preserves active region if it present. May 12, 2015 at 13:05
  • Andreas Röhler, your code behaves exact as mine, did you tested it? Also looks like I do not need progn for else part. May 12, 2015 at 13:38
  • @Geradlus_RU Else-part is implicit: if a point is at point-max position then insert text and move point to new point-max - the second half of this sentence is redundant, as insertion will and at point-max. And yes, your code should work already. May 12, 2015 at 14:08

Your Answer

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

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