unofficial mirror of help-gnu-emacs@gnu.org
 help / color / mirror / Atom feed
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 --]

      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).