1

I looking into extending atomic-chrome to work with text areas that can be modified from the server side, such as site providing collaborative LaTeX editing. The plugin provides updates containing the full text of the modified buffer as a string whenever it changes in the browser window, but it currently performs the update by erasing the buffer and reinserting the full text. As a consequence, the position of point is lost each time changes are made on the browser side.

I believe it might be possible to work around this using a similar mechanism to that which revert-buffer uses behind the scenes to update the buffer contents, which is to call insert-file-contents with the REPLACE argument. Unfortunately, using this function directly would require writing the updated state to a file first, which seems hacky to me.

Is there a way to replicate the behavior of insert-file-contents with a string instead of file contents, or some other way of achieving the same goal?

0

You can restore point with

(let ((old-point (point)))
  (erase-buffer)
  (insert text)
  (goto-char old-point))

I use atomic-chrome as well. If you want the new behavior in your init file, you can advice atomic-chrome-update-buffer, something like the following

(define-advice atomic-chrome-update-buffer (:override (socket text) restore-point)
  "Like `atomic-chrome-update-buffer' but restore point afterwards."
  (let ((buffer (atomic-chrome-get-buffer-by-socket socket)))
    (when buffer
      (with-current-buffer buffer
        (let ((old-point (point)))
          (erase-buffer)
          (insert text)
          (goto-char old-point))))))

To remove the advice, use

(advice-remove 'atomic-chrome-update-buffer
               'atomic-chrome-update-buffer@restore-point)
2

If you're using emacs 26 or newer, replace-buffer-contents might be what you're looking for.

The documentation states:

(replace-buffer-contents SOURCE)

Replace accessible portion of current buffer with that of SOURCE. SOURCE can be a buffer or a string that names a buffer. Interactively, prompt for SOURCE. As far as possible the replacement is non-destructive, i.e. existing buffer contents, markers, properties, and overlays in the current buffer stay intact.

Suppose you want to replace the contents of the current buffer with the string str. The way to do this using replace-buffer-contents would be:

(let ((tmp-buf (generate-new-buffer "tmp")))
  (with-current-buffer tmp-buf (insert str))
  (replace-buffer-contents tmp-buf)
  (kill-buffer tmp-buf))

Note: The implementation of this function in emacs 26.1 has a bug: https://bugzilla.redhat.com/show_bug.cgi?id=1597251

There's a workaround that uses diff to produce an RCS-formatted diff and applies it to the current buffer: https://github.com/ocaml-ppx/ocamlformat/blob/master/emacs/ocamlformat.el#L108

1

You can use compare-strings to find the shared prefix of the before&after strings. Then you can use compare-strings again but on the reverse of those strings to find the shared suffix. Then only update the part between those two.

While it wouldn't be reusing the insert-file-contents code, it would reproduce its behavior.

Of course a better solution would be to try and get some kind of "diff" (description of the changes) from your browser, rather than the whole new text.

0

You may try using Markers, their purpose is to remember position when text is modified.

  • 1
    This doesn't help if you're deleting and replacing the whole buffer text. – npostavs Apr 20 '18 at 0:29
0

git-timemachine records the line number the cursor is at before issuing the "rewrite" command; After rewriting the buffer, it issues a goto-char;

see the git-timemachine-show-nth-revision function here: https://github.com/pidu/git-timemachine/blob/master/git-timemachine.el#L193

It is not "perfect" but depending on the amount of changes not such a dealbreaker.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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