From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Kevin Rodgers Newsgroups: gmane.emacs.help Subject: Re: finding tags files based on location Date: Wed, 27 Feb 2008 21:49:05 -0700 Message-ID: References: <8433d21a-3b4e-48b1-a88a-f5639d8e2f2d@i7g2000prf.googlegroups.com> <38795075-7c18-4e8e-b9a4-ba42fc3f5119@e6g2000prf.googlegroups.com> <20080227021914.1c54cfd6@reforged> NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit X-Trace: ger.gmane.org 1204174156 29031 80.91.229.12 (28 Feb 2008 04:49:16 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Thu, 28 Feb 2008 04:49:16 +0000 (UTC) To: help-gnu-emacs@gnu.org Original-X-From: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Thu Feb 28 05:49:42 2008 Return-path: Envelope-to: geh-help-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([199.232.76.165]) by lo.gmane.org with esmtp (Exim 4.50) id 1JUaiD-0004gJ-Si for geh-help-gnu-emacs@m.gmane.org; Thu, 28 Feb 2008 05:49:42 +0100 Original-Received: from localhost ([127.0.0.1] helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1JUahh-0003l7-Pi for geh-help-gnu-emacs@m.gmane.org; Wed, 27 Feb 2008 23:49:09 -0500 Original-Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1JUahS-0003l1-Mo for help-gnu-emacs@gnu.org; Wed, 27 Feb 2008 23:48:54 -0500 Original-Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1JUahR-0003kp-8M for help-gnu-emacs@gnu.org; Wed, 27 Feb 2008 23:48:53 -0500 Original-Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1JUahR-0003km-1w for help-gnu-emacs@gnu.org; Wed, 27 Feb 2008 23:48:53 -0500 Original-Received: from main.gmane.org ([80.91.229.2] helo=ciao.gmane.org) by monty-python.gnu.org with esmtps (TLS-1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1JUahQ-00077b-H9 for help-gnu-emacs@gnu.org; Wed, 27 Feb 2008 23:48:52 -0500 Original-Received: from list by ciao.gmane.org with local (Exim 4.43) id 1JUahL-00056d-5S for help-gnu-emacs@gnu.org; Thu, 28 Feb 2008 04:48:47 +0000 Original-Received: from c-67-162-159-170.hsd1.co.comcast.net ([67.162.159.170]) by main.gmane.org with esmtp (Gmexim 0.1 (Debian)) id 1AlnuQ-0007hv-00 for ; Thu, 28 Feb 2008 04:48:47 +0000 Original-Received: from kevin.d.rodgers by c-67-162-159-170.hsd1.co.comcast.net with local (Gmexim 0.1 (Debian)) id 1AlnuQ-0007hv-00 for ; Thu, 28 Feb 2008 04:48:47 +0000 X-Injected-Via-Gmane: http://gmane.org/ Original-Lines: 134 Original-X-Complaints-To: usenet@ger.gmane.org X-Gmane-NNTP-Posting-Host: c-67-162-159-170.hsd1.co.comcast.net User-Agent: Thunderbird 2.0.0.9 (Macintosh/20071031) In-Reply-To: <20080227021914.1c54cfd6@reforged> X-detected-kernel: by monty-python.gnu.org: Linux 2.6, seldom 2.4 (older, 4) X-BeenThere: help-gnu-emacs@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Users list for the GNU Emacs text editor List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Errors-To: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.help:51924 Archived-At: Mike Mattie wrote: > On Tue, 26 Feb 2008 21:31:28 -0700 > Kevin Rodgers wrote: > >> gamename wrote: >>> On Feb 25, 8:08 pm, Kevin Rodgers 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