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
Related
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.)
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")
I know this is kind of minor, but it's been bugging me. I'm using Org-mode for a project and I tend to export to either PDF or HTML rather frequently and it leaves my directory littered with PDF, Tex, and HTML files. Is there a way to have Org-mode export to another location, perhaps a subdirectory called ./exports?
In addition to the use of publishing by modifying your org-publish-project-alist variable as #user1248256 suggested, you can directly specify the org-export-publishing-directory variable within your file:
#+bind: org-export-publishing-directory "./exports"
* This is a test headline
Some text here. This should be exported to the "./exports" directory.
Upon export it will be placed in the "exports" directory, but only if that directory exists. If it does not exist, you will get an error message in the console.
The original question referred to exporting of org-files, while most answers above actually have to do with publishing, which is a different concept.
I believe the best way to solve the problem posed by the OP is to add the following to your emacs initialization file (.emacs):
(defadvice org-export-output-file-name (before org-add-export-dir activate)
"Modifies org-export to place exported files in a different directory"
(when (not pub-dir)
(setq pub-dir "exported-org-files")
(when (not (file-directory-p pub-dir))
(make-directory pub-dir))))
PS:
I realize a 5 year old question might no longer be relevant to the OP, but hopefully people searching for similar stuff will benefit from this answer.
This is a slight modification of a code snippet found in http://rwx.io/posts/org-export-configurations/
The original solution found in the above blog allows for setting up different directories for each exported format. However, if the goal is to avoid having
one's directory "littered with PDF, Tex, and HTML files", I think it is best to have only one directory containing exported files of all formats, which is the essence of the modification I offered above.
Edit: The emacs manual (https://www.gnu.org/software/emacs/manual/html_node/elisp/Porting-old-advice.html#Porting-old-advice) states that the defadvice mechanism was made obsolete by the new advice-add. So here is a code snipet with the same effect, using the recommended advice-add:
(defun org-export-output-file-name-modified (orig-fun extension &optional subtreep pub-dir)
(unless pub-dir
(setq pub-dir "exported-org-files")
(unless (file-directory-p pub-dir)
(make-directory pub-dir)))
(apply orig-fun extension subtreep pub-dir nil))
(advice-add 'org-export-output-file-name :around #'org-export-output-file-name-modified)
As before, this should be placed in your .emacs file.
This probably wasn't possible when the question was first asked, but the simplest solution would be to add the directory to the :EXPORT_FILE_NAME: property:
:PROPERTIES:
:EXPORT_FILE_NAME: exports/<filename>
:END:
Just as in the accepted answer, the directory must exist in order for this to work.
You have to put the following line at the beginning of your org file :
#+EXPORT_FILE_NAME: PATH/filename
Where PATH is the path to the folder where you want your file to be exported (e.g. ~/exports) and filename the name you want to give to your exported file (e.g. tutorial.html).
I believe you can get that with org-publish.
Add to you emacs configuration file something like that:
(setq org-publish-project-alist
'(("html"
:base-directory "~/org/"
:base-extension "org"
:publishing-directory "~/org/exports"
:publishing-function org-publish-org-to-html)
("pdf"
:base-directory "~/org/"
:base-extension "org"
:publishing-directory "~/org/exports"
:publishing-function org-publish-org-to-pdf)
("all" :components ("html" "pdf"))))
Eval this expression (or restart emacs), press C-c C-e X at org-mode, then choose a project from a list.
You can see more information at http://orgmode.org/worg/org-tutorials/org-publish-html-tutorial.html and http://orgmode.org/manual/Publishing.html#Publishing
As stated in the section "Export settings", we can use the EXPORT_FILE_NAME within a file in order to set the output directory. The quote shown below is the relevant part of the documentation
‘EXPORT_FILE_NAME’
The name of the output file to be generated. Otherwise, Org generates the file name based on the buffer name and the extension based on the back-end format.
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.
I would like emacs to mark files that are generated as read-only when they're opened. The part of the puzzle that I'm missing is how to check if a file "exists". I currently have the following:
;;
;; get file extension
;;
(defun get-ext (file-name)
(car (cdr (split-string file-name "\\."))))
;;
;; get the base name of the file
;;
(defun base-name (file-name)
(car (split-string file-name "\\.")))
;;
;; if an 'lzz' file exists for this header, mark it as read only
;;
(defun mark-read-only ()
(if (string= (get-ext (cur-file)) "h")
(if ( ??file-exists??? (concat (base-name (cur-file)) ".lzz") )
(toggle-read-only))))
What can I use for "???file-exists???"?
Once I find this, I'll add "mark-read-only" to the appropriate hook (which I think is the find-file-hook).
BACKGROUND
We use lzz as a code generator to simplify our C/C++ development process. Briefly, lzz takes a single input file (which looks very like C/C++) and generates header and source files as appropriate.
By default, lzz includes #line directives so that the debugger points to the original source and not the generated source, however, to reduce compilation dependencies we normally disable these directives in header files. The result is that when debugging templates or inline functions, the debugger normally points to the generated header file and not the original source file.
This is not a big deal, however, recently I've found that when debugging I'll make a quick modification to the displayed file and then I'll rebuild. Of course this normally means that the change I made disappears because the file I edited is generated and so the changes are "blown away" during the library rebuild.
SOLUTION
Thanks to everyone for their help and comments. A special thanks to cobbal for pointing out the correct function to use.
Here's the resulting code (with updates based on the other comments here too):
(defun cur-file ()
"Return the filename (without directory) of the current buffer"
(file-name-nondirectory (buffer-file-name (current-buffer)))
)
(defun mark-generated-as-read-only ()
"Mark generated source files as read only.
Mark generated files (lzz or gz) read only to avoid accidental updates."
(if
(or (string= (file-name-extension (cur-file)) "h")
(string= (file-name-extension (cur-file)) "cpp"))
(cond
(
(file-exists-p (concat (file-name-sans-extension (cur-file)) ".lzz"))
(toggle-read-only))
(
(file-exists-p (concat (file-name-sans-extension (cur-file)) ".gz") )
(toggle-read-only))
)
)
)
try file-exists-p
"Return t if file filename exists (whether or not you can read it.)".
Note that it's not spesific to files and works for directories too.
Depending on what you need, you might want file-readable-p instead of file-exists-p.
Apropos will only get you so far. Icicles provides apropos completion and progressive completion which let you find help easily for command, function, variable, etc. names that match subparts in an arbitrary order (is it file-exists-p or exists-file-p?).
Use f.el, modern library for file and directory manipulation. You can use f-exists?, f-file?, f-directory? and many other predicates. The library is better than standard functions, because it's every file related function you'll ever need under one namespace.