Merge changes from emacs-23 branch
This commit is contained in:
commit
266a86bd7f
113 changed files with 6051 additions and 3231 deletions
|
@ -1,3 +1,9 @@
|
|||
2010-09-21 Glenn Morris <rgm@gnu.org>
|
||||
|
||||
* cons-1.eps, cons-2.eps, cons-2a.eps, cons-3.eps, cons-4.eps:
|
||||
* cons-5.eps, lambda-1.eps, lambda-2.eps, lambda-3.eps:
|
||||
Add first line EPSF magic comment. (Bug#7064)
|
||||
|
||||
2010-06-23 Glenn Morris <rgm@gnu.org>
|
||||
|
||||
* emacs-lisp-intro.texi: Untabify.
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
%!
|
||||
%!PS-Adobe-3.0 EPSF-3.0
|
||||
%%BoundingBox: 35 711 289 757
|
||||
%%Title: cons-cell-diagram1
|
||||
%%CreationDate: Wed Mar 8 14:26:58 1995
|
||||
%%Creator: Tgif-2.16-p4 by William Chia-Wei Cheng (william@cs.UCLA.edu)
|
||||
%
|
||||
% Due to bugs in Transcript, the 'PS-Adobe-' stuff is omitted from line 1
|
||||
%
|
||||
|
||||
% Copyright (C) 1995, 1997, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
|
||||
% Free Software Foundation, Inc.
|
||||
% Copyright (C) 1995, 1997, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
|
||||
% 2008, 2009, 2010 Free Software Foundation, Inc.
|
||||
%
|
||||
% This file is part of GNU Emacs.
|
||||
%
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
%!
|
||||
%!PS-Adobe-3.0 EPSF-3.0
|
||||
%%BoundingBox: 15 712 321 775
|
||||
%%Title: cons-cell-diagram2
|
||||
%%CreationDate: Wed Mar 8 14:26:39 1995
|
||||
%%Creator: Tgif-2.16-p4 by William Chia-Wei Cheng (william@cs.UCLA.edu)
|
||||
%
|
||||
% Due to bugs in Transcript, the 'PS-Adobe-' stuff is omitted from line 1
|
||||
%
|
||||
|
||||
% Copyright (C) 1995, 1997, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
|
||||
% Free Software Foundation, Inc.
|
||||
% Copyright (C) 1995, 1997, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
|
||||
% 2008, 2009, 2010 Free Software Foundation, Inc.
|
||||
%
|
||||
% This file is part of GNU Emacs.
|
||||
%
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
%!
|
||||
%!PS-Adobe-3.0 EPSF-3.0
|
||||
%%BoundingBox: 15 702 300 767
|
||||
%%Title: cons-cell-diagram2a
|
||||
%%CreationDate: Tue Mar 14 15:09:30 1995
|
||||
%%Creator: Tgif-2.16-p4 by William Chia-Wei Cheng (william@cs.UCLA.edu)
|
||||
%
|
||||
% Due to bugs in Transcript, the 'PS-Adobe-' stuff is omitted from line 1
|
||||
%
|
||||
|
||||
% Copyright (C) 1995, 1997, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
|
||||
% Free Software Foundation, Inc.
|
||||
% Copyright (C) 1995, 1997, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
|
||||
% 2008, 2009, 2010 Free Software Foundation, Inc.
|
||||
%
|
||||
% This file is part of GNU Emacs.
|
||||
%
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
%!
|
||||
%!PS-Adobe-3.0 EPSF-3.0
|
||||
%%BoundingBox: -1 691 324 757
|
||||
%%Title: cons-cell-diagram3
|
||||
%%CreationDate: Wed Mar 8 14:25:41 1995
|
||||
%%Creator: Tgif-2.16-p4 by William Chia-Wei Cheng (william@cs.UCLA.edu)
|
||||
%
|
||||
% Due to bugs in Transcript, the 'PS-Adobe-' stuff is omitted from line 1
|
||||
%
|
||||
|
||||
% Copyright (C) 1995, 1997, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
|
||||
% Free Software Foundation, Inc.
|
||||
% Copyright (C) 1995, 1997, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
|
||||
% 2008, 2009, 2010 Free Software Foundation, Inc.
|
||||
%
|
||||
% This file is part of GNU Emacs.
|
||||
%
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
%!
|
||||
%!PS-Adobe-3.0 EPSF-3.0
|
||||
%%BoundingBox: 6 681 355 758
|
||||
%%Title: cons-cell-diagram4
|
||||
%%CreationDate: Wed Mar 8 14:25:06 1995
|
||||
%%Creator: Tgif-2.16-p4 by William Chia-Wei Cheng (william@cs.UCLA.edu)
|
||||
%
|
||||
% Due to bugs in Transcript, the 'PS-Adobe-' stuff is omitted from line 1
|
||||
%
|
||||
|
||||
% Copyright (C) 1995, 1997, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
|
||||
% Free Software Foundation, Inc.
|
||||
% Copyright (C) 1995, 1997, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
|
||||
% 2008, 2009, 2010 Free Software Foundation, Inc.
|
||||
%
|
||||
% This file is part of GNU Emacs.
|
||||
%
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
%!
|
||||
%!PS-Adobe-3.0 EPSF-3.0
|
||||
%%BoundingBox: 15 680 305 764
|
||||
%%Title: cons-cell-diagram5
|
||||
%%CreationDate: Wed Mar 8 14:27:28 1995
|
||||
%%Creator: Tgif-2.16-p4 by William Chia-Wei Cheng (william@cs.UCLA.edu)
|
||||
%
|
||||
% Due to bugs in Transcript, the 'PS-Adobe-' stuff is omitted from line 1
|
||||
%
|
||||
|
||||
% Copyright (C) 1995, 1997, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
|
||||
% Free Software Foundation, Inc.
|
||||
% Copyright (C) 1995, 1997, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
|
||||
% 2008, 2009, 2010 Free Software Foundation, Inc.
|
||||
%
|
||||
% This file is part of GNU Emacs.
|
||||
%
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
%!
|
||||
%!PS-Adobe-3.0 EPSF-3.0
|
||||
%%BoundingBox: 33 710 173 759
|
||||
%%Title: lambda-diagram1
|
||||
%%CreationDate: Wed Mar 8 14:31:53 1995
|
||||
%%Creator: Tgif-2.16-p4 by William Chia-Wei Cheng (william@cs.UCLA.edu)
|
||||
%
|
||||
% Due to bugs in Transcript, the 'PS-Adobe-' stuff is omitted from line 1
|
||||
%
|
||||
|
||||
% Copyright (C) 1995, 1997, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
|
||||
% Free Software Foundation, Inc.
|
||||
% Copyright (C) 1995, 1997, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
|
||||
% 2008, 2009, 2010 Free Software Foundation, Inc.
|
||||
%
|
||||
% This file is part of GNU Emacs.
|
||||
%
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
%!
|
||||
%!PS-Adobe-3.0 EPSF-3.0
|
||||
%%BoundingBox: 33 730 240 777
|
||||
%%Title: lambda-diagram2
|
||||
%%CreationDate: Wed Mar 8 14:33:09 1995
|
||||
%%Creator: Tgif-2.16-p4 by William Chia-Wei Cheng (william@cs.UCLA.edu)
|
||||
%
|
||||
% Due to bugs in Transcript, the 'PS-Adobe-' stuff is omitted from line 1
|
||||
%
|
||||
|
||||
% Copyright (C) 1995, 1997, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
|
||||
% Free Software Foundation, Inc.
|
||||
% Copyright (C) 1995, 1997, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
|
||||
% 2008, 2009, 2010 Free Software Foundation, Inc.
|
||||
%
|
||||
% This file is part of GNU Emacs.
|
||||
%
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
%!
|
||||
%!PS-Adobe-3.0 EPSF-3.0
|
||||
%%BoundingBox: 33 728 211 777
|
||||
%%Title: lambda-diagram3
|
||||
%%CreationDate: Wed Mar 8 14:33:49 1995
|
||||
%%Creator: Tgif-2.16-p4 by William Chia-Wei Cheng (william@cs.UCLA.edu)
|
||||
%
|
||||
% Due to bugs in Transcript, the 'PS-Adobe-' stuff is omitted from line 1
|
||||
%
|
||||
|
||||
% Copyright (C) 1995, 1997, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
|
||||
% Free Software Foundation, Inc.
|
||||
% Copyright (C) 1995, 1997, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
|
||||
% 2008, 2009, 2010 Free Software Foundation, Inc.
|
||||
%
|
||||
% This file is part of GNU Emacs.
|
||||
%
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
2010-09-21 Eric Ludlam <zappo@gnu.org>
|
||||
|
||||
* srecode/java.srt: Make NAME be a prompt.
|
||||
|
||||
2010-09-13 Michael Albinus <michael.albinus@gmx.de>
|
||||
|
||||
* NEWS: Some Tramp methods are discontinued.
|
||||
|
|
|
@ -40,6 +40,8 @@ This can be used in place of the default appt-message-warning-time.
|
|||
|
||||
* Lisp changes in Emacs 23.3
|
||||
|
||||
** `e' and `pi' are now called `float-e' and `float-pi'.
|
||||
The old names are obsolete.
|
||||
** The use of unintern without an obarray arg is declared obsolete.
|
||||
|
||||
** New function byte-to-string, like char-to-string but for bytes.
|
||||
|
|
|
@ -83,7 +83,7 @@ public Class {{?NAME}} {{#PARENTS}}{{#FIRST}}extends {{/FIRST}}{{#NOTFIRST}}impl
|
|||
template include :blank
|
||||
"An include statement."
|
||||
----
|
||||
import {{NAME}};
|
||||
import {{?NAME}};
|
||||
----
|
||||
|
||||
context misc
|
||||
|
|
1057
lisp/ChangeLog
1057
lisp/ChangeLog
File diff suppressed because it is too large
Load diff
|
@ -369,7 +369,8 @@ documentation for an example.")
|
|||
Used for repeating operations in calculator-repR/L.")
|
||||
|
||||
(defvar calculator-registers ; use user-bindings first
|
||||
(append calculator-user-registers (list (cons ?e e) (cons ?p pi)))
|
||||
(append calculator-user-registers
|
||||
(list (cons ?e float-e) (cons ?p float-pi)))
|
||||
"The association list of calculator register values.")
|
||||
|
||||
(defvar calculator-saved-global-map nil
|
||||
|
@ -1300,7 +1301,7 @@ arguments."
|
|||
(calculator-funcall __f__ x y))))
|
||||
(fset 'D (function
|
||||
(lambda (x)
|
||||
(if calculator-deg (/ (* x 180) pi) x))))
|
||||
(if calculator-deg (/ (* x 180) float-pi) x))))
|
||||
(unwind-protect (eval f)
|
||||
(if Fbound (fset 'F Fsave) (fmakunbound 'F))
|
||||
(if Dbound (fset 'D Dsave) (fmakunbound 'D)))))
|
||||
|
|
|
@ -334,30 +334,42 @@ displayed in a window:
|
|||
(if (or force ; eg initialize, diary save
|
||||
(null appt-prev-comp-time) ; first check
|
||||
(< cur-comp-time appt-prev-comp-time)) ; new day
|
||||
(condition-case nil
|
||||
(if appt-display-diary
|
||||
(let ((diary-hook
|
||||
(if (assoc 'appt-make-list diary-hook)
|
||||
diary-hook
|
||||
(cons 'appt-make-list diary-hook))))
|
||||
(diary))
|
||||
(let* ((diary-display-function 'appt-make-list)
|
||||
(d-buff (find-buffer-visiting diary-file))
|
||||
(selective
|
||||
(if d-buff ; diary buffer exists
|
||||
(with-current-buffer d-buff
|
||||
diary-selective-display))))
|
||||
;; FIXME why not using diary-list-entries with
|
||||
;; non-nil LIST-ONLY?
|
||||
(diary)
|
||||
;; If the diary buffer existed before this command,
|
||||
;; restore its display state. Otherwise, kill it.
|
||||
(if d-buff
|
||||
;; Displays the diary buffer.
|
||||
(or selective (diary-show-all-entries))
|
||||
(and (setq d-buff (find-buffer-visiting diary-file))
|
||||
(kill-buffer d-buff)))))
|
||||
(error nil)))
|
||||
(ignore-errors
|
||||
(if appt-display-diary
|
||||
(let ((diary-hook
|
||||
(if (assoc 'appt-make-list diary-hook)
|
||||
diary-hook
|
||||
(cons 'appt-make-list diary-hook))))
|
||||
(diary))
|
||||
(let* ((diary-display-function 'appt-make-list)
|
||||
(d-buff (find-buffer-visiting diary-file))
|
||||
(selective
|
||||
(if d-buff ; diary buffer exists
|
||||
(with-current-buffer d-buff
|
||||
diary-selective-display)))
|
||||
d-buff2)
|
||||
;; Not displaying the diary, so we can ignore
|
||||
;; diary-number-of-entries. Since appt.el only
|
||||
;; works on a daily basis, no need for more entries.
|
||||
;; FIXME why not using diary-list-entries with
|
||||
;; non-nil LIST-ONLY?
|
||||
(diary 1)
|
||||
;; If the diary buffer existed before this command,
|
||||
;; restore its display state. Otherwise, kill it.
|
||||
(and (setq d-buff2 (find-buffer-visiting diary-file))
|
||||
(if d-buff
|
||||
(or selective
|
||||
(with-current-buffer d-buff2
|
||||
(if diary-selective-display
|
||||
;; diary-show-all-entries displays
|
||||
;; the diary buffer.
|
||||
(diary-unhide-everything))))
|
||||
;; FIXME does not kill any included diary files.
|
||||
;; The real issue is that (diary) should not
|
||||
;; have the side effect of visiting all the
|
||||
;; diary files. It is not really appt.el's job to
|
||||
;; clean up this mess...
|
||||
(kill-buffer d-buff2)))))))
|
||||
(setq appt-prev-comp-time cur-comp-time
|
||||
appt-mode-string nil
|
||||
appt-display-count nil)
|
||||
|
@ -573,6 +585,17 @@ appointment package (if it is not already active)."
|
|||
(let ((entry-list diary-entries-list)
|
||||
(new-time-string "")
|
||||
time-string)
|
||||
;; Below, we assume diary-entries-list was in date
|
||||
;; order. It is, unless something on
|
||||
;; diary-list-entries-hook has changed it, eg
|
||||
;; diary-include-other-files (bug#7019). It must be
|
||||
;; in date order if number = 1.
|
||||
(and diary-list-entries-hook
|
||||
appt-display-diary
|
||||
(not (eq diary-number-of-entries 1))
|
||||
(not (memq (car (last diary-list-entries-hook))
|
||||
'(diary-sort-entries sort-diary-entries)))
|
||||
(setq entry-list (sort entry-list 'diary-entry-compare)))
|
||||
;; Skip diary entries for dates before today.
|
||||
(while (and entry-list
|
||||
(calendar-date-compare
|
||||
|
|
|
@ -711,14 +711,26 @@ The arguments are DATE and NUMBER; the entries selected are those
|
|||
for NUMBER days starting with date DATE. The other entries are hidden
|
||||
using overlays. If NUMBER is less than 1, this function does nothing.
|
||||
|
||||
Returns a list of all relevant diary entries found, if any, in order by date.
|
||||
Returns a list of all relevant diary entries found.
|
||||
The list entries have the form ((MONTH DAY YEAR) STRING SPECIFIER) where
|
||||
\(MONTH DAY YEAR) is the date of the entry, STRING is the entry text, and
|
||||
SPECIFIER is the applicability. If the variable `diary-list-include-blanks'
|
||||
is non-nil, this list includes a dummy diary entry consisting of the empty
|
||||
string for a date with no diary entries.
|
||||
|
||||
After the list is prepared, the following hooks are run:
|
||||
If entries are being produced for multiple dates (i.e., NUMBER > 1),
|
||||
then this function normally returns the entries from any given
|
||||
diary file in date order. The entries for any given day are in
|
||||
the order in which they were found in the file, not necessarily
|
||||
in time-of-day order. Note that any functions present on the
|
||||
hooks (see below) may add entries, or change the order. For
|
||||
example, `diary-include-other-diary-files' adds entries from any
|
||||
include files that it finds to the end of the original list. The
|
||||
entries from each file will be in date order, but the overall
|
||||
list will not be. If you want the entire list to be in time order,
|
||||
add `diary-sort-entries' to the end of `diary-list-entries-hook'.
|
||||
|
||||
After the initial list is prepared, the following hooks are run:
|
||||
|
||||
`diary-nongregorian-listing-hook' can cull dates from the diary
|
||||
and each included file, for example to process Islamic diary
|
||||
|
|
|
@ -753,12 +753,12 @@ The values of `calendar-daylight-savings-starts',
|
|||
(sin (mod
|
||||
(+ (cadr x)
|
||||
(* (nth 2 x) U))
|
||||
(* 2 pi)))))
|
||||
(* 2 float-pi)))))
|
||||
solar-data-list)))))
|
||||
(aberration
|
||||
(* 0.0000001 (- (* 17 (cos (+ 3.10 (* 62830.14 U)))) 973)))
|
||||
(A1 (mod (+ 2.18 (* U (+ -3375.70 (* 0.36 U)))) (* 2 pi)))
|
||||
(A2 (mod (+ 3.51 (* U (+ 125666.39 (* 0.10 U)))) (* 2 pi)))
|
||||
(A1 (mod (+ 2.18 (* U (+ -3375.70 (* 0.36 U)))) (* 2 float-pi)))
|
||||
(A2 (mod (+ 3.51 (* U (+ 125666.39 (* 0.10 U)))) (* 2 float-pi)))
|
||||
(nutation (* -0.0000001 (+ (* 834 (sin A1)) (* 64 (sin A2))))))
|
||||
(mod (radians-to-degrees (+ longitude aberration nutation)) 360.0)))
|
||||
|
||||
|
|
1436
lisp/cedet/ChangeLog
Normal file
1436
lisp/cedet/ChangeLog
Normal file
File diff suppressed because it is too large
Load diff
|
@ -73,6 +73,12 @@ SCOPE is the scope of the search, such as 'project or 'subdirs."
|
|||
)
|
||||
(cedet-cscope-call (list "-d" "-L" idx searchtext))))
|
||||
|
||||
(defun cedet-cscope-create (flags)
|
||||
"Create a CScope database at the current directory.
|
||||
FLAGS are additional flags to pass to cscope beyond the
|
||||
options -cR."
|
||||
(cedet-cscope-call (append (list "-cR") flags)))
|
||||
|
||||
(defun cedet-cscope-call (flags)
|
||||
"Call CScope with the list of FLAGS."
|
||||
(let ((b (get-buffer-create "*CEDET CScope*"))
|
||||
|
@ -113,13 +119,19 @@ Return a fully qualified filename."
|
|||
If DIR is not supplied, use the current default directory.
|
||||
This works by running cscope on a bogus symbol, and looking for
|
||||
the error code."
|
||||
(interactive "DDirectory: ")
|
||||
(save-excursion
|
||||
(let ((default-directory (or dir default-directory)))
|
||||
(set-buffer (cedet-cscope-call (list "-d" "-L" "-7" "moose")))
|
||||
(goto-char (point-min))
|
||||
(if (looking-at "[^ \n]*cscope: ")
|
||||
nil
|
||||
t))))
|
||||
(let ((ans (looking-at "[^ \n]*cscope: ")))
|
||||
(if (called-interactively-p 'interactive)
|
||||
(if ans
|
||||
(message "No support for CScope in %s" default-directory)
|
||||
(message "CScope is supported in %s" default-directory))
|
||||
(if ans
|
||||
nil
|
||||
t))))))
|
||||
|
||||
(defun cedet-cscope-version-check (&optional noerror)
|
||||
"Check the version of the installed CScope command.
|
||||
|
@ -151,6 +163,14 @@ return nil."
|
|||
(message "CScope %s - Good enough for CEDET." rev))
|
||||
t)))))
|
||||
|
||||
(defun cedet-cscope-create/update-database (&optional dir)
|
||||
"Create a CScope database in DIR.
|
||||
CScope will automatically choose incremental rebuild if
|
||||
there is already a database in DIR."
|
||||
(interactive "DDirectory: ")
|
||||
(let ((default-directory dir))
|
||||
(cedet-cscope-create nil)))
|
||||
|
||||
(provide 'cedet-cscope)
|
||||
|
||||
;; arch-tag: 9973f1ad-f13b-4399-bc67-7f488478d78d
|
||||
|
|
|
@ -34,6 +34,12 @@
|
|||
:type 'string
|
||||
:group 'cedet)
|
||||
|
||||
(defcustom cedet-global-gtags-command "gtags"
|
||||
"Command name for the GNU Global gtags executable.
|
||||
GTAGS is used to create the tags table queried by the 'global' command."
|
||||
:type 'string
|
||||
:group 'cedet)
|
||||
|
||||
;;; Code:
|
||||
(defun cedet-gnu-global-search (searchtext texttype type scope)
|
||||
"Perform a search with GNU Global, return the created buffer.
|
||||
|
@ -76,6 +82,19 @@ SCOPE is the scope of the search, such as 'project or 'subdirs."
|
|||
flags)
|
||||
b))
|
||||
|
||||
(defun cedet-gnu-global-gtags-call (flags)
|
||||
"Create GNU Global TAGS using gtags with FLAGS."
|
||||
(let ((b (get-buffer-create "*CEDET Global gtags*"))
|
||||
(cd default-directory)
|
||||
)
|
||||
(with-current-buffer b
|
||||
(setq default-directory cd)
|
||||
(erase-buffer))
|
||||
(apply 'call-process cedet-global-gtags-command
|
||||
nil b nil
|
||||
flags)
|
||||
b))
|
||||
|
||||
(defun cedet-gnu-global-expand-filename (filename)
|
||||
"Expand the FILENAME with GNU Global.
|
||||
Return a fully qualified filename."
|
||||
|
@ -153,6 +172,18 @@ return nil."
|
|||
;; Return the results
|
||||
(nreverse hits))))
|
||||
|
||||
(defun cedet-gnu-global-create/update-database (&optional dir)
|
||||
"Create a GNU Global database in DIR.
|
||||
If a database already exists, then just update it."
|
||||
(interactive "DDirectory: ")
|
||||
(let ((root (cedet-gnu-global-root dir)))
|
||||
(if root (setq dir root))
|
||||
(let ((default-directory dir))
|
||||
(cedet-gnu-global-gtags-call
|
||||
(when root
|
||||
'("-i");; Incremental update flag.
|
||||
)))))
|
||||
|
||||
(provide 'cedet-global)
|
||||
|
||||
;; arch-tag: 0d0d3ac2-91ef-4820-bb2b-1d59ccf38392
|
||||
|
|
|
@ -44,6 +44,11 @@
|
|||
:type 'string
|
||||
:group 'cedet)
|
||||
|
||||
(defcustom cedet-idutils-make-command "mkid"
|
||||
"Command name for the ID Utils executable for creating token databases."
|
||||
:type 'string
|
||||
:group 'cedet)
|
||||
|
||||
(defun cedet-idutils-search (searchtext texttype type scope)
|
||||
"Perform a search with ID Utils, return the created buffer.
|
||||
SEARCHTEXT is text to find.
|
||||
|
@ -105,6 +110,20 @@ Return the created buffer with with program output."
|
|||
flags)
|
||||
b))
|
||||
|
||||
(defun cedet-idutils-mkid-call (flags)
|
||||
"Call ID Utils mkid with the list of FLAGS.
|
||||
Return the created buffer with with program output."
|
||||
(let ((b (get-buffer-create "*CEDET mkid*"))
|
||||
(cd default-directory)
|
||||
)
|
||||
(with-current-buffer b
|
||||
(setq default-directory cd)
|
||||
(erase-buffer))
|
||||
(apply 'call-process cedet-idutils-make-command
|
||||
nil b nil
|
||||
flags)
|
||||
b))
|
||||
|
||||
;;; UTIL CALLS
|
||||
;;
|
||||
(defun cedet-idutils-expand-filename (filename)
|
||||
|
@ -172,6 +191,12 @@ return nil."
|
|||
(message "ID Utils %s - Good enough for CEDET." rev))
|
||||
t)))))
|
||||
|
||||
(defun cedet-idutils-create/update-database (&optional dir)
|
||||
"Create an IDUtils database in DIR.
|
||||
IDUtils must start from scratch when updating a database."
|
||||
(interactive "DDirectory: ")
|
||||
(let ((default-directory dir))
|
||||
(cedet-idutils-mkid-call nil)))
|
||||
|
||||
(provide 'cedet-idutils)
|
||||
|
||||
|
|
|
@ -36,19 +36,19 @@
|
|||
|
||||
(declare-function inversion-find-version "inversion")
|
||||
|
||||
(defconst cedet-version "1.0pre7"
|
||||
(defconst cedet-version "1.0"
|
||||
"Current version of CEDET.")
|
||||
|
||||
(defconst cedet-packages
|
||||
`(
|
||||
;;PACKAGE MIN-VERSION
|
||||
(cedet ,cedet-version)
|
||||
(eieio "1.2")
|
||||
(semantic "2.0pre7")
|
||||
(srecode "1.0pre7")
|
||||
(ede "1.0pre7")
|
||||
(speedbar "1.0.3"))
|
||||
"Table of CEDET packages to install.")
|
||||
(eieio "1.3")
|
||||
(semantic "2.0")
|
||||
(srecode "1.0")
|
||||
(ede "1.0")
|
||||
(speedbar "1.0"))
|
||||
"Table of CEDET packages installed.")
|
||||
|
||||
(defvar cedet-menu-map ;(make-sparse-keymap "CEDET menu")
|
||||
(let ((map (make-sparse-keymap "CEDET menu")))
|
||||
|
|
File diff suppressed because it is too large
Load diff
128
lisp/cedet/ede/auto.el
Normal file
128
lisp/cedet/ede/auto.el
Normal file
|
@ -0,0 +1,128 @@
|
|||
;;; ede/auto.el --- Autoload features for EDE
|
||||
|
||||
;; Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Eric M. Ludlam <zappo@gnu.org>
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs 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 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs 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. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; EDE Autoloads are a way to refer to different project types without
|
||||
;; loading those projects into Emacs.
|
||||
;;
|
||||
;; These routines are used to detect a project in a filesystem before
|
||||
;; handing over control to the usual EDE project system.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'eieio)
|
||||
|
||||
(defclass ede-project-autoload ()
|
||||
((name :initarg :name
|
||||
:documentation "Name of this project type")
|
||||
(file :initarg :file
|
||||
:documentation "The lisp file belonging to this class.")
|
||||
(proj-file :initarg :proj-file
|
||||
:documentation "Name of a project file of this type.")
|
||||
(proj-root :initarg :proj-root
|
||||
:type function
|
||||
:documentation "A function symbol to call for the project root.
|
||||
This function takes no arguments, and returns the current directories
|
||||
root, if available. Leave blank to use the EDE directory walking
|
||||
routine instead.")
|
||||
(initializers :initarg :initializers
|
||||
:initform nil
|
||||
:documentation
|
||||
"Initializers passed to the project object.
|
||||
These are used so there can be multiple types of projects
|
||||
associated with a single object class, based on the initilizeres used.")
|
||||
(load-type :initarg :load-type
|
||||
:documentation "Fn symbol used to load this project file.")
|
||||
(class-sym :initarg :class-sym
|
||||
:documentation "Symbol representing the project class to use.")
|
||||
(new-p :initarg :new-p
|
||||
:initform t
|
||||
:documentation
|
||||
"Non-nil if this is an option when a user creates a project.")
|
||||
)
|
||||
"Class representing minimal knowledge set to run preliminary EDE functions.
|
||||
When more advanced functionality is needed from a project type, that projects
|
||||
type is required and the load function used.")
|
||||
|
||||
(defvar ede-project-class-files
|
||||
(list
|
||||
(ede-project-autoload "edeproject-makefile"
|
||||
:name "Make" :file 'ede/proj
|
||||
:proj-file "Project.ede"
|
||||
:load-type 'ede-proj-load
|
||||
:class-sym 'ede-proj-project)
|
||||
(ede-project-autoload "edeproject-automake"
|
||||
:name "Automake" :file 'ede/proj
|
||||
:proj-file "Project.ede"
|
||||
:initializers '(:makefile-type Makefile.am)
|
||||
:load-type 'ede-proj-load
|
||||
:class-sym 'ede-proj-project)
|
||||
(ede-project-autoload "automake"
|
||||
:name "automake" :file 'ede/project-am
|
||||
:proj-file "Makefile.am"
|
||||
:load-type 'project-am-load
|
||||
:class-sym 'project-am-makefile
|
||||
:new-p nil))
|
||||
"List of vectors defining how to determine what type of projects exist.")
|
||||
|
||||
;;; EDE project-autoload methods
|
||||
;;
|
||||
(defmethod ede-project-root ((this ede-project-autoload))
|
||||
"If a project knows its root, return it here.
|
||||
Allows for one-project-object-for-a-tree type systems."
|
||||
nil)
|
||||
|
||||
(defmethod ede-project-root-directory ((this ede-project-autoload)
|
||||
&optional file)
|
||||
"If a project knows its root, return it here.
|
||||
Allows for one-project-object-for-a-tree type systems.
|
||||
Optional FILE is the file to test. If there is no FILE, use
|
||||
the current buffer."
|
||||
(when (not file)
|
||||
(setq file default-directory))
|
||||
(when (slot-boundp this :proj-root)
|
||||
(let ((rootfcn (oref this proj-root)))
|
||||
(when rootfcn
|
||||
(condition-case nil
|
||||
(funcall rootfcn file)
|
||||
(error
|
||||
(funcall rootfcn)))
|
||||
))))
|
||||
|
||||
(defmethod ede-dir-to-projectfile ((this ede-project-autoload) dir)
|
||||
"Return a full file name of project THIS found in DIR.
|
||||
Return nil if the project file does not exist."
|
||||
(let* ((d (file-name-as-directory dir))
|
||||
(root (ede-project-root-directory this d))
|
||||
(pf (oref this proj-file))
|
||||
(f (cond ((stringp pf)
|
||||
(expand-file-name pf (or root d)))
|
||||
((and (symbolp pf) (fboundp pf))
|
||||
(funcall pf (or root d)))))
|
||||
)
|
||||
(when (and f (file-exists-p f))
|
||||
f)))
|
||||
|
||||
|
||||
(provide 'ede/auto)
|
||||
|
||||
;;; ede/auto.el ends here
|
|
@ -27,20 +27,8 @@
|
|||
|
||||
;;; Code:
|
||||
(require 'autoconf)
|
||||
|
||||
(defvar autoconf-new-automake-string
|
||||
"dnl Process this file with autoconf to produce a configure script
|
||||
|
||||
AC_INIT(%s)
|
||||
AM_INIT_AUTOMAKE([%s], 0)
|
||||
AM_CONFIG_HEADER(config.h)
|
||||
|
||||
dnl End the configure script.
|
||||
AC_OUTPUT(Makefile, [date > stamp-h] )\n"
|
||||
"This string is used to initialize a new configure.in.
|
||||
The default is designed to be used with automake.
|
||||
The first %s will be filled with the test file.
|
||||
The second %s will be filled with the program name.")
|
||||
(declare-function ede-srecode-setup "ede/srecode")
|
||||
(declare-function ede-srecode-insert "ede/srecode")
|
||||
|
||||
(defun autoconf-new-program (rootdir program testfile)
|
||||
"Initialize a new configure.in in ROOTDIR for PROGRAM using TESTFILE.
|
||||
|
@ -49,6 +37,7 @@ PROGRAM is the program to be configured.
|
|||
TESTFILE is the file used with AC_INIT.
|
||||
configure the initial configure script using `autoconf-new-automake-string'"
|
||||
(interactive "DRoot Dir: \nsProgram: \nsTest File: ")
|
||||
(require 'ede/srecode)
|
||||
(if (bufferp rootdir)
|
||||
(set-buffer rootdir)
|
||||
(let ((cf1 (expand-file-name "configure.in" rootdir))
|
||||
|
@ -62,7 +51,12 @@ configure the initial configure script using `autoconf-new-automake-string'"
|
|||
(find-file cf2)))
|
||||
;; Note, we only ask about overwrite if a string/path is specified.
|
||||
(erase-buffer)
|
||||
(insert (format autoconf-new-automake-string testfile program)))
|
||||
(ede-srecode-setup)
|
||||
(ede-srecode-insert
|
||||
"file:ede-empty"
|
||||
"TEST_FILE" testfile
|
||||
"PROGRAM" program)
|
||||
)
|
||||
|
||||
(defvar autoconf-preferred-macro-order
|
||||
'("AC_INIT"
|
||||
|
@ -151,42 +145,44 @@ From the autoconf manual:
|
|||
(beginning-of-line)
|
||||
(looking-at (concat "\\(A[CM]_" macro "\\|" macro "\\)"))))
|
||||
|
||||
(defun autoconf-find-last-macro (macro)
|
||||
(defun autoconf-find-last-macro (macro &optional ignore-bol)
|
||||
"Move to the last occurrence of MACRO in FILE, and return that point.
|
||||
The last macro is usually the one in which we would like to insert more
|
||||
items such as CHECK_HEADERS."
|
||||
(let ((op (point)))
|
||||
(let ((op (point)) (atbol (if ignore-bol "" "^")))
|
||||
(goto-char (point-max))
|
||||
(if (re-search-backward (concat "^" (regexp-quote macro) "\\s-*\\((\\|$\\)") nil t)
|
||||
(if (re-search-backward (concat atbol (regexp-quote macro) "\\s-*\\((\\|$\\)") nil t)
|
||||
(progn
|
||||
(beginning-of-line)
|
||||
(unless ignore-bol (beginning-of-line))
|
||||
(point))
|
||||
(goto-char op)
|
||||
nil)))
|
||||
|
||||
(defun autoconf-parameter-strip (param)
|
||||
"Strip the parameter PARAM of whitespace and miscellaneous characters."
|
||||
(when (string-match "^\\s-*\\[?\\s-*" param)
|
||||
;; force greedy match for \n.
|
||||
(when (string-match "\\`\n*\\s-*\\[?\\s-*" param)
|
||||
(setq param (substring param (match-end 0))))
|
||||
(when (string-match "\\s-*\\]?\\s-*$" param)
|
||||
(when (string-match "\\s-*\\]?\\s-*\\'" param)
|
||||
(setq param (substring param 0 (match-beginning 0))))
|
||||
param)
|
||||
|
||||
(defun autoconf-parameters-for-macro (macro)
|
||||
(defun autoconf-parameters-for-macro (macro &optional ignore-bol ignore-case)
|
||||
"Retrieve the parameters to MACRO.
|
||||
Returns a list of the arguments passed into MACRO as strings."
|
||||
(save-excursion
|
||||
(when (autoconf-find-last-macro macro)
|
||||
(forward-sexp 1)
|
||||
(mapcar
|
||||
#'autoconf-parameter-strip
|
||||
(when (looking-at "(")
|
||||
(let* ((start (+ (point) 1))
|
||||
(end (save-excursion
|
||||
(forward-sexp 1)
|
||||
(- (point) 1)))
|
||||
(ans (buffer-substring-no-properties start end)))
|
||||
(split-string ans "," t)))))))
|
||||
(let ((case-fold-search ignore-case))
|
||||
(save-excursion
|
||||
(when (autoconf-find-last-macro macro ignore-bol)
|
||||
(forward-sexp 1)
|
||||
(mapcar
|
||||
#'autoconf-parameter-strip
|
||||
(when (looking-at "(")
|
||||
(let* ((start (+ (point) 1))
|
||||
(end (save-excursion
|
||||
(forward-sexp 1)
|
||||
(- (point) 1)))
|
||||
(ans (buffer-substring-no-properties start end)))
|
||||
(split-string ans "," t))))))))
|
||||
|
||||
(defun autoconf-position-for-macro (macro)
|
||||
"Position the cursor where a new MACRO could be inserted.
|
||||
|
|
636
lisp/cedet/ede/base.el
Normal file
636
lisp/cedet/ede/base.el
Normal file
|
@ -0,0 +1,636 @@
|
|||
;;; ede/base.el --- Baseclasses for EDE.
|
||||
|
||||
;; Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Eric M. Ludlam <zappo@gnu.org>
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs 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 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs 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. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; Baseclasses for EDE.
|
||||
;;
|
||||
;; Contains all the base structures needed by EDE.
|
||||
|
||||
;;; Code:
|
||||
(require 'eieio)
|
||||
(require 'eieio-speedbar)
|
||||
(require 'ede/auto)
|
||||
|
||||
;; Defined in ede.el:
|
||||
(defvar ede-projects)
|
||||
(defvar ede-object)
|
||||
(defvar ede-object-root-project)
|
||||
|
||||
(declare-function data-debug-new-buffer "data-debug")
|
||||
(declare-function data-debug-insert-object-slots "eieio-datadebug")
|
||||
(declare-function ede-parent-project "ede" (&optional obj))
|
||||
(declare-function ede-current-project "ede" (&optional dir))
|
||||
|
||||
;;; TARGET
|
||||
;;
|
||||
;; The TARGET is an entity in a project that knows about files
|
||||
;; and features of those files.
|
||||
|
||||
(defclass ede-target (eieio-speedbar-directory-button)
|
||||
((buttonface :initform speedbar-file-face) ;override for superclass
|
||||
(name :initarg :name
|
||||
:type string
|
||||
:custom string
|
||||
:label "Name"
|
||||
:group (default name)
|
||||
:documentation "Name of this target.")
|
||||
;; @todo - I think this should be "dir", and not "path".
|
||||
(path :initarg :path
|
||||
:type string
|
||||
;:custom string
|
||||
;:label "Path to target"
|
||||
;:group (default name)
|
||||
:documentation "The path to the sources of this target.
|
||||
Relative to the path of the project it belongs to.")
|
||||
(source :initarg :source
|
||||
:initform nil
|
||||
;; I'd prefer a list of strings.
|
||||
:type list
|
||||
:custom (repeat (string :tag "File"))
|
||||
:label "Source Files"
|
||||
:group (default source)
|
||||
:documentation "Source files in this target.")
|
||||
(versionsource :initarg :versionsource
|
||||
:initform nil
|
||||
:type list
|
||||
:custom (repeat (string :tag "File"))
|
||||
:label "Source Files with Version String"
|
||||
:group (source)
|
||||
:documentation
|
||||
"Source files with a version string in them.
|
||||
These files are checked for a version string whenever the EDE version
|
||||
of the master project is changed. When strings are found, the version
|
||||
previously there is updated.")
|
||||
;; Class level slots
|
||||
;;
|
||||
(sourcetype :allocation :class
|
||||
:type list ;; list of symbols
|
||||
:documentation
|
||||
"A list of `ede-sourcecode' objects this class will handle.
|
||||
This is used to match target objects with the compilers they can use, and
|
||||
which files this object is interested in."
|
||||
:accessor ede-object-sourcecode)
|
||||
(keybindings :allocation :class
|
||||
:initform (("D" . ede-debug-target))
|
||||
:documentation
|
||||
"Keybindings specialized to this type of target."
|
||||
:accessor ede-object-keybindings)
|
||||
(menu :allocation :class
|
||||
:initform ( [ "Debug target" ede-debug-target
|
||||
(ede-buffer-belongs-to-target-p) ]
|
||||
[ "Run target" ede-run-target
|
||||
(ede-buffer-belongs-to-target-p) ]
|
||||
)
|
||||
:documentation "Menu specialized to this type of target."
|
||||
:accessor ede-object-menu)
|
||||
)
|
||||
"A target is a structure that describes a file set that produces something.
|
||||
Targets, as with 'Make', is an entity that will manage a file set
|
||||
and knows how to compile or otherwise transform those files into some
|
||||
other desired outcome.")
|
||||
|
||||
;;; PROJECT/PLACEHOLDER
|
||||
;;
|
||||
;; Project placeholders are minimum parts of a project used
|
||||
;; by the project cache. The project cache can refer to these placeholders,
|
||||
;; and swap them out with the real-deal when that project is loaded.
|
||||
;;
|
||||
(defclass ede-project-placeholder (eieio-speedbar-directory-button)
|
||||
((name :initarg :name
|
||||
:initform "Untitled"
|
||||
:type string
|
||||
:custom string
|
||||
:label "Name"
|
||||
:group (default name)
|
||||
:documentation "The name used when generating distribution files.")
|
||||
(version :initarg :version
|
||||
:initform "1.0"
|
||||
:type string
|
||||
:custom string
|
||||
:label "Version"
|
||||
:group (default name)
|
||||
:documentation "The version number used when distributing files.")
|
||||
(directory :type string
|
||||
:initarg :directory
|
||||
:documentation "Directory this project is associated with.")
|
||||
(dirinode :documentation "The inode id for :directory.")
|
||||
(file :type string
|
||||
:initarg :file
|
||||
:documentation "File name where this project is stored.")
|
||||
(rootproject ; :initarg - no initarg, don't save this slot!
|
||||
:initform nil
|
||||
:type (or null ede-project-placeholder-child)
|
||||
:documentation "Pointer to our root project.")
|
||||
)
|
||||
"Placeholder object for projects not loaded into memory.
|
||||
Projects placeholders will be stored in a user specific location
|
||||
and querying them will cause the actual project to get loaded.")
|
||||
|
||||
;;; PROJECT
|
||||
;;
|
||||
;; An EDE project controls a set of TARGETS, and can also contain
|
||||
;; multiple SUBPROJECTS.
|
||||
;;
|
||||
;; The project defines a set of features that need to be built from
|
||||
;; files, in addition as to controlling what to do with the file set,
|
||||
;; such as creating distributions, compilation, and web sites.
|
||||
;;
|
||||
;; Projects can also affect how EDE works, by changing what appears in
|
||||
;; the EDE menu, or how some keys are bound.
|
||||
;;
|
||||
(defclass ede-project (ede-project-placeholder)
|
||||
((subproj :initform nil
|
||||
:type list
|
||||
:documentation "Sub projects controlled by this project.
|
||||
For Automake based projects, each directory is treated as a project.")
|
||||
(targets :initarg :targets
|
||||
:type list
|
||||
:custom (repeat (object :objectcreatefcn ede-new-target-custom))
|
||||
:label "Local Targets"
|
||||
:group (targets)
|
||||
:documentation "List of top level targets in this project.")
|
||||
(locate-obj :type (or null ede-locate-base-child)
|
||||
:documentation
|
||||
"A locate object to use as a backup to `ede-expand-filename'.")
|
||||
(tool-cache :initarg :tool-cache
|
||||
:type list
|
||||
:custom (repeat object)
|
||||
:label "Tool: "
|
||||
:group tools
|
||||
:documentation "List of tool cache configurations in this project.
|
||||
This allows any tool to create, manage, and persist project-specific settings.")
|
||||
(mailinglist :initarg :mailinglist
|
||||
:initform ""
|
||||
:type string
|
||||
:custom string
|
||||
:label "Mailing List Address"
|
||||
:group name
|
||||
:documentation
|
||||
"An email address where users might send email for help.")
|
||||
(web-site-url :initarg :web-site-url
|
||||
:initform ""
|
||||
:type string
|
||||
:custom string
|
||||
:label "Web Site URL"
|
||||
:group name
|
||||
:documentation "URL to this projects web site.
|
||||
This is a URL to be sent to a web site for documentation.")
|
||||
(web-site-directory :initarg :web-site-directory
|
||||
:initform ""
|
||||
:custom string
|
||||
:label "Web Page Directory"
|
||||
:group name
|
||||
:documentation
|
||||
"A directory where web pages can be found by Emacs.
|
||||
For remote locations use a path compatible with ange-ftp or EFS.
|
||||
You can also use TRAMP for use with rcp & scp.")
|
||||
(web-site-file :initarg :web-site-file
|
||||
:initform ""
|
||||
:custom string
|
||||
:label "Web Page File"
|
||||
:group name
|
||||
:documentation
|
||||
"A file which contains the home page for this project.
|
||||
This file can be relative to slot `web-site-directory'.
|
||||
This can be a local file, use ange-ftp, EFS, or TRAMP.")
|
||||
(ftp-site :initarg :ftp-site
|
||||
:initform ""
|
||||
:type string
|
||||
:custom string
|
||||
:label "FTP site"
|
||||
:group name
|
||||
:documentation
|
||||
"FTP site where this project's distribution can be found.
|
||||
This FTP site should be in Emacs form, as needed by `ange-ftp', but can
|
||||
also be of a form used by TRAMP for use with scp, or rcp.")
|
||||
(ftp-upload-site :initarg :ftp-upload-site
|
||||
:initform ""
|
||||
:type string
|
||||
:custom string
|
||||
:label "FTP Upload site"
|
||||
:group name
|
||||
:documentation
|
||||
"FTP Site to upload new distributions to.
|
||||
This FTP site should be in Emacs form as needed by `ange-ftp'.
|
||||
If this slot is nil, then use `ftp-site' instead.")
|
||||
(configurations :initarg :configurations
|
||||
:initform ("debug" "release")
|
||||
:type list
|
||||
:custom (repeat string)
|
||||
:label "Configuration Options"
|
||||
:group (settings)
|
||||
:documentation "List of available configuration types.
|
||||
Individual target/project types can form associations between a configuration,
|
||||
and target specific elements such as build variables.")
|
||||
(configuration-default :initarg :configuration-default
|
||||
:initform "debug"
|
||||
:custom string
|
||||
:label "Current Configuration"
|
||||
:group (settings)
|
||||
:documentation "The default configuration.")
|
||||
(local-variables :initarg :local-variables
|
||||
:initform nil
|
||||
:custom (repeat (cons (sexp :tag "Variable")
|
||||
(sexp :tag "Value")))
|
||||
:label "Project Local Variables"
|
||||
:group (settings)
|
||||
:documentation "Project local variables")
|
||||
(keybindings :allocation :class
|
||||
:initform (("D" . ede-debug-target)
|
||||
("R" . ede-run-target))
|
||||
:documentation "Keybindings specialized to this type of target."
|
||||
:accessor ede-object-keybindings)
|
||||
(menu :allocation :class
|
||||
:initform
|
||||
(
|
||||
[ "Update Version" ede-update-version ede-object ]
|
||||
[ "Version Control Status" ede-vc-project-directory ede-object ]
|
||||
[ "Edit Project Homepage" ede-edit-web-page
|
||||
(and ede-object (oref (ede-toplevel) web-site-file)) ]
|
||||
[ "Browse Project URL" ede-web-browse-home
|
||||
(and ede-object
|
||||
(not (string= "" (oref (ede-toplevel) web-site-url)))) ]
|
||||
"--"
|
||||
[ "Rescan Project Files" ede-rescan-toplevel t ]
|
||||
[ "Edit Projectfile" ede-edit-file-target
|
||||
(ede-buffer-belongs-to-project-p) ]
|
||||
)
|
||||
:documentation "Menu specialized to this type of target."
|
||||
:accessor ede-object-menu)
|
||||
)
|
||||
"Top level EDE project specification.
|
||||
All specific project types must derive from this project."
|
||||
:method-invocation-order :depth-first)
|
||||
|
||||
;;; Important macros for doing commands.
|
||||
;;
|
||||
(defmacro ede-with-projectfile (obj &rest forms)
|
||||
"For the project in which OBJ resides, execute FORMS."
|
||||
(list 'save-window-excursion
|
||||
(list 'let* (list
|
||||
(list 'pf
|
||||
(list 'if (list 'obj-of-class-p
|
||||
obj 'ede-target)
|
||||
;; @todo -I think I can change
|
||||
;; this to not need ede-load-project-file
|
||||
;; but I'm not sure how to test well.
|
||||
(list 'ede-load-project-file
|
||||
(list 'oref obj 'path))
|
||||
obj))
|
||||
'(dbka (get-file-buffer (oref pf file))))
|
||||
'(if (not dbka) (find-file (oref pf file))
|
||||
(switch-to-buffer dbka))
|
||||
(cons 'progn forms)
|
||||
'(if (not dbka) (kill-buffer (current-buffer))))))
|
||||
(put 'ede-with-projectfile 'lisp-indent-function 1)
|
||||
|
||||
;;; The EDE persistent cache.
|
||||
;;
|
||||
;; The cache is a way to mark where all known projects live without
|
||||
;; loading those projects into memory, or scanning for them each time
|
||||
;; emacs starts.
|
||||
;;
|
||||
(defcustom ede-project-placeholder-cache-file
|
||||
(locate-user-emacs-file "ede-projects.el" ".projects.ede")
|
||||
"File containing the list of projects EDE has viewed."
|
||||
:group 'ede
|
||||
:type 'file)
|
||||
|
||||
(defvar ede-project-cache-files nil
|
||||
"List of project files EDE has seen before.")
|
||||
|
||||
(defun ede-save-cache ()
|
||||
"Save a cache of EDE objects that Emacs has seen before."
|
||||
(interactive)
|
||||
(let ((p ede-projects)
|
||||
(c ede-project-cache-files)
|
||||
(recentf-exclude '( (lambda (f) t) ))
|
||||
)
|
||||
(condition-case nil
|
||||
(progn
|
||||
(set-buffer (find-file-noselect ede-project-placeholder-cache-file t))
|
||||
(erase-buffer)
|
||||
(insert ";; EDE project cache file.
|
||||
;; This contains a list of projects you have visited.\n(")
|
||||
(while p
|
||||
(when (and (car p) (ede-project-p p))
|
||||
(let ((f (oref (car p) file)))
|
||||
(when (file-exists-p f)
|
||||
(insert "\n \"" f "\""))))
|
||||
(setq p (cdr p)))
|
||||
(while c
|
||||
(insert "\n \"" (car c) "\"")
|
||||
(setq c (cdr c)))
|
||||
(insert "\n)\n")
|
||||
(condition-case nil
|
||||
(save-buffer 0)
|
||||
(error
|
||||
(message "File %s could not be saved."
|
||||
ede-project-placeholder-cache-file)))
|
||||
(kill-buffer (current-buffer))
|
||||
)
|
||||
(error
|
||||
(message "File %s could not be read."
|
||||
ede-project-placeholder-cache-file))
|
||||
|
||||
)))
|
||||
|
||||
(defun ede-load-cache ()
|
||||
"Load the cache of EDE projects."
|
||||
(save-excursion
|
||||
(let ((cachebuffer nil))
|
||||
(condition-case nil
|
||||
(progn
|
||||
(setq cachebuffer
|
||||
(find-file-noselect ede-project-placeholder-cache-file t))
|
||||
(set-buffer cachebuffer)
|
||||
(goto-char (point-min))
|
||||
(let ((c (read (current-buffer)))
|
||||
(new nil)
|
||||
(p ede-projects))
|
||||
;; Remove loaded projects from the cache.
|
||||
(while p
|
||||
(setq c (delete (oref (car p) file) c))
|
||||
(setq p (cdr p)))
|
||||
;; Remove projects that aren't on the filesystem
|
||||
;; anymore.
|
||||
(while c
|
||||
(when (file-exists-p (car c))
|
||||
(setq new (cons (car c) new)))
|
||||
(setq c (cdr c)))
|
||||
;; Save it
|
||||
(setq ede-project-cache-files (nreverse new))))
|
||||
(error nil))
|
||||
(when cachebuffer (kill-buffer cachebuffer))
|
||||
)))
|
||||
|
||||
;;; Get the cache usable.
|
||||
|
||||
;; @TODO - Remove this cache setup, or use this for something helpful.
|
||||
;;(add-hook 'kill-emacs-hook 'ede-save-cache)
|
||||
;;(when (not noninteractive)
|
||||
;; ;; No need to load the EDE cache if we aren't interactive.
|
||||
;; ;; This occurs during batch byte-compiling of other tools.
|
||||
;; (ede-load-cache))
|
||||
|
||||
|
||||
;;; METHODS
|
||||
;;
|
||||
;; The methods in ede-base handle project related behavior, and DO NOT
|
||||
;; related to EDE mode commands directory, such as keybindings.
|
||||
;;
|
||||
;; Mode related methods are in ede.el. These methods are related
|
||||
;; project specific activities not directly tied to a keybinding.
|
||||
(defmethod ede-subproject-relative-path ((proj ede-project) &optional parent-in)
|
||||
"Get a path name for PROJ which is relative to the parent project.
|
||||
If PARENT is specified, then be relative to the PARENT project.
|
||||
Specifying PARENT is useful for sub-sub projects relative to the root project."
|
||||
(let* ((parent (or parent-in (ede-parent-project proj)))
|
||||
(dir (file-name-directory (oref proj file))))
|
||||
(if (and parent (not (eq parent proj)))
|
||||
(file-relative-name dir (file-name-directory (oref parent file)))
|
||||
"")))
|
||||
|
||||
(defmethod ede-subproject-p ((proj ede-project))
|
||||
"Return non-nil if PROJ is a sub project."
|
||||
;; @TODO - Use this in more places, and also pay attention to
|
||||
;; metasubproject in ede-proj.el
|
||||
(ede-parent-project proj))
|
||||
|
||||
|
||||
;;; Default descriptive methods for EDE classes
|
||||
;;
|
||||
;; These are methods which you might want to override, but there is
|
||||
;; no need to in most situations because they are either a) simple, or
|
||||
;; b) cosmetic.
|
||||
|
||||
(defmethod ede-name ((this ede-target))
|
||||
"Return the name of THIS target."
|
||||
(oref this name))
|
||||
|
||||
(defmethod ede-target-name ((this ede-target))
|
||||
"Return the name of THIS target, suitable for make or debug style commands."
|
||||
(oref this name))
|
||||
|
||||
(defmethod ede-name ((this ede-project))
|
||||
"Return a short-name for THIS project file.
|
||||
Do this by extracting the lowest directory name."
|
||||
(oref this name))
|
||||
|
||||
(defmethod ede-description ((this ede-project))
|
||||
"Return a description suitable for the minibuffer about THIS."
|
||||
(format "Project %s: %d subprojects, %d targets."
|
||||
(ede-name this) (length (oref this subproj))
|
||||
(length (oref this targets))))
|
||||
|
||||
(defmethod ede-description ((this ede-target))
|
||||
"Return a description suitable for the minibuffer about THIS."
|
||||
(format "Target %s: with %d source files."
|
||||
(ede-name this) (length (oref this source))))
|
||||
|
||||
;;; HEADERS/DOC
|
||||
;;
|
||||
;; Targets and projects are often associated with other files, such as
|
||||
;; header files, documentation files and the like. Have strong
|
||||
;; associations can make useful user commands to quickly navigate
|
||||
;; between the files base on their assocaitions.
|
||||
;;
|
||||
(defun ede-header-file ()
|
||||
"Return the header file for the current buffer.
|
||||
Not all buffers need headers, so return nil if no applicable."
|
||||
(if ede-object
|
||||
(ede-buffer-header-file ede-object (current-buffer))
|
||||
nil))
|
||||
|
||||
(defmethod ede-buffer-header-file ((this ede-project) buffer)
|
||||
"Return nil, projects don't have header files."
|
||||
nil)
|
||||
|
||||
(defmethod ede-buffer-header-file ((this ede-target) buffer)
|
||||
"There are no default header files in EDE.
|
||||
Do a quick check to see if there is a Header tag in this buffer."
|
||||
(with-current-buffer buffer
|
||||
(if (re-search-forward "::Header:: \\([a-zA-Z0-9.]+\\)" nil t)
|
||||
(buffer-substring-no-properties (match-beginning 1)
|
||||
(match-end 1))
|
||||
(let ((src (ede-target-sourcecode this))
|
||||
(found nil))
|
||||
(while (and src (not found))
|
||||
(setq found (ede-buffer-header-file (car src) (buffer-file-name))
|
||||
src (cdr src)))
|
||||
found))))
|
||||
|
||||
(defun ede-documentation-files ()
|
||||
"Return the documentation files for the current buffer.
|
||||
Not all buffers need documentations, so return nil if no applicable.
|
||||
Some projects may have multiple documentation files, so return a list."
|
||||
(if ede-object
|
||||
(ede-buffer-documentation-files ede-object (current-buffer))
|
||||
nil))
|
||||
|
||||
(defmethod ede-buffer-documentation-files ((this ede-project) buffer)
|
||||
"Return all documentation in project THIS based on BUFFER."
|
||||
;; Find the info node.
|
||||
(ede-documentation this))
|
||||
|
||||
(defmethod ede-buffer-documentation-files ((this ede-target) buffer)
|
||||
"Check for some documentation files for THIS.
|
||||
Also do a quick check to see if there is a Documentation tag in this BUFFER."
|
||||
(with-current-buffer buffer
|
||||
(if (re-search-forward "::Documentation:: \\([a-zA-Z0-9.]+\\)" nil t)
|
||||
(buffer-substring-no-properties (match-beginning 1)
|
||||
(match-end 1))
|
||||
;; Check the master project
|
||||
(let ((cp (ede-toplevel)))
|
||||
(ede-buffer-documentation-files cp (current-buffer))))))
|
||||
|
||||
(defmethod ede-documentation ((this ede-project))
|
||||
"Return a list of files that provide documentation.
|
||||
Documentation is not for object THIS, but is provided by THIS for other
|
||||
files in the project."
|
||||
(let ((targ (oref this targets))
|
||||
(proj (oref this subproj))
|
||||
(found nil))
|
||||
(while targ
|
||||
(setq found (append (ede-documentation (car targ)) found)
|
||||
targ (cdr targ)))
|
||||
(while proj
|
||||
(setq found (append (ede-documentation (car proj)) found)
|
||||
proj (cdr proj)))
|
||||
found))
|
||||
|
||||
(defmethod ede-documentation ((this ede-target))
|
||||
"Return a list of files that provide documentation.
|
||||
Documentation is not for object THIS, but is provided by THIS for other
|
||||
files in the project."
|
||||
nil)
|
||||
|
||||
(defun ede-html-documentation-files ()
|
||||
"Return a list of HTML documentation files associated with this project."
|
||||
(ede-html-documentation (ede-toplevel))
|
||||
)
|
||||
|
||||
(defmethod ede-html-documentation ((this ede-project))
|
||||
"Return a list of HTML files provided by project THIS."
|
||||
|
||||
)
|
||||
|
||||
;;; Default "WANT" methods.
|
||||
;;
|
||||
;; These methods are used to determine if a target "wants", or could
|
||||
;; somehow handle a file, or some source type.
|
||||
;;
|
||||
(defmethod ede-want-file-p ((this ede-target) file)
|
||||
"Return non-nil if THIS target wants FILE."
|
||||
;; By default, all targets reference the source object, and let it decide.
|
||||
(let ((src (ede-target-sourcecode this)))
|
||||
(while (and src (not (ede-want-file-p (car src) file)))
|
||||
(setq src (cdr src)))
|
||||
src))
|
||||
|
||||
(defmethod ede-want-file-source-p ((this ede-target) file)
|
||||
"Return non-nil if THIS target wants FILE."
|
||||
;; By default, all targets reference the source object, and let it decide.
|
||||
(let ((src (ede-target-sourcecode this)))
|
||||
(while (and src (not (ede-want-file-source-p (car src) file)))
|
||||
(setq src (cdr src)))
|
||||
src))
|
||||
|
||||
(defmethod ede-target-sourcecode ((this ede-target))
|
||||
"Return the sourcecode objects which THIS permits."
|
||||
(let ((sc (oref this sourcetype))
|
||||
(rs nil))
|
||||
(while (and (listp sc) sc)
|
||||
(setq rs (cons (symbol-value (car sc)) rs)
|
||||
sc (cdr sc)))
|
||||
rs))
|
||||
|
||||
|
||||
;;; Debugging.
|
||||
;;
|
||||
(defun ede-adebug-project ()
|
||||
"Run adebug against the current EDE project.
|
||||
Display the results as a debug list."
|
||||
(interactive)
|
||||
(require 'data-debug)
|
||||
(when (ede-current-project)
|
||||
(data-debug-new-buffer "*Analyzer ADEBUG*")
|
||||
(data-debug-insert-object-slots (ede-current-project) "")
|
||||
))
|
||||
|
||||
(defun ede-adebug-project-parent ()
|
||||
"Run adebug against the current EDE parent project.
|
||||
Display the results as a debug list."
|
||||
(interactive)
|
||||
(require 'data-debug)
|
||||
(when (ede-parent-project)
|
||||
(data-debug-new-buffer "*Analyzer ADEBUG*")
|
||||
(data-debug-insert-object-slots (ede-parent-project) "")
|
||||
))
|
||||
|
||||
(defun ede-adebug-project-root ()
|
||||
"Run adebug against the current EDE parent project.
|
||||
Display the results as a debug list."
|
||||
(interactive)
|
||||
(require 'data-debug)
|
||||
(when (ede-toplevel)
|
||||
(data-debug-new-buffer "*Analyzer ADEBUG*")
|
||||
(data-debug-insert-object-slots (ede-toplevel) "")
|
||||
))
|
||||
|
||||
|
||||
|
||||
;;; TOPLEVEL PROJECT
|
||||
;;
|
||||
;; The toplevel project is a way to identify the EDE structure that belongs
|
||||
;; to the top of a project.
|
||||
|
||||
(defun ede-toplevel (&optional subproj)
|
||||
"Return the ede project which is the root of the current project.
|
||||
Optional argument SUBPROJ indicates a subproject to start from
|
||||
instead of the current project."
|
||||
(or ede-object-root-project
|
||||
(let* ((cp (or subproj (ede-current-project))))
|
||||
(or (and cp (ede-project-root cp))
|
||||
(progn
|
||||
(while (ede-parent-project cp)
|
||||
(setq cp (ede-parent-project cp)))
|
||||
cp)))))
|
||||
|
||||
|
||||
;;; Hooks & Autoloads
|
||||
;;
|
||||
;; These let us watch various activities, and respond appropriately.
|
||||
|
||||
;; (add-hook 'edebug-setup-hook
|
||||
;; (lambda ()
|
||||
;; (def-edebug-spec ede-with-projectfile
|
||||
;; (form def-body))))
|
||||
|
||||
(provide 'ede/base)
|
||||
|
||||
;; Local variables:
|
||||
;; generated-autoload-file: "loaddefs.el"
|
||||
;; generated-autoload-load-name: "ede/base"
|
||||
;; End:
|
||||
|
||||
;;; ede/base.el ends here
|
|
@ -237,6 +237,18 @@ ROOTPROJ is nil, since there is only one project."
|
|||
;; Snoop through our master list.
|
||||
(ede-cpp-root-file-existing dir))
|
||||
|
||||
;;;###autoload
|
||||
(add-to-list 'ede-project-class-files
|
||||
(ede-project-autoload "cpp-root"
|
||||
:name "CPP ROOT"
|
||||
:file 'ede-cpp-root
|
||||
:proj-file 'ede-cpp-root-project-file-for-dir
|
||||
:proj-root 'ede-cpp-root-project-root
|
||||
:load-type 'ede-cpp-root-load
|
||||
:class-sym 'ede-cpp-root
|
||||
:new-p nil)
|
||||
t)
|
||||
|
||||
;;; CLASSES
|
||||
;;
|
||||
;; EDE sets up projects with two kinds of objects.
|
||||
|
@ -504,6 +516,21 @@ Also set up the lexical preprocessor map."
|
|||
"Get the pre-processor map for project THIS."
|
||||
(ede-preprocessor-map (ede-target-parent this)))
|
||||
|
||||
;;; Quick Hack
|
||||
(defun ede-create-lots-of-projects-under-dir (dir projfile &rest attributes)
|
||||
"Create a bunch of projects under directory DIR.
|
||||
PROJFILE is a file name sans directory that indicates a subdirectory
|
||||
is a project directory.
|
||||
Generic ATTRIBUTES, such as :include-path can be added.
|
||||
Note: This needs some work."
|
||||
(let ((files (directory-files dir t)))
|
||||
(dolist (F files)
|
||||
(if (file-exists-p (expand-file-name projfile F))
|
||||
`(ede-cpp-root-project (file-name-nondirectory F)
|
||||
:name (file-name-nondirectory F)
|
||||
:file (expand-file-name projfile F)
|
||||
attributes)))))
|
||||
|
||||
(provide 'ede/cpp-root)
|
||||
|
||||
;; Local variables:
|
||||
|
|
215
lisp/cedet/ede/custom.el
Normal file
215
lisp/cedet/ede/custom.el
Normal file
|
@ -0,0 +1,215 @@
|
|||
;;; ede.el --- customization of EDE projects.
|
||||
|
||||
;; Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Eric M. Ludlam <zappo@gnu.org>
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs 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 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs 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. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; Customization commands/hooks for EDE.
|
||||
;;
|
||||
;; EIEIO supports customizing objects, and EDE uses this to allow
|
||||
;; users to change basic settings in their projects.
|
||||
;;
|
||||
|
||||
;;; Code:
|
||||
;;; Customization
|
||||
;;
|
||||
;; Routines for customizing projects and targets.
|
||||
|
||||
(require 'ede)
|
||||
(eval-when-compile (require 'eieio-custom))
|
||||
|
||||
(defvar eieio-ede-old-variables nil
|
||||
"The old variables for a project.")
|
||||
|
||||
;;; Customization Commands
|
||||
;;
|
||||
;; These commands initialize custoization of EDE control objects.
|
||||
|
||||
;;;###autoload
|
||||
(defun ede-customize-project ()
|
||||
"Edit fields of the current project through EIEIO & Custom."
|
||||
(interactive)
|
||||
(require 'eieio-custom)
|
||||
(let* ((ov (oref (ede-current-project) local-variables))
|
||||
(cp (ede-current-project)))
|
||||
(ede-customize cp)
|
||||
(make-local-variable 'eieio-ede-old-variables)
|
||||
(setq eieio-ede-old-variables ov)))
|
||||
|
||||
;;;###autoload
|
||||
(defalias 'customize-project 'ede-customize-project)
|
||||
|
||||
;;;###autoload
|
||||
(defun ede-customize-current-target()
|
||||
"Edit fields of the current target through EIEIO & Custom."
|
||||
(interactive)
|
||||
(require 'eieio-custom)
|
||||
(if (not (obj-of-class-p ede-object ede-target))
|
||||
(error "Current file is not part of a target"))
|
||||
(ede-customize-target ede-object))
|
||||
|
||||
;;;###autoload
|
||||
(defalias 'customize-target 'ede-customize-current-target)
|
||||
|
||||
(defun ede-customize-target (obj)
|
||||
"Edit fields of the current target through EIEIO & Custom.
|
||||
OBJ is the target object to customize."
|
||||
(require 'eieio-custom)
|
||||
(if (and obj (not (obj-of-class-p obj ede-target)))
|
||||
(error "No logical target to customize"))
|
||||
(ede-customize obj))
|
||||
|
||||
(defmethod ede-customize ((proj ede-project))
|
||||
"Customize the EDE project PROJ."
|
||||
(eieio-customize-object proj 'default))
|
||||
|
||||
(defmethod ede-customize ((target ede-target))
|
||||
"Customize the EDE TARGET."
|
||||
(eieio-customize-object target 'default))
|
||||
|
||||
;;; Target Sorting
|
||||
;;
|
||||
;; Target order can be important, but custom doesn't support a way
|
||||
;; to resort items in a list. This function by David Engster allows
|
||||
;; targets to be re-arranged.
|
||||
|
||||
(defvar ede-project-sort-targets-order nil
|
||||
"Variable for tracking target order in `ede-project-sort-targets'.")
|
||||
|
||||
;;;###autoload
|
||||
(defun ede-project-sort-targets ()
|
||||
"Create a custom-like buffer for sorting targets of current project."
|
||||
(interactive)
|
||||
(let ((proj (ede-current-project))
|
||||
(count 1)
|
||||
current order)
|
||||
(switch-to-buffer (get-buffer-create "*EDE sort targets*"))
|
||||
(erase-buffer)
|
||||
(setq ede-object-project proj)
|
||||
(widget-create 'push-button
|
||||
:notify (lambda (&rest ignore)
|
||||
(let ((targets (oref ede-object-project targets))
|
||||
cur newtargets)
|
||||
(while (setq cur (pop ede-project-sort-targets-order))
|
||||
(setq newtargets (append newtargets
|
||||
(list (nth cur targets)))))
|
||||
(oset ede-object-project targets newtargets))
|
||||
(ede-commit-project ede-object-project)
|
||||
(kill-buffer))
|
||||
" Accept ")
|
||||
(widget-insert " ")
|
||||
(widget-create 'push-button
|
||||
:notify (lambda (&rest ignore)
|
||||
(kill-buffer))
|
||||
" Cancel ")
|
||||
(widget-insert "\n\n")
|
||||
(setq ede-project-sort-targets-order nil)
|
||||
(mapc (lambda (x)
|
||||
(add-to-ordered-list
|
||||
'ede-project-sort-targets-order
|
||||
x x))
|
||||
(number-sequence 0 (1- (length (oref proj targets)))))
|
||||
(ede-project-sort-targets-list)
|
||||
(use-local-map widget-keymap)
|
||||
(widget-setup)
|
||||
(goto-char (point-min))))
|
||||
|
||||
(defun ede-project-sort-targets-list ()
|
||||
"Sort the target list while using `ede-project-sort-targets'."
|
||||
(save-excursion
|
||||
(let ((count 0)
|
||||
(targets (oref ede-object-project targets))
|
||||
(inhibit-read-only t)
|
||||
(inhibit-modification-hooks t))
|
||||
(goto-char (point-min))
|
||||
(forward-line 2)
|
||||
(delete-region (point) (point-max))
|
||||
(while (< count (length targets))
|
||||
(if (> count 0)
|
||||
(widget-create 'push-button
|
||||
:notify `(lambda (&rest ignore)
|
||||
(let ((cur ede-project-sort-targets-order))
|
||||
(add-to-ordered-list
|
||||
'ede-project-sort-targets-order
|
||||
(nth ,count cur)
|
||||
(1- ,count))
|
||||
(add-to-ordered-list
|
||||
'ede-project-sort-targets-order
|
||||
(nth (1- ,count) cur) ,count))
|
||||
(ede-project-sort-targets-list))
|
||||
" Up ")
|
||||
(widget-insert " "))
|
||||
(if (< count (1- (length targets)))
|
||||
(widget-create 'push-button
|
||||
:notify `(lambda (&rest ignore)
|
||||
(let ((cur ede-project-sort-targets-order))
|
||||
(add-to-ordered-list
|
||||
'ede-project-sort-targets-order
|
||||
(nth ,count cur) (1+ ,count))
|
||||
(add-to-ordered-list
|
||||
'ede-project-sort-targets-order
|
||||
(nth (1+ ,count) cur) ,count))
|
||||
(ede-project-sort-targets-list))
|
||||
" Down ")
|
||||
(widget-insert " "))
|
||||
(widget-insert (concat " " (number-to-string (1+ count)) ".: "
|
||||
(oref (nth (nth count ede-project-sort-targets-order)
|
||||
targets) name) "\n"))
|
||||
(setq count (1+ count))))))
|
||||
|
||||
;;; Customization hooks
|
||||
;;
|
||||
;; These hooks are used when finishing up a customization.
|
||||
(defmethod eieio-done-customizing ((proj ede-project))
|
||||
"Call this when a user finishes customizing PROJ."
|
||||
(let ((ov eieio-ede-old-variables)
|
||||
(nv (oref proj local-variables)))
|
||||
(setq eieio-ede-old-variables nil)
|
||||
(while ov
|
||||
(if (not (assoc (car (car ov)) nv))
|
||||
(save-excursion
|
||||
(mapc (lambda (b)
|
||||
(set-buffer b)
|
||||
(kill-local-variable (car (car ov))))
|
||||
(ede-project-buffers proj))))
|
||||
(setq ov (cdr ov)))
|
||||
(mapc (lambda (b) (ede-set-project-variables proj b))
|
||||
(ede-project-buffers proj))))
|
||||
|
||||
;; These two methods should be implemented by subclasses of
|
||||
;; project and targets in order to account for user specified
|
||||
;; changes.
|
||||
(defmethod eieio-done-customizing ((target ede-target))
|
||||
"Call this when a user finishes customizing TARGET."
|
||||
nil)
|
||||
|
||||
(defmethod ede-commit-project ((proj ede-project))
|
||||
"Commit any change to PROJ to its file."
|
||||
nil
|
||||
)
|
||||
|
||||
(provide 'ede/custom)
|
||||
|
||||
;; Local variables:
|
||||
;; generated-autoload-file: "loaddefs.el"
|
||||
;; generated-autoload-load-name: "ede/custom"
|
||||
;; End:
|
||||
|
||||
;;; ede/custom.el ends here
|
|
@ -76,11 +76,11 @@ negative, force off."
|
|||
"Add files to Target: "))))
|
||||
(dolist (file (dired-get-marked-files t))
|
||||
(project-add-file target file)
|
||||
;; Find the buffer for this files, and set it's ede-object
|
||||
;; Find the buffer for this files, and set its ede-object
|
||||
(if (get-file-buffer file)
|
||||
(with-current-buffer (get-file-buffer file)
|
||||
(setq ede-object nil)
|
||||
(setq ede-object (ede-buffer-object (current-buffer)))))))
|
||||
(with-current-buffer (get-file-buffer file)
|
||||
(setq ede-object nil)
|
||||
(setq ede-object (ede-buffer-object (current-buffer)))))))
|
||||
|
||||
(provide 'ede/dired)
|
||||
|
||||
|
|
|
@ -133,6 +133,18 @@ ROOTPROJ is nil, since there is only one project."
|
|||
)
|
||||
)
|
||||
|
||||
;;;###autoload
|
||||
(add-to-list 'ede-project-class-files
|
||||
(ede-project-autoload "emacs"
|
||||
:name "EMACS ROOT"
|
||||
:file 'ede-emacs
|
||||
:proj-file "src/emacs.c"
|
||||
:proj-root 'ede-emacs-project-root
|
||||
:load-type 'ede-emacs-load
|
||||
:class-sym 'ede-emacs-project
|
||||
:new-p nil)
|
||||
t)
|
||||
|
||||
(defclass ede-emacs-target-c (ede-target)
|
||||
()
|
||||
"EDE Emacs Project target for C code.
|
||||
|
@ -150,7 +162,7 @@ All directories need at least one target.")
|
|||
|
||||
(defmethod initialize-instance ((this ede-emacs-project)
|
||||
&rest fields)
|
||||
"Make sure the :file is fully expanded."
|
||||
"Make sure the targets slot is bound."
|
||||
(call-next-method)
|
||||
(unless (slot-boundp this 'targets)
|
||||
(oset this :targets nil)))
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
(declare-function ede-locate-file-in-hash "ede/locate")
|
||||
(declare-function ede-locate-add-file-to-hash "ede/locate")
|
||||
(declare-function ede-locate-file-in-project "ede/locate")
|
||||
(declare-function ede-locate-flush-hash "ede/locate")
|
||||
|
||||
(defvar ede--disable-inode nil
|
||||
"Set to 't' to simulate systems w/out inode support.")
|
||||
|
@ -57,44 +58,29 @@ the current EDE project."
|
|||
(ede-project-root-directory (ede-current-project))))
|
||||
(find-file fname)))
|
||||
|
||||
(defun ede-flush-project-hash ()
|
||||
"Flush the file locate hash for the current project."
|
||||
(interactive)
|
||||
(require 'ede/locate)
|
||||
(let* ((loc (ede-get-locator-object (ede-current-project))))
|
||||
(ede-locate-flush-hash loc)))
|
||||
|
||||
;;; Placeholders for ROOT directory scanning on base objects
|
||||
;;
|
||||
(defmethod ede-project-root ((this ede-project-placeholder))
|
||||
"If a project knows it's root, return it here.
|
||||
"If a project knows its root, return it here.
|
||||
Allows for one-project-object-for-a-tree type systems."
|
||||
(oref this rootproject))
|
||||
|
||||
(defmethod ede-project-root-directory ((this ede-project-placeholder)
|
||||
&optional file)
|
||||
"If a project knows it's root, return it here.
|
||||
"If a project knows its root, return it here.
|
||||
Allows for one-project-object-for-a-tree type systems.
|
||||
Optional FILE is the file to test. It is ignored in preference
|
||||
of the anchor file for the project."
|
||||
(file-name-directory (expand-file-name (oref this file))))
|
||||
|
||||
|
||||
(defmethod ede-project-root ((this ede-project-autoload))
|
||||
"If a project knows it's root, return it here.
|
||||
Allows for one-project-object-for-a-tree type systems."
|
||||
nil)
|
||||
|
||||
(defmethod ede-project-root-directory ((this ede-project-autoload)
|
||||
&optional file)
|
||||
"If a project knows it's root, return it here.
|
||||
Allows for one-project-object-for-a-tree type systems.
|
||||
Optional FILE is the file to test. If there is no FILE, use
|
||||
the current buffer."
|
||||
(when (not file)
|
||||
(setq file default-directory))
|
||||
(when (slot-boundp this :proj-root)
|
||||
(let ((rootfcn (oref this proj-root)))
|
||||
(when rootfcn
|
||||
(condition-case nil
|
||||
(funcall rootfcn file)
|
||||
(error
|
||||
(funcall rootfcn)))
|
||||
))))
|
||||
|
||||
(defmethod ede--project-inode ((proj ede-project-placeholder))
|
||||
"Get the inode of the directory project PROJ is in."
|
||||
(if (slot-boundp proj 'dirinode)
|
||||
|
@ -262,27 +248,30 @@ Do this whenever a new project is created, as opposed to loaded."
|
|||
(defun ede-directory-project-p (dir &optional force)
|
||||
"Return a project description object if DIR has a project.
|
||||
Optional argument FORCE means to ignore a hash-hit of 'nomatch.
|
||||
This depends on an up to date `ede-project-class-files' variable."
|
||||
(let* ((dirtest (expand-file-name dir))
|
||||
(match (ede-directory-project-from-hash dirtest)))
|
||||
(cond
|
||||
((and (eq match 'nomatch) (not force))
|
||||
nil)
|
||||
((and match (not (eq match 'nomatch)))
|
||||
match)
|
||||
(t
|
||||
(let ((types ede-project-class-files)
|
||||
(ret nil))
|
||||
;; Loop over all types, loading in the first type that we find.
|
||||
(while (and types (not ret))
|
||||
(if (ede-dir-to-projectfile (car types) dirtest)
|
||||
(progn
|
||||
;; We found one! Require it now since we will need it.
|
||||
(require (oref (car types) file))
|
||||
(setq ret (car types))))
|
||||
(setq types (cdr types)))
|
||||
(ede-directory-project-add-description-to-hash dirtest (or ret 'nomatch))
|
||||
ret)))))
|
||||
This depends on an up to date `ede-project-class-files' variable.
|
||||
Any directory that contains the file .ede-ignore will allways
|
||||
return nil."
|
||||
(when (not (file-exists-p (expand-file-name ".ede-ignore" dir)))
|
||||
(let* ((dirtest (expand-file-name dir))
|
||||
(match (ede-directory-project-from-hash dirtest)))
|
||||
(cond
|
||||
((and (eq match 'nomatch) (not force))
|
||||
nil)
|
||||
((and match (not (eq match 'nomatch)))
|
||||
match)
|
||||
(t
|
||||
(let ((types ede-project-class-files)
|
||||
(ret nil))
|
||||
;; Loop over all types, loading in the first type that we find.
|
||||
(while (and types (not ret))
|
||||
(if (ede-dir-to-projectfile (car types) dirtest)
|
||||
(progn
|
||||
;; We found one! Require it now since we will need it.
|
||||
(require (oref (car types) file))
|
||||
(setq ret (car types))))
|
||||
(setq types (cdr types)))
|
||||
(ede-directory-project-add-description-to-hash dirtest (or ret 'nomatch))
|
||||
ret))))))
|
||||
|
||||
;;; TOPLEVEL
|
||||
;;
|
||||
|
@ -324,7 +313,7 @@ nil is returned if the current directory is not a part of a project."
|
|||
;; If PROJ didn't know, or there is no PROJ, then
|
||||
|
||||
;; Loop up to the topmost project, and then load that single
|
||||
;; project, and it's sub projects. When we are done, identify the
|
||||
;; project, and its sub projects. When we are done, identify the
|
||||
;; sub-project object belonging to file.
|
||||
(while (and (not ans) newpath proj)
|
||||
(setq toppath newpath
|
||||
|
@ -338,24 +327,6 @@ nil is returned if the current directory is not a part of a project."
|
|||
)
|
||||
(or ans toppath))))))
|
||||
|
||||
;;; TOPLEVEL PROJECT
|
||||
;;
|
||||
;; The toplevel project is a way to identify the EDE structure that belongs
|
||||
;; to the top of a project.
|
||||
|
||||
(defun ede-toplevel (&optional subproj)
|
||||
"Return the ede project which is the root of the current project.
|
||||
Optional argument SUBPROJ indicates a subproject to start from
|
||||
instead of the current project."
|
||||
(or ede-object-root-project
|
||||
(let* ((cp (or subproj (ede-current-project)))
|
||||
)
|
||||
(or (and cp (ede-project-root cp))
|
||||
(progn
|
||||
(while (ede-parent-project cp)
|
||||
(setq cp (ede-parent-project cp)))
|
||||
cp)))))
|
||||
|
||||
;;; DIRECTORY CONVERSION STUFF
|
||||
;;
|
||||
(defmethod ede-convert-path ((this ede-project) path)
|
||||
|
@ -372,11 +343,13 @@ Argument THIS is the project to convert PATH to."
|
|||
(substring fptf (match-end 0))
|
||||
(error "Cannot convert relativize path %s" fp))))))
|
||||
|
||||
(defmethod ede-convert-path ((this ede-target) path)
|
||||
(defmethod ede-convert-path ((this ede-target) path &optional project)
|
||||
"Convert path in a standard way for a given project.
|
||||
Default to making it project relative.
|
||||
Argument THIS is the project to convert PATH to."
|
||||
(let ((proj (ede-target-parent this)))
|
||||
Argument THIS is the project to convert PATH to.
|
||||
Optional PROJECT is the project that THIS belongs to. Associating
|
||||
a target to a project is expensive, so using this can speed things up."
|
||||
(let ((proj (or project (ede-target-parent this))))
|
||||
(if proj
|
||||
(let ((p (ede-convert-path proj path))
|
||||
(lp (or (oref this path) "")))
|
||||
|
@ -406,7 +379,8 @@ FILENAME should be just a filename which occurs in a directory controlled
|
|||
by this project.
|
||||
Optional argument FORCE forces the default filename to be provided even if it
|
||||
doesn't exist.
|
||||
If FORCE equals 'newfile, then the cache is ignored."
|
||||
If FORCE equals 'newfile, then the cache is ignored and a new file in THIS
|
||||
is returned."
|
||||
(require 'ede/locate)
|
||||
(let* ((loc (ede-get-locator-object this))
|
||||
(ha (ede-locate-file-in-hash loc filename))
|
||||
|
@ -467,17 +441,8 @@ doesn't exist."
|
|||
(proj (oref this subproj))
|
||||
(found nil))
|
||||
;; find it Locally.
|
||||
(setq found
|
||||
(cond ((file-exists-p (expand-file-name filename path))
|
||||
(expand-file-name filename path))
|
||||
((file-exists-p (expand-file-name (concat "include/" filename) path))
|
||||
(expand-file-name (concat "include/" filename) path))
|
||||
(t
|
||||
(while (and (not found) proj)
|
||||
(setq found (when (car proj)
|
||||
(ede-expand-filename (car proj) filename))
|
||||
proj (cdr proj)))
|
||||
found)))
|
||||
(setq found (or (ede-expand-filename-local this filename)
|
||||
(ede-expand-filename-impl-via-subproj this filename)))
|
||||
;; Use an external locate tool.
|
||||
(when (not found)
|
||||
(require 'ede/locate)
|
||||
|
@ -485,6 +450,30 @@ doesn't exist."
|
|||
;; Return it
|
||||
found))
|
||||
|
||||
(defmethod ede-expand-filename-local ((this ede-project) filename)
|
||||
"Expand filename locally to project THIS with filesystem tests."
|
||||
(let ((path (ede-project-root-directory this)))
|
||||
(cond ((file-exists-p (expand-file-name filename path))
|
||||
(expand-file-name filename path))
|
||||
((file-exists-p (expand-file-name (concat "include/" filename) path))
|
||||
(expand-file-name (concat "include/" filename) path)))))
|
||||
|
||||
(defmethod ede-expand-filename-impl-via-subproj ((this ede-project) filename)
|
||||
"Return a fully qualified file name based on project THIS.
|
||||
FILENAME should be just a filename which occurs in a directory controlled
|
||||
by this project."
|
||||
(let ((proj (list (ede-toplevel this)))
|
||||
(found nil))
|
||||
;; find it Locally.
|
||||
(while (and (not found) proj)
|
||||
(let ((thisproj (car proj)))
|
||||
(setq proj (append (cdr proj) (oref thisproj subproj)))
|
||||
(setq found (when thisproj
|
||||
(ede-expand-filename-local thisproj filename)))
|
||||
))
|
||||
;; Return it
|
||||
found))
|
||||
|
||||
(defmethod ede-expand-filename ((this ede-target) filename &optional force)
|
||||
"Return a fully qualified file name based on target THIS.
|
||||
FILENAME should be a filename which occurs in a directory in which THIS works.
|
||||
|
|
442
lisp/cedet/ede/generic.el
Normal file
442
lisp/cedet/ede/generic.el
Normal file
|
@ -0,0 +1,442 @@
|
|||
;;; ede/generic.el --- Base Support for generic build systems
|
||||
|
||||
;; Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Eric M. Ludlam <eric@siege-engine.com>
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs 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 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs 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. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; There are a lot of build systems out there, and EDE can't support
|
||||
;; them all fully. The ede-generic.el system is the base for
|
||||
;; supporting alternate build systems in a simple way, automatically.
|
||||
;;
|
||||
;; The structure is for the ede-generic baseclass, which is augmented
|
||||
;; by simple sub-classes that can be created by users on an as needed
|
||||
;; basis. The generic system will have targets for many language
|
||||
;; types, and create the targets on an as needed basis. All
|
||||
;; sub-project types will recycle the same generic target types.
|
||||
;;
|
||||
;; The generic target types will only be implemented for languages
|
||||
;; where having EDE support actually matters, with a single MISC to
|
||||
;; represent anything else.
|
||||
;;
|
||||
;; TOO MANY PROJECTS DETECTED:
|
||||
;;
|
||||
;; If enabling ede-generic support starts identifying too many
|
||||
;; projects, drop a file called `.ede-ignore' into any directory where
|
||||
;; you do not want a project to be.
|
||||
;;
|
||||
;; Customization:
|
||||
;;
|
||||
;; Since these projects are all so increadibly generic, a user will
|
||||
;; need to configure some aspects of the project by hand. In order to
|
||||
;; enable this without configuring the project objects directly (which
|
||||
;; are auto-generated) a special ede-generic-confg object is defined to
|
||||
;; hold the basics. Generic projects will identify and use these
|
||||
;; config files.
|
||||
;;
|
||||
;; Adding support for new projects:
|
||||
;;
|
||||
;; To add support to EDE Generic for new project types is very quick.
|
||||
;; See the end of this file for examples such as CMake and SCons.
|
||||
;;
|
||||
;; Support consists of one class for your project, specifying the file
|
||||
;; name used by the project system you want to support. It also
|
||||
;; should implement th method `ede-generic-setup-configuration' to
|
||||
;; prepopulate the configurable portion of the generic project with
|
||||
;; build details.
|
||||
;;
|
||||
;; Lastly, call `ede-generic-new-autoloader' to setup your project so
|
||||
;; EDE can use it.
|
||||
;;
|
||||
;; Adding support for new types of source code:
|
||||
;;
|
||||
;; Sources of different types are supported with a simple class which
|
||||
;; subclasses `ede-generic-target'. The slots `shortname' and
|
||||
;; `extension' should be given new initial values.
|
||||
;;
|
||||
;; Optionally, any target method used by EDE can then be overriden.
|
||||
;; The ede-generic-target-c-cpp has some example methods setting up
|
||||
;; the pre-processor map and system include path.
|
||||
;;
|
||||
;; NOTE: It is not necessary to modify ede-generic.el to add any of
|
||||
;; the above described support features.
|
||||
|
||||
(require 'eieio-opt)
|
||||
(require 'ede)
|
||||
(require 'semantic/db)
|
||||
|
||||
;;; Code:
|
||||
;;
|
||||
;; Start with the configuration system
|
||||
(defclass ede-generic-config (eieio-persistent)
|
||||
((extension :initform ".ede")
|
||||
(file-header-line :initform ";; EDE Generic Project Configuration")
|
||||
(project :initform nil
|
||||
:documentation
|
||||
"The project this config is bound to.")
|
||||
;; Generic customizations
|
||||
(build-command :initarg :build-command
|
||||
:initform "make -k"
|
||||
:type string
|
||||
:custom string
|
||||
:group (default build)
|
||||
:documentation
|
||||
"Command used for building this project.")
|
||||
(debug-command :initarg :debug-command
|
||||
:initform "gdb "
|
||||
:type string
|
||||
:custom string
|
||||
:group (default build)
|
||||
:documentation
|
||||
"Command used for debugging this project.")
|
||||
;; C target customixations
|
||||
(c-include-path :initarg :c-include-path
|
||||
:initform nil
|
||||
:type list
|
||||
:custom (repeat (string :tag "Path"))
|
||||
:group c
|
||||
:documentation
|
||||
"The include path used by C/C++ projects.")
|
||||
(c-preprocessor-table :initarg :c-preprocessor-table
|
||||
:initform nil
|
||||
:type list
|
||||
:custom (repeat (cons (string :tag "Macro")
|
||||
(string :tag "Value")))
|
||||
:group c
|
||||
:documentation
|
||||
"Preprocessor Symbols for this project.")
|
||||
(c-preprocessor-files :initarg :c-preprocessor-files
|
||||
:initform nil
|
||||
:type list
|
||||
:custom (repeat (string :tag "Include File")))
|
||||
)
|
||||
"User Configuration object for a generic project.")
|
||||
|
||||
(defun ede-generic-load (dir &optional rootproj)
|
||||
"Return a Generic Project object if there is a match.
|
||||
Return nil if there isn't one.
|
||||
Argument DIR is the directory it is created for.
|
||||
ROOTPROJ is nil, since there is only one project."
|
||||
;; Doesn't already exist, so lets make one.
|
||||
(let* ((alobj ede-constructing)
|
||||
(this nil))
|
||||
(when (not alobj) (error "Cannot load generic project without the autoload instance"))
|
||||
|
||||
(setq this
|
||||
(funcall (oref alobj class-sym)
|
||||
(symbol-name (oref alobj class-sym))
|
||||
:name (file-name-nondirectory
|
||||
(directory-file-name dir))
|
||||
:version "1.0"
|
||||
:directory (file-name-as-directory dir)
|
||||
:file (expand-file-name (oref alobj :proj-file)) ))
|
||||
(ede-add-project-to-global-list this)
|
||||
))
|
||||
|
||||
;;; Base Classes for the system
|
||||
(defclass ede-generic-target (ede-target)
|
||||
((shortname :initform ""
|
||||
:type string
|
||||
:allocation :class
|
||||
:documentation
|
||||
"Something prepended to the target name.")
|
||||
(extension :initform ""
|
||||
:type string
|
||||
:allocation :class
|
||||
:documentation
|
||||
"Regular expression representing the extension used for this target.
|
||||
subclasses of this base target will override the default value.")
|
||||
)
|
||||
"Baseclass for all targets belonging to the generic ede system."
|
||||
:abstract t)
|
||||
|
||||
(defclass ede-generic-project (ede-project)
|
||||
((buildfile :initform ""
|
||||
:type string
|
||||
:allocation :class
|
||||
:documentation "The file name that identifies a project of this type.
|
||||
The class allocated value is replace by different sub classes.")
|
||||
(config :initform nil
|
||||
:type (or null ede-generic-config)
|
||||
:documentation
|
||||
"The configuration object for this project.")
|
||||
)
|
||||
"The baseclass for all generic EDE project types."
|
||||
:abstract t)
|
||||
|
||||
(defmethod initialize-instance ((this ede-generic-project)
|
||||
&rest fields)
|
||||
"Make sure the targets slot is bound."
|
||||
(call-next-method)
|
||||
(unless (slot-boundp this 'targets)
|
||||
(oset this :targets nil))
|
||||
)
|
||||
|
||||
(defmethod ede-generic-get-configuration ((proj ede-generic-project))
|
||||
"Return the configuration for the project PROJ."
|
||||
(let ((config (oref proj config)))
|
||||
(when (not config)
|
||||
(let ((fname (expand-file-name "EDEConfig.el"
|
||||
(oref proj :directory))))
|
||||
(if (file-exists-p fname)
|
||||
;; Load in the configuration
|
||||
(setq config (eieio-persistent-read fname))
|
||||
;; Create a new one.
|
||||
(setq config (ede-generic-config
|
||||
"Configuration"
|
||||
:file fname))
|
||||
;; Set initial values based on project.
|
||||
(ede-generic-setup-configuration proj config))
|
||||
;; Link things together.
|
||||
(oset proj config config)
|
||||
(oset config project proj)))
|
||||
config))
|
||||
|
||||
(defmethod ede-generic-setup-configuration ((proj ede-generic-project) config)
|
||||
"Default configuration setup method."
|
||||
nil)
|
||||
|
||||
(defmethod ede-commit-project ((proj ede-generic-project))
|
||||
"Commit any change to PROJ to its file."
|
||||
(let ((config (ede-generic-get-configuration proj)))
|
||||
(ede-commit config)))
|
||||
|
||||
;;; A list of different targets
|
||||
(defclass ede-generic-target-c-cpp (ede-generic-target)
|
||||
((shortname :initform "C/C++")
|
||||
(extension :initform "\\([ch]\\(pp\\|xx\\|\\+\\+\\)?\\|cc\\|hh\\|CC?\\)"))
|
||||
"EDE Generic Project target for C and C++ code.
|
||||
All directories need at least one target.")
|
||||
|
||||
(defclass ede-generic-target-el (ede-generic-target)
|
||||
((shortname :initform "ELisp")
|
||||
(extension :initform "el"))
|
||||
"EDE Generic Project target for Emacs Lisp code.
|
||||
All directories need at least one target.")
|
||||
|
||||
(defclass ede-generic-target-fortran (ede-generic-target)
|
||||
((shortname :initform "Fortran")
|
||||
(extension :initform "[fF]9[05]\\|[fF]\\|for"))
|
||||
"EDE Generic Project target for Fortran code.
|
||||
All directories need at least one target.")
|
||||
|
||||
(defclass ede-generic-target-texi (ede-generic-target)
|
||||
((shortname :initform "Texinfo")
|
||||
(extension :initform "texi"))
|
||||
"EDE Generic Project target for texinfo code.
|
||||
All directories need at least one target.")
|
||||
|
||||
;; MISC must always be last since it will always match the file.
|
||||
(defclass ede-generic-target-misc (ede-generic-target)
|
||||
((shortname :initform "Misc")
|
||||
(extension :initform ""))
|
||||
"EDE Generic Project target for Misc files.
|
||||
All directories need at least one target.")
|
||||
|
||||
;;; Automatic target aquisition.
|
||||
(defun ede-generic-find-matching-target (class dir targets)
|
||||
"Find a target that is a CLASS and is in DIR in the list of TARGETS."
|
||||
(let ((match nil))
|
||||
(dolist (T targets)
|
||||
(when (and (object-of-class-p T class)
|
||||
(string= (oref T :path) dir))
|
||||
(setq match T)
|
||||
))
|
||||
match))
|
||||
|
||||
(defmethod ede-find-target ((proj ede-generic-project) buffer)
|
||||
"Find an EDE target in PROJ for BUFFER.
|
||||
If one doesn't exist, create a new one for this directory."
|
||||
(let* ((ext (file-name-extension (buffer-file-name buffer)))
|
||||
(classes (eieio-build-class-alist 'ede-generic-target t))
|
||||
(cls nil)
|
||||
(targets (oref proj targets))
|
||||
(dir default-directory)
|
||||
(ans nil)
|
||||
)
|
||||
;; Pick a matching class type.
|
||||
(when ext
|
||||
(dolist (C classes)
|
||||
(let* ((classsym (intern (car C)))
|
||||
(extreg (oref classsym extension)))
|
||||
(when (and (not (string= extreg ""))
|
||||
(string-match (concat "^" extreg "$") ext))
|
||||
(setq cls classsym)))))
|
||||
(when (not cls) (setq cls 'ede-generic-target-misc))
|
||||
;; find a pre-existing matching target
|
||||
(setq ans (ede-generic-find-matching-target cls dir targets))
|
||||
;; Create a new instance if there wasn't one
|
||||
(when (not ans)
|
||||
(setq ans (make-instance
|
||||
cls
|
||||
:name (oref cls shortname)
|
||||
:path dir
|
||||
:source nil))
|
||||
(object-add-to-list proj :targets ans)
|
||||
)
|
||||
ans))
|
||||
|
||||
;;; C/C++ support
|
||||
(defmethod ede-preprocessor-map ((this ede-generic-target-c-cpp))
|
||||
"Get the pre-processor map for some generic C code."
|
||||
(let* ((proj (ede-target-parent this))
|
||||
(root (ede-project-root proj))
|
||||
(config (ede-generic-get-configuration proj))
|
||||
filemap
|
||||
)
|
||||
;; Preprocessor files
|
||||
(dolist (G (oref config :c-preprocessor-files))
|
||||
(let ((table (semanticdb-file-table-object
|
||||
(ede-expand-filename root G))))
|
||||
(when table
|
||||
(when (semanticdb-needs-refresh-p table)
|
||||
(semanticdb-refresh-table table))
|
||||
(setq filemap (append filemap (oref table lexical-table)))
|
||||
)))
|
||||
;; The core table
|
||||
(setq filemap (append filemap (oref config :c-preprocessor-table)))
|
||||
|
||||
filemap
|
||||
))
|
||||
|
||||
(defmethod ede-system-include-path ((this ede-generic-target-c-cpp))
|
||||
"Get the system include path used by project THIS."
|
||||
(let* ((proj (ede-target-parent this))
|
||||
(config (ede-generic-get-configuration proj)))
|
||||
(oref config c-include-path)))
|
||||
|
||||
;;; Customization
|
||||
;;
|
||||
(defmethod ede-customize ((proj ede-generic-project))
|
||||
"Customize the EDE project PROJ."
|
||||
(let ((config (ede-generic-get-configuration proj)))
|
||||
(eieio-customize-object config)))
|
||||
|
||||
(defmethod ede-customize ((target ede-generic-target))
|
||||
"Customize the EDE TARGET."
|
||||
;; Nothing unique for the targets, use the project.
|
||||
(ede-customize-project))
|
||||
|
||||
(defmethod eieio-done-customizing ((config ede-generic-config))
|
||||
"Called when EIEIO is done customizing the configuration object.
|
||||
We need to go back through the old buffers, and update them with
|
||||
the new configuration."
|
||||
(ede-commit config)
|
||||
;; Loop over all the open buffers, and re-apply.
|
||||
(ede-map-targets
|
||||
(oref config project)
|
||||
(lambda (target)
|
||||
(ede-map-target-buffers
|
||||
target
|
||||
(lambda (b)
|
||||
(with-current-buffer b
|
||||
(ede-apply-target-options)))))))
|
||||
|
||||
(defmethod ede-commit ((config ede-generic-config))
|
||||
"Commit all changes to the configuration to disk."
|
||||
(eieio-persistent-save config))
|
||||
|
||||
;;; Creating Derived Projects:
|
||||
;;
|
||||
;; Derived projects need an autoloader so that EDE can find the
|
||||
;; different projects on disk.
|
||||
(defun ede-generic-new-autoloader (internal-name external-name
|
||||
projectfile class)
|
||||
"Add a new EDE Autoload instance for identifying a generic project.
|
||||
INTERNAL-NAME is a long name that identifies thsi project type.
|
||||
EXTERNAL-NAME is a shorter human readable name to describe the project.
|
||||
PROJECTFILE is a file name that identifies a project of this type to EDE, such as
|
||||
a Makefile, or SConstruct file.
|
||||
CLASS is the EIEIO class that is used to track this project. It should subclass
|
||||
the class `ede-generic-project' project."
|
||||
(add-to-list 'ede-project-class-files
|
||||
(ede-project-autoload internal-name
|
||||
:name external-name
|
||||
:file 'ede-generic
|
||||
:proj-file projectfile
|
||||
:load-type 'ede-generic-load
|
||||
:class-sym class
|
||||
:new-p nil)
|
||||
;; Generics must go at the end, since more specific types
|
||||
;; can create Makefiles also.
|
||||
t))
|
||||
|
||||
;;;###autoload
|
||||
(defun ede-enable-generic-projects ()
|
||||
"Enable generic project loaders."
|
||||
(interactive)
|
||||
(ede-generic-new-autoloader "edeproject-makefile" "Make"
|
||||
"Makefile" 'ede-generic-makefile-project)
|
||||
(ede-generic-new-autoloader "edeproject-scons" "SCons"
|
||||
"SConstruct" 'ede-generic-scons-project)
|
||||
(ede-generic-new-autoloader "edeproject-cmake" "CMake"
|
||||
"CMakeLists" 'ede-generic-cmake-project)
|
||||
)
|
||||
|
||||
|
||||
;;; SPECIFIC TYPES OF GENERIC BUILDS
|
||||
;;
|
||||
|
||||
;;; MAKEFILE
|
||||
|
||||
(defclass ede-generic-makefile-project (ede-generic-project)
|
||||
((buildfile :initform "Makefile")
|
||||
)
|
||||
"Generic Project for makefiles.")
|
||||
|
||||
(defmethod ede-generic-setup-configuration ((proj ede-generic-makefile-project) config)
|
||||
"Setup a configuration for Make."
|
||||
(oset config build-command "make -k")
|
||||
(oset config debug-command "gdb ")
|
||||
)
|
||||
|
||||
|
||||
;;; SCONS
|
||||
(defclass ede-generic-scons-project (ede-generic-project)
|
||||
((buildfile :initform "SConstruct")
|
||||
)
|
||||
"Generic Project for scons.")
|
||||
|
||||
(defmethod ede-generic-setup-configuration ((proj ede-generic-scons-project) config)
|
||||
"Setup a configuration for SCONS."
|
||||
(oset config build-command "scons")
|
||||
(oset config debug-command "gdb ")
|
||||
)
|
||||
|
||||
|
||||
;;; CMAKE
|
||||
(defclass ede-generic-cmake-project (ede-generic-project)
|
||||
((buildfile :initform "CMakeLists")
|
||||
)
|
||||
"Generic Project for cmake.")
|
||||
|
||||
(defmethod ede-generic-setup-configuration ((proj ede-generic-cmake-project) config)
|
||||
"Setup a configuration for CMake."
|
||||
(oset config build-command "cmake")
|
||||
(oset config debug-command "gdb ")
|
||||
)
|
||||
|
||||
(provide 'ede/generic)
|
||||
|
||||
;; Local variables:
|
||||
;; generated-autoload-file: "loaddefs.el"
|
||||
;; generated-autoload-load-name: "ede/generic"
|
||||
;; End:
|
||||
|
||||
;;; ede/generic.el ends here
|
|
@ -112,6 +112,18 @@ ROOTPROJ is nil, since there is only one project."
|
|||
)
|
||||
)
|
||||
|
||||
;;;###autoload
|
||||
(add-to-list 'ede-project-class-files
|
||||
(ede-project-autoload "linux"
|
||||
:name "LINUX ROOT"
|
||||
:file 'ede-linux
|
||||
:proj-file "scripts/ver_linux"
|
||||
:proj-root 'ede-linux-project-root
|
||||
:load-type 'ede-linux-load
|
||||
:class-sym 'ede-linux-project
|
||||
:new-p nil)
|
||||
t)
|
||||
|
||||
(defclass ede-linux-target-c (ede-target)
|
||||
()
|
||||
"EDE Linux Project target for C code.
|
||||
|
@ -124,7 +136,7 @@ All directories need at least one target.")
|
|||
|
||||
(defmethod initialize-instance ((this ede-linux-project)
|
||||
&rest fields)
|
||||
"Make sure the :file is fully expanded."
|
||||
"Make sure the targets slot is bound."
|
||||
(call-next-method)
|
||||
(unless (slot-boundp this 'targets)
|
||||
(oset this :targets nil)))
|
||||
|
|
|
@ -121,7 +121,7 @@ based on `ede-locate-setup-options'."
|
|||
;; Basic setup.
|
||||
(call-next-method)
|
||||
;; Make sure we have a hash table.
|
||||
(oset loc hash (make-hash-table :test 'equal))
|
||||
(ede-locate-flush-hash loc)
|
||||
)
|
||||
|
||||
(defmethod ede-locate-ok-in-project :static ((loc ede-locate-base)
|
||||
|
@ -129,6 +129,10 @@ based on `ede-locate-setup-options'."
|
|||
"Is it ok to use this project type under ROOT."
|
||||
t)
|
||||
|
||||
(defmethod ede-locate-flush-hash ((loc ede-locate-base))
|
||||
"For LOC, flush hashtable and start from scratch."
|
||||
(oset loc hash (make-hash-table :test 'equal)))
|
||||
|
||||
(defmethod ede-locate-file-in-hash ((loc ede-locate-base)
|
||||
filestring)
|
||||
"For LOC, is the file FILESTRING in our hashtable?"
|
||||
|
@ -160,6 +164,13 @@ that created this EDE locate object."
|
|||
nil
|
||||
)
|
||||
|
||||
(defmethod ede-locate-create/update-root-database :STATIC
|
||||
((loc ede-locate-base) root)
|
||||
"Create or update the database for the current project.
|
||||
You cannot create projects for the baseclass."
|
||||
(error "Cannot create/update a database of type %S"
|
||||
(object-name loc)))
|
||||
|
||||
;;; LOCATE
|
||||
;;
|
||||
;; Using the standard unix "locate" command.
|
||||
|
@ -242,6 +253,11 @@ that created this EDE locate object."
|
|||
(let ((default-directory (oref loc root)))
|
||||
(cedet-gnu-global-expand-filename filesubstring)))
|
||||
|
||||
(defmethod ede-locate-create/update-root-database :STATIC
|
||||
((loc ede-locate-global) root)
|
||||
"Create or update the GNU Global database for the current project."
|
||||
(cedet-gnu-global-create/update-database root))
|
||||
|
||||
;;; IDUTILS
|
||||
;;
|
||||
(defclass ede-locate-idutils (ede-locate-base)
|
||||
|
@ -280,6 +296,11 @@ that created this EDE locate object."
|
|||
(let ((default-directory (oref loc root)))
|
||||
(cedet-idutils-expand-filename filesubstring)))
|
||||
|
||||
(defmethod ede-locate-create/update-root-database :STATIC
|
||||
((loc ede-locate-idutils) root)
|
||||
"Create or update the GNU Global database for the current project."
|
||||
(cedet-idutils-create/update-database root))
|
||||
|
||||
;;; CSCOPE
|
||||
;;
|
||||
(defclass ede-locate-cscope (ede-locate-base)
|
||||
|
@ -315,6 +336,11 @@ that created this EDE locate object."
|
|||
(let ((default-directory (oref loc root)))
|
||||
(cedet-cscope-expand-filename filesubstring)))
|
||||
|
||||
(defmethod ede-locate-create/update-root-database :STATIC
|
||||
((loc ede-locate-cscope) root)
|
||||
"Create or update the GNU Global database for the current project."
|
||||
(cedet-cscope-create/update-database root))
|
||||
|
||||
(provide 'ede/locate)
|
||||
|
||||
;; Local variables:
|
||||
|
|
|
@ -126,7 +126,11 @@ don't do it. A value of nil means to just do it.")
|
|||
|
||||
(while compilation-in-progress
|
||||
(accept-process-output)
|
||||
(sit-for 1))
|
||||
;; If sit for indicates that input is waiting, then
|
||||
;; read and discard whatever it is that is going on.
|
||||
(when (not (sit-for 1))
|
||||
(read-event nil nil .1)
|
||||
))
|
||||
|
||||
(with-current-buffer "*compilation*"
|
||||
(goto-char (point-max))
|
||||
|
|
|
@ -262,6 +262,18 @@ Execute BODY in a location where a value can be placed."
|
|||
(goto-char (point-max))))
|
||||
(put 'ede-pmake-insert-variable-shared 'lisp-indent-function 1)
|
||||
|
||||
(defmacro ede-pmake-insert-variable-once (varname &rest body)
|
||||
"Add VARNAME into the current Makefile if it doesn't exist.
|
||||
Execute BODY in a location where a value can be placed."
|
||||
`(let ((addcr t) (v ,varname))
|
||||
(unless (re-search-backward (concat "^" v "\\s-*=") nil t)
|
||||
(insert v "=")
|
||||
,@body
|
||||
(if addcr (insert "\n"))
|
||||
(goto-char (point-max)))
|
||||
))
|
||||
(put 'ede-pmake-insert-variable-once 'lisp-indent-function 1)
|
||||
|
||||
;;; SOURCE VARIABLE NAME CONSTRUCTION
|
||||
|
||||
(defsubst ede-pmake-varname (obj)
|
||||
|
@ -369,10 +381,14 @@ NOTE: Not yet in use! This is part of an SRecode conversion of
|
|||
conf-table))
|
||||
(let* ((top "")
|
||||
(tmp this))
|
||||
;; Use relative paths for subdirs.
|
||||
(while (ede-parent-project tmp)
|
||||
(setq tmp (ede-parent-project tmp)
|
||||
top (concat "../" top)))
|
||||
(insert "\ntop=" top))
|
||||
;; If this is the top, then use CURDIR.
|
||||
(if (and (not (oref this metasubproject)) (string= top ""))
|
||||
(insert "\ntop=\"$(CURDIR)\"/")
|
||||
(insert "\ntop=" top)))
|
||||
(insert "\nede_FILES=" (file-name-nondirectory (oref this file)) " "
|
||||
(file-name-nondirectory (ede-proj-dist-makefile this)) "\n"))
|
||||
|
||||
|
@ -425,14 +441,13 @@ sources variable."
|
|||
(link (ede-proj-linkers this))
|
||||
(name (ede-proj-makefile-target-name this))
|
||||
(src (oref this source)))
|
||||
(ede-proj-makefile-insert-object-variables (car comp) name src)
|
||||
(dolist (obj comp)
|
||||
(ede-compiler-only-once obj
|
||||
(ede-proj-makefile-insert-variables obj)))
|
||||
(ede-proj-makefile-insert-object-variables (car comp) name src)
|
||||
(while link
|
||||
(ede-linker-only-once (car link)
|
||||
(ede-proj-makefile-insert-variables (car link)))
|
||||
(setq link (cdr link)))))
|
||||
(dolist (linker link)
|
||||
(ede-linker-only-once linker
|
||||
(ede-proj-makefile-insert-variables linker)))))
|
||||
|
||||
(defmethod ede-proj-makefile-insert-automake-pre-variables
|
||||
((this ede-proj-target))
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
(defclass ede-proj-target-makefile-archive
|
||||
(ede-proj-target-makefile-objectcode)
|
||||
((availablelinkers :initform (ede-archive-linker)))
|
||||
((availablelinkers :initform '(ede-archive-linker)))
|
||||
"This target generates an object code archive.")
|
||||
|
||||
(defvar ede-archive-linker
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
;;; Code:
|
||||
(defclass ede-proj-target-aux (ede-proj-target)
|
||||
((sourcetype :initform (ede-aux-source)))
|
||||
((sourcetype :initform '(ede-aux-source)))
|
||||
"This target consists of aux files such as READMEs and COPYING.")
|
||||
|
||||
(defvar ede-aux-source
|
||||
|
|
|
@ -36,8 +36,8 @@
|
|||
((menu :initform nil)
|
||||
(keybindings :initform nil)
|
||||
(phony :initform t)
|
||||
(sourcetype :initform (ede-source-emacs))
|
||||
(availablecompilers :initform (ede-emacs-compiler ede-xemacs-compiler))
|
||||
(sourcetype :initform '(ede-source-emacs))
|
||||
(availablecompilers :initform '(ede-emacs-compiler ede-xemacs-compiler))
|
||||
(aux-packages :initarg :aux-packages
|
||||
:initform nil
|
||||
:type list
|
||||
|
@ -259,7 +259,7 @@ is found, such as a `-version' variable, or the standard header."
|
|||
;; Autoload generators
|
||||
;;
|
||||
(defclass ede-proj-target-elisp-autoloads (ede-proj-target-elisp)
|
||||
((availablecompilers :initform (ede-emacs-cedet-autogen-compiler))
|
||||
((availablecompilers :initform '(ede-emacs-cedet-autogen-compiler))
|
||||
(aux-packages :initform ("cedet-autogen"))
|
||||
(phony :initform t)
|
||||
(autoload-file :initarg :autoload-file
|
||||
|
|
|
@ -31,9 +31,9 @@
|
|||
(defclass ede-proj-target-makefile-info (ede-proj-target-makefile)
|
||||
((menu :initform nil)
|
||||
(keybindings :initform nil)
|
||||
(availablecompilers :initform (ede-makeinfo-compiler
|
||||
ede-texi2html-compiler))
|
||||
(sourcetype :initform (ede-makeinfo-source))
|
||||
(availablecompilers :initform '(ede-makeinfo-compiler
|
||||
ede-texi2html-compiler))
|
||||
(sourcetype :initform '(ede-makeinfo-source))
|
||||
(mainmenu :initarg :mainmenu
|
||||
:initform ""
|
||||
:type string
|
||||
|
|
|
@ -35,8 +35,8 @@
|
|||
|
||||
;; FIXME this isn't how you spell "miscellaneous". :(
|
||||
(defclass ede-proj-target-makefile-miscelaneous (ede-proj-target-makefile)
|
||||
((sourcetype :initform (ede-misc-source))
|
||||
(availablecompilers :initform (ede-misc-compile))
|
||||
((sourcetype :initform '(ede-misc-source))
|
||||
(availablecompilers :initform '(ede-misc-compile))
|
||||
(submakefile :initarg :submakefile
|
||||
:initform ""
|
||||
:type string
|
||||
|
|
|
@ -39,28 +39,32 @@
|
|||
(configuration-variables :initform ("debug" . (("CFLAGS" . "-g")
|
||||
("LDFLAGS" . "-g"))))
|
||||
;; @TODO - add an include path.
|
||||
(availablecompilers :initform (ede-gcc-compiler
|
||||
ede-g++-compiler
|
||||
ede-gfortran-compiler
|
||||
ede-gfortran-module-compiler
|
||||
;; More C and C++ compilers, plus
|
||||
;; fortran or pascal can be added here
|
||||
))
|
||||
(availablelinkers :initform (ede-g++-linker
|
||||
ede-cc-linker
|
||||
ede-gfortran-linker
|
||||
ede-ld-linker
|
||||
;; Add more linker thingies here.
|
||||
))
|
||||
(sourcetype :initform (ede-source-c
|
||||
ede-source-c++
|
||||
ede-source-f77
|
||||
ede-source-f90
|
||||
;; ede-source-other
|
||||
;; This object should take everything that
|
||||
;; gets compiled into objects like fortran
|
||||
;; and pascal.
|
||||
))
|
||||
(availablecompilers :initform '(ede-gcc-compiler
|
||||
ede-g++-compiler
|
||||
ede-gfortran-compiler
|
||||
ede-gfortran-module-compiler
|
||||
ede-lex-compiler
|
||||
ede-yacc-compiler
|
||||
;; More C and C++ compilers, plus
|
||||
;; fortran or pascal can be added here
|
||||
))
|
||||
(availablelinkers :initform '(ede-g++-linker
|
||||
ede-cc-linker
|
||||
ede-ld-linker
|
||||
ede-gfortran-linker
|
||||
;; Add more linker thingies here.
|
||||
))
|
||||
(sourcetype :initform '(ede-source-c
|
||||
ede-source-c++
|
||||
ede-source-f77
|
||||
ede-source-f90
|
||||
ede-source-lex
|
||||
ede-source-yacc
|
||||
;; ede-source-other
|
||||
;; This object should take everything that
|
||||
;; gets compiled into objects like fortran
|
||||
;; and pascal.
|
||||
))
|
||||
)
|
||||
"Abstract class for Makefile based object code generating targets.
|
||||
Belonging to this group assumes you could make a .o from an element source
|
||||
|
@ -115,15 +119,15 @@ file.")
|
|||
:name "cc"
|
||||
:sourcetype '(ede-source-c)
|
||||
:variables '(("C_LINK" . "$(CC) $(CFLAGS) $(LDFLAGS) -L."))
|
||||
:commands '("$(C_LINK) -o $@ $^")
|
||||
:commands '("$(C_LINK) -o $@ $^ $(LDDEPS)")
|
||||
:objectextention "")
|
||||
"Linker for C sourcecode.")
|
||||
|
||||
(defvar ede-source-c++
|
||||
(ede-sourcecode "ede-source-c++"
|
||||
:name "C++"
|
||||
:sourcepattern "\\.\\(cpp\\|cc\\|cxx\\)$"
|
||||
:auxsourcepattern "\\.\\(hpp\\|hh?\\|hxx\\)$"
|
||||
:sourcepattern "\\.\\(c\\(pp?\\|c\\|xx\\|++\\)\\|C\\\(PP\\)?\\)$"
|
||||
:auxsourcepattern "\\.\\(hpp?\\|hh?\\|hxx\\|H\\)$"
|
||||
:garbagepattern '("*.o" "*.obj" ".deps/*.P" ".lo"))
|
||||
"C++ source code definition.")
|
||||
|
||||
|
@ -158,11 +162,43 @@ file.")
|
|||
;; Only use this linker when c++ exists.
|
||||
:sourcetype '(ede-source-c++)
|
||||
:variables '(("CXX_LINK" . "$(CXX) $(CFLAGS) $(LDFLAGS) -L."))
|
||||
:commands '("$(CXX_LINK) -o $@ $^")
|
||||
:commands '("$(CXX_LINK) -o $@ $^ $(LDDEPS)")
|
||||
:autoconf '("AC_PROG_CXX")
|
||||
:objectextention "")
|
||||
"Linker needed for c++ programs.")
|
||||
|
||||
;;; LEX
|
||||
(defvar ede-source-lex
|
||||
(ede-sourcecode "ede-source-lex"
|
||||
:name "lex"
|
||||
:sourcepattern "\\.l\\(l\\|pp\\|++\\)")
|
||||
"Lex source code definition.
|
||||
No garbage pattern since it creates C or C++ code.")
|
||||
|
||||
(defvar ede-lex-compiler
|
||||
(ede-object-compiler
|
||||
"ede-lex-compiler"
|
||||
;; Can we support regular makefiles too??
|
||||
:autoconf '("AC_PROG_LEX")
|
||||
:sourcetype '(ede-source-lex))
|
||||
"Compiler used for Lexical source.")
|
||||
|
||||
;;; YACC
|
||||
(defvar ede-source-yacc
|
||||
(ede-sourcecode "ede-source-yacc"
|
||||
:name "yacc"
|
||||
:sourcepattern "\\.y\\(y\\|pp\\|++\\)")
|
||||
"Yacc source code definition.
|
||||
No garbage pattern since it creates C or C++ code.")
|
||||
|
||||
(defvar ede-yacc-compiler
|
||||
(ede-object-compiler
|
||||
"ede-yacc-compiler"
|
||||
;; Can we support regular makefiles too??
|
||||
:autoconf '("AC_PROG_YACC")
|
||||
:sourcetype '(ede-source-yacc))
|
||||
"Compiler used for yacc/bison grammar files source.")
|
||||
|
||||
;;; Fortran Compiler/Linker
|
||||
;;
|
||||
;; Contributed by David Engster
|
||||
|
@ -233,7 +269,7 @@ file.")
|
|||
:name "ld"
|
||||
:variables '(("LD" . "ld")
|
||||
("LD_LINK" . "$(LD) $(LDFLAGS) -L."))
|
||||
:commands '("$(LD_LINK) -o $@ $^")
|
||||
:commands '("$(LD_LINK) -o $@ $^ $(LDDEPS)")
|
||||
:objectextention "")
|
||||
"Linker needed for c++ programs.")
|
||||
|
||||
|
|
|
@ -34,14 +34,14 @@
|
|||
;;; Code:
|
||||
(defclass ede-proj-target-makefile-program
|
||||
(ede-proj-target-makefile-objectcode)
|
||||
((ldlibs :initarg :ldlibs
|
||||
:initform nil
|
||||
:type list
|
||||
:custom (repeat (string :tag "Library"))
|
||||
:documentation
|
||||
"Libraries, such as \"m\" or \"Xt\" which this program depends on.
|
||||
The linker flag \"-l\" is automatically prepended. Do not include a \"lib\"
|
||||
prefix, or a \".so\" suffix.
|
||||
((ldlibs-local :initarg :ldlibs-local
|
||||
:initform nil
|
||||
:type list
|
||||
:custom (repeat (string :tag "Local Library"))
|
||||
:documentation
|
||||
"Libraries that are part of this project.
|
||||
The full path to these libraries should be specified, such as:
|
||||
../lib/libMylib.la or ../ar/myArchive.a
|
||||
|
||||
Note: Currently only used for Automake projects."
|
||||
)
|
||||
|
@ -51,10 +51,21 @@ Note: Currently only used for Automake projects."
|
|||
:custom (repeat (string :tag "Link Flag"))
|
||||
:documentation
|
||||
"Additional flags to add when linking this target.
|
||||
Use ldlibs to add addition libraries. Use this to specify specific
|
||||
options to the linker.
|
||||
Use this to specify specific options to the linker.
|
||||
A Common use may be to add -L to specify in-project locations of libraries
|
||||
specified with ldlibs.")
|
||||
(ldlibs :initarg :ldlibs
|
||||
:initform nil
|
||||
:type list
|
||||
:custom (repeat (string :tag "Library"))
|
||||
:documentation
|
||||
"Libraries, such as \"m\" or \"Xt\" which this program depends on.
|
||||
The linker flag \"-l\" is automatically prepended. Do not include a \"lib\"
|
||||
prefix, or a \".so\" suffix.
|
||||
Use the 'ldflags' slot to specify where in-project libraries might be.
|
||||
|
||||
Note: Not currently used. This bug needs to be fixed.")
|
||||
Note: Currently only used for Automake projects."
|
||||
)
|
||||
)
|
||||
"This target is an executable program.")
|
||||
|
||||
|
@ -70,27 +81,24 @@ Note: Not currently used. This bug needs to be fixed.")
|
|||
"Insert bin_PROGRAMS variables needed by target THIS."
|
||||
(ede-pmake-insert-variable-shared
|
||||
(concat (ede-name this) "_LDADD")
|
||||
(mapc (lambda (c) (insert " -l" c)) (oref this ldlibs)))
|
||||
;; For other targets THIS depends on
|
||||
;;
|
||||
;; NOTE: FIX THIS
|
||||
;;
|
||||
;;(ede-pmake-insert-variable-shared
|
||||
;; (concat (ede-name this) "_DEPENDENCIES")
|
||||
;; (mapcar (lambda (d) (insert d)) (oref this FOOOOOOOO)))
|
||||
(mapc (lambda (l) (insert " " l)) (oref this ldlibs-local))
|
||||
(mapc (lambda (c) (insert " " c)) (oref this ldflags))
|
||||
(when (oref this ldlibs)
|
||||
(mapc (lambda (d) (insert " -l" d)) (oref this ldlibs)))
|
||||
)
|
||||
(call-next-method))
|
||||
|
||||
(defmethod ede-proj-makefile-insert-rules ((this ede-proj-target-makefile-program))
|
||||
"Insert rules needed by THIS target."
|
||||
(let ((ede-proj-compiler-object-linkflags
|
||||
(mapconcat 'identity (oref this ldflags) " ")))
|
||||
(defmethod ede-proj-makefile-insert-variables ((this ede-proj-target-makefile-program))
|
||||
"Insert variables needed by the compiler THIS."
|
||||
(call-next-method)
|
||||
(let ((lf (mapconcat 'identity (oref this ldflags) " ")))
|
||||
(with-slots (ldlibs) this
|
||||
(if ldlibs
|
||||
(setq ede-proj-compiler-object-linkflags
|
||||
(concat ede-proj-compiler-object-linkflags
|
||||
" -l"
|
||||
(mapconcat 'identity ldlibs " -l")))))
|
||||
(call-next-method)))
|
||||
(setq lf
|
||||
(concat lf " -l" (mapconcat 'identity ldlibs " -l")))))
|
||||
;; LDFLAGS as needed.
|
||||
(when (and lf (not (string= "" lf)))
|
||||
(ede-pmake-insert-variable-once "LDDEPS" (insert lf)))))
|
||||
|
||||
(defmethod project-debug-target ((obj ede-proj-target-makefile-program))
|
||||
"Debug a program target OBJ."
|
||||
|
|
|
@ -34,15 +34,15 @@
|
|||
;;; Code:
|
||||
(defclass ede-proj-target-makefile-shared-object
|
||||
(ede-proj-target-makefile-program)
|
||||
((availablecompilers :initform (ede-gcc-libtool-shared-compiler
|
||||
;;ede-gcc-shared-compiler
|
||||
ede-g++-libtool-shared-compiler
|
||||
;;ede-g++-shared-compiler
|
||||
))
|
||||
(availablelinkers :initform (ede-cc-linker-libtool
|
||||
ede-g++-linker-libtool
|
||||
;; Add more linker thingies here.
|
||||
))
|
||||
((availablecompilers :initform '(ede-gcc-libtool-shared-compiler
|
||||
;;ede-gcc-shared-compiler
|
||||
ede-g++-libtool-shared-compiler
|
||||
;;ede-g++-shared-compiler
|
||||
))
|
||||
(availablelinkers :initform '(ede-cc-linker-libtool
|
||||
ede-g++-linker-libtool
|
||||
;; Add more linker thingies here.
|
||||
))
|
||||
(ldflags :custom (repeat (string :tag "Libtool flag"))
|
||||
:documentation
|
||||
"Additional flags to add when linking this shared library.
|
||||
|
@ -124,7 +124,7 @@ Use ldlibs to add addition libraries.")
|
|||
:rules (list (ede-makefile-rule
|
||||
"c++-inference-rule-libtool"
|
||||
:target "%.o"
|
||||
:dependencies "%.c"
|
||||
:dependencies "%.cpp"
|
||||
:rules '("@echo '$(LTCOMPILE) -o $@ $<'; \\"
|
||||
"$(LTCOMPILE) -o $@ $<"
|
||||
)
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
;; rebuild. The targets provided in ede-proj can be augmented with
|
||||
;; additional target types inherited directly from `ede-proj-target'.
|
||||
|
||||
;; (eval-and-compile '(require 'ede))
|
||||
(require 'ede/proj-comp)
|
||||
(require 'ede/make)
|
||||
|
||||
|
@ -336,7 +335,9 @@ Argument TARGET is the project we are completing customization on."
|
|||
(or (string= (file-name-nondirectory (oref this file)) f)
|
||||
(string= (ede-proj-dist-makefile this) f)
|
||||
(string-match "Makefile\\(\\.\\(in\\|am\\)\\)?$" f)
|
||||
(string-match "config\\(ure\\.in\\|\\.stutus\\)?$" f)
|
||||
(string-match "config\\(ure\\.\\(in\\|ac\\)\\|\\.status\\)?$" f)
|
||||
(string-match "config.h\\(\\.in\\)?" f)
|
||||
(member f '("AUTHORS" "NEWS" "COPYING" "INSTALL" "README"))
|
||||
)))
|
||||
|
||||
(defmethod ede-buffer-mine ((this ede-proj-target) buffer)
|
||||
|
@ -398,11 +399,11 @@ Argument TARGET is the project we are completing customization on."
|
|||
:source nil)))
|
||||
|
||||
(defmethod project-delete-target ((this ede-proj-target))
|
||||
"Delete the current target THIS from it's parent project."
|
||||
"Delete the current target THIS from its parent project."
|
||||
(let ((p (ede-current-project))
|
||||
(ts (oref this source)))
|
||||
;; Loop across all sources. If it exists in a buffer,
|
||||
;; clear it's object.
|
||||
;; clear its object.
|
||||
(while ts
|
||||
(let* ((default-directory (oref this path))
|
||||
(b (get-file-buffer (car ts))))
|
||||
|
@ -413,7 +414,7 @@ Argument TARGET is the project we are completing customization on."
|
|||
(setq ede-object nil)
|
||||
(ede-apply-object-keymap))))))
|
||||
(setq ts (cdr ts)))
|
||||
;; Remove THIS from it's parent.
|
||||
;; Remove THIS from its parent.
|
||||
;; The two vectors should be pointer equivalent.
|
||||
(oset p targets (delq this (oref p targets)))
|
||||
(ede-proj-save (ede-current-project))))
|
||||
|
@ -447,15 +448,13 @@ FILE must be massaged by `ede-convert-path'."
|
|||
|
||||
(defmethod project-make-dist ((this ede-proj-project))
|
||||
"Build a distribution for the project based on THIS target."
|
||||
;; I'm a lazy bum, so I'll make a makefile for doing this sort
|
||||
;; of thing, and rely only on that small section of code.
|
||||
(let ((pm (ede-proj-dist-makefile this))
|
||||
(df (project-dist-files this)))
|
||||
(if (and (file-exists-p (car df))
|
||||
(not (y-or-n-p "Dist file already exists. Rebuild? ")))
|
||||
(error "Try `ede-update-version' before making a distribution"))
|
||||
(ede-proj-setup-buildenvironment this)
|
||||
(if (string= (file-name-nondirectory pm) "Makefile.am")
|
||||
(if (ede-proj-automake-p this)
|
||||
(setq pm (expand-file-name "Makefile"
|
||||
(file-name-directory pm))))
|
||||
(compile (concat ede-make-command " -f " pm " dist"))))
|
||||
|
@ -473,7 +472,7 @@ Argument COMMAND is the command to use when compiling."
|
|||
(let ((pm (ede-proj-dist-makefile proj))
|
||||
(default-directory (file-name-directory (oref proj file))))
|
||||
(ede-proj-setup-buildenvironment proj)
|
||||
(if (string= (file-name-nondirectory pm) "Makefile.am")
|
||||
(if (ede-proj-automake-p proj)
|
||||
(setq pm (expand-file-name "Makefile"
|
||||
(file-name-directory pm))))
|
||||
(compile (concat ede-make-command" -f " pm " all"))))
|
||||
|
@ -539,7 +538,15 @@ Converts all symbols into the objects to be used."
|
|||
(if (ede-want-any-source-files-p (symbol-value (car st)) sources)
|
||||
(let ((c (ede-proj-find-compiler avail (car st))))
|
||||
(if c (setq comp (cons c comp)))))
|
||||
(setq st (cdr st)))))
|
||||
(setq st (cdr st)))
|
||||
;; Provide a good error msg.
|
||||
(unless comp
|
||||
(error "Could not find compiler match for source code extension \"%s\".
|
||||
You may need to add support for this type of file."
|
||||
(if sources
|
||||
(file-name-extension (car sources))
|
||||
"")))
|
||||
))
|
||||
;; Return the disovered compilers
|
||||
comp)))
|
||||
|
||||
|
@ -664,18 +671,9 @@ Optional argument FORCE will force items to be regenerated."
|
|||
(let ((root (or (ede-project-root this) this))
|
||||
)
|
||||
(setq ede-projects (delq root ede-projects))
|
||||
(ede-proj-load (ede-project-root-directory root))
|
||||
(ede-load-project-file (ede-project-root-directory root))
|
||||
))
|
||||
|
||||
(defmethod project-rescan ((this ede-proj-target) readstream)
|
||||
"Rescan target THIS from the read list READSTREAM."
|
||||
(setq readstream (cdr (cdr readstream))) ;; constructor/name
|
||||
(while readstream
|
||||
(let ((tag (car readstream))
|
||||
(val (car (cdr readstream))))
|
||||
(eieio-oset this tag val))
|
||||
(setq readstream (cdr (cdr readstream)))))
|
||||
|
||||
(provide 'ede/proj)
|
||||
|
||||
;; arch-tag: eb8a40f8-0d2c-41c4-b273-af04101d1cdf
|
||||
|
|
|
@ -30,27 +30,19 @@
|
|||
;; fashion.
|
||||
;;
|
||||
;; project-am uses the structure defined in all good GNU projects with
|
||||
;; the Automake file as it's base template, and then maintains that
|
||||
;; the Automake file as its base template, and then maintains that
|
||||
;; information during edits, automatically updating the automake file
|
||||
;; where appropriate.
|
||||
|
||||
|
||||
;; (eval-and-compile
|
||||
;; ;; Compatibility for makefile mode.
|
||||
;; (condition-case nil
|
||||
;; (require 'makefile "make-mode")
|
||||
;; (error (require 'make-mode "make-mode")))
|
||||
|
||||
;; ;; Requiring the .el files prevents incomplete builds.
|
||||
;; (require 'eieio "eieio.el")
|
||||
;; (require 'ede "ede.el"))
|
||||
|
||||
(require 'make-mode)
|
||||
(require 'ede)
|
||||
(require 'ede/make)
|
||||
(require 'ede/makefile-edit)
|
||||
(require 'semantic/find) ;; for semantic-find-tags-by-...
|
||||
(require 'ede/autoconf-edit)
|
||||
|
||||
(declare-function autoconf-parameters-for-macro "ede/autoconf-edit")
|
||||
(declare-function ede-shell-run-something "ede/shell")
|
||||
(eval-when-compile (require 'compile))
|
||||
|
||||
;;; Code:
|
||||
|
@ -104,7 +96,7 @@
|
|||
;; ("ltlibcustom" project-am-lib ".*?_LTLIBRARIES" t)
|
||||
)
|
||||
"Alist of type names and the type of object to create for them.
|
||||
Each entry is of th form:
|
||||
Each entry is of the form:
|
||||
(EMACSNAME CLASS AUTOMAKEVAR INDIRECT)
|
||||
where EMACSNAME is a name for Emacs to use.
|
||||
CLASS is the EDE target class to represent the target.
|
||||
|
@ -113,6 +105,23 @@ AUTOMAKEVAR is the Automake variable to identify. This cannot be a
|
|||
INDIRECT is optional. If it is non-nil, then the variable in
|
||||
question lists other variables that need to be looked up.")
|
||||
|
||||
|
||||
(defconst project-am-meta-type-alist
|
||||
'((project-am-program "_PROGRAMS$" t)
|
||||
(project-am-lib "_\\(LIBS\\|LIBRARIES\\|LTLIBRARIES\\)$" t)
|
||||
|
||||
;; direct primary target use a dummy object (man target)
|
||||
;; update to: * 3.3 Uniform in automake-1.11 info node.
|
||||
(project-am-man "_\\(DATA\\|HEADERS\\|PYTHON\\|JAVA\\|SCRIPTS\\|MANS\\|TEXINFOS\\)$" nil)
|
||||
)
|
||||
"Alist of meta-target type, each entry has form:
|
||||
(CLASS REGEXPVAR INDIRECT)
|
||||
where CLASS is the EDE target class for target.
|
||||
REGEXPVAR is the regexp used in `semantic-find-tags-by-name-regexp'.
|
||||
INDIRECT is optional. If it is non-nil, then the variable in it have
|
||||
other meta-variable based on this name.")
|
||||
|
||||
|
||||
(defclass project-am-target (ede-target)
|
||||
nil
|
||||
"Base target class for everything in project-am.")
|
||||
|
@ -291,16 +300,6 @@ buffer being in order to provide a smart default target type."
|
|||
;; Rescan the object in this makefile.
|
||||
(project-rescan ede-object))))
|
||||
|
||||
;(defun project-am-rescan-toplevel ()
|
||||
; "Rescan all projects in which the current buffer resides."
|
||||
; (interactive)
|
||||
; (let* ((tlof (project-am-find-topmost-level default-directory))
|
||||
; (tlo (project-am-load tlof))
|
||||
; (ede-deep-rescan t)) ; scan deep in this case.
|
||||
; ;; tlo is the top level object for whatever file we are in
|
||||
; ;; or nil. If we have an object, call the rescan method.
|
||||
; (if tlo (project-am-rescan tlo))))
|
||||
|
||||
;;
|
||||
;; NOTE TO SELF
|
||||
;;
|
||||
|
@ -406,6 +405,7 @@ Argument COMMAND is the command to use for compiling the target."
|
|||
|
||||
(defmethod project-run-target ((obj project-am-objectcode))
|
||||
"Run the current project target in comint buffer."
|
||||
(require 'ede/shell)
|
||||
(let ((tb (get-buffer-create " *padt*"))
|
||||
(dd (oref obj path))
|
||||
(cmd nil))
|
||||
|
@ -429,45 +429,17 @@ Argument COMMAND is the command to use for compiling the target."
|
|||
|
||||
;;; Project loading and saving
|
||||
;;
|
||||
(defun project-am-load (project &optional rootproj)
|
||||
"Read an automakefile PROJECT into our data structure.
|
||||
Make sure that the tree down to our makefile is complete so that there
|
||||
is cohesion in the project. Return the project file (or sub-project).
|
||||
(defun project-am-load (directory &optional rootproj)
|
||||
"Read an automakefile DIRECTORY into our data structure.
|
||||
If a given set of projects has already been loaded, then do nothing
|
||||
but return the project for the directory given.
|
||||
Optional ROOTPROJ is the root EDE project."
|
||||
;; @TODO - rationalize this to the newer EDE way of doing things.
|
||||
(setq project (expand-file-name project))
|
||||
(let* ((ede-constructing t)
|
||||
(fn (project-am-find-topmost-level (file-name-as-directory project)))
|
||||
(amo nil)
|
||||
(trimmed (if (string-match (regexp-quote fn)
|
||||
project)
|
||||
(replace-match "" t t project)
|
||||
""))
|
||||
(subdir nil))
|
||||
(setq amo (object-assoc (expand-file-name "Makefile.am" fn)
|
||||
'file ede-projects))
|
||||
(if amo
|
||||
(error "Synchronous error in ede/project-am objects")
|
||||
(let ((project-am-constructing t))
|
||||
(setq amo (project-am-load-makefile fn))))
|
||||
(if (not amo)
|
||||
nil
|
||||
;; Now scan down from amo, and find the current directory
|
||||
;; from the PROJECT file.
|
||||
(while (< 0 (length trimmed))
|
||||
(if (string-match "\\([a-zA-Z0-9.-]+\\)/" trimmed)
|
||||
(setq subdir (match-string 0 trimmed)
|
||||
trimmed (replace-match "" t t trimmed))
|
||||
(error "Error scanning down path for project"))
|
||||
(setq amo (project-am-subtree
|
||||
amo
|
||||
(expand-file-name "Makefile.am"
|
||||
(expand-file-name subdir fn)))
|
||||
fn (expand-file-name subdir fn)))
|
||||
amo)
|
||||
))
|
||||
(let* ((ede-constructiong t)
|
||||
(amo (object-assoc (expand-file-name "Makefile.am" directory)
|
||||
'file ede-projects)))
|
||||
(when (not amo)
|
||||
(setq amo (project-am-load-makefile directory)))
|
||||
amo))
|
||||
|
||||
(defun project-am-find-topmost-level (dir)
|
||||
"Find the topmost automakefile starting with DIR."
|
||||
|
@ -488,17 +460,19 @@ Kill the makefile if it was not loaded before the load."
|
|||
(fb nil)
|
||||
(kb (get-file-buffer fn)))
|
||||
(if (not (file-exists-p fn))
|
||||
nil
|
||||
(save-excursion
|
||||
(if kb (setq fb kb)
|
||||
;; We need to find-file this thing, but don't use
|
||||
;; any semantic features.
|
||||
(let ((semantic-init-hook nil))
|
||||
(setq fb (find-file-noselect fn)))
|
||||
)
|
||||
(set-buffer fb)
|
||||
(prog1 ,@forms
|
||||
(if (not kb) (kill-buffer (current-buffer))))))))
|
||||
nil
|
||||
(save-excursion
|
||||
(if kb (setq fb kb)
|
||||
;; We need to find-file this thing, but don't use
|
||||
;; any semantic features.
|
||||
(let ((semantic-init-hook nil)
|
||||
(recentf-exclude '( (lambda (f) t) ))
|
||||
)
|
||||
(setq fb (find-file-noselect fn)))
|
||||
)
|
||||
(set-buffer fb)
|
||||
(prog1 ,@forms
|
||||
(if (not kb) (kill-buffer (current-buffer))))))))
|
||||
(put 'project-am-with-makefile-current 'lisp-indent-function 1)
|
||||
|
||||
(add-hook 'edebug-setup-hook
|
||||
|
@ -507,14 +481,18 @@ Kill the makefile if it was not loaded before the load."
|
|||
(form def-body))))
|
||||
|
||||
|
||||
(defun project-am-load-makefile (path)
|
||||
(defun project-am-load-makefile (path &optional suggestedname)
|
||||
"Convert PATH into a project Makefile, and return its project object.
|
||||
It does not check for existing project objects. Use `project-am-load'."
|
||||
It does not check for existing project objects. Use `project-am-load'.
|
||||
Optional argument SUGGESTEDNAME will be the project name.
|
||||
This is used when subprojects are made in named subdirectories."
|
||||
(project-am-with-makefile-current path
|
||||
(if (and ede-object (project-am-makefile-p ede-object))
|
||||
ede-object
|
||||
(let* ((pi (project-am-package-info path))
|
||||
(pn (or (nth 0 pi) (project-am-last-dir fn)))
|
||||
(sfn (when suggestedname
|
||||
(project-am-last-dir suggestedname)))
|
||||
(pn (or sfn (nth 0 pi) (project-am-last-dir fn)))
|
||||
(ver (or (nth 1 pi) "0.0"))
|
||||
(bug (nth 2 pi))
|
||||
(cof (nth 3 pi))
|
||||
|
@ -532,21 +510,6 @@ It does not check for existing project objects. Use `project-am-load'."
|
|||
ampf))))
|
||||
|
||||
;;; Methods:
|
||||
(defmethod ede-find-target ((amf project-am-makefile) buffer)
|
||||
"Fetch the target belonging to BUFFER."
|
||||
(or (call-next-method)
|
||||
(let ((targ (oref amf targets))
|
||||
(sobj (oref amf subproj))
|
||||
(obj nil))
|
||||
(while (and targ (not obj))
|
||||
(if (ede-buffer-mine (car targ) buffer)
|
||||
(setq obj (car targ)))
|
||||
(setq targ (cdr targ)))
|
||||
(while (and sobj (not obj))
|
||||
(setq obj (project-am-buffer-object (car sobj) buffer)
|
||||
sobj (cdr sobj)))
|
||||
obj)))
|
||||
|
||||
(defmethod project-targets-for-file ((proj project-am-makefile))
|
||||
"Return a list of targets the project PROJ."
|
||||
(oref proj targets))
|
||||
|
@ -556,44 +519,110 @@ It does not check for existing project objects. Use `project-am-load'."
|
|||
CURRPROJ is the current project being scanned.
|
||||
DIR is the directory to apply to new targets."
|
||||
(let* ((otargets (oref currproj targets))
|
||||
;; `ntargets' results in complete targets list
|
||||
;; not only the new targets by diffing.
|
||||
(ntargets nil)
|
||||
(tmp nil)
|
||||
)
|
||||
(mapc
|
||||
;; Map all the different types
|
||||
(lambda (typecar)
|
||||
(let ((macro (nth 2 typecar))
|
||||
(class (nth 1 typecar))
|
||||
(indirect (nth 3 typecar))
|
||||
;(name (car typecar))
|
||||
)
|
||||
(if indirect
|
||||
;; Map all the found objects
|
||||
(mapc (lambda (lstcar)
|
||||
(setq tmp (object-assoc lstcar 'name otargets))
|
||||
(when (not tmp)
|
||||
(setq tmp (apply class lstcar :name lstcar
|
||||
:path dir nil)))
|
||||
(project-rescan tmp)
|
||||
(setq ntargets (cons tmp ntargets)))
|
||||
(makefile-macro-file-list macro))
|
||||
;; Non-indirect will have a target whos sources
|
||||
;; are actual files, not names of other targets.
|
||||
(let ((files (makefile-macro-file-list macro)))
|
||||
(when files
|
||||
(setq tmp (object-assoc macro 'name otargets))
|
||||
(when (not tmp)
|
||||
(setq tmp (apply class macro :name macro
|
||||
:path dir nil)))
|
||||
(project-rescan tmp)
|
||||
(setq ntargets (cons tmp ntargets))
|
||||
))
|
||||
)
|
||||
))
|
||||
project-am-type-alist)
|
||||
ntargets))
|
||||
|
||||
(defmethod project-rescan ((this project-am-makefile))
|
||||
(mapc
|
||||
;; Map all the different types
|
||||
(lambda (typecar)
|
||||
(let ((macro (nth 2 typecar))
|
||||
(class (nth 1 typecar))
|
||||
(indirect (nth 3 typecar))
|
||||
)
|
||||
(if indirect
|
||||
;; Map all the found objects
|
||||
(mapc (lambda (lstcar)
|
||||
(setq tmp (object-assoc lstcar 'name otargets))
|
||||
(when (not tmp)
|
||||
(setq tmp (apply class lstcar :name lstcar
|
||||
:path dir nil)))
|
||||
(project-rescan tmp)
|
||||
(setq ntargets (cons tmp ntargets)))
|
||||
(makefile-macro-file-list macro))
|
||||
;; Non-indirect will have a target whos sources
|
||||
;; are actual files, not names of other targets.
|
||||
(let ((files (makefile-macro-file-list macro)))
|
||||
(when files
|
||||
(setq tmp (object-assoc macro 'name otargets))
|
||||
(when (not tmp)
|
||||
(setq tmp (apply class macro :name macro
|
||||
:path dir nil)))
|
||||
(project-rescan tmp)
|
||||
(setq ntargets (cons tmp ntargets))
|
||||
))
|
||||
)
|
||||
))
|
||||
project-am-type-alist)
|
||||
|
||||
;; At now check variables for meta-target regexp
|
||||
;; We have to check ntargets to avoid useless rescan.
|
||||
;; Also we have check otargets to prevent duplication.
|
||||
(mapc
|
||||
(lambda (typecar)
|
||||
(let ((class (nth 0 typecar))
|
||||
(metaregex (nth 1 typecar))
|
||||
(indirect (nth 2 typecar)))
|
||||
(if indirect
|
||||
;; Map all the found objects
|
||||
(mapc
|
||||
(lambda (lstcar)
|
||||
(unless (object-assoc lstcar 'name ntargets)
|
||||
(or
|
||||
(setq tmp (object-assoc lstcar 'name otargets))
|
||||
(setq tmp (apply class lstcar :name lstcar
|
||||
:path dir nil)))
|
||||
(project-rescan tmp)
|
||||
(setq ntargets (cons tmp ntargets))))
|
||||
;; build a target list to map over
|
||||
(let (atargets)
|
||||
(dolist (TAG
|
||||
(semantic-find-tags-by-name-regexp
|
||||
metaregex (semantic-find-tags-by-class
|
||||
'variable (semantic-fetch-tags))))
|
||||
;; default-value have to be a list
|
||||
(when (cadr (assoc ':default-value TAG))
|
||||
(setq atargets
|
||||
(append
|
||||
(nreverse (cadr (assoc ':default-value TAG)))
|
||||
atargets))))
|
||||
(nreverse atargets)))
|
||||
|
||||
;; else not indirect, TODO: FIX various direct meta type in a sane way.
|
||||
(dolist (T (semantic-find-tags-by-name-regexp
|
||||
metaregex (semantic-find-tags-by-class
|
||||
'variable (semantic-fetch-tags))))
|
||||
(unless (setq tmp (object-assoc (car T) 'name ntargets))
|
||||
(or (setq tmp (object-assoc (car T) 'name otargets))
|
||||
;; we are really new
|
||||
(setq tmp (apply class (car T) :name (car T)
|
||||
:path dir nil)))
|
||||
(project-rescan tmp)
|
||||
(setq ntargets (cons tmp ntargets))))
|
||||
)))
|
||||
project-am-meta-type-alist)
|
||||
ntargets))
|
||||
|
||||
(defun project-am-expand-subdirlist (place subdirs)
|
||||
"Store in PLACE the SUBDIRS expanded from variables.
|
||||
Strip out duplicates, and recurse on variables."
|
||||
(mapc (lambda (sp)
|
||||
(let ((var (makefile-extract-varname-from-text sp)))
|
||||
(if var
|
||||
;; If it is a variable, expand that variable, and keep going.
|
||||
(project-am-expand-subdirlist
|
||||
place (makefile-macro-file-list var))
|
||||
;; Else, add SP in if it isn't a dup.
|
||||
(if (member sp (symbol-value place))
|
||||
nil ; don't do it twice.
|
||||
(set place (cons sp (symbol-value place))) ;; add
|
||||
))))
|
||||
subdirs)
|
||||
)
|
||||
|
||||
(defmethod project-rescan ((this project-am-makefile) &optional suggestedname)
|
||||
"Rescan the makefile for all targets and sub targets."
|
||||
(project-am-with-makefile-current (file-name-directory (oref this file))
|
||||
;;(message "Scanning %s..." (oref this file))
|
||||
|
@ -603,10 +632,10 @@ DIR is the directory to apply to new targets."
|
|||
(bug (nth 2 pi))
|
||||
(cof (nth 3 pi))
|
||||
(osubproj (oref this subproj))
|
||||
(csubproj (or
|
||||
;; If DIST_SUBDIRS doesn't exist, then go for the
|
||||
;; static list of SUBDIRS. The DIST version should
|
||||
;; contain SUBDIRS plus extra stuff.
|
||||
;; 1/30/10 - We need to append these two lists together,
|
||||
;; then strip out duplicates. Expanding this list (via
|
||||
;; references to other variables should also strip out dups
|
||||
(csubproj (append
|
||||
(makefile-macro-file-list "DIST_SUBDIRS")
|
||||
(makefile-macro-file-list "SUBDIRS")))
|
||||
(csubprojexpanded nil)
|
||||
|
@ -617,79 +646,57 @@ DIR is the directory to apply to new targets."
|
|||
(tmp nil)
|
||||
(ntargets (project-am-scan-for-targets this dir))
|
||||
)
|
||||
|
||||
(and pn (string= (directory-file-name
|
||||
(oref this directory))
|
||||
(directory-file-name
|
||||
(project-am-find-topmost-level
|
||||
(oref this directory))))
|
||||
(oset this name pn)
|
||||
(and pv (oset this version pv))
|
||||
(and bug (oset this mailinglist bug))
|
||||
(oset this configureoutputfiles cof))
|
||||
|
||||
; ;; LISP is different. Here there is only one kind of lisp (that I know of
|
||||
; ;; anyway) so it doesn't get mapped when it is found.
|
||||
; (if (makefile-move-to-macro "lisp_LISP")
|
||||
; (let ((tmp (project-am-lisp "lisp"
|
||||
; :name "lisp"
|
||||
; :path dir)))
|
||||
; (project-rescan tmp)
|
||||
; (setq ntargets (cons tmp ntargets))))
|
||||
;
|
||||
(if suggestedname
|
||||
(oset this name (project-am-last-dir suggestedname))
|
||||
;; Else, setup toplevel project info.
|
||||
(and pn (string= (directory-file-name
|
||||
(oref this directory))
|
||||
(directory-file-name
|
||||
(project-am-find-topmost-level
|
||||
(oref this directory))))
|
||||
(oset this name pn)
|
||||
(and pv (oset this version pv))
|
||||
(and bug (oset this mailinglist bug))
|
||||
(oset this configureoutputfiles cof)))
|
||||
;; Now that we have this new list, chuck the old targets
|
||||
;; and replace it with the new list of targets I just created.
|
||||
(oset this targets (nreverse ntargets))
|
||||
;; We still have a list of targets. For all buffers, make sure
|
||||
;; their object still exists!
|
||||
|
||||
;; FIGURE THIS OUT
|
||||
|
||||
(mapc (lambda (sp)
|
||||
(let ((var (makefile-extract-varname-from-text sp))
|
||||
)
|
||||
(if (not var)
|
||||
(setq csubprojexpanded (cons sp csubprojexpanded))
|
||||
;; If it is a variable, expand that variable, and keep going.
|
||||
(let ((varexp (makefile-macro-file-list var)))
|
||||
(dolist (V varexp)
|
||||
(setq csubprojexpanded (cons V csubprojexpanded)))))
|
||||
))
|
||||
csubproj)
|
||||
|
||||
(project-am-expand-subdirlist 'csubprojexpanded csubproj)
|
||||
;; Ok, now lets look at all our sub-projects.
|
||||
(mapc (lambda (sp)
|
||||
(let* ((subdir (file-name-as-directory
|
||||
(expand-file-name
|
||||
sp (file-name-directory (oref this :file)))))
|
||||
(submake (expand-file-name
|
||||
"Makefile.am"
|
||||
subdir)))
|
||||
(if (string= submake (oref this :file))
|
||||
nil ;; don't recurse.. please!
|
||||
|
||||
;; For each project id found, see if we need to recycle,
|
||||
;; and if we do not, then make a new one. Check the deep
|
||||
;; rescan value for behavior patterns.
|
||||
(setq tmp (object-assoc
|
||||
submake
|
||||
'file osubproj))
|
||||
(if (not tmp)
|
||||
(setq tmp
|
||||
(condition-case nil
|
||||
;; In case of problem, ignore it.
|
||||
(project-am-load-makefile subdir)
|
||||
(error nil)))
|
||||
;; If we have tmp, then rescan it only if deep mode.
|
||||
(if ede-deep-rescan
|
||||
(project-rescan tmp)))
|
||||
;; Tac tmp onto our list of things to keep, but only
|
||||
;; if tmp was found.
|
||||
(when tmp
|
||||
;;(message "Adding %S" (object-print tmp))
|
||||
(setq nsubproj (cons tmp nsubproj)))))
|
||||
)
|
||||
(nreverse csubprojexpanded))
|
||||
(let* ((subdir (file-name-as-directory
|
||||
(expand-file-name
|
||||
sp (file-name-directory (oref this :file)))))
|
||||
(submake (expand-file-name
|
||||
"Makefile.am"
|
||||
subdir)))
|
||||
(if (string= submake (oref this :file))
|
||||
nil ;; don't recurse.. please!
|
||||
;; For each project id found, see if we need to recycle,
|
||||
;; and if we do not, then make a new one. Check the deep
|
||||
;; rescan value for behavior patterns.
|
||||
(setq tmp (object-assoc
|
||||
submake
|
||||
'file osubproj))
|
||||
(if (not tmp)
|
||||
(setq tmp
|
||||
(condition-case nil
|
||||
;; In case of problem, ignore it.
|
||||
(project-am-load-makefile subdir subdir)
|
||||
(error nil)))
|
||||
;; If we have tmp, then rescan it only if deep mode.
|
||||
(if ede-deep-rescan
|
||||
(project-rescan tmp subdir)))
|
||||
;; Tac tmp onto our list of things to keep, but only
|
||||
;; if tmp was found.
|
||||
(when tmp
|
||||
;;(message "Adding %S" (object-print tmp))
|
||||
(setq nsubproj (cons tmp nsubproj)))))
|
||||
)
|
||||
(nreverse csubprojexpanded))
|
||||
(oset this subproj nsubproj)
|
||||
;; All elements should be updated now.
|
||||
)))
|
||||
|
@ -698,12 +705,16 @@ DIR is the directory to apply to new targets."
|
|||
(defmethod project-rescan ((this project-am-program))
|
||||
"Rescan object THIS."
|
||||
(oset this :source (makefile-macro-file-list (project-am-macro this)))
|
||||
(unless (oref this :source)
|
||||
(oset this :source (list (concat (oref this :name) ".c"))))
|
||||
(oset this :ldadd (makefile-macro-file-list
|
||||
(concat (oref this :name) "_LDADD"))))
|
||||
|
||||
(defmethod project-rescan ((this project-am-lib))
|
||||
"Rescan object THIS."
|
||||
(oset this :source (makefile-macro-file-list (project-am-macro this))))
|
||||
(oset this :source (makefile-macro-file-list (project-am-macro this)))
|
||||
(unless (oref this :source)
|
||||
(oset this :source (list (concat (file-name-sans-extension (oref this :name)) ".c")))))
|
||||
|
||||
(defmethod project-rescan ((this project-am-texinfo))
|
||||
"Rescan object THIS."
|
||||
|
@ -728,19 +739,6 @@ DIR is the directory to apply to new targets."
|
|||
(defmethod project-rescan ((this project-am-extra-dist))
|
||||
"Rescan object THIS."
|
||||
(oset this :source (makefile-macro-file-list "EXTRA_DIST")))
|
||||
;; NOTE: The below calls 'file' then checks that it is some sort of
|
||||
;; text file. The file command may not be available on all platforms
|
||||
;; and some files may not exist yet. (ie - auto-generated)
|
||||
|
||||
;;(mapc
|
||||
;; (lambda (f)
|
||||
;; ;; prevent garbage to be parsed, could we use :aux ?
|
||||
;; (if (and (not (member f (oref this :source)))
|
||||
;; (string-match-p "ASCII\\|text"
|
||||
;; (shell-command-to-string
|
||||
;; (concat "file " f))))
|
||||
;; (oset this :source (cons f (oref this :source)))))
|
||||
;; (makefile-macro-file-list "EXTRA_DIST")))
|
||||
|
||||
(defmethod project-am-macro ((this project-am-objectcode))
|
||||
"Return the default macro to 'edit' for this object type."
|
||||
|
@ -810,22 +808,24 @@ nil means that this buffer belongs to no-one."
|
|||
|
||||
(defmethod ede-buffer-mine ((this project-am-objectcode) buffer)
|
||||
"Return t if object THIS lays claim to the file in BUFFER."
|
||||
(member (file-name-nondirectory (buffer-file-name buffer))
|
||||
(member (file-relative-name (buffer-file-name buffer) (oref this :path))
|
||||
(oref this :source)))
|
||||
|
||||
(defmethod ede-buffer-mine ((this project-am-texinfo) buffer)
|
||||
"Return t if object THIS lays claim to the file in BUFFER."
|
||||
(let ((bfn (buffer-file-name buffer)))
|
||||
(or (string= (oref this :name) (file-name-nondirectory bfn))
|
||||
(member (file-name-nondirectory bfn) (oref this :include)))))
|
||||
(let ((bfn (file-relative-name (buffer-file-name buffer)
|
||||
(oref this :path))))
|
||||
(or (string= (oref this :name) bfn)
|
||||
(member bfn (oref this :include)))))
|
||||
|
||||
(defmethod ede-buffer-mine ((this project-am-man) buffer)
|
||||
"Return t if object THIS lays claim to the file in BUFFER."
|
||||
(string= (oref this :name) (buffer-file-name buffer)))
|
||||
(string= (oref this :name)
|
||||
(file-relative-name (buffer-file-name buffer) (oref this :path))))
|
||||
|
||||
(defmethod ede-buffer-mine ((this project-am-lisp) buffer)
|
||||
"Return t if object THIS lays claim to the file in BUFFER."
|
||||
(member (file-name-nondirectory (buffer-file-name buffer))
|
||||
(member (file-relative-name (buffer-file-name buffer) (oref this :path))
|
||||
(oref this :source)))
|
||||
|
||||
(defmethod project-am-subtree ((ampf project-am-makefile) subdir)
|
||||
|
@ -956,7 +956,6 @@ Kill the Configure buffer if it was not already in a buffer."
|
|||
(cond
|
||||
;; Try configure.in or configure.ac
|
||||
(conf-in
|
||||
(require 'ede/autoconf-edit)
|
||||
(project-am-with-config-current conf-in
|
||||
(let ((aci (autoconf-parameters-for-macro "AC_INIT"))
|
||||
(aia (autoconf-parameters-for-macro "AM_INIT_AUTOMAKE"))
|
||||
|
@ -982,7 +981,7 @@ Kill the Configure buffer if it was not already in a buffer."
|
|||
(t acf))))
|
||||
(if (> (length outfiles) 1)
|
||||
(setq configfiles outfiles)
|
||||
(setq configfiles (split-string (car outfiles) " " t)))
|
||||
(setq configfiles (split-string (car outfiles) "\\s-" t)))
|
||||
)
|
||||
))
|
||||
)
|
||||
|
@ -1007,6 +1006,18 @@ Calculates the info with `project-am-extract-package-info'."
|
|||
(when top (setq dir (oref top :directory)))
|
||||
(project-am-extract-package-info dir)))
|
||||
|
||||
;; for simple per project include path extension
|
||||
(defmethod ede-system-include-path ((this project-am-makefile))
|
||||
"Return `project-am-localvars-include-path', usually local variable
|
||||
per file or in .dir-locals.el or similar."
|
||||
(bound-and-true-p project-am-localvars-include-path))
|
||||
|
||||
(defmethod ede-system-include-path ((this project-am-target))
|
||||
"Return `project-am-localvars-include-path', usually local variable
|
||||
per file or in .dir-locals.el or similar."
|
||||
(bound-and-true-p project-am-localvars-include-path))
|
||||
|
||||
|
||||
(provide 'ede/project-am)
|
||||
|
||||
;; arch-tag: 528db935-f186-4240-b647-e305c5b784a2
|
||||
|
|
|
@ -70,7 +70,7 @@ COMMAND is a text string representing the thing to be run."
|
|||
(defmethod ede-shell-buffer ((target ede-target))
|
||||
"Get the buffer for running shell commands for TARGET."
|
||||
(let ((name (ede-name target)))
|
||||
(get-buffer-create (format "*EDE Shell %s" name))))
|
||||
(get-buffer-create (format "*EDE Shell %s*" name))))
|
||||
|
||||
(provide 'ede/shell)
|
||||
|
||||
|
|
|
@ -21,6 +21,10 @@
|
|||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; NOTE: EDE Simple Projects are considered obsolete. Use generic
|
||||
;; projects instead. They have much better automatic support and
|
||||
;; simpler configuration.
|
||||
;;
|
||||
;; A vast majority of projects use non-EDE project techniques, such
|
||||
;; as hand written Makefiles, or other IDE's.
|
||||
;;
|
||||
|
@ -41,6 +45,14 @@
|
|||
|
||||
;;; Code:
|
||||
|
||||
(add-to-list 'ede-project-class-files
|
||||
(ede-project-autoload "simple-overlay"
|
||||
:name "Simple" :file 'ede-simple
|
||||
:proj-file 'ede-simple-projectfile-for-dir
|
||||
:load-type 'ede-simple-load
|
||||
:class-sym 'ede-simple-project)
|
||||
t)
|
||||
|
||||
(defcustom ede-simple-save-directory "~/.ede"
|
||||
"*Directory where simple EDE project overlays are saved."
|
||||
:group 'ede
|
||||
|
|
|
@ -108,7 +108,7 @@ Argument DIR is the directory from which to derive the list of objects."
|
|||
;;; Some special commands useful in EDE
|
||||
;;
|
||||
(defun ede-speedbar-remove-file-from-target ()
|
||||
"Remove the file at point from it's target."
|
||||
"Remove the file at point from its target."
|
||||
(interactive)
|
||||
(if (stringp (speedbar-line-token))
|
||||
(progn
|
||||
|
|
|
@ -43,7 +43,9 @@
|
|||
(srecode-map-update-map t)
|
||||
;; We don't call this unless we need it. Load in the templates.
|
||||
(srecode-load-tables-for-mode 'makefile-mode)
|
||||
(srecode-load-tables-for-mode 'makefile-mode 'ede))
|
||||
(srecode-load-tables-for-mode 'makefile-mode 'ede)
|
||||
(srecode-load-tables-for-mode 'autoconf-mode)
|
||||
(srecode-load-tables-for-mode 'autoconf-mode 'ede))
|
||||
|
||||
(defmacro ede-srecode-insert-with-dictionary (template &rest forms)
|
||||
"Insert TEMPLATE after executing FORMS with a dictionary.
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
;;; Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Eric M. Ludlam <eric@siege-engine.com>
|
||||
;; Version: 1.0
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
|
@ -57,10 +58,14 @@
|
|||
(error nil)))
|
||||
|
||||
(defcustom pulse-flag (pulse-available-p)
|
||||
"*Non-nil means to pulse the overlay face for momentary highlighting.
|
||||
Pulsing involves a bright highlight that slowly shifts to the background
|
||||
color. Non-nil just means to highlight with an unchanging color for a short
|
||||
time.
|
||||
"Whether to use pulsing for momentary highlighting.
|
||||
Pulsing involves a bright highlight that slowly shifts to the
|
||||
background color.
|
||||
|
||||
If the value is nil, highlight with an unchanging color until a
|
||||
key is pressed.
|
||||
If the value is `never', do no coloring at all.
|
||||
Any other value means to the default pulsing behavior.
|
||||
|
||||
If `pulse-flag' is non-nil, but `pulse-available-p' is nil, then
|
||||
this flag is ignored."
|
||||
|
@ -178,22 +183,23 @@ Be sure to call `pulse-reset-face' after calling pulse."
|
|||
Optional argument FACE specifies the fact to do the highlighting."
|
||||
(overlay-put o 'original-face (overlay-get o 'face))
|
||||
(add-to-list 'pulse-momentary-overlay o)
|
||||
(if (or (not pulse-flag) (not (pulse-available-p)))
|
||||
;; Provide a face... clear on next command
|
||||
(progn
|
||||
(overlay-put o 'face (or face 'pulse-highlight-start-face))
|
||||
(add-hook 'pre-command-hook
|
||||
'pulse-momentary-unhighlight)
|
||||
)
|
||||
;; pulse it.
|
||||
(unwind-protect
|
||||
(if (eq pulse-flag 'never)
|
||||
nil
|
||||
(if (or (not pulse-flag) (not (pulse-available-p)))
|
||||
;; Provide a face... clear on next command
|
||||
(progn
|
||||
(overlay-put o 'face 'pulse-highlight-face)
|
||||
;; The pulse function puts FACE onto 'pulse-highlight-face.
|
||||
;; Thus above we put our face on the overlay, but pulse
|
||||
;; with a reference face needed for the color.
|
||||
(pulse face))
|
||||
(pulse-momentary-unhighlight))))
|
||||
(overlay-put o 'face (or face 'pulse-highlight-start-face))
|
||||
(add-hook 'pre-command-hook
|
||||
'pulse-momentary-unhighlight))
|
||||
;; pulse it.
|
||||
(unwind-protect
|
||||
(progn
|
||||
(overlay-put o 'face 'pulse-highlight-face)
|
||||
;; The pulse function puts FACE onto 'pulse-highlight-face.
|
||||
;; Thus above we put our face on the overlay, but pulse
|
||||
;; with a reference face needed for the color.
|
||||
(pulse face))
|
||||
(pulse-momentary-unhighlight)))))
|
||||
|
||||
(defun pulse-momentary-unhighlight ()
|
||||
"Unhighlight a line recently highlighted."
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
;; Author: Eric M. Ludlam <zappo@gnu.org>
|
||||
;; Keywords: syntax tools
|
||||
;; Version: 2.0pre7
|
||||
;; Version: 2.0
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
|
@ -39,7 +39,7 @@
|
|||
(require 'semantic/tag)
|
||||
(require 'semantic/lex)
|
||||
|
||||
(defvar semantic-version "2.0pre7"
|
||||
(defvar semantic-version "2.0"
|
||||
"Current version of Semantic.")
|
||||
|
||||
(declare-function inversion-test "inversion")
|
||||
|
@ -876,6 +876,7 @@ Throw away all the old tags, and recreate the tag database."
|
|||
;; (define-key km "i" 'senator-isearch-toggle-semantic-mode)
|
||||
(define-key map "\C-c,j" 'semantic-complete-jump-local)
|
||||
(define-key map "\C-c,J" 'semantic-complete-jump)
|
||||
(define-key map "\C-c,m" 'semantic-complete-jump-local-members)
|
||||
(define-key map "\C-c,g" 'semantic-symref-symbol)
|
||||
(define-key map "\C-c,G" 'semantic-symref)
|
||||
(define-key map "\C-c,p" 'senator-previous-tag)
|
||||
|
@ -886,6 +887,7 @@ Throw away all the old tags, and recreate the tag database."
|
|||
(define-key map "\C-c,\M-w" 'senator-copy-tag)
|
||||
(define-key map "\C-c,\C-y" 'senator-yank-tag)
|
||||
(define-key map "\C-c,r" 'senator-copy-tag-to-register)
|
||||
(define-key map "\C-c,," 'semantic-force-refresh)
|
||||
(define-key map [?\C-c ?, up] 'senator-transpose-tags-up)
|
||||
(define-key map [?\C-c ?, down] 'senator-transpose-tags-down)
|
||||
(define-key map "\C-c,l" 'semantic-analyze-possible-completions)
|
||||
|
@ -951,6 +953,9 @@ Throw away all the old tags, and recreate the tag database."
|
|||
(define-key navigate-menu [semantic-complete-jump]
|
||||
'(menu-item "Find Tag Globally..." semantic-complete-jump
|
||||
:help "Read a tag name and find it in the current project"))
|
||||
(define-key navigate-menu [semantic-complete-jump-local-members]
|
||||
'(menu-item "Find Local Members ..." semantic-complete-jump-local-members
|
||||
:help "Read a tag name and find a local member with that name"))
|
||||
(define-key navigate-menu [semantic-complete-jump-local]
|
||||
'(menu-item "Find Tag in This Buffer..." semantic-complete-jump-local
|
||||
:help "Read a tag name and find it in this buffer"))
|
||||
|
|
|
@ -253,7 +253,7 @@ Optional argument THROWSYM specifies a symbol the throw on non-recoverable error
|
|||
(tag nil) ; tag return list
|
||||
(tagtype nil) ; tag types return list
|
||||
(fname nil)
|
||||
(miniscope (clone scope))
|
||||
(miniscope (when scope (clone scope)))
|
||||
)
|
||||
;; First order check. Is this wholely contained in the typecache?
|
||||
(setq tmp (semanticdb-typecache-find sequence))
|
||||
|
@ -297,11 +297,12 @@ Optional argument THROWSYM specifies a symbol the throw on non-recoverable error
|
|||
;; and we can use it directly.
|
||||
(cond ((semantic-tag-of-class-p tmp 'type)
|
||||
;; update the miniscope when we need to analyze types directly.
|
||||
(let ((rawscope
|
||||
(apply 'append
|
||||
(mapcar 'semantic-tag-type-members
|
||||
tagtype))))
|
||||
(oset miniscope fullscope rawscope))
|
||||
(when miniscope
|
||||
(let ((rawscope
|
||||
(apply 'append
|
||||
(mapcar 'semantic-tag-type-members
|
||||
tagtype))))
|
||||
(oset miniscope fullscope rawscope)))
|
||||
;; Now analayze the type to remove metatypes.
|
||||
(or (semantic-analyze-type tmp miniscope)
|
||||
tmp))
|
||||
|
@ -351,7 +352,7 @@ Optional argument SCOPE specifies a scope object which has
|
|||
additional tags which are in SCOPE and do not need prefixing to
|
||||
find.
|
||||
|
||||
This is a wrapper on top of semanticdb, semanticdb-typecache,
|
||||
This is a wrapper on top of semanticdb, semanticdb typecache,
|
||||
semantic-scope, and semantic search functions. Almost all
|
||||
searches use the same arguments."
|
||||
(let ((namelst (if (consp name) name ;; test if pre-split.
|
||||
|
|
|
@ -63,11 +63,15 @@ Used as options when completing.")
|
|||
;;; MAIN completion calculator
|
||||
;;
|
||||
;;;###autoload
|
||||
(define-overloadable-function semantic-analyze-possible-completions (context)
|
||||
(define-overloadable-function semantic-analyze-possible-completions (context &rest flags)
|
||||
"Return a list of semantic tags which are possible completions.
|
||||
CONTEXT is either a position (such as point), or a precalculated
|
||||
context. Passing in a context is useful if the caller also needs
|
||||
to access parts of the analysis.
|
||||
The remaining FLAGS arguments are passed to the mode specific completion engine.
|
||||
Bad flags should be ignored by modes that don't use them.
|
||||
See `semantic-analyze-possible-completions-default' for details on the default FLAGS.
|
||||
|
||||
Completions run through the following filters:
|
||||
* Elements currently in scope
|
||||
* Constants currently in scope
|
||||
|
@ -98,9 +102,13 @@ in a buffer."
|
|||
(get-buffer-window "*Possible Completions*")))
|
||||
ans)))
|
||||
|
||||
(defun semantic-analyze-possible-completions-default (context)
|
||||
(defun semantic-analyze-possible-completions-default (context &optional flags)
|
||||
"Default method for producing smart completions.
|
||||
Argument CONTEXT is an object specifying the locally derived context."
|
||||
Argument CONTEXT is an object specifying the locally derived context.
|
||||
The optional argument FLAGS changes which return options are returned.
|
||||
FLAGS can be any number of:
|
||||
'no-tc - do not apply data-type constraint.
|
||||
'no-unique - do not apply unique by name filtering."
|
||||
(let* ((a context)
|
||||
(desired-type (semantic-analyze-type-constraint a))
|
||||
(desired-class (oref a prefixclass))
|
||||
|
@ -109,8 +117,13 @@ Argument CONTEXT is an object specifying the locally derived context."
|
|||
(completetext nil)
|
||||
(completetexttype nil)
|
||||
(scope (oref a scope))
|
||||
(localvar (oref scope localvar))
|
||||
(c nil))
|
||||
(localvar (when scope (oref scope localvar)))
|
||||
(origc nil)
|
||||
(c nil)
|
||||
(any nil)
|
||||
(do-typeconstraint (not (memq 'no-tc flags)))
|
||||
(do-unique (not (memq 'no-unique flags)))
|
||||
)
|
||||
|
||||
;; Calculate what our prefix string is so that we can
|
||||
;; find all our matching text.
|
||||
|
@ -160,33 +173,36 @@ Argument CONTEXT is an object specifying the locally derived context."
|
|||
;; Argument list and local variables
|
||||
(semantic-find-tags-for-completion completetext localvar)
|
||||
;; The current scope
|
||||
(semantic-find-tags-for-completion completetext (oref scope fullscope))
|
||||
(semantic-find-tags-for-completion completetext (when scope (oref scope fullscope)))
|
||||
;; The world
|
||||
(semantic-analyze-find-tags-by-prefix completetext))
|
||||
)
|
||||
)
|
||||
|
||||
(let ((origc c)
|
||||
(let ((loopc c)
|
||||
(dtname (semantic-tag-name desired-type)))
|
||||
|
||||
;; Save off our first batch of completions
|
||||
(setq origc c)
|
||||
|
||||
;; Reset c.
|
||||
(setq c nil)
|
||||
|
||||
;; Loop over all the found matches, and catagorize them
|
||||
;; as being possible features.
|
||||
(while origc
|
||||
(while (and loopc do-typeconstraint)
|
||||
|
||||
(cond
|
||||
;; Strip operators
|
||||
((semantic-tag-get-attribute (car origc) :operator-flag)
|
||||
((semantic-tag-get-attribute (car loopc) :operator-flag)
|
||||
nil
|
||||
)
|
||||
|
||||
;; If we are completing from within some prefix,
|
||||
;; then we want to exclude constructors and destructors
|
||||
((and completetexttype
|
||||
(or (semantic-tag-get-attribute (car origc) :constructor-flag)
|
||||
(semantic-tag-get-attribute (car origc) :destructor-flag)))
|
||||
(or (semantic-tag-get-attribute (car loopc) :constructor-flag)
|
||||
(semantic-tag-get-attribute (car loopc) :destructor-flag)))
|
||||
nil
|
||||
)
|
||||
|
||||
|
@ -197,17 +213,17 @@ Argument CONTEXT is an object specifying the locally derived context."
|
|||
;; Ok, we now have a completion list based on the text we found
|
||||
;; we want to complete on. Now filter that stream against the
|
||||
;; type we want to search for.
|
||||
((string= dtname (semantic-analyze-type-to-name (semantic-tag-type (car origc))))
|
||||
(setq c (cons (car origc) c))
|
||||
((string= dtname (semantic-analyze-type-to-name (semantic-tag-type (car loopc))))
|
||||
(setq c (cons (car loopc) c))
|
||||
)
|
||||
|
||||
;; Now anything that is a compound type which could contain
|
||||
;; additional things which are of the desired type
|
||||
((semantic-tag-type (car origc))
|
||||
(let ((att (semantic-analyze-tag-type (car origc) scope))
|
||||
((semantic-tag-type (car loopc))
|
||||
(let ((att (semantic-analyze-tag-type (car loopc) scope))
|
||||
)
|
||||
(if (and att (semantic-tag-type-members att))
|
||||
(setq c (cons (car origc) c))))
|
||||
(setq c (cons (car loopc) c))))
|
||||
)
|
||||
|
||||
) ; cond
|
||||
|
@ -215,11 +231,11 @@ Argument CONTEXT is an object specifying the locally derived context."
|
|||
|
||||
;; No desired type, no other restrictions. Just add.
|
||||
(t
|
||||
(setq c (cons (car origc) c)))
|
||||
(setq c (cons (car loopc) c)))
|
||||
|
||||
); cond
|
||||
|
||||
(setq origc (cdr origc)))
|
||||
(setq loopc (cdr loopc)))
|
||||
|
||||
(when desired-type
|
||||
;; Some types, like the enum in C, have special constant values that
|
||||
|
@ -241,15 +257,16 @@ Argument CONTEXT is an object specifying the locally derived context."
|
|||
(when desired-class
|
||||
(setq c (semantic-analyze-tags-of-class-list c desired-class)))
|
||||
|
||||
;; Pull out trash.
|
||||
;; NOTE TO SELF: Is this too slow?
|
||||
;; OTHER NOTE: Do we not want to strip duplicates by name and
|
||||
;; only by position? When are duplicate by name but not by tag
|
||||
;; useful?
|
||||
(setq c (semantic-unique-tag-table-by-name c))
|
||||
(if do-unique
|
||||
(if c
|
||||
;; Pull out trash.
|
||||
;; NOTE TO SELF: Is this too slow?
|
||||
(setq c (semantic-unique-tag-table-by-name c))
|
||||
(setq c (semantic-unique-tag-table-by-name origc)))
|
||||
(when (not c)
|
||||
(setq c origc)))
|
||||
|
||||
;; All done!
|
||||
|
||||
c))
|
||||
|
||||
(provide 'semantic/analyze/complete)
|
||||
|
|
|
@ -54,6 +54,8 @@
|
|||
|
||||
))
|
||||
|
||||
;; @TODO - If this happens, but the last found type is
|
||||
;; a datatype, then the below is wrong
|
||||
(defun semantic-analyzer-debug-found-prefix (ctxt)
|
||||
"Debug the prefix found by the analyzer output CTXT."
|
||||
(let* ((pf (oref ctxt prefix))
|
||||
|
@ -97,7 +99,7 @@ Argument COMP are possible completions here."
|
|||
)
|
||||
(with-output-to-temp-buffer (help-buffer)
|
||||
(with-current-buffer standard-output
|
||||
(princ "Unable to find prefix ")
|
||||
(princ "Unable to find symbol ")
|
||||
(princ prefix)
|
||||
(princ ".\n\n")
|
||||
|
||||
|
@ -217,7 +219,7 @@ Argument COMP are possible completions here."
|
|||
(when (not dt) (error "Missing Innertype debugger is confused"))
|
||||
(with-output-to-temp-buffer (help-buffer)
|
||||
(with-current-buffer standard-output
|
||||
(princ "Cannot find prefix \"")
|
||||
(princ "Cannot find symbol \"")
|
||||
(princ prefixitem)
|
||||
(princ "\" in datatype:
|
||||
")
|
||||
|
@ -550,24 +552,25 @@ PARENT is a possible parent (by nesting) tag."
|
|||
(let ((str (semantic-format-tag-prototype tag parent)))
|
||||
(if (and (semantic-tag-with-position-p tag)
|
||||
(semantic-tag-file-name tag))
|
||||
(insert-button str
|
||||
'mouse-face 'custom-button-pressed-face
|
||||
'tag tag
|
||||
'action
|
||||
`(lambda (button)
|
||||
(let ((buff nil)
|
||||
(pnt nil))
|
||||
(save-excursion
|
||||
(semantic-go-to-tag
|
||||
(button-get button 'tag))
|
||||
(setq buff (current-buffer))
|
||||
(setq pnt (point)))
|
||||
(if (get-buffer-window buff)
|
||||
(select-window (get-buffer-window buff))
|
||||
(pop-to-buffer buff t))
|
||||
(goto-char pnt)
|
||||
(pulse-line-hook-function)))
|
||||
)
|
||||
(with-current-buffer standard-output
|
||||
(insert-button str
|
||||
'mouse-face 'custom-button-pressed-face
|
||||
'tag tag
|
||||
'action
|
||||
`(lambda (button)
|
||||
(let ((buff nil)
|
||||
(pnt nil))
|
||||
(save-excursion
|
||||
(semantic-go-to-tag
|
||||
(button-get button 'tag))
|
||||
(setq buff (current-buffer))
|
||||
(setq pnt (point)))
|
||||
(if (get-buffer-window buff)
|
||||
(select-window (get-buffer-window buff))
|
||||
(pop-to-buffer buff t))
|
||||
(goto-char pnt)
|
||||
(pulse-line-hook-function)))
|
||||
))
|
||||
(princ "\"")
|
||||
(princ str)
|
||||
(princ "\""))
|
||||
|
|
|
@ -104,6 +104,7 @@ Use `semantic-analyze-current-tag' to debug this fcn."
|
|||
"Return the implementations derived in the reference analyzer REFS.
|
||||
Optional argument IN-BUFFER indicates that the returned tag should be in an active buffer."
|
||||
(let ((allhits (oref refs rawsearchdata))
|
||||
(tag (oref refs :tag))
|
||||
(impl nil)
|
||||
)
|
||||
(semanticdb-find-result-mapc
|
||||
|
@ -113,7 +114,8 @@ Optional argument IN-BUFFER indicates that the returned tag should be in an acti
|
|||
(aT (cdr ans))
|
||||
(aDB (car ans))
|
||||
)
|
||||
(when (not (semantic-tag-prototype-p aT))
|
||||
(when (and (not (semantic-tag-prototype-p aT))
|
||||
(semantic-tag-similar-p tag aT :prototype-flag :parent))
|
||||
(when in-buffer (save-excursion (semantic-go-to-tag aT aDB)))
|
||||
(push aT impl))))
|
||||
allhits)
|
||||
|
@ -123,6 +125,7 @@ Optional argument IN-BUFFER indicates that the returned tag should be in an acti
|
|||
"Return the prototypes derived in the reference analyzer REFS.
|
||||
Optional argument IN-BUFFER indicates that the returned tag should be in an active buffer."
|
||||
(let ((allhits (oref refs rawsearchdata))
|
||||
(tag (oref refs :tag))
|
||||
(proto nil))
|
||||
(semanticdb-find-result-mapc
|
||||
(lambda (T DB)
|
||||
|
@ -131,7 +134,8 @@ Optional argument IN-BUFFER indicates that the returned tag should be in an acti
|
|||
(aT (cdr ans))
|
||||
(aDB (car ans))
|
||||
)
|
||||
(when (semantic-tag-prototype-p aT)
|
||||
(when (and (semantic-tag-prototype-p aT)
|
||||
(semantic-tag-similar-p tag aT :prototype-flag :parent))
|
||||
(when in-buffer (save-excursion (semantic-go-to-tag aT aDB)))
|
||||
(push aT proto))))
|
||||
allhits)
|
||||
|
@ -142,8 +146,8 @@ Optional argument IN-BUFFER indicates that the returned tag should be in an acti
|
|||
(defun semantic--analyze-refs-full-lookup (tag scope)
|
||||
"Perform a full lookup for all occurrences of TAG in the current project.
|
||||
TAG should be the tag currently under point.
|
||||
PARENT is the list of tags that are parents to TAG by
|
||||
containment, as opposed to reference."
|
||||
SCOPE is the scope the cursor is in. From this a list of parents is
|
||||
derived. If SCOPE does not have parents, then only a simple lookup is done."
|
||||
(if (not (oref scope parents))
|
||||
;; If this tag has some named parent, but is not
|
||||
(semantic--analyze-refs-full-lookup-simple tag)
|
||||
|
@ -177,20 +181,36 @@ CLASS is the class of the tag that ought to be returned."
|
|||
ans))
|
||||
|
||||
(defun semantic--analyze-refs-find-tags-with-parent (find-results parents)
|
||||
"Find in FIND-RESULTS all tags with PARNTS.
|
||||
"Find in FIND-RESULTS all tags with PARENTS.
|
||||
NAME is the name of the tag needing finding.
|
||||
PARENTS is a list of names."
|
||||
(let ((ans nil))
|
||||
(let ((ans nil) (usingnames nil))
|
||||
;; Loop over the find-results passed in.
|
||||
(semanticdb-find-result-mapc
|
||||
(lambda (tag db)
|
||||
(let* ((p (semantic-tag-named-parent tag))
|
||||
(ps (when (stringp p)
|
||||
(semantic-analyze-split-name p))))
|
||||
(ps (when (stringp p) (semantic-analyze-split-name p))))
|
||||
(when (stringp ps) (setq ps (list ps)))
|
||||
(when (and ps (equal ps parents))
|
||||
;; We could optimize this, but it seems unlikely.
|
||||
(push (list db tag) ans))
|
||||
))
|
||||
(when ps
|
||||
;; If there is a perfect match, then use it.
|
||||
(if (equal ps parents)
|
||||
(push (list db tag) ans))
|
||||
;; No match, find something from our list of using names.
|
||||
;; Do we need to split UN?
|
||||
(save-excursion
|
||||
(semantic-go-to-tag tag db)
|
||||
(setq usingnames nil)
|
||||
(let ((imports (semantic-ctxt-imported-packages)))
|
||||
;; Derive the names from all the using statements.
|
||||
(mapc (lambda (T)
|
||||
(setq usingnames
|
||||
(cons (semantic-format-tag-name-from-anything T) usingnames)))
|
||||
imports))
|
||||
(dolist (UN usingnames)
|
||||
(when (equal (cons UN ps) parents)
|
||||
(push (list db tag) ans)
|
||||
(setq usingnames (cdr usingnames))))
|
||||
))))
|
||||
find-results)
|
||||
ans))
|
||||
|
||||
|
@ -206,7 +226,7 @@ TAG should be the tag currently under point."
|
|||
;; Find all hits for the first parent name.
|
||||
(brute (semanticdb-find-tags-collector
|
||||
(lambda (table tags)
|
||||
(semanticdb-find-tags-by-name-method table name tags)
|
||||
(semanticdb-deep-find-tags-by-name-method table name tags)
|
||||
)
|
||||
nil nil t))
|
||||
;; Prime the answer.
|
||||
|
@ -214,6 +234,7 @@ TAG should be the tag currently under point."
|
|||
)
|
||||
;; First parent is already search to initialize "brute".
|
||||
(setq plist (cdr plist))
|
||||
|
||||
;; Go through the list of parents, and try to find matches.
|
||||
;; As we cycle through plist, for each level look for NAME,
|
||||
;; and compare the named-parent, and also dive into the next item of
|
||||
|
@ -253,7 +274,8 @@ Only works for tags in the global namespace."
|
|||
(lambda (table tags)
|
||||
(semanticdb-find-tags-by-name-method table name tags)
|
||||
)
|
||||
nil nil t))
|
||||
nil ;; This may need to be the entire project??
|
||||
nil t))
|
||||
)
|
||||
|
||||
(when (and (not brute) (not noerror))
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
(declare-function semantic-brute-find-tag-by-attribute "semantic/find")
|
||||
(declare-function semanticdb-minor-mode-p "semantic/db-mode")
|
||||
(declare-function semanticdb-needs-refresh-p "semantic/db")
|
||||
(declare-function semanticdb-typecache-faux-namespace "semantic/db-typecache")
|
||||
(declare-function c-forward-conditional "cc-cmds")
|
||||
(declare-function ede-system-include-path "ede")
|
||||
|
||||
|
@ -158,7 +159,7 @@ part of the preprocessor map.")
|
|||
Each entry is a cons cell like this:
|
||||
( \"KEYWORD\" . \"REPLACEMENT\" )
|
||||
Where KEYWORD is the macro that gets replaced in the lexical phase,
|
||||
and REPLACEMENT is a string that is inserted in it's place. Empty string
|
||||
and REPLACEMENT is a string that is inserted in its place. Empty string
|
||||
implies that the lexical analyzer will discard KEYWORD when it is encountered.
|
||||
|
||||
Alternately, it can be of the form:
|
||||
|
@ -295,6 +296,7 @@ Moves completely over balanced #if blocks."
|
|||
(cond
|
||||
((looking-at "^\\s-*#\\s-*if")
|
||||
;; We found a nested if. Skip it.
|
||||
;; @TODO - can we use the new c-scan-conditionals
|
||||
(c-forward-conditional 1))
|
||||
((looking-at "^\\s-*#\\s-*elif")
|
||||
;; We need to let the preprocessor analize this one.
|
||||
|
@ -348,7 +350,6 @@ Uses known macro tables in SPP to determine what block to skip."
|
|||
;; (message "%s %s yes" ift sym)
|
||||
(beginning-of-line)
|
||||
(setq pt (point))
|
||||
;;(c-forward-conditional 1)
|
||||
;; This skips only a section of a conditional. Once that section
|
||||
;; is opened, encountering any new #else or related conditional
|
||||
;; should be skipped.
|
||||
|
@ -356,8 +357,8 @@ Uses known macro tables in SPP to determine what block to skip."
|
|||
(setq semantic-lex-end-point (point))
|
||||
(semantic-push-parser-warning (format "Skip #%s %s" ift sym)
|
||||
pt (point))
|
||||
;; (semantic-lex-push-token
|
||||
;; (semantic-lex-token 'c-preprocessor-skip pt (point)))
|
||||
;; (semantic-lex-push-token
|
||||
;; (semantic-lex-token 'c-preprocessor-skip pt (point)))
|
||||
nil)
|
||||
;; Else, don't ignore it, but do handle the internals.
|
||||
;;(message "%s %s no" ift sym)
|
||||
|
@ -703,58 +704,60 @@ the regular parser."
|
|||
(symtext (semantic-lex-token-text lexicaltoken))
|
||||
(macros (get-text-property 0 'macros symtext))
|
||||
)
|
||||
(with-current-buffer buf
|
||||
(erase-buffer)
|
||||
(when (not (eq major-mode mode))
|
||||
(save-match-data
|
||||
(if (> semantic-c-parse-token-hack-depth 5)
|
||||
nil
|
||||
(with-current-buffer buf
|
||||
(erase-buffer)
|
||||
(when (not (eq major-mode mode))
|
||||
(save-match-data
|
||||
|
||||
;; Protect against user hooks throwing errors.
|
||||
(condition-case nil
|
||||
(funcall mode)
|
||||
(error
|
||||
(if (y-or-n-p
|
||||
(format "There was an error initializing %s in buffer \"%s\". Debug your hooks? "
|
||||
mode (buffer-name)))
|
||||
(semantic-c-debug-mode-init mode)
|
||||
(message "Macro parsing state may be broken...")
|
||||
(sit-for 1))))
|
||||
) ; save match data
|
||||
;; Protect against user hooks throwing errors.
|
||||
(condition-case nil
|
||||
(funcall mode)
|
||||
(error
|
||||
(if (y-or-n-p
|
||||
(format "There was an error initializing %s in buffer \"%s\". Debug your hooks? "
|
||||
mode (buffer-name)))
|
||||
(semantic-c-debug-mode-init mode)
|
||||
(message "Macro parsing state may be broken...")
|
||||
(sit-for 1))))
|
||||
) ; save match data
|
||||
|
||||
;; Hack in mode-local
|
||||
(activate-mode-local-bindings)
|
||||
;; CHEATER! The following 3 lines are from
|
||||
;; `semantic-new-buffer-fcn', but we don't want to turn
|
||||
;; on all the other annoying modes for this little task.
|
||||
(setq semantic-new-buffer-fcn-was-run t)
|
||||
(semantic-lex-init)
|
||||
(semantic-clear-toplevel-cache)
|
||||
(remove-hook 'semantic-lex-reset-hooks 'semantic-lex-spp-reset-hook
|
||||
t)
|
||||
)
|
||||
;; Get the macro symbol table right.
|
||||
(setq semantic-lex-spp-dynamic-macro-symbol-obarray spp-syms)
|
||||
;; (message "%S" macros)
|
||||
(dolist (sym macros)
|
||||
(semantic-lex-spp-symbol-set (car sym) (cdr sym)))
|
||||
;; Hack in mode-local
|
||||
(activate-mode-local-bindings)
|
||||
;; CHEATER! The following 3 lines are from
|
||||
;; `semantic-new-buffer-fcn', but we don't want to turn
|
||||
;; on all the other annoying modes for this little task.
|
||||
(setq semantic-new-buffer-fcn-was-run t)
|
||||
(semantic-lex-init)
|
||||
(semantic-clear-toplevel-cache)
|
||||
(remove-hook 'semantic-lex-reset-hooks 'semantic-lex-spp-reset-hook
|
||||
t)
|
||||
)
|
||||
;; Get the macro symbol table right.
|
||||
(setq semantic-lex-spp-dynamic-macro-symbol-obarray spp-syms)
|
||||
;; (message "%S" macros)
|
||||
(dolist (sym macros)
|
||||
(semantic-lex-spp-symbol-set (car sym) (cdr sym)))
|
||||
|
||||
(insert symtext)
|
||||
(insert symtext)
|
||||
|
||||
(setq stream
|
||||
(semantic-parse-region-default
|
||||
(point-min) (point-max) nonterminal depth returnonerror))
|
||||
(setq stream
|
||||
(semantic-parse-region-default
|
||||
(point-min) (point-max) nonterminal depth returnonerror))
|
||||
|
||||
;; Clean up macro symbols
|
||||
(dolist (sym macros)
|
||||
(semantic-lex-spp-symbol-remove (car sym)))
|
||||
;; Clean up macro symbols
|
||||
(dolist (sym macros)
|
||||
(semantic-lex-spp-symbol-remove (car sym)))
|
||||
|
||||
;; Convert the text of the stream.
|
||||
(dolist (tag stream)
|
||||
;; Only do two levels here 'cause I'm lazy.
|
||||
(semantic--tag-set-overlay tag (list start end))
|
||||
(dolist (stag (semantic-tag-components-with-overlays tag))
|
||||
(semantic--tag-set-overlay stag (list start end))
|
||||
))
|
||||
)
|
||||
;; Convert the text of the stream.
|
||||
(dolist (tag stream)
|
||||
;; Only do two levels here 'cause I'm lazy.
|
||||
(semantic--tag-set-overlay tag (list start end))
|
||||
(dolist (stag (semantic-tag-components-with-overlays tag))
|
||||
(semantic--tag-set-overlay stag (list start end))
|
||||
))
|
||||
))
|
||||
stream))
|
||||
|
||||
(defvar semantic-c-debug-mode-init-last-mode nil
|
||||
|
@ -920,8 +923,34 @@ now.
|
|||
;; of type "typedef".
|
||||
;; Each elt of NAME is ( STARS NAME )
|
||||
(let ((vl nil)
|
||||
(names (semantic-tag-name tag)))
|
||||
(names (semantic-tag-name tag))
|
||||
(super (semantic-tag-get-attribute tag :superclasses))
|
||||
(addlast nil))
|
||||
|
||||
(when (and (semantic-tag-of-type-p tag "typedef")
|
||||
(semantic-tag-of-class-p super 'type)
|
||||
(semantic-tag-type-members super))
|
||||
;; This is a typedef of a real type. Extract
|
||||
;; the super class, and stick it into the tags list.
|
||||
(setq addlast super)
|
||||
|
||||
;; Clone super and remove the members IFF super has a name.
|
||||
;; Note: anonymous struct/enums that are typedef'd shouldn't
|
||||
;; exist in the top level type list, so they will appear only
|
||||
;; in the :typedef slot of the typedef.
|
||||
(setq super (semantic-tag-clone super))
|
||||
(if (not (string= (semantic-tag-name super) ""))
|
||||
(semantic-tag-put-attribute super :members nil)
|
||||
(setq addlast nil))
|
||||
|
||||
;; Add in props to the full superclass.
|
||||
(when addlast
|
||||
(semantic--tag-copy-properties tag addlast)
|
||||
(semantic--tag-set-overlay addlast (semantic-tag-overlay tag)))
|
||||
)
|
||||
|
||||
(while names
|
||||
|
||||
(setq vl (cons (semantic-tag-new-type
|
||||
(nth 1 (car names)) ; name
|
||||
"typedef"
|
||||
|
@ -938,16 +967,18 @@ now.
|
|||
;; is expanded out as. Just the
|
||||
;; name shows up as a parent of this
|
||||
;; typedef.
|
||||
:typedef
|
||||
(semantic-tag-get-attribute tag :superclasses)
|
||||
:typedef super
|
||||
;;(semantic-tag-type-superclasses tag)
|
||||
:documentation
|
||||
(semantic-tag-docstring tag))
|
||||
vl))
|
||||
(semantic--tag-copy-properties tag (car vl))
|
||||
(semantic--tag-set-overlay (car vl)
|
||||
(semantic-tag-overlay tag))
|
||||
(semantic--tag-set-overlay (car vl) (semantic-tag-overlay tag))
|
||||
(setq names (cdr names)))
|
||||
|
||||
;; Add typedef superclass last.
|
||||
(when addlast (setq vl (cons addlast vl)))
|
||||
|
||||
vl))
|
||||
((and (listp (car tag))
|
||||
(semantic-tag-of-class-p (car tag) 'variable))
|
||||
|
@ -999,6 +1030,7 @@ Optional argument STAR and REF indicate the number of * and & in the typedef."
|
|||
(car tokenpart)))
|
||||
(and (stringp (car (nth 2 tokenpart)))
|
||||
(string= (car (nth 2 tokenpart)) (car tokenpart)))
|
||||
(nth 10 tokenpart) ; initializers
|
||||
)
|
||||
(not (car (nth 3 tokenpart)))))
|
||||
(fcnpointer (string-match "^\\*" (car tokenpart)))
|
||||
|
@ -1029,7 +1061,10 @@ Optional argument STAR and REF indicate the number of * and & in the typedef."
|
|||
(semantic-tag-new-type
|
||||
;; name
|
||||
(or (car semantic-c-classname)
|
||||
(car (nth 2 tokenpart)))
|
||||
(let ((split (semantic-analyze-split-name-c-mode
|
||||
(car (nth 2 tokenpart)))))
|
||||
(if (stringp split) split
|
||||
(car (last split)))))
|
||||
;; type
|
||||
(or (cdr semantic-c-classname)
|
||||
"class")
|
||||
|
@ -1580,6 +1615,48 @@ DO NOT return the list of tags encompassing point."
|
|||
tagreturn
|
||||
))
|
||||
|
||||
(define-mode-local-override semantic-ctxt-imported-packages c++-mode (&optional point)
|
||||
"Return the list of using tag types in scope of POINT."
|
||||
(when point (goto-char (point)))
|
||||
(let ((tagsaroundpoint (semantic-find-tag-by-overlay))
|
||||
(namereturn nil)
|
||||
(tmp nil)
|
||||
)
|
||||
;; Collect using statements from the top level.
|
||||
(setq tmp (semantic-find-tags-by-class 'using (current-buffer)))
|
||||
(dolist (T tmp) (setq namereturn (cons (semantic-tag-type T) namereturn)))
|
||||
;; Move through the tags around point looking for more using statements
|
||||
(while (cdr tagsaroundpoint) ; don't search the last one
|
||||
(setq tmp (semantic-find-tags-by-class 'using (semantic-tag-components (car tagsaroundpoint))))
|
||||
(dolist (T tmp) (setq namereturn (cons (semantic-tag-type T) namereturn)))
|
||||
(setq tagsaroundpoint (cdr tagsaroundpoint))
|
||||
)
|
||||
namereturn))
|
||||
|
||||
(define-mode-local-override semanticdb-expand-nested-tag c++-mode (tag)
|
||||
"Expand TAG if it has a fully qualified name.
|
||||
For types with a :parent, create faux namespaces to put TAG into."
|
||||
(let ((p (semantic-tag-get-attribute tag :parent)))
|
||||
(if (and p (semantic-tag-of-class-p tag 'type))
|
||||
;; Expand the tag
|
||||
(let ((s (semantic-analyze-split-name p))
|
||||
(newtag (semantic-tag-copy tag nil t)))
|
||||
;; Erase the qualified name.
|
||||
(semantic-tag-put-attribute newtag :parent nil)
|
||||
;; Fixup the namespace name
|
||||
(setq s (if (stringp s) (list s) (nreverse s)))
|
||||
;; Loop over all the parents, creating the nested
|
||||
;; namespace.
|
||||
(require 'semantic/db-typecache)
|
||||
(dolist (namespace s)
|
||||
(setq newtag (semanticdb-typecache-faux-namespace
|
||||
namespace (list newtag)))
|
||||
)
|
||||
;; Return the last created namespace.
|
||||
newtag)
|
||||
;; Else, return tag unmodified.
|
||||
tag)))
|
||||
|
||||
(define-mode-local-override semantic-get-local-variables c++-mode ()
|
||||
"Do what `semantic-get-local-variables' does, plus add `this' if needed."
|
||||
(let* ((origvar (semantic-get-local-variables-default))
|
||||
|
@ -1759,7 +1836,9 @@ DO NOT return the list of tags encompassing point."
|
|||
(princ "\n")
|
||||
))
|
||||
|
||||
(when (arrayp semantic-lex-spp-project-macro-symbol-obarray)
|
||||
(when (and (boundp 'ede-object)
|
||||
ede-object
|
||||
(arrayp semantic-lex-spp-project-macro-symbol-obarray))
|
||||
(princ "\n Project symbol map:\n")
|
||||
(when (and (boundp 'ede-object) ede-object)
|
||||
(princ " Your project symbol map is derived from the EDE object:\n ")
|
||||
|
|
|
@ -1206,6 +1206,27 @@ Uses semanticdb for searching all tags in the current project."
|
|||
(require 'semantic/db-find)
|
||||
(semanticdb-brute-deep-find-tags-for-completion prefix (oref obj path)))
|
||||
|
||||
;;; Current Datatype member search.
|
||||
(defclass semantic-collector-local-members (semantic-collector-project-abstract)
|
||||
((scope :initform nil
|
||||
:type (or null semantic-scope-cache)
|
||||
:documentation
|
||||
"The scope the local members are being completed from."))
|
||||
"Completion engine for tags in a project.")
|
||||
|
||||
(defmethod semantic-collector-calculate-completions-raw
|
||||
((obj semantic-collector-local-members) prefix completionlist)
|
||||
"Calculate the completions for prefix from completionlist."
|
||||
(let* ((scope (or (oref obj scope)
|
||||
(oset obj scope (semantic-calculate-scope))))
|
||||
(localstuff (oref scope scope)))
|
||||
(list
|
||||
(cons
|
||||
(oref scope :table)
|
||||
(semantic-find-tags-for-completion prefix localstuff)))))
|
||||
;(semanticdb-brute-deep-find-tags-for-completion prefix (oref obj path))))
|
||||
|
||||
;;; Smart completion collector
|
||||
(defclass semantic-collector-analyze-completions (semantic-collector-abstract)
|
||||
((context :initarg :context
|
||||
:type semantic-analyze-context
|
||||
|
@ -1800,6 +1821,28 @@ HISTORY is a symbol representing a variable to store the history in."
|
|||
history)
|
||||
)
|
||||
|
||||
(defun semantic-complete-read-tag-local-members (prompt &optional
|
||||
default-tag
|
||||
initial-input
|
||||
history)
|
||||
"Ask for a tag by name from the local type members.
|
||||
Available tags are from the the current scope.
|
||||
Completion options are presented in a traditional way, with highlighting
|
||||
to resolve same-name collisions.
|
||||
PROMPT is a string to prompt with.
|
||||
DEFAULT-TAG is a semantic tag or string to use as the default value.
|
||||
If INITIAL-INPUT is non-nil, insert it in the minibuffer initially.
|
||||
HISTORY is a symbol representing a variable to store the history in."
|
||||
(semantic-complete-read-tag-engine
|
||||
(semantic-collector-local-members prompt :buffer (current-buffer))
|
||||
(semantic-displayor-traditional-with-focus-highlight "simple")
|
||||
;;(semantic-displayor-tooltip "simple")
|
||||
prompt
|
||||
default-tag
|
||||
initial-input
|
||||
history)
|
||||
)
|
||||
|
||||
(defun semantic-complete-read-tag-project (prompt &optional
|
||||
default-tag
|
||||
initial-input
|
||||
|
@ -1979,7 +2022,7 @@ completion works."
|
|||
|
||||
;;;###autoload
|
||||
(defun semantic-complete-jump-local ()
|
||||
"Jump to a semantic symbol."
|
||||
"Jump to a local semantic symbol."
|
||||
(interactive)
|
||||
(let ((tag (semantic-complete-read-tag-buffer-deep "Jump to symbol: ")))
|
||||
(when (semantic-tag-p tag)
|
||||
|
@ -2004,6 +2047,23 @@ completion works."
|
|||
(semantic-tag-class tag)
|
||||
(semantic-tag-name tag)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun semantic-complete-jump-local-members ()
|
||||
"Jump to a semantic symbol."
|
||||
(interactive)
|
||||
(let* ((tag (semantic-complete-read-tag-local-members "Jump to symbol: ")))
|
||||
(when (semantic-tag-p tag)
|
||||
(let ((start (condition-case nil (semantic-tag-start tag)
|
||||
(error nil))))
|
||||
(unless start
|
||||
(error "Tag %s has no location" (semantic-format-tag-prototype tag)))
|
||||
(push-mark)
|
||||
(goto-char start)
|
||||
(semantic-momentary-highlight-tag tag)
|
||||
(message "%S: %s "
|
||||
(semantic-tag-class tag)
|
||||
(semantic-tag-name tag))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun semantic-complete-analyze-and-replace ()
|
||||
"Perform prompt completion to do in buffer completion.
|
||||
|
@ -2075,15 +2135,17 @@ use `semantic-complete-analyze-inline' to complete."
|
|||
|
||||
;; Prepare for doing completion, but exit quickly if there is keyboard
|
||||
;; input.
|
||||
(when (and (not (semantic-exit-on-input 'csi
|
||||
(semantic-fetch-tags)
|
||||
(semantic-throw-on-input 'csi)
|
||||
nil))
|
||||
(= arg 1)
|
||||
(not (semantic-exit-on-input 'csi
|
||||
(semantic-analyze-current-context)
|
||||
(semantic-throw-on-input 'csi)
|
||||
nil)))
|
||||
(when (save-window-excursion
|
||||
(save-excursion
|
||||
(and (not (semantic-exit-on-input 'csi
|
||||
(semantic-fetch-tags)
|
||||
(semantic-throw-on-input 'csi)
|
||||
nil))
|
||||
(= arg 1)
|
||||
(not (semantic-exit-on-input 'csi
|
||||
(semantic-analyze-current-context)
|
||||
(semantic-throw-on-input 'csi)
|
||||
nil)))))
|
||||
(condition-case nil
|
||||
(semantic-complete-analyze-inline)
|
||||
;; Ignore errors. Seems likely that we'll get some once in a while.
|
||||
|
|
|
@ -599,12 +599,18 @@ that may or may not have a name.)")
|
|||
"Return a list of scoped types by name for the current context at POINT.
|
||||
This is very different for various languages, and does nothing unless
|
||||
overridden."
|
||||
(if point (goto-char point))
|
||||
(let ((case-fold-search semantic-case-fold))
|
||||
;; We need to look at TYPES within the bounds of locally parse arguments.
|
||||
;; C needs to find using statements and the like too. Bleh.
|
||||
nil
|
||||
))
|
||||
nil)
|
||||
|
||||
(define-overloadable-function semantic-ctxt-imported-packages (&optional point)
|
||||
"Return a list of package tags or names which are being imported at POINT.
|
||||
The return value is a list of strings which are package names
|
||||
that are implied in code. Thus a C++ symbol:
|
||||
foo::bar();
|
||||
where there is a statement such as:
|
||||
using baz;
|
||||
means that the first symbol might be:
|
||||
baz::foo::bar();"
|
||||
nil)
|
||||
|
||||
(provide 'semantic/ctxt)
|
||||
|
||||
|
|
|
@ -245,7 +245,7 @@ If DB is not specified, then use the current database."
|
|||
;; @todo - It should ask if we are not called from a hook.
|
||||
;; How?
|
||||
(if (or supress-questions
|
||||
(y-or-n-p (format "Skip Error: %S ?" (car (cdr foo)))))
|
||||
(y-or-n-p (format "Skip Error: %s ?" (car (cdr foo)))))
|
||||
(message "Save Error: %S: %s" (car (cdr foo))
|
||||
objname)
|
||||
(error "%S" (car (cdr foo))))))))
|
||||
|
|
|
@ -202,7 +202,7 @@ This class will cache data derived during various searches.")
|
|||
(when (oref idx type-cache)
|
||||
(semantic-reset (oref idx type-cache)))
|
||||
;; Clear the scope. Scope doesn't have the data it needs to track
|
||||
;; it's own reset.
|
||||
;; its own reset.
|
||||
(semantic-scope-reset-cache)
|
||||
)
|
||||
|
||||
|
@ -262,13 +262,13 @@ This class will cache data derived during various searches.")
|
|||
"Translate PATH into a list of semantic tables.
|
||||
Path translation involves identifying the PATH input argument
|
||||
in one of the following ways:
|
||||
nil - Take the current buffer, and use it's include list
|
||||
nil - Take the current buffer, and use its include list
|
||||
buffer - Use that buffer's include list.
|
||||
filename - Use that file's include list. If the file is not
|
||||
in a buffer, see of there is a semanticdb table for it. If
|
||||
not, read that file into a buffer.
|
||||
tag - Get that tag's buffer of file file. See above.
|
||||
table - Search that table, and it's include list.
|
||||
table - Search that table, and its include list.
|
||||
find result - Search the results of a previous find.
|
||||
|
||||
In addition, once the base path is found, there is the possibility of
|
||||
|
@ -1006,9 +1006,14 @@ is still made current."
|
|||
(when norm
|
||||
;; The normalized tags can now be found based on that
|
||||
;; tags table.
|
||||
(semanticdb-set-buffer (car norm))
|
||||
;; Now reset ans
|
||||
(setq ans (cdr norm))
|
||||
(condition-case foo
|
||||
(progn
|
||||
(semanticdb-set-buffer (car norm))
|
||||
;; Now reset ans
|
||||
(setq ans (cdr norm)))
|
||||
;; Don't error for this case, but don't store
|
||||
;; the thing either.
|
||||
(no-method-definition nil))
|
||||
))
|
||||
)
|
||||
;; Return the tag.
|
||||
|
@ -1019,10 +1024,10 @@ is still made current."
|
|||
FCN takes two arguments. The first is a TAG, and the
|
||||
second is a DB from whence TAG originated.
|
||||
Returns result."
|
||||
(mapc (lambda (sublst)
|
||||
(mapc (lambda (tag)
|
||||
(funcall fcn tag (car sublst)))
|
||||
(cdr sublst)))
|
||||
(mapc (lambda (sublst-icky)
|
||||
(mapc (lambda (tag-icky)
|
||||
(funcall fcn tag-icky (car sublst-icky)))
|
||||
(cdr sublst-icky)))
|
||||
result)
|
||||
result)
|
||||
|
||||
|
|
|
@ -93,7 +93,7 @@ if optional DONT-ERR-IF-NOT-AVAILABLE is non-nil; else throw an error."
|
|||
'(omniscience))
|
||||
)
|
||||
(if dont-err-if-not-available
|
||||
(message "No Global support in %s" default-directory)
|
||||
nil; (message "No Global support in %s" default-directory)
|
||||
(error "No Global support in %s" default-directory))
|
||||
))
|
||||
|
||||
|
|
|
@ -217,6 +217,14 @@ Adds a filename and copies the tags."
|
|||
(semanticdb-full-filename table)
|
||||
tags))
|
||||
|
||||
(defun semanticdb-typecache-faux-namespace (name members)
|
||||
"Create a new namespace tag with NAME and a set of MEMBERS.
|
||||
The new tag will be a faux tag, used as a placeholder in a typecache."
|
||||
(let ((tag (semantic-tag-new-type name "namespace" members nil)))
|
||||
;; Make sure we mark this as a fake tag.
|
||||
(semantic-tag-set-faux tag)
|
||||
tag))
|
||||
|
||||
(defun semanticdb-typecache-merge-streams (cache1 cache2)
|
||||
"Merge into CACHE1 and CACHE2 together. The Caches will be merged in place."
|
||||
(if (or (and (not cache1) (not cache2))
|
||||
|
@ -256,23 +264,22 @@ Adds a filename and copies the tags."
|
|||
(setq ans (cons next ans))
|
||||
;; ELSE - We have a NAME match.
|
||||
(setq type (semantic-tag-type next))
|
||||
(if (semantic-tag-of-type-p prev type) ; Are they the same datatype
|
||||
(if (or (semantic-tag-of-type-p prev type) ; Are they the same datatype
|
||||
(semantic-tag-faux-p prev)
|
||||
(semantic-tag-faux-p next) ; or either a faux tag?
|
||||
)
|
||||
;; Same Class, we can do a merge.
|
||||
(cond
|
||||
((and (semantic-tag-of-class-p next 'type)
|
||||
(string= type "namespace"))
|
||||
;; Namespaces - merge the children together.
|
||||
(setcar ans
|
||||
(semantic-tag-new-type
|
||||
(semanticdb-typecache-faux-namespace
|
||||
(semantic-tag-name prev) ; - they are the same
|
||||
"namespace" ; - we know this as fact
|
||||
(semanticdb-typecache-merge-streams
|
||||
(semanticdb-typecache-safe-tag-members prev)
|
||||
(semanticdb-typecache-safe-tag-members next))
|
||||
nil ; - no attributes
|
||||
))
|
||||
;; Make sure we mark this as a fake tag.
|
||||
(semantic-tag-set-faux (car ans))
|
||||
)
|
||||
((semantic-tag-prototype-p next)
|
||||
;; NEXT is a prototype... so keep previous.
|
||||
|
@ -299,6 +306,12 @@ Adds a filename and copies the tags."
|
|||
;;; Refresh / Query API
|
||||
;;
|
||||
;; Queries that can be made for the typecache.
|
||||
(define-overloadable-function semanticdb-expand-nested-tag (tag)
|
||||
"Expand TAG from fully qualified names.
|
||||
If TAG has fully qualified names, expand it to a series of nested
|
||||
namespaces instead."
|
||||
tag)
|
||||
|
||||
(defmethod semanticdb-typecache-file-tags ((table semanticdb-abstract-table))
|
||||
"No tags available from non-file based tables."
|
||||
nil)
|
||||
|
@ -313,10 +326,13 @@ all included files."
|
|||
|
||||
;; Make sure our file-tags list is up to date.
|
||||
(when (not (oref cache filestream))
|
||||
(let ((tags (semantic-find-tags-by-class 'type table)))
|
||||
(let ((tags (semantic-find-tags-by-class 'type table))
|
||||
(exptags nil))
|
||||
(when tags
|
||||
(setq tags (semanticdb-typecache-safe-tag-list tags table))
|
||||
(oset cache filestream (semanticdb-typecache-merge-streams tags nil)))))
|
||||
(dolist (T tags)
|
||||
(push (semanticdb-expand-nested-tag T) exptags))
|
||||
(oset cache filestream (semanticdb-typecache-merge-streams exptags nil)))))
|
||||
|
||||
;; Return our cache.
|
||||
(oref cache filestream)
|
||||
|
@ -372,6 +388,7 @@ a master list."
|
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;;; Search Routines
|
||||
;;
|
||||
;;;###autoload
|
||||
(define-overloadable-function semanticdb-typecache-find (type &optional path find-file-match)
|
||||
"Search the typecache for TYPE in PATH.
|
||||
|
@ -386,16 +403,20 @@ TYPE is the datatype to find.
|
|||
PATH is the search path, which should be one table object.
|
||||
If FIND-FILE-MATCH is non-nil, then force the file belonging to the
|
||||
found tag to be loaded."
|
||||
(semanticdb-typecache-find-method (or path semanticdb-current-table)
|
||||
type find-file-match))
|
||||
(if (not (and (featurep 'semanticdb) semanticdb-current-database))
|
||||
nil ;; No DB, no search
|
||||
(save-excursion
|
||||
(semanticdb-typecache-find-method (or path semanticdb-current-table)
|
||||
type find-file-match))))
|
||||
|
||||
(defun semanticdb-typecache-find-by-name-helper (name table)
|
||||
"Find the tag with NAME in TABLE, which is from a typecache.
|
||||
If more than one tag has NAME in TABLE, we will prefer the tag that
|
||||
is of class 'type."
|
||||
(let* ((names (semantic-find-tags-by-name name table))
|
||||
(types (semantic-find-tags-by-class 'type names)))
|
||||
(or (car-safe types) (car-safe names))))
|
||||
(nmerge (semanticdb-typecache-merge-streams names nil))
|
||||
(types (semantic-find-tags-by-class 'type nmerge)))
|
||||
(or (car-safe types) (car-safe nmerge))))
|
||||
|
||||
(defmethod semanticdb-typecache-find-method ((table semanticdb-abstract-table)
|
||||
type find-file-match)
|
||||
|
|
|
@ -542,10 +542,25 @@ Optional argument FORCE will force a refresh even if the file in question
|
|||
is not in a buffer. Avoid using FORCE for most uses, as an old cache
|
||||
may be sufficient for the general case. Forced updates can be slow.
|
||||
This will call `semantic-fetch-tags' if that file is in memory."
|
||||
(when (or (semanticdb-in-buffer-p obj) force)
|
||||
(cond
|
||||
;;
|
||||
;; Already in a buffer, just do it.
|
||||
((semanticdb-in-buffer-p obj)
|
||||
(semanticdb-set-buffer obj)
|
||||
(semantic-fetch-tags))
|
||||
;;
|
||||
;; Not in a buffer. Forcing a load.
|
||||
(force
|
||||
;; Patch from Iain Nicol. --
|
||||
;; @TODO: I wonder if there is a way to recycle
|
||||
;; semanticdb-create-table-for-file-not-in-buffer
|
||||
(save-excursion
|
||||
(semanticdb-set-buffer obj)
|
||||
(semantic-fetch-tags))))
|
||||
(let ((buff (semantic-find-file-noselect
|
||||
(semanticdb-full-filename obj))))
|
||||
(set-buffer buff)
|
||||
(semantic-fetch-tags)
|
||||
;; Kill off the buffer if it didn't exist when we were called.
|
||||
(kill-buffer buff))))))
|
||||
|
||||
(defmethod semanticdb-needs-refresh-p ((obj semanticdb-table))
|
||||
"Return non-nil of OBJ's tag list is out of date.
|
||||
|
@ -808,12 +823,14 @@ Always append `semanticdb-project-system-databases' if
|
|||
(setq root (run-hook-with-args-until-success
|
||||
'semanticdb-project-root-functions
|
||||
dir))
|
||||
;; Find roots based on strings
|
||||
(while (and roots (not root))
|
||||
(let ((r (file-truename (car roots))))
|
||||
(if (string-match (concat "^" (regexp-quote r)) dir)
|
||||
(setq root r)))
|
||||
(setq roots (cdr roots)))
|
||||
(if root
|
||||
(setq root (file-truename root))
|
||||
;; Else, Find roots based on strings
|
||||
(while roots
|
||||
(let ((r (file-truename (car roots))))
|
||||
(if (string-match (concat "^" (regexp-quote r)) dir)
|
||||
(setq root r)))
|
||||
(setq roots (cdr roots))))
|
||||
|
||||
;; If no roots are found, use this directory.
|
||||
(unless root (setq root dir))
|
||||
|
|
|
@ -45,7 +45,7 @@ Optional FACE specifies the face to use."
|
|||
))
|
||||
|
||||
(defun semantic-unhighlight-tag (tag)
|
||||
"Unhighlight TAG, restoring it's previous face."
|
||||
"Unhighlight TAG, restoring its previous face."
|
||||
(let ((o (semantic-tag-overlay tag)))
|
||||
(semantic-overlay-put o 'face (car (semantic-overlay-get o 'old-face)))
|
||||
(semantic-overlay-put o 'old-face (cdr (semantic-overlay-get o 'old-face)))
|
||||
|
|
|
@ -118,7 +118,7 @@ Used by the decoration style: `semantic-decoration-on-includes'."
|
|||
'((((class color) (background dark))
|
||||
(:background "#900000"))
|
||||
(((class color) (background light))
|
||||
(:background "#ff5050")))
|
||||
(:background "#fff0f0")))
|
||||
"*Face used to show includes that cannot be found.
|
||||
Used by the decoration style: `semantic-decoration-on-unknown-includes'."
|
||||
:group 'semantic-faces)
|
||||
|
@ -302,16 +302,19 @@ This mode provides a nice context menu on the include statements."
|
|||
)
|
||||
))
|
||||
|
||||
(let ((ol (semantic-decorate-tag tag
|
||||
(semantic-tag-start tag)
|
||||
(semantic-tag-end tag)
|
||||
face))
|
||||
)
|
||||
(semantic-overlay-put ol 'mouse-face 'highlight)
|
||||
(semantic-overlay-put ol 'keymap map)
|
||||
(semantic-overlay-put ol 'help-echo
|
||||
"Header File : mouse-3 - Context menu")
|
||||
)))
|
||||
;; @TODO - if not a tag w/ a position, we need to get one. How?
|
||||
|
||||
(when (semantic-tag-with-position-p tag)
|
||||
(let ((ol (semantic-decorate-tag tag
|
||||
(semantic-tag-start tag)
|
||||
(semantic-tag-end tag)
|
||||
face))
|
||||
)
|
||||
(semantic-overlay-put ol 'mouse-face 'highlight)
|
||||
(semantic-overlay-put ol 'keymap map)
|
||||
(semantic-overlay-put ol 'help-echo
|
||||
"Header File : mouse-3 - Context menu")
|
||||
))))
|
||||
|
||||
;;; Regular Include Functions
|
||||
;;
|
||||
|
|
|
@ -208,7 +208,8 @@ provided mode, not from the current major mode."
|
|||
mode 'semantic-dependency-system-include-path))
|
||||
(edesys (when (and (featurep 'ede) ede-minor-mode
|
||||
ede-object)
|
||||
(ede-system-include-path ede-object)))
|
||||
(ede-system-include-path
|
||||
(if (listp ede-object) (car ede-object) ede-object))))
|
||||
(locp (mode-local-value
|
||||
mode 'semantic-dependency-include-path))
|
||||
(found nil))
|
||||
|
|
|
@ -78,7 +78,8 @@ just the lexical token and not the string."
|
|||
(start (if starttag
|
||||
(semantic-tag-end starttag)
|
||||
(point-min))))
|
||||
(when (re-search-backward comment-start-skip start t)
|
||||
(when (and comment-start-skip
|
||||
(re-search-backward comment-start-skip start t))
|
||||
;; We found a comment that doesn't belong to the body
|
||||
;; of a function.
|
||||
(semantic-doc-snarf-comment-for-tag nosnarf)))
|
||||
|
|
|
@ -310,6 +310,17 @@ FILE, NOWARN, RAWFILE, and WILDCARDS are passed into `find-file-noselect'"
|
|||
(find-file-noselect file nowarn rawfile wildcards)))
|
||||
))
|
||||
|
||||
;;; Database restriction settings
|
||||
;;
|
||||
(defmacro semanticdb-without-unloaded-file-searches (forms)
|
||||
"Execute FORMS with `unloaded' removed from the current throttle."
|
||||
`(let ((semanticdb-find-default-throttle
|
||||
(if (featurep 'semanticdb-find)
|
||||
(remq 'unloaded semanticdb-find-default-throttle)
|
||||
nil)))
|
||||
,forms))
|
||||
(put 'semanticdb-without-unloaded-file-searches 'lisp-indent-function 1)
|
||||
|
||||
|
||||
;; ;;; Editor goodies ;-)
|
||||
;; ;;
|
||||
|
|
|
@ -928,6 +928,12 @@ Lisp code."
|
|||
;; If running interactively, eval declarations and epilogue
|
||||
;; code, then pop to the buffer visiting the generated file.
|
||||
(eval-region (point) (point-max))
|
||||
;; Loop over the defvars and eval them explicitly to force
|
||||
;; them to be evaluated and ready to use.
|
||||
(goto-char (point-min))
|
||||
(while (re-search-forward "(defvar " nil t)
|
||||
(eval-defun nil))
|
||||
;; Move cursor to a logical spot in the generated code.
|
||||
(goto-char (point-min))
|
||||
(pop-to-buffer (current-buffer))
|
||||
;; The generated code has been evaluated and updated into
|
||||
|
|
|
@ -243,6 +243,7 @@ tag with greater section value than LEVEL is found."
|
|||
semantic-imenu-bucketize-file nil
|
||||
semantic-imenu-bucketize-type-members nil
|
||||
senator-step-at-start-end-tag-classes '(section)
|
||||
senator-step-at-tag-classes '(section)
|
||||
semantic-stickyfunc-sticky-classes '(section)
|
||||
)
|
||||
(semantic-install-function-overrides
|
||||
|
|
|
@ -40,7 +40,8 @@
|
|||
(require 'pulse)
|
||||
(eval-when-compile
|
||||
(require 'semantic/analyze)
|
||||
(require 'semantic/analyze/refs))
|
||||
(require 'semantic/analyze/refs)
|
||||
(require 'semantic/find))
|
||||
|
||||
(declare-function imenu--mouse-menu "imenu")
|
||||
|
||||
|
@ -57,14 +58,6 @@
|
|||
:group 'semantic
|
||||
:type semantic-format-tag-custom-list)
|
||||
|
||||
(defvar semantic-ia-cache nil
|
||||
"Cache of the last completion request.
|
||||
Of the form ( POINT . COMPLETIONS ) where POINT is a location in the
|
||||
buffer where the completion was requested. COMPLETONS is the list
|
||||
of semantic tag names that provide logical completions from that
|
||||
location.")
|
||||
(make-variable-buffer-local 'semantic-ia-cache)
|
||||
|
||||
;;; COMPLETION HELPER
|
||||
;;
|
||||
;; This overload function handles inserting a tag
|
||||
|
@ -86,23 +79,16 @@ location.")
|
|||
(insert "("))
|
||||
(t nil))))
|
||||
|
||||
(declare-function semantic-analyze-possible-completions
|
||||
"semantic/analyze/complete")
|
||||
(defalias 'semantic-ia-get-completions 'semantic-ia-get-completions-deprecated
|
||||
"`Semantic-ia-get-completions' is obsolete.
|
||||
Use `semantic-analyze-possible-completions' instead.")
|
||||
|
||||
(defun semantic-ia-get-completions (context point)
|
||||
"Fetch the completion of CONTEXT at POINT.
|
||||
Supports caching."
|
||||
;; Cache the current set of symbols so that we can get at
|
||||
;; them quickly the second time someone presses the
|
||||
;; complete button.
|
||||
(let ((symbols
|
||||
(if (and semantic-ia-cache
|
||||
(= point (car semantic-ia-cache)))
|
||||
(cdr semantic-ia-cache)
|
||||
(semantic-analyze-possible-completions context))))
|
||||
;; Set the cache
|
||||
(setq semantic-ia-cache (cons point symbols))
|
||||
symbols))
|
||||
(defun semantic-ia-get-completions-deprecated (context point)
|
||||
"A function to help transition away from `semantic-ia-get-completions'.
|
||||
Return completions based on CONTEXT at POINT.
|
||||
You should not use this, nor the aliased version.
|
||||
Use `semantic-analyze-possible-completions' instead."
|
||||
(semantic-analyze-possible-completions context))
|
||||
|
||||
;;;###autoload
|
||||
(defun semantic-ia-complete-symbol (&optional pos)
|
||||
|
@ -119,7 +105,7 @@ Completion options are calculated with `semantic-analyze-possible-completions'."
|
|||
;;
|
||||
;; The second step derives completions from that context.
|
||||
(let* ((a (semantic-analyze-current-context pos))
|
||||
(syms (semantic-ia-get-completions a pos))
|
||||
(syms (semantic-analyze-possible-completions a))
|
||||
(pre (car (reverse (oref a prefix)))))
|
||||
;; If PRE was actually an already completed symbol, it doesn't
|
||||
;; come in as a string, but as a tag instead.
|
||||
|
@ -173,7 +159,7 @@ Completion options are calculated with `semantic-analyze-possible-completions'."
|
|||
"Pop up a tooltip for completion at POINT."
|
||||
(interactive "d")
|
||||
(let* ((a (semantic-analyze-current-context point))
|
||||
(syms (semantic-ia-get-completions a point))
|
||||
(syms (semantic-analyze-possible-completions a))
|
||||
(x (mod (- (current-column) (window-hscroll))
|
||||
(window-width)))
|
||||
(y (save-excursion
|
||||
|
@ -212,8 +198,48 @@ Completion options are calculated with `semantic-analyze-possible-completions'."
|
|||
;; tag associated with the current context.
|
||||
(semantic-analyze-interesting-tag ctxt)))
|
||||
)
|
||||
(when pf
|
||||
(message "%s" (semantic-format-tag-summarize pf nil t)))))
|
||||
(if pf
|
||||
(message "%s" (semantic-format-tag-summarize pf nil t))
|
||||
(message "No summary info availalble"))))
|
||||
|
||||
;;; Variants
|
||||
;;
|
||||
;; Show all variants for the symbol under point.
|
||||
|
||||
;;;###autoload
|
||||
(defun semantic-ia-show-variants (point)
|
||||
"Display a list of all variants for the symbol under POINT."
|
||||
(interactive "P")
|
||||
(let* ((ctxt (semantic-analyze-current-context point))
|
||||
(comp nil))
|
||||
|
||||
;; We really want to look at the function if we are on an
|
||||
;; argument. Are there some additional rules we care about for
|
||||
;; changing the CTXT we look at?
|
||||
(when (semantic-analyze-context-functionarg-p ctxt)
|
||||
(goto-char (cdr (oref ctxt bounds)))
|
||||
(setq ctxt (semantic-analyze-current-context (point))))
|
||||
|
||||
;; Get the "completion list", but remove ALL filters to get the master list
|
||||
;; of all the possible things.
|
||||
(setq comp (semantic-analyze-possible-completions ctxt 'no-unique 'no-tc))
|
||||
|
||||
;; Special case for a single type. List the constructors?
|
||||
(when (and (= (length comp) 1) (semantic-tag-of-class-p (car comp) 'type))
|
||||
(setq comp (semantic-find-tags-by-name (semantic-tag-name (car comp))
|
||||
(semantic-tag-type-members (car comp)))))
|
||||
|
||||
;; Display the results.
|
||||
(cond ((= (length comp) 0)
|
||||
(message "No Variants found."))
|
||||
((= (length comp) 1)
|
||||
(message "%s" (semantic-format-tag-summarize (car comp) nil t)))
|
||||
(t
|
||||
(with-output-to-temp-buffer "*Symbol Variants*"
|
||||
(semantic-analyze-princ-sequence comp "" (current-buffer)))
|
||||
(shrink-window-if-larger-than-buffer
|
||||
(get-buffer-window "*Symbol Variants*")))
|
||||
)))
|
||||
|
||||
;;; FAST Jump
|
||||
;;
|
||||
|
@ -354,18 +380,21 @@ See `semantic-ia-fast-jump' for details on how it works.
|
|||
;; The default tries to find a comment in front of the tag
|
||||
;; and then strings off comment prefixes.
|
||||
(let ((doc (semantic-documentation-for-tag (car pf))))
|
||||
(with-output-to-temp-buffer "*TAG DOCUMENTATION*"
|
||||
(princ "Tag: ")
|
||||
(princ (semantic-format-tag-prototype (car pf)))
|
||||
(princ "\n")
|
||||
(princ "\n")
|
||||
(princ "Snarfed Documentation: ")
|
||||
(princ "\n")
|
||||
(princ "\n")
|
||||
(if doc
|
||||
(princ doc)
|
||||
(princ " Documentation unavailable."))
|
||||
)))
|
||||
(if (or (null doc) (string= doc ""))
|
||||
(message "Doc unavailable for: %s"
|
||||
(semantic-format-tag-prototype (car pf)))
|
||||
(with-output-to-temp-buffer "*TAG DOCUMENTATION*"
|
||||
(princ "Tag: ")
|
||||
(princ (semantic-format-tag-prototype (car pf)))
|
||||
(princ "\n")
|
||||
(princ "\n")
|
||||
(princ "Snarfed Documentation: ")
|
||||
(princ "\n")
|
||||
(princ "\n")
|
||||
(if doc
|
||||
(princ doc)
|
||||
(princ " Documentation unavailable."))
|
||||
))))
|
||||
(t
|
||||
(message "Unknown tag.")))
|
||||
))
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
(defvar eldoc-last-message)
|
||||
(declare-function eldoc-message "eldoc")
|
||||
(declare-function semantic-analyze-interesting-tag "semantic/analyze")
|
||||
(declare-function semantic-analyze-unsplit-name "semantic/analyze/fcn")
|
||||
(declare-function semantic-complete-analyze-inline-idle "semantic/complete")
|
||||
(declare-function semanticdb-deep-find-tags-by-name "semantic/db-find")
|
||||
(declare-function semanticdb-save-all-db-idle "semantic/db")
|
||||
|
@ -294,12 +295,18 @@ call additional functions registered with the timer calls."
|
|||
;;
|
||||
;; Unlike the shorter timer, the WORK timer will kick of tasks that
|
||||
;; may take a long time to complete.
|
||||
(defcustom semantic-idle-work-parse-neighboring-files-flag t
|
||||
(defcustom semantic-idle-work-parse-neighboring-files-flag nil
|
||||
"*Non-nil means to parse files in the same dir as the current buffer.
|
||||
Disable to prevent lots of excessive parsing in idle time."
|
||||
:group 'semantic
|
||||
:type 'boolean)
|
||||
|
||||
(defcustom semantic-idle-work-update-headers-flag nil
|
||||
"*Non-nil means to parse through header files in idle time.
|
||||
Disable to prevent idle time parsing of many files. If completion
|
||||
is called that work will be done then instead."
|
||||
:group 'semantic
|
||||
:type 'boolean)
|
||||
|
||||
(defun semantic-idle-work-for-one-buffer (buffer)
|
||||
"Do long-processing work for BUFFER.
|
||||
|
@ -312,6 +319,9 @@ Returns t if all processing succeeded."
|
|||
(semantic-idle-scheduler-refresh-tags)
|
||||
t)
|
||||
|
||||
;; Option to disable this work.
|
||||
semantic-idle-work-update-headers-flag
|
||||
|
||||
;; Force all our include files to get read in so we
|
||||
;; are ready to provide good smart completion and idle
|
||||
;; summary information
|
||||
|
@ -603,6 +613,11 @@ turned on in every Semantic-supported buffer.")
|
|||
;;; SUMMARY MODE
|
||||
;;
|
||||
;; A mode similar to eldoc using semantic
|
||||
(defcustom semantic-idle-truncate-long-summaries t
|
||||
"Truncate summaries that are too long to fit in the minibuffer.
|
||||
This can prevent minibuffer resizing in idle time."
|
||||
:group 'semantic
|
||||
:type 'boolean)
|
||||
|
||||
(defcustom semantic-idle-summary-function
|
||||
'semantic-format-tag-summarize-with-file
|
||||
|
@ -654,21 +669,16 @@ Use the semantic analyzer to find the symbol information."
|
|||
"Return a string message describing the current context.
|
||||
This function will disable loading of previously unloaded files
|
||||
by semanticdb as a time-saving measure."
|
||||
(let (
|
||||
(semanticdb-find-default-throttle
|
||||
(if (featurep 'semantic/db-find)
|
||||
(remq 'unloaded semanticdb-find-default-throttle)
|
||||
nil))
|
||||
)
|
||||
(save-excursion
|
||||
;; use whicever has success first.
|
||||
(or
|
||||
(semantic-idle-summary-current-symbol-keyword)
|
||||
(semanticdb-without-unloaded-file-searches
|
||||
(save-excursion
|
||||
;; use whichever has success first.
|
||||
(or
|
||||
(semantic-idle-summary-current-symbol-keyword)
|
||||
|
||||
(semantic-idle-summary-current-symbol-info-context)
|
||||
(semantic-idle-summary-current-symbol-info-context)
|
||||
|
||||
(semantic-idle-summary-current-symbol-info-brutish)
|
||||
))))
|
||||
(semantic-idle-summary-current-symbol-info-brutish)
|
||||
))))
|
||||
|
||||
(defvar semantic-idle-summary-out-of-context-faces
|
||||
'(
|
||||
|
@ -732,6 +742,14 @@ current tag to display information."
|
|||
(let ((w (1- (window-width (minibuffer-window)))))
|
||||
(if (> (length str) w)
|
||||
(setq str (substring str 0 w)))))
|
||||
;; I borrowed some bits from eldoc to shorten the
|
||||
;; message.
|
||||
(when semantic-idle-truncate-long-summaries
|
||||
(let ((ea-width (1- (window-width (minibuffer-window))))
|
||||
(strlen (length str)))
|
||||
(when (> strlen ea-width)
|
||||
(setq str (substring str 0 ea-width)))))
|
||||
;; Display it
|
||||
(eldoc-message str))))
|
||||
|
||||
(define-minor-mode semantic-idle-summary-mode
|
||||
|
@ -791,12 +809,12 @@ turned on in every Semantic-supported buffer."
|
|||
;; of all uses of the symbol that is under the cursor.
|
||||
;;
|
||||
;; This is to mimic the Eclipse tool of a similar nature.
|
||||
(defvar semantic-idle-summary-highlight-face 'region
|
||||
"Face used for the summary highlight.")
|
||||
(defvar semantic-idle-symbol-highlight-face 'region
|
||||
"Face used for highlighting local symbols.")
|
||||
|
||||
(defun semantic-idle-summary-maybe-highlight (tag)
|
||||
"Perhaps add highlighting onto TAG.
|
||||
TAG was found as the thing under point. If it happens to be
|
||||
(defun semantic-idle-symbol-maybe-highlight (tag)
|
||||
"Perhaps add highlighting to the symbol represented by TAG.
|
||||
TAG was found as the symbol under point. If it happens to be
|
||||
visible, then highlight it."
|
||||
(require 'pulse)
|
||||
(let* ((region (when (and (semantic-tag-p tag)
|
||||
|
@ -817,12 +835,12 @@ visible, then highlight it."
|
|||
(point) (get-buffer-window (current-buffer) 'visible))
|
||||
(if (< (semantic-overlay-end region) (point-at-eol))
|
||||
(pulse-momentary-highlight-overlay
|
||||
region semantic-idle-summary-highlight-face)
|
||||
region semantic-idle-symbol-highlight-face)
|
||||
;; Not the same
|
||||
(pulse-momentary-highlight-region
|
||||
(semantic-overlay-start region)
|
||||
(point-at-eol)
|
||||
semantic-idle-summary-highlight-face)))
|
||||
semantic-idle-symbol-highlight-face)))
|
||||
))
|
||||
((vectorp region)
|
||||
(let ((start (aref region 0))
|
||||
|
@ -842,17 +860,19 @@ visible, then highlight it."
|
|||
(pulse-momentary-highlight-region
|
||||
start (if (<= end (point-at-eol)) end
|
||||
(point-at-eol))
|
||||
semantic-idle-summary-highlight-face)))
|
||||
semantic-idle-symbol-highlight-face)))
|
||||
))))
|
||||
nil))
|
||||
|
||||
(define-semantic-idle-service semantic-idle-tag-highlight
|
||||
"Highlight the tag, and references of the symbol under point.
|
||||
(define-semantic-idle-service semantic-idle-local-symbol-highlight
|
||||
"Highlight the tag and symbol references of the symbol under point.
|
||||
Call `semantic-analyze-current-context' to find the reference tag.
|
||||
Call `semantic-symref-hits-in-region' to identify local references."
|
||||
(require 'pulse)
|
||||
(when (semantic-idle-summary-useful-context-p)
|
||||
(let* ((ctxt (semantic-analyze-current-context))
|
||||
(let* ((ctxt
|
||||
(semanticdb-without-unloaded-file-searches
|
||||
(semantic-analyze-current-context)))
|
||||
(Hbounds (when ctxt (oref ctxt bounds)))
|
||||
(target (when ctxt (car (reverse (oref ctxt prefix)))))
|
||||
(tag (semantic-current-tag))
|
||||
|
@ -862,7 +882,7 @@ Call `semantic-symref-hits-in-region' to identify local references."
|
|||
(when ctxt
|
||||
;; Highlight the original tag? Protect against problems.
|
||||
(condition-case nil
|
||||
(semantic-idle-summary-maybe-highlight target)
|
||||
(semantic-idle-symbol-maybe-highlight target)
|
||||
(error nil))
|
||||
;; Identify all hits in this current tag.
|
||||
(when (semantic-tag-p target)
|
||||
|
@ -871,7 +891,7 @@ Call `semantic-symref-hits-in-region' to identify local references."
|
|||
target (lambda (start end prefix)
|
||||
(when (/= start (car Hbounds))
|
||||
(pulse-momentary-highlight-region
|
||||
start end semantic-idle-summary-highlight-face))
|
||||
start end semantic-idle-symbol-highlight-face))
|
||||
(semantic-throw-on-input 'symref-highlight)
|
||||
)
|
||||
(semantic-tag-start tag)
|
||||
|
@ -891,7 +911,7 @@ If ARG is positive or nil, enable, if it is negative, disable."
|
|||
;; When turning off, disable other idle modes.
|
||||
(when (null global-semantic-idle-scheduler-mode)
|
||||
(global-semantic-idle-summary-mode -1)
|
||||
(global-semantic-idle-tag-highlight-mode -1)
|
||||
(global-semantic-idle-local-symbol-highlight-mode -1)
|
||||
(global-semantic-idle-completions-mode -1))
|
||||
(semantic-toggle-minor-mode-globally
|
||||
'semantic-idle-scheduler-mode
|
||||
|
@ -903,25 +923,23 @@ If ARG is positive or nil, enable, if it is negative, disable."
|
|||
;; This mode uses tooltips to display a (hopefully) short list of possible
|
||||
;; completions available for the text under point. It provides
|
||||
;; NO provision for actually filling in the values from those completions.
|
||||
(defun semantic-idle-completions-end-of-symbol-p ()
|
||||
"Return non-nil if the cursor is at the END of a symbol.
|
||||
If the cursor is in the middle of a symbol, then we shouldn't be
|
||||
doing fancy completions."
|
||||
(not (looking-at "\\w\\|\\s_")))
|
||||
|
||||
(defun semantic-idle-completion-list-default ()
|
||||
"Calculate and display a list of completions."
|
||||
(when (semantic-idle-summary-useful-context-p)
|
||||
(when (and (semantic-idle-summary-useful-context-p)
|
||||
(semantic-idle-completions-end-of-symbol-p))
|
||||
;; This mode can be fragile. Ignore problems.
|
||||
;; If something doesn't do what you expect, run
|
||||
;; the below command by hand instead.
|
||||
(condition-case nil
|
||||
(let (
|
||||
;; Don't go loading in oodles of header libraries in
|
||||
;; IDLE time.
|
||||
(semanticdb-find-default-throttle
|
||||
(if (featurep 'semantic/db-find)
|
||||
(remq 'unloaded semanticdb-find-default-throttle)
|
||||
nil))
|
||||
)
|
||||
;; Use idle version.
|
||||
(require 'semantic/complete)
|
||||
(semantic-complete-analyze-inline-idle)
|
||||
(semanticdb-without-unloaded-file-searches
|
||||
;; Use idle version.
|
||||
(semantic-complete-analyze-inline-idle)
|
||||
)
|
||||
(error nil))
|
||||
))
|
||||
|
@ -949,6 +967,347 @@ completion.
|
|||
;; Add the ability to override sometime.
|
||||
(semantic-idle-completion-list-default))
|
||||
|
||||
|
||||
;;; Breadcrumbs for tag under point
|
||||
;;
|
||||
;; Service that displays a breadcrumbs indication of the tag under
|
||||
;; point and its parents in the header or mode line.
|
||||
;;
|
||||
|
||||
(defcustom semantic-idle-breadcrumbs-display-function
|
||||
#'semantic-idle-breadcrumbs--display-in-header-line
|
||||
"Function to display the tag under point in idle time.
|
||||
This function should take a list of Semantic tags as its only
|
||||
argument. The tags are sorted according to their nesting order,
|
||||
starting with the outermost tag. The function should call
|
||||
`semantic-idle-breadcrumbs-format-tag-list-function' to convert
|
||||
the tag list into a string."
|
||||
:group 'semantic
|
||||
:type '(choice
|
||||
(const :tag "Display in header line"
|
||||
semantic-idle-breadcrumbs--display-in-header-line)
|
||||
(const :tag "Display in mode line"
|
||||
semantic-idle-breadcrumbs--display-in-mode-line)
|
||||
(function :tag "Other function")))
|
||||
|
||||
(defcustom semantic-idle-breadcrumbs-format-tag-list-function
|
||||
#'semantic-idle-breadcrumbs--format-linear
|
||||
"Function to format the list of tags containing point.
|
||||
This function should take a list of Semantic tags and an optional
|
||||
maximum length of the produced string as its arguments. The
|
||||
maximum length is a hint and can be ignored. When the maximum
|
||||
length is omitted, an unconstrained string should be
|
||||
produced. The tags are sorted according to their nesting order,
|
||||
starting with the outermost tag. Single tags should be formatted
|
||||
using `semantic-idle-breadcrumbs-format-tag-function' unless
|
||||
special formatting is required."
|
||||
:group 'semantic
|
||||
:type '(choice
|
||||
(const :tag "Format tags as list, innermost last"
|
||||
semantic-idle-breadcrumbs--format-linear)
|
||||
(const :tag "Innermost tag with details, followed by remaining tags"
|
||||
semantic-idle-breadcrumbs--format-innermost-first)
|
||||
(function :tag "Other function")))
|
||||
|
||||
(defcustom semantic-idle-breadcrumbs-format-tag-function
|
||||
#'semantic-format-tag-abbreviate
|
||||
"Function to call to format information about tags.
|
||||
This function should take a single argument, a Semantic tag, and
|
||||
return a string to display.
|
||||
Some useful functions are found in `semantic-format-tag-functions'."
|
||||
:group 'semantic
|
||||
:type semantic-format-tag-custom-list)
|
||||
|
||||
(defcustom semantic-idle-breadcrumbs-separator 'mode-specific
|
||||
"Specify how to separate tags in the breadcrumbs string.
|
||||
An arbitrary string or a mode-specific scope nesting
|
||||
string (like, for example, \"::\" in C++, or \".\" in Java) can
|
||||
be used."
|
||||
:group 'semantic
|
||||
:type '(choice
|
||||
(const :tag "Use mode specific separator"
|
||||
mode-specific)
|
||||
(string :tag "Specify separator string")))
|
||||
|
||||
(defcustom semantic-idle-breadcrumbs-header-line-prefix
|
||||
semantic-stickyfunc-indent-string ;; TODO not optimal
|
||||
"String used to indent the breadcrumbs string.
|
||||
Customize this string to match the space used by scrollbars and
|
||||
fringe."
|
||||
:group 'semantic
|
||||
:type 'string)
|
||||
|
||||
(defvar semantic-idle-breadcrumbs-popup-menu nil
|
||||
"Menu used when a tag displayed by `semantic-idle-breadcrumbs-mode' is clicked.")
|
||||
|
||||
(defun semantic-idle-breadcrumbs--popup-menu (event)
|
||||
"Popup a menu that displays things to do to the clicked tag.
|
||||
Argument EVENT describes the event that caused this function to
|
||||
be called."
|
||||
(interactive "e")
|
||||
(let ((old-window (selected-window))
|
||||
(window (semantic-event-window event)))
|
||||
(select-window window t)
|
||||
(semantic-popup-menu semantic-idle-breadcrumbs-popup-menu)
|
||||
(select-window old-window)))
|
||||
|
||||
(defmacro semantic-idle-breadcrumbs--tag-function (function)
|
||||
"Return lambda expression calling FUNCTION when called from a popup."
|
||||
`(lambda (event)
|
||||
(interactive "e")
|
||||
(let* ((old-window (selected-window))
|
||||
(window (semantic-event-window event))
|
||||
(column (car (nth 6 (nth 1 event)))) ;; TODO semantic-event-column?
|
||||
(tag (progn
|
||||
(select-window window t)
|
||||
(plist-get
|
||||
(text-properties-at column header-line-format)
|
||||
'tag))))
|
||||
(,function tag)
|
||||
(select-window old-window)))
|
||||
)
|
||||
|
||||
;; TODO does this work for mode-line case?
|
||||
(defvar semantic-idle-breadcrumbs-popup-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
;; mouse-1 goes to clicked tag
|
||||
(define-key map
|
||||
[ header-line mouse-1 ]
|
||||
(semantic-idle-breadcrumbs--tag-function
|
||||
semantic-go-to-tag))
|
||||
;; mouse-3 pops up a context menu
|
||||
(define-key map
|
||||
[ header-line mouse-3 ]
|
||||
'semantic-idle-breadcrumbs--popup-menu)
|
||||
map)
|
||||
"Keymap for semantic idle breadcrumbs minor mode.")
|
||||
|
||||
(easy-menu-define
|
||||
semantic-idle-breadcrumbs-popup-menu
|
||||
semantic-idle-breadcrumbs-popup-map
|
||||
"Semantic Breadcrumbs Mode Menu"
|
||||
(list
|
||||
"Breadcrumb Tag"
|
||||
(semantic-menu-item
|
||||
(vector
|
||||
"Go to Tag"
|
||||
(semantic-idle-breadcrumbs--tag-function
|
||||
semantic-go-to-tag)
|
||||
:active t
|
||||
:help "Jump to this tag"))
|
||||
;; TODO these entries need minor changes (optional tag argument) in
|
||||
;; senator-copy-tag etc
|
||||
;; (semantic-menu-item
|
||||
;; (vector
|
||||
;; "Copy Tag"
|
||||
;; (semantic-idle-breadcrumbs--tag-function
|
||||
;; senator-copy-tag)
|
||||
;; :active t
|
||||
;; :help "Copy this tag"))
|
||||
;; (semantic-menu-item
|
||||
;; (vector
|
||||
;; "Kill Tag"
|
||||
;; (semantic-idle-breadcrumbs--tag-function
|
||||
;; senator-kill-tag)
|
||||
;; :active t
|
||||
;; :help "Kill tag text to the kill ring, and copy the tag to
|
||||
;; the tag ring"))
|
||||
;; (semantic-menu-item
|
||||
;; (vector
|
||||
;; "Copy Tag to Register"
|
||||
;; (semantic-idle-breadcrumbs--tag-function
|
||||
;; senator-copy-tag-to-register)
|
||||
;; :active t
|
||||
;; :help "Copy this tag"))
|
||||
;; (semantic-menu-item
|
||||
;; (vector
|
||||
;; "Narrow to Tag"
|
||||
;; (semantic-idle-breadcrumbs--tag-function
|
||||
;; senator-narrow-to-defun)
|
||||
;; :active t
|
||||
;; :help "Narrow to the bounds of the current tag"))
|
||||
;; (semantic-menu-item
|
||||
;; (vector
|
||||
;; "Fold Tag"
|
||||
;; (semantic-idle-breadcrumbs--tag-function
|
||||
;; senator-fold-tag-toggle)
|
||||
;; :active t
|
||||
;; :style 'toggle
|
||||
;; :selected '(let ((tag (semantic-current-tag)))
|
||||
;; (and tag (semantic-tag-folded-p tag)))
|
||||
;; :help "Fold the current tag to one line"))
|
||||
"---"
|
||||
(semantic-menu-item
|
||||
(vector
|
||||
"About this Header Line"
|
||||
(lambda ()
|
||||
(interactive)
|
||||
(describe-function 'semantic-idle-breadcrumbs-mode))
|
||||
:active t
|
||||
:help "Display help about this header line."))
|
||||
)
|
||||
)
|
||||
|
||||
(define-semantic-idle-service semantic-idle-breadcrumbs
|
||||
"Display breadcrumbs for the tag under point and its parents."
|
||||
(let* ((scope (semantic-calculate-scope))
|
||||
(tag-list (if scope
|
||||
;; If there is a scope, extract the tag and its
|
||||
;; parents.
|
||||
(append (oref scope parents)
|
||||
(when (oref scope tag)
|
||||
(list (oref scope tag))))
|
||||
;; Fall back to tags by overlay
|
||||
(semantic-find-tag-by-overlay))))
|
||||
;; Display the tags.
|
||||
(funcall semantic-idle-breadcrumbs-display-function tag-list)))
|
||||
|
||||
(defun semantic-idle-breadcrumbs--display-in-header-line (tag-list)
|
||||
"Display the tags in TAG-LIST in the header line of their buffer."
|
||||
(let ((width (- (nth 2 (window-edges))
|
||||
(nth 0 (window-edges)))))
|
||||
;; Format TAG-LIST and put the formatted string into the header
|
||||
;; line.
|
||||
(setq header-line-format
|
||||
(concat
|
||||
semantic-idle-breadcrumbs-header-line-prefix
|
||||
(if tag-list
|
||||
(semantic-idle-breadcrumbs--format-tag-list
|
||||
tag-list
|
||||
(- width
|
||||
(length semantic-idle-breadcrumbs-header-line-prefix)))
|
||||
(propertize
|
||||
"<not on tags>"
|
||||
'face
|
||||
'font-lock-comment-face)))))
|
||||
|
||||
;; Update the header line.
|
||||
(force-mode-line-update))
|
||||
|
||||
(defun semantic-idle-breadcrumbs--display-in-mode-line (tag-list)
|
||||
"Display the tags in TAG-LIST in the mode line of their buffer.
|
||||
TODO THIS FUNCTION DOES NOT WORK YET."
|
||||
|
||||
(error "This function does not work yet")
|
||||
|
||||
(let ((width (- (nth 2 (window-edges))
|
||||
(nth 0 (window-edges)))))
|
||||
(setq mode-line-format
|
||||
(semantic-idle-breadcrumbs--format-tag-list tag-list width)))
|
||||
|
||||
(force-mode-line-update))
|
||||
|
||||
(defun semantic-idle-breadcrumbs--format-tag-list (tag-list max-length)
|
||||
"Format TAG-LIST using configured functions respecting MAX-LENGTH.
|
||||
If the initial formatting result is longer than MAX-LENGTH, it is
|
||||
shortened at the beginning."
|
||||
;; Format TAG-LIST using the configured formatting function.
|
||||
(let* ((complete-format (funcall
|
||||
semantic-idle-breadcrumbs-format-tag-list-function
|
||||
tag-list max-length))
|
||||
;; Determine length of complete format.
|
||||
(complete-length (length complete-format)))
|
||||
;; Shorten string if necessary.
|
||||
(if (<= complete-length max-length)
|
||||
complete-format
|
||||
(concat "... "
|
||||
(substring
|
||||
complete-format
|
||||
(- complete-length (- max-length 4))))))
|
||||
)
|
||||
|
||||
(defun semantic-idle-breadcrumbs--format-linear
|
||||
(tag-list &optional max-length)
|
||||
"Format TAG-LIST as a linear list, starting with the outermost tag.
|
||||
MAX-LENGTH is not used."
|
||||
(require 'semantic/analyze/fcn)
|
||||
(let* ((format-pieces (mapcar
|
||||
#'semantic-idle-breadcrumbs--format-tag
|
||||
tag-list))
|
||||
;; Format tag list, putting configured separators between the
|
||||
;; tags.
|
||||
(complete-format (cond
|
||||
;; Mode specific separator.
|
||||
((eq semantic-idle-breadcrumbs-separator
|
||||
'mode-specific)
|
||||
(semantic-analyze-unsplit-name format-pieces))
|
||||
|
||||
;; Custom separator.
|
||||
((stringp semantic-idle-breadcrumbs-separator)
|
||||
(mapconcat
|
||||
#'identity
|
||||
format-pieces
|
||||
semantic-idle-breadcrumbs-separator)))))
|
||||
complete-format)
|
||||
)
|
||||
|
||||
(defun semantic-idle-breadcrumbs--format-innermost-first
|
||||
(tag-list &optional max-length)
|
||||
"Format TAG-LIST placing the innermost tag first, separated from its parents.
|
||||
If MAX-LENGTH is non-nil, the innermost tag is shortened."
|
||||
(let* (;; Separate and format remaining tags. Calculate length of
|
||||
;; resulting string.
|
||||
(rest-tags (butlast tag-list))
|
||||
(rest-format (if rest-tags
|
||||
(concat
|
||||
" | "
|
||||
(semantic-idle-breadcrumbs--format-linear
|
||||
rest-tags))
|
||||
""))
|
||||
(rest-length (length rest-format))
|
||||
;; Format innermost tag and calculate length of resulting
|
||||
;; string.
|
||||
(inner-format (semantic-idle-breadcrumbs--format-tag
|
||||
(car (last tag-list))
|
||||
#'semantic-format-tag-prototype))
|
||||
(inner-length (length inner-format))
|
||||
;; Calculate complete length and shorten string for innermost
|
||||
;; tag if MAX-LENGTH is non-nil and the complete string is
|
||||
;; too long.
|
||||
(complete-length (+ inner-length rest-length))
|
||||
(inner-short (if (and max-length
|
||||
(<= complete-length max-length))
|
||||
inner-format
|
||||
(concat (substring
|
||||
inner-format
|
||||
0
|
||||
(- inner-length
|
||||
(- complete-length max-length)
|
||||
4))
|
||||
" ..."))))
|
||||
;; Concat both parts.
|
||||
(concat inner-short rest-format))
|
||||
)
|
||||
|
||||
(defun semantic-idle-breadcrumbs--format-tag (tag &optional format-function)
|
||||
"Format TAG using the configured function or FORMAT-FUNCTION.
|
||||
This function also adds text properties for help-echo, mouse
|
||||
highlighting and a keymap."
|
||||
(let ((formatted (funcall
|
||||
(or format-function
|
||||
semantic-idle-breadcrumbs-format-tag-function)
|
||||
tag nil t)))
|
||||
(add-text-properties
|
||||
0 (length formatted)
|
||||
(list
|
||||
'tag
|
||||
tag
|
||||
'help-echo
|
||||
(format
|
||||
"Tag %s
|
||||
Type: %s
|
||||
mouse-1: jump to tag
|
||||
mouse-3: popup context menu"
|
||||
(semantic-tag-name tag)
|
||||
(semantic-tag-class tag))
|
||||
'mouse-face
|
||||
'highlight
|
||||
'keymap
|
||||
semantic-idle-breadcrumbs-popup-map)
|
||||
formatted)
|
||||
formatted))
|
||||
|
||||
|
||||
(provide 'semantic/idle)
|
||||
|
||||
;; Local variables:
|
||||
|
|
|
@ -99,7 +99,7 @@ A nil value means to keep them in the same order.
|
|||
Overriden to nil if `semantic-imenu-bucketize-file' is nil."
|
||||
:group 'semantic-imenu
|
||||
:type 'boolean)
|
||||
(make-variable-buffer-local 'semantic-imenu-bucketize-type-parts)
|
||||
(make-variable-buffer-local 'semantic-imenu-bucketize-type-members)
|
||||
(semantic-varalias-obsolete 'semantic-imenu-bucketize-type-parts
|
||||
'semantic-imenu-bucketize-type-members "23.2")
|
||||
|
||||
|
|
|
@ -864,42 +864,45 @@ and variable state from the current buffer."
|
|||
semantic-lex-spp-expanded-macro-stack
|
||||
))
|
||||
)
|
||||
(with-current-buffer buf
|
||||
(erase-buffer)
|
||||
;; Below is a painful hack to make sure everything is setup correctly.
|
||||
(when (not (eq major-mode mode))
|
||||
(save-match-data
|
||||
(if (> semantic-lex-spp-hack-depth 5)
|
||||
nil
|
||||
(with-current-buffer buf
|
||||
(erase-buffer)
|
||||
;; Below is a painful hack to make sure everything is setup correctly.
|
||||
(when (not (eq major-mode mode))
|
||||
(save-match-data
|
||||
|
||||
;; Protect against user-hooks that throw errors.
|
||||
(condition-case nil
|
||||
(funcall mode)
|
||||
(error nil))
|
||||
;; Protect against user-hooks that throw errors.
|
||||
(condition-case nil
|
||||
(funcall mode)
|
||||
(error nil))
|
||||
|
||||
;; Hack in mode-local
|
||||
(activate-mode-local-bindings)
|
||||
;; CHEATER! The following 3 lines are from
|
||||
;; `semantic-new-buffer-fcn', but we don't want to turn
|
||||
;; on all the other annoying modes for this little task.
|
||||
(setq semantic-new-buffer-fcn-was-run t)
|
||||
(semantic-lex-init)
|
||||
(semantic-clear-toplevel-cache)
|
||||
(remove-hook 'semantic-lex-reset-hooks 'semantic-lex-spp-reset-hook
|
||||
t)
|
||||
))
|
||||
;; Hack in mode-local
|
||||
(activate-mode-local-bindings)
|
||||
|
||||
;; Second Cheat: copy key variables regarding macro state from the
|
||||
;; the originating buffer we are parsing. We need to do this every time
|
||||
;; since the state changes.
|
||||
(dolist (V important-vars)
|
||||
(set V (semantic-buffer-local-value V origbuff)))
|
||||
(insert text)
|
||||
(goto-char (point-min))
|
||||
;; CHEATER! The following 3 lines are from
|
||||
;; `semantic-new-buffer-fcn', but we don't want to turn
|
||||
;; on all the other annoying modes for this little task.
|
||||
(setq semantic-new-buffer-fcn-was-run t)
|
||||
(semantic-lex-init)
|
||||
(semantic-clear-toplevel-cache)
|
||||
(remove-hook 'semantic-lex-reset-hooks 'semantic-lex-spp-reset-hook
|
||||
t)
|
||||
))
|
||||
|
||||
(setq fresh-toks (semantic-lex-spp-stream-for-macro (point-max))))
|
||||
;; Second Cheat: copy key variables regarding macro state from the
|
||||
;; the originating buffer we are parsing. We need to do this every time
|
||||
;; since the state changes.
|
||||
(dolist (V important-vars)
|
||||
(set V (semantic-buffer-local-value V origbuff)))
|
||||
(insert text)
|
||||
(goto-char (point-min))
|
||||
|
||||
(dolist (tok fresh-toks)
|
||||
(when (memq (semantic-lex-token-class tok) '(symbol semantic-list))
|
||||
(setq toks (cons tok toks))))
|
||||
(setq fresh-toks (semantic-lex-spp-stream-for-macro (point-max))))
|
||||
|
||||
(dolist (tok fresh-toks)
|
||||
(when (memq (semantic-lex-token-class tok) '(symbol semantic-list))
|
||||
(setq toks (cons tok toks)))))
|
||||
|
||||
(nreverse toks)))
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@
|
|||
:documentation
|
||||
"The list of types currently in scope.
|
||||
For C++, this would contain anonymous namespaces known, and
|
||||
anything labled by a `using' statement.")
|
||||
anything labeled by a `using' statement.")
|
||||
(parents :initform nil
|
||||
:documentation
|
||||
"List of parents in scope w/in the body of this function.
|
||||
|
@ -239,8 +239,11 @@ are from nesting data types."
|
|||
)
|
||||
;; In case of arg lists or some-such, throw out non-types.
|
||||
(while (and stack (not (semantic-tag-of-class-p pparent 'type)))
|
||||
(setq stack (cdr stack)
|
||||
pparent (car (cdr stack))))
|
||||
(setq stack (cdr stack) pparent (car (cdr stack))))
|
||||
|
||||
;; Remove duplicates
|
||||
(while (member pparent scopetypes)
|
||||
(setq stack (cdr stack) pparent (car (cdr stack))))
|
||||
|
||||
;; Step 1:
|
||||
;; Analyze the stack of tags we are nested in as parents.
|
||||
|
@ -611,7 +614,7 @@ whose tags can be searched when needed, OR it may be a scope object."
|
|||
;; to do any of the stuff related to variables and what-not.
|
||||
(setq tmpscope (semantic-scope-cache "mini"))
|
||||
(let* ( ;; Step 1:
|
||||
(scopetypes (semantic-analyze-scoped-types (point)))
|
||||
(scopetypes (cons type (semantic-analyze-scoped-types (point))))
|
||||
(parents (semantic-analyze-scope-nested-tags (point) scopetypes))
|
||||
;;(parentinherited (semantic-analyze-scope-lineage-tags parents scopetypes))
|
||||
(lscope nil)
|
||||
|
|
|
@ -463,7 +463,7 @@ include the default behavior, and merely extend your own."
|
|||
)
|
||||
|
||||
(defun semantic-tag-external-member-parent-default (tag)
|
||||
"Return the name of TAGs parent only if TAG is not defined in it's parent."
|
||||
"Return the name of TAGs parent only if TAG is not defined in its parent."
|
||||
;; Use only the extra spec because a type has a parent which
|
||||
;; means something completely different.
|
||||
(let ((tp (semantic-tag-get-attribute tag :parent)))
|
||||
|
@ -473,7 +473,7 @@ include the default behavior, and merely extend your own."
|
|||
(define-overloadable-function semantic-tag-external-member-p (parent tag)
|
||||
"Return non-nil if PARENT is the parent of TAG.
|
||||
TAG is an external member of PARENT when it is somehow tagged
|
||||
as having PARENT as it's parent.
|
||||
as having PARENT as its parent.
|
||||
PARENT and TAG must both be semantic tags.
|
||||
|
||||
The default behavior, if not overridden with
|
||||
|
|
|
@ -71,6 +71,7 @@
|
|||
(declare-function data-debug-insert-object-slots "eieio-datadebug")
|
||||
(declare-function ede-toplevel "ede/files")
|
||||
(declare-function ede-project-root-directory "ede/files")
|
||||
(declare-function ede-up-directory "ede/files")
|
||||
|
||||
;;; Code:
|
||||
(defvar semantic-symref-tool 'detect
|
||||
|
@ -98,16 +99,27 @@ is supported.
|
|||
|
||||
If no tools are supported, then 'grep is assumed.")
|
||||
|
||||
(defun semantic-symref-calculate-rootdir ()
|
||||
"Calculate the root directory for a symref search.
|
||||
Start with and EDE project, or use the default directory."
|
||||
(let* ((rootproj (when (and (featurep 'ede) ede-minor-mode)
|
||||
(ede-toplevel)))
|
||||
(rootdirbase (if rootproj
|
||||
(ede-project-root-directory rootproj)
|
||||
default-directory)))
|
||||
(if (and rootproj (condition-case nil
|
||||
;; Hack for subprojects.
|
||||
(oref rootproj :metasubproject)
|
||||
(error nil)))
|
||||
(ede-up-directory rootdirbase)
|
||||
rootdirbase)))
|
||||
|
||||
(defun semantic-symref-detect-symref-tool ()
|
||||
"Detect the symref tool to use for the current buffer."
|
||||
(if (not (eq semantic-symref-tool 'detect))
|
||||
semantic-symref-tool
|
||||
;; We are to perform a detection for the right tool to use.
|
||||
(let* ((rootproj (when (and (featurep 'ede) ede-minor-mode)
|
||||
(ede-toplevel)))
|
||||
(rootdir (if rootproj
|
||||
(ede-project-root-directory rootproj)
|
||||
default-directory))
|
||||
(let* ((rootdir (semantic-symref-calculate-rootdir))
|
||||
(tools semantic-symref-tool-alist))
|
||||
(while (and tools (eq semantic-symref-tool 'detect))
|
||||
(when (funcall (car (car tools)) rootdir)
|
||||
|
|
|
@ -30,10 +30,6 @@
|
|||
(require 'semantic/symref)
|
||||
(require 'grep)
|
||||
|
||||
(defvar ede-minor-mode)
|
||||
(declare-function ede-toplevel "ede/files")
|
||||
(declare-function ede-project-root-directory "ede/files")
|
||||
|
||||
;;; Code:
|
||||
|
||||
;;; GREP
|
||||
|
@ -86,7 +82,7 @@ Optional argument MODE specifies the `major-mode' to test."
|
|||
" -o ")
|
||||
" \\)"))
|
||||
(t
|
||||
(error "Configuration for `semantic-symref-tool-grep' needed for %s" major-mode))
|
||||
(error "Customize `semantic-symref-filepattern-alist' for %s" major-mode))
|
||||
)))
|
||||
|
||||
(defvar semantic-symref-grep-expand-keywords
|
||||
|
@ -119,6 +115,12 @@ GREPPATTERN is the pattern used by grep."
|
|||
;;(message "New command: %s" cmd)
|
||||
cmd))
|
||||
|
||||
(defcustom semantic-symref-grep-shell "sh"
|
||||
"The shell command to use for executing find/grep.
|
||||
This shell should support pipe redirect syntax."
|
||||
:group 'semantic
|
||||
:type 'string)
|
||||
|
||||
(defmethod semantic-symref-perform-search ((tool semantic-symref-tool-grep))
|
||||
"Perform a search with Grep."
|
||||
;; Grep doesn't support some types of searches.
|
||||
|
@ -129,19 +131,7 @@ GREPPATTERN is the pattern used by grep."
|
|||
;; Find the root of the project, and do a find-grep...
|
||||
(let* (;; Find the file patterns to use.
|
||||
(pat (cdr (assoc major-mode semantic-symref-filepattern-alist)))
|
||||
(rootdir (cond
|
||||
;; Project root via EDE.
|
||||
((eq (oref tool :searchscope) 'project)
|
||||
(let ((rootproj (when (and (featurep 'ede) ede-minor-mode)
|
||||
(ede-toplevel))))
|
||||
(if rootproj
|
||||
(ede-project-root-directory rootproj)
|
||||
default-directory)))
|
||||
;; Calculate the target files as just in
|
||||
;; this directory... cause I'm lazy.
|
||||
((eq (oref tool :searchscope) 'target)
|
||||
default-directory)
|
||||
))
|
||||
(rootdir (semantic-symref-calculate-rootdir))
|
||||
(filepattern (semantic-symref-derive-find-filepatterns))
|
||||
;; Grep based flags.
|
||||
(grepflags (cond ((eq (oref tool :resulttype) 'file)
|
||||
|
@ -168,10 +158,10 @@ GREPPATTERN is the pattern used by grep."
|
|||
(let ((cmd (concat "find " default-directory " -type f " filepattern " -print0 "
|
||||
"| xargs -0 grep -H " grepflags "-e " greppat)))
|
||||
;;(message "Old command: %s" cmd)
|
||||
(call-process "sh" nil b nil "-c" cmd)
|
||||
(call-process semantic-symref-grep-shell nil b nil "-c" cmd)
|
||||
)
|
||||
(let ((cmd (semantic-symref-grep-use-template rootdir filepattern grepflags greppat)))
|
||||
(call-process "sh" nil b nil "-c" cmd))
|
||||
(call-process semantic-symref-grep-shell nil b nil "-c" cmd))
|
||||
))
|
||||
(setq ans (semantic-symref-parse-tool-output tool b))
|
||||
;; Return the answer
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
(require 'semantic/symref)
|
||||
(require 'semantic/complete)
|
||||
(require 'semantic/senator)
|
||||
(require 'pulse)
|
||||
|
||||
;;; Code:
|
||||
|
@ -42,9 +43,9 @@
|
|||
"Find references to the current tag.
|
||||
This command uses the currently configured references tool within the
|
||||
current project to find references to the current tag. The
|
||||
references are the organized by file and the name of the function
|
||||
references are organized by file and the name of the function
|
||||
they are used in.
|
||||
Display the references in`semantic-symref-results-mode'."
|
||||
Display the references in `semantic-symref-results-mode'."
|
||||
(interactive)
|
||||
(semantic-fetch-tags)
|
||||
(let ((ct (semantic-current-tag))
|
||||
|
@ -65,6 +66,24 @@ Display the references in`semantic-symref-results-mode'."
|
|||
"Find references to the symbol SYM.
|
||||
This command uses the currently configured references tool within the
|
||||
current project to find references to the input SYM. The
|
||||
references are organized by file and the name of the function
|
||||
they are used in.
|
||||
Display the references in `semantic-symref-results-mode'."
|
||||
(interactive (list (semantic-tag-name (semantic-complete-read-tag-buffer-deep
|
||||
"Symrefs for: "))))
|
||||
(semantic-fetch-tags)
|
||||
(let ((res nil)
|
||||
)
|
||||
;; Gather results and tags
|
||||
(message "Gathering References...")
|
||||
(setq res (semantic-symref-find-references-by-name sym))
|
||||
(semantic-symref-produce-list-on-results res sym)))
|
||||
|
||||
;;;###autoload
|
||||
(defun semantic-symref-regexp (sym)
|
||||
"Find references to the a symbol regexp SYM.
|
||||
This command uses the currently configured references tool within the
|
||||
current project to find references to the input SYM. The
|
||||
references are the organized by file and the name of the function
|
||||
they are used in.
|
||||
Display the references in`semantic-symref-results-mode'."
|
||||
|
@ -75,7 +94,7 @@ Display the references in`semantic-symref-results-mode'."
|
|||
)
|
||||
;; Gather results and tags
|
||||
(message "Gathering References...")
|
||||
(setq res (semantic-symref-find-references-by-name sym))
|
||||
(setq res (semantic-symref-find-text sym))
|
||||
(semantic-symref-produce-list-on-results res sym)))
|
||||
|
||||
|
||||
|
@ -110,11 +129,59 @@ Display the references in`semantic-symref-results-mode'."
|
|||
(define-key km "n" 'semantic-symref-list-next-line)
|
||||
(define-key km "p" 'semantic-symref-list-prev-line)
|
||||
(define-key km "q" 'semantic-symref-hide-buffer)
|
||||
(define-key km "\C-c\C-e" 'semantic-symref-list-expand-all)
|
||||
(define-key km "\C-c\C-r" 'semantic-symref-list-contract-all)
|
||||
(define-key km "R" 'semantic-symref-list-rename-open-hits)
|
||||
(define-key km "(" 'semantic-symref-list-create-macro-on-open-hit)
|
||||
(define-key km "E" 'semantic-symref-list-call-macro-on-open-hits)
|
||||
km)
|
||||
"Keymap used in `semantic-symref-results-mode'.")
|
||||
|
||||
(defvar semantic-symref-list-menu-entries
|
||||
(list
|
||||
"Symref"
|
||||
(semantic-menu-item
|
||||
["Toggle Line Open"
|
||||
semantic-symref-list-toggle-showing
|
||||
:active t
|
||||
:help "Toggle the current line open or closed."
|
||||
])
|
||||
(semantic-menu-item
|
||||
["Expand All Entries"
|
||||
semantic-symref-list-expand-all
|
||||
:active t
|
||||
:help "Expand every expandable entry."
|
||||
])
|
||||
(semantic-menu-item
|
||||
["Contract All Entries"
|
||||
semantic-symref-list-contract-all
|
||||
:active t
|
||||
:help "Close every expandable entry."
|
||||
])
|
||||
(semantic-menu-item
|
||||
["Rename Symbol in Open hits"
|
||||
semantic-symref-list-rename-open-hits
|
||||
:active t
|
||||
:help "Rename the searched for symbol in all hits that are currently open."
|
||||
])
|
||||
)
|
||||
"Menu entries for the Semantic Symref list mode.")
|
||||
|
||||
(defvar semantic-symref-list-menu nil
|
||||
"Menu keymap build from `semantic-symref-results-mode'.")
|
||||
|
||||
(easy-menu-define semantic-symref-list-menu
|
||||
semantic-symref-results-mode-map
|
||||
"Symref Mode Menu"
|
||||
semantic-symref-list-menu-entries)
|
||||
|
||||
(defcustom semantic-symref-auto-expand-results nil
|
||||
"Non-nil to expand symref results on buffer creation."
|
||||
:group 'semantic-symref
|
||||
:type 'boolean)
|
||||
|
||||
(defcustom semantic-symref-results-mode-hook nil
|
||||
"*Hook run when `semantic-symref-results-mode' starts."
|
||||
"Hook run when `semantic-symref-results-mode' starts."
|
||||
:group 'semantic-symref
|
||||
:type 'hook)
|
||||
|
||||
|
@ -189,6 +256,10 @@ Some useful functions are found in `semantic-format-tag-functions'."
|
|||
|
||||
))
|
||||
|
||||
;; Auto expand
|
||||
(when semantic-symref-auto-expand-results
|
||||
(semantic-symref-list-expand-all))
|
||||
|
||||
;; Clean up the mess
|
||||
(toggle-read-only 1)
|
||||
(set-buffer-modified-p nil)
|
||||
|
@ -305,7 +376,8 @@ BUTTON is the button that was clicked."
|
|||
(win (selected-window))
|
||||
)
|
||||
(switch-to-buffer-other-window buff)
|
||||
(with-no-warnings (goto-line line))
|
||||
(goto-char (point-min))
|
||||
(forward-line (1- line))
|
||||
(pulse-momentary-highlight-one-line (point))
|
||||
(when (eq last-command-event ?\s) (select-window win))
|
||||
)
|
||||
|
@ -323,6 +395,158 @@ BUTTON is the button that was clicked."
|
|||
(forward-line -1)
|
||||
(back-to-indentation))
|
||||
|
||||
(defun semantic-symref-list-expand-all ()
|
||||
"Expand all the nodes in the current buffer."
|
||||
(interactive)
|
||||
(let ((start (make-marker)))
|
||||
(move-marker start (point))
|
||||
(goto-char (point-min))
|
||||
(while (re-search-forward "\\[[+]\\]" nil t)
|
||||
(semantic-symref-list-toggle-showing))
|
||||
;; Restore position
|
||||
(goto-char start)))
|
||||
|
||||
(defun semantic-symref-list-contract-all ()
|
||||
"Expand all the nodes in the current buffer."
|
||||
(interactive)
|
||||
(let ((start (make-marker)))
|
||||
(move-marker start (point))
|
||||
(goto-char (point-min))
|
||||
(while (re-search-forward "\\[[-]\\]" nil t)
|
||||
(semantic-symref-list-toggle-showing))
|
||||
;; Restore position
|
||||
(goto-char start)))
|
||||
|
||||
;;; UTILS
|
||||
;;
|
||||
;; List mode utils for understadning the current line
|
||||
|
||||
(defun semantic-symref-list-on-hit-p ()
|
||||
"Return the line number if the cursor is on a buffer line with a hit.
|
||||
Hits are the line of code from the buffer, not the tag summar or file lines."
|
||||
(save-excursion
|
||||
(end-of-line)
|
||||
(let* ((ol (car (semantic-overlays-at (1- (point)))))) ;; trust this for now
|
||||
(when ol (semantic-overlay-get ol 'line)))))
|
||||
|
||||
|
||||
;;; Keyboard Macros on a Hit
|
||||
;;
|
||||
;; Record a macro on a hit, and store in a special way for execution later.
|
||||
(defun semantic-symref-list-create-macro-on-open-hit ()
|
||||
"Record a keyboard macro at the location of the hit in the current list.
|
||||
Under point should be one hit for the active keyword. Move
|
||||
cursor to the beginning of that symbol, then record a macro as if
|
||||
`kmacro-start-macro' was pressed. Use `kmacro-end-macro',
|
||||
{kmacro-end-macro} to end the macro, and return to the symbol found list."
|
||||
(interactive)
|
||||
(let* ((oldsym (oref (oref semantic-symref-current-results
|
||||
:created-by)
|
||||
:searchfor))
|
||||
(ol (save-excursion
|
||||
(end-of-line)
|
||||
(car (semantic-overlays-at (1- (point))))))
|
||||
(tag (when ol (semantic-overlay-get ol 'tag)))
|
||||
(line (when ol (semantic-overlay-get ol 'line))))
|
||||
(when (not line)
|
||||
(error "Cannot create macro on a non-hit line"))
|
||||
;; Go there, and do something useful.
|
||||
(switch-to-buffer-other-window (semantic-tag-buffer tag))
|
||||
(goto-char (point-min))
|
||||
(forward-line (1- line))
|
||||
(when (not (re-search-forward (regexp-quote oldsym) (point-at-eol) t))
|
||||
(error "Cannot find hit. Cannot record macro"))
|
||||
(goto-char (match-beginning 0))
|
||||
;; Cursor is now in the right location. Start recording a macro.
|
||||
(kmacro-start-macro nil)
|
||||
;; Notify the user
|
||||
(message "Complete with C-x ). Use E in the symref buffer to call this macro.")))
|
||||
|
||||
(defun semantic-symref-list-call-macro-on-open-hits ()
|
||||
"Call the most recently created keyboard macro on each hit.
|
||||
Cursor is placed at the beginning of the symbol found, even if
|
||||
there is more than one symbol on the current line. The
|
||||
previously recorded macro is then executed."
|
||||
(interactive)
|
||||
(save-window-excursion
|
||||
(let ((count (semantic-symref-list-map-open-hits
|
||||
(lambda ()
|
||||
(switch-to-buffer (current-buffer))
|
||||
(kmacro-call-macro nil)))))
|
||||
(semantic-symref-list-update-open-hits)
|
||||
(message "Executed Macro %d times." count))))
|
||||
|
||||
;;; REFACTORING EDITS
|
||||
;;
|
||||
;; Utilities and features for refactoring across a list of hits.
|
||||
;;
|
||||
(defun semantic-symref-list-rename-open-hits (newname)
|
||||
"Rename the discovered symbol references to NEWNAME.
|
||||
Only renames the locations that are open in the symref list.
|
||||
Closed items will be skipped."
|
||||
(interactive
|
||||
(list (read-string "Rename to: "
|
||||
(oref (oref semantic-symref-current-results
|
||||
:created-by)
|
||||
:searchfor))))
|
||||
(let ((count (semantic-symref-list-map-open-hits
|
||||
(lambda () (replace-match newname nil t)))))
|
||||
(semantic-symref-list-update-open-hits)
|
||||
(message "Renamed %d occurances." count)))
|
||||
|
||||
;;; REFACTORING UTILITIES
|
||||
;;
|
||||
;; Refactoring tools want to operate on only the "good" stuff the
|
||||
;; user selected.
|
||||
(defun semantic-symref-list-map-open-hits (function)
|
||||
"For every open hit in the symref buffer, perform FUNCTION.
|
||||
The `match-data' will be set to a successful hit of the searched for symbol.
|
||||
Return the number of occurances FUNCTION was operated upon."
|
||||
|
||||
;; First Pass in this function - a straight rename.
|
||||
;; Second Pass - Allow context specification based on
|
||||
;; class members. (Not Done)
|
||||
|
||||
(let ((oldsym (oref (oref semantic-symref-current-results
|
||||
:created-by)
|
||||
:searchfor))
|
||||
(count 0))
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(while (not (eobp))
|
||||
;; Is this line a "hit" line?
|
||||
(let* ((ol (car (semantic-overlays-at (1- (point))))) ;; trust this for now
|
||||
(tag (when ol (semantic-overlay-get ol 'tag)))
|
||||
(line (when ol (semantic-overlay-get ol 'line))))
|
||||
(when line
|
||||
;; The "line" means we have an open hit.
|
||||
(with-current-buffer (semantic-tag-buffer tag)
|
||||
(goto-char (point-min))
|
||||
(forward-line (1- line))
|
||||
(beginning-of-line)
|
||||
(while (re-search-forward (regexp-quote oldsym) (point-at-eol) t)
|
||||
(setq count (1+ count))
|
||||
(save-excursion ;; Leave cursor after the matched name.
|
||||
(goto-char (match-beginning 0)) ;; Go to beginning of that sym
|
||||
(funcall function))))))
|
||||
;; Go to the next line
|
||||
(forward-line 1)
|
||||
(end-of-line)))
|
||||
count))
|
||||
|
||||
(defun semantic-symref-list-update-open-hits ()
|
||||
"Update the text for all the open hits in the symref list."
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(while (re-search-forward "\\[-\\]" nil t)
|
||||
(end-of-line)
|
||||
(let* ((ol (car (semantic-overlays-at (1- (point))))) ;; trust this for now
|
||||
(tag (when ol (semantic-overlay-get ol 'tag))))
|
||||
;; If there is a tag, then close/open it.
|
||||
(when tag
|
||||
(semantic-symref-list-toggle-showing)
|
||||
(semantic-symref-list-toggle-showing))))))
|
||||
|
||||
(provide 'semantic/symref/list)
|
||||
|
||||
;; Local variables:
|
||||
|
|
|
@ -687,18 +687,24 @@ This function is for internal use only."
|
|||
;;
|
||||
(defun semantic-tag-deep-copy-one-tag (tag &optional filter)
|
||||
"Make a deep copy of TAG, applying FILTER to each child-tag.
|
||||
Properties and overlay info are not copied.
|
||||
FILTER takes TAG as an argument, and should returns a semantic-tag.
|
||||
No properties are copied except for :filename.
|
||||
Overlay will be a vector.
|
||||
FILTER takes TAG as an argument, and should return a `semantic-tag'.
|
||||
It is safe for FILTER to modify the input tag and return it."
|
||||
(when (not filter) (setq filter 'identity))
|
||||
(when (not (semantic-tag-p tag))
|
||||
(signal 'wrong-type-argument (list tag 'semantic-tag-p)))
|
||||
(funcall filter (list (semantic-tag-name tag)
|
||||
(semantic-tag-class tag)
|
||||
(semantic--tag-deep-copy-attributes
|
||||
(semantic-tag-attributes tag) filter)
|
||||
nil
|
||||
nil)))
|
||||
(let ((ol (semantic-tag-overlay tag))
|
||||
(fn (semantic-tag-file-name tag)))
|
||||
(funcall filter (list (semantic-tag-name tag)
|
||||
(semantic-tag-class tag)
|
||||
(semantic--tag-deep-copy-attributes
|
||||
(semantic-tag-attributes tag) filter)
|
||||
;; Only copy the filename property
|
||||
(when fn (list :filename fn))
|
||||
;; Only setup a vector if we had an overlay.
|
||||
(when ol (vector (semantic-tag-start tag)
|
||||
(semantic-tag-end tag)))))))
|
||||
|
||||
(defun semantic--tag-deep-copy-attributes (attrs &optional filter)
|
||||
"Make a deep copy of ATTRS, applying FILTER to each child-tag.
|
||||
|
@ -877,7 +883,7 @@ That is the value of the `:throws' attribute."
|
|||
"Return the parent of the function that TAG describes.
|
||||
That is the value of the `:parent' attribute.
|
||||
A function has a parent if it is a method of a class, and if the
|
||||
function does not appear in body of it's parent class."
|
||||
function does not appear in body of its parent class."
|
||||
(semantic-tag-named-parent tag))
|
||||
|
||||
(defsubst semantic-tag-function-destructor-p (tag)
|
||||
|
|
|
@ -591,12 +591,16 @@ Note: TYPE not yet implemented."
|
|||
;; ;; Test for doc string
|
||||
;; (unless docstring
|
||||
;; (error "Could not find documentation for %s" (semantic-tag-name tag)))
|
||||
;;
|
||||
;; (require 'srecode)
|
||||
;; (require 'srecode-texi)
|
||||
;;
|
||||
;; ;; If we have a string, do the replacement.
|
||||
;; (delete-region (semantic-tag-start tag)
|
||||
;; (semantic-tag-end tag))
|
||||
;; ;; Use useful functions from the docaument library.
|
||||
;; (require 'document)
|
||||
;; (document-insert-texinfo doctag (semantic-tag-buffer doctag))
|
||||
;; (srecode-texi-insert-tag-as-doc doctag)
|
||||
;; ;(semantic-insert-foreign-tag doctag)
|
||||
;; ))
|
||||
|
||||
;; (defun semantic-texi-update-doc-from-source (&optional tag)
|
||||
|
|
|
@ -743,6 +743,13 @@ minor mode is enabled."
|
|||
"List of tag classes which stickyfunc will display in the header line.")
|
||||
(make-variable-buffer-local 'semantic-stickyfunc-sticky-classes)
|
||||
|
||||
(defcustom semantic-stickyfunc-show-only-functions-p nil
|
||||
"Non-nil means don't show lines that aren't part of a tag.
|
||||
If this is nil, then comments or other text between tags that is
|
||||
1 line above the top of the current window will be shown."
|
||||
:group 'semantic
|
||||
:type 'boolean)
|
||||
|
||||
(defun semantic-stickyfunc-tag-to-stick ()
|
||||
"Return the tag to stick at the current point."
|
||||
(let ((tags (nreverse (semantic-find-tag-by-overlay (point)))))
|
||||
|
@ -759,45 +766,51 @@ minor mode is enabled."
|
|||
"Make the function at the top of the current window sticky.
|
||||
Capture its function declaration, and place it in the header line.
|
||||
If there is no function, disable the header line."
|
||||
(let ((str
|
||||
(save-excursion
|
||||
(goto-char (window-start (selected-window)))
|
||||
(forward-line -1)
|
||||
(end-of-line)
|
||||
;; Capture this function
|
||||
(let* ((tag (semantic-stickyfunc-tag-to-stick)))
|
||||
;; TAG is nil if there was nothing of the appropriate type there.
|
||||
(if (not tag)
|
||||
;; Set it to be the text under the header line
|
||||
(buffer-substring (point-at-bol) (point-at-eol))
|
||||
;; Get it
|
||||
(goto-char (semantic-tag-start tag))
|
||||
;; Klaus Berndl <klaus.berndl@sdm.de>:
|
||||
;; goto the tag name; this is especially needed for languages
|
||||
;; like c++ where a often used style is like:
|
||||
;; void
|
||||
;; ClassX::methodM(arg1...)
|
||||
;; {
|
||||
;; ...
|
||||
;; }
|
||||
;; Without going to the tag-name we would get"void" in the
|
||||
;; header line which is IMHO not really useful
|
||||
(search-forward (semantic-tag-name tag) nil t)
|
||||
(buffer-substring (point-at-bol) (point-at-eol))
|
||||
))))
|
||||
(start 0))
|
||||
(while (string-match "%" str start)
|
||||
(setq str (replace-match "%%" t t str 0)
|
||||
start (1+ (match-end 0)))
|
||||
)
|
||||
;; In 21.4 (or 22.1) the heder doesn't expand tabs. Hmmmm.
|
||||
;; We should replace them here.
|
||||
;;
|
||||
;; This hack assumes that tabs are kept smartly at tab boundaries
|
||||
;; instead of in a tab boundary where it might only represent 4 spaces.
|
||||
(while (string-match "\t" str start)
|
||||
(setq str (replace-match " " t t str 0)))
|
||||
str))
|
||||
(save-excursion
|
||||
(goto-char (window-start (selected-window)))
|
||||
(let* ((noshow (bobp))
|
||||
(str
|
||||
(progn
|
||||
(forward-line -1)
|
||||
(end-of-line)
|
||||
;; Capture this function
|
||||
(let* ((tag (semantic-stickyfunc-tag-to-stick)))
|
||||
;; TAG is nil if there was nothing of the appropriate type there.
|
||||
(if (not tag)
|
||||
;; Set it to be the text under the header line
|
||||
(if noshow
|
||||
""
|
||||
(if semantic-stickyfunc-show-only-functions-p ""
|
||||
(buffer-substring (point-at-bol) (point-at-eol))
|
||||
))
|
||||
;; Go get the first line of this tag.
|
||||
(goto-char (semantic-tag-start tag))
|
||||
;; Klaus Berndl <klaus.berndl@sdm.de>:
|
||||
;; goto the tag name; this is especially needed for languages
|
||||
;; like c++ where a often used style is like:
|
||||
;; void
|
||||
;; ClassX::methodM(arg1...)
|
||||
;; {
|
||||
;; ...
|
||||
;; }
|
||||
;; Without going to the tag-name we would get"void" in the
|
||||
;; header line which is IMHO not really useful
|
||||
(search-forward (semantic-tag-name tag) nil t)
|
||||
(buffer-substring (point-at-bol) (point-at-eol))
|
||||
))))
|
||||
(start 0))
|
||||
(while (string-match "%" str start)
|
||||
(setq str (replace-match "%%" t t str 0)
|
||||
start (1+ (match-end 0)))
|
||||
)
|
||||
;; In 21.4 (or 22.1) the header doesn't expand tabs. Hmmmm.
|
||||
;; We should replace them here.
|
||||
;;
|
||||
;; This hack assumes that tabs are kept smartly at tab boundaries
|
||||
;; instead of in a tab boundary where it might only represent 4 spaces.
|
||||
(while (string-match "\t" str start)
|
||||
(setq str (replace-match " " t t str 0)))
|
||||
str)))
|
||||
|
||||
(defun semantic-stickyfunc-menu (event)
|
||||
"Popup a menu that can help a user understand stickyfunc-mode.
|
||||
|
|
|
@ -132,44 +132,6 @@ buffer, or a filename. If SOMETHING is nil return nil."
|
|||
(semantic-alias-obsolete 'semantic-something-to-stream
|
||||
'semantic-something-to-tag-table "23.2")
|
||||
|
||||
;;; Recursive searching through dependency trees
|
||||
;;
|
||||
;; This will depend on the general searching APIS defined above.
|
||||
;; but will add full recursion through the dependencies list per
|
||||
;; stream.
|
||||
(defun semantic-recursive-find-nonterminal-by-name (name buffer)
|
||||
"Recursively find the first occurrence of NAME.
|
||||
Start search with BUFFER. Recurse through all dependencies till found.
|
||||
The return item is of the form (BUFFER TOKEN) where BUFFER is the buffer
|
||||
in which TOKEN (the token found to match NAME) was found.
|
||||
|
||||
THIS ISN'T USED IN SEMANTIC. DELETE ME SOON."
|
||||
(with-current-buffer buffer
|
||||
(let* ((stream (semantic-fetch-tags))
|
||||
(includelist (or (semantic-find-tags-by-class 'include stream)
|
||||
"empty.silly.thing"))
|
||||
(found (semantic-find-first-tag-by-name name stream))
|
||||
(unfound nil))
|
||||
(while (and (not found) includelist)
|
||||
(let ((fn (semantic-dependency-tag-file (car includelist))))
|
||||
(if (and fn (not (member fn unfound)))
|
||||
(with-current-buffer (save-match-data
|
||||
(find-file-noselect fn))
|
||||
(message "Scanning %s" (buffer-file-name))
|
||||
(setq stream (semantic-fetch-tags))
|
||||
(setq found (semantic-find-first-tag-by-name name stream))
|
||||
(if found
|
||||
(setq found (cons (current-buffer) (list found)))
|
||||
(setq includelist
|
||||
(append includelist
|
||||
(semantic-find-tags-by-class
|
||||
'include stream))))
|
||||
(setq unfound (cons fn unfound)))))
|
||||
(setq includelist (cdr includelist)))
|
||||
found)))
|
||||
(make-obsolete 'semantic-recursive-find-nonterminal-by-name
|
||||
"Do not use this function." "23.2")
|
||||
|
||||
;;; Completion APIs
|
||||
;;
|
||||
;; These functions provide minibuffer reading/completion for lists of
|
||||
|
@ -315,11 +277,12 @@ If TAG is not specified, use the tag at point."
|
|||
(princ "Buffer specific configuration items:\n")
|
||||
(let ((vars '(major-mode
|
||||
semantic-case-fold
|
||||
semantic-expand-nonterminal
|
||||
semantic-tag-expand-function
|
||||
semantic-parser-name
|
||||
semantic-parse-tree-state
|
||||
semantic-lex-analyzer
|
||||
semantic-lex-reset-hooks
|
||||
semantic-lex-syntax-modifications
|
||||
)))
|
||||
(dolist (V vars)
|
||||
(semantic-describe-buffer-var-helper V buff)))
|
||||
|
@ -334,7 +297,8 @@ If TAG is not specified, use the tag at point."
|
|||
semantic-after-toplevel-cache-change-hook
|
||||
semantic-before-toplevel-cache-flush-hook
|
||||
semantic-dump-parse
|
||||
|
||||
semantic-type-relation-separator-character
|
||||
semantic-command-separation-character
|
||||
)))
|
||||
(dolist (V vars)
|
||||
(semantic-describe-buffer-var-helper V buff)))
|
||||
|
@ -344,34 +308,6 @@ If TAG is not specified, use the tag at point."
|
|||
)))
|
||||
)
|
||||
|
||||
(defun semantic-current-tag-interactive (p)
|
||||
"Display the current token.
|
||||
Argument P is the point to search from in the current buffer."
|
||||
(interactive "d")
|
||||
(require 'semantic/find)
|
||||
(let ((tok (semantic-brute-find-innermost-tag-by-position
|
||||
p (current-buffer))))
|
||||
(message (mapconcat 'semantic-abbreviate-nonterminal tok ","))
|
||||
(car tok))
|
||||
)
|
||||
|
||||
(defun semantic-hack-search ()
|
||||
"Display info about something under the cursor using generic methods."
|
||||
(interactive)
|
||||
(require 'semantic/find)
|
||||
(let ((strm (cdr (semantic-fetch-tags)))
|
||||
(res nil))
|
||||
(setq res (semantic-brute-find-tag-by-position (point) strm))
|
||||
(if res
|
||||
(progn
|
||||
(pop-to-buffer "*SEMANTIC HACK RESULTS*")
|
||||
(require 'pp)
|
||||
(erase-buffer)
|
||||
(insert (pp-to-string res) "\n")
|
||||
(goto-char (point-min))
|
||||
(shrink-window-if-larger-than-buffer))
|
||||
(message "nil"))))
|
||||
|
||||
(defun semantic-assert-valid-token (tok)
|
||||
"Assert that TOK is a valid token."
|
||||
(if (semantic-tag-p tok)
|
||||
|
@ -415,7 +351,8 @@ NOTFIRST indicates that this was not the first call in the recursive use."
|
|||
'unmatched)))
|
||||
(setq o (cons (car over) o)))
|
||||
(setq over (cdr over)))
|
||||
(message "Remaining overlays: %S" o)))
|
||||
(when (called-interactively-p 'any)
|
||||
(message "Remaining overlays: %S" o))))
|
||||
over)
|
||||
|
||||
;;; Interactive commands (from Senator).
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
(defconst wisent-python-wy--keyword-table
|
||||
(semantic-lex-make-keyword-table
|
||||
'(("and" . AND)
|
||||
("as" . AS)
|
||||
("assert" . ASSERT)
|
||||
("break" . BREAK)
|
||||
("class" . CLASS)
|
||||
|
@ -72,6 +73,7 @@
|
|||
("pass" summary "Statement that does nothing")
|
||||
("or" summary "Binary logical 'or' operator")
|
||||
("not" summary "Unary boolean negation operator")
|
||||
("lambda" summary "Create anonymous function")
|
||||
("is" summary "Binary operator that tests for object equality")
|
||||
("in" summary "Part of 'for' statement ")
|
||||
("import" summary "Load specified modules")
|
||||
|
@ -86,10 +88,11 @@
|
|||
("elif" summary "Shorthand for 'else if' following an 'if' statement")
|
||||
("del" summary "Delete specified objects, i.e., undo what assignment did")
|
||||
("def" summary "Define a new function")
|
||||
("continue" summary "Skip to the next interation of enclosing 'for' or 'while' loop")
|
||||
("continue" summary "Skip to the next iteration of enclosing 'for' or 'while' loop")
|
||||
("class" summary "Define a new class")
|
||||
("break" summary "Terminate 'for' or 'while' loop")
|
||||
("assert" summary "Raise AssertionError exception if <expr> is false")
|
||||
("as" summary "EXPR as NAME makes value of EXPR available as variable NAME")
|
||||
("and" summary "Logical AND binary operator ... ")))
|
||||
"Table of language keywords.")
|
||||
|
||||
|
@ -172,7 +175,7 @@
|
|||
(eval-when-compile
|
||||
(require 'semantic/wisent/comp))
|
||||
(wisent-compile-grammar
|
||||
'((BACKSLASH NEWLINE INDENT DEDENT INDENT_BLOCK PAREN_BLOCK BRACE_BLOCK BRACK_BLOCK LPAREN RPAREN LBRACE RBRACE LBRACK RBRACK LTLTEQ GTGTEQ EXPEQ DIVDIVEQ DIVDIV LTLT GTGT EXPONENT EQ GE LE PLUSEQ MINUSEQ MULTEQ DIVEQ MODEQ AMPEQ OREQ HATEQ LTGT NE HAT LT GT AMP MULT DIV MOD PLUS MINUS PERIOD TILDE BAR COLON SEMICOLON COMMA ASSIGN BACKQUOTE STRING_LITERAL NUMBER_LITERAL NAME AND ASSERT BREAK CLASS CONTINUE DEF DEL ELIF ELSE EXCEPT EXEC FINALLY FOR FROM GLOBAL IF IMPORT IN IS LAMBDA NOT OR PASS PRINT RAISE RETURN TRY WHILE YIELD)
|
||||
'((BACKSLASH NEWLINE INDENT DEDENT INDENT_BLOCK PAREN_BLOCK BRACE_BLOCK BRACK_BLOCK LPAREN RPAREN LBRACE RBRACE LBRACK RBRACK LTLTEQ GTGTEQ EXPEQ DIVDIVEQ DIVDIV LTLT GTGT EXPONENT EQ GE LE PLUSEQ MINUSEQ MULTEQ DIVEQ MODEQ AMPEQ OREQ HATEQ LTGT NE HAT LT GT AMP MULT DIV MOD PLUS MINUS PERIOD TILDE BAR COLON SEMICOLON COMMA ASSIGN BACKQUOTE STRING_LITERAL NUMBER_LITERAL NAME AND AS ASSERT BREAK CLASS CONTINUE DEF DEL ELIF ELSE EXCEPT EXEC FINALLY FOR FROM GLOBAL IF IMPORT IN IS LAMBDA NOT OR PASS PRINT RAISE RETURN TRY WHILE YIELD)
|
||||
nil
|
||||
(goal
|
||||
((NEWLINE))
|
||||
|
@ -280,6 +283,9 @@
|
|||
((testlist)
|
||||
nil))
|
||||
(yield_stmt
|
||||
((YIELD)
|
||||
(wisent-raw-tag
|
||||
(semantic-tag-new-code $1 nil)))
|
||||
((YIELD testlist)
|
||||
(wisent-raw-tag
|
||||
(semantic-tag-new-code $1 nil))))
|
||||
|
@ -320,14 +326,14 @@
|
|||
((import_as_name_list COMMA import_as_name)
|
||||
nil))
|
||||
(import_as_name
|
||||
((NAME name_name_opt)
|
||||
((NAME as_name_opt)
|
||||
nil))
|
||||
(dotted_as_name
|
||||
((dotted_name name_name_opt)))
|
||||
(name_name_opt
|
||||
((dotted_name as_name_opt)))
|
||||
(as_name_opt
|
||||
(nil)
|
||||
((NAME NAME)
|
||||
nil))
|
||||
((AS NAME)
|
||||
(identity $2)))
|
||||
(dotted_name
|
||||
((NAME))
|
||||
((dotted_name PERIOD NAME)
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
(require 'mode-local)
|
||||
(load "srecode/loaddefs" nil 'nomessage)
|
||||
|
||||
(defvar srecode-version "1.0pre7"
|
||||
(defvar srecode-version "1.0"
|
||||
"Current version of the Semantic Recoder.")
|
||||
|
||||
;;; Code:
|
||||
|
|
|
@ -35,19 +35,17 @@
|
|||
(require 'semantic)
|
||||
(require 'eieio)
|
||||
(require 'eieio-base)
|
||||
(require 'srecode)
|
||||
(require 'srecode/table)
|
||||
(require 'srecode/dictionary)
|
||||
|
||||
(declare-function srecode-template-inserter-newline-child-p "srecode/insert"
|
||||
t t)
|
||||
(declare-function srecode-create-section-dictionary "srecode/dictionary")
|
||||
(declare-function srecode-dictionary-compound-variable "srecode/dictionary")
|
||||
|
||||
;;; Code:
|
||||
|
||||
;;; Template Class
|
||||
;;
|
||||
;; Templatets describe a patter of text that can be inserted into a
|
||||
;; Templates describe a pattern of text that can be inserted into a
|
||||
;; buffer.
|
||||
;;
|
||||
(defclass srecode-template (eieio-named)
|
||||
|
@ -213,6 +211,7 @@ Arguments ESCAPE-START and ESCAPE-END are the current escape sequences in use."
|
|||
(mode nil)
|
||||
(application nil)
|
||||
(priority nil)
|
||||
(project nil)
|
||||
(vars nil)
|
||||
)
|
||||
|
||||
|
@ -256,6 +255,8 @@ Arguments ESCAPE-START and ESCAPE-END are the current escape sequences in use."
|
|||
(setq application (read firstvalue)))
|
||||
((string= name "priority")
|
||||
(setq priority (read firstvalue)))
|
||||
((string= name "project")
|
||||
(setq project firstvalue))
|
||||
(t
|
||||
;; Assign this into some table of variables.
|
||||
(setq vars (cons (cons name firstvalue) vars))
|
||||
|
@ -297,12 +298,19 @@ Arguments ESCAPE-START and ESCAPE-END are the current escape sequences in use."
|
|||
;; Calculate priority
|
||||
;;
|
||||
(if (not priority)
|
||||
(let ((d (file-name-directory (buffer-file-name)))
|
||||
(sd (file-name-directory (locate-library "srecode")))
|
||||
(defaultdelta (if (eq mode 'default) 20 0)))
|
||||
(if (string= d sd)
|
||||
(setq priority (+ 80 defaultdelta))
|
||||
(setq priority (+ 30 defaultdelta)))
|
||||
(let ((d (expand-file-name (file-name-directory (buffer-file-name))))
|
||||
(sd (expand-file-name (file-name-directory (locate-library "srecode"))))
|
||||
(defaultdelta (if (eq mode 'default) 0 10)))
|
||||
;; @TODO : WHEN INTEGRATING INTO EMACS
|
||||
;; The location of Emacs default templates needs to be specified
|
||||
;; here to also have a lower priority.
|
||||
(if (string-match (concat "^" sd) d)
|
||||
(setq priority (+ 30 defaultdelta))
|
||||
;; If the user created template is for a project, then
|
||||
;; don't add as much as if it is unique to just some user.
|
||||
(if (stringp project)
|
||||
(setq priority (+ 50 defaultdelta))
|
||||
(setq priority (+ 80 defaultdelta))))
|
||||
(message "Templates %s has estimated priority of %d"
|
||||
(file-name-nondirectory (buffer-file-name))
|
||||
priority))
|
||||
|
@ -311,56 +319,56 @@ Arguments ESCAPE-START and ESCAPE-END are the current escape sequences in use."
|
|||
priority))
|
||||
|
||||
;; Save it up!
|
||||
(srecode-compile-template-table table mode priority application vars)
|
||||
(srecode-compile-template-table table mode priority application project vars)
|
||||
)
|
||||
)
|
||||
|
||||
(defun srecode-compile-one-template-tag (tag STATE)
|
||||
"Compile a template tag TAG into an srecode template class.
|
||||
STATE is the current compile state as an object `srecode-compile-state'."
|
||||
(require 'srecode/dictionary)
|
||||
(let* ((context (oref STATE context))
|
||||
(codeout (srecode-compile-split-code
|
||||
tag (semantic-tag-get-attribute tag :code)
|
||||
STATE))
|
||||
(code (cdr codeout))
|
||||
(args (semantic-tag-function-arguments tag))
|
||||
(binding (semantic-tag-get-attribute tag :binding))
|
||||
(rawdicts (semantic-tag-get-attribute tag :dictionaries))
|
||||
(sdicts (srecode-create-section-dictionary rawdicts STATE))
|
||||
(addargs nil)
|
||||
)
|
||||
; (message "Compiled %s to %d codes with %d args and %d prompts."
|
||||
; (semantic-tag-name tag)
|
||||
; (length code)
|
||||
; (length args)
|
||||
; (length prompts))
|
||||
(while args
|
||||
(setq addargs (cons (intern (car args)) addargs))
|
||||
(when (eq (car addargs) :blank)
|
||||
;; If we have a wrap, then put wrap inserters on both
|
||||
;; ends of the code.
|
||||
(setq code (append
|
||||
(list (srecode-compile-inserter "BLANK"
|
||||
"\r"
|
||||
STATE
|
||||
:secondname nil
|
||||
:where 'begin))
|
||||
code
|
||||
(list (srecode-compile-inserter "BLANK"
|
||||
"\r"
|
||||
STATE
|
||||
:secondname nil
|
||||
:where 'end))
|
||||
)))
|
||||
(setq args (cdr args)))
|
||||
(defun srecode-compile-one-template-tag (tag state)
|
||||
"Compile a template tag TAG into a srecode template object.
|
||||
STATE is the current compile state as an object of class
|
||||
`srecode-compile-state'."
|
||||
(let* ((context (oref state context))
|
||||
(code (cdr (srecode-compile-split-code
|
||||
tag (semantic-tag-get-attribute tag :code)
|
||||
state)))
|
||||
(args (semantic-tag-function-arguments tag))
|
||||
(binding (semantic-tag-get-attribute tag :binding))
|
||||
(dict-tags (semantic-tag-get-attribute tag :dictionaries))
|
||||
(root-dict (when dict-tags
|
||||
(srecode-create-dictionaries-from-tags
|
||||
dict-tags state)))
|
||||
(addargs))
|
||||
;; Examine arguments.
|
||||
(dolist (arg args)
|
||||
(let ((symbol (intern arg)))
|
||||
(push symbol addargs)
|
||||
|
||||
;; If we have a wrap, then put wrap inserters on both ends of
|
||||
;; the code.
|
||||
(when (eq symbol :blank)
|
||||
(setq code (append
|
||||
(list (srecode-compile-inserter
|
||||
"BLANK"
|
||||
"\r"
|
||||
state
|
||||
:secondname nil
|
||||
:where 'begin))
|
||||
code
|
||||
(list (srecode-compile-inserter
|
||||
"BLANK"
|
||||
"\r"
|
||||
state
|
||||
:secondname nil
|
||||
:where 'end)))))))
|
||||
|
||||
;; Construct and return the template object.
|
||||
(srecode-template (semantic-tag-name tag)
|
||||
:context context
|
||||
:args (nreverse addargs)
|
||||
:dictionary sdicts
|
||||
:binding binding
|
||||
:code code)
|
||||
))
|
||||
:context context
|
||||
:args (nreverse addargs)
|
||||
:dictionary root-dict
|
||||
:binding binding
|
||||
:code code))
|
||||
)
|
||||
|
||||
(defun srecode-compile-do-hard-newline-p (comp)
|
||||
"Examine COMP to decide if the upcoming newline should be hard.
|
||||
|
@ -514,12 +522,13 @@ to the inserter constructor."
|
|||
(if (not new) (error "SRECODE: Unknown macro code %S" key))
|
||||
new)))
|
||||
|
||||
(defun srecode-compile-template-table (templates mode priority application vars)
|
||||
(defun srecode-compile-template-table (templates mode priority application project vars)
|
||||
"Compile a list of TEMPLATES into an semantic recode table.
|
||||
The table being compiled is for MODE, or the string \"default\".
|
||||
PRIORITY is a numerical value that indicates this tables location
|
||||
in an ordered search.
|
||||
APPLICATION is the name of the application these templates belong to.
|
||||
PROJECT is a directory name which these templates scope to.
|
||||
A list of defined variables VARS provides a variable table."
|
||||
(let ((namehash (make-hash-table :test 'equal
|
||||
:size (length templates)))
|
||||
|
@ -549,6 +558,9 @@ A list of defined variables VARS provides a variable table."
|
|||
|
||||
(setq lp (cdr lp))))
|
||||
|
||||
(when (stringp project)
|
||||
(setq project (expand-file-name project)))
|
||||
|
||||
(let* ((table (srecode-mode-table-new mode (buffer-file-name)
|
||||
:templates (nreverse templates)
|
||||
:namehash namehash
|
||||
|
@ -556,7 +568,8 @@ A list of defined variables VARS provides a variable table."
|
|||
:variables vars
|
||||
:major-mode mode
|
||||
:priority priority
|
||||
:application application))
|
||||
:application application
|
||||
:project project))
|
||||
(tmpl (oref table templates)))
|
||||
;; Loop over all the templates, and xref.
|
||||
(while tmpl
|
||||
|
|
|
@ -26,6 +26,27 @@
|
|||
|
||||
;;; Code:
|
||||
|
||||
(require 'srecode)
|
||||
(require 'srecode/dictionary)
|
||||
(require 'srecode/semantic)
|
||||
(require 'semantic/tag)
|
||||
|
||||
;;; Customization
|
||||
;;
|
||||
|
||||
(defgroup srecode-cpp nil
|
||||
"C++-specific Semantic Recoder settings."
|
||||
:group 'srecode)
|
||||
|
||||
(defcustom srecode-cpp-namespaces
|
||||
'("std" "boost")
|
||||
"List expansion candidates for the :using-namespaces argument.
|
||||
A dictionary entry of the named PREFIX_NAMESPACE with the value
|
||||
NAMESPACE:: is created for each namespace unless the current
|
||||
buffer contains a using NAMESPACE; statement "
|
||||
:group 'srecode-cpp
|
||||
:type '(repeat string))
|
||||
|
||||
;;; :cpp ARGUMENT HANDLING
|
||||
;;
|
||||
;; When a :cpp argument is required, fill the dictionary with
|
||||
|
@ -33,10 +54,6 @@
|
|||
;;
|
||||
;; Error if not in a C++ mode.
|
||||
|
||||
(require 'srecode)
|
||||
(require 'srecode/dictionary)
|
||||
(require 'srecode/semantic)
|
||||
|
||||
;;;###autoload
|
||||
(defun srecode-semantic-handle-:cpp (dict)
|
||||
"Add macros into the dictionary DICT based on the current c++ file.
|
||||
|
@ -59,6 +76,23 @@ HEADER - Shown section if in a header file."
|
|||
)
|
||||
)
|
||||
|
||||
(defun srecode-semantic-handle-:using-namespaces (dict)
|
||||
"Add macros into the dictionary DICT based on used namespaces.
|
||||
Adds the following:
|
||||
PREFIX_NAMESPACE - for each NAMESPACE in `srecode-cpp-namespaces'."
|
||||
(let ((tags (semantic-find-tags-by-class
|
||||
'using (semantic-fetch-tags))))
|
||||
(dolist (name srecode-cpp-namespaces)
|
||||
(let ((variable (format "PREFIX_%s" (upcase name)))
|
||||
(prefix (format "%s::" name)))
|
||||
(srecode-dictionary-set-value dict variable prefix)
|
||||
(dolist (tag tags)
|
||||
(when (and (eq (semantic-tag-get-attribute tag :kind)
|
||||
'namespace)
|
||||
(string= (semantic-tag-name tag) name))
|
||||
(srecode-dictionary-set-value dict variable ""))))))
|
||||
)
|
||||
|
||||
(define-mode-local-override srecode-semantic-apply-tag-to-dict
|
||||
c++-mode (tag-wrapper dict)
|
||||
"Apply C++ specific features from TAG-WRAPPER into DICT.
|
||||
|
@ -97,6 +131,7 @@ special behavior for tag of classes include, using and function."
|
|||
(srecode-semantic-tag (semantic-tag-name value-tag)
|
||||
:prime value-tag)
|
||||
value-dict))
|
||||
|
||||
;; Discriminate using statements referring to namespaces and
|
||||
;; types.
|
||||
(when (eq (semantic-tag-get-attribute tag :kind) 'namespace)
|
||||
|
@ -111,7 +146,8 @@ special behavior for tag of classes include, using and function."
|
|||
;; when they make sense. My best bet would be
|
||||
;; (semantic-tag-function-parent tag), but it is not there, when
|
||||
;; the function is defined in the scope of a class.
|
||||
(let ((member 't)
|
||||
(let ((member t)
|
||||
(templates (semantic-tag-get-attribute tag :template))
|
||||
(modifiers (semantic-tag-modifiers tag)))
|
||||
|
||||
;; Add modifiers into the dictionary
|
||||
|
@ -120,6 +156,9 @@ special behavior for tag of classes include, using and function."
|
|||
dict "MODIFIERS")))
|
||||
(srecode-dictionary-set-value modifier-dict "NAME" modifier)))
|
||||
|
||||
;; Add templates into child dictionaries.
|
||||
(srecode-cpp-apply-templates dict templates)
|
||||
|
||||
;; When the function is a member function, it can have
|
||||
;; additional modifiers.
|
||||
(when member
|
||||
|
@ -133,11 +172,40 @@ special behavior for tag of classes include, using and function."
|
|||
;; entry.
|
||||
(when (semantic-tag-get-attribute tag :pure-virtual-flag)
|
||||
(srecode-dictionary-show-section dict "PURE"))
|
||||
)
|
||||
))
|
||||
)))
|
||||
|
||||
;;
|
||||
;; CLASS
|
||||
;;
|
||||
((eq class 'type)
|
||||
;; For classes, add template parameters.
|
||||
(when (or (semantic-tag-of-type-p tag "class")
|
||||
(semantic-tag-of-type-p tag "struct"))
|
||||
|
||||
;; Add templates into child dictionaries.
|
||||
(let ((templates (semantic-tag-get-attribute tag :template)))
|
||||
(srecode-cpp-apply-templates dict templates))))
|
||||
))
|
||||
)
|
||||
|
||||
|
||||
;;; Helper functions
|
||||
;;
|
||||
|
||||
(defun srecode-cpp-apply-templates (dict templates)
|
||||
"Add section dictionaries for TEMPLATES to DICT."
|
||||
(when templates
|
||||
(let ((templates-dict (srecode-dictionary-add-section-dictionary
|
||||
dict "TEMPLATES")))
|
||||
(dolist (template templates)
|
||||
(let ((template-dict (srecode-dictionary-add-section-dictionary
|
||||
templates-dict "ARGS")))
|
||||
(srecode-semantic-apply-tag-to-dict
|
||||
(srecode-semantic-tag (semantic-tag-name template)
|
||||
:prime template)
|
||||
template-dict)))))
|
||||
)
|
||||
|
||||
(provide 'srecode/cpp)
|
||||
|
||||
;; Local variables:
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
(declare-function srecode-compile-parse-inserter "srecode/compile")
|
||||
(declare-function srecode-dump-code-list "srecode/compile")
|
||||
(declare-function srecode-load-tables-for-mode "srecode/find")
|
||||
(declare-function srecode-template-table-in-project-p "srecode/find")
|
||||
(declare-function srecode-insert-code-stream "srecode/insert")
|
||||
(declare-function data-debug-new-buffer "data-debug")
|
||||
(declare-function data-debug-insert-object-slots "eieio-datadebug")
|
||||
|
@ -157,40 +158,49 @@ buffer's table.
|
|||
If BUFFER-OR-PARENT is t, then this dictionary should not be
|
||||
associated with a buffer or parent."
|
||||
(save-excursion
|
||||
;; Handle the parent
|
||||
(let ((parent nil)
|
||||
(buffer nil)
|
||||
(origin nil)
|
||||
(initfrombuff nil))
|
||||
(cond ((bufferp buffer-or-parent)
|
||||
(set-buffer buffer-or-parent)
|
||||
(setq buffer buffer-or-parent
|
||||
origin (buffer-name buffer-or-parent)
|
||||
initfrombuff t))
|
||||
((srecode-dictionary-child-p buffer-or-parent)
|
||||
(setq parent buffer-or-parent
|
||||
buffer (oref buffer-or-parent buffer)
|
||||
origin (concat (object-name buffer-or-parent) " in "
|
||||
(if buffer (buffer-name buffer)
|
||||
"no buffer")))
|
||||
(when buffer
|
||||
(set-buffer buffer)))
|
||||
((eq buffer-or-parent t)
|
||||
(setq buffer nil
|
||||
origin "Unspecified Origin"))
|
||||
(t
|
||||
(setq buffer (current-buffer)
|
||||
origin (concat "Unspecified. Assume "
|
||||
(buffer-name buffer))
|
||||
initfrombuff t)
|
||||
)
|
||||
)
|
||||
(cond
|
||||
;; Parent is a buffer
|
||||
((bufferp buffer-or-parent)
|
||||
(set-buffer buffer-or-parent)
|
||||
(setq buffer buffer-or-parent
|
||||
origin (buffer-name buffer-or-parent)
|
||||
initfrombuff t))
|
||||
|
||||
;; Parent is another dictionary
|
||||
((srecode-dictionary-child-p buffer-or-parent)
|
||||
(setq parent buffer-or-parent
|
||||
buffer (oref buffer-or-parent buffer)
|
||||
origin (concat (object-name buffer-or-parent) " in "
|
||||
(if buffer (buffer-name buffer)
|
||||
"no buffer")))
|
||||
(when buffer
|
||||
(set-buffer buffer)))
|
||||
|
||||
;; No parent
|
||||
((eq buffer-or-parent t)
|
||||
(setq buffer nil
|
||||
origin "Unspecified Origin"))
|
||||
|
||||
;; Default to unspecified parent
|
||||
(t
|
||||
(setq buffer (current-buffer)
|
||||
origin (concat "Unspecified. Assume "
|
||||
(buffer-name buffer))
|
||||
initfrombuff t)))
|
||||
|
||||
;; Create the new dictionary object.
|
||||
(let ((dict (srecode-dictionary
|
||||
major-mode
|
||||
:buffer buffer
|
||||
:parent parent
|
||||
:namehash (make-hash-table :test 'equal
|
||||
:size 20)
|
||||
:origin origin)))
|
||||
:buffer buffer
|
||||
:parent parent
|
||||
:namehash (make-hash-table :test 'equal
|
||||
:size 20)
|
||||
:origin origin)))
|
||||
;; Only set up the default variables if we are being built
|
||||
;; directroy for a particular buffer.
|
||||
(when initfrombuff
|
||||
|
@ -211,34 +221,37 @@ associated with a buffer or parent."
|
|||
TPL is an object representing a compiled template file."
|
||||
(when tpl
|
||||
(let ((tabs (oref tpl :tables)))
|
||||
(require 'srecode/find) ; For srecode-template-table-in-project-p
|
||||
(while tabs
|
||||
(let ((vars (oref (car tabs) variables)))
|
||||
(while vars
|
||||
(srecode-dictionary-set-value
|
||||
dict (car (car vars)) (cdr (car vars)))
|
||||
(setq vars (cdr vars))))
|
||||
(setq tabs (cdr tabs))))))
|
||||
(when (srecode-template-table-in-project-p (car tabs))
|
||||
(let ((vars (oref (car tabs) variables)))
|
||||
(while vars
|
||||
(srecode-dictionary-set-value
|
||||
dict (car (car vars)) (cdr (car vars)))
|
||||
(setq vars (cdr vars)))))
|
||||
(setq tabs (cdr tabs))))))
|
||||
|
||||
|
||||
(defmethod srecode-dictionary-set-value ((dict srecode-dictionary)
|
||||
name value)
|
||||
"In dictionary DICT, set NAME to have VALUE."
|
||||
;; Validate inputs
|
||||
(if (not (stringp name))
|
||||
(signal 'wrong-type-argument (list name 'stringp)))
|
||||
(unless (stringp name)
|
||||
(signal 'wrong-type-argument (list name 'stringp)))
|
||||
|
||||
;; Add the value.
|
||||
(with-slots (namehash) dict
|
||||
(puthash name value namehash))
|
||||
)
|
||||
|
||||
(defmethod srecode-dictionary-add-section-dictionary ((dict srecode-dictionary)
|
||||
name &optional show-only)
|
||||
name &optional show-only force)
|
||||
"In dictionary DICT, add a section dictionary for section macro NAME.
|
||||
Return the new dictionary.
|
||||
|
||||
You can add several dictionaries to the same section macro.
|
||||
For each dictionary added to a macro, the block of codes in the
|
||||
template will be repeated.
|
||||
You can add several dictionaries to the same section entry.
|
||||
For each dictionary added to a variable, the block of codes in
|
||||
the template will be repeated.
|
||||
|
||||
If optional argument SHOW-ONLY is non-nil, then don't add a new dictionary
|
||||
if there is already one in place. Also, don't add FIRST/LAST entries.
|
||||
|
@ -255,10 +268,11 @@ which will enable SECTIONS to be enabled.
|
|||
Adding a new dictionary will alter these values in previously
|
||||
inserted dictionaries."
|
||||
;; Validate inputs
|
||||
(if (not (stringp name))
|
||||
(signal 'wrong-type-argument (list name 'stringp)))
|
||||
(unless (stringp name)
|
||||
(signal 'wrong-type-argument (list name 'stringp)))
|
||||
|
||||
(let ((new (srecode-create-dictionary dict))
|
||||
(ov (srecode-dictionary-lookup-name dict name)))
|
||||
(ov (srecode-dictionary-lookup-name dict name t)))
|
||||
|
||||
(when (not show-only)
|
||||
;; Setup the FIRST/NOTFIRST and LAST/NOTLAST entries.
|
||||
|
@ -275,7 +289,9 @@ inserted dictionaries."
|
|||
(srecode-dictionary-show-section new "LAST"))
|
||||
)
|
||||
|
||||
(when (or (not show-only) (null ov))
|
||||
(when (or force
|
||||
(not show-only)
|
||||
(null ov))
|
||||
(srecode-dictionary-set-value dict name (append ov (list new))))
|
||||
;; Return the new sub-dictionary.
|
||||
new))
|
||||
|
@ -283,8 +299,9 @@ inserted dictionaries."
|
|||
(defmethod srecode-dictionary-show-section ((dict srecode-dictionary) name)
|
||||
"In dictionary DICT, indicate that the section NAME should be exposed."
|
||||
;; Validate inputs
|
||||
(if (not (stringp name))
|
||||
(signal 'wrong-type-argument (list name 'stringp)))
|
||||
(unless (stringp name)
|
||||
(signal 'wrong-type-argument (list name 'stringp)))
|
||||
|
||||
;; Showing a section is just like making a section dictionary, but
|
||||
;; with no dictionary values to add.
|
||||
(srecode-dictionary-add-section-dictionary dict name t)
|
||||
|
@ -294,51 +311,120 @@ inserted dictionaries."
|
|||
"In dictionary DICT, indicate that the section NAME should be hidden."
|
||||
;; We need to find the has value, and then delete it.
|
||||
;; Validate inputs
|
||||
(if (not (stringp name))
|
||||
(signal 'wrong-type-argument (list name 'stringp)))
|
||||
(unless (stringp name)
|
||||
(signal 'wrong-type-argument (list name 'stringp)))
|
||||
|
||||
;; Add the value.
|
||||
(with-slots (namehash) dict
|
||||
(remhash name namehash))
|
||||
nil)
|
||||
|
||||
(defmethod srecode-dictionary-merge ((dict srecode-dictionary) otherdict)
|
||||
"Merge into DICT the dictionary entries from OTHERDICT."
|
||||
(defmethod srecode-dictionary-add-entries ((dict srecode-dictionary)
|
||||
entries &optional state)
|
||||
"Add ENTRIES to DICT.
|
||||
|
||||
ENTRIES is a list of even length of dictionary entries to
|
||||
add. ENTRIES looks like this:
|
||||
|
||||
(NAME_1 VALUE_1 NAME_2 VALUE_2 ...)
|
||||
|
||||
The following rules apply:
|
||||
* NAME_N is a string
|
||||
and for values
|
||||
* If VALUE_N is t, the section NAME_N is shown.
|
||||
* If VALUE_N is a string, an ordinary value is inserted.
|
||||
* If VALUE_N is a dictionary, it is inserted as entry NAME_N.
|
||||
* Otherwise, a compound variable is created for VALUE_N.
|
||||
|
||||
The optional argument STATE has to non-nil when compound values
|
||||
are inserted. An error is signaled if ENTRIES contains compound
|
||||
values but STATE is nil."
|
||||
(while entries
|
||||
(let ((name (nth 0 entries))
|
||||
(value (nth 1 entries)))
|
||||
(cond
|
||||
;; Value is t; show a section.
|
||||
((eq value t)
|
||||
(srecode-dictionary-show-section dict name))
|
||||
|
||||
;; Value is a simple string; create an ordinary dictionary
|
||||
;; entry
|
||||
((stringp value)
|
||||
(srecode-dictionary-set-value dict name value))
|
||||
|
||||
;; Value is a dictionary; insert as child dictionary.
|
||||
((srecode-dictionary-child-p value)
|
||||
(srecode-dictionary-merge
|
||||
(srecode-dictionary-add-section-dictionary dict name)
|
||||
value t))
|
||||
|
||||
;; Value is some other object; create a compound value.
|
||||
(t
|
||||
(unless state
|
||||
(error "Cannot insert compound values without state."))
|
||||
|
||||
(srecode-dictionary-set-value
|
||||
dict name
|
||||
(srecode-dictionary-compound-variable
|
||||
name :value value :state state)))))
|
||||
(setq entries (nthcdr 2 entries)))
|
||||
dict)
|
||||
|
||||
(defmethod srecode-dictionary-merge ((dict srecode-dictionary) otherdict
|
||||
&optional force)
|
||||
"Merge into DICT the dictionary entries from OTHERDICT.
|
||||
Unless the optional argument FORCE is non-nil, values in DICT are
|
||||
not modified, even if there are values of the same names in
|
||||
OTHERDICT."
|
||||
(when otherdict
|
||||
(maphash
|
||||
(lambda (key entry)
|
||||
;; Only merge in the new values if there was no old value.
|
||||
;; The new values is only merged in if there was no old value
|
||||
;; or FORCE is non-nil.
|
||||
;;
|
||||
;; This protects applications from being whacked, and basically
|
||||
;; makes these new section dictionary entries act like
|
||||
;; "defaults" instead of overrides.
|
||||
(when (not (srecode-dictionary-lookup-name dict key))
|
||||
(cond ((and (listp entry) (srecode-dictionary-p (car entry)))
|
||||
;; A list of section dictionaries.
|
||||
;; We need to merge them in.
|
||||
(while entry
|
||||
(let ((new-sub-dict
|
||||
(srecode-dictionary-add-section-dictionary
|
||||
dict key)))
|
||||
(srecode-dictionary-merge new-sub-dict (car entry)))
|
||||
(setq entry (cdr entry)))
|
||||
)
|
||||
(when (or force
|
||||
(not (srecode-dictionary-lookup-name dict key t)))
|
||||
(cond
|
||||
;; A list of section dictionaries. We need to merge them in.
|
||||
((and (listp entry)
|
||||
(srecode-dictionary-p (car entry)))
|
||||
(dolist (sub-dict entry)
|
||||
(srecode-dictionary-merge
|
||||
(srecode-dictionary-add-section-dictionary
|
||||
dict key t t)
|
||||
sub-dict force)))
|
||||
|
||||
(t
|
||||
(srecode-dictionary-set-value dict key entry)))
|
||||
))
|
||||
;; Other values can be set directly.
|
||||
(t
|
||||
(srecode-dictionary-set-value dict key entry)))))
|
||||
(oref otherdict namehash))))
|
||||
|
||||
(defmethod srecode-dictionary-lookup-name ((dict srecode-dictionary)
|
||||
name)
|
||||
"Return information about the current DICT's value for NAME."
|
||||
name &optional non-recursive)
|
||||
"Return information about DICT's value for NAME.
|
||||
DICT is a dictionary, and NAME is a string that is treated as the
|
||||
name of an entry in the dictionary. If such an entry exists, its
|
||||
value is returned. Otherwise, nil is returned. Normally, the
|
||||
lookup is recursive in the sense that the parent of DICT is
|
||||
searched for NAME if it is not found in DICT. This recursive
|
||||
lookup can be disabled by the optional argument NON-RECURSIVE.
|
||||
|
||||
This function derives values for some special NAMEs, such as
|
||||
'FIRST' and 'LAST'."
|
||||
(if (not (slot-boundp dict 'namehash))
|
||||
nil
|
||||
;; Get the value of this name from the dictionary
|
||||
(or (with-slots (namehash) dict
|
||||
(gethash name namehash))
|
||||
(and (not (member name '("FIRST" "LAST" "NOTFIRST" "NOTLAST")))
|
||||
(oref dict parent)
|
||||
(srecode-dictionary-lookup-name (oref dict parent) name))
|
||||
)))
|
||||
;; Get the value of this name from the dictionary or its parent
|
||||
;; unless the lookup should be non-recursive.
|
||||
(with-slots (namehash parent) dict
|
||||
(or (gethash name namehash)
|
||||
(and (not non-recursive)
|
||||
(not (member name '("FIRST" "LAST" "NOTFIRST" "NOTLAST")))
|
||||
parent
|
||||
(srecode-dictionary-lookup-name parent name)))))
|
||||
)
|
||||
|
||||
(defmethod srecode-root-dictionary ((dict srecode-dictionary))
|
||||
"For dictionary DICT, return the root dictionary.
|
||||
|
@ -431,10 +517,22 @@ inserted with a new editable field.")
|
|||
(start (point))
|
||||
(name (oref sti :object-name)))
|
||||
|
||||
(if (or (not dv) (string= dv ""))
|
||||
(insert name)
|
||||
(insert dv))
|
||||
(cond
|
||||
;; No default value.
|
||||
((not dv) (insert name))
|
||||
;; A compound value as the default? Recurse.
|
||||
((srecode-dictionary-compound-value-child-p dv)
|
||||
(srecode-compound-toString dv function dictionary))
|
||||
;; A string that is empty? Use the name.
|
||||
((and (stringp dv) (string= dv ""))
|
||||
(insert name))
|
||||
;; Insert strings
|
||||
((stringp dv) (insert dv))
|
||||
;; Some other issue
|
||||
(t
|
||||
(error "Unknown default value for value %S" name)))
|
||||
|
||||
;; Create a field from the inserter.
|
||||
(srecode-field name :name name
|
||||
:start start
|
||||
:end (point)
|
||||
|
@ -482,6 +580,53 @@ STATE is the current compiler state."
|
|||
(setq sectiondicts (cdr sectiondicts)))
|
||||
new)))
|
||||
|
||||
(defun srecode-create-dictionaries-from-tags (tags state)
|
||||
"Create a dictionary with entries according to TAGS.
|
||||
|
||||
TAGS should be in the format produced by the template file
|
||||
grammar. That is
|
||||
|
||||
TAGS = (ENTRY_1 ENTRY_2 ...)
|
||||
|
||||
where
|
||||
|
||||
ENTRY_N = (NAME ENTRY_N_1 ENTRY_N_2 ...) | TAG
|
||||
|
||||
where TAG is a semantic tag of class 'variable. The (NAME ... )
|
||||
form creates a child dictionary which is stored under the name
|
||||
NAME. The TAG form creates a value entry or section dictionary
|
||||
entry whose name is the name of the tag.
|
||||
|
||||
STATE is the current compiler state."
|
||||
(let ((dict (srecode-create-dictionary t))
|
||||
(entries (apply #'append
|
||||
(mapcar
|
||||
(lambda (entry)
|
||||
(cond
|
||||
;; Entry is a tag
|
||||
((semantic-tag-p entry)
|
||||
(let ((name (semantic-tag-name entry))
|
||||
(value (semantic-tag-variable-default entry)))
|
||||
(list name
|
||||
(if (and (listp value)
|
||||
(= (length value) 1)
|
||||
(stringp (car value)))
|
||||
(car value)
|
||||
value))))
|
||||
|
||||
;; Entry is a nested dictionary
|
||||
(t
|
||||
(let ((name (car entry))
|
||||
(entries (cdr entry)))
|
||||
(list name
|
||||
(srecode-create-dictionaries-from-tags
|
||||
entries state))))))
|
||||
tags))))
|
||||
(srecode-dictionary-add-entries
|
||||
dict entries state)
|
||||
dict)
|
||||
)
|
||||
|
||||
;;; DUMP DICTIONARY
|
||||
;;
|
||||
;; Make a dictionary, and dump it's contents.
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
;; Each field has 2 overlays. The second overlay allows control in
|
||||
;; the character just after the field, but does not highlight it.
|
||||
|
||||
;; @TODO - Cancel an old field array if a new one is about to be created!
|
||||
|
||||
;; Keep this library independent of SRecode proper.
|
||||
(require 'eieio)
|
||||
|
||||
|
@ -43,6 +45,10 @@
|
|||
"While inserting a set of fields, collect in this variable.
|
||||
Once an insertion set is done, these fields will be activated.")
|
||||
|
||||
|
||||
;;; Customization
|
||||
;;
|
||||
|
||||
(defface srecode-field-face
|
||||
'((((class color) (background dark))
|
||||
(:underline "green"))
|
||||
|
@ -51,6 +57,11 @@ Once an insertion set is done, these fields will be activated.")
|
|||
"*Face used to specify editable fields from a template."
|
||||
:group 'semantic-faces)
|
||||
|
||||
(defcustom srecode-fields-exit-confirmation nil
|
||||
"Ask for confirmation before leaving field editing mode."
|
||||
:group 'srecode
|
||||
:type 'boolean)
|
||||
|
||||
;;; BASECLASS
|
||||
;;
|
||||
;; Fields and the template region share some basic overlay features.
|
||||
|
@ -237,7 +248,7 @@ If SET-TO is a string, then replace the text of OLAID wit SET-TO."
|
|||
(remove-hook 'post-command-hook 'srecode-field-post-command t)
|
||||
(if (srecode-point-in-region-p ar)
|
||||
nil ;; Keep going
|
||||
;; We moved out of the temlate. Cancel the edits.
|
||||
;; We moved out of the template. Cancel the edits.
|
||||
(srecode-delete ar)))
|
||||
))
|
||||
|
||||
|
@ -429,7 +440,8 @@ PRE-LEN is used in the after mode for the length of the changed text."
|
|||
(defun srecode-field-exit-ask ()
|
||||
"Ask if the user wants to exit field-editing mini-mode."
|
||||
(interactive)
|
||||
(when (y-or-n-p "Exit field-editing mode? ")
|
||||
(when (or (not srecode-fields-exit-confirmation)
|
||||
(y-or-n-p "Exit field-editing mode? "))
|
||||
(srecode-delete (srecode-active-template-region))))
|
||||
|
||||
|
||||
|
|
|
@ -92,6 +92,23 @@ all template files for that application will be loaded."
|
|||
))
|
||||
))
|
||||
|
||||
;;; PROJECT
|
||||
;;
|
||||
;; Find if a template table has a project set, and if so, is the
|
||||
;; current buffer in that project.
|
||||
(defmethod srecode-template-table-in-project-p ((tab srecode-template-table))
|
||||
"Return non-nil if the table TAB can be used in the current project.
|
||||
If TAB has a :project set, check that the directories match.
|
||||
If TAB is nil, then always return t."
|
||||
(let ((proj (oref tab :project)))
|
||||
;; Return t if the project wasn't set.
|
||||
(if (not proj) t
|
||||
;; If the project directory was set, lets check it.
|
||||
(let ((dd (expand-file-name default-directory))
|
||||
(projexp (regexp-quote (directory-file-name proj))))
|
||||
(if (string-match (concat "^" projexp) dd)
|
||||
t nil)))))
|
||||
|
||||
;;; SEARCH
|
||||
;;
|
||||
;; Find a given template based on name, and features of the current
|
||||
|
@ -103,13 +120,14 @@ all template files for that application will be loaded."
|
|||
Optional argument CONTEXT specifies that the template should part
|
||||
of a particular context.
|
||||
The APPLICATION argument is unused."
|
||||
(if context
|
||||
;; If a context is specified, then look it up there.
|
||||
(let ((ctxth (gethash context (oref tab contexthash))))
|
||||
(when ctxth
|
||||
(gethash template-name ctxth)))
|
||||
;; No context, perhaps a merged name?
|
||||
(gethash template-name (oref tab namehash))))
|
||||
(when (srecode-template-table-in-project-p tab)
|
||||
(if context
|
||||
;; If a context is specified, then look it up there.
|
||||
(let ((ctxth (gethash context (oref tab contexthash))))
|
||||
(when ctxth
|
||||
(gethash template-name ctxth)))
|
||||
;; No context, perhaps a merged name?
|
||||
(gethash template-name (oref tab namehash)))))
|
||||
|
||||
(defmethod srecode-template-get-table ((tab srecode-mode-table)
|
||||
template-name &optional
|
||||
|
@ -144,32 +162,33 @@ tables that do not belong to an application will be searched."
|
|||
"Find in the template name in table TAB, the template with BINDING.
|
||||
Optional argument CONTEXT specifies that the template should part
|
||||
of a particular context."
|
||||
(let* ((keyout nil)
|
||||
(hashfcn (lambda (key value)
|
||||
(when (and (slot-boundp value 'binding)
|
||||
(oref value binding)
|
||||
(= (aref (oref value binding) 0) binding))
|
||||
(setq keyout key))))
|
||||
(contextstr (cond ((listp context)
|
||||
(car-safe context))
|
||||
((stringp context)
|
||||
context)
|
||||
(t nil)))
|
||||
)
|
||||
(if context
|
||||
(let ((ctxth (gethash contextstr (oref tab contexthash))))
|
||||
(when ctxth
|
||||
;; If a context is specified, then look it up there.
|
||||
(maphash hashfcn ctxth)
|
||||
;; Context hashes EXCLUDE the context prefix which
|
||||
;; we need to include, so concat it here
|
||||
(when keyout
|
||||
(setq keyout (concat contextstr ":" keyout)))
|
||||
)))
|
||||
(when (not keyout)
|
||||
;; No context, or binding in context. Try full hash.
|
||||
(maphash hashfcn (oref tab namehash)))
|
||||
keyout))
|
||||
(when (srecode-template-table-in-project-p tab)
|
||||
(let* ((keyout nil)
|
||||
(hashfcn (lambda (key value)
|
||||
(when (and (slot-boundp value 'binding)
|
||||
(oref value binding)
|
||||
(= (aref (oref value binding) 0) binding))
|
||||
(setq keyout key))))
|
||||
(contextstr (cond ((listp context)
|
||||
(car-safe context))
|
||||
((stringp context)
|
||||
context)
|
||||
(t nil)))
|
||||
)
|
||||
(if context
|
||||
(let ((ctxth (gethash contextstr (oref tab contexthash))))
|
||||
(when ctxth
|
||||
;; If a context is specified, then look it up there.
|
||||
(maphash hashfcn ctxth)
|
||||
;; Context hashes EXCLUDE the context prefix which
|
||||
;; we need to include, so concat it here
|
||||
(when keyout
|
||||
(setq keyout (concat contextstr ":" keyout)))
|
||||
)))
|
||||
(when (not keyout)
|
||||
;; No context, or binding in context. Try full hash.
|
||||
(maphash hashfcn (oref tab namehash)))
|
||||
keyout)))
|
||||
|
||||
(defmethod srecode-template-get-table-for-binding
|
||||
((tab srecode-mode-table) binding &optional context application)
|
||||
|
@ -220,7 +239,8 @@ Optional argument HASH is the hash table to fill in."
|
|||
)
|
||||
(while tabs
|
||||
;; Exclude templates for a perticular application.
|
||||
(when (not (oref (car tabs) :application))
|
||||
(when (and (not (oref (car tabs) :application))
|
||||
(srecode-template-table-in-project-p (car tabs)))
|
||||
(maphash (lambda (key temp)
|
||||
(puthash key temp mhash)
|
||||
)
|
||||
|
|
|
@ -55,8 +55,9 @@ will be derived."
|
|||
(error "No templates for inserting get/set"))
|
||||
|
||||
;; Step 1: Try to derive the tag for the class we will use
|
||||
(semantic-fetch-tags)
|
||||
(let* ((class (or class-in (srecode-auto-choose-class (point))))
|
||||
(tagstart (semantic-tag-start class))
|
||||
(tagstart (when class (semantic-tag-start class)))
|
||||
(inclass (eq (semantic-current-tag-of-class 'type) class))
|
||||
(field nil)
|
||||
)
|
||||
|
|
|
@ -26,6 +26,9 @@
|
|||
;; Manage the insertion process for a template.
|
||||
;;
|
||||
|
||||
(eval-when-compile
|
||||
(require 'cl)) ;; for `lexical-let'
|
||||
|
||||
(require 'srecode/compile)
|
||||
(require 'srecode/find)
|
||||
(require 'srecode/dictionary)
|
||||
|
@ -49,7 +52,7 @@ Possible values are:
|
|||
NOTE: The field feature does not yet work with XEmacs."
|
||||
:group 'srecode
|
||||
:type '(choice (const :tag "Ask" ask)
|
||||
(cons :tag "Field" field)))
|
||||
(const :tag "Field" field)))
|
||||
|
||||
(defvar srecode-insert-with-fields-in-progress nil
|
||||
"Non-nil means that we are actively inserting a template with fields.")
|
||||
|
@ -86,7 +89,6 @@ DICT-ENTRIES are additional dictionary values to add."
|
|||
(car dict-entries)
|
||||
(car (cdr dict-entries)))
|
||||
(setq dict-entries (cdr (cdr dict-entries))))
|
||||
;;(srecode-resolve-arguments temp newdict)
|
||||
(srecode-insert-fcn temp newdict)
|
||||
;; Don't put code here. We need to return the end-mark
|
||||
;; for this insertion step.
|
||||
|
@ -100,6 +102,10 @@ has set everything up already."
|
|||
;; Perform the insertion.
|
||||
(let ((standard-output (or stream (current-buffer)))
|
||||
(end-mark nil))
|
||||
;; Merge any template entries into the input dictionary.
|
||||
(when (slot-boundp template 'dictionary)
|
||||
(srecode-dictionary-merge dictionary (oref template dictionary)))
|
||||
|
||||
(unless skipresolver
|
||||
;; Make sure the semantic tags are up to date.
|
||||
(semantic-fetch-tags)
|
||||
|
@ -110,7 +116,7 @@ has set everything up already."
|
|||
;; If there is a buffer, turn off various hooks. This will cause
|
||||
;; the mod hooks to be buffered up during the insert, but
|
||||
;; prevent tools like font-lock from fontifying mid-template.
|
||||
;; Especialy important during insertion of complex comments that
|
||||
;; Especially important during insertion of complex comments that
|
||||
;; cause the new font-lock to comment-color stuff after the inserted
|
||||
;; comment.
|
||||
;;
|
||||
|
@ -239,6 +245,9 @@ ST can be a class, or an object."
|
|||
(defmethod srecode-insert-method ((st srecode-template) dictionary)
|
||||
"Insert the srecoder template ST."
|
||||
;; Merge any template entries into the input dictionary.
|
||||
;; This may happen twice since some templates arguments need
|
||||
;; these dictionary values earlier, but these values always
|
||||
;; need merging for template inserting in other templates.
|
||||
(when (slot-boundp st 'dictionary)
|
||||
(srecode-dictionary-merge dictionary (oref st dictionary)))
|
||||
;; Do an insertion.
|
||||
|
@ -264,7 +273,7 @@ Use DICTIONARY to resolve any macros."
|
|||
;; Specific srecode inserters.
|
||||
;; The base class is from srecode-compile.
|
||||
;;
|
||||
;; Each inserter handles various macro codes from the temlate.
|
||||
;; Each inserter handles various macro codes from the template.
|
||||
;; The `code' slot specifies a character used to identify which
|
||||
;; inserter is to be created.
|
||||
;;
|
||||
|
@ -471,7 +480,7 @@ If SECONDNAME is nil, return VALUE."
|
|||
;; (setq val (format "%S" val))))
|
||||
))
|
||||
;; Output the dumb thing unless the type of thing specifically
|
||||
;; did the inserting forus.
|
||||
;; did the inserting for us.
|
||||
(when do-princ
|
||||
(princ val))))
|
||||
|
||||
|
@ -498,7 +507,8 @@ If there is no entry, prompt the user for the value to use.
|
|||
The prompt text used is derived from the previous PROMPT command in the
|
||||
template file.")
|
||||
|
||||
(defmethod srecode-inserter-apply-state ((ins srecode-template-inserter-ask) STATE)
|
||||
(defmethod srecode-inserter-apply-state
|
||||
((ins srecode-template-inserter-ask) STATE)
|
||||
"For the template inserter INS, apply information from STATE.
|
||||
Loop over the prompts to see if we have a match."
|
||||
(let ((prompts (oref STATE prompts))
|
||||
|
@ -669,7 +679,13 @@ Arguments ESCAPE-START and ESCAPE-END are the current escape sequences in use."
|
|||
)
|
||||
|
||||
(defvar srecode-template-inserter-point-override nil
|
||||
"When non-nil, the point inserter will do this function instead.")
|
||||
"Point-positioning method for the SRecode template inserter.
|
||||
When nil, perform normal point-positioning behavior.
|
||||
When the value is a cons cell (DEPTH . FUNCTION), call FUNCTION
|
||||
instead, unless the template nesting depth, measured
|
||||
by (length (oref srecode-template active)), is greater than
|
||||
DEPTH.")
|
||||
|
||||
|
||||
(defclass srecode-template-inserter-point (srecode-template-inserter)
|
||||
((key :initform ?^
|
||||
|
@ -702,15 +718,20 @@ Arguments ESCAPE-START and ESCAPE-END are the current escape sequences in use."
|
|||
dictionary)
|
||||
"Insert the STI inserter.
|
||||
Save point in the class allocated 'point' slot.
|
||||
If `srecode-template-inserter-point-override' then this generalized
|
||||
marker will do something else. See `srecode-template-inserter-include-wrap'
|
||||
as an example."
|
||||
(if srecode-template-inserter-point-override
|
||||
If `srecode-template-inserter-point-override' non-nil then this
|
||||
generalized marker will do something else. See
|
||||
`srecode-template-inserter-include-wrap' as an example."
|
||||
;; If `srecode-template-inserter-point-override' is non-nil, its car
|
||||
;; is the maximum template nesting depth for which the override is
|
||||
;; valid. Compare this to the actual template nesting depth and
|
||||
;; maybe use the override function which is stored in the cdr.
|
||||
(if (and srecode-template-inserter-point-override
|
||||
(<= (length (oref srecode-template active))
|
||||
(car srecode-template-inserter-point-override)))
|
||||
;; Disable the old override while we do this.
|
||||
(let ((over srecode-template-inserter-point-override)
|
||||
(let ((over (cdr srecode-template-inserter-point-override))
|
||||
(srecode-template-inserter-point-override nil))
|
||||
(funcall over dictionary)
|
||||
)
|
||||
(funcall over dictionary))
|
||||
(oset sti point (point-marker))
|
||||
))
|
||||
|
||||
|
@ -751,9 +772,15 @@ Loops over the embedded CODE which was saved here during compilation.
|
|||
The template to insert is stored in SLOT."
|
||||
(let ((dicts (srecode-dictionary-lookup-name
|
||||
dictionary (oref sti :object-name))))
|
||||
(when (not (listp dicts))
|
||||
(error "Cannot insert section %S from non-section variable."
|
||||
(oref sti :object-name)))
|
||||
;; If there is no section dictionary, then don't output anything
|
||||
;; from this section.
|
||||
(while dicts
|
||||
(when (not (srecode-dictionary-p (car dicts)))
|
||||
(error "Cannot insert section %S from non-section variable."
|
||||
(oref sti :object-name)))
|
||||
(srecode-insert-subtemplate sti (car dicts) slot)
|
||||
(setq dicts (cdr dicts)))))
|
||||
|
||||
|
@ -853,39 +880,44 @@ this template instance."
|
|||
;; If there was no template name, throw an error
|
||||
(if (not templatenamepart)
|
||||
(error "Include macro %s needs a template name" (oref sti :object-name)))
|
||||
;; Find the template by name, and save it.
|
||||
(if (or (not (slot-boundp sti 'includedtemplate))
|
||||
(not (oref sti includedtemplate)))
|
||||
(let ((tmpl (srecode-template-get-table (srecode-table)
|
||||
templatenamepart))
|
||||
(active (oref srecode-template active))
|
||||
ctxt)
|
||||
|
||||
;; NOTE: We used to cache the template and not look it up a second time,
|
||||
;; but changes in the template tables can change which template is
|
||||
;; eventually discovered, so now we always lookup that template.
|
||||
|
||||
;; Calculate and store the discovered template
|
||||
(let ((tmpl (srecode-template-get-table (srecode-table)
|
||||
templatenamepart))
|
||||
(active (oref srecode-template active))
|
||||
ctxt)
|
||||
(when (not tmpl)
|
||||
;; If it isn't just available, scan back through
|
||||
;; the active template stack, searching for a matching
|
||||
;; context.
|
||||
(while (and (not tmpl) active)
|
||||
(setq ctxt (oref (car active) context))
|
||||
(setq tmpl (srecode-template-get-table (srecode-table)
|
||||
templatenamepart
|
||||
ctxt))
|
||||
(when (not tmpl)
|
||||
;; If it isn't just available, scan back through
|
||||
;; the active template stack, searching for a matching
|
||||
;; context.
|
||||
(while (and (not tmpl) active)
|
||||
(setq ctxt (oref (car active) context))
|
||||
(setq tmpl (srecode-template-get-table (srecode-table)
|
||||
templatenamepart
|
||||
ctxt))
|
||||
(when (not tmpl)
|
||||
(when (slot-boundp (car active) 'table)
|
||||
(let ((app (oref (oref (car active) table) application)))
|
||||
(when app
|
||||
(setq tmpl (srecode-template-get-table
|
||||
(srecode-table)
|
||||
templatenamepart
|
||||
ctxt app)))
|
||||
)))
|
||||
(setq active (cdr active)))
|
||||
(when (not tmpl)
|
||||
;; If it wasn't in this context, look to see if it
|
||||
;; defines its own context
|
||||
(setq tmpl (srecode-template-get-table (srecode-table)
|
||||
templatenamepart)))
|
||||
)
|
||||
(oset sti :includedtemplate tmpl)))
|
||||
(when (slot-boundp (car active) 'table)
|
||||
(let ((app (oref (oref (car active) table) application)))
|
||||
(when app
|
||||
(setq tmpl (srecode-template-get-table
|
||||
(srecode-table)
|
||||
templatenamepart
|
||||
ctxt app)))
|
||||
)))
|
||||
(setq active (cdr active)))
|
||||
(when (not tmpl)
|
||||
;; If it wasn't in this context, look to see if it
|
||||
;; defines it's own context
|
||||
(setq tmpl (srecode-template-get-table (srecode-table)
|
||||
templatenamepart)))
|
||||
)
|
||||
|
||||
;; Store the found template into this object for later use.
|
||||
(oset sti :includedtemplate tmpl))
|
||||
|
||||
(if (not (oref sti includedtemplate))
|
||||
;; @todo - Call into a debugger to help find the template in question.
|
||||
|
@ -955,23 +987,31 @@ insert the section it wraps into the location in the included
|
|||
template where a ^ inserter occurs."
|
||||
;; Step 1: Look up the included inserter
|
||||
(srecode-insert-include-lookup sti dictionary)
|
||||
;; Step 2: Temporarilly override the point inserter.
|
||||
(let* ((vaguely-unique-name sti)
|
||||
(srecode-template-inserter-point-override
|
||||
(lambda (dict2)
|
||||
(if (srecode-dictionary-lookup-name
|
||||
dict2 (oref vaguely-unique-name :object-name))
|
||||
;; Insert our sectional part with looping.
|
||||
(srecode-insert-method-helper
|
||||
vaguely-unique-name dict2 'template)
|
||||
;; Insert our sectional part just once.
|
||||
(srecode-insert-subtemplate vaguely-unique-name
|
||||
dict2 'template))
|
||||
)))
|
||||
;; Step 2: Temporarily override the point inserter.
|
||||
;; We bind `srecode-template-inserter-point-override' to a cons cell
|
||||
;; (DEPTH . FUNCTION) that has the maximum template nesting depth,
|
||||
;; for which the override is valid, in DEPTH and a lambda function
|
||||
;; which implements the wrap insertion behavior in FUNCTION. The
|
||||
;; maximum valid nesting depth is just the current depth + 1.
|
||||
(let ((srecode-template-inserter-point-override
|
||||
(lexical-let ((inserter1 sti))
|
||||
(cons
|
||||
;; DEPTH
|
||||
(+ (length (oref srecode-template active)) 1)
|
||||
;; FUNCTION
|
||||
(lambda (dict)
|
||||
(let ((srecode-template-inserter-point-override nil))
|
||||
(if (srecode-dictionary-lookup-name
|
||||
dict (oref inserter1 :object-name))
|
||||
;; Insert our sectional part with looping.
|
||||
(srecode-insert-method-helper
|
||||
inserter1 dict 'template)
|
||||
;; Insert our sectional part just once.
|
||||
(srecode-insert-subtemplate
|
||||
inserter1 dict 'template))))))))
|
||||
;; Do a regular insertion for an include, but with our override in
|
||||
;; place.
|
||||
(call-next-method)
|
||||
))
|
||||
(call-next-method)))
|
||||
|
||||
(provide 'srecode/insert)
|
||||
|
||||
|
|
|
@ -295,8 +295,14 @@ if that file is NEW, otherwise assume the mode has not changed."
|
|||
|
||||
;; 2) Do we not have a current map? If so load.
|
||||
(when (not srecode-current-map)
|
||||
(setq srecode-current-map
|
||||
(eieio-persistent-read srecode-map-save-file))
|
||||
(condition-case nil
|
||||
(setq srecode-current-map
|
||||
(eieio-persistent-read srecode-map-save-file))
|
||||
(error
|
||||
;; There was an error loading the old map. Create a new one.
|
||||
(setq srecode-current-map
|
||||
(srecode-map "SRecode Map"
|
||||
:file srecode-map-save-file))))
|
||||
)
|
||||
|
||||
)
|
||||
|
|
|
@ -112,7 +112,13 @@
|
|||
["Dump Dictionary"
|
||||
srecode-dictionary-dump
|
||||
:active t
|
||||
:help "Calculate a dump a dictionary for point."
|
||||
:help "Calculate and dump a dictionary for point."
|
||||
])
|
||||
(semantic-menu-item
|
||||
["Show Macro Help"
|
||||
srecode-macro-help
|
||||
:active t
|
||||
:help "Display the different types of macros available."
|
||||
])
|
||||
)
|
||||
)
|
||||
|
@ -196,43 +202,44 @@ MENU-DEF is the menu to bind this into."
|
|||
(setq context (car-safe (srecode-calculate-context)))
|
||||
|
||||
(while subtab
|
||||
(setq ltab (oref (car subtab) templates))
|
||||
(while ltab
|
||||
(setq temp (car ltab))
|
||||
(when (srecode-template-table-in-project-p (car subtab))
|
||||
(setq ltab (oref (car subtab) templates))
|
||||
(while ltab
|
||||
(setq temp (car ltab))
|
||||
|
||||
;; Do something with this template.
|
||||
;; Do something with this template.
|
||||
|
||||
(let* ((ctxt (oref temp context))
|
||||
(ctxtcons (assoc ctxt alltabs))
|
||||
(bind (if (slot-boundp temp 'binding)
|
||||
(oref temp binding)))
|
||||
(name (object-name-string temp)))
|
||||
(let* ((ctxt (oref temp context))
|
||||
(ctxtcons (assoc ctxt alltabs))
|
||||
(bind (if (slot-boundp temp 'binding)
|
||||
(oref temp binding)))
|
||||
(name (object-name-string temp)))
|
||||
|
||||
(when (not ctxtcons)
|
||||
(if (string= context ctxt)
|
||||
;; If this context is not in the current list of contexts
|
||||
;; is equal to the current context, then manage the
|
||||
;; active list instead
|
||||
(setq active
|
||||
(setq ctxtcons (or active (cons ctxt nil))))
|
||||
;; This is not an active context, add it to alltabs.
|
||||
(setq ctxtcons (cons ctxt nil))
|
||||
(setq alltabs (cons ctxtcons alltabs))))
|
||||
(when (not ctxtcons)
|
||||
(if (string= context ctxt)
|
||||
;; If this context is not in the current list of contexts
|
||||
;; is equal to the current context, then manage the
|
||||
;; active list instead
|
||||
(setq active
|
||||
(setq ctxtcons (or active (cons ctxt nil))))
|
||||
;; This is not an active context, add it to alltabs.
|
||||
(setq ctxtcons (cons ctxt nil))
|
||||
(setq alltabs (cons ctxtcons alltabs))))
|
||||
|
||||
(let ((new (vector
|
||||
(if bind
|
||||
(concat name " (" bind ")")
|
||||
name)
|
||||
`(lambda () (interactive)
|
||||
(srecode-insert (concat ,ctxt ":" ,name)))
|
||||
t)))
|
||||
(let ((new (vector
|
||||
(if bind
|
||||
(concat name " (" bind ")")
|
||||
name)
|
||||
`(lambda () (interactive)
|
||||
(srecode-insert (concat ,ctxt ":" ,name)))
|
||||
t)))
|
||||
|
||||
(setcdr ctxtcons (cons
|
||||
new
|
||||
(cdr ctxtcons)))))
|
||||
(setcdr ctxtcons (cons
|
||||
new
|
||||
(cdr ctxtcons)))))
|
||||
|
||||
(setq ltab (cdr ltab)))
|
||||
(setq subtab (cdr subtab)))
|
||||
(setq ltab (cdr ltab))))
|
||||
(setq subtab (cdr subtab)))
|
||||
|
||||
;; Now create the menu
|
||||
(easy-menu-filter-return
|
||||
|
@ -273,6 +280,7 @@ MENU-DEF is the menu to bind this into."
|
|||
This command will insert whichever srecode template has a binding
|
||||
to the current key."
|
||||
(interactive)
|
||||
(srecode-load-tables-for-mode major-mode)
|
||||
(let* ((k last-command-event)
|
||||
(ctxt (srecode-calculate-context))
|
||||
;; Find the template with the binding K
|
||||
|
|
|
@ -91,7 +91,7 @@ The hook is called with two arguments, the TAG and DICT
|
|||
to be augmented.")
|
||||
|
||||
(define-overload srecode-semantic-apply-tag-to-dict (tagobj dict)
|
||||
"Insert fewatures of TAGOBJ into the dictionary DICT.
|
||||
"Insert features of TAGOBJ into the dictionary DICT.
|
||||
TAGOBJ is an object of class `srecode-semantic-tag'. This class
|
||||
is a compound inserter value.
|
||||
DICT is a dictionary object.
|
||||
|
@ -195,7 +195,7 @@ variable default values, and other things."
|
|||
;;; :tag ARGUMENT HANDLING
|
||||
;;
|
||||
;; When a :tag argument is required, identify the current :tag,
|
||||
;; and apply it's parts into the dictionary.
|
||||
;; and apply its parts into the dictionary.
|
||||
(defun srecode-semantic-handle-:tag (dict)
|
||||
"Add macros into the dictionary DICT based on the current :tag."
|
||||
;; We have a tag, start adding "stuff" into the dictionary.
|
||||
|
@ -305,8 +305,8 @@ or `code'.
|
|||
|
||||
For various conditions, this function looks for a template with
|
||||
the name CLASS-tag, where CLASS is the tag class. If it cannot
|
||||
find that, it will look for that template in the
|
||||
`declaration'context (if the current context was not `declaration').
|
||||
find that, it will look for that template in the `declaration'
|
||||
context (if the current context was not `declaration').
|
||||
|
||||
If PROTOTYPE is specified, it will first look for templates with
|
||||
the name CLASS-tag-prototype, or CLASS-prototype as above.
|
||||
|
@ -382,7 +382,7 @@ as `function' will leave point where code might be inserted."
|
|||
(error "Cannot find template %s in %s for inserting tag %S"
|
||||
errtype top (semantic-format-tag-summarize tag)))
|
||||
|
||||
;; Resolve Arguments
|
||||
;; Resolve arguments
|
||||
(let ((srecode-semantic-selected-tag tag))
|
||||
(srecode-resolve-arguments temp dict))
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
(require 'srecode)
|
||||
|
||||
(declare-function srecode-load-tables-for-mode "srecode/find")
|
||||
(declare-function srecode-template-table-in-project-p "srecode/find")
|
||||
|
||||
;;; Code:
|
||||
|
||||
|
@ -74,6 +75,12 @@ Emacs Lisp code to fill in the dictionary.")
|
|||
When there are multiple template files with similar names, templates with
|
||||
the highest priority are scanned last, allowing them to override values in
|
||||
previous template files.")
|
||||
(project :initarg :project
|
||||
:type (or null string)
|
||||
:documentation
|
||||
"Scope some project files to a specific project.
|
||||
The value is a directory which forms the root of a particular project,
|
||||
or a subset of a particular project.")
|
||||
;;
|
||||
;; Parsed Data from the template file
|
||||
;;
|
||||
|
@ -224,6 +231,12 @@ Use PREDICATE is the same as for the `sort' function."
|
|||
(when (oref tab :application)
|
||||
(princ "\nApplication: ")
|
||||
(princ (oref tab :application)))
|
||||
(when (oref tab :project)
|
||||
(require 'srecode/find) ; For srecode-template-table-in-project-p
|
||||
(princ "\nProject Directory: ")
|
||||
(princ (oref tab :project))
|
||||
(when (not (srecode-template-table-in-project-p tab))
|
||||
(princ "\n ** Not Usable in this file. **")))
|
||||
(princ "\n\nVariables:\n")
|
||||
(let ((vars (oref tab variables)))
|
||||
(while vars
|
||||
|
|
|
@ -175,10 +175,17 @@ Adds the following:
|
|||
|
||||
(define-mode-local-override semantic-insert-foreign-tag
|
||||
texinfo-mode (foreign-tag)
|
||||
"Insert TAG from a foreign buffer in TAGFILE.
|
||||
"Insert FOREIGN-TAG from a foreign buffer in TAGFILE.
|
||||
Assume TAGFILE is a source buffer, and create a documentation
|
||||
thingy from it using the `document' tool."
|
||||
(let ((srecode-semantic-selected-tag foreign-tag))
|
||||
(srecode-texi-insert-tag-as-doc foreign-tag))
|
||||
|
||||
(defun srecode-texi-insert-tag-as-doc (tag)
|
||||
"Insert TAG into the current buffer with SRecode."
|
||||
(when (not (eq major-mode 'texinfo-mode))
|
||||
(error "Can only insert tags into texinfo in texinfo mode"))
|
||||
(let ((srecode-semantic-selected-tag tag))
|
||||
(srecode-load-tables-for-mode major-mode)
|
||||
;; @todo - choose of the many types of tags to insert,
|
||||
;; or put all that logic into srecode.
|
||||
(srecode-insert "declaration:function")))
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
;; 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Eric M. Ludlam <zappo@gnu.org>
|
||||
;; Version: 0.2
|
||||
;; Version: 1.3
|
||||
;; Keywords: OO, lisp
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
@ -31,6 +31,11 @@
|
|||
;; Emacs running environment.
|
||||
;;
|
||||
;; See eieio.texi for complete documentation on using this package.
|
||||
;;
|
||||
;; Note: the implementation of the c3 algorithm is based on:
|
||||
;; Kim Barrett et al.: A Monotonic Superclass Linearization for Dylan
|
||||
;; Retrieved from:
|
||||
;; http://192.220.96.201/dylan/linearization-oopsla96.html
|
||||
|
||||
;; There is funny stuff going on with typep and deftype. This
|
||||
;; is the only way I seem to be able to make this stuff load properly.
|
||||
|
@ -44,7 +49,7 @@
|
|||
(require 'cl)
|
||||
(require 'eieio-comp))
|
||||
|
||||
(defvar eieio-version "1.2"
|
||||
(defvar eieio-version "1.3"
|
||||
"Current version of EIEIO.")
|
||||
|
||||
(defun eieio-version ()
|
||||
|
@ -79,7 +84,7 @@
|
|||
"*This hook is executed, then cleared each time `defclass' is called.")
|
||||
|
||||
(defvar eieio-error-unsupported-class-tags nil
|
||||
"*Non-nil to throw an error if an encountered tag us unsupported.
|
||||
"Non-nil to throw an error if an encountered tag is unsupported.
|
||||
This may prevent classes from CLOS applications from being used with EIEIO
|
||||
since EIEIO does not support all CLOS tags.")
|
||||
|
||||
|
@ -170,6 +175,13 @@ Stored outright without modifications or stripping.")
|
|||
(defconst method-generic-after 6 "Index into generic :after tag on a method.")
|
||||
(defconst method-num-slots 7 "Number of indexes into a method's vector.")
|
||||
|
||||
(defsubst eieio-specialized-key-to-generic-key (key)
|
||||
"Convert a specialized KEY into a generic method key."
|
||||
(cond ((eq key method-static) 0) ;; don't convert
|
||||
((< key method-num-lists) (+ key 3)) ;; The conversion
|
||||
(t key) ;; already generic.. maybe.
|
||||
))
|
||||
|
||||
;; How to specialty compile stuff.
|
||||
(autoload 'byte-compile-file-form-defmethod "eieio-comp"
|
||||
"This function is used to byte compile methods in a nice way.")
|
||||
|
@ -243,8 +255,7 @@ Methods with only primary implementations are executed in an optimized way."
|
|||
))
|
||||
|
||||
(defmacro class-option-assoc (list option)
|
||||
"Return from LIST the found OPTION.
|
||||
Return nil if it doesn't exist."
|
||||
"Return from LIST the found OPTION, or nil if it doesn't exist."
|
||||
`(car-safe (cdr (memq ,option ,list))))
|
||||
|
||||
(defmacro class-option (class option)
|
||||
|
@ -518,7 +529,7 @@ See `defclass' for more information."
|
|||
|
||||
;; Make sure the method invocation order is a valid value.
|
||||
(let ((io (class-option-assoc options :method-invocation-order)))
|
||||
(when (and io (not (member io '(:depth-first :breadth-first))))
|
||||
(when (and io (not (member io '(:depth-first :breadth-first :c3))))
|
||||
(error "Method invocation order %s is not allowed" io)
|
||||
))
|
||||
|
||||
|
@ -800,11 +811,11 @@ See `defclass' for more information."
|
|||
(defun eieio-perform-slot-validation-for-default (slot spec value skipnil)
|
||||
"For SLOT, signal if SPEC does not match VALUE.
|
||||
If SKIPNIL is non-nil, then if VALUE is nil return t instead."
|
||||
(let ((val (eieio-default-eval-maybe value)))
|
||||
(if (and (not eieio-skip-typecheck)
|
||||
(not (and skipnil (null val)))
|
||||
(not (eieio-perform-slot-validation spec val)))
|
||||
(signal 'invalid-slot-type (list slot spec val)))))
|
||||
(if (and (not (eieio-eval-default-p value))
|
||||
(not eieio-skip-typecheck)
|
||||
(not (and skipnil (null value)))
|
||||
(not (eieio-perform-slot-validation spec value)))
|
||||
(signal 'invalid-slot-type (list slot spec value))))
|
||||
|
||||
(defun eieio-add-new-slot (newc a d doc type cust label custg print prot init alloc
|
||||
&optional defaultoverride skipnil)
|
||||
|
@ -1340,7 +1351,7 @@ Summary:
|
|||
(if (= key -1)
|
||||
(signal 'wrong-type-argument (list :static 'non-class-arg)))
|
||||
;; generics are higher
|
||||
(setq key (+ key 3)))
|
||||
(setq key (eieio-specialized-key-to-generic-key key)))
|
||||
;; Put this lambda into the symbol so we can find it
|
||||
(if (byte-code-function-p (car-safe body))
|
||||
(eieiomt-add method (car-safe body) key argclass)
|
||||
|
@ -1516,13 +1527,21 @@ Fills in OBJ's SLOT with its default value."
|
|||
(eieio-default-eval-maybe val))
|
||||
obj cl 'oref-default))))
|
||||
|
||||
(defsubst eieio-eval-default-p (val)
|
||||
"Whether the default value VAL should be evaluated for use."
|
||||
(and (consp val) (symbolp (car val)) (fboundp (car val))))
|
||||
|
||||
(defun eieio-default-eval-maybe (val)
|
||||
"Check VAL, and return what `oref-default' would provide."
|
||||
;; check for quoted things, and unquote them
|
||||
(if (and (listp val) (eq (car val) 'quote))
|
||||
(car (cdr val))
|
||||
;; return it verbatim
|
||||
val))
|
||||
(cond
|
||||
;; Is it a function call? If so, evaluate it.
|
||||
((eieio-eval-default-p val)
|
||||
(eval val))
|
||||
;;;; check for quoted things, and unquote them
|
||||
;;((and (consp val) (eq (car val) 'quote))
|
||||
;; (car (cdr val)))
|
||||
;; return it verbatim
|
||||
(t val)))
|
||||
|
||||
;;; Object Set macros
|
||||
;;
|
||||
|
@ -1677,6 +1696,116 @@ The CLOS function `class-direct-subclasses' is aliased to this function."
|
|||
(if (not (class-p class)) (signal 'wrong-type-argument (list 'class-p class)))
|
||||
(class-children-fast class))
|
||||
|
||||
(defun eieio-c3-candidate (class remaining-inputs)
|
||||
"Returns CLASS if it can go in the result now, otherwise nil"
|
||||
;; Ensure CLASS is not in any position but the first in any of the
|
||||
;; element lists of REMAINING-INPUTS.
|
||||
(and (not (let ((found nil))
|
||||
(while (and remaining-inputs (not found))
|
||||
(setq found (member class (cdr (car remaining-inputs)))
|
||||
remaining-inputs (cdr remaining-inputs)))
|
||||
found))
|
||||
class))
|
||||
|
||||
(defun eieio-c3-merge-lists (reversed-partial-result remaining-inputs)
|
||||
"Merge REVERSED-PARTIAL-RESULT REMAINING-INPUTS in a consistent order, if possible.
|
||||
If a consistent order does not exist, signal an error."
|
||||
(if (let ((tail remaining-inputs)
|
||||
(found nil))
|
||||
(while (and tail (not found))
|
||||
(setq found (car tail) tail (cdr tail)))
|
||||
(not found))
|
||||
;; If all remaining inputs are empty lists, we are done.
|
||||
(nreverse reversed-partial-result)
|
||||
;; Otherwise, we try to find the next element of the result. This
|
||||
;; is achieved by considering the first element of each
|
||||
;; (non-empty) input list and accepting a candidate if it is
|
||||
;; consistent with the rests of the input lists.
|
||||
(let* ((found nil)
|
||||
(tail remaining-inputs)
|
||||
(next (progn
|
||||
(while (and tail (not found))
|
||||
(setq found (and (car tail)
|
||||
(eieio-c3-candidate (caar tail)
|
||||
remaining-inputs))
|
||||
tail (cdr tail)))
|
||||
found)))
|
||||
(if next
|
||||
;; The graph is consistent so far, add NEXT to result and
|
||||
;; merge input lists, dropping NEXT from their heads where
|
||||
;; applicable.
|
||||
(eieio-c3-merge-lists
|
||||
(cons next reversed-partial-result)
|
||||
(mapcar (lambda (l) (if (eq (first l) next) (rest l) l))
|
||||
remaining-inputs))
|
||||
;; The graph is inconsistent, give up
|
||||
(signal 'inconsistent-class-hierarchy (list remaining-inputs))))))
|
||||
|
||||
(defun eieio-class-precedence-dfs (class)
|
||||
"Return all parents of CLASS in depth-first order."
|
||||
(let* ((parents (class-parents-fast class))
|
||||
(classes (copy-sequence
|
||||
(apply #'append
|
||||
(list class)
|
||||
(or
|
||||
(mapcar
|
||||
(lambda (parent)
|
||||
(cons parent
|
||||
(eieio-class-precedence-dfs parent)))
|
||||
parents)
|
||||
'((eieio-default-superclass))))))
|
||||
(tail classes))
|
||||
;; Remove duplicates.
|
||||
(while tail
|
||||
(setcdr tail (delq (car tail) (cdr tail)))
|
||||
(setq tail (cdr tail)))
|
||||
classes))
|
||||
|
||||
(defun eieio-class-precedence-bfs (class)
|
||||
"Return all parents of CLASS in breadth-first order."
|
||||
(let ((result)
|
||||
(queue (or (class-parents-fast class)
|
||||
'(eieio-default-superclass))))
|
||||
(while queue
|
||||
(let ((head (pop queue)))
|
||||
(unless (member head result)
|
||||
(push head result)
|
||||
(unless (eq head 'eieio-default-superclass)
|
||||
(setq queue (append queue (or (class-parents-fast head)
|
||||
'(eieio-default-superclass))))))))
|
||||
(cons class (nreverse result)))
|
||||
)
|
||||
|
||||
(defun eieio-class-precedence-c3 (class)
|
||||
"Return all parents of CLASS in c3 order."
|
||||
(let ((parents (class-parents-fast class)))
|
||||
(eieio-c3-merge-lists
|
||||
(list class)
|
||||
(append
|
||||
(or
|
||||
(mapcar
|
||||
(lambda (x)
|
||||
(eieio-class-precedence-c3 x))
|
||||
parents)
|
||||
'((eieio-default-superclass)))
|
||||
(list parents))))
|
||||
)
|
||||
|
||||
(defun class-precedence-list (class)
|
||||
"Return (transitively closed) list of parents of CLASS.
|
||||
The order, in which the parents are returned depends on the
|
||||
method invocation orders of the involved classes."
|
||||
(if (or (null class) (eq class 'eieio-default-superclass))
|
||||
nil
|
||||
(case (class-method-invocation-order class)
|
||||
(:depth-first
|
||||
(eieio-class-precedence-dfs class))
|
||||
(:breadth-first
|
||||
(eieio-class-precedence-bfs class))
|
||||
(:c3
|
||||
(eieio-class-precedence-c3 class))))
|
||||
)
|
||||
|
||||
;; Official CLOS functions.
|
||||
(defalias 'class-direct-superclasses 'class-parents)
|
||||
(defalias 'class-direct-subclasses 'class-children)
|
||||
|
@ -1714,7 +1843,8 @@ The CLOS function `class-direct-subclasses' is aliased to this function."
|
|||
p (cdr p)))
|
||||
(if child t)))
|
||||
|
||||
(defun object-slots (obj) "Return list of slots available in OBJ."
|
||||
(defun object-slots (obj)
|
||||
"Return list of slots available in OBJ."
|
||||
(if (not (eieio-object-p obj)) (signal 'wrong-type-argument (list 'eieio-object-p obj)))
|
||||
(aref (class-v (object-class-fast obj)) class-public-a))
|
||||
|
||||
|
@ -2008,14 +2138,26 @@ This should only be called from a generic function."
|
|||
keys (append (make-list (length tlambdas) method-before) keys))
|
||||
)
|
||||
|
||||
;; If there were no methods found, then there could be :static methods.
|
||||
(when (not lambdas)
|
||||
(if mclass
|
||||
;; For the case of a class,
|
||||
;; if there were no methods found, then there could be :static methods.
|
||||
(when (not lambdas)
|
||||
(setq tlambdas
|
||||
(eieio-generic-form method method-static mclass))
|
||||
(setq lambdas (cons tlambdas lambdas)
|
||||
keys (cons method-static keys)
|
||||
primarymethodlist ;; Re-use even with bad name here
|
||||
(eieiomt-method-list method method-static mclass)))
|
||||
;; For the case of no class (ie - mclass == nil) then there may
|
||||
;; be a primary method.
|
||||
(setq tlambdas
|
||||
(eieio-generic-form method method-static mclass))
|
||||
(setq lambdas (cons tlambdas lambdas)
|
||||
keys (cons method-static keys)
|
||||
primarymethodlist ;; Re-use even with bad name here
|
||||
(eieiomt-method-list method method-static mclass)))
|
||||
(eieio-generic-form method method-primary nil))
|
||||
(when tlambdas
|
||||
(setq lambdas (cons tlambdas lambdas)
|
||||
keys (cons method-primary keys)
|
||||
primarymethodlist
|
||||
(eieiomt-method-list method method-primary nil)))
|
||||
)
|
||||
|
||||
(run-hook-with-args 'eieio-pre-method-execution-hooks
|
||||
primarymethodlist)
|
||||
|
@ -2142,37 +2284,23 @@ CLASS is the starting class to search from in the method tree.
|
|||
If CLASS is nil, then an empty list of methods should be returned."
|
||||
;; Note: eieiomt - the MT means MethodTree. See more comments below
|
||||
;; for the rest of the eieiomt methods.
|
||||
(let ((lambdas nil)
|
||||
(mclass (list class)))
|
||||
(while mclass
|
||||
;; Note: a nil can show up in the class list once we start
|
||||
;; searching through the method tree.
|
||||
(when (car mclass)
|
||||
;; lookup the form to use for the PRIMARY object for the next level
|
||||
(let ((tmpl (eieio-generic-form method key (car mclass))))
|
||||
(when (or (not lambdas)
|
||||
;; This prevents duplicates coming out of the
|
||||
;; class method optimizer. Perhaps we should
|
||||
;; just not optimize before/afters?
|
||||
(not (eq (car tmpl) (car (car lambdas)))))
|
||||
(setq lambdas (cons tmpl lambdas))
|
||||
(if (null (car lambdas))
|
||||
(setq lambdas (cdr lambdas))))))
|
||||
;; Add new classes to mclass. Since our input might not be a class
|
||||
;; protect against that.
|
||||
(if (car mclass)
|
||||
;; If there is a class, append any methods it may provide
|
||||
;; to the remainder of the class list.
|
||||
(let ((io (class-method-invocation-order (car mclass))))
|
||||
(if (eq io :depth-first)
|
||||
;; Depth first.
|
||||
(setq mclass (append (eieiomt-next (car mclass)) (cdr mclass)))
|
||||
;; Breadth first.
|
||||
(setq mclass (append (cdr mclass) (eieiomt-next (car mclass)))))
|
||||
)
|
||||
;; Advance to next entry in mclass if it is nil.
|
||||
(setq mclass (cdr mclass)))
|
||||
)
|
||||
|
||||
;; Collect lambda expressions stored for the class and its parent
|
||||
;; classes.
|
||||
(let (lambdas)
|
||||
(dolist (ancestor (class-precedence-list class))
|
||||
;; Lookup the form to use for the PRIMARY object for the next level
|
||||
(let ((tmpl (eieio-generic-form method key ancestor)))
|
||||
(when (and tmpl
|
||||
(or (not lambdas)
|
||||
;; This prevents duplicates coming out of the
|
||||
;; class method optimizer. Perhaps we should
|
||||
;; just not optimize before/afters?
|
||||
(not (member tmpl lambdas))))
|
||||
(push tmpl lambdas))))
|
||||
|
||||
;; Return collected lambda. For :after methods, return in current
|
||||
;; order (most general class last); Otherwise, reverse order.
|
||||
(if (eq key method-after)
|
||||
lambdas
|
||||
(nreverse lambdas))))
|
||||
|
@ -2206,6 +2334,7 @@ Use `next-method-p' to find out if there is a next method to call."
|
|||
(apply 'no-next-method (car newargs) (cdr newargs))
|
||||
(let* ((eieio-generic-call-next-method-list
|
||||
(cdr eieio-generic-call-next-method-list))
|
||||
(eieio-generic-call-arglst newargs)
|
||||
(scoped-class (cdr next))
|
||||
(fcn (car next))
|
||||
)
|
||||
|
@ -2298,32 +2427,18 @@ nil for superclasses. This function performs no type checking!"
|
|||
|
||||
(defun eieiomt-sym-optimize (s)
|
||||
"Find the next class above S which has a function body for the optimizer."
|
||||
;; (message "Optimizing %S" s)
|
||||
(let* ((es (intern-soft (symbol-name s))) ;external symbol of class
|
||||
(io (class-method-invocation-order es))
|
||||
(ov nil)
|
||||
(cont t))
|
||||
;; This converts ES from a single symbol to a list of parent classes.
|
||||
(setq es (eieiomt-next es))
|
||||
;; Loop over ES, then its children individually.
|
||||
;; We can have multiple hits only at one level of the parent tree.
|
||||
(while (and es cont)
|
||||
(setq ov (intern-soft (symbol-name (car es)) eieiomt-optimizing-obarray))
|
||||
(if (fboundp ov)
|
||||
(progn
|
||||
(set s ov) ;store ov as our next symbol
|
||||
(setq cont nil))
|
||||
(if (eq io :depth-first)
|
||||
;; Pre-pend the subclasses of (car es) so we get
|
||||
;; DEPTH FIRST optimization.
|
||||
(setq es (append (eieiomt-next (car es)) (cdr es)))
|
||||
;; Else, we are breadth first.
|
||||
;; (message "Class %s is breadth first" es)
|
||||
(setq es (append (cdr es) (eieiomt-next (car es))))
|
||||
)))
|
||||
;; If there is no nearest call, then set our value to nil
|
||||
(if (not es) (set s nil))
|
||||
))
|
||||
;; Set the value to nil in case there is no nearest cell.
|
||||
(set s nil)
|
||||
;; Find the nearest cell that has a function body. If we find one,
|
||||
;; we replace the nil from above.
|
||||
(let ((external-symbol (intern-soft (symbol-name s))))
|
||||
(catch 'done
|
||||
(dolist (ancestor (rest (class-precedence-list external-symbol)))
|
||||
(let ((ov (intern-soft (symbol-name ancestor)
|
||||
eieiomt-optimizing-obarray)))
|
||||
(when (fboundp ov)
|
||||
(set s ov) ;; store ov as our next symbol
|
||||
(throw 'done ancestor)))))))
|
||||
|
||||
(defun eieio-generic-form (method key class)
|
||||
"Return the lambda form belonging to METHOD using KEY based upon CLASS.
|
||||
|
@ -2332,7 +2447,7 @@ no form, but has a parent class, then trace to that parent class.
|
|||
The first time a form is requested from a symbol, an optimized path
|
||||
is memorized for faster future use."
|
||||
(let ((emto (aref (get method 'eieio-method-obarray)
|
||||
(if class key (+ key 3)))))
|
||||
(if class key (eieio-specialized-key-to-generic-key key)))))
|
||||
(if (class-p class)
|
||||
;; 1) find our symbol
|
||||
(let ((cs (intern-soft (symbol-name class) emto)))
|
||||
|
@ -2365,7 +2480,7 @@ is memorized for faster future use."
|
|||
nil)))
|
||||
;; for a generic call, what is a list, is the function body we want.
|
||||
(let ((emtl (aref (get method 'eieio-method-tree)
|
||||
(if class key (+ key 3)))))
|
||||
(if class key (eieio-specialized-key-to-generic-key key)))))
|
||||
(if emtl
|
||||
;; The car of EMTL is supposed to be a class, which in this
|
||||
;; case is nil, so skip it.
|
||||
|
@ -2430,6 +2545,11 @@ This is usually a symbol that starts with `:'."
|
|||
(put 'unbound-slot 'error-conditions '(unbound-slot error nil))
|
||||
(put 'unbound-slot 'error-message "Unbound slot")
|
||||
|
||||
(intern "inconsistent-class-hierarchy")
|
||||
(put 'inconsistent-class-hierarchy 'error-conditions
|
||||
'(inconsistent-class-hierarchy error nil))
|
||||
(put 'inconsistent-class-hierarchy 'error-message "Inconsistent class hierarchy")
|
||||
|
||||
;;; Here are some CLOS items that need the CL package
|
||||
;;
|
||||
|
||||
|
@ -2525,6 +2645,17 @@ dynamically set from SLOTS."
|
|||
(slot (aref scoped-class class-public-a))
|
||||
(defaults (aref scoped-class class-public-d)))
|
||||
(while slot
|
||||
;; For each slot, see if we need to evaluate it.
|
||||
;;
|
||||
;; Paul Landes said in an email:
|
||||
;; > CL evaluates it if it can, and otherwise, leaves it as
|
||||
;; > the quoted thing as you already have. This is by the
|
||||
;; > Sonya E. Keene book and other things I've look at on the
|
||||
;; > web.
|
||||
(let ((dflt (eieio-default-eval-maybe (car defaults))))
|
||||
(when (not (eq dflt (car defaults)))
|
||||
(eieio-oset this (car slot) dflt) ))
|
||||
;; Next.
|
||||
(setq slot (cdr slot)
|
||||
defaults (cdr defaults))))
|
||||
;; Shared initialize will parse our slots for us.
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue