I am using vc-dir and I have a few dozen "unregistered" files I would like to delete. I searched the menus, the Internet, and the key bindings, but I haven't figured out how to do it.
Is this truly impossible?
Looks like it's not implemented. Try this. The directory handling is derived from the interactive form of delete-directory. If any of the deletions cause an error we bail out, but we still refresh the *vc-dir* buffer so that we can see what has been done.
(defun my-vc-dir-delete-marked-files ()
"Delete all marked files in a `vc-dir' buffer."
(interactive)
(let ((files (vc-dir-marked-files)))
(if (not files)
(message "No marked files.")
(when (yes-or-no-p (format "%s %d marked file(s)? "
(if delete-by-moving-to-trash "Trash" "Delete")
(length files)))
(unwind-protect
(mapcar
(lambda (path)
(if (and (file-directory-p path)
(not (file-symlink-p path)))
(when (or (not (directory-files
path nil directory-files-no-dot-files-regexp))
(y-or-n-p
(format "Directory `%s' is not empty, really %s? "
path (if delete-by-moving-to-trash
"trash" "delete"))))
(delete-directory path t t))
(delete-file path t)))
files)
(revert-buffer))))))
(eval-after-load 'vc-dir
'(define-key vc-dir-mode-map (kbd "k") 'my-vc-dir-delete-marked-files))
Related
Where can I find the all Emacs' elisp scripts? I don't mean scripts users developed or installed themselves, but the common elisp script already there.
For example,
if I have a function like describe-char or insert-file, how can I find the file contained these functions?
Ctrl-h f will tell a function's explanation and where it is contained.
And if you want a function to do this automaticlly, here's a draft:
(defun my-find-lisp-object-file-name (function)
"Display the lisp file name of FUNCTION (a symbol)."
(interactive
(let ((fn (function-called-at-point))
(enable-recursive-minibuffers t)
val)
(setq val (completing-read (if fn
(format "Describe function (default %s): " fn)
"Describe function: ")
obarray 'fboundp t nil nil
(and fn (symbol-name fn))))
(list (if (equal val "")
fn (intern val)))))
(if (null function)
(message "You didn't specify a function")
(setq object-file-name (find-lisp-object-file-name function (symbol-function function)))
(if (eq object-file-name 'C-source)
(message "%s is in %s" function "C source code")
(setq buff (find-function-search-for-symbol function nil object-file-name))
(setq buf-name (buffer-name(car buff)))
(setq buf-pos (cdr buff))
(switch-to-buffer (car buff))
(message "%s is in %s(%s, %d)" function object-file-name buf-name buf-pos))))
I guess M-x locate-library RET <libname> RET could be an answer tho it needs the library name rather than the function name. Else, M-x find-function-other-window will not just tell you where the file is, but instead will open the file, after which you can use M-x pwd to know where you are.
One more thing: you can do C-h v load-path RET to see the directories that Emacs uses to find its libraries, so that should give you a good idea of where all the bundled Elisp files reside.
INITIAL DRAFT (March 25, 2014): First rough draft.
EDIT (March 26, 2014): Added a global-set-key. Added one more car to the final message in order to fully extract the path of the file name from the list of button text properties. Added some colorization to the initial and final messages. Added return cursor to beginning of buffer at the end of the function. Added options for find-variable-other-window and find-function-other-window. Added conditions so that no messages are generated if there is no file name.
Here is a fun little function that I whipped up -- it displays a message with a file path if an *.el file is displayed in the *Help* buffer.
(global-set-key (kbd "C-h z") 'lawlist-describe-find-function-variable)
(defun lawlist-describe-find-function-variable ()
"Describe or find a function / variable. Displays the path of filename."
(interactive)
(message (concat
(propertize "Describe" 'face 'font-lock-keyword-face)
" ["
(propertize "f" 'face 'font-lock-warning-face)
"]unction / ["
(propertize "v" 'face 'font-lock-warning-face)
"]ariable | "
(propertize "Find" 'face 'font-lock-keyword-face)
" ["
(propertize "F" 'face 'font-lock-warning-face)
"]unction / ["
(propertize "V" 'face 'font-lock-warning-face)
"]ariable"))
(let* (
(select-f-or-v (read-char-exclusive))
function
variable)
(cond
((eq select-f-or-v ?f)
(setq function (read (read-string "Please enter a function name: ")))
(describe-function function)
(select-window (get-buffer-window "*Help*")))
((eq select-f-or-v ?v)
(setq variable (read (read-string "Please enter a variable name: ")))
(describe-variable variable)
(select-window (get-buffer-window "*Help*")))
((eq select-f-or-v ?F)
(setq function (read (read-string "Please enter a function name: ")))
(find-function-other-window function)
(when buffer-file-name
(message (propertize buffer-file-name 'face 'font-lock-warning-face))))
((eq select-f-or-v ?V)
(setq variable (read (read-string "Please enter a variable name: ")))
(find-variable-other-window variable)
(when buffer-file-name
(message (propertize buffer-file-name 'face 'font-lock-warning-face))))
(t
(message "Thanks and come again!")))
(when (and
(equal (buffer-name) "*Help*")
(save-excursion
(goto-char (point-max))
(re-search-backward "\\(`*[.]el'\\)" nil t)))
(goto-char (point-max))
(re-search-backward "\\(`*[.]el'\\)" nil t)
(message
(propertize
(car (cdr (car (nthcdr 1 (text-properties-at (point))))))
'face 'font-lock-warning-face) )
(goto-char (point-min))) ))
If you use lispy minor mode:
You can open the definition of current function by positioning the point
on the open paren of that function and pressing F.
You can open the definition of current variable by marking it and
pressing F.
You can find all definitions in current directory with g.
You get a helm completion interface for all tags in all Elisp files.
Each line will have the tag in the first column and the file in the second.
My installation's base Elisp directory has 19838 tags, and the completion is fast enough.
You can find all definitions in current directory and its sub-directories
with lispy-goto-recursive. It takes minutes to parse and seconds to bring
up the completion interface. But it allows to interactively search through
all the files in the Emacs source - that's 89675 tags.
A sample search: there are 55 top-level tags that contain insert-file spread
around about 20 files.
Most of them are functions, but the top-level tag (define-key ctl-x-map "i" 'insert-file)
is also matched and can be viewed without opening the file.
You can grab the source of Emacs (if you installed Emacs you probably have .elc files - which are compiled elisp files), and search for the function, if you're on Unix like system you can use ack or find/grep all lisp files are in lisp directory
cd Emacs-24.4/lisp
ack 'defun some-function'
find . -name '*.el' | xargs grep 'defun some-function'
Sometimes I open files from different source trees to compare with current tree.
I would like to have a function that kills all these opened files that does not reside in a "default tree" that the user is prompt to keep or change at the time the function is executed.
Set default-tree to the name of the directory you want (it must be an absolute path).
(defun bruce-connor-buffer-killer ()
(interactive)
(unless (file-directory-p default-tree) (error "You forgot to set `default-tree'."))
(let ((case-fold-search nil)
(dir-length (length default-tree)))
(dolist (buffer (buffer-list))
(when (buffer-file-name buffer)
(unless (equal t (compare-strings
(expand-file-name (buffer-file-name buffer)) 0 dir-length
default-tree 0 nil)))
(kill-buffer buffer)))))
I want to rename a file that is bound current buffer in Emacs.
I found following elisp from this article:
How do I rename an open file in Emacs?
;; source: http://steve.yegge.googlepages.com/my-dot-emacs-file
(defun rename-file-and-buffer (new-name)
"Renames both current buffer and file it's visiting to NEW-NAME."
(interactive "sNew name: ")
(let ((name (buffer-name))
(filename (buffer-file-name)))
(if (not filename)
(message "Buffer '%s' is not visiting a file!" name)
(if (get-buffer new-name)
(message "A buffer named '%s' already exists!" new-name)
(progn
(rename-file name new-name 1)
(rename-buffer new-name)
(set-visited-file-name new-name)
(set-buffer-modified-p nil))))))
It works fine, but if possible I want to set current file name as a default value.
How would I write this?
There recently was a
post on the
Emacs Redux blog on this subject.
Basically it is implemented in the Prelude
configuration (by the same author) which you can install to get this behaviour and tons of other interesting stuff. Otherwise, you can put in your configuration file only the relevant snippet (taken from the blog post above):
(defun rename-file-and-buffer ()
"Rename the current buffer and file it is visiting."
(interactive)
(let ((filename (buffer-file-name)))
(if (not (and filename (file-exists-p filename)))
(message "Buffer is not visiting a file!")
(let ((new-name (read-file-name "New name: " filename)))
(cond
((vc-backend filename) (vc-rename-file filename new-name))
(t
(rename-file filename new-name t)
(set-visited-file-name new-name t t)))))))
(global-set-key (kbd "C-c r") 'rename-file-and-buffer)
Could you elaborate more on why you need to do it?
What are the conditions?
Because this has never come up since I started using Emacs.
But here's what I do sometimes when I want to rename something:
Say I'm editing spam-spom-spam.cc. And I want to fix the name.
C-x d
C-s spo
C-x C-q
DEL a
C-c C-c
This may seem like a lot of commands, but they flow quite naturally.
As a bonus, you get an overview of your directory and of how the
newly renamed file looks there.
No external tool needed for this. See
http://www.gnu.org/software/emacs/manual/html_node/emacs/Wdired.html
After changing the file-name in the dired-buffer, the buffer-name is changed too.
I have generated the TAGS file using ctags for the *.h and *.cpp file in a directory.
How to find the files in TAGS file.
Assuming i have generated the TAGS file for the files one.h two.h three.h. What is the command to find the file one.h, two.h, three.h not the tags in those files.
Assuming that you simply want to know how to use the TAGS file...
Load the TAGS file with:
M-x visit-tags-table RET TAGS file or parent directory RET
Then you can use it with:
M-. (i.e. find-tag)
M-x tags-search RET pattern RET
(with M-, to move to each successive match)
M-x tags-apropos RET pattern RET
M-x tags-query-replace RET pattern RET replacement RET
Those are the defaults. Naturally there are enhancements available:
http://www.emacswiki.org/emacs/EmacsTags
Personally I use etags-select (which you can obtain via ELPA), and I have M-. bound to etags-select-find-tag.
I wrote this a couple of years ago, I haven't gotten around to releasing it yet, though... Enjoy!
The function tags-extra-find-file will let you visit a file in the current tags table, complete with file-name completion. This is perfect if you have many source files spread out over a large number of directories. (Honestly, I use this at least one hundred times every day...)
(defun tags-extra-get-all-tags-files ()
"Return all, fully qualified, file names."
(save-excursion
(let ((first-time t))
(while (visit-tags-table-buffer (not first-time))
(setq first-time nil)
(setq res
(append res (mapcar 'expand-file-name (tags-table-files)))))))
res))
(defun tags-extra-find-file (name)
"Edit file named NAME that is part of the current tags table.
The file name should not include parts of the path."
(interactive
(list
(completing-read "Name of file: "
;; Make an a-list of all files without path.
(mapcar
(lambda (file)
(cons (file-name-nondirectory file) nil))
(tags-extra-get-all-tags-files)))))
(let ((files (tags-extra-get-all-tags-files))
(done nil)
(name-re (concat "^" (regexp-quote name) "$")))
(while (and (not done)
files)
(let ((case-fold-search t))
(if (string-match name-re (file-name-nondirectory (car files)))
(setq done t)
(setq files (cdr files)))))
(if files
(find-file (car files))
(error "File not found in the tags table."))))
This correction works in emacs 26.3. With an old etags, M-. would accept a file name, such as Setup.cpp, and visit the file wherever etags found it. Very handy with lots of files in many directories. No need to remember what directory the file was in to visit it. I'm surprised that's not an out-of-the-box feature!
(defun tags-extra-get-all-tags-files ()
"Return all, fully qualified, file names."
(setq res nil)
(save-excursion
(let ((first-time t))
(while (visit-tags-table-buffer (not first-time))
(setq first-time nil)
(setq res
(append res (mapcar 'expand-file-name (tags-table-files)))))))
res)
Something like this? It might not be entirely robust.
(defun visit-tags-table-and-files (file)
"Run `visit-tags-table FILE', then visit all the referenced files."
(interactive "fTags file: ")
(visit-tags-table file)
(save-excursion
(set-buffer (get-file-buffer tags-file-name))
(mapc #'find-file (tags-table-files)) ) )
Thanks #Lindydancer's answer and emacswiki ido. The emacswiki version only support one tag file. Combining them which allows me jumping to any file in all TAG files. Petty close to the sublime text's goto anything.
Here is the code.
;;; using ido find file in tag files
(defun tags-extra-get-all-tags-files ()
"Return all, fully qualified, file names."
(save-excursion
(let ((first-time t)
(res nil))
(while (visit-tags-table-buffer (not first-time))
(setq first-time nil)
(setq res
(append res (mapcar 'expand-file-name (tags-table-files)))))
res)))
(defun ido-find-file-in-tag-files ()
(interactive)
(find-file
(expand-file-name
(ido-completing-read
"Files: " (tags-extra-get-all-tags-files) nil t))))
When trying to kill a buffer that contains changes in Emacs, the message:
" Buffer [buffer] modified; kill anyway? (yes or no)" is displayed.
Instead of this I'd like to have Emacs ask me if I want to:
1. View a diff of what changed,
2. Save the buffer,
3. Kill the buffer.
How?
The answer lies in using advice, because the hooks normally run when killing buffers run after the "buffer modified" prompt you want to change.
The following advice does what you want (I think). A couple of notes:
When running the diff, the original buffer is marked as not modified - but you'll really need to save it.
The other buffer in the diff doesn't get deleted
(defadvice kill-buffer (around my-kill-buffer-check activate)
"Prompt when a buffer is about to be killed."
(let* ((buffer-file-name (buffer-file-name))
backup-file)
;; see 'backup-buffer
(if (and (buffer-modified-p)
buffer-file-name
(file-exists-p buffer-file-name)
(setq backup-file (car (find-backup-file-name buffer-file-name))))
(let ((answer (completing-read (format "Buffer modified %s, (d)iff, (s)ave, (k)ill? " (buffer-name))
'("d" "s" "k") nil t)))
(cond ((equal answer "d")
(set-buffer-modified-p nil)
(let ((orig-buffer (current-buffer))
(file-to-diff (if (file-newer-than-file-p buffer-file-name backup-file)
buffer-file-name
backup-file)))
(set-buffer (get-buffer-create (format "%s last-revision" (file-name-nondirectory file-to-diff))))
(buffer-disable-undo)
(insert-file-contents file-to-diff nil nil nil t)
(set-buffer-modified-p nil)
(setq buffer-read-only t)
(ediff-buffers (current-buffer) orig-buffer)))
((equal answer "k")
(set-buffer-modified-p nil)
ad-do-it)
(t
(save-buffer)
ad-do-it)))
ad-do-it)))
You'll want to write some code to put in the kill-buffer-hooks and write-file-functions lists. Conceptually, what you want to do is
test if the buffer has been modified
display your message and get a
response, and do what's requested
then clear the modified flag so the
normal kill-buffer doesn't come back
and ask again.