unofficial mirror of help-gnu-emacs@gnu.org
 help / color / mirror / Atom feed
* finding tags files based on location
@ 2008-02-25 19:18 gamename
  2008-02-26  4:08 ` Kevin Rodgers
       [not found] ` <mailman.7944.1203998891.18990.help-gnu-emacs@gnu.org>
  0 siblings, 2 replies; 7+ messages in thread
From: gamename @ 2008-02-25 19:18 UTC (permalink / raw)
  To: help-gnu-emacs

Hi,

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?

TIA,
-T


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: finding tags files based on location
  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>
  1 sibling, 0 replies; 7+ messages in thread
From: Kevin Rodgers @ 2008-02-26  4:08 UTC (permalink / raw)
  To: help-gnu-emacs

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)

-- 
Kevin Rodgers
Denver, Colorado, USA





^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: finding tags files based on location
       [not found] ` <mailman.7944.1203998891.18990.help-gnu-emacs@gnu.org>
@ 2008-02-26 19:01   ` gamename
  2008-02-27  4:31     ` Kevin Rodgers
  0 siblings, 1 reply; 7+ messages in thread
From: gamename @ 2008-02-26 19:01 UTC (permalink / raw)
  To: help-gnu-emacs

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



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: finding tags files based on location
  2008-02-26 19:01   ` gamename
@ 2008-02-27  4:31     ` Kevin Rodgers
  2008-02-27 10:19       ` Mike Mattie
  0 siblings, 1 reply; 7+ messages in thread
From: Kevin Rodgers @ 2008-02-27  4:31 UTC (permalink / raw)
  To: help-gnu-emacs

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

-- 
Kevin Rodgers
Denver, Colorado, USA





^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: finding tags files based on location
  2008-02-27  4:31     ` Kevin Rodgers
@ 2008-02-27 10:19       ` Mike Mattie
  2008-02-28  4:49         ` Kevin Rodgers
  0 siblings, 1 reply; 7+ messages in thread
From: Mike Mattie @ 2008-02-27 10:19 UTC (permalink / raw)
  To: help-gnu-emacs

[-- Attachment #1: Type: text/plain, Size: 4290 bytes --]

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.

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.

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.

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

Cheers,
Mike Mattie

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: finding tags files based on location
  2008-02-27 10:19       ` Mike Mattie
@ 2008-02-28  4:49         ` Kevin Rodgers
  2008-02-28  8:43           ` Mike Mattie
  0 siblings, 1 reply; 7+ messages in thread
From: Kevin Rodgers @ 2008-02-28  4:49 UTC (permalink / raw)
  To: help-gnu-emacs

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.

> 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?

(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!

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




-- 
Kevin Rodgers
Denver, Colorado, USA





^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: finding tags files based on location
  2008-02-28  4:49         ` Kevin Rodgers
@ 2008-02-28  8:43           ` Mike Mattie
  0 siblings, 0 replies; 7+ messages in thread
From: Mike Mattie @ 2008-02-28  8:43 UTC (permalink / raw)
  To: help-gnu-emacs

[-- 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 --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2008-02-28  8:43 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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 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).