I have the function below in my .emacs which I use quite frequently to put the filename/path of a local file in the current buffer. It is working nicely, however, I'd like it to have ido completion. But I seem unable to achieve that... maybe you can help me.
(defun insert-file-name (filename &optional args)
"Insert name of file FILENAME into buffer after point.
Prefixed with \\[universal-argument], expand the file name to
its fully canocalized path. See `expand-file-name'.
Prefixed with \\[negative-argument], use relative path to file
name from current directory, `default-directory'. See
`file-relative-name'.
The default with no prefix is to insert the file name exactly as
it appears in the minibuffer prompt."
;; Based on insert-file in Emacs -- ashawley 20080926
(interactive "*fInsert file name: \nP")
(cond ((eq '- args)
(insert (expand-file-name filename)))
((not (null args))
(insert (filename)))
(t
(insert (file-relative-name filename)))))
With ido-everywhere turned-on, (interactive "f") will normally use ido-read-file-name, which will not only provide automatic completion for your function, but also almost everywhere.
If you want to have ido completion only for this function, but not everywhere, you can explicitly call ido-read-file-name in the interactive form. One side effect of using ido in your case is that it seems to always return a full path, making the distinction between filename and (expand-file-name filename) effectless.
(defun insert-file-name (filename &optional args)
"Insert name of file FILENAME into buffer after point.
Prefixed with \\[universal-argument], expand the file name to
its fully canocalized path. See `expand-file-name'.
Prefixed with \\[negative-argument], use relative path to file
name from current directory, `default-directory'. See
`file-relative-name'.
The default with no prefix is to insert the file name exactly as
it appears in the minibuffer prompt."
;; Based on insert-file in Emacs -- ashawley 20080926
(interactive `(,(ido-read-file-name "File Name: ")
,current-prefix-arg))
(cond ((eq '- args)
(insert (expand-file-name filename)))
((not (null args))
(insert filename))
(t
(insert (file-relative-name filename)))))
Related
I have a list of org files under a directory:
> org-file1.org
> org-file2.org
> org-file3.org
> ...
> org-fileN.org
I want to extract their titles (using #+title tag) as links as follows:
[[file:org-file1.org][title for org file 1]]
[[file:org-file2.org][title for org file 2]]
[[file:org-file3.org][title for org file 3]]
...
[[file:org-fileN.org][title for org file N]]
How can I extract these as a list using Emacs Lisp?
You could use the org-element-api for this, but in this case it is probably easier/faster to simply search by regexp using looking-at-p. To get all files in a directory, there is directory-files(-recursively). Then finally you could achieve it using the following function:
(defun extract-org-directory-titles-as-list (&optional dir)
(interactive "D")
(print
(delete nil
(let ((case-fold-search t))
(mapcar (lambda (f)
(when (string-match "org$" f)
(with-temp-buffer
(insert-file-contents-literally
(concat (file-name-as-directory dir) f))
(while (and (not (looking-at-p "#\\+TITLE:"))
(not (eobp)))
(forward-line))
(when (not (eobp))
(cons f (substring (thing-at-point 'line) 9 -1))))))
(directory-files dir))))))
(defun insert-directory-org-file-titles (&optional dir)
(interactive "D")
(let ((files-titles (extract-org-directory-titles-as-list dir)))
(dolist (ft files-titles)
(insert (concat "[[file:" (car ft)"][" (cdr ft) "]]\n")))))
If you prefer to just have it as a (a)list, like you asked, then just use extract-org-directory-titles-as-list.
Here's some code that can be used on a single file to get the title. It's part of an org mode file that can be used for testing. Save it as an Org mode file, visit it in Emacs and type C-c C-c on the code block. Change the title and evaluate the code block again.
#+OPTIONS: toc:nil
#+TITLE: This is a very nice title, don't you think?
#+AUTHOR: A.U. Thor
* foo
bar
* Code
#+begin_src elisp :results drawer
(save-excursion
(goto-char (point-min))
(let ((case-fold-search t))
(search-forward-regexp "^#\\+TITLE:")
(org-element-property :value (org-element-context (org-element-at-point)))))
#+end_src
#+RESULTS:
:results:
This is a very nice title, don't you think?
:end:
The code block goes to the beginning of the buffer, searches forward for the string #+TITLE: at the beginning of a line (the search is case-insensitive) and then uses some functions from the org-element library to parse the buffer at point, get the context and get the :value property out of it.
In order to make it into a complete solution, you have to:
make it more robust: check that this is a title keyword not just some random junk that happened to satisfy the match, although that's unlikely; but better safe than sorry.
wrap it in a loop that does a find-file on every file in the directory and gets the title for each file and returns a list of tuples: (filename title) that you can easily use to create your links.
I have set this in my .emacs file:
(add-hook 'TeX-mode-hook
(lambda ()
(setq TeX-command-default "LaTeX"))
(add-hook 'LaTeX-mode-hook
(lambda ()
(setq TeX-command-default "LaTeX"))
I see that C-c C-c is bound to TeX-command-master, which calls TeX-command-query. But since my (TeX-master-file) is "<none>", I expect the default command to be called, but keeps wanting to invoke "View" instead of "LaTeX".
If you check the source for TeX-command-query you'll find that it checks the modification date of the tex (lines 4-9) and bbl (lines 10-19) files involved in your document. Unless those files are more recent than the output file and there is no known next command to be performed (lines 20-22) it will use the "View" command as default (line 23).
This behaviour is of course sensible because normally you don't want to recompile unless there are changes (modified tex files). Apart from "patching" the command [posted below, would not really recommend to use because it will not receive automatic updates ;-) ] there isn't really anything you can do.
If you decide to use the patched command, just put is somewhere in your init file after the original command has been loaded. You could for example wrap it into (replace ;; BODY by code)
(eval-after-load "tex-buf"
'(progn
;; BODY
))
Here comes the patched command:
(defun TeX-command-query (name)
"Query the user for what TeX command to use."
(let* ((default
(cond ((if (string-equal name TeX-region)
(TeX-check-files (concat name "." (TeX-output-extension))
(list name)
TeX-file-extensions)
(TeX-save-document (TeX-master-file)))
TeX-command-default)
((and (memq major-mode '(doctex-mode latex-mode))
;; Want to know if bib file is newer than .bbl
;; We don't care whether the bib files are open in emacs
(TeX-check-files (concat name ".bbl")
(mapcar 'car
(LaTeX-bibliography-list))
(append BibTeX-file-extensions
TeX-Biber-file-extensions)))
;; We should check for bst files here as well.
(if LaTeX-using-Biber TeX-command-Biber TeX-command-BibTeX))
((TeX-process-get-variable name
'TeX-command-next
;; HERE COMES THE PATCH
;; was TeX-command-View
TeX-command-default))
;; END OF PATCH
(TeX-command-Show)))
(completion-ignore-case t)
(answer (or TeX-command-force
(completing-read
(concat "Command: (default " default ") ")
(TeX-mode-specific-command-list major-mode) nil t
nil 'TeX-command-history))))
;; If the answer is "latex" it will not be expanded to "LaTeX"
(setq answer (car-safe (TeX-assoc answer TeX-command-list)))
(if (and answer
(not (string-equal answer "")))
answer
default)))
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))))
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".