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

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)

Related

Emacs: load-file .emacs when saved

I'm new to emacs and lisp.
I wanted to auto-load the dot file when it was saved. Meaning, when I save my .emacs file, it would automatically call load-file on it (thus letting me know right away if I messed up).
But I can't seen to be able to find a comprehensive tutorial on hooks in emacs.
This is what I've come up with:
(defun load-init-after-save ()
"After saving this file, load it"
(if (eq bname this) ('load-file this) (nil))
)
(add-hook 'after-save-hook 'load-init-after-save)
Of course, this is incorrect: bname and this are just placeholders. And I don't want this function to run on all saves, just when the .emacs file is saved.
Does anyone know how to do this? Is there a better, easier way?
The following code loads your .emacs or ~/.emacs.d/init.el file after save:
(defun my-load-user-init-file-after-save ()
(when (string= (file-truename user-init-file)
(file-truename (buffer-file-name)))
(let ((debug-on-error t))
(load (buffer-file-name)))))
(add-hook 'after-save-hook #'my-load-user-init-file-after-save)
Since your intended use is error-checking, the code also enables the debugger while loading the init file, so that you get a nice backtrace in case of errors.
For error checking of your init file you may also find Flycheck useful. It checks your init file on the fly with the byte compiler, highlights any errors and warnings in the buffer, and—optionally—gives you a list of all errors and warnings.
Disclaimer: I'm the maintainer of this library.
Way 1
One way of doing is to install auto-compile-mode from MELPA, and enable it:
(defun my-emacs-lisp-hook ()
(auto-compile-mode 1))
(add-hook 'emacs-lisp-mode-hook 'my-emacs-lisp-hook)
Now each time you save an Elisp file that's byte-compiled, it will be
re-compiled. Compilation will usually catch some bad errors.
To compile any Elisp file, select it in dired (C-x d)
and press B (dired-do-byte-compile).
Way 2
Use this custom code I wrote.
(defun test-emacs ()
(interactive)
(require 'async)
(async-start
(lambda () (shell-command-to-string "emacs --batch --eval \"(condition-case e (progn (load \\\"~/.emacs\\\") (message \\\"-OK-\\\")) (error (message \\\"ERROR!\\\") (signal (car e) (cdr e))))\""))
`(lambda (output)
(if (string-match "-OK-" output)
(when ,(called-interactively-p 'any)
(message "All is well"))
(switch-to-buffer-other-window "*startup error*")
(delete-region (point-min) (point-max))
(insert output)
(search-backward "ERROR!")))))
(defun auto-test-emacs ()
(when (eq major-mode 'emacs-lisp-mode))
(test-emacs))
(add-hook 'after-save-hook 'auto-test-emacs)
This will start a new Emacs instance in the background each time you
save a file. If something goes wrong, it will complain.
The second approach uses async.
If you really want to do this just for .emacs user this:
(defun auto-test-emacs ()
(when (and (eq major-mode 'emacs-lisp-mode)
(equal (file-truename user-init-file)
(expand-file-name
buffer-file-truename)))
(test-emacs)))

If desktop previously saved, then switch from *scratch* to last viewed file

Could someone please give me a hand switching to the last viewed file from the desktop save when opening Emacs, taking into consideration that my *scratch* buffer is also an existing file?
The *scratch* buffer always trumps the desktop save in terms of the initial buffer choice.
(setq initial-scratch-message nil)
;; (setq initial-buffer-choice "~/.0.data/.0.emacs/*scratch*")
(defun kill-default-scratch ()
"Avoid having a buffer named `*scratch*<2>` when Emacs loads
my preferred *scratch* file from a specified location -- however,
yield to the last viewed file if it exists from desktop-save."
(kill-buffer "*scratch*")
(find-file "~/.0.data/.0.emacs/*scratch*") )
(add-hook 'after-init-hook 'kill-default-scratch)
(require 'saveplace)
(setq-default save-place t)
(setq save-place-file "~/.0.data/.0.emacs/.saved-places")
(desktop-save-mode 1)
(setq desktop-dirname "~/.0.data/.0.emacs/"
desktop-base-file-name ".emacs.desktop"
desktop-base-lock-name ".lock"
desktop-path (list desktop-dirname)
desktop-save t
desktop-files-not-to-save "[*]bbdb[*]\\|[*]BBDB[*]\\|[*]TODO[*]" ;; "^$" reload tramp paths
desktop-load-locked-desktop nil )
(setq desktop-buffers-not-to-save
(concat "\\("
"^nn\\.a[0-9]+\\|\\.log\\|(ftp)\\|^tags\\|^TAGS"
"\\|\\.emacs.*\\|\\.diary\\|\\.newsrc-dribble"
"\\)$"))
(add-to-list 'desktop-modes-not-to-save 'dired-mode)
(add-to-list 'desktop-modes-not-to-save 'Info-mode)
(add-to-list 'desktop-modes-not-to-save 'info-lookup-mode)
(add-to-list 'desktop-modes-not-to-save 'fundamental-mode)
EDIT: Based upon the answer provided by #juanleon, I decided to just let nature run its course and deal with it using the emacs-startup-hook (which loads subsequent to the after-init-hook). The scratch buffer wants to trump desktop.el, so let it and then bury it. To deal with the situation when there is no last viewed file saved by desktop.el (i.e., because they were all closed before exiting), I bury the *Messages* buffer (if it has focus) so the result is that the custom *scratch* buffer has focus again. To remove the custom *scratch* file from the desktop.el save feature, I added [*]scratch[*] to the list of desktop-files-not-to-save. I am using auto-save-buffers-enhanced to automatically save my custom *scratch* file (set to occur 1 second after every modification) and that utility lets me exclude user-defined file types with (setq auto-save-buffers-enhanced-exclude-regexps . . .): https://github.com/kentaro/auto-save-buffers-enhanced/blob/master/auto-save-buffers-enhanced.el [NOTE: The reference to flet therein would need to be changed to cl-flet if using a recent version of Emacs.]
(setq initial-scratch-message nil)
(setq initial-buffer-choice t)
(require 'auto-save-buffers-enhanced)
(auto-save-buffers-enhanced t)
(setq auto-save-buffers-enhanced-save-scratch-buffer-to-file-p 1)
(setq auto-save-buffers-enhanced-exclude-regexps '("^not-save-file" "\\.ignore$" "\\.txt" "[*]TODO[*]" "\\.yasnippet" "\\.tex" "\\user_pref" "\\.org_archive" "\\.org" "\\.ppet"))
(require 'saveplace)
(setq-default save-place t)
(setq save-place-file "~/.0.data/.0.emacs/.saved-places")
(desktop-save-mode 1) ;; uses the after-init-hook
(setq desktop-dirname "~/.0.data/.0.emacs/"
desktop-base-file-name ".emacs.desktop"
desktop-base-lock-name ".lock"
desktop-path (list desktop-dirname)
desktop-save t
desktop-files-not-to-save "[*]scratch[*]\\|[*]bbdb[*]\\|[*]BBDB[*]\\|[*]TODO[*]" ;; "^$" reload tramp paths
desktop-load-locked-desktop nil )
(setq desktop-buffers-not-to-save
(concat "\\("
"^nn\\.a[0-9]+\\|\\.log\\|(ftp)\\|^tags\\|^TAGS"
"\\|\\.emacs.*\\|\\.diary\\|\\.newsrc-dribble"
"\\)$"))
(add-to-list 'desktop-modes-not-to-save 'dired-mode)
(add-to-list 'desktop-modes-not-to-save 'Info-mode)
(add-to-list 'desktop-modes-not-to-save 'info-lookup-mode)
(add-to-list 'desktop-modes-not-to-save 'fundamental-mode)
(defun custom-scratch-setup ()
"Avoid having a buffer named `*scratch*<2>` when Emacs loads
my preferred *scratch* file from a specified location -- however,
yield to the last viewed file if it exists from desktop-save."
(kill-buffer "*scratch*")
(message "The default `*scratch*` buffer has been killed.")
(find-file "~/.0.data/.0.emacs/*scratch*")
(message "Finished loading the custom `*scratch*` file.")
(bury-buffer)
(message "The buffer *scratch* has been buried.")
(if (eq (current-buffer)
(get-buffer "*Messages*") )
(progn (bury-buffer)
(message "The buffer *Messages* has been buried."))) )
(add-hook 'emacs-startup-hook 'custom-scratch-setup)
My guess would be that after-init-hook runs after desktop has finished loading its stuff (desktop uses that hook)
So, the find-file will run at the end of everything, and find-file happens to "unbury" the buffer of a file, if already loaded. You may add a (bury-buffer) at the end of your kill-default-scratch if you don't want it to taking over initial buffer choice, nor being the initial buffer choice.
Another option would be to swap the order the hooks in after-init-hook are run. You can do that by playing with the moment desktop.el is "required" and/or using the arg APPEND of add-hook. If your function is run before desktop's function, (desktop-read) will take precedence over your find-file

In emacs, how do I save without running save hooks?

I have various things set up in my 'before-save-hook. For example, I run 'delete-trailing-whitespace. This is what I want in almost all occasions.
But sometimes, I'm working on files that are shared with other people, and the file already has a bunch of trailing whitespace. If I save the file, I'll get a big diff that's pretty confusing, as my change is buried in dozens or hundreds of meaningless changes. Yes, everyone could just tell their diff tool to not show whitespace changes, but that's something that everyone has to do every time they look at the diff. I'd rather not even have the whitespace change.
Is there anything I can do to save the file without the whitespace changes, short of starting a new instance of Emacs with no init.el file, or with a modified init.el that doesn't have the hook?
Here is how I save without triggering delete-trailing-whitespace:
C-x C-q C-x C-s C-x C-q: read-only, save, revert read-only
A simpler solution I came up with is that my fundamental-mode has no hooks installed, because I want it to be as plain as possible. Thus if I want to save a file without running hooks, I temporarily switch to fundamental-mode.
Based on a comment discussion with #Stefan, here are two possible (untested) solutions:
Use let:
(defun save-buffer-without-dtw ()
(interactive)
(let ((b (current-buffer))) ; memorize the buffer
(with-temp-buffer ; new temp buffer to bind the global value of before-save-hook
(let ((before-save-hook (remove 'delete-trailing-whitespace before-save-hook)))
(with-current-buffer b ; go back to the current buffer, before-save-hook is now buffer-local
(let ((before-save-hook (remove 'delete-trailing-whitespace before-save-hook)))
(save-buffer)))))))
Use unwind-protect:
(defun save-buffer-without-dtw ()
(interactive)
(let ((restore-global
(memq 'delete-trailing-whitespace (default-value before-save-hook)))
(restore-local
(and (local-variable-p 'before-save-hook)
(memq 'delete-trailing-whitespace before-save-hook))))
(unwind-protect
(progn
(when restore-global
(remove-hook 'before-save-hook 'delete-trailing-whitespace))
(when restore-local
(remove-hook 'before-save-hook 'delete-trailing-whitespace t))
(save-buffer))
(when restore-global
(add-hook 'before-save-hook 'delete-trailing-whitespace))
(when restore-local
(add-hook 'before-save-hook 'delete-trailing-whitespace nil t)))))
The problem with the second solution is that the order of functions in the before-save-hook may change.
Here's another solution:
(defvar my-inhibit-dtw nil)
(defun my-delete-trailing-whitespace ()
(unless my-inhibit-dtw (delete-trailing-whitespace)))
(add-hook 'before-save-hook 'my-delete-trailing-whitespace)
and then
(defun my-inhibit-dtw ()
(interactive)
(set (make-local-variable 'my-inhibit-dtw) t))
so you can M-x my-inhibit-dtw RET in the buffers where you don't want to trim whitespace.
I wrote a command inspired by Nicholas Douma's solution.
(defun olav-save-buffer-as-is ()
"Save file \"as is\", that is in read-only-mode."
(interactive)
(if buffer-read-only
(save-buffer)
(read-only-mode 1)
(save-buffer)
(read-only-mode 0)))
What we need to do is remove 'delete-trailing-whitespace from before-save-hook, save the buffer, then add it back.
This code will do that, but only remove and add it if it's there to begin with.
;; save the buffer, removing and readding the 'delete-trailing-whitespace function
;; to 'before-save-hook if it's there
(defun save-buffer-no-delete-trailing-whitespace ()
(interactive)
(let ((normally-should-delete-trailing-whitespace (memq 'delete-trailing-whitespace before-save-hook)))
(when normally-should-delete-trailing-whitespace
(remove-hook 'before-save-hook 'delete-trailing-whitespace))
(save-buffer)
(when normally-should-delete-trailing-whitespace
(add-hook 'before-save-hook 'delete-trailing-whitespace))))
(global-set-key (kbd "C-c C-s") 'save-buffer-no-delete-trailing-whitespace)
It also binds the command to (kbd C-c C-s), for convenience.

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".

Re-open *scratch* buffer in Emacs?

If I accidentally closed the scratch buffer in Emacs, how do I create a new scratch buffer?
GNU Emacs default bindings:
C-xb *scratch* RET
or, more verbosely
M-x switch-to-buffer *scratch* RET
The *scratch* buffer is the buffer selected upon startup, and has the major mode Lisp Interaction. Note: the mode for the *scratch* buffer is controlled by the variable initial-major-mode.
In general you can create as many "scratch" buffers as you want, and name them however you choose.
C-xb NAME RET
switches to a buffer NAME, creating it if it doesn't exist. A new buffer is not associated with a file on disk until you use C-xC-w (or M-x write-file RET) to choose a file where it should be saved.
M-x text-mode RET
changes the current buffer's major mode to Text mode. To find all the modes available (that is, without requiring any new packages), you can get a list by typing:
M-x apropos-command -mode$ RET
I add following in my .emacs:
;; bury *scratch* buffer instead of kill it
(defadvice kill-buffer (around kill-buffer-around-advice activate)
(let ((buffer-to-kill (ad-get-arg 0)))
(if (equal buffer-to-kill "*scratch*")
(bury-buffer)
ad-do-it)))
If I don't want to see scratch buffer I press C-x C-k , but it doesn't kill it, just place in the end of buffer list, so then I need it next time I don't have to create new one.
There are a whole bunch of tips on this EmacsWiki page.
Here's the first one:
A very simple function to recreate the scratch buffer:
(defun create-scratch-buffer nil
"create a scratch buffer"
(interactive)
(switch-to-buffer (get-buffer-create "*scratch*"))
(lisp-interaction-mode))
C-x b *scratch* RET y RET with iswitchb-mode enabled.
Just C-x b *scratch* RET otherwise.
I found this years ago when I first started using emacs; I have no idea where now but it has always had a home in my personal .el files. It does pop up in google searches.
;;; Prevent killing the *scratch* buffer -- source forgotten
;;;----------------------------------------------------------------------
;;; Make the *scratch* buffer behave like "The thing your aunt gave you,
;;; which you don't know what is."
(save-excursion
(set-buffer (get-buffer-create "*scratch*"))
(make-local-variable 'kill-buffer-query-functions)
(add-hook 'kill-buffer-query-functions 'kill-scratch-buffer))
(defun kill-scratch-buffer ()
;; The next line is just in case someone calls this manually
(set-buffer (get-buffer-create "*scratch*"))
;; Kill the current (*scratch*) buffer
(remove-hook 'kill-buffer-query-functions 'kill-scratch-buffer)
(kill-buffer (current-buffer))
;; Make a brand new *scratch* buffer
(set-buffer (get-buffer-create "*scratch*"))
(lisp-interaction-mode)
(make-local-variable 'kill-buffer-query-functions)
(add-hook 'kill-buffer-query-functions 'kill-scratch-buffer)
;; Since we killed it, don't let caller do that.
nil)
;;;----------------------------------------------------------------------
Like the docstring says, this function will:
Switch to the scratch buffer. If the buffer doesn't exist create it and write the initial message into it."
This will bring a new scratch buffer up which looks like the initial scratch buffer.
(defun switch-buffer-scratch ()
"Switch to the scratch buffer. If the buffer doesn't exist,
create it and write the initial message into it."
(interactive)
(let* ((scratch-buffer-name "*scratch*")
(scratch-buffer (get-buffer scratch-buffer-name)))
(unless scratch-buffer
(setq scratch-buffer (get-buffer-create scratch-buffer-name))
(with-current-buffer scratch-buffer
(lisp-interaction-mode)
(insert initial-scratch-message)))
(switch-to-buffer scratch-buffer)))
(global-set-key "\C-cbs" 'switch-buffer-scratch)
I used to use dwj's solution, and I was quite happy about it, until the day I realized that it failed when you actually rename the scratch buffer (for example by saving it).
Then I adopted this, which works well for me :
(run-with-idle-timer 1 t
'(lambda () (get-buffer-create "*scratch*")))
I have scratch as an interactive command for opening a new scratch buffer (I like to have several):
(defun scratch ()
"create a new scratch buffer to work in. (could be *scratch* - *scratchX*)"
(interactive)
(let ((n 0)
bufname)
(while (progn
(setq bufname (concat "*scratch"
(if (= n 0) "" (int-to-string n))
"*"))
(setq n (1+ n))
(get-buffer bufname)))
(switch-to-buffer (get-buffer-create bufname))
(if (= n 1) initial-major-mode))) ; 1, because n was incremented
adopted from: http://everything2.com/index.pl?node_id=1038451
(global-set-key (kbd "C-x M-z")
'(lambda ()
(interactive)
(switch-to-buffer "*scratch*")))
This will not only quickly switch to *scratch* buffer(since I do this frequently), but recreate a *scratch* buffer and enable lisp-interaction-mode automatically if you kill it accidentally. Change the binding as you like.
Just to note emacs package unkillable-scratch in MELPA will do this. There is also scratch-persist that will automatically save and restore the buffer between sessions.
This is what I use - I have this bound to a convenient keystroke. It sends you to the *scratch* buffer, regardless of whether or not it already exists, and sets it to be in lisp-interaction-mode
(defun eme-goto-scratch ()
"this sends you to the scratch buffer"
(interactive)
(let ((eme-scratch-buffer (get-buffer-create "*scratch*")))
(switch-to-buffer eme-scratch-buffer)
(lisp-interaction-mode)))
I prefer to have my scratch buffer be an actual file that is automatically saved, and reopening it is as simple as opening a file. On startup, I kill the default and find my own like this.
(add-hook 'emacs-startup-hook
(lambda ()
(kill-buffer "*scratch*")
(find-file "/Users/HOME/Desktop/.scratch")))
I have a custom kill-buffer function that does essentially the same thing -- reopens my personal scratch saved file and kills the default scratch if I killed the last visible buffer.
I customized a few of the desktop.el functions to load after (kill-buffer "*scratch*") and (find-file "/Users/HOME/Desktop/.scratch") so that the file last visible on exiting Emacs doesn't get buried by the default scratch or buried by my custom scratch when launching Emacs.
I enjoy using auto-save-buffers-enhanced, which automatically saves any file extension that is not specifically excluded:
https://github.com/kentaro/auto-save-buffers-enhanced/blob/master/auto-save-buffers-enhanced.el
(require 'auto-save-buffers-enhanced)
(auto-save-buffers-enhanced t)
(setq auto-save-buffers-enhanced-save-scratch-buffer-to-file-p 1)
(setq auto-save-buffers-enhanced-exclude-regexps '("\\.txt" "\\.el" "\\.tex"))
I use a slight variation of the function by #paprika when I want to create a no-file visiting buffer:
(defun lawlist-new-buffer ()
"Create a new buffer -- \*lawlist\*"
(interactive)
(let* (
(n 0)
bufname)
(catch 'done
(while t
(setq bufname (concat "*lawlist"
(if (= n 0) "" (int-to-string n))
"*"))
(setq n (1+ n))
(if (not (get-buffer bufname))
(throw 'done nil)) ))
(switch-to-buffer (get-buffer-create bufname))
(text-mode) ))
I have combined the solutions posted so far into one function:
(defun --scratch-buffer(&optional reset)
"Get the *scratch* buffer object.
Make new scratch buffer unless it exists.
If RESET is non-nil arrange it that it can't be killed."
(let ((R (get-buffer "*scratch*")))
(unless R
(message "Creating new *scratch* buffer")
(setq R (get-buffer-create "*scratch*") reset t))
(when reset
(save-excursion
(set-buffer R)
(lisp-interaction-mode)
(make-local-variable 'kill-buffer-query-functions)
(add-hook 'kill-buffer-query-functions '(lambda()(bury-buffer) nil)
)))
R))
To apply this function in your .emacs use:
(--scratch-buffer t)
(run-with-idle-timer 3 t '--scratch-buffer)
This will make the scratch buffer indestructible in the first place, and if saved it will be recreated. Additionally we can use a shortcut function scratch to bring up the buffer quickly:
(defun scratch()
"Switch to *scratch*. With prefix-arg delete its contents."
(interactive)
(switch-to-buffer (--scratch-buffer))
(if current-prefix-arg
(delete-region (point-min) (point-max))
(goto-char (point-max))))
In the past it has proven useful to know the original startup-directory from which Emacs was started. This is either the value of desktop-dirname or the default-directory local variable of the scratch-buffer:
(defvar --scratch-directory
(save-excursion (set-buffer "*scratch*") default-directory)
"The `default-directory' local variable of the *scratch* buffer.")
(defconst --no-desktop (member "--no-desktop" command-line-args)
"True when no desktop file is loaded (--no-desktop command-line switch set).")
(defun --startup-directory ()
"Return directory from which Emacs was started: `desktop-dirname' or the `--scratch-directory'.
Note also `default-minibuffer-frame'."
(if (and (not --no-desktop) desktop-dirname)
desktop-dirname
--scratch-directory))
So --startup-directory will always return the base directory of your makefile, TODO-file etc. In case there is no desktop (--no-desktop commandline-switch or no desktop-file) the --scratch-directory variable will hold directory Emacs was once started under.
find answer in EmacsWiki: http://www.emacswiki.org/emacs/RecreateScratchBuffer
(defun create-scratch-buffer nil
"create a scratch buffer"
(interactive)
(switch-to-buffer (get-buffer-create "*scratch*"))
(lisp-interaction-mode))
To add to the accepted answer, if you have ILO mode on (and it is autocompleting after C-x b, thus not letting you write *scratch*), then try:
C-xb C-b*scratch* RET
C-x b C-b *scratch* RET
C-xb and then type *scratch* ↩︎
to create a new buffer which is in lisp interaction mode also.