0

I'd like to write Elisp code that compares text character by character between two buffers.

To do that, I need to first assign buffer names to the variables source-buffer and target-buffer respectively.

(defun set-source-buffer (&optional buffer)
  "Sets source-buffer to current-buffer. "
  (interactive "bSelect Source Buffer: \nr" buffer)
  (cond ((boundp 'buffer) buffer)
        (setq source-buffer (current-buffer))))

I would like to call this function by either activating the buffer to be selected as source and do (setq source-buffer (current-buffer)) or use (set-source-buffer buffer) in code, whereby buffer is the name of the buffer to be selected.

The above code returns nil when run on an active buffer.

How do I fix this?


Update:

I refer to the if statement provided by @Hubisan below.

(defun my-set-source-buffer (&optional buffer-or-name)
  "Sets `my-source-buffer' to `current-buffer' unless BUFFER-OR-NAME is given.
BUFFER-OR-NAME can be a string of an existing buffer or a buffer object."
  (interactive "bSelect Source Buffer:")
  (setq my-source-buffer
    (if (buffer-live-p (get-buffer buffer))
        (get-buffer buffer)
      (current-buffer))))

When should we use buffer-or-name for a variable and when to use just buffer alone?

  • "The above code yields a void function buffer error." is not true. It does complain that there are not enough arguments, as you have (seemingly inexplicably) included a second interactive code r after the b -- which means the function needs to accept a pair of region delimiter arguments as well. I'm not seeing any way that the code you've shown could result in the error you've quoted. Please try to sanity-check your questions to check that what you state is happening is actually what is happening. – phils Nov 10 at 20:44
  • Yes - you are right! The only issue with the above code is that it returns nil when run on an active buffer. – Sati Nov 10 at 23:56
  • @Sati just forgot to change the if part, sorry for that. fixed. – Hubisan Nov 11 at 6:14
  • From my understanding, to have a working function, either buffer or buffer-or-name can be used, so long as the upper part right after the defun - the defined arguments to the function - and variables called within the body of the function itself agree. Is that correct? So buffer-or-name is just a convention to indicate that the function accepts either a string of an existing buffer or a buffer object as its argument? (any other symbol can be used in its place from a functional perspective) – Sati Nov 11 at 11:39
  • 1
    @Sati Exactly. I always try to find a function that has a similar argument to sort of copy the common symbol used for it. buffer-or-name is used in many functions as argument so it's a good idea to use the same. – Hubisan Nov 11 at 12:37
3
  • Use cond to bind either the buffer provided or the current buffer to my-source-buffer. No need for the extra line below. As there is actually only one condition an if statement would probably serve you better.
  • For the interactive line: Don't include the buffer variable. See Using-Interactive.
  • (boundp 'buffer) also returns t if buffer is nil as the symbol itself exists because it is an argument of the function. To check if buffer was provided a simple (when buffer ...) is enough.
  • It's advisable to prefix custom variables and functions with for instance my-. See Elisp > Coding-Conventions. Adapted the names in the following code accordingly.
(defun my-set-source-buffer (&optional buffer-or-name)
  "Sets `my-source-buffer' to `current-buffer' unless BUFFER-OR-NAME is given.
BUFFER-OR-NAME can be a string of an existing buffer or a buffer object."
  (interactive "bSelect Source Buffer:")
  (setq my-source-buffer
        (cond
         ;; Check if buffer is a buffer and if it still exists.
         ;; `get-buffer' is used to get the buffer by name if needed.
         ((buffer-live-p (get-buffer buffer-or-name)) (get-buffer buffer-or-name))
         ;; Otherwise return the current buffer.
         (t (current-buffer))))
  ;; Same with using if statement.
  ;; (setq my-source-buffer
  ;;       (if (buffer-live-p (get-buffer buffer-or-name))
  ;;           (get-buffer buffer-or-name)
  ;;         (current-buffer)))
  )

The function can be called as follows:

  • with string of an existing buffer: (my-set-source-buffer "*scratch*")
  • with a buffer object: (my-set-source-buffer (get-buffer "*scratch*"))
  • interactively: M-x my-set-source-buffer and select the buffer interactively.
  • 1
    (and (bufferp b) (buffer-live-p b)) = (buffer-live-p b). See C-h f buffer-live-p. – Drew Nov 10 at 16:26
  • 1
    The interactive form will give a buffer name, but the code you've written checks for a buffer object. One of them should be adjusted. – npostavs Nov 10 at 17:05
  • @npostavs thx for the input. Fixed the function. – Hubisan Nov 10 at 22:31

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.