Select other window in Emacs at startup - emacs

Suppose I have two text files A.txt and B.txt. I choose to open both from Emacs using
emacs -no-splash -mm A.txt B.txt
Now the frame is split in two parts vertically, and file A is shown in the left window and file B in the right window. However file B is automatically selected by Emacs. I can move the point to the other window by entering C-x o or ESC-: (other-window 1). But I would like to do this automatically, for instance at the command line or in the .emacs file.
I tried
emacs -no-splash -mm --eval `(other-window 1)` A.txt B.txt
but it did not work..

The following seems to work: Enter in .emacs :
(add-hook 'emacs-startup-hook '(lambda () (other-window 1)))

Put the following in your ~/.emacs file:
(add-hook 'emacs-startup-hook '(lambda () (select-first-buffer-in-list command-line-args)))
(defun select-first-buffer-in-list (list)
(let (buffer)
(while list
(if (setq buffer (get-file-buffer (car list)))
(progn (select-window (get-buffer-window buffer))
(setq list nil))
(setq list (cdr list))))))
It will check which of the command line parameters correspond to a buffer. It selects a window displaying the buffer of the first such parameter.

Independent of the order of the command line parameters, this approach finds the left-most, upper-most window and selects it. Put the following code in your .emacs file:
(add-hook 'emacs-startup-hook '(lambda () (select-upper-left-window)))
(defun select-upper-left-window ()
(let (window)
(while (setq window (window-in-direction 'above nil t))
(select-window window))
(while (setq window (window-in-direction 'left nil t))
(select-window window))))

This would keep a single window with "B.txt"
emacs --find-file A.txt B.txt -Q -eval "(delete-other-windows)"

Is there a reason you don't want to just reverse the order of the file names on the command line?

Related

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 make grep-find to always open in window where there's *ansi-term*

When I work on a project I always have ansi-term with bash shell in one window. Is it possible to direct grep-find to always open in window where I have *ansi-term* buffer, if it exists?
I have function that run grep-find over git repo I'm in. I only need to direct the function to open in window where I have *ansi-term*.
This seems to do what you are requesting, but I have only tested very briefly.
(defadvice find-grep (around switch-to-ansi-term activate)
(let ((b (get-buffer "*ansi-term*")))
(and b (select-window (get-buffer-window b t))) )
ad-do-it
(and b (delete-window)) )
I've created those 2 functions:
(defun windows-buffer-match (regex)
"return window for open buffer that match regex"
(let ((list '()))
(walk-windows (lambda (window)
(let ((buffer (window-buffer window)))
(if (string-match regex (buffer-name buffer))
(setq list (cons window list))))))
list))
(defun window-match-jump (regex)
(interactive "sBuffer: ")
(let ((windows (windows-buffer-match regex)))
(if (not (null windows))
(select-window (car windows)))))
and as #tripleee suggest in his answer, I use it with devadvice:
(defadvice find-grep (around switch-to-ansi-term activate)
(window-match-jump (regexp-quote "*ansi-term*")))
Also this function can be use to open grep in window with differnt name then ansi-term.
You could use a FIFO. In your ansi-term
mkfifo ~/ansi
while :; do cat ~/ansi; done
and elsewhere
grep xyz abc > ~/ansi

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.

How to format all files under a dir in emacs?

In emacs, I format a file as:
1) C-x h (or M-x mark-whole-buffer)
2) C-M-\ (or M-x indent-region)
I need help show me how to format all files under a dir?
Here's another way to go about it:
First, evaluate this function definition in your *scratch* buffer:
(defun indent-marked-files ()
(interactive)
(dolist (file (dired-get-marked-files))
(find-file file)
(indent-region (point-min) (point-max))
(save-buffer)
(kill-buffer nil)))
Next, open a Dired buffer at the top level of the directory under which you want to change all of the files. Give the dired command a numeric prefix so that it will ask for the switches to give to the ls command, and add the R (recurse) switch: C-u C-x d R RET your-directory RET.
Next, mark all of the regular files in the recursive directory listing: first * / to mark all the directories, then * t to toggle the selection.
Finally, run the above command: M-x indent-marked-files.
Be aware that if you already have any buffers visiting any of the target files, they'll be killed by indent-marked-files. Also be aware that none of the file changes will be undoable; use with caution! I tested it in a simple case and it seems to work as described, but I make no guarantees.
Create a macro to do it. Open the directory in dired (C-x d), and then:
Put point on the first file.
Press F3 to start recording the macro.
Hit RET to open the file.
Format it with C-x h, C-M-\.
Bury the buffer with M-x bury-buffer. You'll be back in the dired buffer.
Go down one line.
Hit F4 to stop recording the macro.
So now you have a macro that opens the file on the current line, formats it, drops back to dired, and puts point to the next line. Run it with F4 as many times as needed.
I am late in answering this question, but this is still the first result on Google.
I made an improvement to #Sean's answer to remove the need for the complicated Dired interaction.
(defun my/indent-files (directory extension)
(interactive (list (read-directory-name "Directory: ")
(read-string "File extension: ")))
(dolist (file (directory-files-recursively directory extension))
(find-file file)
(indent-region (point-min) (point-max))
(save-buffer)
(kill-buffer nil)))
Sample use: M-x my/indent-files then ~/Dropbox then .org.
This will run indent-region on the all .org files, save the buffer then kill it.
You can try this:
(defun format-all-files (regexp)
"Format multiple files in one command."
(interactive "sFind files matching regexp (default all): ")
(when (string= "" regexp) (setq regexp ""))
(let ((dir (file-name-directory regexp))
(nodir (file-name-nondirectory regexp)))
(when dir (cd dir))
(when (string= "" nodir) (setq nodir "."))
(let ((files (directory-files "." t nodir nil t))
(errors 0))
(while (not (null files))
(let ((filename (car files)))
(if (file-readable-p filename)
(progn
(set-buffer (find-file-noselect filename))
(mark-whole-buffer)
(indent-region-or-balanced-expression)
(save-buffer)
(kill-buffer (current-buffer)))
(incf errors))
(setq files (cdr files))))
(when (> errors 0)
(message (format "%d files were unreadable." errors))))))
But note that this must load the file-specific mode over and over again, which may involve syntax highlighting or whatever initialization happens on a load of that type. For really big formatting jobs, a batch program such as indent which only indents will be much faster.

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