diff options
author | Tobias Klauser <tklauser@distanz.ch> | 2006-11-13 22:13:33 +0100 |
---|---|---|
committer | Tobias Klauser <tklauser@xenon.tklauser.home> | 2006-11-13 22:13:33 +0100 |
commit | b37e0da0b7dc72ddfa513e319ca71b5f5b8aeb7d (patch) | |
tree | 810ec4a83a30b7e001321fdb2402c756f511727e /contrib/xcscope |
Initial import15.6-2
Diffstat (limited to 'contrib/xcscope')
-rw-r--r-- | contrib/xcscope/CVS/Entries | 3 | ||||
-rw-r--r-- | contrib/xcscope/CVS/Repository | 1 | ||||
-rw-r--r-- | contrib/xcscope/CVS/Root | 1 | ||||
-rwxr-xr-x | contrib/xcscope/cscope-indexer | 166 | ||||
-rw-r--r-- | contrib/xcscope/xcscope.el | 2463 |
5 files changed, 2634 insertions, 0 deletions
diff --git a/contrib/xcscope/CVS/Entries b/contrib/xcscope/CVS/Entries new file mode 100644 index 0000000..f7439f6 --- /dev/null +++ b/contrib/xcscope/CVS/Entries @@ -0,0 +1,3 @@ +/cscope-indexer/1.2/Thu Jun 28 04:39:47 2001// +/xcscope.el/1.14/Wed Apr 10 16:59:00 2002// +D diff --git a/contrib/xcscope/CVS/Repository b/contrib/xcscope/CVS/Repository new file mode 100644 index 0000000..f1ac4c6 --- /dev/null +++ b/contrib/xcscope/CVS/Repository @@ -0,0 +1 @@ +cscope/contrib/xcscope diff --git a/contrib/xcscope/CVS/Root b/contrib/xcscope/CVS/Root new file mode 100644 index 0000000..e0eb551 --- /dev/null +++ b/contrib/xcscope/CVS/Root @@ -0,0 +1 @@ +broeker@cscope.cvs.sourceforge.net:/cvsroot/cscope diff --git a/contrib/xcscope/cscope-indexer b/contrib/xcscope/cscope-indexer new file mode 100755 index 0000000..13c0ae2 --- /dev/null +++ b/contrib/xcscope/cscope-indexer @@ -0,0 +1,166 @@ +#! /bin/sh +############################################################################### +# +# File: cscope-indexer +# RCS: $Header: /cvsroot/cscope/cscope/contrib/xcscope/cscope-indexer,v 1.2 2001/06/28 04:39:47 darrylo Exp $ +# Description: Script to index files for cscope +# +# This script generates a list of files to index +# (cscope.out), which is then (optionally) used to +# generate a cscope database. You can use this script +# to just build a list of files, or it can be used to +# build a list and database. This script is not used to +# just build a database (skipping the list of files +# step), as this can be simply done by just calling +# "cscope -b". +# +# Normally, cscope will do its own indexing, but this +# script can be used to force indexing. This is useful +# if you need to recurse into subdirectories, or have +# many files to index (you can run this script from a +# cron job, during the night). It is especially useful +# for large projects, which can contstantly have source +# files added and deleted; by using this script, the +# changing sources files are automatically handled. +# +# Currently, any paths containing "/CVS/" or "/RCS/" are +# stripped out (ignored). +# +# This script is written to use only basic shell features, as +# not all shells have advanced features. +# +# Author: Darryl Okahata +# Created: Thu Apr 27 17:12:14 2000 +# Modified: Tue Jun 19 09:47:45 2001 (Darryl Okahata) darrylo@soco.agilent.com +# Language: Shell-script +# Package: N/A +# Status: Experimental +# +# (C) Copyright 2000, Darryl Okahata, all rights reserved. +# +############################################################################### +# +# Usage: +# +# cscope-indexer [ -v ] [-f database_file ] [-i list_file ] [ -l ] [ -r ] +# +# where: +# +# -f database_file +# Specifies the cscope database file (default: cscope.out). +# +# -i list_file +# Specifies the name of the file into which the list of files +# to index is placed (default: cscope.files). +# +# -l +# Suppress the generation/updating of the cscope database +# file. Only a list of files is generated. +# +# -r +# Recurse into subdirectories to locate files to index. +# Without this option, only the current directory is +# searched. +# +# -v +# Be verbose. Output simple progress messages. +# +# +############################################################################### +set -e + +# May have to edit this: +PATH="/usr/local/bin:/sbin:/usr/sbin:/bin:/usr/bin:$PATH" +export PATH + +LIST_ONLY= +DIR='.' +LIST_FILE='cscope.files' +DATABASE_FILE='cscope.out' +RECURSE= +VERBOSE= +export DIR RECURSE # Need to pass these to subprocesses + +while [ -n "$1" ] +do + case "$1" in + -f) + if [ "X$2" = "X" ] + then + echo "$0: No database file specified" >&2 + exit 1 + fi + DATABASE_FILE="$2" + shift + ;; + -i) + if [ "X$2" = "X" ] + then + echo "$0: No list file specified" >&2 + exit 1 + fi + LIST_FILE="$2" + shift + ;; + -l) + LIST_ONLY=1 + ;; + -r) + RECURSE=1 + ;; + -v) + VERBOSE=1 + ;; + *) + DIR="$1" + ;; + esac + shift +done + +cd $DIR + +if [ "X$VERBOSE" != "X" ] +then + echo "Creating list of files to index ..." +fi + +( + if [ "X$RECURSE" = "X" ] + then + # Ugly, inefficient, but it works. + for f in * + do + echo "$DIR/$f" + done + else + find $DIR \( -type f -o -type l \) + fi +) | \ + egrep -i '\.([chly](xx|pp)*|cc|hh)$' | \ + sed -e '/\/CVS\//d' -e '/\/RCS\//d' -e 's/^\.\///' | \ + sort > $LIST_FILE + +if [ "X$VERBOSE" != "X" ] +then + echo "Creating list of files to index ... done" +fi + +if [ "X$LIST_ONLY" != "X" ] +then + exit 0 +fi + +if [ "X$VERBOSE" != "X" ] +then + echo "Indexing files ..." +fi + +cscope -b -i $LIST_FILE -f $DATABASE_FILE + +if [ "X$VERBOSE" != "X" ] +then + echo "Indexing files ... done" +fi + +exit 0 diff --git a/contrib/xcscope/xcscope.el b/contrib/xcscope/xcscope.el new file mode 100644 index 0000000..ce382a4 --- /dev/null +++ b/contrib/xcscope/xcscope.el @@ -0,0 +1,2463 @@ +; -*-Emacs-Lisp-*- +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; +; File: xcscope.el +; RCS: $RCSfile: xcscope.el,v $ $Revision: 1.14 $ $Date: 2002/04/10 16:59:00 $ $Author: darrylo $ +; Description: cscope interface for (X)Emacs +; Author: Darryl Okahata +; Created: Wed Apr 19 17:03:38 2000 +; Modified: Thu Apr 4 17:22:22 2002 (Darryl Okahata) darrylo@soco.agilent.com +; Language: Emacs-Lisp +; Package: N/A +; Status: Experimental +; +; (C) Copyright 2000, 2001, 2002, Darryl Okahata <darrylo@sonic.net>, +; all rights reserved. +; GNU Emacs enhancements (C) Copyright 2001, +; Triet H. Lai <thlai@mail.usyd.edu.au> +; Fuzzy matching and navigation code (C) Copyright 2001, +; Steven Elliott <selliott4@austin.rr.com> +; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ALPHA VERSION 0.96 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to +;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; This is a cscope interface for (X)Emacs. +;; It currently runs under Unix only. +;; +;; Using cscope, you can easily search for where symbols are used and defined. +;; Cscope is designed to answer questions like: +;; +;; Where is this variable used? +;; What is the value of this preprocessor symbol? +;; Where is this function in the source files? +;; What functions call this function? +;; What functions are called by this function? +;; Where does the message "out of space" come from? +;; Where is this source file in the directory structure? +;; What files include this header file? +;; +;; Send comments to one of: darrylo@soco.agilent.com +;; darryl_okahata@agilent.com +;; darrylo@sonic.net +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; ***** INSTALLATION ***** +;; +;; * NOTE: this interface currently runs under Unix only. +;; +;; This module needs a shell script called "cscope-indexer", which +;; should have been supplied along with this emacs-lisp file. The +;; purpose of "cscope-indexer" is to create and optionally maintain +;; the cscope databases. If all of your source files are in one +;; directory, you don't need this script; it's very nice to have, +;; though, as it handles recursive subdirectory indexing, and can be +;; used in a nightly or weekly cron job to index very large source +;; repositories. See the beginning of the file, "cscope-indexer", for +;; usage information. +;; +;; Installation steps: +;; +;; 0. (It is, of course, assumed that cscope is already properly +;; installed on the current system.) +;; +;; 1. Install the "cscope-indexer" script into some convenient +;; directory in $PATH. The only real constraint is that (X)Emacs +;; must be able to find and execute it. You may also have to edit +;; the value of PATH in the script, although this is unlikely; the +;; majority of people should be able to use the script, "as-is". +;; +;; 2. Make sure that the "cscope-indexer" script is executable. In +;; particular, if you had to ftp this file, it is probably no +;; longer executable. +;; +;; 3. Put this emacs-lisp file somewhere where (X)Emacs can find it. It +;; basically has to be in some directory listed in "load-path". +;; +;; 4. Edit your ~/.emacs file to add the line: +;; +;; (require 'xcscope) +;; +;; 5. If you intend to use xcscope.el often you can optionally edit your +;; ~/.emacs file to add keybindings that reduce the number of keystrokes +;; required. For example, the following will add "C-f#" keybindings, which +;; are easier to type than the usual "C-c s" prefixed keybindings. Note +;; that specifying "global-map" instead of "cscope:map" makes the +;; keybindings available in all buffers: +;; +;; (define-key global-map [(control f3)] 'cscope-set-initial-directory) +;; (define-key global-map [(control f4)] 'cscope-unset-initial-directory) +;; (define-key global-map [(control f5)] 'cscope-find-this-symbol) +;; (define-key global-map [(control f6)] 'cscope-find-global-definition) +;; (define-key global-map [(control f7)] +;; 'cscope-find-global-definition-no-prompting) +;; (define-key global-map [(control f8)] 'cscope-pop-mark) +;; (define-key global-map [(control f9)] 'cscope-next-symbol) +;; (define-key global-map [(control f10)] 'cscope-next-file) +;; (define-key global-map [(control f11)] 'cscope-prev-symbol) +;; (define-key global-map [(control f12)] 'cscope-prev-file) +;; (define-key global-map [(meta f9)] 'cscope-display-buffer) +;; (defin-ekey global-map [(meta f10)] 'cscope-display-buffer-toggle) +;; +;; 6. Restart (X)Emacs. That's it. +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; ***** USING THIS MODULE ***** +;; +;; * Basic usage: +;; +;; If all of your C/C++/lex/yacc source files are in the same +;; directory, you can just start using this module. If your files are +;; spread out over multiple directories, see "Advanced usage", below. +;; +;; Just edit a source file, and use the pull-down or pop-up (button 3) +;; menus to select one of: +;; +;; Find symbol +;; Find global definition +;; Find called functions +;; Find functions calling a function +;; Find text string +;; Find egrep pattern +;; Find a file +;; Find files #including a file +;; +;; The cscope database will be automatically created in the same +;; directory as the source files (assuming that you've never used +;; cscope before), and a buffer will pop-up displaying the results. +;; You can then use button 2 (the middle button) on the mouse to edit +;; the selected file, or you can move the text cursor over a selection +;; and press [Enter]. +;; +;; Hopefully, the interface should be fairly intuitive. +;; +;; +;; * Locating the cscope databases: +;; +;; This module will first use the variable, `cscope-database-regexps', +;; to search for a suitable database directory. If a database location +;; cannot be found using this variable then a search is begun at the +;; variable, `cscope-initial-directory', if set, or the current +;; directory otherwise. If the directory is not a cscope database +;; directory then the directory's parent, parent's parent, etc. is +;; searched until a cscope database directory is found, or the root +;; directory is reached. If the root directory is reached, the current +;; directory will be used. +;; +;; A cscope database directory is one in which EITHER a cscope database +;; file (e.g., "cscope.out") OR a cscope file list (e.g., +;; "cscope.files") exists. If only "cscope.files" exists, the +;; corresponding "cscope.out" will be automatically created by cscope +;; when a search is done. By default, the cscope database file is called +;; "cscope.out", but this can be changed (on a global basis) via the +;; variable, `cscope-database-file'. There is limited support for cscope +;; databases that are named differently than that given by +;; `cscope-database-file', using the variable, `cscope-database-regexps'. +;; +;; Note that the variable, `cscope-database-regexps', is generally not +;; needed, as the normal hierarchical database search is sufficient +;; for placing and/or locating the cscope databases. However, there +;; may be cases where it makes sense to place the cscope databases +;; away from where the source files are kept; in this case, this +;; variable is used to determine the mapping. One use for this +;; variable is when you want to share the database file with other +;; users; in this case, the database may be located in a directory +;; separate from the source files. +;; +;; Setting the variable, `cscope-initial-directory', is useful when a +;; search is to be expanded by specifying a cscope database directory +;; that is a parent of the directory that this module would otherwise +;; use. For example, consider a project that contains the following +;; cscope database directories: +;; +;; /users/jdoe/sources +;; /users/jdoe/sources/proj1 +;; /users/jdoe/sources/proj2 +;; +;; If a search is initiated from a .c file in /users/jdoe/sources/proj1 +;; then (assuming the variable, `cscope-database-regexps', is not set) +;; /users/jdoe/sources/proj1 will be used as the cscope data base directory. +;; Only matches in files in /users/jdoe/sources/proj1 will be found. This +;; can be remedied by typing "C-c s a" and then "M-del" to remove single +;; path element in order to use a cscope database directory of +;; /users/jdoe/sources. Normal searching can be restored by typing "C-c s A". +;; +;; +;; * Keybindings: +;; +;; All keybindings use the "C-c s" prefix, but are usable only while +;; editing a source file, or in the cscope results buffer: +;; +;; C-c s s Find symbol. +;; C-c s d Find global definition. +;; C-c s g Find global definition (alternate binding). +;; C-c s G Find global definition without prompting. +;; C-c s c Find functions calling a function. +;; C-c s C Find called functions (list functions called +;; from a function). +;; C-c s t Find text string. +;; C-c s e Find egrep pattern. +;; C-c s f Find a file. +;; C-c s i Find files #including a file. +;; +;; These pertain to navigation through the search results: +;; +;; C-c s b Display *cscope* buffer. +;; C-c s B Auto display *cscope* buffer toggle. +;; C-c s n Next symbol. +;; C-c s N Next file. +;; C-c s p Previous symbol. +;; C-c s P Previous file. +;; C-c s u Pop mark. +;; +;; These pertain to setting and unsetting the variable, +;; `cscope-initial-directory', (location searched for the cscope database +;; directory): +;; +;; C-c s a Set initial directory. +;; C-c s A Unset initial directory. +;; +;; These pertain to cscope database maintenance: +;; +;; C-c s L Create list of files to index. +;; C-c s I Create list and index. +;; C-c s E Edit list of files to index. +;; C-c s W Locate this buffer's cscope directory +;; ("W" --> "where"). +;; C-c s S Locate this buffer's cscope directory. +;; (alternate binding: "S" --> "show"). +;; C-c s T Locate this buffer's cscope directory. +;; (alternate binding: "T" --> "tell"). +;; C-c s D Dired this buffer's directory. +;; +;; +;; * Advanced usage: +;; +;; If the source files are spread out over multiple directories, +;; you've got a few choices: +;; +;; [ NOTE: you will need to have the script, "cscope-indexer", +;; properly installed in order for the following to work. ] +;; +;; 1. If all of the directories exist below a common directory +;; (without any extraneous, unrelated subdirectories), you can tell +;; this module to place the cscope database into the top-level, +;; common directory. This assumes that you do not have any cscope +;; databases in any of the subdirectories. If you do, you should +;; delete them; otherwise, they will take precedence over the +;; top-level database. +;; +;; If you do have cscope databases in any subdirectory, the +;; following instructions may not work right. +;; +;; It's pretty easy to tell this module to use a top-level, common +;; directory: +;; +;; a. Make sure that the menu pick, "Cscope/Index recursively", is +;; checked (the default value). +;; +;; b. Select the menu pick, "Cscope/Create list and index", and +;; specify the top-level directory. This will run the script, +;; "cscope-indexer", in the background, so you can do other +;; things if indexing takes a long time. A list of files to +;; index will be created in "cscope.files", and the cscope +;; database will be created in "cscope.out". +;; +;; Once this has been done, you can then use the menu picks +;; (described in "Basic usage", above) to search for symbols. +;; +;; Note, however, that, if you add or delete source files, you'll +;; have to either rebuild the database using the above procedure, +;; or edit the file, "cscope.files" to add/delete the names of the +;; source files. To edit this file, you can use the menu pick, +;; "Cscope/Edit list of files to index". +;; +;; +;; 2. If most of the files exist below a common directory, but a few +;; are outside, you can use the menu pick, "Cscope/Create list of +;; files to index", and specify the top-level directory. Make sure +;; that "Cscope/Index recursively", is checked before you do so, +;; though. You can then edit the list of files to index using the +;; menu pick, "Cscope/Edit list of files to index". Just edit the +;; list to include any additional source files not already listed. +;; +;; Once you've created, edited, and saved the list, you can then +;; use the menu picks described under "Basic usage", above, to +;; search for symbols. The first time you search, you will have to +;; wait a while for cscope to fully index the source files, though. +;; If you have a lot of source files, you may want to manually run +;; cscope to build the database: +;; +;; cd top-level-directory # or wherever +;; rm -f cscope.out # not always necessary +;; cscope -b +;; +;; +;; 3. If the source files are scattered in many different, unrelated +;; places, you'll have to manually create cscope.files and put a +;; list of all pathnames into it. Then build the database using: +;; +;; cd some-directory # wherever cscope.files exists +;; rm -f cscope.out # not always necessary +;; cscope -b +;; +;; Next, read the documentation for the variable, +;; "cscope-database-regexps", and set it appropriately, such that +;; the above-created cscope database will be referenced when you +;; edit a related source file. +;; +;; Once this has been done, you can then use the menu picks +;; described under "Basic usage", above, to search for symbols. +;; +;; +;; * Interesting configuration variables: +;; +;; "cscope-truncate-lines" +;; This is the value of `truncate-lines' to use in cscope +;; buffers; the default is the current setting of +;; `truncate-lines'. This variable exists because it can be +;; easier to read cscope buffers with truncated lines, while +;; other buffers do not have truncated lines. +;; +;; "cscope-use-relative-paths" +;; If non-nil, use relative paths when creating the list of files +;; to index. The path is relative to the directory in which the +;; cscope database will be created. If nil, absolute paths will +;; be used. Absolute paths are good if you plan on moving the +;; database to some other directory (if you do so, you'll +;; probably also have to modify `cscope-database-regexps'). +;; Absolute paths may also be good if you share the database file +;; with other users (you'll probably want to specify some +;; automounted network path for this). +;; +;; "cscope-index-recursively" +;; If non-nil, index files in the current directory and all +;; subdirectories. If nil, only files in the current directory +;; are indexed. This variable is only used when creating the +;; list of files to index, or when creating the list of files and +;; the corresponding cscope database. +;; +;; "cscope-name-line-width" +;; The width of the combined "function name:line number" field in +;; the cscope results buffer. If negative, the field is +;; left-justified. +;; +;; "cscope-do-not-update-database" +;; If non-nil, never check and/or update the cscope database when +;; searching. Beware of setting this to non-nil, as this will +;; disable automatic database creation, updating, and +;; maintenance. +;; +;; "cscope-display-cscope-buffer" +;; If non-nil, display the *cscope* buffer after each search +;; (default). This variable can be set in order to reduce the +;; number of keystrokes required to navigate through the matches. +;; +;; "cscope-database-regexps" +;; List to force directory-to-cscope-database mappings. +;; This is a list of `(REGEXP DBLIST [ DBLIST ... ])', where: +;; +;; REGEXP is a regular expression matched against the current buffer's +;; current directory. The current buffer is typically some source file, +;; and you're probably searching for some symbol in or related to this +;; file. Basically, this regexp is used to relate the current directory +;; to a cscope database. You need to start REGEXP with "^" if you want +;; to match from the beginning of the current directory. +;; +;; DBLIST is a list that contains one or more of: +;; +;; ( DBDIR ) +;; ( DBDIR ( OPTIONS ) ) +;; ( t ) +;; t +;; +;; Here, DBDIR is a directory (or a file) that contains a cscope +;; database. If DBDIR is a directory, then it is expected that the +;; cscope database, if present, has the filename given by the variable, +;; `cscope-database-file'; if DBDIR is a file, then DBDIR is the path +;; name to a cscope database file (which does not have to be the same as +;; that given by `cscope-database-file'). If only DBDIR is specified, +;; then that cscope database will be searched without any additional +;; cscope command-line options. If OPTIONS is given, then OPTIONS is a +;; list of strings, where each string is a separate cscope command-line +;; option. +;; +;; In the case of "( t )", this specifies that the search is to use the +;; normal hierarchical database search. This option is used to +;; explicitly search using the hierarchical database search either before +;; or after other cscope database directories. +;; +;; If "t" is specified (not inside a list), this tells the searching +;; mechanism to stop searching if a match has been found (at the point +;; where "t" is encountered). This is useful for those projects that +;; consist of many subprojects. You can specify the most-used +;; subprojects first, followed by a "t", and then followed by a master +;; cscope database directory that covers all subprojects. This will +;; cause the most-used subprojects to be searched first (hopefully +;; quickly), and the search will then stop if a match was found. If not, +;; the search will continue using the master cscope database directory. +;; +;; Here, `cscope-database-regexps' is generally not used, as the normal +;; hierarchical database search is sufficient for placing and/or locating +;; the cscope databases. However, there may be cases where it makes +;; sense to place the cscope databases away from where the source files +;; are kept; in this case, this variable is used to determine the +;; mapping. +;; +;; This module searches for the cscope databases by first using this +;; variable; if a database location cannot be found using this variable, +;; then the current directory is searched, then the parent, then the +;; parent's parent, until a cscope database directory is found, or the +;; root directory is reached. If the root directory is reached, the +;; current directory will be used. +;; +;; A cscope database directory is one in which EITHER a cscope database +;; file (e.g., "cscope.out") OR a cscope file list (e.g., +;; "cscope.files") exists. If only "cscope.files" exists, the +;; corresponding "cscope.out" will be automatically created by cscope +;; when a search is done. By default, the cscope database file is called +;; "cscope.out", but this can be changed (on a global basis) via the +;; variable, `cscope-database-file'. There is limited support for cscope +;; databases that are named differently than that given by +;; `cscope-database-file', using the variable, `cscope-database-regexps'. +;; +;; Here is an example of `cscope-database-regexps': +;; +;; (setq cscope-database-regexps +;; '( +;; ( "^/users/jdoe/sources/proj1" +;; ( t ) +;; ( "/users/jdoe/sources/proj2") +;; ( "/users/jdoe/sources/proj3/mycscope.out") +;; ( "/users/jdoe/sources/proj4") +;; t +;; ( "/some/master/directory" ("-d" "-I/usr/local/include") ) +;; ) +;; ( "^/users/jdoe/sources/gnome/" +;; ( "/master/gnome/database" ("-d") ) +;; ) +;; )) +;; +;; If the current buffer's directory matches the regexp, +;; "^/users/jdoe/sources/proj1", then the following search will be +;; done: +;; +;; 1. First, the normal hierarchical database search will be used to +;; locate a cscope database. +;; +;; 2. Next, searches will be done using the cscope database +;; directories, "/users/jdoe/sources/proj2", +;; "/users/jdoe/sources/proj3/mycscope.out", and +;; "/users/jdoe/sources/proj4". Note that, instead of the file, +;; "cscope.out", the file, "mycscope.out", will be used in the +;; directory "/users/jdoe/sources/proj3". +;; +;; 3. If a match was found, searching will stop. +;; +;; 4. If a match was not found, searching will be done using +;; "/some/master/directory", and the command-line options "-d" +;; and "-I/usr/local/include" will be passed to cscope. +;; +;; If the current buffer's directory matches the regexp, +;; "^/users/jdoe/sources/gnome", then the following search will be +;; done: +;; +;; The search will be done only using the directory, +;; "/master/gnome/database". The "-d" option will be passed to +;; cscope. +;; +;; If the current buffer's directory does not match any of the above +;; regexps, then only the normal hierarchical database search will be +;; done. +;; +;; +;; * Other notes: +;; +;; 1. The script, "cscope-indexer", uses a sed command to determine +;; what is and is not a C/C++/lex/yacc source file. It's idea of a +;; source file may not correspond to yours. +;; +;; 2. This module is called, "xcscope", because someone else has +;; already written a "cscope.el" (although it's quite old). +;; +;; +;; * KNOWN BUGS: +;; +;; 1. Cannot handle whitespace in directory or file names. +;; +;; 2. By default, colored faces are used to display results. If you happen +;; to use a black background, part of the results may be invisible +;; (because the foreground color may be black, too). There are at least +;; two solutions for this: +;; +;; 2a. Turn off colored faces, by setting `cscope-use-face' to `nil', +;; e.g.: +;; +;; (setq cscope-use-face nil) +;; +;; 2b. Explicitly set colors for the faces used by cscope. The faces +;; are: +;; +;; cscope-file-face +;; cscope-function-face +;; cscope-line-number-face +;; cscope-line-face +;; cscope-mouse-face +;; +;; The face most likely to cause problems (e.g., black-on-black +;; color) is `cscope-line-face'. +;; +;; 3. The support for cscope databases different from that specified by +;; `cscope-database-file' is quirky. If the file does not exist, it +;; will not be auto-created (unlike files names by +;; `cscope-database-file'). You can manually force the file to be +;; created by using touch(1) to create a zero-length file; the +;; database will be created the next time a search is done. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(require 'easymenu) + + +(defgroup cscope nil + "Cscope interface for (X)Emacs. +Using cscope, you can easily search for where symbols are used and defined. +It is designed to answer questions like: + + Where is this variable used? + What is the value of this preprocessor symbol? + Where is this function in the source files? + What functions call this function? + What functions are called by this function? + Where does the message \"out of space\" come from? + Where is this source file in the directory structure? + What files include this header file? +" + :prefix "cscope-" + :group 'tools) + + +(defcustom cscope-do-not-update-database nil + "*If non-nil, never check and/or update the cscope database when searching. +Beware of setting this to non-nil, as this will disable automatic database +creation, updating, and maintenance." + :type 'boolean + :group 'cscope) + + +(defcustom cscope-database-regexps nil + "*List to force directory-to-cscope-database mappings. +This is a list of `(REGEXP DBLIST [ DBLIST ... ])', where: + +REGEXP is a regular expression matched against the current buffer's +current directory. The current buffer is typically some source file, +and you're probably searching for some symbol in or related to this +file. Basically, this regexp is used to relate the current directory +to a cscope database. You need to start REGEXP with \"^\" if you want +to match from the beginning of the current directory. + +DBLIST is a list that contains one or more of: + + ( DBDIR ) + ( DBDIR ( OPTIONS ) ) + ( t ) + t + +Here, DBDIR is a directory (or a file) that contains a cscope database. +If DBDIR is a directory, then it is expected that the cscope database, +if present, has the filename given by the variable, +`cscope-database-file'; if DBDIR is a file, then DBDIR is the path name +to a cscope database file (which does not have to be the same as that +given by `cscope-database-file'). If only DBDIR is specified, then that +cscope database will be searched without any additional cscope +command-line options. If OPTIONS is given, then OPTIONS is a list of +strings, where each string is a separate cscope command-line option. + +In the case of \"( t )\", this specifies that the search is to use the +normal hierarchical database search. This option is used to +explicitly search using the hierarchical database search either before +or after other cscope database directories. + +If \"t\" is specified (not inside a list), this tells the searching +mechanism to stop searching if a match has been found (at the point +where \"t\" is encountered). This is useful for those projects that +consist of many subprojects. You can specify the most-used +subprojects first, followed by a \"t\", and then followed by a master +cscope database directory that covers all subprojects. This will +cause the most-used subprojects to be searched first (hopefully +quickly), and the search will then stop if a match was found. If not, +the search will continue using the master cscope database directory. + +Here, `cscope-database-regexps' is generally not used, as the normal +hierarchical database search is sufficient for placing and/or locating +the cscope databases. However, there may be cases where it makes +sense to place the cscope databases away from where the source files +are kept; in this case, this variable is used to determine the +mapping. + +This module searches for the cscope databases by first using this +variable; if a database location cannot be found using this variable, +then the current directory is searched, then the parent, then the +parent's parent, until a cscope database directory is found, or the +root directory is reached. If the root directory is reached, the +current directory will be used. + +A cscope database directory is one in which EITHER a cscope database +file (e.g., \"cscope.out\") OR a cscope file list (e.g., +\"cscope.files\") exists. If only \"cscope.files\" exists, the +corresponding \"cscope.out\" will be automatically created by cscope +when a search is done. By default, the cscope database file is called +\"cscope.out\", but this can be changed (on a global basis) via the +variable, `cscope-database-file'. There is limited support for cscope +databases that are named differently than that given by +`cscope-database-file', using the variable, `cscope-database-regexps'. + +Here is an example of `cscope-database-regexps': + + (setq cscope-database-regexps + '( + ( \"^/users/jdoe/sources/proj1\" + ( t ) + ( \"/users/jdoe/sources/proj2\") + ( \"/users/jdoe/sources/proj3/mycscope.out\") + ( \"/users/jdoe/sources/proj4\") + t + ( \"/some/master/directory\" (\"-d\" \"-I/usr/local/include\") ) + ) + ( \"^/users/jdoe/sources/gnome/\" + ( \"/master/gnome/database\" (\"-d\") ) + ) + )) + +If the current buffer's directory matches the regexp, +\"^/users/jdoe/sources/proj1\", then the following search will be +done: + + 1. First, the normal hierarchical database search will be used to + locate a cscope database. + + 2. Next, searches will be done using the cscope database + directories, \"/users/jdoe/sources/proj2\", + \"/users/jdoe/sources/proj3/mycscope.out\", and + \"/users/jdoe/sources/proj4\". Note that, instead of the file, + \"cscope.out\", the file, \"mycscope.out\", will be used in the + directory \"/users/jdoe/sources/proj3\". + + 3. If a match was found, searching will stop. + + 4. If a match was not found, searching will be done using + \"/some/master/directory\", and the command-line options \"-d\" + and \"-I/usr/local/include\" will be passed to cscope. + +If the current buffer's directory matches the regexp, +\"^/users/jdoe/sources/gnome\", then the following search will be +done: + + The search will be done only using the directory, + \"/master/gnome/database\". The \"-d\" option will be passed to + cscope. + +If the current buffer's directory does not match any of the above +regexps, then only the normal hierarchical database search will be +done. + +" + :type '(repeat (list :format "%v" + (choice :value "" + (regexp :tag "Buffer regexp") + string) + (choice :value "" + (directory :tag "Cscope database directory") + string) + (string :value "" + :tag "Optional cscope command-line arguments") + )) + :group 'cscope) +(defcustom cscope-name-line-width -30 + "*The width of the combined \"function name:line number\" field in the +cscope results buffer. If negative, the field is left-justified." + :type 'integer + :group 'cscope) + + +(defcustom cscope-truncate-lines truncate-lines + "*The value of `truncate-lines' to use in cscope buffers. +This variable exists because it can be easier to read cscope buffers +with truncated lines, while other buffers do not have truncated lines." + :type 'boolean + :group 'cscope) + + +(defcustom cscope-display-times t + "*If non-nil, display how long each search took. +The elasped times are in seconds. Floating-point support is required +for this to work." + :type 'boolean + :group 'cscope) + + +(defcustom cscope-program "cscope" + "*The pathname of the cscope executable to use." + :type 'string + :group 'cscope) + + +(defcustom cscope-index-file "cscope.files" + "*The name of the cscope file list file." + :type 'string + :group 'cscope) + + +(defcustom cscope-database-file "cscope.out" + "*The name of the cscope database file." + :type 'string + :group 'cscope) + + +(defcustom cscope-edit-single-match t + "*If non-nil and only one match is output, edit the matched location." + :type 'boolean + :group 'cscope) + + +(defcustom cscope-display-cscope-buffer t + "*If non-nil automatically display the *cscope* buffer after each search." + :type 'boolean + :group 'cscope) + + +(defcustom cscope-stop-at-first-match-dir nil + "*If non-nil, stop searching through multiple databases if a match is found. +This option is useful only if multiple cscope database directories are being +used. When multiple databases are searched, setting this variable to non-nil +will cause searches to stop when a search outputs anything; no databases after +this one will be searched." + :type 'boolean + :group 'cscope) + + +(defcustom cscope-use-relative-paths t + "*If non-nil, use relative paths when creating the list of files to index. +The path is relative to the directory in which the cscope database +will be created. If nil, absolute paths will be used. Absolute paths +are good if you plan on moving the database to some other directory +(if you do so, you'll probably also have to modify +\`cscope-database-regexps\'). Absolute paths may also be good if you +share the database file with other users (you\'ll probably want to +specify some automounted network path for this)." + :type 'boolean + :group 'cscope) + + +(defcustom cscope-index-recursively t + "*If non-nil, index files in the current directory and all subdirectories. +If nil, only files in the current directory are indexed. This +variable is only used when creating the list of files to index, or +when creating the list of files and the corresponding cscope database." + :type 'boolean + :group 'cscope) + + +(defcustom cscope-no-mouse-prompts nil + "*If non-nil, use the symbol under the cursor instead of prompting. +Do not prompt for a value, except for when seaching for a egrep pattern +or a file." + :type 'boolean + :group 'cscope) + + +(defcustom cscope-suppress-empty-matches t + "*If non-nil, delete empty matches.") + + +(defcustom cscope-indexing-script "cscope-indexer" + "*The shell script used to create cscope indices." + :type 'string + :group 'cscope) + + +(defcustom cscope-symbol-chars "A-Za-z0-9_" + "*A string containing legal characters in a symbol. +The current syntax table should really be used for this." + :type 'string + :group 'cscope) + + +(defcustom cscope-filename-chars "-.,/A-Za-z0-9_~!@#$%&+=\\\\" + "*A string containing legal characters in a symbol. +The current syntax table should really be used for this." + :type 'string + :group 'cscope) + + +(defcustom cscope-allow-arrow-overlays t + "*If non-nil, use an arrow overlay to show target lines. +Arrow overlays are only used when the following functions are used: + + cscope-show-entry-other-window + cscope-show-next-entry-other-window + cscope-show-prev-entry-other-window + +The arrow overlay is removed when other cscope functions are used. +Note that the arrow overlay is not an actual part of the text, and can +be removed by quitting the cscope buffer." + :type 'boolean + :group 'cscope) + + +(defcustom cscope-overlay-arrow-string "=>" + "*The overlay string to use when displaying arrow overlays." + :type 'string + :group 'cscope) + + +(defvar cscope-minor-mode-hooks nil + "List of hooks to call when entering cscope-minor-mode.") + + +(defconst cscope-separator-line + "-------------------------------------------------------------------------------\n" + "Line of text to use as a visual separator. +Must end with a newline.") + + +;;;; +;;;; Faces for fontification +;;;; + +(defcustom cscope-use-face t + "*Whether to use text highlighting (à la font-lock) or not." + :group 'cscope + :type '(boolean)) + + +(defface cscope-file-face + '((((class color) (background dark)) + (:foreground "yellow")) + (((class color) (background light)) + (:foreground "blue")) + (t (:bold t))) + "Face used to highlight file name in the *cscope* buffer." + :group 'cscope) + + +(defface cscope-function-face + '((((class color) (background dark)) + (:foreground "cyan")) + (((class color) (background light)) + (:foreground "magenta")) + (t (:bold t))) + "Face used to highlight function name in the *cscope* buffer." + :group 'cscope) + + +(defface cscope-line-number-face + '((((class color) (background dark)) + (:foreground "red")) + (((class color) (background light)) + (:foreground "red")) + (t (:bold t))) + "Face used to highlight line number in the *cscope* buffer." + :group 'cscope) + + +(defface cscope-line-face + '((((class color) (background dark)) + (:foreground "green")) + (((class color) (background light)) + (:foreground "black")) + (t (:bold nil))) + "Face used to highlight the rest of line in the *cscope* buffer." + :group 'cscope) + + +(defface cscope-mouse-face + '((((class color) (background dark)) + (:foreground "white" :background "blue")) + (((class color) (background light)) + (:foreground "white" :background "blue")) + (t (:bold nil))) + "Face used when mouse pointer is within the region of an entry." + :group 'cscope) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Probably, nothing user-customizable past this point. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(defconst cscope-running-in-xemacs (string-match "XEmacs\\|Lucid" emacs-version)) + +(defvar cscope-list-entry-keymap nil + "The keymap used in the *cscope* buffer which lists search results.") +(if cscope-list-entry-keymap + nil + (setq cscope-list-entry-keymap (make-keymap)) + (suppress-keymap cscope-list-entry-keymap) + ;; The following section does not appear in the "Cscope" menu. + (if cscope-running-in-xemacs + (define-key cscope-list-entry-keymap [button2] 'cscope-mouse-select-entry-other-window) + (define-key cscope-list-entry-keymap [mouse-2] 'cscope-mouse-select-entry-other-window)) + (define-key cscope-list-entry-keymap [return] 'cscope-select-entry-other-window) + (define-key cscope-list-entry-keymap " " 'cscope-show-entry-other-window) + (define-key cscope-list-entry-keymap "o" 'cscope-select-entry-one-window) + (define-key cscope-list-entry-keymap "q" 'cscope-bury-buffer) + (define-key cscope-list-entry-keymap "Q" 'cscope-quit) + (define-key cscope-list-entry-keymap "h" 'cscope-help) + (define-key cscope-list-entry-keymap "?" 'cscope-help) + ;; The following line corresponds to be beginning of the "Cscope" menu. + (define-key cscope-list-entry-keymap "s" 'cscope-find-this-symbol) + (define-key cscope-list-entry-keymap "d" 'cscope-find-this-symbol) + (define-key cscope-list-entry-keymap "g" 'cscope-find-global-definition) + (define-key cscope-list-entry-keymap "G" + 'cscope-find-global-definition-no-prompting) + (define-key cscope-list-entry-keymap "c" 'cscope-find-functions-calling-this-function) + (define-key cscope-list-entry-keymap "C" 'cscope-find-called-functions) + (define-key cscope-list-entry-keymap "t" 'cscope-find-this-text-string) + (define-key cscope-list-entry-keymap "e" 'cscope-find-egrep-pattern) + (define-key cscope-list-entry-keymap "f" 'cscope-find-this-file) + (define-key cscope-list-entry-keymap "i" 'cscope-find-files-including-file) + ;; --- (The '---' indicates that this line corresponds to a menu separator.) + (define-key cscope-list-entry-keymap "n" 'cscope-next-symbol) + (define-key cscope-list-entry-keymap "N" 'cscope-next-file) + (define-key cscope-list-entry-keymap "p" 'cscope-prev-symbol) + (define-key cscope-list-entry-keymap "P" 'cscope-prev-file) + (define-key cscope-list-entry-keymap "u" 'cscope-pop-mark) + ;; --- + (define-key cscope-list-entry-keymap "a" 'cscope-set-initial-directory) + (define-key cscope-list-entry-keymap "A" 'cscope-unset-initial-directory) + ;; --- + (define-key cscope-list-entry-keymap "L" 'cscope-create-list-of-files-to-index) + (define-key cscope-list-entry-keymap "I" 'cscope-index-files) + (define-key cscope-list-entry-keymap "E" 'cscope-edit-list-of-files-to-index) + (define-key cscope-list-entry-keymap "W" 'cscope-tell-user-about-directory) + (define-key cscope-list-entry-keymap "S" 'cscope-tell-user-about-directory) + (define-key cscope-list-entry-keymap "T" 'cscope-tell-user-about-directory) + (define-key cscope-list-entry-keymap "D" 'cscope-dired-directory) + ;; The previous line corresponds to be end of the "Cscope" menu. + ) + + +(defvar cscope-list-entry-hook nil + "*Hook run after cscope-list-entry-mode entered.") + + +(defun cscope-list-entry-mode () + "Major mode for jumping/showing entry from the list in the *cscope* buffer. + +\\{cscope-list-entry-keymap}" + (use-local-map cscope-list-entry-keymap) + (setq buffer-read-only t + mode-name "cscope" + major-mode 'cscope-list-entry-mode + overlay-arrow-string cscope-overlay-arrow-string) + (or overlay-arrow-position + (setq overlay-arrow-position (make-marker))) + (run-hooks 'cscope-list-entry-hook)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defvar cscope-output-buffer-name "*cscope*" + "The name of the cscope output buffer.") + + +(defvar cscope-info-buffer-name "*cscope-info*" + "The name of the cscope information buffer.") + + +(defvar cscope-process nil + "The current cscope process.") +(make-variable-buffer-local 'cscope-process) + + +(defvar cscope-process-output nil + "A buffer for holding partial cscope process output.") +(make-variable-buffer-local 'cscope-process-output) + + +(defvar cscope-command-args nil + "Internal variable for holding major command args to pass to cscope.") +(make-variable-buffer-local 'cscope-command-args) + + +(defvar cscope-start-directory nil + "Internal variable used to save the initial start directory. +The results buffer gets reset to this directory when a search has +completely finished.") +(make-variable-buffer-local 'cscope-start-directory) + + +(defvar cscope-search-list nil + "A list of (DIR . FLAGS) entries. +This is a list of database directories to search. Each entry in the list +is a (DIR . FLAGS) cell. DIR is the directory to search, and FLAGS are the +flags to pass to cscope when using this database directory. FLAGS can be +nil (meaning, \"no flags\").") +(make-variable-buffer-local 'cscope-search-list) + + +(defvar cscope-searched-dirs nil + "The list of database directories already searched.") +(make-variable-buffer-local 'cscope-searched-dirs) + + +(defvar cscope-filter-func nil + "Internal variable for holding the filter function to use (if any) when +searching.") +(make-variable-buffer-local 'cscope-filter-func) + + +(defvar cscope-sentinel-func nil + "Internal variable for holding the sentinel function to use (if any) when +searching.") +(make-variable-buffer-local 'cscope-filter-func) + + +(defvar cscope-last-file nil + "The file referenced by the last line of cscope process output.") +(make-variable-buffer-local 'cscope-last-file) + + +(defvar cscope-start-time nil + "The search start time, in seconds.") +(make-variable-buffer-local 'cscope-start-time) + + +(defvar cscope-first-match nil + "The first match result output by cscope.") +(make-variable-buffer-local 'cscope-first-match) + + +(defvar cscope-first-match-point nil + "Buffer location of the first match.") +(make-variable-buffer-local 'cscope-first-match-point) + + +(defvar cscope-item-start nil + "The point location of the start of a search's output, before header info.") +(make-variable-buffer-local 'cscope-output-start) + + +(defvar cscope-output-start nil + "The point location of the start of a search's output.") +(make-variable-buffer-local 'cscope-output-start) + + +(defvar cscope-matched-multiple nil + "Non-nil if cscope output multiple matches.") +(make-variable-buffer-local 'cscope-matched-multiple) + + +(defvar cscope-stop-at-first-match-dir-meta nil + "") +(make-variable-buffer-local 'cscope-stop-at-first-match-dir-meta) + + +(defvar cscope-symbol nil + "The last symbol searched for.") + + +(defvar cscope-adjust t + "True if the symbol searched for (cscope-symbol) should be on +the line specified by the cscope database. In such cases the point will be +adjusted if need be (fuzzy matching).") + + +(defvar cscope-adjust-range 1000 + "How far the point should be adjusted if the symbol is not on the line +specified by the cscope database.") + + +(defvar cscope-marker nil + "The location from which cscope was invoked.") + + +(defvar cscope-marker-window nil + "The window which should contain cscope-marker. This is the window from +which cscope-marker is set when searches are launched from the *cscope* +buffer.") + + +(defvar cscope-marker-ring-length 16 + "Length of the cscope marker ring.") + + +(defvar cscope-marker-ring (make-ring cscope-marker-ring-length) + "Ring of markers which are locations from which cscope was invoked.") + + +(defvar cscope-initial-directory nil + "When set the directory in which searches for the cscope database +directory should begin.") + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defvar cscope:map nil + "The cscope keymap.") +(if cscope:map + nil + (setq cscope:map (make-sparse-keymap)) + ;; The following line corresponds to be beginning of the "Cscope" menu. + (define-key cscope:map "\C-css" 'cscope-find-this-symbol) + (define-key cscope:map "\C-csd" 'cscope-find-global-definition) + (define-key cscope:map "\C-csg" 'cscope-find-global-definition) + (define-key cscope:map "\C-csG" 'cscope-find-global-definition-no-prompting) + (define-key cscope:map "\C-csc" 'cscope-find-functions-calling-this-function) + (define-key cscope:map "\C-csC" 'cscope-find-called-functions) + (define-key cscope:map "\C-cst" 'cscope-find-this-text-string) + (define-key cscope:map "\C-cse" 'cscope-find-egrep-pattern) + (define-key cscope:map "\C-csf" 'cscope-find-this-file) + (define-key cscope:map "\C-csi" 'cscope-find-files-including-file) + ;; --- (The '---' indicates that this line corresponds to a menu separator.) + (define-key cscope:map "\C-csb" 'cscope-display-buffer) + (define-key cscope:map "\C-csB" 'cscope-display-buffer-toggle) + (define-key cscope:map "\C-csn" 'cscope-next-symbol) + (define-key cscope:map "\C-csN" 'cscope-next-file) + (define-key cscope:map "\C-csp" 'cscope-prev-symbol) + (define-key cscope:map "\C-csP" 'cscope-prev-file) + (define-key cscope:map "\C-csu" 'cscope-pop-mark) + ;; --- + (define-key cscope:map "\C-csa" 'cscope-set-initial-directory) + (define-key cscope:map "\C-csA" 'cscope-unset-initial-directory) + ;; --- + (define-key cscope:map "\C-csL" 'cscope-create-list-of-files-to-index) + (define-key cscope:map "\C-csI" 'cscope-index-files) + (define-key cscope:map "\C-csE" 'cscope-edit-list-of-files-to-index) + (define-key cscope:map "\C-csW" 'cscope-tell-user-about-directory) + (define-key cscope:map "\C-csS" 'cscope-tell-user-about-directory) + (define-key cscope:map "\C-csT" 'cscope-tell-user-about-directory) + (define-key cscope:map "\C-csD" 'cscope-dired-directory)) + ;; The previous line corresponds to be end of the "Cscope" menu. + +(easy-menu-define cscope:menu + (list cscope:map cscope-list-entry-keymap) + "cscope menu" + '("Cscope" + [ "Find symbol" cscope-find-this-symbol t ] + [ "Find global definition" cscope-find-global-definition t ] + [ "Find global definition no prompting" + cscope-find-global-definition-no-prompting t ] + [ "Find functions calling a function" + cscope-find-functions-calling-this-function t ] + [ "Find called functions" cscope-find-called-functions t ] + [ "Find text string" cscope-find-this-text-string t ] + [ "Find egrep pattern" cscope-find-egrep-pattern t ] + [ "Find a file" cscope-find-this-file t ] + [ "Find files #including a file" + cscope-find-files-including-file t ] + "-----------" + [ "Display *cscope* buffer" cscope-display-buffer t ] + [ "Auto display *cscope* buffer toggle" + cscope-display-buffer-toggle t ] + [ "Next symbol" cscope-next-symbol t ] + [ "Next file" cscope-next-file t ] + [ "Previous symbol" cscope-prev-symbol t ] + [ "Previous file" cscope-prev-file t ] + [ "Pop mark" cscope-pop-mark t ] + "-----------" + ( "Cscope Database" + [ "Set initial directory" + cscope-set-initial-directory t ] + [ "Unset initial directory" + cscope-unset-initial-directory t ] + "-----------" + [ "Create list of files to index" + cscope-create-list-of-files-to-index t ] + [ "Create list and index" + cscope-index-files t ] + [ "Edit list of files to index" + cscope-edit-list-of-files-to-index t ] + [ "Locate this buffer's cscope directory" + cscope-tell-user-about-directory t ] + [ "Dired this buffer's cscope directory" + cscope-dired-directory t ] + ) + "-----------" + ( "Options" + [ "Auto edit single match" + (setq cscope-edit-single-match + (not cscope-edit-single-match)) + :style toggle :selected cscope-edit-single-match ] + [ "Auto display *cscope* buffer" + (setq cscope-display-cscope-buffer + (not cscope-display-cscope-buffer)) + :style toggle :selected cscope-display-cscope-buffer ] + [ "Stop at first matching database" + (setq cscope-stop-at-first-match-dir + (not cscope-stop-at-first-match-dir)) + :style toggle + :selected cscope-stop-at-first-match-dir ] + [ "Never update cscope database" + (setq cscope-do-not-update-database + (not cscope-do-not-update-database)) + :style toggle :selected cscope-do-not-update-database ] + [ "Index recursively" + (setq cscope-index-recursively + (not cscope-index-recursively)) + :style toggle :selected cscope-index-recursively ] + [ "Suppress empty matches" + (setq cscope-suppress-empty-matches + (not cscope-suppress-empty-matches)) + :style toggle :selected cscope-suppress-empty-matches ] + [ "Use relative paths" + (setq cscope-use-relative-paths + (not cscope-use-relative-paths)) + :style toggle :selected cscope-use-relative-paths ] + [ "No mouse prompts" (setq cscope-no-mouse-prompts + (not cscope-no-mouse-prompts)) + :style toggle :selected cscope-no-mouse-prompts ] + ) + )) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Internal functions and variables +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defvar cscope-common-text-plist + (let (plist) + (setq plist (plist-put plist 'mouse-face 'cscope-mouse-face)) + plist) + "List of common text properties to be added to the entry line.") + + +(defun cscope-insert-with-text-properties (text filename &optional line-number) + "Insert an entry with given TEXT, add entry attributes as text properties. +The text properties to be added: +- common property: mouse-face, +- properties are used to open target file and its location: cscope-file, + cscope-line-number" + (let ((plist cscope-common-text-plist) + beg end) + (setq beg (point)) + (insert text) + (setq end (point) + plist (plist-put plist 'cscope-file filename)) + (if line-number + (progn + (if (stringp line-number) + (setq line-number (string-to-number line-number))) + (setq plist (plist-put plist 'cscope-line-number line-number)) + )) + (add-text-properties beg end plist) + )) + + +(if cscope-running-in-xemacs + (progn + (defalias 'cscope-event-window 'event-window) + (defalias 'cscope-event-point 'event-point) + (defalias 'cscope-recenter 'recenter) + ) + (defun cscope-event-window (event) + "Return the window at which the mouse EVENT occurred." + (posn-window (event-start event))) + (defun cscope-event-point (event) + "Return the point at which the mouse EVENT occurred." + (posn-point (event-start event))) + (defun cscope-recenter (&optional n window) + "Center point in WINDOW and redisplay frame. With N, put point on line N." + (save-selected-window + (if (windowp window) + (select-window window)) + (recenter n))) + ) + + +(defun cscope-show-entry-internal (file line-number + &optional save-mark-p window arrow-p) + "Display the buffer corresponding to FILE and LINE-NUMBER +in some window. If optional argument WINDOW is given, +display the buffer in that WINDOW instead. The window is +not selected. Save point on mark ring before goto +LINE-NUMBER if optional argument SAVE-MARK-P is non-nil. +Put `overlay-arrow-string' if arrow-p is non-nil. +Returns the window displaying BUFFER." + (let (buffer old-pos old-point new-point forward-point backward-point + line-end line-length) + (if (and (stringp file) + (integerp line-number)) + (progn + (unless (file-readable-p file) + (error "%s is not readable or exists" file)) + (setq buffer (find-file-noselect file)) + (if (windowp window) + (set-window-buffer window buffer) + (setq window (display-buffer buffer))) + (set-buffer buffer) + (if (> line-number 0) + (progn + (setq old-pos (point)) + (goto-line line-number) + (setq old-point (point)) + (if (and cscope-adjust cscope-adjust-range) + (progn + ;; Calculate the length of the line specified by cscope. + (end-of-line) + (setq line-end (point)) + (goto-char old-point) + (setq line-length (- line-end old-point)) + + ;; Search forward and backward for the pattern. + (setq forward-point (search-forward + cscope-symbol + (+ old-point + cscope-adjust-range) t)) + (goto-char old-point) + (setq backward-point (search-backward + cscope-symbol + (- old-point + cscope-adjust-range) t)) + (if forward-point + (progn + (if backward-point + (setq new-point + ;; Use whichever of forward-point or + ;; backward-point is closest to old-point. + ;; Give forward-point a line-length advantage + ;; so that if the symbol is on the current + ;; line the current line is chosen. + (if (<= (- (- forward-point line-length) + old-point) + (- old-point backward-point)) + forward-point + backward-point)) + (setq new-point forward-point))) + (if backward-point + (setq new-point backward-point) + (setq new-point old-point))) + (goto-char new-point) + (beginning-of-line) + (setq new-point (point))) + (setq new-point old-point)) + (set-window-point window new-point) + (if (and cscope-allow-arrow-overlays arrow-p) + (set-marker overlay-arrow-position (point)) + (set-marker overlay-arrow-position nil)) + (or (not save-mark-p) + (= old-pos (point)) + (push-mark old-pos)) + )) + + (if cscope-marker + (progn ;; The search was successful. Save the marker so it + ;; can be returned to by cscope-pop-mark. + (ring-insert cscope-marker-ring cscope-marker) + ;; Unset cscope-marker so that moving between matches + ;; (cscope-next-symbol, etc.) does not fill + ;; cscope-marker-ring. + (setq cscope-marker nil))) + (setq cscope-marker-window window) + ) + (message "No entry found at point.")) + ) + window) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; functions in *cscope* buffer which lists the search results +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun cscope-select-entry-other-window () + "Display the entry at point in other window, select the window. +Push current point on mark ring and select the entry window." + (interactive) + (let ((file (get-text-property (point) 'cscope-file)) + (line-number (get-text-property (point) 'cscope-line-number)) + window) + (setq window (cscope-show-entry-internal file line-number t)) + (if (windowp window) + (select-window window)) + )) + + +(defun cscope-select-entry-one-window () + "Display the entry at point in one window, select the window." + (interactive) + (let ((file (get-text-property (point) 'cscope-file)) + (line-number (get-text-property (point) 'cscope-line-number)) + window) + (setq window (cscope-show-entry-internal file line-number t)) + (if (windowp window) + (progn + (select-window window) + (sit-for 0) ;; Redisplay hack to allow delete-other-windows + ;; to continue displaying the correct location. + (delete-other-windows window) + )) + )) + + +(defun cscope-select-entry-specified-window (window) + "Display the entry at point in a specified window, select the window." + (interactive) + (let ((file (get-text-property (point) 'cscope-file)) + (line-number (get-text-property (point) 'cscope-line-number))) + (setq window (cscope-show-entry-internal file line-number t window)) + (if (windowp window) + (select-window window)) + )) + + +(defun cscope-mouse-select-entry-other-window (event) + "Display the entry over which the mouse event occurred, select the window." + (interactive "e") + (let ((ep (cscope-event-point event)) + (win (cscope-event-window event)) + buffer file line-number window) + (if ep + (progn + (setq buffer (window-buffer win) + file (get-text-property ep 'cscope-file buffer) + line-number (get-text-property ep 'cscope-line-number buffer)) + (select-window win) + (setq window (cscope-show-entry-internal file line-number t)) + (if (windowp window) + (select-window window)) + ) + (message "No entry found at point.") + ) + )) + + +(defun cscope-show-entry-other-window () + "Display the entry at point in other window. +Point is not saved on mark ring." + (interactive) + (let ((file (get-text-property (point) 'cscope-file)) + (line-number (get-text-property (point) 'cscope-line-number))) + (cscope-show-entry-internal file line-number nil nil t) + )) + + +(defun cscope-buffer-search (do-symbol do-next) + "The body of the following four functions." + (let* (line-number old-point point + (search-file (not do-symbol)) + (search-prev (not do-next)) + (direction (if do-next 1 -1)) + (old-buffer (current-buffer)) + (old-buffer-window (get-buffer-window old-buffer)) + (buffer (get-buffer cscope-output-buffer-name)) + (buffer-window (get-buffer-window (or buffer (error "The *cscope* buffer does not exist yet")))) + ) + (set-buffer buffer) + (setq old-point (point)) + (forward-line direction) + (setq point (point)) + (setq line-number (get-text-property point 'cscope-line-number)) + (while (or (not line-number) + (or (and do-symbol (= line-number -1)) + (and search-file (/= line-number -1)))) + (forward-line direction) + (setq point (point)) + (if (or (and do-next (>= point (point-max))) + (and search-prev (<= point (point-min)))) + (progn + (goto-char old-point) + (error "The %s of the *cscope* buffer has been reached" + (if do-next "end" "beginning")))) + (setq line-number (get-text-property point 'cscope-line-number))) + (if (eq old-buffer buffer) ;; In the *cscope* buffer. + (cscope-show-entry-other-window) + (cscope-select-entry-specified-window old-buffer-window) ;; else + (if (windowp buffer-window) + (set-window-point buffer-window point))) + (set-buffer old-buffer) + )) + + +(defun cscope-display-buffer () + "Display the *cscope* buffer." + (interactive) + (let ((buffer (get-buffer cscope-output-buffer-name))) + (if buffer + (pop-to-buffer buffer) + (error "The *cscope* buffer does not exist yet")))) + + +(defun cscope-display-buffer-toggle () + "Toggle cscope-display-cscope-buffer, which corresponds to +\"Auto display *cscope* buffer\"." + (interactive) + (setq cscope-display-cscope-buffer (not cscope-display-cscope-buffer)) + (message "The cscope-display-cscope-buffer variable is now %s." + (if cscope-display-cscope-buffer "set" "unset"))) + + +(defun cscope-next-symbol () + "Move to the next symbol in the *cscope* buffer." + (interactive) + (cscope-buffer-search t t)) + + +(defun cscope-next-file () + "Move to the next file in the *cscope* buffer." + (interactive) + (cscope-buffer-search nil t)) + + +(defun cscope-prev-symbol () + "Move to the previous symbol in the *cscope* buffer." + (interactive) + (cscope-buffer-search t nil)) + + +(defun cscope-prev-file () + "Move to the previous file in the *cscope* buffer." + (interactive) + (cscope-buffer-search nil nil)) + + +(defun cscope-pop-mark () + "Pop back to where cscope was last invoked." + (interactive) + + ;; This function is based on pop-tag-mark, which can be found in + ;; lisp/progmodes/etags.el. + + (if (ring-empty-p cscope-marker-ring) + (error "There are no marked buffers in the cscope-marker-ring yet")) + (let* ( (marker (ring-remove cscope-marker-ring 0)) + (old-buffer (current-buffer)) + (marker-buffer (marker-buffer marker)) + marker-window + (marker-point (marker-position marker)) + (cscope-buffer (get-buffer cscope-output-buffer-name)) ) + + ;; After the following both cscope-marker-ring and cscope-marker will be + ;; in the state they were immediately after the last search. This way if + ;; the user now makes a selection in the previously generated *cscope* + ;; buffer things will behave the same way as if that selection had been + ;; made immediately after the last search. + (setq cscope-marker marker) + + (if marker-buffer + (if (eq old-buffer cscope-buffer) + (progn ;; In the *cscope* buffer. + (set-buffer marker-buffer) + (setq marker-window (display-buffer marker-buffer)) + (set-window-point marker-window marker-point) + (select-window marker-window)) + (switch-to-buffer marker-buffer)) + (error "The marked buffer has been deleted")) + (goto-char marker-point) + (set-buffer old-buffer))) + + +(defun cscope-set-initial-directory (cs-id) + "Set the cscope-initial-directory variable. The +cscope-initial-directory variable, when set, specifies the directory +where searches for the cscope database directory should begin. This +overrides the current directory, which would otherwise be used." + (interactive "DCscope Initial Directory: ") + (setq cscope-initial-directory cs-id)) + + +(defun cscope-unset-initial-directory () + "Unset the cscope-initial-directory variable." + (interactive) + (setq cscope-initial-directory nil) + (message "The cscope-initial-directory variable is now unset.")) + + +(defun cscope-help () + (interactive) + (message + (format "RET=%s, SPC=%s, o=%s, n=%s, p=%s, q=%s, h=%s" + "Select" + "Show" + "SelectOneWin" + "ShowNext" + "ShowPrev" + "Quit" + "Help"))) + + +(defun cscope-bury-buffer () + "Clean up cscope, if necessary, and bury the buffer." + (interactive) + (let () + (if overlay-arrow-position + (set-marker overlay-arrow-position nil)) + (setq overlay-arrow-position nil + overlay-arrow-string nil) + (bury-buffer (get-buffer cscope-output-buffer-name)) + )) + + +(defun cscope-quit () + (interactive) + (cscope-bury-buffer) + (kill-buffer cscope-output-buffer-name) + ) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun cscope-canonicalize-directory (dir) + (or dir + (setq dir default-directory)) + (setq dir (file-name-as-directory + (expand-file-name (substitute-in-file-name dir)))) + dir + ) + + +(defun cscope-search-directory-hierarchy (directory) + "Look for a cscope database in the directory hierarchy. +Starting from DIRECTORY, look upwards for a cscope database." + (let (this-directory database-dir) + (catch 'done + (if (file-regular-p directory) + (throw 'done directory)) + (setq directory (cscope-canonicalize-directory directory) + this-directory directory) + (while this-directory + (if (or (file-exists-p (concat this-directory cscope-database-file)) + (file-exists-p (concat this-directory cscope-index-file))) + (progn + (setq database-dir this-directory) + (throw 'done database-dir) + )) + (if (string-match "^\\(/\\|[A-Za-z]:[\\/]\\)$" this-directory) + (throw 'done directory)) + (setq this-directory (file-name-as-directory + (file-name-directory + (directory-file-name this-directory)))) + )) + )) + + +(defun cscope-find-info (top-directory) + "Locate a suitable cscope database directory. +First, `cscope-database-regexps' is used to search for a suitable +database directory. If a database location cannot be found using this +variable, then the current directory is searched, then the parent, +then the parent's parent, until a cscope database directory is found, +or the root directory is reached. If the root directory is reached, +the current directory will be used." + (let (info regexps dir-regexp this-directory) + (setq top-directory (cscope-canonicalize-directory + (or top-directory cscope-initial-directory))) + (catch 'done + ;; Try searching using `cscope-database-regexps' ... + (setq regexps cscope-database-regexps) + (while regexps + (setq dir-regexp (car (car regexps))) + (cond + ( (stringp dir-regexp) + (if (string-match dir-regexp top-directory) + (progn + (setq info (cdr (car regexps))) + (throw 'done t) + )) ) + ( (and (symbolp dir-regexp) dir-regexp) + (progn + (setq info (cdr (car regexps))) + (throw 'done t) + ) )) + (setq regexps (cdr regexps)) + ) + + ;; Try looking in the directory hierarchy ... + (if (setq this-directory + (cscope-search-directory-hierarchy top-directory)) + (progn + (setq info (list (list this-directory))) + (throw 'done t) + )) + + ;; Should we add any more places to look? + + ) ;; end catch + (if (not info) + (setq info (list (list top-directory)))) + info + )) + + +(defun cscope-make-entry-line (func-name line-number line) + ;; The format of entry line: + ;; func-name[line-number]______line + ;; <- cscope-name-line-width -> + ;; `format' of Emacs doesn't have "*s" spec. + (let* ((fmt (format "%%%ds %%s" cscope-name-line-width)) + (str (format fmt (format "%s[%s]" func-name line-number) line)) + beg end) + (if cscope-use-face + (progn + (setq end (length func-name)) + (put-text-property 0 end 'face 'cscope-function-face str) + (setq beg (1+ end) + end (+ beg (length line-number))) + (put-text-property beg end 'face 'cscope-line-number-face str) + (setq end (length str) + beg (- end (length line))) + (put-text-property beg end 'face 'cscope-line-face str) + )) + str)) + + +(defun cscope-process-filter (process output) + "Accept cscope process output and reformat it for human readability. +Magic text properties are added to allow the user to select lines +using the mouse." + (let ( (old-buffer (current-buffer)) ) + (unwind-protect + (progn + (set-buffer (process-buffer process)) + ;; Make buffer-read-only nil + (let (buffer-read-only line file function-name line-number moving) + (setq moving (= (point) (process-mark process))) + (save-excursion + (goto-char (process-mark process)) + ;; Get the output thus far ... + (if cscope-process-output + (setq cscope-process-output (concat cscope-process-output + output)) + (setq cscope-process-output output)) + ;; Slice and dice it into lines. + ;; While there are whole lines left ... + (while (and cscope-process-output + (string-match "\\([^\n]+\n\\)\\(\\(.\\|\n\\)*\\)" + cscope-process-output)) + (setq file nil + glimpse-stripped-directory nil + ) + ;; Get a line + (setq line (substring cscope-process-output + (match-beginning 1) (match-end 1))) + (setq cscope-process-output (substring cscope-process-output + (match-beginning 2) + (match-end 2))) + (if (= (length cscope-process-output) 0) + (setq cscope-process-output nil)) + + ;; This should always match. + (if (string-match + "^\\([^ \t]+\\)[ \t]+\\([^ \t]+\\)[ \t]+\\([0-9]+\\)[ \t]+\\(.*\\)\n" + line) + (progn + (let (str) + (setq file (substring line (match-beginning 1) + (match-end 1)) + function-name (substring line (match-beginning 2) + (match-end 2)) + line-number (substring line (match-beginning 3) + (match-end 3)) + line (substring line (match-beginning 4) + (match-end 4)) + ) + ;; If the current file is not the same as the previous + ;; one ... + (if (not (and cscope-last-file + (string= file cscope-last-file))) + (progn + ;; The current file is different. + + ;; Insert a separating blank line if + ;; necessary. + (if cscope-last-file (insert "\n")) + ;; Insert the file name + (setq str (concat "*** " file ":")) + (if cscope-use-face + (put-text-property 0 (length str) + 'face 'cscope-file-face + str)) + (cscope-insert-with-text-properties + str + (expand-file-name file) + ;; Yes, -1 is intentional + -1) + (insert "\n") + )) + (if (not cscope-first-match) + (setq cscope-first-match-point (point))) + ;; ... and insert the line, with the + ;; appropriate indentation. + (cscope-insert-with-text-properties + (cscope-make-entry-line function-name + line-number + line) + (expand-file-name file) + line-number) + (insert "\n") + (setq cscope-last-file file) + (if cscope-first-match + (setq cscope-matched-multiple t) + (setq cscope-first-match + (cons (expand-file-name file) + (string-to-number line-number)))) + )) + (insert line "\n") + )) + (set-marker (process-mark process) (point)) + ) + (if moving + (goto-char (process-mark process))) + (set-buffer-modified-p nil) + )) + (set-buffer old-buffer)) + )) + + +(defun cscope-process-sentinel (process event) + "Sentinel for when the cscope process dies." + (let* ( (buffer (process-buffer process)) window update-window + (done t) (old-buffer (current-buffer)) + (old-buffer-window (get-buffer-window old-buffer)) ) + (set-buffer buffer) + (save-window-excursion + (save-excursion + (if (or (and (setq window (get-buffer-window buffer)) + (= (window-point window) (point-max))) + (= (point) (point-max))) + (progn + (setq update-window t) + )) + (delete-process process) + (let (buffer-read-only continue) + (goto-char (point-max)) + (if (and cscope-suppress-empty-matches + (= cscope-output-start (point))) + (delete-region cscope-item-start (point-max)) + (progn + (if (not cscope-start-directory) + (setq cscope-start-directory default-directory)) + (insert cscope-separator-line) + )) + (setq continue + (and cscope-search-list + (not (and cscope-first-match + cscope-stop-at-first-match-dir + (not cscope-stop-at-first-match-dir-meta))))) + (if continue + (setq continue (cscope-search-one-database))) + (if continue + (progn + (setq done nil) + ) + (progn + (insert "\nSearch complete.") + (if cscope-display-times + (let ( (times (current-time)) cscope-stop elapsed-time ) + (setq cscope-stop (+ (* (car times) 65536.0) + (car (cdr times)) + (* (car (cdr (cdr times))) 1.0E-6))) + (setq elapsed-time (- cscope-stop cscope-start-time)) + (insert (format " Search time = %.2f seconds." + elapsed-time)) + )) + (setq cscope-process nil) + (if cscope-running-in-xemacs + (setq modeline-process ": Search complete")) + (if cscope-start-directory + (setq default-directory cscope-start-directory)) + (if (not cscope-first-match) + (message "No matches were found.")) + ) + )) + (set-buffer-modified-p nil) + )) + (if (and done cscope-first-match-point update-window) + (if window + (set-window-point window cscope-first-match-point) + (goto-char cscope-first-match-point)) + ) + (cond + ( (not done) ;; we're not done -- do nothing for now + (if update-window + (if window + (set-window-point window (point-max)) + (goto-char (point-max)))) + ) + ( cscope-first-match + (if cscope-display-cscope-buffer + (if (and cscope-edit-single-match (not cscope-matched-multiple)) + (cscope-show-entry-internal(car cscope-first-match) + (cdr cscope-first-match) t)) + (cscope-select-entry-specified-window old-buffer-window)) + ) + ) + (if (and done (eq old-buffer buffer) cscope-first-match) + (cscope-help)) + (set-buffer old-buffer) + )) + + +(defun cscope-search-one-database () + "Pop a database entry from cscope-search-list and do a search there." + (let ( next-item options cscope-directory database-file outbuf done + base-database-file-name) + (setq outbuf (get-buffer-create cscope-output-buffer-name)) + (save-excursion + (catch 'finished + (set-buffer outbuf) + (setq options '("-L")) + (while (and (not done) cscope-search-list) + (setq next-item (car cscope-search-list) + cscope-search-list (cdr cscope-search-list) + base-database-file-name cscope-database-file + ) + (if (listp next-item) + (progn + (setq cscope-directory (car next-item)) + (if (not (stringp cscope-directory)) + (setq cscope-directory + (cscope-search-directory-hierarchy + default-directory))) + (if (file-regular-p cscope-directory) + (progn + ;; Handle the case where `cscope-directory' is really + ;; a full path name to a cscope database. + (setq base-database-file-name + (file-name-nondirectory cscope-directory) + cscope-directory + (file-name-directory cscope-directory)) + )) + (setq cscope-directory + (file-name-as-directory cscope-directory)) + (if (not (member cscope-directory cscope-searched-dirs)) + (progn + (setq cscope-searched-dirs (cons cscope-directory + cscope-searched-dirs) + done t) + )) + ) + (progn + (if (and cscope-first-match + cscope-stop-at-first-match-dir + cscope-stop-at-first-match-dir-meta) + (throw 'finished nil)) + )) + ) + (if (not done) + (throw 'finished nil)) + (if (car (cdr next-item)) + (let (newopts) + (setq newopts (car (cdr next-item))) + (if (not (listp newopts)) + (error (format "Cscope options must be a list: %s" newopts))) + (setq options (append options newopts)) + )) + (if cscope-command-args + (setq options (append options cscope-command-args))) + (setq database-file (concat cscope-directory base-database-file-name) + cscope-searched-dirs (cons cscope-directory + cscope-searched-dirs) + ) + + ;; The database file and the directory containing the database file + ;; must both be writable. + (if (or (not (file-writable-p database-file)) + (not (file-writable-p (file-name-directory database-file))) + cscope-do-not-update-database) + (setq options (cons "-d" options))) + + (goto-char (point-max)) + (setq cscope-item-start (point)) + (if (string= base-database-file-name cscope-database-file) + (insert "\nDatabase directory: " cscope-directory "\n" + cscope-separator-line) + (insert "\nDatabase directory/file: " + cscope-directory base-database-file-name "\n" + cscope-separator-line)) + ;; Add the correct database file to search + (setq options (cons base-database-file-name options)) + (setq options (cons "-f" options)) + (setq cscope-output-start (point)) + (setq default-directory cscope-directory) + (if cscope-filter-func + (progn + (setq cscope-process-output nil + cscope-last-file nil + ) + (setq cscope-process + (apply 'start-process "cscope" outbuf + cscope-program options)) + (set-process-filter cscope-process cscope-filter-func) + (set-process-sentinel cscope-process cscope-sentinel-func) + (set-marker (process-mark cscope-process) (point)) + (process-kill-without-query cscope-process) + (if cscope-running-in-xemacs + (setq modeline-process ": Searching ...")) + (setq buffer-read-only t) + ) + (apply 'call-process cscope-program nil outbuf t options) + ) + t + )) + )) + + +(defun cscope-call (msg args &optional directory filter-func sentinel-func) + "Generic function to call to process cscope requests. +ARGS is a list of command-line arguments to pass to the cscope +process. DIRECTORY is the current working directory to use (generally, +the directory in which the cscope database is located, but not +necessarily), if different that the current one. FILTER-FUNC and +SENTINEL-FUNC are optional process filter and sentinel, respectively." + (let ( (outbuf (get-buffer-create cscope-output-buffer-name)) + (old-buffer (current-buffer)) ) + (if cscope-process + (error "A cscope search is still in progress -- only one at a time is allowed")) + (setq directory (cscope-canonicalize-directory + (or cscope-initial-directory directory))) + (if (eq outbuf old-buffer) ;; In the *cscope* buffer. + (if cscope-marker-window + (progn + ;; Assume that cscope-marker-window is the window, from the + ;; users perspective, from which the search was launched and the + ;; window that should be returned to upon cscope-pop-mark. + (set-buffer (window-buffer cscope-marker-window)) + (setq cscope-marker (point-marker)) + (set-buffer old-buffer))) + (progn ;; Not in the *cscope buffer. + ;; Set the cscope-marker-window to whichever window this search + ;; was launched from. + (setq cscope-marker-window (get-buffer-window old-buffer)) + (setq cscope-marker (point-marker)))) + (save-excursion + (set-buffer outbuf) + (if cscope-display-times + (let ( (times (current-time)) ) + (setq cscope-start-time (+ (* (car times) 65536.0) (car (cdr times)) + (* (car (cdr (cdr times))) 1.0E-6))))) + (setq default-directory directory + cscope-start-directory nil + cscope-search-list (cscope-find-info directory) + cscope-searched-dirs nil + cscope-command-args args + cscope-filter-func filter-func + cscope-sentinel-func sentinel-func + cscope-first-match nil + cscope-first-match-point nil + cscope-stop-at-first-match-dir-meta (memq t cscope-search-list) + cscope-matched-multiple nil + buffer-read-only nil) + (buffer-disable-undo) + (erase-buffer) + (setq truncate-lines cscope-truncate-lines) + (if msg + (insert msg "\n")) + (cscope-search-one-database) + ) + (if cscope-display-cscope-buffer + (progn + (pop-to-buffer outbuf) + (cscope-help)) + (set-buffer outbuf)) + (goto-char (point-max)) + (cscope-list-entry-mode) + )) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defvar cscope-unix-index-process-buffer-name "*cscope-indexing-buffer*" + "The name of the buffer to use for displaying indexing status/progress.") + + +(defvar cscope-unix-index-process-buffer nil + "The buffer to use for displaying indexing status/progress.") + + +(defvar cscope-unix-index-process nil + "The current indexing process.") + + +(defun cscope-unix-index-files-sentinel (process event) + "Simple sentinel to print a message saying that indexing is finished." + (let (buffer) + (save-window-excursion + (save-excursion + (setq buffer (process-buffer process)) + (set-buffer buffer) + (goto-char (point-max)) + (insert cscope-separator-line "\nIndexing finished\n") + (delete-process process) + (setq cscope-unix-index-process nil) + (set-buffer-modified-p nil) + )) + )) + + +(defun cscope-unix-index-files-internal (top-directory header-text args) + "Core function to call the indexing script." + (let () + (save-excursion + (setq top-directory (cscope-canonicalize-directory top-directory)) + (setq cscope-unix-index-process-buffer + (get-buffer-create cscope-unix-index-process-buffer-name)) + (display-buffer cscope-unix-index-process-buffer) + (set-buffer cscope-unix-index-process-buffer) + (setq buffer-read-only nil) + (setq default-directory top-directory) + (buffer-disable-undo) + (erase-buffer) + (if header-text + (insert header-text)) + (setq args (append args + (list "-v" + "-i" cscope-index-file + "-f" cscope-database-file + (if cscope-use-relative-paths + "." top-directory)))) + (if cscope-index-recursively + (setq args (cons "-r" args))) + (setq cscope-unix-index-process + (apply 'start-process "cscope-indexer" + cscope-unix-index-process-buffer + cscope-indexing-script args)) + (set-process-sentinel cscope-unix-index-process + 'cscope-unix-index-files-sentinel) + (process-kill-without-query cscope-unix-index-process) + ) + )) + + +(defun cscope-index-files (top-directory) + "Index files in a directory. +This function creates a list of files to index, and then indexes +the listed files. +The variable, \"cscope-index-recursively\", controls whether or not +subdirectories are indexed." + (interactive "DIndex files in directory: ") + (let () + (cscope-unix-index-files-internal + top-directory + (format "Creating cscope index `%s' in:\n\t%s\n\n%s" + cscope-database-file top-directory cscope-separator-line) + nil) + )) + + +(defun cscope-create-list-of-files-to-index (top-directory) + "Create a list of files to index. +The variable, \"cscope-index-recursively\", controls whether or not +subdirectories are indexed." + (interactive "DCreate file list in directory: ") + (let () + (cscope-unix-index-files-internal + top-directory + (format "Creating cscope file list `%s' in:\n\t%s\n\n" + cscope-index-file top-directory) + '("-l")) + )) + + +(defun cscope-edit-list-of-files-to-index () + "Search for and edit the list of files to index. +If this functions causes a new file to be edited, that means that a +cscope.out file was found without a corresponding cscope.files file." + (interactive) + (let (info directory file) + (setq info (cscope-find-info nil)) + (if (/= (length info) 1) + (error "There is no unique cscope database directory!")) + (setq directory (car (car info))) + (if (not (stringp directory)) + (setq directory + (cscope-search-directory-hierarchy default-directory))) + (setq file (concat (file-name-as-directory directory) cscope-index-file)) + (find-file file) + (message (concat "File: " file)) + )) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun cscope-tell-user-about-directory () + "Display the name of the directory containing the cscope database." + (interactive) + (let (info directory) + (setq info (cscope-find-info nil)) + (if (= (length info) 1) + (progn + (setq directory (car (car info))) + (message (concat "Cscope directory: " directory)) + ) + (let ( (outbuf (get-buffer-create cscope-info-buffer-name)) ) + (display-buffer outbuf) + (save-excursion + (set-buffer outbuf) + (buffer-disable-undo) + (erase-buffer) + (insert "Cscope search directories:\n") + (while info + (if (listp (car info)) + (progn + (setq directory (car (car info))) + (if (not (stringp directory)) + (setq directory + (cscope-search-directory-hierarchy + default-directory))) + (insert "\t" directory "\n") + )) + (setq info (cdr info)) + ) + ) + )) + )) + + +(defun cscope-dired-directory () + "Run dired upon the cscope database directory. +If possible, the cursor is moved to the name of the cscope database +file." + (interactive) + (let (info directory buffer p1 p2 pos) + (setq info (cscope-find-info nil)) + (if (/= (length info) 1) + (error "There is no unique cscope database directory!")) + (setq directory (car (car info))) + (if (not (stringp directory)) + (setq directory + (cscope-search-directory-hierarchy default-directory))) + (setq buffer (dired-noselect directory nil)) + (switch-to-buffer buffer) + (set-buffer buffer) + (save-excursion + (goto-char (point-min)) + (setq p1 (search-forward cscope-index-file nil t)) + (if p1 + (setq p1 (- p1 (length cscope-index-file)))) + ) + (save-excursion + (goto-char (point-min)) + (setq p2 (search-forward cscope-database-file nil t)) + (if p2 + (setq p2 (- p2 (length cscope-database-file)))) + ) + (cond + ( (and p1 p2) + (if (< p1 p2) + (setq pos p1) + (setq pos p2)) + ) + ( p1 + (setq pos p1) + ) + ( p2 + (setq pos p2) + ) + ) + (if pos + (set-window-point (get-buffer-window buffer) pos)) + )) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun cscope-extract-symbol-at-cursor (extract-filename) + (let* ( (symbol-chars (if extract-filename + cscope-filename-chars + cscope-symbol-chars)) + (symbol-char-regexp (concat "[" symbol-chars "]")) + ) + (save-excursion + (buffer-substring-no-properties + (progn + (if (not (looking-at symbol-char-regexp)) + (re-search-backward "\\w" nil t)) + (skip-chars-backward symbol-chars) + (point)) + (progn + (skip-chars-forward symbol-chars) + (point) + ))) + )) + + +(defun cscope-prompt-for-symbol (prompt extract-filename) + "Prompt the user for a cscope symbol." + (let (sym) + (setq sym (cscope-extract-symbol-at-cursor extract-filename)) + (if (or (not sym) + (string= sym "") + (not (and cscope-running-in-xemacs + cscope-no-mouse-prompts current-mouse-event + (or (mouse-event-p current-mouse-event) + (misc-user-event-p current-mouse-event)))) + ;; Always prompt for symbol in dired mode. + (eq major-mode 'dired-mode) + ) + (setq sym (read-from-minibuffer prompt sym)) + sym) + )) + + +(defun cscope-find-this-symbol (symbol) + "Locate a symbol in source code." + (interactive (list + (cscope-prompt-for-symbol "Find this symbol: " nil) + )) + (let ( (cscope-adjust t) ) ;; Use fuzzy matching. + (setq cscope-symbol symbol) + (cscope-call (format "Finding symbol: %s" symbol) + (list "-0" symbol) nil 'cscope-process-filter + 'cscope-process-sentinel) + )) + + +(defun cscope-find-global-definition (symbol) + "Find a symbol's global definition." + (interactive (list + (cscope-prompt-for-symbol "Find this global definition: " nil) + )) + (let ( (cscope-adjust t) ) ;; Use fuzzy matching. + (setq cscope-symbol symbol) + (cscope-call (format "Finding global definition: %s" symbol) + (list "-1" symbol) nil 'cscope-process-filter + 'cscope-process-sentinel) + )) + + +(defun cscope-find-global-definition-no-prompting () + "Find a symbol's global definition without prompting." + (interactive) + (let ( (symbol (cscope-extract-symbol-at-cursor nil)) + (cscope-adjust t) ) ;; Use fuzzy matching. + (setq cscope-symbol symbol) + (cscope-call (format "Finding global definition: %s" symbol) + (list "-1" symbol) nil 'cscope-process-filter + 'cscope-process-sentinel) + )) + + +(defun cscope-find-called-functions (symbol) + "Display functions called by a function." + (interactive (list + (cscope-prompt-for-symbol + "Find functions called by this function: " nil) + )) + (let ( (cscope-adjust nil) ) ;; Disable fuzzy matching. + (setq cscope-symbol symbol) + (cscope-call (format "Finding functions called by: %s" symbol) + (list "-2" symbol) nil 'cscope-process-filter + 'cscope-process-sentinel) + )) + + +(defun cscope-find-functions-calling-this-function (symbol) + "Display functions calling a function." + (interactive (list + (cscope-prompt-for-symbol + "Find functions calling this function: " nil) + )) + (let ( (cscope-adjust t) ) ;; Use fuzzy matching. + (setq cscope-symbol symbol) + (cscope-call (format "Finding functions calling: %s" symbol) + (list "-3" symbol) nil 'cscope-process-filter + 'cscope-process-sentinel) + )) + + +(defun cscope-find-this-text-string (symbol) + "Locate where a text string occurs." + (interactive (list + (cscope-prompt-for-symbol "Find this text string: " nil) + )) + (let ( (cscope-adjust t) ) ;; Use fuzzy matching. + (setq cscope-symbol symbol) + (cscope-call (format "Finding text string: %s" symbol) + (list "-4" symbol) nil 'cscope-process-filter + 'cscope-process-sentinel) + )) + + +(defun cscope-find-egrep-pattern (symbol) + "Run egrep over the cscope database." + (interactive (list + (let (cscope-no-mouse-prompts) + (cscope-prompt-for-symbol "Find this egrep pattern: " nil)) + )) + (let ( (cscope-adjust t) ) ;; Use fuzzy matching. + (setq cscope-symbol symbol) + (cscope-call (format "Finding egrep pattern: %s" symbol) + (list "-6" symbol) nil 'cscope-process-filter + 'cscope-process-sentinel) + )) + + +(defun cscope-find-this-file (symbol) + "Locate a file." + (interactive (list + (let (cscope-no-mouse-prompts) + (cscope-prompt-for-symbol "Find this file: " t)) + )) + (let ( (cscope-adjust nil) ) ;; Disable fuzzy matching. + (setq cscope-symbol symbol) + (cscope-call (format "Finding file: %s" symbol) + (list "-7" symbol) nil 'cscope-process-filter + 'cscope-process-sentinel) + )) + + +(defun cscope-find-files-including-file (symbol) + "Locate all files #including a file." + (interactive (list + (let (cscope-no-mouse-prompts) + (cscope-prompt-for-symbol + "Find files #including this file: " t)) + )) + (let ( (cscope-adjust t) ) ;; Use fuzzy matching. + (setq cscope-symbol symbol) + (cscope-call (format "Finding files #including file: %s" symbol) + (list "-8" symbol) nil 'cscope-process-filter + 'cscope-process-sentinel) + )) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defvar cscope-minor-mode nil + "") +(make-variable-buffer-local 'cscope-minor-mode) +(put 'cscope-minor-mode 'permanent-local t) + + +(defun cscope-minor-mode (&optional arg) + "" + (progn + (setq cscope-minor-mode (if (null arg) t (car arg))) + (if cscope-minor-mode + (progn + (easy-menu-add cscope:menu cscope:map) + (run-hooks 'cscope-minor-mode-hooks) + )) + cscope-minor-mode + )) + + +(defun cscope:hook () + "" + (progn + (cscope-minor-mode) + )) + + +(or (assq 'cscope-minor-mode minor-mode-map-alist) + (setq minor-mode-map-alist (cons (cons 'cscope-minor-mode cscope:map) + minor-mode-map-alist))) + +(add-hook 'c-mode-hook (function cscope:hook)) +(add-hook 'c++-mode-hook (function cscope:hook)) +(add-hook 'dired-mode-hook (function cscope:hook)) + +(provide 'xcscope) |