I need to get the full path of the file that I'm editing with emacs.
Is there a function for that?
If not, what would be the elisp function for getting that?
How can I copy the result (path name) to a clipboard so that I can reuse it?
I'm using Mac OS X and Aqumacs.
(setq filepath (get-fullpath-current-file)) ???
(copy-to-clipboard 'filepath) ???
ADDED
(defun show-file-name ()
"Show the full path file name in the minibuffer."
(interactive)
(message (buffer-file-name))
(kill-new (file-truename buffer-file-name))
)
(global-set-key "\C-cz" 'show-file-name)
Combining the two answers that I got, I could get what I want. Thanks for the answers. And some more questions.
What's for (file-truename)?
Can I copy the path name to System(OS)'s clipboard, not the kill ring so that I can use the info with the other apps?
It's the built-in function buffer-file-name that gives you the full path of your file.
The best thing to do is to have your emacs window to always show your system-name and the full path of the buffer you're currently editing :
(setq frame-title-format
(list (format "%s %%S: %%j " (system-name))
'(buffer-file-name "%f" (dired-directory dired-directory "%b"))))
You can also do something like this :
(defun show-file-name ()
"Show the full path file name in the minibuffer."
(interactive)
(message (buffer-file-name)))
(global-set-key [C-f1] 'show-file-name) ; Or any other key you want
To borrow from Jérôme Radix's answer, if you just want to quickly see the file path of the current buffer, you can do M-: buffer-file-name.
Alternately, type (buffer-file-name) in the buffer somewhere and run C-x C-e on the closing parenthesis (this will work in any mode, not just lisp-mode).
My trick is to do a C-x C-f like to open a file, it wil prefill the minibuff with the current file path, C-g to quit. Faster than M-: buffer-file-name but far far uglier than any other methods.
The direct implementation of what you want is:
(defun copy-full-path-to-kill-ring ()
"copy buffer's full path to kill ring"
(interactive)
(when buffer-file-name
(kill-new (file-truename buffer-file-name))))
That said, I find it incredibly useful to be able to get the full path of what is in the minibuffer, and this is what I use:
(define-key minibuffer-local-completion-map "\C-r" 'resolve-sym-link)
(defun resolve-sym-link ()
"Try to resolve symbolic links into true paths."
(interactive)
(beginning-of-line)
(let* ((file (buffer-substring (point)
(save-excursion (end-of-line) (point))))
(file-dir (file-name-directory file))
(file-true-dir (file-truename file-dir))
(file-name (file-name-nondirectory file)))
(delete-region (point) (save-excursion (end-of-line) (point)))
(insert (concat file-true-dir file-name))))
And then if I want it in the clipboard, I just kill the line (C-a C-k). But we could easily copy the truename to the clipboard in the above command, just change the last line to be:
(insert (kill-new (concat file-true-dir file-name)))))
The new part is the call to 'kill-new which puts the string in the kill ring.
No need for extra function, just
M-! pwd
C-x C-b shows a list of buffers and the file path for each buffer where applicable.
C-x C-d, also callable via M-x list-directory, will show you the directory for your current file, and you only need to hit the "Enter" key to clear the minibuffer. Additional details are available here.
I have the following code already in use for a long time.
It copies the full file path to the kill ring when I press the middle mouse button on the buffer name in the mode-line. It copies just the buffer name to the kill-ring when I press shift-mouse-2 on the buffer-name in the mode-line.
(defun copy-buffer-file-name (event &optional bufName)
"Copy buffer file name to kill ring.
If no file is associated with buffer just get buffer name.
"
(interactive "eP")
(save-selected-window
(message "bufName: %S" bufName)
(select-window (posn-window (event-start event)))
(let ((name (or (unless bufName (buffer-file-name)) (buffer-name))))
(message "Saved file name \"%s\" in killring." name)
(kill-new name)
name)))
(define-key mode-line-buffer-identification-keymap [mode-line mouse-2] 'copy-buffer-file-name)
(define-key mode-line-buffer-identification-keymap [mode-line S-mouse-2] '(lambda (e) (interactive "e") (copy-buffer-file-name e 't)))
C-u C-x C-b lists buffers currently visiting files.
Can I copy the path name to System(OS)'s clipboard, not the kill ring so that I can use the info with the other apps?
You can if you shell out to something like xclip (Linux), pbcopy (Mac), putclip (Cygwin).
I personally use wrapper scripts c and p for copy and paste respectively, the first reading from standard input, the latter writing to standard output. That way, this works on all my development platforms:
(shell-command (format "echo '%s' | c" buffer-file-name))
I find this more reliable and configurable than using the Emacs clipboard support. For example, my c command copies the input to all 3 clipboards on Linux (primary, secondary, clipboard), so I can paste with either Ctrl-V or middle click.
The simplest way and would be
(buffer-name)<(C-x)(C-e)> for the file name to appear in the echo area
(buffer-name)<(C-u)(C-x)(C-e)> would print the location <here>
Borrowing from Trey Jackson
I came up with this:
(defun buffer-kill-path ()
"copy buffer's full path to kill ring"
(interactive)
(kill-new (buffer-file-name)))
You can find more information on site
copy-buffer-file-name-as-kill from [0] does exactly what you need I think. It also has the option to copy just directory name, or just file name.
[0] http://www.emacswiki.org/emacs/download/buffer-extension.el
To do what the title says (show the current file path in the minibuffer) you can do this:
M-x buffer-file-name
To permanently show it in the mode-line, you can use this:
(setq-default mode-line-buffer-identification
(list 'buffer-file-name
(propertized-buffer-identification "%12f")
(propertized-buffer-identification "%12b")))
Or this (color + abbrev) :
(setq-default mode-line-buffer-identification
'((:eval
(list (propertize (abbreviate-file-name
(expand-file-name buffer-file-name))
'face 'font-lock-string-face)))))
Related
For example: I have a file longest_substring_no_repeating_chars.cc. One day I want to rename it to longest_substr_no_repeating_chars.cc. How do I do it by editing the old name? Or is there any convenient way to do it?
Assuming you want to rename the file you're currently editing you can define a function like this one:
(defun rename-file-and-buffer ()
"Renames current buffer and file it is visiting."
(interactive)
(let ((name (buffer-name))
(filename (buffer-file-name)))
(if (not (and filename (file-exists-p filename)))
(message "Buffer '%s' is not visiting a file!" name)
(let ((new-name (read-file-name "New name: " filename)))
(cond ((get-buffer new-name)
(message "A buffer named '%s' already exists!" new-name))
(t
(rename-file name new-name 1)
(rename-buffer new-name)
(set-visited-file-name new-name)
(set-buffer-modified-p nil)))))))
And the you can bind it to a key combo like C-c r
(global-set-key (kbd "C-c r") 'rename-file-and-buffer)
Otherwise, #Oleg's suggestion to use dired is a great option.
You can do this in dired mode. R shortcut invokes dired-do-rename where you
can press down to get back the old name.
It's even easier if you use dired-x, just add to your init file.
(require 'dired-x)
Then you can press C-x C-j R to edit as you need to, then
q to go back to your buffer.
Another possibility: M-x wdired-change-to-wdired-mode. In this mode you can
edit files directly. Press C-c C-c when you want to commit your changes or
C-c ESC to cancel them.
I'm remodeling my toolchain away from R + TeXShop to what I hope is a more efficient Sweave -> LaTeX -> SyncteX -> pdfview (skim) through emacs (Aquamacs, to be specific) AUCTeX-mode (with emacs-speaks-statsitics' sweave minor-mode). Everything works great with SyncteX from the AUCTeX -> pdfview chain, and everything works fine compiling from Sweave to .pdf.
The trouble comes in when I add Sweave as the first step. The .Rnw file now becomes the principal original document, and the .tex file it generates is just an intermediate step. Of course, it's the .tex file that SyncteX locks to.
The only changes I've made to my .emacs file are to register two new commands to build the .pdf from the .Rnw.
Can anyone offer advice on how to get emacs to use SyncteX to sync the output .pdf to the .Rnw, instead of the .tex?
Thanks!
Edit 1: Warning: This ended up being a summary of my fumbling around all afternoon. I get very close to the solution but foiled by an error at the very end that I cannot find documentation for. Warning 2: Today was the first time I've ever looked anywhere near this deep into emacs' inner workings. There's bound to be errors or inefficiencies.
VitoshKa's answer got me most of the way there. Adding his recommendation to my .emacs (well, Preferences.el, but functionally the same) file caused an Symbol’s value as variable is void: noweb-minor-mode-map error on launch because Aquamacs seems to load the .emacs file before the rest of its init files.
I fixed this by adding (require 'ess-site) (require 'ess-eldoc) immediately before VitoshKa's (define-key noweb-minor-mode-map (kbd "\C-c \C-c") 'Rnw-command-master). Unfortunately, Aquamacs ships with the ess-swv.elc file already in binary and forces the M-n P reader to be acroread. So I added the following edits of a portion of the ess-swv.el file to the bottom of my own .emacs:
(defun ess-makePDFandView ()
(interactive)
(setq namestem (substring (buffer-name) 0 (search ".Rnw" (buffer-name))))
(setq tex-filename (concat "\"" namestem "\".tex"))
(setq my-command-string (concat "pdflatex -synctex=1" tex-filename))
(shell-command my-command-string)
(setq my-command-string (concat "/Applications/Skim.app/Contents/MacOS/Skim \"" namestem ".pdf\" &"))
(shell-command my-command-string))
(define-key noweb-minor-mode-map "\M-nv" 'ess-makePDFandView)
Now emacs will launch skim with the correct pdf name from emacs with either M-n v or C-c C-c View RET. There's still one more snag to get through...
Command-Shift-Click in emacs tries to sync to filename.Rnw.pdf (but discarding the error message at least still causes a correct sync in the pdfviewer).
Command-Shift-Click in the pdfviewer to search back to the source forces emacs to open the filename.tex file and syncs to that. Fortunately, Cameron Bracken has a fix for that. He just doesn't quite go all the way to emacs integration.
So I added this further hack of ess-swv.el to my .emacs:
(defun ess-swv-latex-rnw-sync ()
"Run LaTeX on the product of Sweave()ing the current file."
(interactive)
(save-excursion
(let* ((namestem (file-name-sans-extension (buffer-file-name)))
(latex-filename (concat namestem ".tex"))
(synctex-filename (concat namestem ".synctex.gz"))
(tex-buf (get-buffer-create " *ESS-tex-output*"))
(patchDVI-command-string (concat "Rscript -e \"library('patchDVI');patchSynctex('" synctex-filename "')\"")))
(message "synctex string: %s" patchDVI-command-string)
(message "Running LaTeX on '%s' ..." latex-filename)
(switch-to-buffer tex-buf)
(call-process "latex" nil tex-buf 1 "-synctex=1 " latex-filename)
(switch-to-buffer (buffer-name))
(display-buffer tex-buf)
(message "Finished running LaTeX" )
(message "Running patchDVI...")
(shell-command patchDVI-command-string))))
(define-key noweb-minor-mode-map "\M-nq" 'ess-swv-latex-rnw-sync)
With the thinking that it was the lack patching the DVI and syncing it in... but no! Same behaviour on Command-Shift-Click as above... Back to hacking up ess-swv. I removed the ess-makePDFandView function, and instead added the following to my .emacs:
(defun ess-swv-PDF-rnw-sync (&optional pdflatex-cmd)
"From LaTeX file, create a PDF (via 'texi2pdf' or 'pdflatex', ...), by
default using the first entry of `ess-swv-pdflatex-commands' and display it."
(interactive
(list
(let ((def (elt ess-swv-pdflatex-commands 0)))
(completing-read (format "pdf latex command (%s): " def)
ess-swv-pdflatex-commands ; <- collection to choose from
nil 'confirm ; or 'confirm-after-completion
nil nil def))))
(let* ((buf (buffer-name))
(namestem (file-name-sans-extension (buffer-file-name)))
(latex-filename (concat namestem ".tex"))
(tex-buf (get-buffer-create " *ESS-tex-output*"))
(pdfviewer (ess-get-pdf-viewer))
(pdf-status)
(cmdstr-win (format "start \"%s\" \"%s.pdf\""
pdfviewer namestem))
(cmdstr (format "\"%s\" \"%s.pdf\" &" pdfviewer namestem)))
;;(shell-command (concat "pdflatex " latex-filename))
(message "Running '%s' on '%s' ..." pdflatex-cmd latex-filename)
(switch-to-buffer tex-buf)
(setq pdf-status
(call-process pdflatex-cmd nil tex-buf 1 "-synctex=1 "
(if (string= "texi2" (substring pdflatex-cmd 0 5))
;; workaround (bug?): texi2pdf or texi2dvi *fail* to work with full path:
(file-name-nondirectory latex-filename)
latex-filename)))
(if (not (= 0 pdf-status))
(message "** OOPS: error in '%s' (%d)!" pdflatex-cmd pdf-status)
;; else: pdflatex probably ok
(shell-command
(concat (if (and ess-microsoft-p (w32-shell-dos-semantics))
cmdstr-win
cmdstr))))
(switch-to-buffer buf)
(display-buffer tex-buf)))
(define-key noweb-minor-mode-map "\M-nv" 'ess-swv-PDF-rnw-sync)
Getting closer and closer, but we still need to tell auctex what filenames to pass through to skim. So I bit the bullet and edited auctex-config.el. I commented out the existing aquamacs-call-viewer function definition and replaced it with my own:
(defun aquamacs-call-viewer (line source)
"Display current output file as PDF at LINE (as in file SOURCE).
Calls `aquamacs-tex-pdf-viewer' to display the PDF file using the
Skim AppleScript protocol."
(cond
((string= (file-name-extension (TeX-active-master)) "Rnw")
(let* ((full-file-name
(expand-file-name
;; as in TeX-view
;; C-c C-c view uses %o (from TeX-expand-list), which
;; is the same.
(concat (file-name-sans-extension (TeX-active-master)) "." (TeX-output-extension))
default-directory))
(full-source-name
(expand-file-name
(concat (file-name-sans-extension (source)) ".Rnw") ;; this is relative to the master
(file-name-directory (full-file-name)))))
(message "full pdf name: %s" full-file-name)
(message "full rnw sournce name: %s" full-source-name)
(do-applescript
(format
"
set theSink to POSIX file \"%s\"
set theSource to POSIX file \"%s\"
tell application \"%s\"
activate
open theSink
tell front document to go to TeX line %d from theSource%s
end tell
"
full-file-name full-source-name aquamacs-tex-pdf-viewer line
;; do not say "showing reading bar false" so users can override in future
(cond ((eq t aquamacs-skim-show-reading-bar)
" showing reading bar true")
((eq nil aquamacs-skim-show-reading-bar)
" showing reading bar false")
(t ""))))))
(t
(let* ((full-file-name
(expand-file-name
;; as in TeX-view
;; C-c C-c view uses %o (from TeX-expand-list), which
;; is the same.
(TeX-active-master (TeX-output-extension))
default-directory))
(full-source-name
(expand-file-name
source ;; this is relative to the master
(file-name-directory full-file-name))))
(message "IN OTHERWISE!! WAT: %s" (file-name-extension (TeX-active-master)))
(do-applescript
(format
"
set theSink to POSIX file \"%s\"
set theSource to POSIX file \"%s\"
tell application \"%s\"
activate
open theSink
tell front document to go to TeX line %d from theSource%s
end tell
"
full-file-name full-source-name aquamacs-tex-pdf-viewer line
;; do not say "showing reading bar false" so users can override in future
(cond ((eq t aquamacs-skim-show-reading-bar)
" showing reading bar true")
((eq nil aquamacs-skim-show-reading-bar)
" showing reading bar false")
(t ""))))))))
And one more final test (notice I changed the keybindings of the toolchain to: M-n s -> M-n q -> M-n v in that order for sweave -> latex -> view [note that for this last step you have to use pdflatex and not texi2pdf]), everything builds, no errors, launching viewer...
"Skim" "/Users/myname/text/testing/myfile.pdf": exited abnormally with code 127.
And now I'm completely lost again. Anyone sufficiently familiar with Skim?
Edit 2: Well, error 127 is simply file-not-found on the binary. Somewhere in there I must have clobbered the path. So I added (setenv "PATH" (concat (getenv "PATH") ":" "/Applications/Skim.app/Contents/MacOS")) near the top of my auctex-config.el. Now everything compiles and launches with no errors ... but Command-Shift-Click on emacs does not get Skim to respond (at least it gives no errors). Command-Shift-Click on Skim still forces emacs to open the .tex file.
I guess this has now become a very Aquamacs + Skim specific question, since most of the rest of the interaction is in applescript, unless I missed something obvious in the key lines of lisp pointed out above.
To clarify. You want C-c C-c from Rnw files to run AUCTeX commands on the output of Sweave (M-n s).
The problem is that Auctex doesn't know that it has to act on a different file. This is how to make it aware of that:
(defun Rnw-command-master (&optional override-confirm)
"Run command on the current document.
If a prefix argument OVERRIDE-CONFIRM is given, confirmation will
depend on it being positive instead of the entry in `TeX-command-list'."
(interactive "P")
(let ((TeX-transient-master (concat
(file-name-sans-extension (buffer-file-name))
".tex"))
(TeX-master nil))
(TeX-command (TeX-command-query (TeX-master-file)) 'TeX-master-file
override-confirm)))
(define-key noweb-minor-mode-map (kbd "\C-c \C-c") 'Rnw-command-master)
To make Auctex run sweave first it would require a bit of additional work. Noweb support is now actively rewritten in ESS and by next version you will have a completely new system with AucTeX integration and many other useful things activated by default.
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.
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".
If a file is set to read only mode, how do I change it to write mode and vice versa from within Emacs?
M-x read-only-mode
in very old versions of Emacs, the command was:
M-x toggle-read-only
On my Windows box, that amounts to Alt-x to bring up the meta prompt and typing "read-only-mode" to call the correct elisp function.
If you are using the default keyboard bindings,
C-x C-q
(which you read aloud as "Control-X Control-Q") will have the same effect. Remember, however, given that emacs is essentially infinitely re-configurable, your mileage may vary.
Following up from the commentary: you should note that the writeable status of the buffer does not change the writeable permission of the file. If you try to write out to a read only file, you'll see a confirmation message. However, if you own the file, you can write out your changes without changing the permissions on the file.
This is very convenient if you'd like to make a quick change to a file without having to go through the multiple steps of add write permission, write out changes, remove write permission. I tend to forget that last step, leaving potentially critical files open for accidental changes later on.
Be sure you're not confusing 'file' with 'buffer'. You can set buffers to read-only and back again with C-x C-q (toggle-read-only). If you have permission to read, but not write, a file, the buffer you get when you visit the file (C-x C-f or find-file) will be put in read-only mode automatically. If you want to change the permissions on a file in the file system, perhaps start with dired on the directory that contains the file. Documentation for dired can be found in info; C-h i (emacs)dired RET.
What I found is M-x set-file-modes filename mode
It worked at my Windows Vista box.
For example: M-x set-file-modes <RET> ReadOnlyFile.txt <RET> 0666
As mentioned up there by somebody else: M-x toggle-read-only would work.
However, this is now deprecated and M-x read-only-mode is the current way to do it, that it is set to C-x C-q keybinding.
CTRL + X + CTRL + Q
If only the buffer (and not the file) is read-only, you can use toggle-read-only, which is usually bound to C-x C-q.
If the file itself is read-only, however, you may find the following function useful:
(defun set-buffer-file-writable ()
"Make the file shown in the current buffer writable.
Make the buffer writable as well."
(interactive)
(unix-output "chmod" "+w" (buffer-file-name))
(toggle-read-only nil)
(message (trim-right '(?\n) (unix-output "ls" "-l" (buffer-file-name)))))
The function depends on unix-output and trim-right:
(defun unix-output (command &rest args)
"Run a unix command and, if it returns 0, return the output as a string.
Otherwise, signal an error. The error message is the first line of the output."
(let ((output-buffer (generate-new-buffer "*stdout*")))
(unwind-protect
(let ((return-value (apply 'call-process command nil
output-buffer nil args)))
(set-buffer output-buffer)
(save-excursion
(unless (= return-value 0)
(goto-char (point-min))
(end-of-line)
(if (= (point-min) (point))
(error "Command failed: %s%s" command
(with-output-to-string
(dolist (arg args)
(princ " ")
(princ arg))))
(error "%s" (buffer-substring-no-properties (point-min)
(point)))))
(buffer-substring-no-properties (point-min) (point-max))))
(kill-buffer output-buffer))))
(defun trim-right (bag string &optional start end)
(setq bag (if (eq bag t) '(?\ ?\n ?\t ?\v ?\r ?\f) bag)
start (or start 0)
end (or end (length string)))
(while (and (> end 0)
(member (aref string (1- end)) bag))
(decf end))
(substring string start end))
Place the functions in your ~/.emacs.el, evaluate them (or restart emacs). You can then make the file in the current buffer writable with M-x set-buffer-file-writable.
If you are looking at a directory of files (dired), then you can use Shift + M on a filename and enter the modespec, the same attributes used in the chmod command.
M modespec <RET>
See the other useful commands on files in a directory listing at
http://www.gnu.org/s/libtool/manual/emacs/Operating-on-Files.html
I tried out Vebjorn Ljosa's solution, and it turned out that at least in my Emacs (22.3.1) there isn't such function as 'trim-right', which is used for removing an useless newline at the end of chmod output.
Removing the call to 'trim-right' helped, but made the status row "bounce" because of the extra newline.
C-x C-q is useless. Because your also need the permission to save a file.
I use Spacemacs. It gives me a convenient function to solve this question. The code is following.
(defun spacemacs/sudo-edit (&optional arg)
(interactive "p")
(if (or arg (not buffer-file-name))
(find-file (concat "/sudo:root#localhost:" (ido-read-file-name "File: ")))
(find-alternate-file (concat "/sudo:root#localhost:" buffer-file-name))))
I call spacemacs/sudo-edit to open a file in emacs and input my password, I can change the file without read-only mode.
You can write a new function like spacemacs/sudo-edit.