Hi,
I have managed to get exuberant ctags working with org mode. This
means that
plain links [[like this]], instead of defaulting to plain text
search when no
match is found in the current file, now look for a matching tag
<<like this>> in
all your *.org files, and jumps there.
This means your org files all now "seamlessly" talk to each other
and interlink.
You can split that monolithic file up into smaller files and the
plain links
still work. You can throw a plain link to a topic you know exists
in another
file, without having to worry about the format of special inter-
file links,
whether you got the directory right, and so on.
Steps:
1. First you need a small patch to org.el. This is necessary
because AFAIK there
is no easy way to customise or advise org's behaviour when opening
a plain link.
The patch is at the end of this post.
2. Next you need to get exuberant ctags from http://ctags.sourceforge.net/
There is a windows executable there (a zip file). Many linux
distributions have
'ctags-exuberant' as an installable package in their repositories.
If you are using windows, extract the ctags.zip file into a
directory somewhere,
eg C:\emacs23\ctags
3. Now make a new file called .ctags in your HOME directory. If you
are not sure
where this is, evaluate (getenv "HOME") in the emacs scratch buffer.
Put the following 3 lines into this file, then save it:
--langdef=orgmode
--langmap=orgmode:.org
--regex-orgmode=/<<([^>]+)>>/\1/d,definition/
The last line is a regular expression that defines what a tag is in
orgmode. If
you don't like my definition based on angle brackets, or you want
to add other
destinations as tags, just alter the bit between the first
two /...slashes.../
4. Paste the following into your .emacs file:
(defvar home-dir "/home/paul/") ; replace with your home dir
(defun operating-system ()
(case system-type
((windows-nt cygwin) 'windows)
(darwin 'macos)
(otherwise 'unix)))
(defvar path-to-ctags
(case (operating-system)
(windows "c:/emacs/ctags/ctags.exe") ; or whereever you
extracted it
(unix "/usr/bin/ctags-exuberant")) ; wherever it went
"Path to the CTAGS executable.")
(defun create-tags (dir-name)
"Create tags file."
(interactive "DBase directory: ")
(shell-command
(format "%s --options=%s/.ctags -f %s/TAGS -e -R %s/*"
path-to-ctags home-dir dir-name dir-name)))
(global-set-key (kbd "<M-kp-multiply>") 'pop-tag-mark)
(defadvice find-tag (before set-org-mark-before-finding-tag
activate compile)
"Before trying to find a tag, save our current position on org mark
ring."
(save-excursion
(if (org-mode-p)
(org-mark-ring-push))))
5. Now run create-tags:
M-x create-tags ENTER "/path/to/org/files/" ENTER
create-tags searches all subdirectories as well, and will also
create tags for
all source code files that if finds (*.c, *.lisp, *.el, etc). All
these tags
will go in one big TAGS file, located in the "base" directory that
you specify
as an argument to create-tags. Thus, if you have any large source
trees in
subdirectories, create-tags may pause for a few seconds.
6. Check that the file 'TAGS' is in the right place and is not an
empty file.
Tags is now ready to use. See below for usage. The first time you
try and find
a tag, you will be asked which tags file to use. The right answer
is the file
named TAGS which you created with create-tags.
To avoid being asked this every time you restart emacs, try putting
this in your
.emacs:
(add-hook 'org-mode-hook
(lambda () (visit-tags-table "/path/to/TAGSfile")
Tags are defined in the .ctags file as any text in <<double angle
brackets>>.
(triple angle brackets work too)
When you click on a link "[[foo]]" and org cannot find a matching
"<<foo>>" in
the current buffer, the tags facility will take over. The file TAGS
is examined
to see if the tags facility knows about "<<foo>>" in any other
files. If it
does, the matching file will be opened and the cursor will jump to
the position
of "<<foo>>" in that file.
Important commands:
* M-.
Press to enter a tag name (default is a string extracted from the
current cursor position) and then try & jump there. No
autocompletion yet.
* C-M-.
as above, but search term is a regular expression
* M-x tags-search
Also searches for a regexp, but searches through the *entire text* of
all the files that the tags facility knows about. Jumps to the
first match.
Then, press M-, to jump to each successive match.
* M-* "go back" from a tag jump. (note: if you jumped from an org-
mode buffer,
your previous position will also have been saved on the org mark
ring).
Tags mode has no way of knowing when you create new tags. So, any
new <<link
targets>> you make after running create-tags will not be in the
'TAGS' file & so
will be unknown to the tags facility. For new tags to make it into
the TAGS
file, you need to re-run (create-tags "path") to refresh the file.
You also might want to put (create-tags "/path/to/org/files") in
your .emacs or
even "ctags-exuberant -e -R /path/to/org/ &" in your .bashrc or
equivalent.
There is probably a clever way to re-run create-tags at sensible
times eg when
saving an org file, but I haven't looked into it.
Also if someone clever wants to enable tabbed completion when
prompted for a tag
name with find-tag: please feel free.
There are other tags programs that interface with emacs, for
example GNU Global.
However I believe that to write parsers for new languages like
orgmode, you have
to write them in C for most of the other tags programs. With
exuberant ctags
it's just a matter of writing a regular expression.
Hope some people find this helpful.
Here is the patch. Sadly the dumb gmane web interface thingy forced
me to change
all '<' to '{' and '>' to '}' before I could post this, as it
accused me of top
posting. You will therefore need to change them all back.
----BEGIN PATCH for org.el (delete this line)----
8349,8369c8349,8350
{ (condition-case nil (eval cmd)
{ ;; ORG-TAGS
{ (error
{ (progn
{ (widen)
{ (condition-case nil (eval cmd)
{ (error
{ ;; No matching link found anywhere in this file
{ ;; See if we can find a tag
{ ;; If so, jump to it
{ (condition-case nil (find-tag path)
{ (error
{ (cond
{ (org-make-new-topics-for-missing-links-p
{ (if (y-or-n-p
{ (format "Topic `%S' not found;
append to current
buffer?"
{ path)))
{ (org-append-new-topic path nil))
{ (t
{ (error "No match found"))))))))))))
{
---
} (condition-case nil (eval cmd)
} (error (progn (widen) (eval cmd))))))
8592,8595d8572
{ ;; ORG-TAGS
{ ((not org-open-link-defaults-to-normal-string-search-p)
{ ;; We don't want to search for a plain text match.
{ (error "No match."))
8651,8682d8627
{
{
{ ;; ORG-TAGS
{
{ (defvar org-open-link-defaults-to-normal-string-search-p nil
{ "Behaviour when attempting to open a 'thisfile' hyperlink for
which no
{ EXACT match can be found (i.e. no match in angled brackets, etc).
{ If true (default), exhibit normal org behaviour of doing a search
for a string
{ matching the link name.
{ If nil, abort the attempt to open the link.")
{
{
{ (defvar org-make-new-topics-for-missing-links-p nil
{ "If true, when attempting to follow a 'plain' hyperlink for
which no precise
{ match is found, offer to append a top-level heading with the same
name as the
{ hyperlink, to the end of the buffer.")
{
{
{ (defun org-append-new-topic (word)
{ (interactive "s")
{ (widen)
{ (end-of-buffer)
{ (newline 2)
{ (insert (format "* <<%s>>" word)) ; <<<>>> to make radio word
{ (backward-char 4)
{ ;;(org-update-radio-target-regexp)
{ (end-of-line)
{ (newline 2)
{ (next-line 2))
{
{
{
----END PATCH (delete this line)----
_______________________________________________
Emacs-orgmode mailing list
Please use `Reply All' to send replies to the list.
address@hidden
http://lists.gnu.org/mailman/listinfo/emacs-orgmode