An alternative find file function with the same default folder, every time - emacs

I'd like to bind super and 9 to open the "find file:", "C-x C-f" menu with ~/x/ as the "default path" in the user input field, no matter what directory the file I currently have open is in. My elisp skills are unfortunately pretty basic. I would really appreciate some help with this.
(global-set-key (kbd "s-9") 'enter_find_file_with_dir_x_as_default)
(defun enter_find_file_with_dir_x_as_default ()
"Enter find file with the path ~/x/ as the default input every time."
())

Just define a command that calls read-file-name with the directory you want as the default (in the interactive spec), and then calls find-file on the file name read.
(defun my-find-file (file)
"..."
(interactive (list (read-file-name "File: " "~/x/")))
(find-file file))
See the doc for read-file-name, to decide what other arguments you might want (e.g., whether you accept only existing file names or allow a new-file buffer).
Note too that if you want to bind this to a key then it has to be a command, so it needs an interactive spec. If you just wanted a function that reads a file name starting in directory ~/x/ then the answer is read-file-name -- just pass it ~/x/ as its DIR argument.
See the Elisp manual, node Reading File Names, for more information. (C-h i; choose Elisp; i read-file-name.)

Related

OSX -- How to define save-file-as that opens a directory tree window

I need some assistance, please, defining a save-as function that opens a directory tree instead of just giving me a path in the status bar . . . Specifically, ns-popup-save-panel is not recognized by the current version of emacs. I am looking for something similar to write-file filename &optional confirm. I have tried different combinations, but I still cannot get the pop-up menu save-file directory tree. I already have the keyboard shortcut figured out. Emacs complains of void variables when I try to insert write-file filename &optional confirm. Just plain old write-file or save-buffer doesn't open the directory listing.
(defun mac-key-save-file-as (&optional filename)
"Save buffer to a file, selecting file by dialog.
Displays sheet. File is saved once user has dismissed sheet."
(interactive)
(ns-popup-save-panel "Select File to Save Buffer" default-directory (if buffer-file-name (file-name-nondirectory buffer-file-name) "Untitled"))
)
M-x ns RET
This brings up a list of all commands begging with ns-
The code cited in the question is from Aquamacs 2.4.
The newest version of Emacs (24.3) built from source uses different names. In this particular case, the new name is ns-write-file-using-panel.

For Emacs, how to store what view-lossage collects into an external file?

For Emacs, how do I store what view-lossage collects into an external file? Ideally I'd like to store these keystroke data into an external log file incrementally and automatically, meaning it is done so by default when Emacs is started.
In Emacs 24 at least (I can't check a prior version right now), the docstring for view-lossage states:
Display last 300 input keystrokes.
To record all your input on a file, use `open-dribble-file'.
And C-hf open-dribble-file RET tells me:
open-dribble-file is an interactive built-in function in `C source
code'.
(open-dribble-file FILE)
Start writing all keyboard characters to a dribble file called FILE.
If FILE is nil, close any open dribble file.
The file will be closed when Emacs exits.
So simply add something like the following to your .emacs file:
(open-dribble-file (expand-file-name "~/.emacs.d/lossage.txt"))
Experimentally this clobbers the file if it already exists, so you'll need to deal with that.
Here's one approach. It accounts for multiple Emacs sessions by using make-temp-name to generate a semi-random filename for the dribble file, and then appends the contents of that to a primary lossage log file when Emacs exists. (If Emacs crashes, it would leave behind the temp file for you to deal with manually.)
(defmacro my-persistent-dribble-file (file)
"Append the dribble-file for this session to persistent lossage log FILE."
`(let* ((persistent-file (expand-file-name ,file))
(temporary-file (make-temp-name (concat persistent-file "-")))
(persistent-arg (shell-quote-argument persistent-file))
(temporary-arg (shell-quote-argument temporary-file))
(append-dribble-command (format
"cat %s >>%s && rm %s"
temporary-arg persistent-arg temporary-arg)))
(open-dribble-file temporary-file)
(eval `(add-hook 'kill-emacs-hook
(lambda () (shell-command ,append-dribble-command))))))
(my-persistent-dribble-file "~/.emacs.d/lossage")

Emacs - intercept file before it is open with external program and modify it, then open modified verison

I need to process a file of certain types with external command line program accepting single argument (filename) and then use file modified by this program either open modified file or accept output of command line program as data source for file.
Any way to do this?
Where I used to work there were some binary files that I wanted to view in emacs. The way I did this was to add to jka-compr-compression-info-list like the following for editing applescripts:
(add-to-list 'jka-compr-compression-info-list
["\\.scpt\\'"
"Compiling" "osacompile-helper.sh" nil
"Decompiling" "osacompile-helper.sh" ("-d")
nil nil "Fasd"])
(jka-compr-update)
Here osacompile-helper.sh is just a little shell wrapper around osacompile and osadecompile that reads from stdin and writes to stdout (which is required). You also need to turn on auto-compression-mode, although I think that's the default. If you use the customize interface to change jka-compr-compression-info-list, instead of setting it directly, then you don't have to call jka-compr-update.
If you just want this to work when you open the file with C-x C-f, then you can probably just attach your behaviour to find-file, but deeper down I believe insert-file-contents is what eventually reads files in.
A cursory look doesn't seem to show any appropriate hook, so you could look at doing this with before advice.
(defadvice insert-file-contents
(before my-before-insert-file-contents-advice)
"Process files externally before reading them."
(let ((filename (expand-file-name (ad-get-arg 0))))
(message "About to read file %s" filename)
;; your code here.
;; ;; stupid unsafe example:
;; (let ((file (shell-quote-argument filename))
;; (tempfile (shell-quote-argument (make-temp-file "some-prefix-"))))
;; (shell-command (format "sort %s >%s" file tempfile))
;; (shell-command (format "mv %s %s" tempfile file)))
))
(ad-activate 'insert-file-contents)
You might like to elaborate on your requirements, in case you don't actually need to clobber the original file? (which I think is a horrendous idea, frankly; I certainly wouldn't use code like this!)
For example, you could read in the original file, process it within the buffer (maybe using shell-command-on-region with the replace flag), and set the buffer as unmodified. That way you are only likely to save the changes made by the shell command if you make other edits to the file, and the mere act of loading the file into an editor hasn't actually modified it.
In any case, I trust you'll implement sensible backup processes into your code, and will be plenty paranoid when testing!
You can call the external program with shell-command, with the output directed to a new buffer. A minimal working example is:
(defun my-find-and-process-file ()
(interactive)
(let* ((file (read-file-name "File name: "))
(buf (pop-to-buffer file)))
(shell-command (format "cat %s" file) buf)))
Replace cat with the name of your program. This will create a buffer and fill it with the output of your program. If a buffer with the name of your file already exists, it will over-write it. If that's a possibility, you will want to change the buffer name to something safe by adding a suffix or something. This code also doesn't trigger any of the find-file hooks, so you'll have to manually select the mode, or modify the code to do that for you.

How to use org-annotate-file?

I recently found org-annotate-file. I would like to use it to annotate pdf documents or music files or any other files on my computer, and write my annotations in a file annotations.org. I am not looking to include annotations IN the pdf. But what I cannot figure out is what it means to "visit a file"? Does it have to be a file that emacs can open?
But more generally, is there a package that can do something like this: I visit a directory in dired mode, mark a bunch of files on some topic of my interest, and with one command I send links to the files to my annotations.org file (maybe as subheadings under a heading, which may be the directory name), and then I can write the annotations in the annotations file. Then with one command, I should be able to reach any of the files (which org-mode will allow) or open it in an external program. Is this possible in some package?
Thanks.
Of course, it can be done. However, it seems the actual code of org-annotate-file.el, that I found
here, doesn't seem to accept annotating a file that has not been opened (visited means here opened), because the function to annotate uses the current open file as a source for the name. The current implementation of org-annotate-file is this:
(defun org-annotate-file ()
"Put a section for the current file into your annotation file"
(interactive)
(error-if-no-file)
(org-annotate-file-show-section))
At least you could modify it to accept an arbitrary file (if you provide it):
(defun org-annotate-file (&optional filename)
"Put a section for the current file into your annotation file"
(interactive "FFile to tag: ")
; if a file is specified, bypass the check for error when no file
(if filename
(org-annotate-file-show-section filename)
(progn
(error-if-no-file)
(org-annotate-file-show-section))))
This ask you for a file name whenever you do M-xorg-annotate-file.
You also have to change the org-annotate-file-show-section to accept either a file name or a buffer. The first let should be like this:
(defun org-annotate-file-show-section (&optional buffer-or-file)
"Visit the buffer named `org-annotate-file-storage-file' and
show the relevant section"
(let* ((line (buffer-substring-no-properties (point-at-bol) (point-at-eol)))
(filename (if (stringp buffer-or-file)
buffer-or-file
(get-filename buffer-or-file (buffer-file-name))))
(link (get-link filename))
(search-link (org-make-link-string
(concat "file:" filename "::" line)
(org-annotate-file-prettyfy-desc line))))
(show-annotations filename link)
.... rest of the code....
dired integration can be started from here, but I'm still not familiar with the dired API...
EDIT: I'm creating a branch in bitbucket for that modifications. I find the utility very useful and might use it myself. I'll post the link here. And here it is: https://bitbucket.org/dsevilla/org-annotate-file/src

Emacs lisp - autocomplete bookmark names

I'm new to elisp. http://www.gnu.org/s/emacs/manual/html_node/elisp/Interactive-Codes.html#Interactive-Codes lists 'code characters' for interactive parameters, which AFAIK modifies the behaviour of the input mechanism when prompting the user for input (eg: if you specify that the input is a filename that exists, emacs' autocomplete functionality will look for file names that exists).
I'm trying to find a code for a bookmark name that already exists - ie: emacs will prompt the user for a bookmark name, and upon pressing tab emacs will show possible bookmark name completions.
Does such a code exist?
Use completing-read for that. You could write a function that prompts the user for a bookmark like so:
(defun my-function ()
(interactive)
(let ((bookmark (completing-read "Bookmark: " (bookmark-all-names))))
...))
If you prefer the prompting to be part of interactive (so that the result will be bound automatically to your function's arguments), you could use the following alternative:
(defun my-function (bookmark)
(interactive (list (completing-read "Bookmark: " (bookmark-all-names))))
...)
For Emacs to find the function bookmark-all-names you also have to add the following line to your .emacs file:
(require 'bookmark)
Function bookmark-completing-read is the standard way to complete a bookmark name. You do not need the lower-level function completing-read for this. Example:
(bookmark-completing-read "Bookmark" bookmark-current-bookmark)
If you use Bookmark+ then bookmark-completing-read accepts some optional arguments (similar to completing-read) that can help:
ALIST -- an alist of bookmarks to choose from (instead of all bookmarks: bookmark-alist)
PRED -- a predicate that filters the list of bookmark candidates
HIST -- an input history list
There is also a non-strict version of the function, bmkp-completing-read-lax, which is useful if you want to accept a new bookmark name or complete against existing names.