From: Mike Mattie <codermattie@gmail.com>
To: help-gnu-emacs@gnu.org
Subject: Re: finding tags files based on location
Date: Thu, 28 Feb 2008 00:43:15 -0800 [thread overview]
Message-ID: <20080228004315.3dae0ed3@reforged> (raw)
In-Reply-To: <fq5ef9$s8m$1@ger.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 6808 bytes --]
On Wed, 27 Feb 2008 21:49:05 -0700
Kevin Rodgers <kevin.d.rodgers@gmail.com> wrote:
> Mike Mattie wrote:
> > On Tue, 26 Feb 2008 21:31:28 -0700
> > Kevin Rodgers <kevin.d.rodgers@gmail.com> wrote:
> >
> >> gamename wrote:
> >>> On Feb 25, 8:08 pm, Kevin Rodgers <kevin.d.rodg...@gmail.com>
> >>> wrote:
> >>>> gamename wrote:
> >>>>> I often have to checkout multiple copies of the same source tree
> >>>>> from cvs. For example, if I have a source tree 'foo' in cvs, I
> >>>>> may have 2 copies like ~/foo0/bar and ~/foo1/bar in my home
> >>>>> directory at the same time. Each copy of the foo tree will have
> >>>>> a tags file in 'foo/tags'. Does anyone have code that will
> >>>>> enable emacs to determine which tags file to use based on the
> >>>>> tree i'm currently using? For example, if I'm in foo1/bar, I
> >>>>> would be using the tags file in foo1/tags, not foo0/ tags. Is
> >>>>> there code to dynamically determine that?
> >> >>
> >>>> Is it enough to make tags-file-name a buffer local variable, set
> >>>> appropriately for each file? If so:
> >>>>
> >>>> (defun set-local-tags-file-name ()
> >>>> (when (file-exists-p "tags")
> >>>> (set (make-local-variable 'tags-file-name)
> >>>> (expand-file-name "tags"))))
> >>>>
> >>>> (add-hook 'find-file-hook 'set-local-tags-file-name)
> >>> Thanks Kevin, but I don't think that scales very well. If I have
> >>> thousands of files, that wouldn't be workable.
> >> Actually, it scales perfectly well: No matter how many files you
> >> have, the hook is only run once for each file that you actually
> >> visit.
> >>
> >> The question is: Does it actually work? I see now that
> >> vist-tags-table explicitly provides a way to do the same thing, so
> >> perhaps this is better:
> >>
> >> (defun set-local-tags-file-name ()
> >> (when (file-exists-p "tags")
> >> (visit-tags-table (expand-file-name "tags") t)))
> >>
> >
> > Actually that won't be all that useful as it will scope the tags
> > table to the directory of the file, instead of the entire source
> > tree. If you use version control alot you can find a good location
> > for the tags table by ascending the FS tree looking for the highest
> > directory that is writable and under version control.
>
> Yes, OP mentioned source trees but since the examples given simply had
> the tags file in the same directory as the source file, that's what I
> presented.
My statement was a poor articulation without vital qualification, and
sounds harsh besides wrong.
My technique of using vc to find a source tree root is opportunistic.
Both techniques would be best since placing the tags table in the
immediate directory is a sane decision when there
is no version control meta-information or other hints that mark
the source tree root.
Ah, much better.
> > The code below will give you a sketch of the algorithm. It's all
> > recursive so it will hit the stack limit with valid inputs. But it
> > might help you.
> >
> > If your hook used a global structure that paired the loaded tags
> > tables with their directory you could cheaply determine a best
> > table from the list to associate with a buffer.
>
> Why bother generating a global structure, instead of just searching up
> the directory tree from the source file towards the root until you
> find a tags file?
Maybe it's a premature optimization. If a tags table is already loaded
i figured it should find the buffer before it started walking the FS
with system calls. By creating a index of the tags tables keyed
by the path the design treads lightly on the FS. nice for laptop batteries ?
Not a big deal overall though.
> (defun set-local-tags-file-name (&optional directory)
> "Set the buffer's local `tags-file-name' value to the directory's
> TAGS file.
> If there is no TAGS file in the current directory, search up the
> directory tree to the root until a TAGS file is found."
> (interactive)
> (let ((file (expand-file-name "TAGS" directory)))
> (cond ((file-exists-p file) (visit-tags-table file t))
> ((equal directory "/") nil)
> (t (set-local-tags-file-name (expand-file-name ".."
> directory))))))
>
> > If you know the root of the tree it's pretty easy to make up the
> > commands to generate the table when it is missing as well.
>
> Now that's an interesting idea!
It would be even slicker if it tried the standard makefile tags targets first. I
might resurrect my old tag configuration and rebuild it along these lines.
Another good question is the usefulness of pre-loading tags tables. An always-load
list of TAG table paths might be neat for making libraries searchable by tags tables as well
as projects. When run from the initialization hook of a programming mode it would
be quite handy.
> > (defun prefix-strings (prefix list)
> > "prefix all the strings of the list concatenating the result."
> > (mapcar
> > (lambda ( string )
> > (concat prefix string))
> > list))
> >
> > (defun strip-list-last ( list )
> > "strip the last element from a list"
> > (if (consp (cdr list))
> > (cons
> > (car list)
> > (strip-list-last (cdr list)))
> > nil))
> >
> > (defun ascend-to-checkout-root ( dir )
> > "The recursive core of find-checkout-root. use that entry point
> > instead." (if (and
> > (file-accessible-directory-p dir)
> > (file-writable-p (concat dir "/_")))
> >
> > ;; vc-backend is not robust with inputs. If a directory is
> > given without a trailing ;; slash a nil value will be returned
> > incorrectly for directories under version ;; control.
> >
> > (if (vc-backend dir)
> > (lexical-let
> > ((traverse (strip-list-last (split-string dir "/" t))))
> >
> > (if traverse
> > (lexical-let
> > ((found (ascend-to-checkout-root (prefix-strings "/"
> > traverse)))) (if (eq 't found)
> > dir
> > found))
> > t)) ;; halt when list is exhausted
> > t) ;; halt when the directory is no longer under
> > version control. t)) ;; halt when we don't have read and
> > write permission for the directory.
> >
> > (defun find-checkout-root ( dir )
> > "Find the ancestor directory that is the root of the checkout
> > containing DIR.
> >
> > Recursion halts on these conditions:
> > * exhausted path.
> > * directory is not: accesible,readable, and writable.
> > * directory is not under version control according to vc-backend.
> > "
> > (lexical-let
> > ((found (ascend-to-checkout-root dir)))
> > (if (eq 't found)
> > dir
> > found)))
>
>
>
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
prev parent reply other threads:[~2008-02-28 8:43 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-02-25 19:18 finding tags files based on location gamename
2008-02-26 4:08 ` Kevin Rodgers
[not found] ` <mailman.7944.1203998891.18990.help-gnu-emacs@gnu.org>
2008-02-26 19:01 ` gamename
2008-02-27 4:31 ` Kevin Rodgers
2008-02-27 10:19 ` Mike Mattie
2008-02-28 4:49 ` Kevin Rodgers
2008-02-28 8:43 ` Mike Mattie [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/emacs/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20080228004315.3dae0ed3@reforged \
--to=codermattie@gmail.com \
--cc=help-gnu-emacs@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).