1 ; This buffer is for notes you don't want to save, and for Lisp evaluation.
2 ;; If you want to create a file, visit that file with C-x C-f,
3 ;; then enter the text in that file's own buffer.
5 ;; TO DO : tag completion DONE
6 ;; TO DO : tags search DONE
7 ;; TO DO : eldoc integration DONE
8 ;; TO DO : more than one lang per dir DONE
9 ;; TO DO : compile window for ectags DONE
10 ;; TO DO : do sthing about ginormous tag files
11 ;; TO DO : .. use abbreviated info
12 ;; TO DO : .. use gzipped tag files
13 ;; TO DO : use search for locating tag rather than line #
14 ;; TO DO : some kind of higlighting for select buffer
15 ;; TO DO : include line matched when searching for references
21 ;; Asm *.asm *.ASM *.s *.S *.A51 *.29[kK] *.[68][68][kKsSxX] *.[xX][68][68]
23 ;; Awk *.awk *.gawk *.mawk
26 ;; C++ *.c++ *.cc *.cp *.cpp *.cxx *.h *.h++ *.hh *.hp *.hpp *.hxx *.C *.H
28 ;; Cobol *.cbl *.cob *.CBL *.COB
30 ;; Erlang *.erl *.ERL *.hrl *.HRL
31 ;; Fortran *.f *.for *.ftn *.f77 *.f90 *.f95 *.F *.FOR *.FTN *.F77 *.F90 *.F95
35 ;; Lisp *.cl *.clisp *.el *.l *.lisp *.lsp *.ml
37 ;; Make *.mak *.mk [Mm]akefile
39 ;; Perl *.pl *.pm *.plx *.perl
40 ;; PHP *.php *.php3 *.phtml
41 ;; Python *.py *.python
42 ;; REXX *.cmd *.rexx *.rx
44 ;; Scheme *.SCM *.SM *.sch *.scheme *.scm *.sm
45 ;; Sh *.sh *.SH *.bsh *.bash *.ksh *.zsh
49 ;; Tcl *.tcl *.tk *.wish *.itcl
50 ;; Vera *.vr *.vri *.vrh
55 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
61 "Exuberant Ctags Support for Emacs"
66 (defcustom ectags-command
"ectags"
67 "Name of the exuberant ctags executable on your system"
72 (defcustom ectags-config-file
"~/.ectags"
73 "Name of the exuberant-ctags configuration file."
78 (defcustom ectags-language-file-suffix-alist
79 '(( "asp" .
( "*.asp" "*.asa" ))
80 ( "awk" .
( "*.awk" "*.gawk" "*.mawk"))
81 ( "c" .
( "*.c" "*.h" ))
82 ( "c++" .
( "*.c++" "*.cc" "*.cp" "*.cpp" "*.cxx" "*.h" "*.h++" "*.hh" "*.hp" "*.hpp" "*.hxx" "*.c" "*.C" "*.h" "*.H"))
84 ( "java" .
( "*.java " ))
85 ( "lisp" .
( "*.cl" "*.clisp" "*.el" "*.l" "*.lisp" "*.lsp" "*.ml"))
86 ( "python" .
( "*.py" "*.python" ))
87 ( "SQL" .
( "*.sql" ))
88 ( "Tcl" .
( "*.tcl" "*.tk" "*.wish" "*.itcl" )))
89 "Association list defining file masks for languages"
94 (defcustom ectags-system-tag-table-list nil
95 "List of tags tables that include system headers"
100 (defcustom ectags-api-files
101 '(( "wx" .
"/usr/local/include/wx" )
102 ( "gtk" .
"/usr/include/gtk-2.0" )
103 ( "glib" .
"/usr/include/glib-2.0" ))
104 "Association list mapping apis to directories"
110 (defcustom ectags-select-mode-hook nil
111 "*List of functions to call on entry to ectags-select-mode mode."
115 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
118 (defvar *ectags-matches
* nil
119 "List of candiate tag matches")
121 (defvar *ectags-regexp
* nil
122 "Holds regexp currently being sought in tags")
124 (defvar *ectags-max-candidates
* 7
125 "How many candidates to select between")
127 (defvar *ectags-case-sensitive
* t
128 "Is the tag matching case sensitive?")
130 (defvar *ectags-autopop-tag
* t
131 "If non-nil, automatically pop the tag off the tag stack when jumped to")
133 (defvar *ectags-tag-stack
* nil
134 "Stack of tag positions for browsing.")
136 (defvar *ectags-obarray
* nil
137 "Obarray used for ectags completions.")
139 (defvar *ectags-select-buffer-name
* "*ectags-select*"
140 "ectags-select buffer name.")
142 (defvar *ectags-reference-buffer-name
* "*ectag References*"
143 "ectags-reference buffer-name")
146 (defvar ectags-select-mode-font-lock-keywords nil
147 "ectags-select font-lock-keywords.")
149 (defvar *ectags-select-source-buffer
* nil
150 "ectags-select source buffer tag was found from.")
152 (defvar *ectags-reference-source-buffer
* nil
153 "ectags-reference source buffer tag was found from.")
155 (defvar *ectags-select-opened-window
* nil
156 "ectags-select opened a select window.")
158 (defvar *ectags-reference-opened-window
* nil
159 "ectags-referecnce opened a reference window.")
162 (defvar *ectags-scan-marks
* nil
163 "Holds markers where matches found.")
165 (defconst ectags-select-non-tag-regexp
"\\(\\s-*$\\|In:\\|Finding tag:\\)"
166 "ectags-select non-tag regex.")
169 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
172 ;; Klaus Berndl <klaus.berndl@sdm.de>: we have to take account that GNU Emacs
173 ;; > 21.3 has changed its split-string function! For the new split-string is
174 ;; (cdr (split-string ...)) not nil (at least in our context below), for GNU
175 ;; Emacs <= 21.3 nil!
176 (defun ectags-left-trim (str)
177 "Return a string stripped of all leading whitespaces of STR."
178 (let ((split-result (split-string str
"^[\n\t ]*")))
179 (or (or (and (cdr split-result
) ;; GNU Emacs > 21.3
180 (car (cdr split-result
)))
184 (defun ectags-right-trim (str)
185 "Return a string stripped of all trailing whitespaces of STR."
186 (or (car (split-string str
"[\n\t ]*$")) ""))
188 (defun ectags-trim (str)
189 "Applies `ectags-right-trim' and `ectags-left-trim' to STR."
190 (ectags-left-trim (ectags-right-trim str
)))
192 (defun ectags-full-trim (str)
193 "Applies `ectags-trim' and `ectags-middle-trim' to STR."
194 (ectags-excessive-trim (ectags-trim str
)))
196 ;; creating tag files ------------------------------------------------------------------------------------
199 (defun make-suffix-clauses (languages)
202 (concat " -iname \"" s
"\""))
203 (cdr (assoc-string l ectags-language-file-suffix-alist
))))
204 (split-string languages
)))
206 (defun make-shell-command-prefix (directory)
207 (concat "find " (expand-file-name directory
)))
209 (defun make-tag-file-name (directory)
210 (expand-file-name (concat directory
(string directory-sep-char
) "tags")))
212 (defun ectag-directory-command (directory languages
)
213 "Produce a command needed to scan the given directory for files
214 of the given language and produce tags"
217 (car (make-suffix-clauses languages
)))
218 (shell-command-prefix
219 (make-shell-command-prefix directory
))
220 (shell-command-suffix
221 (concat " | " ectags-command
" -o " (make-tag-file-name directory
) " --options="
222 (expand-file-name ectags-config-file
) " --verbose --excmd=n --extra=+fq --fields=+afiKlmnsSzt --file-scope=no -L -")))
223 (concat shell-command-prefix
228 (cdr suffix-clauses
)))
229 shell-command-suffix
)))
234 (defun ectags-tag-directory ()
235 "Prompt for a directory and a langage and create a tag file."
237 ;; prompt for directory
239 (read-directory-name "Directory to tag? " default-directory
))
240 (tag-languages (completing-read "Languages to tag? " ectags-language-file-suffix-alist nil nil
)))
241 (add-to-list 'compilation-error-regexp-alist
242 '("^\\([^:]+\\) confusing argument declarations beginning at line \\([0-9]+\\))" 1 2))
243 (compile (ectag-directory-command tag-directory tag-languages
) t
)))
246 ;; building tag completion obarray --------------------------------------------------
248 (defun extract-ectags (&optional tag-buffer obarray
)
249 "Extract a list of tags from a buffer"
252 (set-buffer tag-buffer
))
253 (goto-char (point-min))
255 ;; now point is at first tag
256 (while (/= (point) (point-max))
259 (let* ((start (point-marker))
260 (end (progn (forward-word) (point-marker))))
261 (intern-soft (buffer-substring-no-properties start end
) obarray
)
265 (defun extract-ectags-files (&optional tag-buffer
)
266 "Extract a list of tags from a tag-buffer"
270 (set-buffer tag-buffer
))
271 (goto-char (point-min))
273 ;; now point is at first tag
274 (while (search-forward "kind:file" (point-max) t
)
276 (when (search-forward " " (point-max) t
)
280 (search-forward " " (point-max) t
)
283 (add-to-list 'result
(buffer-substring-no-properties start end
)))
288 (defun make-ectags-obarray ()
289 (let ((result (make-vector 65535 0)))
293 (extract-ectags b result
))))
295 (setq *ectags-obarray
* result
)))
297 (defun flatten-file-list (l)
302 (setq stack
(cons (cdr l
)
305 (setq result
(cons l result
)
311 (defun make-ectags-file-list ()
312 "Create a list of all files in the tags"
315 (mapcar (lambda (b) (extract-ectags-files b
)) (ectags-table-list)))
316 (flatten-file-list result
)))
318 ;; tags table mode ------------------------------------------------------------------------------------
320 (defun ectags-table-list ()
321 "Return a list of available tag tables."
322 (let (tags-table-list)
323 (dolist (buffer (buffer-list) tags-table-list
)
324 (when (assoc 'is-ectag-table
(buffer-local-variables buffer
))
325 (push buffer tags-table-list
)))
329 (defvar ectags-table-mode-syntax-table
330 (let ((ectags-syntax-table text-mode-syntax-table
))
331 (modify-syntax-entry ?_
"w" ectags-syntax-table
)
332 (modify-syntax-entry ?-
"w" ectags-syntax-table
)
333 (modify-syntax-entry ?
# "w" ectags-syntax-table
)
334 (modify-syntax-entry ?
! "w" ectags-syntax-table
)
335 (modify-syntax-entry ?
\" "w" ectags-syntax-table
)
336 (modify-syntax-entry ?
& "w" ectags-syntax-table
)
337 (modify-syntax-entry ?
< "w" ectags-syntax-table
)
338 (modify-syntax-entry ?\
( "w" ectags-syntax-table
)
339 (modify-syntax-entry ?\
) "w" ectags-syntax-table
)
340 (modify-syntax-entry ?
: "w" ectags-syntax-table
)
341 (modify-syntax-entry ?\
; "w" ectags-syntax-table)
342 (modify-syntax-entry ??
"w" ectags-syntax-table
)
343 (modify-syntax-entry ?
@ "w" ectags-syntax-table
)
344 (modify-syntax-entry ?\
"w" ectags-syntax-table
)
345 (modify-syntax-entry ?\
[ "w" ectags-syntax-table
)
346 (modify-syntax-entry ?\
] "w" ectags-syntax-table
)
347 (modify-syntax-entry ?\
{ "w" ectags-syntax-table
)
348 (modify-syntax-entry ?\
} "w" ectags-syntax-table
)
349 (modify-syntax-entry ?|
"w" ectags-syntax-table
)
350 (modify-syntax-entry ?
\' "w" ectags-syntax-table
)
351 (modify-syntax-entry ?^
"w" ectags-syntax-table
)
352 (modify-syntax-entry ?
, "w" ectags-syntax-table
)
353 (modify-syntax-entry ?
` "w" ectags-syntax-table
)
354 (modify-syntax-entry ?~
"w" ectags-syntax-table
)
356 "Punctuation free table")
360 (defun ectags-table-mode ()
361 "Major mode for exuberant ctags table file buffers."
363 (kill-all-local-variables)
364 (setq major-mode
'ectags-table-mode
)
365 (set-syntax-table ectags-table-mode-syntax-table
)
366 (setq mode-name
"ECTags Tags Table")
367 (set (make-local-variable 'is-ectag-table
) t
))
371 ;; removing tags tables ------------------------------------------------------------------------------------
373 (defun ectags-wipe-tag-tables ()
374 "Wipe out all ectags tables"
378 (when (bufferp x
) (progn (bury-buffer x
) (kill-buffer x
))))
380 (setq *ectags-obarray
* nil
))
382 ;; -- adding tags tables ---------------------------------------------------------------------------------
385 ;; Expand tags table name FILE into a complete file name.
386 (defun ectags-expand-table-name (file)
387 (setq file
(expand-file-name file
))
388 (if (file-directory-p file
)
389 (expand-file-name "tags" file
)
392 ;; Return non-nil iff the current buffer is a valid etags TAGS file.
393 (defun ectags-verify-tags-table ()
394 "Is current buffer actually an ectags table."
395 ;; Use eq instead of = in case char-after returns nil.
396 (goto-char (point-min))
397 (looking-at "!_TAG_FILE_FORMAT"))
399 (defun ectags-verify-table (file)
400 "Given a file, read it in to a buffer and validate it as a tags table."
402 (message "Validating tags table %s " file
)
403 (if (get-file-buffer file
)
405 (set-buffer (get-file-buffer file
))
406 (unless (ectags-verify-tags-table)
408 (when (file-exists-p file
)
410 (set-buffer (find-file-noselect file
))
411 (when (ectags-verify-tags-table)
412 (ectags-table-mode)))))
413 (assoc 'is-ectag-table
(buffer-local-variables))))
416 (defun ectags-visit-tags-table (name)
417 "Visit an exuberant ctags file and add it to the current list of tags tables."
419 (list (read-file-name "Visit tags table (default tags): "
421 (expand-file-name "tags"
424 (let ((curbuf (current-buffer))
425 (local-tags-filename (ectags-expand-table-name name
)))
426 (if (ectags-verify-table local-tags-filename
)
427 ;; We have a valid tags table.
428 (progn (message "Valid tags table")
429 (setq *ectags-obarray
* (make-ectags-obarray)))
430 ;; The buffer was not valid. Don't use it again.
431 (progn (error "Not a valid tags table")))))
434 ;; -- saving and reloading sets of tag tables ------------------------------------------------
437 (defun ectags-output (tag-buffer)
438 "Output a line needed to restore this table to the tags buffer list"
439 (insert "(add-working-ectags-table " (buffer-file-name tag-buffer
) ")\n"))
441 (defun save-working-ectags-tables (fname)
442 "Save the current working list of ectags tables in a file"
443 (interactive "fFile to save tags tables in?:")
447 ";; -*- mode: fundamental; coding: emacs-mule; -*-\n"
448 ";; Created " (current-time-string) "\n"
449 ";; Emacs version " emacs-version
"\n\n"
450 (dolist (tagbuff (ectags-table-list))
451 (ectags-output tagbuff
))
453 (write-region (point min
) (point-max) fname nil
'nomessage
))))
455 (defun read-working-ectags-tables (fname)
456 "Read the current working list of ectags tables in a file"
457 (interactive "fFile to read tags tables from?:")
461 ;; actually finding tags and so forth ------------------------------------------------------------------------------------------------
463 (defun ectags-match-tagname (tag-match)
466 (defun ectags-match-filename (tag-match)
469 (defun ectags-match-linenumber (tag-match)
472 (defun ectags-match-tag-info (tag-match)
475 (defun ectags-fname (tag-match))
478 (defun match-ectags (tag fname lnumber info
)
479 "Given a tags match, rank it (via regexp match length) and
480 plonk it in the match candidates."
482 ((saved-fold-search case-fold-search
)
483 (case-fold-search (not *ectags-case-sensitive
*))
484 (match-rank (string-match *ectags-regexp
* tag
)))
487 ((full-match-rank (- (length tag
) (length *ectags-regexp
*))))
488 ;; (message (format "Found %s ranking %d " tag full-match-rank))
489 (add-to-list '*ectags-matches
*
494 (string-to-number lnumber
)
495 (ectags-trim info
)))))
496 (setq case-fold-search saved-fold-search
)))
498 (defun scan-ectag (fn tag-buffer
)
499 "Scan a tag table buffer for a match with a tag. Applies fn to all matches."
501 (set-buffer tag-buffer
)
502 (goto-char (point-min))
503 (while (re-search-forward (format "^\\([^ ]*%s[^ ]*\\) \\([^ ]+\\) \\([0-9]+\\);\"\\(.+\\)$" *ectags-regexp
*) nil t
)
504 (apply fn
(list (match-string-no-properties 1)
505 (match-string-no-properties 2)
506 (match-string-no-properties 3)
507 (match-string-no-properties 4))))))
509 (defun find-ectag (fn tag-buffer
)
510 "Scan a tag table buffer for an exact match with a tag"
512 (set-buffer tag-buffer
)
513 (goto-char (point-min))
514 (while (re-search-forward (format "^\\(%s\\) \\([^ ]+\\) \\([0-9]+\\);\"\\(.+\\)$" *ectags-regexp
*) nil t
)
515 (apply fn
(list (match-string-no-properties 1)
516 (match-string-no-properties 2)
517 (match-string-no-properties 3)
518 (match-string-no-properties 4))))))
520 (defun seek-ectag (regexp locate-fn
)
521 "Seek a match for the current regexp with the tags in the current tag table buffer"
522 (setq *ectags-matches
* nil
)
523 (setq *ectags-regexp
* regexp
)
524 (dolist (tags-buffer (ectags-table-list))
525 (funcall locate-fn
'match-ectags tags-buffer
)
526 (setq *ectags-matches
*
527 (sort *ectags-matches
* '(lambda (x y
)
528 (< (car x
) (car y
)))))))
531 ;; hiipe expand tag ----------------------------------------------------------
532 (defun he-ectag-beg ()
540 (defun try-expand-ectag (old)
542 (he-init-string (he-tag-beg) (point))
545 (all-completions he-search-string
*ectags-obarray
*) 'string-lessp
))
546 (while (and he-expand-list
547 (he-string-member (car he-expand-list
) he-tried-table
))
548 (setq he-expand-list
(cdr he-expand-list
))))
549 (if (null he-expand-list
)
551 (when old
(he-reset-string))
553 (he-substitute-string (car he-expand-list
))
554 (setq he-expand-list
(cdr he-expand-list
))
559 ;; ectags search ---------------------------------------------------------------------------------------------
562 (defun ectags-file-scan (file-list tag
)
563 "Scan the list of files for the tag and return a list of markers where it is found"
567 for file in file-list
569 (message "Scanning %s " file
)
572 (while (search-forward tag
(point-max) t
)
574 (message "Found in %s " file
)
575 (add-to-list 'result
(list file
(line-number-at-pos (point)))))
579 (defun reference-ectag (tag)
580 "Scan all currently tagged files for a tag and return a list of markers"
581 (let* ((file-list (make-ectags-file-list)))
582 (setq *ectags-scan-marks
* (ectags-file-scan file-list tag
))))
584 (defun next-ectag-reference ()
585 "Goto next ectag reference in current list, used as with tags-loop-continue"
587 (if (not (zerop (length *ectags-scan-marks
*)))
588 (let ((mark (car *ectags-scan-marks
*)))
589 (find-file (car mark
))
590 (forward-line (cadr mark
))
591 (setq *ectags-scan-marks
* (cdr *ectags-scan-marks
*)))
593 (or (find-tag-default)
594 (completing-read "Tag to reference " *ectags-obarray
*))))
595 (reference-ectag (tag))
596 (when (not (zerop (length *ectags-scan-marks
*)))
597 (next-ectag-reference)))))
600 (defun insert-ectag-references (tagname)
601 "Insert a refererence to a tag in an ectags-select buffer"
603 for index from
0 below
(length *ectags-scan-marks
*)
605 (let ((mark (nth index
*ectags-scan-marks
*)))
606 (insert "<" (int-to-string index
) ">:["
609 (int-to-string (cadr mark
)) "]\n"
612 (defun list-ectag-references (tag)
613 "List all references to the tag in a suitable buffer"
614 (setq *ectags-scan-marks
* nil
)
615 (setq *ectags-reference-source-buffer
* (buffer-name))
616 (get-buffer-create *ectags-reference-buffer-name
*)
617 (set-buffer *ectags-reference-buffer-name
*)
618 (setq buffer-read-only nil
)
620 (insert "Finding tag: " tagname
"\n")
621 (reference-ectag tag
)
622 (if (not (zerop (length *ectags-scan-marks
*)))
624 (insert-ectag-references tag
)
625 (set-buffer *ectags-reference-buffer-name
*)
626 (goto-char (point-min))
627 (set-buffer-modified-p nil
)
628 (setq buffer-read-only t
)
629 (setq *ectags-reference-opened-window
* (selected-window))
630 (unless (get-buffer-window *ectags-reference-buffer-name
*)
631 (select-window (split-window-vertically))
632 (switch-to-buffer *ectags-reference-buffer-name
*)
633 (ectags-select-mode))
634 (shrink-window-if-larger-than-buffer))
636 (message "Failed to find any references to tag %s " tagname
)
640 ;; ectags mode ------------------------------------------------------------------------------------------------
642 (defun ectags-select-case-fold-search ()
643 (when (boundp 'tags-case-fold-search
)
644 (if (memq tags-case-fold-search
'(nil t
))
645 tags-case-fold-search
648 (defun ectags-select-insert-matches (tagname)
649 (when *ectags-matches
*
650 (set-buffer *ectags-select-buffer-name
*)
651 (loop for index from
0 below
(min (length *ectags-matches
*) *ectags-max-candidates
*)
653 (let ((mtch (nth index
*ectags-matches
*)))
654 (insert "<" (int-to-string index
) ">:["
655 (ectags-match-tagname mtch
) " in "
656 (ectags-match-filename mtch
) "@"
657 (int-to-string (ectags-match-linenumber mtch
)) "]\n"
658 "*" (ectags-match-tag-info mtch
) "\n")))))
660 (defun ectags-select-find (tagname)
661 "Actually find a list of tags and push them into the tags select buffer"
662 (setq *ectags-select-source-buffer
* (buffer-name))
663 (get-buffer-create *ectags-select-buffer-name
*)
664 (set-buffer *ectags-select-buffer-name
*)
665 (setq buffer-read-only nil
)
667 (insert "Finding tag: " tagname
"\n")
668 (seek-ectag tagname
'scan-ectag
)
669 (if (> (length *ectags-matches
*) 0)
670 (progn (ectags-select-insert-matches tagname
)
671 (set-buffer *ectags-select-buffer-name
*)
672 (goto-char (point-min))
673 (ectags-select-next-tag)
674 (set-buffer-modified-p nil
)
675 (setq buffer-read-only t
)
676 (setq *ectags-select-opened-window
* (selected-window))
677 (unless (get-buffer-window *ectags-select-buffer-name
*)
678 (select-window (split-window-vertically))
679 (switch-to-buffer *ectags-select-buffer-name
*)
680 (ectags-select-mode))
681 (shrink-window-if-larger-than-buffer))
683 (message "Failed to find tag: %s " tagname
)
687 (defun ectags-select-goto-tag ()
688 "Goto the tag we currently have the point over in an ectags select mode window"
690 (let ((case-fold-search (not *ectags-case-sensitive
*)))
692 (goto-char (point-min))
693 (re-search-forward "Finding tag: \\(.*\\)$")
694 (setq tagname
(match-string-no-properties 1)))
696 (if (not (looking-at "<"))
697 (message "Please put the cursor on a line with a tag")
698 (setq tag-point
(point))
699 (setq overlay-arrow-position
(point-marker))
700 (re-search-forward "\\[\\([^ ]+\\) in \\([^@]+\\)@\\([0-9]+\\)")
701 (let ((tag (match-string-no-properties 1))
702 (fname (match-string-no-properties 2))
703 (lnno (match-string-no-properties 3)))
704 (ring-insert find-tag-marker-ring
(point-marker))
705 (find-file-other-window fname
)
706 (goto-char (point-min))
707 (forward-line (1- (string-to-int lnno
)))))))
710 (defun ectags-select-next-tag ()
711 "Move to next tag in buffer."
717 (defun ectags-select-previous-tag ()
718 "Move to previous tag in buffer."
724 (defun ectags-select-quit ()
725 "Quit ectags-select buffer."
730 (defun ectags-select-by-tag-number (first-digit)
731 (let ((tag-num (read-from-minibuffer "Tag number? " first-digit
))
732 (current-point (point)))
733 (goto-char (point-min))
734 (if (re-search-forward (concat "^<" tag-num
">") nil t
)
735 ;; TODO -- need to push tag and close window
736 (ectags-select-goto-tag)
737 (goto-char current-point
)
738 (message (concat "Couldn't find tag number " tag-num
))
742 ;; user commands ------------------------------------------------------------------------------------------------------
745 (defun ectags-select-find-tag-at-point ()
746 "Do a find-tag-at-point, and display all exact matches. If only one match is
747 found, see the `etags-select-no-select-for-one-match' variable to decide what
751 (or (find-tag-default)
752 (completing-read "Tag to find" *ectags-obarray
*))))
753 (ectags-select-find tag-to-find
)))
756 (defun ectags-select-reference-tag-at-point ()
757 "Do a search for tag in all files in tags tables and list all hits"
760 (or (find-tag-default)
761 (completing-read "Tag to find" *ectags-obarray
*))))
762 (list-ectag-references tag-to-find
)))
766 (defun ectags-select-find-tag ()
767 "Do a find-tag, and display all exact matches. If only one match is
768 found, see the `etags-select-no-select-for-one-match' variable to decide what
771 (let ((tagname (read-from-minibuffer
772 (format "Find tag (default %s): " (find-tag-default)) nil nil
773 nil
'find-tag-history
)))
774 (when (string= tagname
"")
775 (setq tagname
(find-tag-default)))
776 (ectags-select-find tagname
)))
779 (defun ectags-select-reference-tag ()
780 "Do a find-tag, and display all exact matches. If only one match is
781 found, see the `etags-select-no-select-for-one-match' variable to decide what
784 (let ((tagname (read-from-minibuffer
785 (format "Find tag (default %s): " (find-tag-default)) nil nil
786 nil
'find-tag-history
)))
787 (when (string= tagname
"")
788 (setq tagname
(find-tag-default)))
789 (list-ectag-references tagname
)))
791 ;; eldoc mode ------------------------------------------------------------------------------------------------
795 (defun c-eldoc-scope ()
796 "Try to figure out our scope"
799 (c-beginning-of-defun-1)
801 (c-syntactic-re-search-forward "::")
803 (when (c-on-identifier)
804 (let* ((id-end (point))
805 (id-start (progn (backward-char 1) (c-beginning-of-current-token) (point))))
806 (buffer-substring-no-properties id-start id-end
)))))
808 ;; finds the current function and position in argument list
810 (defun c-eldoc-function (&optional limit
)
811 (let* ((literal-limits (c-literal-limits))
812 (literal-type (c-literal-type literal-limits
)))
814 ;; if this is a string, move out to function domain
815 (when (eq literal-type
'string
)
816 (goto-char (car literal-limits
))
817 (setq literal-type nil
))
820 (when (c-on-identifier)
821 (let* ((id-on (point-marker))
823 (progn (c-beginning-of-current-token)
824 ;; are we looking at a double colon?
825 (if (and (= (char-before) ?
:)
826 (= (char-before (1- (point))) ?
:))
829 (c-beginning-of-current-token)
836 (c-end-of-current-token)
838 (buffer-substring-no-properties id-start id-end
)))))))
840 ;; non scoped verison for more conservative languages
842 (defun ectags-eldoc-print-current-symbol-info ()
843 "Print the ectags info associated with the current eldoc symbol"
844 (let* ((eldoc-sym (c-eldoc-function (- (point) 1000))))
845 (seek-ectag eldoc-sym
'find-ectag
)
846 (if (> (length *ectags-matches
*) 0)
847 (ectags-match-tag-info (car *ectags-matches
*))
848 (format "Unknown %s " eldoc-sym
))))
850 ;; scoped version for cpp and the like : tries to find symbol in current scope first
851 ;; scope format is a format string that concatenates the cureend scope and the symbol with the scope operator
852 ;; eg "%s::%s" for c++
854 (defun ectags-eldoc-print-current-scoped-symbol-info ()
855 "Try to find the meaning of the symbol in the current scope. Probably only useful for cpp mode"
856 (let* ((eldoc-scope (c-eldoc-scope))
857 (eldoc-sym (c-eldoc-function (- (point) 1000))))
859 (seek-ectag (format "%s::%s" eldoc-scope eldoc-sym
) 'find-ectag
)
860 (if (> (length *ectags-matches
*) 0)
861 (format "%s::%s %s" eldoc-scope eldoc-sym
(ectags-match-tag-info (car *ectags-matches
*)))
863 (seek-ectag eldoc-sym
'find-ectag
)
864 (if (> (length *ectags-matches
*) 0)
865 (format "%s %s" eldoc-sym
(ectags-match-tag-info (car *ectags-matches
*)))
867 (format "Scope %s " eldoc-scope
))
868 (format "Unknown %s " eldoc-sym
)))))))
871 (defun ectags-turn-on-eldoc-mode (&optional scope-format
)
874 (set (make-local-variable 'eldoc-documentation-function
)
875 'ectags-eldoc-print-current-scoped-symbol-info
)
876 (set (make-local-variable 'eldoc-documentation-function
)
877 'ectags-eldoc-print-current-symbol-info
)
878 (turn-on-eldoc-mode)))
881 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
885 (defvar ectags-select-mode-map nil
"'ectags-select-mode' keymap.")
886 (if (not ectags-select-mode-map
)
887 (let ((map (make-keymap)))
888 (define-key map
[(return)] 'ectags-select-goto-tag
)
889 (define-key map
[(down)] 'ectags-select-next-tag
)
890 (define-key map
[(up)] 'ectags-select-previous-tag
)
891 (define-key map
[(q)] 'ectags-select-quit
)
892 (define-key map
"0" (lambda () (interactive) (ectags-select-by-tag-number "0")))
893 (define-key map
"1" (lambda () (interactive) (ectags-select-by-tag-number "1")))
894 (define-key map
"2" (lambda () (interactive) (ectags-select-by-tag-number "2")))
895 (define-key map
"3" (lambda () (interactive) (ectags-select-by-tag-number "3")))
896 (define-key map
"4" (lambda () (interactive) (ectags-select-by-tag-number "4")))
897 (define-key map
"5" (lambda () (interactive) (ectags-select-by-tag-number "5")))
898 (define-key map
"6" (lambda () (interactive) (ectags-select-by-tag-number "6")))
899 (define-key map
"7" (lambda () (interactive) (ectags-select-by-tag-number "7")))
900 (define-key map
"8" (lambda () (interactive) (ectags-select-by-tag-number "8")))
901 (define-key map
"9" (lambda () (interactive) (ectags-select-by-tag-number "9")))
902 (setq ectags-select-mode-map map
)))
908 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
910 (defun ectags-select-mode ()
911 "ectags-select-mode is a mode for browsing through exuberant ctags.\n\n
912 \\{ectags-select-mode-map}"
914 (kill-all-local-variables)
915 (setq major-mode
'ectags-select-mode
)
916 (setq mode-name
"Ectags Select")
917 (set-syntax-table text-mode-syntax-table
)
918 (use-local-map ectags-select-mode-map
)
919 (make-local-variable 'font-lock-defaults
)
920 (setq ectags-select-mode-font-lock-keywords
922 (list "^<\\([0-9]+\\)>:\\[\\([^ ]+\\) in \\([^@]+\\)@\\([0-9]+)\\)\\]"
923 '(1 font-lock-warning-face
) '(2 font-lock-function-name-face
) '(3 font-lock-keyword-face
) '(4 font-lock-warning-face
))))
924 (setq font-lock-defaults
'(ectags-select-mode-font-lock-keywords))
925 (setq overlay-arrow-position nil
)
926 (run-hooks 'ectags-select-mode-hook
))