How to clone/duplicate contents of file-visiting buffer in Emacs - emacs

Say I have opened a file foo.c in a buffer A. Now I want to open a new buffer B which contains the same contents as A, but with no connection to the file foo.c. How can this be done?

Maybe something like this:
(defun my-copy-buffer ()
(interactive)
(get-buffer-create "NEWBUF")
(copy-to-buffer "NEWBUF" (point-min) (point-max)))

Related

How to use the function option of org-capture correctly?

I want to dynamically open the correct file in an orgmode capture template using the function option:
("a" "foo" plain
(function my-visit-timestamped-file)
"<some content>")
Function my-visit-timestamped-file is defined as
(defun my-visit-timestamped-file ()
(interactive)
(let
((theDate (format-time-string "%Y%m%d-%H%M.org")))
(find-file (concat "<some_path>" theDate))))
If I run the capture template a, emacs opens the file <some_path>theDate in a buffer and opens the capture buffer with the file.
Thus my window is split into 2 buffers showing the same content.
Can function my-visit-timestamped-file be changed somehow such that the buffer is not opened but org capture still gets the correct file pointer/file handle?
The answer by #jpkotta pointed me in the right direction.
The bug was gone, but instead the content of the capture buffer was always pasted into the buffer I was currently editing.
In an old thread on the org-mode mailing list I found the answer to my question. The function should be:
(defun my-visit-timestamped-file ()
"Visit a new file named by the current timestamp"
(interactive)
(let* (
(curr-date-stamp (format-time-string "%Y%m%d-%H%M.org"))
(file-name (expand-file-name curr-date-stamp "/some/path/")))
(set-buffer (org-capture-target-buffer file-name))
(goto-char (point-max))))
Link to mailing list thread: https://lists.gnu.org/archive/html/emacs-orgmode/2013-11/msg00676.html
You probably want find-file-noselect instead of find-file. Note that the docs of org-capture-templates say this:
(function function-finding-location)
Most general way: write your own function which both visits
the file and moves point to the right location
so you might want to add some code to go to the correct location (I'm guessing either (point-min) or (point-max)) in the file. That might look like this:
(defun my-visit-timestamped-file ()
(interactive)
(let* ((the-date (format-time-string "%Y%m%d-%H%M.org"))
(the-buffer (find-file-noselect (expand-file-name the-date "/some/path/"))))
(with-current-buffer the-buffer
(goto-char (point-min)))
the-buffer))

Forbid buffer content to save to old file when buffer file name is changed

I have follow use case annoying me a lot.
Open file foo.rb in emacs buffer.
rename foo.rb to bar.rb use external tool.(e.g. rename from terminal)
Select foo.rb buffer in Emacs, edit it, when C-x s to save, this buffer
save as old file name (foo.rb), not expected bar.rb.
Is there any emacs config to prevent this??
What i expect is some like:
open file foo.rb in Emacs buffer.
rename foo.rb to bar.rb use external tool
edit foo.rb buffer, when save, told me: file is removed, or prompt,
save as a new file name.
Here's the beginning of a solution. The devil's in the details; there are probably a lot of corner cases that this code doesn't deal with.
(defvar do-not-save-list ())
(defun do-not-save-add-to-list (event)
(when (eq 'renamed (cadr event))
(add-to-list 'do-not-save-list
(caddr event))))
(defun do-not-save-add-watcher ()
(setq do-not-save-list (remove (buffer-file-name) do-not-save-list))
(file-notify-add-watch (buffer-file-name)
'(change)
#'do-not-save-add-to-list))
(add-hook 'find-file-hook #'do-not-save-add-watcher)
(defun do-not-save-check ()
(let ((filename (buffer-file-name)))
(when (member filename do-not-save-list)
(message "not saving %s" filename)
t ;; returns non-nil to prevent write
)))
(add-hook 'write-file-functions #'do-not-save-check)
(defun do-not-save-kill-hook ()
(setq do-not-save-list (remove (buffer-file-name) do-not-save-list)))
(add-hook 'kill-buffer-hook #'do-not-save-kill-hook)

how to create an empty buffer in elscreen?

When I open a new tab in elscreen, it will open the scratch buffer. So if I copy something to a scratch buffer, and then open a new tab, that tab will show the same thing in the previous tab. But actually I need an empty buffer. HOw to do that?
A simple elisp function that calls elscreen-create and opens a new dummy buffer:
(defun my-elscreen-create ()
(interactive)
(elscreen-create)
(switch-to-buffer (concat "test-" (number-to-string (elscreen-get-number-of-screens))) ;; make it unique
))
If you're using the version of elscreen here or here then this might help you (There is a elscreen-create-hook but further buffer manipulation takes place after it's called, so I've been using this advice for the last year or so to do something similar):
(defadvice elscreen-create (after new-blank-buffer)
(let* ((new-buffer (generate-new-buffer "blank"))
(blank-buffer-name (buffer-name new-buffer)))
(switch-to-buffer blank-buffer-name)))
(ad-activate 'elscreen-create)

File path to clipboard in Emacs

What is the most simple way to send current full file name with file path to clipboard?
What I am using now is messages buffer: I copy file name that appears there after saving a file. But, I suppose, there should be much more simple way.
Why no one tell the simple solution.
Just go to your dired buffer then press 0 w or C-u 0 w.
This will call dired-copy-filename-as-kill which gives you full path of a file. If you want current dir, just delete the file at the end of it or you can use the function below, then bind it to any key you like.
(defun my/dired-copy-dirname-as-kill ()
"Copy the current directory into the kill ring."
(interactive)
(kill-new default-directory))
PS: personally I go to current directory from file buffer using dired-jump
I use this:
(defun my-put-file-name-on-clipboard ()
"Put the current file name on the clipboard"
(interactive)
(let ((filename (if (equal major-mode 'dired-mode)
default-directory
(buffer-file-name))))
(when filename
(with-temp-buffer
(insert filename)
(clipboard-kill-region (point-min) (point-max)))
(message filename))))
In Emacs Prelude I use:
(defun prelude-copy-file-name-to-clipboard ()
"Copy the current buffer file name to the clipboard."
(interactive)
(let ((filename (if (equal major-mode 'dired-mode)
default-directory
(buffer-file-name))))
(when filename
(kill-new filename)
(message "Copied buffer file name '%s' to the clipboard." filename))))
If you want to write the name/path of the current buffer you can type C-u M-: and then either (buffer-file-name) - for the full path - or (buffer-name) for the buffer name.
That is:
M-: + ellisp expression evaluates an ellisp expression in the mini-buffer
C-u write the output to the current buffer
Does not exactly answer to the question but could be useful if someone use this or other function sporadically, and prefers to not initialize the function at every startup.
In the Spacemacs distribution, you can press Spacefyy to display the buffer name in the minibuffer and copy it to the kill ring.
The function spacemacs/show-and-copy-buffer-filename seems to originate from this blog post: Emacs: Show Buffer File Name.
(defun camdez/show-buffer-file-name ()
"Show the full path to the current file in the minibuffer."
(interactive)
(let ((file-name (buffer-file-name)))
(if file-name
(progn
(message file-name)
(kill-new file-name))
(error "Buffer not visiting a file"))))
There's a buffer-extension - and it has copy-buffer-file-name-as-kill function. It even asks You what to copy: name, full name or a directory name.
Edit:
I use modified version of copy-buffer-file-name-as-kill from buffer-extension.el:
(defun copy-buffer-file-name-as-kill (choice)
"Copyies the buffer {name/mode}, file {name/full path/directory} to the kill-ring."
(interactive "cCopy (b) buffer name, (m) buffer major mode, (f) full buffer-file path, (d) buffer-file directory, (n) buffer-file basename")
(let ((new-kill-string)
(name (if (eq major-mode 'dired-mode)
(dired-get-filename)
(or (buffer-file-name) ""))))
(cond ((eq choice ?f)
(setq new-kill-string name))
((eq choice ?d)
(setq new-kill-string (file-name-directory name)))
((eq choice ?n)
(setq new-kill-string (file-name-nondirectory name)))
((eq choice ?b)
(setq new-kill-string (buffer-name)))
((eq choice ?m)
(setq new-kill-string (format "%s" major-mode)))
(t (message "Quit")))
(when new-kill-string
(message "%s copied" new-kill-string)
(kill-new new-kill-string))))
If you use Doom Emacs, it can be done with SPC f y.
To paste the current file path in the buffer, the most simple way I see is to do: C-u M-! pwd (this might not work on Windows systems though).
Alternatively, you can use C-x C-b to show the file paths of all opened buffers.
This is what has worked for me on MacOS 10.15.7, GNU Emacs 27.1
(defun copy-current-buffer-file-name ()
(interactive)
(shell-command (concat "echo " (buffer-file-name) " | pbcopy")))
set keybinding to "C-x M-f":
(global-set-key (kbd "C-x M-f") 'copy-current-buffer-file-name)
FYI: For a real beginner reading this, you need to add those lines to your init.el file.
Lots of good answers here, though I think for the "most simple way", as described in the question, there's room for improvement. Here's what I came up with (with thanks to other answers for the bits and pieces):
M-: (kill-new (buffer-file-name)) RET
This does precisely what you asked for -- takes the filename of the current buffer, and puts it in the "kill ring" and, depending on your settings, also the system clipboard. (See emacswiki/CopyAndPaste for more details on that part.)
If you want to do this regularly, then setting up a function like listed in the other answers, and binding it to an available key sequence, would make it easier to do frequently. But the above works with no prior setup, which I'm interpreting to be more "simple".

How do I get a warning before killing a temporary buffer in Emacs?

More than once I've lost work by accidentally killing a temporary buffer in Emacs. Can I set up Emacs to give me a warning when I kill a buffer not associated with a file?
Make a function that will ask you whether you're sure when the buffer has been edited and is not associated with a file. Then add that function to the list kill-buffer-query-functions.
Looking at the documentation for Buffer File Name you understand:
a buffer is not visiting a file if and only if the variable buffer-file-name is nil
Use that insight to write the function:
(defun maybe-kill-buffer ()
(if (and (not buffer-file-name)
(buffer-modified-p))
;; buffer is not visiting a file
(y-or-n-p "This buffer is not visiting a file but has been edited. Kill it anyway? ")
t))
And then add the function to the hook like so:
(add-to-list 'kill-buffer-query-functions 'maybe-kill-buffer)
(defun maybe-kill-buffer ()
(if (and (not buffer-file-name)
(buffer-modified-p))
;; buffer is not visiting a file
(y-or-n-p (format "Buffer %s has been edited. Kill it anyway? "
(buffer-name)))
t))
(add-to-list 'kill-buffer-query-functions 'maybe-kill-buffer)