3

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:

(with-current-buffer
  (get-buffer-create "*scratch*")
  (if (eq (point) (point-max))
      (insert "\n;; ===\n")
    (save-excursion
      (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))
    (progn
      (insert "\n;; ===\n")
      (View-scroll-to-buffer-end)  ;; not works
      (goto-char (point-max)))     ;; so does it too
  (…))

Am I missing something?

Drew
  • 75,699
  • 9
  • 109
  • 225
Geradlus_RU
  • 625
  • 7
  • 17
  • 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 '15 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? – Geradlus_RU May 12 '15 at 13:34
  • I can't reproduce, then. Please try https://gist.github.com/YoungFrog/d7db1fb00e30ef93e9d7 and report output. – YoungFrog May 12 '15 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. – Geradlus_RU May 12 '15 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 '15 at 15:06

2 Answers2

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."
  (interactive
   (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))
         move-point-in-windows)
    (with-current-buffer append-to
      (barf-if-buffer-read-only)
      ;; 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))))))
Scott Weldon
  • 2,695
  • 1
  • 17
  • 31
YoungFrog
  • 3,496
  • 15
  • 27
  • 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. – Geradlus_RU May 12 '15 at 19:57
0
(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.

Scott Weldon
  • 2,695
  • 1
  • 17
  • 31
Andreas Röhler
  • 1,894
  • 10
  • 10
  • Let me check. Did you missed `progn` for else-branch, didn't you? Also save excursion preserves active region if it present. – Geradlus_RU May 12 '15 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. – Geradlus_RU May 12 '15 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. – Andreas Röhler May 12 '15 at 14:08