diff options
author | Chong Yidong <cyd@gnu.org> | 2012-10-02 02:10:29 +0800 |
---|---|---|
committer | Chong Yidong <cyd@gnu.org> | 2012-10-02 02:10:29 +0800 |
commit | 62a81506f802e4824b718cc30321ee3a0057cdf7 (patch) | |
tree | d681d7b767b1c3f7e4aee24ce39f6bef0d7f1f7e /lisp | |
parent | b3317662acc0157406c20c8e14c43b7126eaa8a0 (diff) | |
download | emacs-62a81506f802e4824b718cc30321ee3a0057cdf7.tar.gz |
Update CEDET from upstream.
Diffstat (limited to 'lisp')
95 files changed, 4386 insertions, 1298 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index b5ccfcfcc7c..b324dce5164 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,45 @@ +2012-10-01 David Engster <deng@randomsample.de> + + * emacs-lisp/eieio-opt.el (eieio-describe-class): Add filename + from symbol property and change message to be more consistent with + Emacs proper. + (eieio-describe-generic): Add filename for each implementation. + Fix indices for generic and normal methods. + (eieio-method-def, eieio-class-def): New buttons. + (eieio-help-find-method-definition) + (eieio-help-find-class-definition): New functions. + (eieio-help-mode-augmentation-maybee): Add buttons to filenames of + class, constructor and method definitions. + + * emacs-lisp/eieio.el (eieiomt-add, eieio-defclass): Save file + information in symbol property. + (scoped-class): Remove. + (eieio-slot-name-index, call-next-method): Check if it is bound. + +2012-10-01 Leo P. White <lpw25@cam.ac.uk> + + * emacs-lisp/eieio-custom.el (eieio-custom-mode-map): New option. + (eieio-custom-mode): New major mode. + (eieio-customize-object): Use it. + +2012-10-01 Eric Ludlam <zappo@gnu.org> + + * emacs-lisp/eieio-base.el (eieio-persistent-read): New input args + specifying the expected class, and whether subclassing is allowed. + (eieio-persistent-convert-list-to-object): + (eieio-persistent-validate/fix-slot-value) + (eieio-persistent-slot-type-is-class-p): New functions. + (eieio-named::slot-missing): Doc fix. + + * emacs-lisp/eieio-datadebug.el (data-debug/eieio-insert-slots): + Stop using unused publd variable. + + * emacs-lisp/eieio-speedbar.el (eieio-speedbar-handle-click): + (eieio-speedbar-description, eieio-speedbar-derive-line-path) + (eieio-speedbar-object-buttonname, eieio-speedbar-make-tag-line) + (eieio-speedbar-handle-click): Do not specify a class for the + method. Fixes method invocation order problems with EDE. + 2012-10-01 Stefan Monnier <monnier@iro.umontreal.ca> * emacs-lisp/bytecomp.el (byte-compiler-abbreviate-file): New function. diff --git a/lisp/cedet/ChangeLog b/lisp/cedet/ChangeLog index 925bde8a193..cae56e2f07c 100644 --- a/lisp/cedet/ChangeLog +++ b/lisp/cedet/ChangeLog @@ -1,3 +1,497 @@ +2012-10-01 Chong Yidong <cyd@gnu.org> + + * semantic/bovine/c-by.el: Regenerate. + * semantic/bovine/make-by.el: + * semantic/bovine/scm-by.el: + * semantic/grammar-wy.el: + * semantic/wisent/javat-wy.el: + * semantic/wisent/js-wy.el: + * srecode/srt-wy.el: + +2012-10-01 Eric Ludlam <zappo@gnu.org> + + * cedet.el (cedet-version, cedet-packages): Update. + + * cedet-global.el (cedet-gnu-global-version-check): Support newer + versions that have extra (parens) in the version string. + + * cedet-idutils.el (cedet-idutils-version-check): Make sure a + version number was found before calling inversion-check-version. + + * data-debug.el (data-debug-insert-thing): Bind inhibit-read-only + while inserting the thing, then clear modified bit. + (data-debug-map): Suppress the keymap. + (data-debug-mode, data-debug-new-buffer): Make buffer read-only. + (data-debug-contract-current-line): Inhibit read-only, then clear + modified bit. + + * ede.el (ede-buffer-belongs-to-project-p): Use ede-object-project + to allow use in more kinds of buffers. + (ede-project-forms-menu): Add `Default configuration' menu item. + (ede-configuration-forms-menu): New, for use in above. + (ede-project-configurations-set): New command used from menu. + (ede-java-classpath): New conveninece for Java support. + (ede-apply-object-keymap): Combine keybindings from the project + and the target, not just whatever is local to the buffer. + (ede-apply-target-options): Call fcn to apply project local + variables. + (ede-reset-all-buffers): Remove arg. + (ede, ede-rescan-toplevel): Callers changed. + (ede-new-target): Fix bug where you couldn't call this from Dired. + (ede-add-file): Replace assignment of ede-object with generic call + to re-init the buffer. + (ede-find-target): If ede-object is set, run short-cut code + instead of `or' shortcut. + (ede-project-buffers): Return buffers belonging to input project, + not any buffer belonging to any project. + (ede-system-include-path, ede-apply-project-local-variables) + (ede-set-project-local-variable): New functions. + (ede-make-project-local-variable): Apply to toplevel if none + specified. + (ede-set): Make it interactive. + + * ede/auto.el (ede-project-autoload): New class. + (ede-do-dirmatch): New method. + (ede-project-dirmatch-p): New function. + (ede-project-root-directory): Call it. + (ede-dir-to-projectfile): Don't call project file function if we + didn't match the root. + (ede-project-root-directory): Don't call a project's root function + if the tool in question isn't installed. + (ede-dir-to-projectfile): Don't call project file function if we + didn't match the root. + + * ede/autoconf-edit.el (autoconf-parameter-strip): Remove any + trailing `\' mid string, and replace with a space. + (autoconf-parameter-count): New function. + (autoconf-set-version): Use it. + + * ede/base.el (ede-project): The :type of targets is now a list of + target base classes. + + * ede/emacs.el (ede-emacs-load): Fix typo. + + * ede/files.el (ede-flush-project-hash, ede-flush-directory-hash): + Protect against missing locator object. + (ede-get-locator-object): Protect against missing project. + (ede-flush-directory-hash): New command. + (ede-get-locator-object): Protect against missing project. + + * ede/generic.el (ede-generic-config): Add configurable + `run-command' slot. + (project-compile-project, project-compile-target) + (project-debug-target, project-run-target): New methods. + (ede-generic-get-configuration): Specify the class to load. + (ede-generic-new-autoloader): Use ede-add-project-autoload. + (ede-enable-generic-projects): Rename projects so as to never + match the edeproject-* projects. + + * ede/makefile-edit.el (makefile-macro-file-list): Case sensitive + searches. Protect against "SUBDIRS=$(subdirs)" infloop. + + * ede/proj-elisp.el (ede-proj-tweak-autoconf) + (ede-proj-flush-autoconf): Disable local variables when loading + the autoconf lisp compile script. + + * ede/proj.el (ede-proj-target-aux, -elisp, -elisp-autoloads) + (-scheme, -makefile-misc, ede-proj-target-makefile-program) + (-makefile-archive, -makefile-shared-object) + (ede-proj-target-makefile-info, -grammar): New autoloads. + (ede-proj-project): Inherit from eieio-persistent-read. Specify + extension and header line. + (ede-proj-load, ede-proj-save): Replace with impl using + eieio-persistent-read. + + * ede/project-am.el (project-add-file): Use ede-target-parent + instead of loading the project file. + + * semantic.el (semantic-version): Update. + (semantic-new-buffer-setup-functions): Add f90-mode, texinfo-mode. + (navigate-menu): Add menu item for Stickyfunc mode. + + * semantic/analyze/debug.el + (semantic-analyzer-debug-insert-include-summary): Before + dereferencing tableinner, make sure it has a value. + + * semantic/analyze/refs.el + (semantic-analyze-tag-references-default): When doing a lookup, + specify noerror. + (semantic--analyze-refs-full-lookup): Add optional noerror input + argument. Pass to to full-lookup-simple. + (semantic-analyze-refs-impl, semantic-analyze-refs-proto): Ignore + :typemodifiers during compare. + + * semantic/bovine/c.el (semantic-lex-cpp-define): Specify limits + to looking back for comment chars. + (semantic--tag-similar-names-p, semantic--tag-similar-names-p-default) + (semantic--tag-attribute-similar-p): New. + (semantic-c-describe-environment): Handle list value of ede-object. + (semantic-lex-c-preprocessor-symbol-map-builtin): Add + __attribute_pure__. + + * semantic/bovine/scm.el (semantic-format-tag-prototype): Add + parent and color argument. Pass them through. + + * semantic/complete.el (semantic-collector-calculate-completions): + Search for more matches if new prefix is a substring of old one. + (semantic-complete-inline-project): New function. + + * semantic/db-el.el (object-print): New method. + + * semantic/db-file.el (semanticdb-load-database): Specify class. + + * semantic/db-typecache.el + (semanticdb-abstract-table::semanticdb-typecache-find-method): + Allow proxied tags to be resolved during the search. + (semanticdb-typecache-complete-flush): Support missing or empty + pointmax slot, to allow for more database types. + + * semantic/db.el (semanticdb-abstract-table): Add db-refs slot. + (object-print): Allow child classes to overwrite the display of + the (%d tags) extra string. + (semanticdb-project-database): Specify :type for table. + (semanticdb-create-table-for-file): Specify file-truename. + (semanticdb-synchronize, semanticdb-partial-synchronize): Restore + code that refreshes references to include files. + + * semantic/decorate/include.el + (semantic-decoration-on-fileless-includes): New face. + (semantic-decoration-on-fileless-include-map) + (semantic-decoration-on-fileless-include-menu): New variables. + (semantic-decoration-on-includes-highlight-default): Support + includes that have a table, but are not associated with a file. + (semantic-decoration-fileless-include-describe) + (semantic-decoration-fileless-include-menu): New functions. + (semantic-decoration-all-include-summary): Add arrows to indicate + the file associated with an include name. + + * semantic/find.el + (semantic-find-tags-by-scope-protection-default): Also filter on + package protection of the slot. + + * semantic/java.el (semantic-java-expand-tag): If some type has a + fully qualified name, bust it up into one package and the type + with a short name. + + * semantic/lex.el (define-lex-block-analyzer): Protect against + random extra close parenthesis. + + * semantic/symref.el (semantic-symref-result-get-tags): Make sure + the cursor is on the matched name. + + * semantic/symref/list.el (semantic-symref-results-mode-map): + Suppress keymap. + + * semantic/tag-ls.el (semantic--tag-similar-names-p) + (semantic--tag-attribute-similar-p) + (semantic--tag-similar-types-p): New functions. + (semantic-tag-similar-ignorable-attributes): New variable. + (semantic-tag-protection-default): Add package concept to return + value. + (semantic-tag-package-protected-p): New function. + (semantic-tag-full-package): New overload method. + (semantic-tag-full-package-default): New default for above. + (semantic-tag-full-name-default): Look for the full package name. + + * semantic/tag.el (semantic-create-tag-proxy) + (semantic-tag-set-proxy, semantic-tag-resolve-proxy): New. + + * semantic/util.el (semantic-describe-buffer): Add + semantic-new-buffer-fcn-was-run. + + * semantic/wisent/java-tags.el (semantic-get-local-variables): Add + `this' to the local variable context. + (semantic-analyze-split-name, semantic-analyze-unsplit-name): New. + + * semantic/wisent/python.el (semantic-python-expand-tag): New + function. + + * srecode/compile.el (srecode-compile-templates): Add "framework" + special variable support. + (srecode-compile-template-table): Support framework specifier. + + * srecode/cpp.el (srecode-semantic-handle-:c) + (srecode-semantic-handle-:cpp): New functions. + (srecode-semantic-apply-tag-to-dict): Move from cpp-mode function + to c-mode function. + (srecode-c-apply-templates): Renamed from srecode-cpp-apply-templates. + + * srecode/dictionary.el (initialize-instance): Remove bogus error + condition. + (srecode-create-section-dictionary): Remove unused function. + + * srecode/java.el (srecode-semantic-handle-:java): Fix filename as + package variable. Add current_package variable. + + * srecode/map.el (srecode-map-update-map): Specify the class. + + * srecode/mode.el (srecode-minor-mode): Support the m3 menu. + + * srecode/semantic.el (srecode-semantic-insert-tag): Support + system includes. + + * srecode/srt-mode.el (srecode-font-lock-keywords): Update. + + * srecode/table.el (srecode-template-table): Add :framework slot. + (srecode-dump): Dump it. + (srecode-mode-table): Add new modetables slot. + (srecode-get-mode-table): Find the mode, but also find all parent + modes, and merge the tables together in :tables from :modetables. + (srecode-make-mode-table): Init :modetables + (srecode-mode-table-find): Search in modetables. + (srecode-mode-table-new): Merge the differet files into the + modetables slot. + +2012-10-01 David Engster <deng@randomsample.de> + + * ede.el (ede-apply-preprocessor-map): Check that + `semantic-lex-spp-macro-symbol-obarray' is non-nil. + (global-ede-mode): Fix call to `ede-reset-all-buffers'. + + * ede/cpp-root.el (ede-preprocessor-map): Make sure we add the + lexical-table even when the table doesn't need to be refreshed. + + * ede/dired.el (ede-dired-minor-mode): Use called-interactively-p. + + * ede/pmake.el (ede-pmake-insert-variable-once): Wrap in + save-excursion. + + * ede/proj-comp.el (ede-proj-makefile-insert-rules): Fix insertion + of phony rule. + + * ede/proj-elisp.el (ede-proj-target-elisp): Remove + ede-emacs-preload-compiler. + (ede-proj-makefile-insert-rules, ede-proj-makefile-dependencies): + New methods. + (ede-emacs-compiler): Add 'require' macro to variables and pattern + rule. Add .elc object extension. + (ede-proj-elisp-packages-to-loadpath): Allow longer relative names. + (ede-proj-makefile-insert-variables): Do not insert preload items. + (ede-proj-target-elisp-autoloads): Don't depend on cedet-autogen. + + * ede/util.el (ede-make-buffer-writable): + * semantic/debug.el (semantic-debug-mode): Set buffer-read-only + instead of calling toggle-read-only. + + * semantic.el (semantic-fetch-tags): Use progress reporter only + when called interactively. + (semantic-submode-list): Add debugging modes. + (semantic-mode): Remove Semantic from after-change-functions. + Delete the cache, call semantic--tag-unlink-cache-from-buffer, and + set semantic-new-buffer-fcn-was-run to nil. + + * semantic/analyze/fcn.el (semantic-analyze-tag-prototype-p) + (semantic-analyze-tag-prototype-p-default): Remove. + (semantic-analyze-type, semantic-analyze-dereference-metatype-1): + Use semantic-tag-prototype-p. + + * semantic/bovine/c.el (semantic-c-reset-preprocessor-symbol-map): + Ensure semantic-mode is on before getting preprocessor symbols. + (semantic-c-skip-conditional-section): Use c-scan-conditionals. + (semantic-c-convert-spp-value-to-hideif-value) + (semantic-c-evaluate-symbol-for-hideif, semantic-c-hideif-lookup) + (semantic-c-hideif-defined): Revive hideif code from CEDET trunk. + (semantic-lex-c-if, semantic-c-do-lex-ifdef): Revert changes for + regular expression parsing. + (semantic-cpp-lexer): Add semantic-lex-c-ifdef. + (semantic-expand-c-tag): Check if tag is non-nil before adding it + to return list + (semantic-expand-c-extern-C, semantic-expand-c-complex-type): New + functions, copied from semantic-expand-c-tag. + (semantic-find-tags-included): New override which also searches + for include tags inside of namespaces. + (semantic-c-dereference-typedef): Use semantic-tag-prototype-p. + (semanticdb-find-table-for-include): New override. + + * semantic/bovine/el.el: Remove emacs-lisp-mode-hook. + + * semantic/complete.el (semantic-complete-post-command-hook): Exit + completion when user has deleted all characters from the prefix. + (semantic-displayor-focus-request): Return to previous window when + focussing tags. + + * semantic/db-el.el (semanticdb-normalize-one-tag): Make obsolete. + (semanticdb-elisp-sym->tag): Use help-function-arglist instead. + + * semantic/db-file.el (semanticdb-create-database): Use + semantic-tag-version instead of just semantic-version as the + initializer for the :semantic-tag-version slot. + + * semantic/db-find.el (semanticdb-find-tags-by-class-method): + Delegate `include' to semantic-find-tags-included, which by + default will just call semantic-find-tags-by-class. + + * semantic/db.el (semanticdb-refresh-table): Do not print warnings + when calling semantic-find-file-noselect. This avoids the "file + is write protected" messages when parsing system header files, + which might easily be mistaken to mean the currently loaded file. + (semanticdb-save-current-db, semanticdb-save-all-db): Only emit + message when running interactively. + + * semantic/decorate/mode.el (semantic-decoration-mode): Activate + decoration of includes by default. + + * semantic/doc.el (semantic-doc-snarf-comment-for-tag): Remove + comment delimiter at the end of the text. + + * semantic/ede-grammar.el (semantic-ede-proj-target-grammar): + Change aux- and pre-load-packages. + (ede-proj-makefile-dependencies): Update pattern rule so that + resulting parsers are also byte-compiled. + (semantic-ede-grammar-compiler-bovine) + (semantic-ede-source-grammar-wisent): Remove .elc from gargage + pattern, since this is already covered by the elisp compiler. + (project-compile-target): Add compatibility code for Emacs 23, + which does not have `byte-recompile-file'. + (ede-proj-makefile-insert-rules): Add target specific EMACSFLAGS + to raise max-specpdl-size and max-lisp-eval-depth. + + * semantic/find.el (semantic-find-tags-included): Make + overridable. + + * semantic/fw.el (semantic-alias-obsolete) + (semantic-varalias-obsolete): Use byte-compile-warn. + (semantic-find-file-noselect): Disable font lock by calling + global-font-lock-mode. + + * semantic/grammar.el (semantic-grammar-create-package): Fix + message. + (semantic-grammar-batch-build-one-package): When generating + parsers in batch-mode, ignore version control and make sure we do + not use cached versions. + + * semantic/ia.el (semantic-ia-complete-symbol-menu): Bring back. + + * semantic/lex-spp.el (semantic-lex-spp-symbol-merge): New fun. + (semantic-lex-spp-token-macro-to-macro-stream): Use it. + (semantic-lex-spp-lex-text-string): Instead of only setting the + lexer, call the major mode's setup function. + + * semantic/scope.el (semantic-analyze-scoped-types-default): Use + semantic-tag-prototype-p. + (semantic-analyze-scope-nested-tags-default): Make sure we don't + return tags we already have in scopetypes. + + * semantic/symref/filter.el + (semantic-symref-test-count-hits-in-tag): Restore. + + * semantic/wisent/comp.el (wisent-BITS-PER-WORD): Use + most-positive-fixnum if available. + + * semantic/wisent/javascript.el (semantic-tag-protection) + (semantic-analyze-scope-calculate-access) + (semantic-ctxt-current-symbol): New overrides. + + * semantic/wisent/python.el (wisent-python-lex-beginning-of-line): + Rewrite to fix byte-compiler warning. + +2012-10-01 Robert Jarzmik <robert.jarzmik@free.fr> + + * ede/linux.el (project-linux): New group. + (project-linux-compile-target-command) + (project-linux-compile-project-command): New options. + (project-compile-project, project-compiler-target): New methods. + + * inversion.el (inversion-decoders): New regexps for SXEmacs. + (inversion-package-version): More verbose error message. + (inversion-<): Deal with new special cases. + (inversion-require-emacs): New argument sxemacs-ver; use it. + +2012-10-01 Nelson Ferreira <nelson.ferreira@ieee.org> + + * ede/emacs.el (ede-emacs-version): Detect SXEmacs. + +2012-10-01 William Xu <william.xwl@gmail.com> + + * semantic/bovine/gcc.el (semantic-gcc-query): Returns status when + there is an error. + (semantic-gcc-setup): If the first attempt at calling cpp fails, + try straight GCC. + +2012-10-01 Jan Moringen <jan.moringen@uni-bielefeld.de> + + * semantic/idle.el + (semantic-idle-breadcrumbs--display-in-header-line): Escape + %-characters to avoid erroneous expansion in header line. + (semantic-idle-breadcrumbs--display-in-mode-line): Likewise. + + * semantic/wisent/python.el (wisent-python-reconstitute-function-tag) + (wisent-python-reconstitute-class-tag, semantic-python-special-p) + (semantic-python-private-p, semantic-python-instance-variable-p) + (semantic-python-docstring-p): New functions. + + * srecode/find.el (srecode-user-template-p): New function. + (srecode-all-template-hash): Accept new optional argument + predicate; return only templates matching the predicate. + (srecode-read-template-name): Only retrieve templates matching + srecode-user-template-p. + + * srecode/insert.el (srecode-insert-show-error-report) + (srecode-insert-report-error): New functions. + (srecode-insert-variable-secondname-handler) + (srecode-insert-method, srecode-insert-ask-default) + (srecode-insert-variable-secondname-handler) + (srecode-insert-subtemplate, srecode-insert-method-helper) + (srecode-insert-include-lookup): Use them. + +2012-10-01 Thomas Bach <thbach@students.uni-mainz.de> + + * semantic/wisent/python.el + (semantic-python-get-system-include-path): Add Python3k support. + +2012-10-01 Alexander Haeckel <_@_> (tiny change) + + * srecode/getset.el (srecode-query-for-field): Return the first + tag found by name from all children tags. + +2012-10-01 Dale Sedivec <dale@codefu.org> + + * semantic/wisent/python.el (wisent-python-string-start-re) + (wisent-python-string-re, wisent-python-forward-string) + (wisent-python-forward-line,wisent-python-lex-string): New + variables. + (wisent-python-forward-balanced-expression): New function. + +2012-10-01 Pete Beardmore <elbeardmorez@msn.com> + + * semantic/complete.el (semantic-collector-calculate-completions): + Search for additional matches if new prefix is a substring of the + old prefix. + (semantic-displayor-next-action): Immediately show more + completions after user presses TAB the first time. + (semantic-displayor-tooltip-mode) + (semantic-displayor-tooltip-initial-max-tags) + (semantic-displayor-tooltip-max-tags): New defcustoms. + (semantic-displayor-tooltip): Use new variables as initforms. Use + new slot `mode' instead of `force-show'. Rename `max-tags' to + `max-tags-initial'. + (semantic-displayor-show-request): Display completions according + to new modes, and make variable names clearer. + (semantic-displayor-tooltip::semantic-displayor-scroll-request): + Use new max-tags-initial slot. + + * semantic/idle.el (semantic-idle-local-symbol-highlight): Make + sure there actually is a tag at point. + (semantic-idle-completion-list-default): Report errors as messages + if semantic-idle-scheduler-verbose-flag is non-nil. + +2012-10-01 Richard Kim <emacs18@gmail.com> + + * semantic/db-global.el (semanticdb-enable-gnu-global-databases): + Add optional NOERROR argument. + +2012-10-01 Alex Ott <alexott@gmail.com> + + * semantic/idle.el (semantic-idle-scheduler-enabled-p): Fix + file-checking. + +2012-10-01 Darren Hoo <darren.hoo@gmail.com> (tiny change) + + * semantic/db-find.el (semanticdb-find-default-throttle): Make + buffer-local. + (semanticdb-strip-find-results): Check for existing :filename + attribute, so that file information from GNU Global is not lost. + 2012-08-07 Andreas Schwab <schwab@linux-m68k.org> * ede/base.el (ede-with-projectfile): Use backquote forms. diff --git a/lisp/cedet/cedet-cscope.el b/lisp/cedet/cedet-cscope.el index ae384b005f3..fe954a07712 100644 --- a/lisp/cedet/cedet-cscope.el +++ b/lisp/cedet/cedet-cscope.el @@ -28,7 +28,7 @@ (declare-function inversion-check-version "inversion") -(defvar cedet-cscope-min-version "16.0" +(defvar cedet-cscope-min-version "15.7" "Minimum version of CScope required.") (defcustom cedet-cscope-command "cscope" diff --git a/lisp/cedet/cedet-global.el b/lisp/cedet/cedet-global.el index a6e94dcd5d9..d953d8c0980 100644 --- a/lisp/cedet/cedet-global.el +++ b/lisp/cedet/cedet-global.el @@ -147,7 +147,7 @@ return nil." nil) (with-current-buffer b (goto-char (point-min)) - (re-search-forward "GNU GLOBAL \\([0-9.]+\\)" nil t) + (re-search-forward "(?GNU GLOBAL)? \\([0-9.]+\\)" nil t) (setq rev (match-string 1)) (if (inversion-check-version rev nil cedet-global-min-version) (if noerror diff --git a/lisp/cedet/cedet-idutils.el b/lisp/cedet/cedet-idutils.el index b35035a58b6..db9f3c08c7e 100644 --- a/lisp/cedet/cedet-idutils.el +++ b/lisp/cedet/cedet-idutils.el @@ -179,8 +179,9 @@ return nil." nil) (with-current-buffer b (goto-char (point-min)) - (re-search-forward "fnid - \\([0-9.]+\\)" nil t) - (setq rev (match-string 1)) + (if (re-search-forward "fnid - \\([0-9.]+\\)" nil t) + (setq rev (match-string 1)) + (setq rev "0")) (if (inversion-check-version rev nil cedet-idutils-min-version) (if noerror nil diff --git a/lisp/cedet/cedet.el b/lisp/cedet/cedet.el index 6da3b5de547..5c21e4ab538 100644 --- a/lisp/cedet/cedet.el +++ b/lisp/cedet/cedet.el @@ -35,19 +35,22 @@ (declare-function inversion-find-version "inversion") -(defconst cedet-version "1.0" +(defconst cedet-version "1.1" "Current version of CEDET.") (defconst cedet-packages `( - ;;PACKAGE MIN-VERSION - (cedet ,cedet-version) - (eieio "1.3") - (semantic "2.0") - (srecode "1.0") - (ede "1.0") - (speedbar "1.0")) - "Table of CEDET packages installed.") + ;;PACKAGE MIN-VERSION INSTALLDIR DOCDIR + (cedet ,cedet-version "common" "common" ) + (eieio "1.4" nil "eieio" ) + (semantic "2.1" nil "semantic/doc") + (srecode "1.1" nil "srecode" ) + (ede "1.1" nil "ede" ) + (speedbar "1.0.4" nil "speedbar" ) + (cogre "1.1" nil "cogre" ) + (cedet-contrib "1.1" "contrib" nil ) + ) + "Table of CEDET packages to install.") (defvar cedet-menu-map ;(make-sparse-keymap "CEDET menu") (let ((map (make-sparse-keymap "CEDET menu"))) diff --git a/lisp/cedet/data-debug.el b/lisp/cedet/data-debug.el index 03dca6ceccc..19d0e98aa00 100644 --- a/lisp/cedet/data-debug.el +++ b/lisp/cedet/data-debug.el @@ -821,20 +821,30 @@ FCN is a function that will display stuff in the data debug buffer." PREBUTTONTEXT is some text to insert between prefix and the thing that is not included in the indentation calculation of any children. If PARENT is non-nil, it is somehow related as a parent to thing." - (when (catch 'done - (dolist (test data-debug-thing-alist) - (when (funcall (car test) thing) - (condition-case nil - (funcall (cdr test) thing prefix prebuttontext parent) - (error - (funcall (cdr test) thing prefix prebuttontext))) - (throw 'done nil)) - ) - nil) - (data-debug-insert-simple-thing (format "%S" thing) - prefix - prebuttontext - 'bold))) + (let ((inhibit-read-only t)) + (when (catch 'done + (dolist (test data-debug-thing-alist) + (when (funcall (car test) thing) + (condition-case nil + (progn + (funcall (cdr test) thing prefix prebuttontext parent) + (throw 'done nil)) + (error + (condition-case nil + (progn + (funcall (cdr test) thing prefix prebuttontext) + (throw 'done nil)) + (error nil)))) + ;; Only throw the 'done if no error was caught. + ;; If an error was caught, skip this predicate as being + ;; unsuccessful, and move on. + )) + nil) + (data-debug-insert-simple-thing (format "%S" thing) + prefix + prebuttontext + 'bold))) + (set-buffer-modified-p nil)) ;;; MAJOR MODE ;; @@ -861,6 +871,7 @@ If PARENT is non-nil, it is somehow related as a parent to thing." (defvar data-debug-map (let ((km (make-sparse-keymap))) + (suppress-keymap km) (define-key km [mouse-2] 'data-debug-expand-or-contract-mouse) (define-key km " " 'data-debug-expand-or-contract) (define-key km "\C-m" 'data-debug-expand-or-contract) @@ -885,7 +896,8 @@ If PARENT is non-nil, it is somehow related as a parent to thing." (setq major-mode 'data-debug-mode mode-name "DATA-DEBUG" comment-start ";;" - comment-end "") + comment-end "" + buffer-read-only t) (set (make-local-variable 'comment-start-skip) "\\(\\(^\\|[^\\\\\n]\\)\\(\\\\\\\\\\)*\\);+ *") (set-syntax-table data-debug-mode-syntax-table) @@ -902,6 +914,7 @@ If PARENT is non-nil, it is somehow related as a parent to thing." (let ((b (get-buffer-create name))) (pop-to-buffer b) (set-buffer b) + (setq buffer-read-only nil) ; disable read-only (erase-buffer) (data-debug-mode) b)) @@ -964,7 +977,8 @@ Do nothing if already expanded." (when (or (not (data-debug-line-expandable-p)) (not (data-debug-current-line-expanded-p))) ;; If the next line is the same or less indentation, expand. - (let ((fcn (get-text-property (point) 'ddebug-function))) + (let ((fcn (get-text-property (point) 'ddebug-function)) + (inhibit-read-only t)) (when fcn (funcall fcn (point)) (beginning-of-line) @@ -977,6 +991,7 @@ Do nothing if already contracted." ;; Don't contract if the current line is not expandable. (get-text-property (point) 'ddebug-function)) (let ((ti (current-indentation)) + (inhibit-read-only t) ) ;; If next indentation is larger, collapse. (end-of-line) @@ -995,7 +1010,8 @@ Do nothing if already contracted." (error (setq end (point-max)))) (delete-region start end) (forward-char -1) - (beginning-of-line))))) + (beginning-of-line)))) + (set-buffer-modified-p nil)) (defun data-debug-expand-or-contract () "Expand or contract anything at the current point." @@ -1080,7 +1096,4 @@ If the result is a list or vector, then use the data debugger to display it." (provide 'data-debug) -(if (featurep 'eieio) - (require 'eieio-datadebug)) - ;;; data-debug.el ends here diff --git a/lisp/cedet/ede.el b/lisp/cedet/ede.el index cc8b6f53242..2d4d3956d34 100644 --- a/lisp/cedet/ede.el +++ b/lisp/cedet/ede.el @@ -4,7 +4,6 @@ ;; Author: Eric M. Ludlam <zappo@gnu.org> ;; Keywords: project, make -;; Version: 1.0pre7 ;; This file is part of GNU Emacs. @@ -194,7 +193,6 @@ Argument LIST-O-O is the list of objects to choose from." (define-key pmap "t" 'ede-new-target) (define-key pmap "g" 'ede-rescan-toplevel) (define-key pmap "s" 'ede-speedbar) - (define-key pmap "l" 'ede-load-project-file) (define-key pmap "f" 'ede-find-file) (define-key pmap "C" 'ede-compile-project) (define-key pmap "c" 'ede-compile-target) @@ -252,7 +250,7 @@ Argument LIST-O-O is the list of objects to choose from." (defun ede-buffer-belongs-to-project-p () "Return non-nil if this buffer belongs to at least one project." (if (or (null ede-object) (consp ede-object)) nil - (obj-of-class-p ede-object ede-project))) + (obj-of-class-p ede-object-project ede-project))) (defun ede-menu-obj-of-class-p (class) "Return non-nil if some member of `ede-object' is a child of CLASS." @@ -343,6 +341,7 @@ Argument MENU-DEF is the menu definition to use." (append '( [ "Add Target" ede-new-target (ede-current-project) ] [ "Remove Target" ede-delete-target ede-object ] + ( "Default configuration" :filter ede-configuration-forms-menu ) "-") menu )) @@ -350,6 +349,41 @@ Argument MENU-DEF is the menu definition to use." menu) ))))) +(defun ede-configuration-forms-menu (menu-def) + "Create a submenu for selecting the default configuration for this project. +The current default is in the current object's CONFIGURATION-DEFAULT slot. +All possible configurations are in CONFIGURATIONS. +Argument MENU-DEF specifies the menu being created." + (easy-menu-filter-return + (easy-menu-create-menu + "Configurations" + (let* ((obj (ede-current-project)) + (conf (when obj (oref obj configurations))) + (cdef (when obj (oref obj configuration-default))) + (menu nil)) + (dolist (C conf) + (setq menu (cons (vector C (list 'ede-project-configurations-set C) + :style 'toggle + :selected (string= C cdef)) + menu)) + ) + (nreverse menu))))) + +(defun ede-project-configurations-set (newconfig) + "Set the current project's current configuration to NEWCONFIG. +This function is designed to be used by `ede-configuration-forms-menu' +but can also be used interactively." + (interactive + (list (let* ((proj (ede-current-project)) + (configs (oref proj configurations))) + (completing-read "New configuration: " + configs nil t + (oref proj configuration-default))))) + (oset (ede-current-project) configuration-default newconfig) + (message "%s will now build in %s mode." + (object-name (ede-current-project)) + newconfig)) + (defun ede-customize-forms-menu (menu-def) "Create a menu of the project, and targets that can be customized. Argument MENU-DEF is the definition of the current menu." @@ -377,9 +411,14 @@ Argument MENU-DEF is the definition of the current menu." "Add target specific keybindings into the local map. Optional argument DEFAULT indicates if this should be set to the default version of the keymap." - (let ((object (or ede-object ede-selected-object))) + (let ((object (or ede-object ede-selected-object)) + (proj ede-object-project)) (condition-case nil (let ((keys (ede-object-keybindings object))) + ;; Add keys for the project to whatever is in the current object + ;; so long as it isn't the same. + (when (not (eq object proj)) + (setq keys (append keys (ede-object-keybindings proj)))) (while keys (local-set-key (concat "\C-c." (car (car keys))) (cdr (car keys))) @@ -415,8 +454,8 @@ If optional argument CURRENT is non-nil, return sub-menu code." (defun ede-apply-target-options () "Apply options to the current buffer for the active project/target." - (if (ede-current-project) - (ede-set-project-variables (ede-current-project))) + (ede-apply-project-local-variables) + ;; Apply keymaps and preprocessor symbols. (ede-apply-object-keymap) (ede-apply-preprocessor-map) ) @@ -493,9 +532,9 @@ Sets buffer local variables for EDE." (ede-apply-target-options))))) -(defun ede-reset-all-buffers (onoff) - "Reset all the buffers due to change in EDE. -ONOFF indicates enabling or disabling the mode." +(defun ede-reset-all-buffers () + "Reset all the buffers due to change in EDE." + (interactive) (let ((b (buffer-list))) (while b (when (buffer-file-name (car b)) @@ -533,7 +572,7 @@ an EDE controlled project." (add-hook 'dired-mode-hook 'ede-turn-on-hook) (add-hook 'kill-emacs-hook 'ede-save-cache) (ede-load-cache) - (ede-reset-all-buffers 1)) + (ede-reset-all-buffers)) ;; Turn off global-ede-mode (define-key cedet-menu-map [cedet-menu-separator] nil) (remove-hook 'semanticdb-project-predicate-functions 'ede-directory-project-p) @@ -543,7 +582,7 @@ an EDE controlled project." (remove-hook 'dired-mode-hook 'ede-turn-on-hook) (remove-hook 'kill-emacs-hook 'ede-save-cache) (ede-save-cache) - (ede-reset-all-buffers -1))) + (ede-reset-all-buffers))) (defvar ede-ignored-file-alist '( "\\.cvsignore$" @@ -632,8 +671,7 @@ Otherwise, create a new project for DIR." ;; the user chooses. (if (ede-check-project-directory dir) (progn - ;; If there is a project in DIR, load it, otherwise do - ;; nothing. + ;; Load the project in DIR, or make one. (ede-load-project-file dir) ;; Check if we loaded anything on the previous line. @@ -643,7 +681,7 @@ Otherwise, create a new project for DIR." ;; buffers may also be referring to this project. ;; Resetting all the buffers will get them to also point ;; at this new open project. - (ede-reset-all-buffers 1) + (ede-reset-all-buffers) ;; ELSE ;; There was no project, so switch to `ede-new' which is how @@ -785,7 +823,7 @@ ARGS are additional arguments to pass to method SYM." (ede-deep-rescan t)) (project-rescan (ede-load-project-file toppath)) - (ede-reset-all-buffers 1)))) + (ede-reset-all-buffers)))) (defun ede-new-target (&rest args) "Create a new target specific to this type of project file. @@ -794,9 +832,11 @@ Typically you can specify NAME, target TYPE, and AUTOADD, where AUTOADD is a string \"y\" or \"n\", which answers the y/n question done interactively." (interactive) (apply 'project-new-target (ede-current-project) args) - (setq ede-object nil) - (setq ede-object (ede-buffer-object (current-buffer))) - (ede-apply-target-options)) + (when (and buffer-file-name + (not (file-directory-p buffer-file-name))) + (setq ede-object nil) + (setq ede-object (ede-buffer-object (current-buffer))) + (ede-apply-target-options))) (defun ede-new-target-custom () "Create a new target specific to this type of project file." @@ -837,7 +877,10 @@ a string \"y\" or \"n\", which answers the y/n question done interactively." (project-add-file target (buffer-file-name)) (setq ede-object nil) - (setq ede-object (ede-buffer-object (current-buffer))) + + ;; Setup buffer local variables. + (ede-initialize-state-current-buffer) + (when (not ede-object) (error "Can't add %s to target %s: Wrong file type" (file-name-nondirectory (buffer-file-name)) @@ -1188,16 +1231,24 @@ could become slow in time." (defmethod ede-find-target ((proj ede-project) buffer) "Fetch the target in PROJ belonging to BUFFER or nil." (with-current-buffer buffer - (or ede-object - (if (ede-buffer-mine proj buffer) - proj - (let ((targets (oref proj targets)) - (f nil)) - (while targets - (if (ede-buffer-mine (car targets) buffer) - (setq f (cons (car targets) f))) - (setq targets (cdr targets))) - f))))) + + ;; We can do a short-ut if ede-object local variable is set. + (if ede-object + ;; If the buffer is already loaded with good EDE stuff, make sure the + ;; saved project is the project we're looking for. + (when (and ede-object-project (eq proj ede-object-project)) ede-object) + + ;; If the variable wasn't set, then we are probably initializing the buffer. + ;; In that case, search the file system. + (if (ede-buffer-mine proj buffer) + proj + (let ((targets (oref proj targets)) + (f nil)) + (while targets + (if (ede-buffer-mine (car targets) buffer) + (setq f (cons (car targets) f))) + (setq targets (cdr targets))) + f))))) (defmethod ede-target-buffer-in-sourcelist ((this ede-target) buffer source) "Return non-nil if object THIS is in BUFFER to a SOURCE list. @@ -1225,8 +1276,8 @@ This includes buffers controlled by a specific target of PROJECT." (pl nil)) (while bl (with-current-buffer (car bl) - (if (ede-buffer-belongs-to-project-p) - (setq pl (cons (car bl) pl)))) + (when (and ede-object (ede-find-target project (car bl))) + (setq pl (cons (car bl) pl)))) (setq bl (cdr bl))) pl)) @@ -1301,9 +1352,28 @@ Return the first non-nil value returned by PROC." ;; ;; These items are needed by ede-cpp-root to add better support for ;; configuring items for Semantic. + +;; Generic paths +(defmethod ede-system-include-path ((this ede-project)) + "Get the system include path used by project THIS." + nil) + +(defmethod ede-system-include-path ((this ede-target)) + "Get the system include path used by project THIS." + nil) + +(defmethod ede-source-paths ((this ede-project) mode) + "Get the base to all source trees in the current projet for MODE. +For example, <root>/src for sources of c/c++, Java, etc, +and <root>/doc for doc sources." + nil) + +;; C/C++ (defun ede-apply-preprocessor-map () "Apply preprocessor tables onto the current buffer." - (when (and ede-object (boundp 'semantic-lex-spp-macro-symbol-obarray)) + (when (and ede-object + (boundp 'semantic-lex-spp-macro-symbol-obarray) + semantic-lex-spp-macro-symbol-obarray) (let* ((objs ede-object) (map (ede-preprocessor-map (if (consp objs) (car objs) @@ -1324,27 +1394,66 @@ Return the first non-nil value returned by PROC." "Get the pre-processor map for project THIS." nil) -(defmethod ede-system-include-path ((this ede-target)) - "Get the system include path used by project THIS." - nil) - (defmethod ede-preprocessor-map ((this ede-target)) "Get the pre-processor map for project THIS." nil) +;; Java +(defmethod ede-java-classpath ((this ede-project)) + "Return the classpath for this project." + ;; @TODO - Can JDEE add something here? + nil) + ;;; Project-local variables -;; + +(defun ede-set (variable value &optional proj) + "Set the project local VARIABLE to VALUE. +If VARIABLE is not project local, just use set. Optional argument PROJ +is the project to use, instead of `ede-current-project'." + (interactive "sVariable: \nxExpression: ") + (let ((p (or proj (ede-toplevel))) + a) + ;; Make the change + (ede-make-project-local-variable variable p) + (ede-set-project-local-variable variable value p) + (ede-commit-local-variables p) + + ;; This is a heavy hammer, but will apply variables properly + ;; based on stacking between the toplevel and child projects. + (ede-map-buffers 'ede-apply-project-local-variables) + + value)) + +(defun ede-apply-project-local-variables (&optional buffer) + "Apply project local variables to the current buffer." + (with-current-buffer (or buffer (current-buffer)) + ;; Always apply toplevel variables. + (if (not (eq (ede-current-project) (ede-toplevel))) + (ede-set-project-variables (ede-toplevel))) + ;; Next apply more local project's variables. + (if (ede-current-project) + (ede-set-project-variables (ede-current-project))) + )) + (defun ede-make-project-local-variable (variable &optional project) "Make VARIABLE project-local to PROJECT." - (if (not project) (setq project (ede-current-project))) + (if (not project) (setq project (ede-toplevel))) (if (assoc variable (oref project local-variables)) nil (oset project local-variables (cons (list variable) - (oref project local-variables))) - (dolist (b (ede-project-buffers project)) - (with-current-buffer b - (make-local-variable variable))))) + (oref project local-variables))))) + +(defun ede-set-project-local-variable (variable value &optional project) + "Set VARIABLE to VALUE for PROJECT. +If PROJ isn't specified, use the current project. +This function only assigns the value within the project structure. +It does not apply the value to buffers." + (if (not project) (setq project (ede-toplevel))) + (let ((va (assoc variable (oref project local-variables)))) + (unless va + (error "Cannot set project variable until it is added with `ede-make-project-local-variable'")) + (setcdr va value))) (defmethod ede-set-project-variables ((project ede-project) &optional buffer) "Set variables local to PROJECT in BUFFER." @@ -1352,25 +1461,8 @@ Return the first non-nil value returned by PROC." (with-current-buffer buffer (dolist (v (oref project local-variables)) (make-local-variable (car v)) - ;; set its value here? (set (car v) (cdr v))))) -(defun ede-set (variable value &optional proj) - "Set the project local VARIABLE to VALUE. -If VARIABLE is not project local, just use set. Optional argument PROJ -is the project to use, instead of `ede-current-project'." - (let ((p (or proj (ede-current-project))) - a) - (if (and p (setq a (assoc variable (oref p local-variables)))) - (progn - (setcdr a value) - (dolist (b (ede-project-buffers p)) - (with-current-buffer b - (set variable value)))) - (set variable value)) - (ede-commit-local-variables p)) - value) - (defmethod ede-commit-local-variables ((proj ede-project)) "Commit change to local variables in PROJ." nil) diff --git a/lisp/cedet/ede/auto.el b/lisp/cedet/ede/auto.el index a5ea8178858..f6446db9108 100644 --- a/lisp/cedet/ede/auto.el +++ b/lisp/cedet/ede/auto.el @@ -34,6 +34,84 @@ (declare-function ede-directory-safe-p "ede") (declare-function ede-add-project-to-global-list "ede") +(defclass ede-project-autoload-dirmatch () + ((fromconfig :initarg :fromconfig + :initform nil + :documentation + "A config file within which the match pattern lives.") + (configregex :initarg :configregex + :initform nil + :documentation + "A regexp to identify the dirmatch pattern.") + (configregexidx :initarg :configregexidx + :initform nil + :documentation + "An index into the match-data of `configregex'.") + (configdatastash :initform nil + :documentation + "Save discovered match string.") + ) + "Support complex matches for projects that live in named directories. +For most cases, a simple string is sufficient. If, however, a project +location is varied dependent on other complex criteria, this class +can be used to define that match without loading the specific project +into memory.") + +(defmethod ede-dirmatch-installed ((dirmatch ede-project-autoload-dirmatch)) + "Return non-nil if the tool DIRMATCH might match is installed on the system." + (let ((fc (oref dirmatch fromconfig))) + + (cond + ;; If the thing to match is stored in a config file. + ((stringp fc) + (file-exists-p fc)) + + ;; Add new types of dirmatches here. + + ;; Error for wierd stuff + (t (error "Unknown dirmatch type."))))) + + +(defmethod ede-do-dirmatch ((dirmatch ede-project-autoload-dirmatch) file) + "Does DIRMATCH match the filename FILE." + (let ((fc (oref dirmatch fromconfig))) + + (cond + ;; If the thing to match is stored in a config file. + ((stringp fc) + (when (file-exists-p fc) + (let ((matchstring (oref dirmatch configdatastash))) + (unless matchstring + (save-current-buffer + (let* ((buff (get-file-buffer fc)) + (readbuff + (let ((find-file-hook nil)) ;; Disable ede from recursing + (find-file-noselect fc)))) + (set-buffer readbuff) + (save-excursion + (goto-char (point-min)) + (when (re-search-forward (oref dirmatch configregex) nil t) + (setq matchstring + (match-string (or (oref dirmatch configregexidx) 0))))) + (if (not buff) (kill-buffer readbuff)))) + ;; Save what we find in our cache. + (oset dirmatch configdatastash matchstring)) + ;; Match against our discovered string + (and matchstring (string-match (regexp-quote matchstring) file)) + ))) + + ;; Add new matches here + ;; ((stringp somenewslot ...) + ;; ) + + ;; Error if none others known + (t + (error "Unknown dirmatch object match style."))) + )) + +(declare-function ede-directory-safe-p "ede") +(declare-function ede-add-project-to-global-list "ede") + (defclass ede-project-autoload () ((name :initarg :name :documentation "Name of this project type") @@ -41,6 +119,13 @@ :documentation "The lisp file belonging to this class.") (proj-file :initarg :proj-file :documentation "Name of a project file of this type.") + (proj-root-dirmatch :initarg :proj-root-dirmatch + :initform "" + :type (or string ede-project-autoload-dirmatch) + :documentation + "To avoid loading a project, check if the directory matches this. +For projects that use directory name matches, a function would load that project. +Specifying this matcher will allow EDE to check without loading the project.") (proj-root :initarg :proj-root :type function :documentation "A function symbol to call for the project root. @@ -57,6 +142,11 @@ associated with a single object class, based on the initializers used.") :documentation "Fn symbol used to load this project file.") (class-sym :initarg :class-sym :documentation "Symbol representing the project class to use.") + (generic-p :initform nil + :documentation + "Generic projects are added to the project list at the end. +The add routine will set this to non-nil so that future non-generic placement will +be successful.") (new-p :initarg :new-p :initform t :documentation @@ -93,11 +183,56 @@ type is required and the load function used.") :proj-file "Makefile.am" :load-type 'project-am-load :class-sym 'project-am-makefile - :new-p nil)) + :new-p nil + :safe-p t) + ) "List of vectors defining how to determine what type of projects exist.") (put 'ede-project-class-files 'risky-local-variable t) +(defun ede-add-project-autoload (projauto &optional flag) + "Add PROJAUTO, an EDE autoload definition to `ede-project-class-files'. +Optional argument FLAG indicates how this autoload should be +added. Possible values are: + 'generic - A generic project type. Keep this at the very end. + 'unique - A unique project type for a specific project. Keep at the very + front of the list so more generic projects don't get priority." + ;; First, can we identify PROJAUTO as already in the list? If so, replace. + (let ((projlist ede-project-class-files) + (projname (object-name-string projauto))) + (while (and projlist (not (string= (object-name-string (car projlist)) projname))) + (setq projlist (cdr projlist))) + + (if projlist + ;; Stick the new one into the old slot. + (setcar projlist projauto) + + ;; Else, see where to insert it. + (cond ((and flag (eq flag 'unique)) + ;; Unique items get stuck right onto the front. + (setq ede-project-class-files + (cons projauto ede-project-class-files))) + + ;; Generic Projects go at the very end of the list. + ((and flag (eq flag 'generic)) + (oset projauto generic-p t) + (setq ede-project-class-files + (append ede-project-class-files + (list projauto)))) + + ;; Normal projects go at the end of the list, but + ;; before the generic projects. + (t + (let ((prev nil) + (next ede-project-class-files)) + (while (and next (not (oref (car next) generic-p))) + (setq prev next + next (cdr next))) + (when (not prev) + (error "ede-project-class-files not initialized")) + ;; Splice into the list. + (setcdr prev (cons projauto next)))))))) + ;;; EDE project-autoload methods ;; (defmethod ede-project-root ((this ede-project-autoload)) @@ -105,6 +240,21 @@ type is required and the load function used.") Allows for one-project-object-for-a-tree type systems." nil) +(defun ede-project-dirmatch-p (file dirmatch) + "Return non-nil if FILE matches DIRMATCH. +DIRMATCH could be nil (no match), a string (regexp match), +or an `ede-project-autoload-dirmatch' object." + ;; If dirmatch is a string, then we simply match it against + ;; the file we are testing. + (if (stringp dirmatch) + (string-match dirmatch file) + ;; if dirmatch is instead a dirmatch object, we test against + ;; that object instead. + (if (ede-project-autoload-dirmatch-p dirmatch) + (ede-do-dirmatch dirmatch file) + (error "Unknown project directory match type.")) + )) + (defmethod ede-project-root-directory ((this ede-project-autoload) &optional file) "If a project knows its root, return it here. @@ -114,12 +264,36 @@ the current buffer." (when (not file) (setq file default-directory)) (when (slot-boundp this :proj-root) - (let ((rootfcn (oref this proj-root))) + (let ((dirmatch (oref this proj-root-dirmatch)) + (rootfcn (oref this proj-root)) + (callfcn t)) (when rootfcn - (condition-case nil - (funcall rootfcn file) - (error - (funcall rootfcn))) + (if ;; If the dirmatch (an object) is not installed, then we + ;; always skip doing a match. + (and (ede-project-autoload-dirmatch-p dirmatch) + (not (ede-dirmatch-installed dirmatch))) + (setq callfcn nil) + ;; Other types of dirmatch: + (when (and + ;; If the Emacs Lisp file handling this project hasn't + ;; been loaded, we will use the quick dirmatch feature. + (not (featurep (oref this file))) + ;; If the dirmatch is an empty string, then we always + ;; skip doing a match. + (not (and (stringp dirmatch) (string= dirmatch ""))) + ) + ;; If this file DOES NOT match dirmatch, we set the callfcn + ;; to nil, meaning don't load the ede support file for this + ;; type of project. If it does match, we will load the file + ;; and use a more accurate programatic match from there. + (unless (ede-project-dirmatch-p file dirmatch) + (setq callfcn nil)))) + ;; Call into the project support file for a match. + (when callfcn + (condition-case nil + (funcall rootfcn file) + (error + (funcall rootfcn)))) )))) (defmethod ede-dir-to-projectfile ((this ede-project-autoload) dir) @@ -128,10 +302,20 @@ 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)) + (dm (oref this proj-root-dirmatch)) (f (cond ((stringp pf) (expand-file-name pf (or root d))) ((and (symbolp pf) (fboundp pf)) - (funcall pf (or root d))))) + ;; If there is a symbol to call, lets make extra + ;; sure we really can call it without loading in + ;; other EDE projects. This happens if the file is + ;; already loaded, or if there is a dirmatch, but + ;; root is empty. + (when (and (featurep (oref this file)) + (or (not (stringp dm)) + (not (string= dm ""))) + root) + (funcall pf (or root d)))))) ) (when (and f (file-exists-p f)) f))) diff --git a/lisp/cedet/ede/autoconf-edit.el b/lisp/cedet/ede/autoconf-edit.el index e3c9d2cb4f8..8144b135ac5 100644 --- a/lisp/cedet/ede/autoconf-edit.el +++ b/lisp/cedet/ede/autoconf-edit.el @@ -165,6 +165,9 @@ items such as CHECK_HEADERS." (setq param (substring param (match-end 0)))) (when (string-match "\\s-*\\]?\\s-*\\'" param) (setq param (substring param 0 (match-beginning 0)))) + ;; Look for occurances of backslash newline + (while (string-match "\\s-*\\\\\\s-*\n\\s-*" param) + (setq param (replace-match " " t t param))) param) (defun autoconf-parameters-for-macro (macro &optional ignore-bol ignore-case) @@ -373,6 +376,38 @@ Optional argument BODY is the code to execute which edits the autoconf file." (string= autoconf-deleted-text autoconf-inserted-text)) (set-buffer-modified-p nil)))) +(defun autoconf-parameter-count () + "Return the number of parameters to the function on the current line." + (save-excursion + (beginning-of-line) + (let* ((end-of-cmd + (save-excursion + (if (re-search-forward "(" (point-at-eol) t) + (progn + (forward-char -1) + (forward-sexp 1) + (point)) + ;; Else, just return EOL. + (point-at-eol)))) + (cnt 0)) + (save-restriction + (narrow-to-region (point-at-bol) end-of-cmd) + (condition-case nil + (progn + (down-list 1) + (while (re-search-forward ", ?" end-of-cmd t) + (setq cnt (1+ cnt))) + (cond ((> cnt 1) + ;; If the # is > 1, then there is one fewer , than args. + (1+ cnt)) + ((not (looking-at "\\s-*)")) + ;; If there are 0 args, then we have to see if there is one arg. + (1+ cnt)) + (t + ;; Else, just return the 0. + cnt))) + (error 0)))))) + (defun autoconf-delete-parameter (index) "Delete the INDEXth parameter from the macro starting on the current line. Leaves the cursor where a new parameter can be inserted. @@ -396,12 +431,19 @@ INDEX starts at 1." "Set the version used with automake to VERSION." (if (not (stringp version)) (signal 'wrong-type-argument '(stringp version))) - (if (not (autoconf-find-last-macro "AM_INIT_AUTOMAKE")) - (error "Cannot update version") - ;; Move to correct position. + (if (and (autoconf-find-last-macro "AM_INIT_AUTOMAKE") + (>= (autoconf-parameter-count) 2)) + ;; We can edit right here. + nil + ;; Else, look for AC init instead. + (if (not (and (autoconf-find-last-macro "AC_INIT") + (>= (autoconf-parameter-count) 2))) + (error "Cannot update version"))) + + ;; Perform the edit. (autoconf-edit-cycle (autoconf-delete-parameter 2) - (autoconf-insert version)))) + (autoconf-insert (concat "[" version "]")))) (defun autoconf-set-output (outputlist) "Set the files created in AC_OUTPUT to OUTPUTLIST. diff --git a/lisp/cedet/ede/base.el b/lisp/cedet/ede/base.el index ce3d4a036f3..fe12720500b 100644 --- a/lisp/cedet/ede/base.el +++ b/lisp/cedet/ede/base.el @@ -163,7 +163,7 @@ and querying them will cause the actual project to get loaded.") :documentation "Sub projects controlled by this project. For Automake based projects, each directory is treated as a project.") (targets :initarg :targets - :type list + :type ede-target-list :custom (repeat (object :objectcreatefcn ede-new-target-custom)) :label "Local Targets" :group (targets) @@ -287,10 +287,7 @@ All specific project types must derive from this project." "For the project in which OBJ resides, execute FORMS." `(save-window-excursion (let* ((pf (if (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. - (ede-load-project-file (oref ,obj path)) + (ede-target-parent ,obj) ,obj)) (dbka (get-file-buffer (oref pf file)))) (if (not dbka) (find-file (oref pf file)) diff --git a/lisp/cedet/ede/cpp-root.el b/lisp/cedet/ede/cpp-root.el index e6fd92759de..48b83f30bb0 100644 --- a/lisp/cedet/ede/cpp-root.el +++ b/lisp/cedet/ede/cpp-root.el @@ -85,7 +85,7 @@ ;; file name for a header in your project where most of your CPP ;; macros reside. Doing this can be easier than listing everything in ;; the :spp-table option. The files listed in :spp-files should not -;; start with a /, and are relative to something in :include-path.;; +;; start with a /, and are relative to something in :include-path. ;; ;; If you want to override the file-finding tool with your own ;; function you can do this: @@ -135,7 +135,8 @@ ;; :proj-file 'MY-FILE-FOR-DIR ;; :proj-root 'MY-ROOT-FCN ;; :load-type 'MY-LOAD -;; :class-sym 'ede-cpp-root) +;; :class-sym 'ede-cpp-root-project +;; :safe-p t) ;; t) ;; ;;; TODO @@ -238,16 +239,20 @@ ROOTPROJ is nil, since there is only one project." (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) +(ede-add-project-autoload + (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 + :safe-p t) + ;; When a user creates one of these, it should override any other project + ;; type that might happen to be in this directory, so force this to the + ;; very front. + 'unique) ;;; CLASSES ;; @@ -439,6 +444,7 @@ This knows details about or source tree." ;; Else, do the usual. (setq ans (call-next-method))) ))) + ;; TODO - does this call-next-method happen twice. Is that bad?? Why is it here? (or ans (call-next-method)))) (defmethod ede-project-root ((this ede-cpp-root-project)) @@ -500,16 +506,16 @@ Also set up the lexical preprocessor map." (table (when expfile (semanticdb-file-table-object expfile))) ) - (when (not table) - (message "Cannot find file %s in project." F)) - (when (and table (semanticdb-needs-refresh-p table)) - (semanticdb-refresh-table table) + (if (not table) + (message "Cannot find file %s in project." F) + (when (semanticdb-needs-refresh-p table) + (semanticdb-refresh-table table)) (setq spp (append spp (oref table lexical-table)))))) (oref this spp-files)) spp)) (defmethod ede-system-include-path ((this ede-cpp-root-target)) - "Get the system include path used by project THIS." + "Get the system include path used by target THIS." (ede-system-include-path (ede-target-parent this))) (defmethod ede-preprocessor-map ((this ede-cpp-root-target)) diff --git a/lisp/cedet/ede/dired.el b/lisp/cedet/ede/dired.el index bf9ab272785..fa56a9ac5ca 100644 --- a/lisp/cedet/ede/dired.el +++ b/lisp/cedet/ede/dired.el @@ -64,7 +64,7 @@ negative, force off." (setq ede-dired-minor-mode nil) (error "Not in DIRED mode")) (unless (or (ede-directory-project-p default-directory) - (interactive-p)) + (called-interactively-p 'any)) (setq ede-dired-minor-mode nil))) (defun ede-dired-add-to-target (target) diff --git a/lisp/cedet/ede/emacs.el b/lisp/cedet/ede/emacs.el index e3afe30063c..e3a5789cf3b 100644 --- a/lisp/cedet/ede/emacs.el +++ b/lisp/cedet/ede/emacs.el @@ -99,6 +99,17 @@ emacs_beta_version=\\([0-9]+\\)") (match-string 2) "." (match-string 3))) ) + ((file-exists-p "sxemacs.pc.in") + (setq emacs "SXEmacs") + (insert-file-contents "sxemacs_version.m4") + (goto-char (point-min)) + (re-search-forward "m4_define(\\[SXEM4CS_MAJOR_VERSION\\], \\[\\([0-9]+\\)\\]) +m4_define(\\[SXEM4CS_MINOR_VERSION\\], \\[\\([0-9]+\\)\\]) +m4_define(\\[SXEM4CS_BETA_VERSION\\], \\[\\([0-9]+\\)\\])") + (setq ver (concat (match-string 1) "." + (match-string 2) "." + (match-string 3))) + ) ;; Insert other Emacs here... ;; Vaguely recent version of GNU Emacs? @@ -125,28 +136,29 @@ Argument DIR is the directory it is created for. ROOTPROJ is nil, since there is only one project." (or (ede-emacs-file-existing dir) ;; Doesn't already exist, so let's make one. - (let* ((vertuple (ede-emacs-version dir))) - (ede-emacs-project (car vertuple) - :name (car vertuple) - :version (cdr vertuple) - :directory (file-name-as-directory dir) - :file (expand-file-name "src/emacs.c" - dir))) - (ede-add-project-to-global-list this) - ) - ) + (let* ((vertuple (ede-emacs-version dir)) + (proj (ede-emacs-project + (car vertuple) + :name (car vertuple) + :version (cdr vertuple) + :directory (file-name-as-directory dir) + :file (expand-file-name "src/emacs.c" + dir)))) + (ede-add-project-to-global-list proj)))) ;;;###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) +(ede-add-project-autoload + (ede-project-autoload "emacs" + :name "EMACS ROOT" + :file 'ede/emacs + :proj-file "src/emacs.c" + :proj-root-dirmatch "emacs[^/]*" + :proj-root 'ede-emacs-project-root + :load-type 'ede-emacs-load + :class-sym 'ede-emacs-project + :new-p nil + :safe-p t) + 'unique) (defclass ede-emacs-target-c (ede-target) () diff --git a/lisp/cedet/ede/files.el b/lisp/cedet/ede/files.el index 02aeffc5e2b..e5d75234b49 100644 --- a/lisp/cedet/ede/files.el +++ b/lisp/cedet/ede/files.el @@ -63,7 +63,8 @@ the current EDE project." (interactive) (require 'ede/locate) (let* ((loc (ede-get-locator-object (ede-current-project)))) - (ede-locate-flush-hash loc))) + (when loc + (ede-locate-flush-hash loc)))) ;;; Placeholders for ROOT directory scanning on base objects ;; @@ -110,7 +111,7 @@ of the anchor file for the project." (when (not ans) (if (equal (ede--project-inode SP) inode) (setq ans SP) - (ede-find-subproject-for-directory SP dir))))) + (setq ans (ede-find-subproject-for-directory SP dir)))))) ans))) ;;; DIRECTORY IN OPEN PROJECT @@ -219,6 +220,18 @@ Does not check subprojects." :test 'equal) "A hash of directory names and associated EDE objects.") +(defun ede-flush-directory-hash () + "Flush the project directory hash. +Do this only when developing new projects that are incorrectly putting +'nomatch tokens into the hash." + (interactive) + (setq ede-project-directory-hash (make-hash-table :test 'equal)) + ;; Also slush the current project's locator hash. + (let ((loc (ede-get-locator-object ede-object))) + (when loc + (ede-locate-flush-hash loc))) + ) + (defun ede-project-directory-remove-hash (dir) "Reset the directory hash for DIR. Do this whenever a new project is created, as opposed to loaded." @@ -368,10 +381,11 @@ Get it from the toplevel project. If it doesn't have one, make one." ;; Make sure we have a location object available for ;; caching values, and for locating things more robustly. (let ((top (ede-toplevel proj))) - (when (not (slot-boundp top 'locate-obj)) - (ede-enable-locate-on-project top)) - (oref top locate-obj) - )) + (when top + (when (not (slot-boundp top 'locate-obj)) + (ede-enable-locate-on-project top)) + (oref top locate-obj) + ))) (defmethod ede-expand-filename ((this ede-project) filename &optional force) "Return a fully qualified file name based on project THIS. diff --git a/lisp/cedet/ede/generic.el b/lisp/cedet/ede/generic.el index 67ef63f662e..c4fc5c6b6a9 100644 --- a/lisp/cedet/ede/generic.el +++ b/lisp/cedet/ede/generic.el @@ -79,6 +79,7 @@ (require 'eieio-opt) (require 'ede) +(require 'ede/shell) (require 'semantic/db) ;;; Code: @@ -105,6 +106,13 @@ :group (default build) :documentation "Command used for debugging this project.") + (run-command :initarg :run-command + :initform nil + :type (or null string) + :custom string + :group (default build) + :documentation + "Command used to run something related to this project.") ;; C target customizations (c-include-path :initarg :c-include-path :initform nil @@ -196,7 +204,7 @@ The class allocated value is replace by different sub classes.") (oref proj :directory)))) (if (file-exists-p fname) ;; Load in the configuration - (setq config (eieio-persistent-read fname)) + (setq config (eieio-persistent-read fname 'ede-generic-config)) ;; Create a new one. (setq config (ede-generic-config "Configuration" @@ -321,6 +329,44 @@ If one doesn't exist, create a new one for this directory." (config (ede-generic-get-configuration proj))) (oref config c-include-path))) +;;; Commands +;; +(defmethod project-compile-project ((proj ede-generic-project) &optional command) + "Compile the entire current project PROJ. +Argument COMMAND is the command to use when compiling." + (let* ((config (ede-generic-get-configuration proj)) + (comp (oref config :build-command))) + (compile comp))) + +(defmethod project-compile-target ((obj ede-generic-target) &optional command) + "Compile the current target OBJ. +Argument COMMAND is the command to use for compiling the target." + (project-compile-project (ede-current-project) command)) + +(defmethod project-debug-target ((target ede-generic-target)) + "Run the current project derived from TARGET in a debugger." + (let* ((proj (ede-target-parent target)) + (config (ede-generic-get-configuration proj)) + (debug (oref config :debug-command)) + (cmd (read-from-minibuffer + "Debug Command: " + debug)) + (cmdsplit (split-string cmd " " t)) + ;; @TODO - this depends on the user always typing in something good + ;; like "gdb" or "dbx" which also exists as a useful Emacs command. + ;; Is there a better way? + (cmdsym (intern-soft (car cmdsplit)))) + (call-interactively cmdsym t))) + +(defmethod project-run-target ((target ede-generic-target)) + "Run the current project derived from TARGET." + (require 'ede-shell) + (let* ((proj (ede-target-parent target)) + (config (ede-generic-get-configuration proj)) + (run (concat "./" (oref config :run-command))) + (cmd (read-from-minibuffer "Run (like this): " run))) + (ede-shell-run-something target cmd))) + ;;; Customization ;; (defmethod ede-customize ((proj ede-generic-project)) @@ -365,27 +411,31 @@ PROJECTFILE is a file name that identifies a project of this type to EDE, such a 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)) + (ede-add-project-autoload + (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 + :safe-p nil) ; @todo - could be + ; safe if we do something + ; about the loading of the + ; generic config file. + ;; Generics must go at the end, since more specific types + ;; can create Makefiles also. + 'generic)) ;;;###autoload (defun ede-enable-generic-projects () "Enable generic project loaders." (interactive) - (ede-generic-new-autoloader "edeproject-makefile" "Make" + (ede-generic-new-autoloader "generic-makefile" "Make" "Makefile" 'ede-generic-makefile-project) - (ede-generic-new-autoloader "edeproject-scons" "SCons" + (ede-generic-new-autoloader "generic-scons" "SCons" "SConstruct" 'ede-generic-scons-project) - (ede-generic-new-autoloader "edeproject-cmake" "CMake" + (ede-generic-new-autoloader "generic-cmake" "CMake" "CMakeLists" 'ede-generic-cmake-project) ) diff --git a/lisp/cedet/ede/linux.el b/lisp/cedet/ede/linux.el index 70cd9498f69..7cd066f8b3b 100644 --- a/lisp/cedet/ede/linux.el +++ b/lisp/cedet/ede/linux.el @@ -33,11 +33,29 @@ ;; * Add website (require 'ede) +(require 'ede/make) + (declare-function semanticdb-file-table-object "semantic/db") (declare-function semanticdb-needs-refresh-p "semantic/db") (declare-function semanticdb-refresh-table "semantic/db") ;;; Code: +(defgroup project-linux nil + "File and tag browser frame." + :group 'tools + :group 'ede + ) + +(defcustom project-linux-compile-target-command (concat ede-make-command " -k -C %s SUBDIRS=%s") + "*Default command used to compile a target." + :group 'project-linux + :type 'string) + +(defcustom project-linux-compile-project-command (concat ede-make-command " -k -C %s") + "*Default command used to compile a project." + :group 'project-linux + :type 'string) + (defvar ede-linux-project-list nil "List of projects created by option `ede-linux-project'.") @@ -95,6 +113,7 @@ DIR is the directory to search from." "Project Type for the Linux source code." :method-invocation-order :depth-first) +;;;###autoload (defun ede-linux-load (dir &optional rootproj) "Return an Linux Project object if there is a match. Return nil if there isn't one. @@ -102,27 +121,29 @@ Argument DIR is the directory it is created for. ROOTPROJ is nil, since there is only one project." (or (ede-linux-file-existing dir) ;; Doesn't already exist, so let's make one. - (ede-linux-project "Linux" - :name "Linux" - :version (ede-linux-version dir) - :directory (file-name-as-directory dir) - :file (expand-file-name "scripts/ver_linux" - dir)) - (ede-add-project-to-global-list this) - ) - ) + (let ((proj (ede-linux-project + "Linux" + :name "Linux" + :version (ede-linux-version dir) + :directory (file-name-as-directory dir) + :file (expand-file-name "scripts/ver_linux" + dir)))) + (ede-add-project-to-global-list proj)) + )) ;;;###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) +(ede-add-project-autoload + (ede-project-autoload "linux" + :name "LINUX ROOT" + :file 'ede/linux + :proj-file "scripts/ver_linux" + :proj-root-dirmatch "linux[^/]*" + :proj-root 'ede-linux-project-root + :load-type 'ede-linux-load + :class-sym 'ede-linux-project + :new-p nil + :safe-p t) + 'unique) (defclass ede-linux-target-c (ede-target) () @@ -238,6 +259,42 @@ Knows about how the Linux source tree is organized." ) (or F (call-next-method)))) +(defmethod project-compile-project ((proj ede-linux-project) + &optional command) + "Compile the entire current project. +Argument COMMAND is the command to use when compiling." + (let* ((dir (ede-project-root-directory proj))) + + (require 'compile) + (if (not project-linux-compile-project-command) + (setq project-linux-compile-project-command compile-command)) + (if (not command) + (setq command + (format + project-linux-compile-project-command + dir))) + + (compile command))) + +(defmethod project-compile-target ((obj ede-linux-target-c) &optional command) + "Compile the current target. +Argument COMMAND is the command to use for compiling the target." + (let* ((proj (ede-target-parent obj)) + (root (ede-project-root proj)) + (dir (ede-project-root-directory root)) + (subdir (oref obj path))) + + (require 'compile) + (if (not project-linux-compile-project-command) + (setq project-linux-compile-project-command compile-command)) + (if (not command) + (setq command + (format + project-linux-compile-target-command + dir subdir))) + + (compile command))) + (provide 'ede/linux) ;; Local variables: diff --git a/lisp/cedet/ede/makefile-edit.el b/lisp/cedet/ede/makefile-edit.el index afa1c7200ec..739b774ee52 100644 --- a/lisp/cedet/ede/makefile-edit.el +++ b/lisp/cedet/ede/makefile-edit.el @@ -99,7 +99,8 @@ STOP-BEFORE is a regular expression matching a file name." "Return a list of all files in MACRO." (save-excursion (goto-char (point-min)) - (let ((lst nil)) + (let ((lst nil) + (case-fold-search nil)) (while (makefile-move-to-macro macro t) (let ((e (save-excursion (makefile-end-of-command) diff --git a/lisp/cedet/ede/pmake.el b/lisp/cedet/ede/pmake.el index bd5400bb615..c638a5f0307 100644 --- a/lisp/cedet/ede/pmake.el +++ b/lisp/cedet/ede/pmake.el @@ -265,12 +265,13 @@ Execute BODY in a location where a value can be placed." "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))) - )) + (unless + (save-excursion + (re-search-backward (concat "^" v "\\s-*=") nil t)) + (insert v "=") + ,@body + (when addcr (insert "\n")) + (goto-char (point-max))))) (put 'ede-pmake-insert-variable-once 'lisp-indent-function 1) ;;; SOURCE VARIABLE NAME CONSTRUCTION diff --git a/lisp/cedet/ede/proj-comp.el b/lisp/cedet/ede/proj-comp.el index 8277f58a5e0..87a722ef9be 100644 --- a/lisp/cedet/ede/proj-comp.el +++ b/lisp/cedet/ede/proj-comp.el @@ -319,7 +319,7 @@ Not all compilers do this." (defmethod ede-proj-makefile-insert-rules ((this ede-makefile-rule)) "Insert rules needed for THIS rule object." - (if (oref this phony) (insert ".PHONY: (oref this target)\n")) + (if (oref this phony) (insert ".PHONY: " (oref this target) "\n")) (insert (oref this target) ": " (oref this dependencies) "\n\t" (mapconcat (lambda (c) c) (oref this rules) "\n\t") "\n\n")) @@ -331,15 +331,16 @@ compiler it decides to use after inserting in the rule." (when (slot-boundp this 'commands) (with-slots (commands) this (mapc - (lambda (obj) (insert "\t" - (cond ((stringp obj) - obj) - ((and (listp obj) - (eq (car obj) 'lambda)) - (funcall obj)) - (t - (format "%S" obj))) - "\n")) + (lambda (obj) (insert + (if (bolp) "\t" " ") + (cond ((stringp obj) + obj) + ((and (listp obj) + (eq (car obj) 'lambda)) + (funcall obj)) + (t + (format "%S" obj))) + "\n")) commands)) (insert "\n"))) diff --git a/lisp/cedet/ede/proj-elisp.el b/lisp/cedet/ede/proj-elisp.el index 78200acff7d..db8803fa002 100644 --- a/lisp/cedet/ede/proj-elisp.el +++ b/lisp/cedet/ede/proj-elisp.el @@ -45,10 +45,37 @@ There should only be one toplevel package per auxiliary tool needed. These packages location is found, and added to the compile time load path." - )) + ) + (pre-load-packages :initarg :pre-load-packages + :initform nil + :type list + :custom (repeat string) + :documentation "Additional packages to pre-load. +Each package name will be loaded with `require'. +Each package's directory should also appear in :aux-packages via a package name.") + ) "This target consists of a group of lisp files. A lisp target may be one general program with many separate lisp files in it.") +(defmethod ede-proj-makefile-insert-rules :after ((this ede-proj-target-elisp)) + "Insert rules needed by THIS target. +This inserts the PRELOADS target-local variable." + (let ((preloads (oref this pre-load-packages))) + (when preloads + (insert (format "%s: PRELOADS=%s\n" + (oref this name) + (mapconcat 'identity preloads " "))))) + (insert "\n")) + +(defmethod ede-proj-makefile-dependencies ((this ede-proj-target-elisp)) + "Return a string representing the dependencies for THIS. +Some compilers only use the first element in the dependencies, others +have a list of intermediates (object files), and others don't care. +This allows customization of how these elements appear. +For Emacs Lisp, return addsuffix command on source files." + (format "$(addsuffix c, $(%s))" + (ede-proj-makefile-sourcevar this))) + (defvar ede-source-emacs (ede-sourcecode "ede-emacs-source" :name "Emacs Lisp" @@ -61,18 +88,17 @@ A lisp target may be one general program with many separate lisp files in it.") "ede-emacs-compiler" :name "emacs" :variables '(("EMACS" . "emacs") - ("EMACSFLAGS" . "-batch --no-site-file")) - :commands - '("@echo \"(add-to-list 'load-path nil)\" > $@-compile-script" - "for loadpath in . ${LOADPATH}; do \\" - " echo \"(add-to-list 'load-path \\\"$$loadpath\\\")\" >> $@-compile-script; \\" - "done;" - "@echo \"(setq debug-on-error t)\" >> $@-compile-script" - "\"$(EMACS)\" $(EMACSFLAGS) -l $@-compile-script -f batch-byte-compile $^" - ) + ("EMACSFLAGS" . "-batch --no-site-file --eval '(setq debug-on-error t)'") + ("require" . "$(foreach r,$(1),(require (quote $(r))))")) + :rules (list (ede-makefile-rule + "elisp-inference-rule" + :target "%.elc" + :dependencies "%.el" + :rules '("$(EMACS) $(EMACSFLAGS) $(addprefix -L ,$(LOADPATH)) \ +--eval '(progn $(call require, $(PRELOADS)))' -f batch-byte-compile $^"))) :autoconf '("AM_PATH_LISPDIR") :sourcetype '(ede-source-emacs) -; :objectextention ".elc" + :objectextention ".elc" ) "Compile Emacs Lisp programs.") @@ -112,7 +138,7 @@ Lays claim to all .elc files that match .el files in this target." (full nil) ) ;; Make sure the relative name isn't to far off - (when (string-match "^\\.\\./\\.\\./\\.\\./\\.\\." rel) + (when (string-match "^\\.\\./\\.\\./\\.\\./\\.\\./\\.\\." rel) (setq full fnd)) ;; Do the setup. (setq paths (cons (or full rel) paths) @@ -129,9 +155,20 @@ Bonus: Return a cons cell: (COMPILED . UPTODATE)." (mapc (lambda (src) (let* ((fsrc (expand-file-name src dir)) (elc (concat (file-name-sans-extension fsrc) ".elc"))) - (if (eq (byte-recompile-file fsrc nil 0) t) - (setq comp (1+ comp)) - (setq utd (1+ utd))))) + (with-no-warnings + (if (< emacs-major-version 24) + ;; Does not have `byte-recompile-file' + (if (or (not (file-exists-p elc)) + (file-newer-than-file-p fsrc elc)) + (progn + (setq comp (1+ comp)) + (byte-compile-file fsrc)) + (setq utd (1+ utd))) + + (if (eq (byte-recompile-file fsrc nil 0) t) + (setq comp (1+ comp)) + (setq utd (1+ utd))))))) + (oref obj source)) (message "All Emacs Lisp sources are up to date in %s" (object-name obj)) (cons comp utd))) @@ -185,8 +222,7 @@ is found, such as a `-version' variable, or the standard header." "Insert variables needed by target THIS." (let ((newitems (if (oref this aux-packages) (ede-proj-elisp-packages-to-loadpath - (oref this aux-packages)))) - ) + (oref this aux-packages))))) (ede-proj-makefile-insert-loadpath-items newitems))) (defun ede-proj-elisp-add-path (path) @@ -211,7 +247,8 @@ is found, such as a `-version' variable, or the standard header." "Tweak the configure file (current buffer) to accommodate THIS." (call-next-method) ;; Ok, now we have to tweak the autoconf provided `elisp-comp' program. - (let ((ec (ede-expand-filename this "elisp-comp" 'newfile))) + (let ((ec (ede-expand-filename this "elisp-comp" 'newfile)) + (enable-local-variables nil)) (if (or (not ec) (not (file-exists-p ec))) (message "No elisp-comp file. There may be compile errors? Rerun a second time.") (save-excursion @@ -235,7 +272,7 @@ is found, such as a `-version' variable, or the standard header." "Flush the configure file (current buffer) to accommodate THIS." ;; Remove crufty old paths from elisp-compile (let ((ec (ede-expand-filename this "elisp-comp" 'newfile)) - ) + (enable-local-variables nil)) (if (and ec (file-exists-p ec)) (with-current-buffer (find-file-noselect ec t) (goto-char (point-min)) @@ -251,8 +288,8 @@ is found, such as a `-version' variable, or the standard header." ;; (defclass ede-proj-target-elisp-autoloads (ede-proj-target-elisp) ((availablecompilers :initform '(ede-emacs-cedet-autogen-compiler)) - (aux-packages :initform ("cedet-autogen")) (phony :initform t) + (rules :initform nil) (autoload-file :initarg :autoload-file :initform "loaddefs.el" :type string @@ -287,15 +324,14 @@ Lays claim to all .elc files that match .el files in this target." (ede-compiler "ede-emacs-autogen-compiler" :name "emacs" - :variables '(("EMACS" . "emacs")) + :variables '(("EMACS" . "emacs") + ("EMACSFLAGS" . "-batch --no-site-file --eval '(setq debug-on-error t)'") + ("require" . "$(foreach r,$(1),(require (quote $(r))))")) :commands - '("@echo \"(add-to-list 'load-path nil)\" > $@-compile-script" - "for loadpath in . ${LOADPATH}; do \\" - " echo \"(add-to-list 'load-path \\\"$$loadpath\\\")\" >> $@-compile-script; \\" - "done;" - "@echo \"(require 'cedet-autogen)\" >> $@-compile-script" - "\"$(EMACS)\" -batch --no-site-file -l $@-compile-script -f cedet-batch-update-autoloads $(LOADDEFS) $(LOADDIRS)" - ) + '("$(EMACS) $(EMACSFLAGS) $(addprefix -L ,$(LOADPATH)) \ +--eval '(setq generated-autoload-file \"$(abspath $(LOADDEFS))\")' \ +-f batch-update-autoloads $(abspath $(LOADDIRS))") + :rules (list (ede-makefile-rule "clean-autoloads" :target "clean-autoloads" :phony t :rules '("rm -f $(LOADDEFS)"))) :sourcetype '(ede-source-emacs) ) "Build an autoloads file.") diff --git a/lisp/cedet/ede/proj.el b/lisp/cedet/ede/proj.el index a8afe9ec804..8d81b825565 100644 --- a/lisp/cedet/ede/proj.el +++ b/lisp/cedet/ede/proj.el @@ -53,6 +53,39 @@ (autoload 'ede-proj-target-makefile-info "ede/proj-info" "Target class for info files." nil nil) +(eieio-defclass-autoload 'ede-proj-target-aux '(ede-proj-target) + "ede/proj-aux" + "Target class for a group of lisp files.") +(eieio-defclass-autoload 'ede-proj-target-elisp '(ede-proj-target-makefile) + "ede/proj-elisp" + "Target class for a group of lisp files.") +(eieio-defclass-autoload 'ede-proj-target-elisp-autoloads '(ede-proj-target-elisp) + "ede/proj-elisp" + "Target class for generating autoload files.") +(eieio-defclass-autoload 'ede-proj-target-scheme '(ede-proj-target) + "ede/proj-scheme" + "Target class for a group of lisp files.") +(eieio-defclass-autoload 'ede-proj-target-makefile-miscelaneous '(ede-proj-target-makefile) + "ede/proj-misc" + "Target class for a group of miscellaneous w/ a special makefile.") +(eieio-defclass-autoload 'ede-proj-target-makefile-program '(ede-proj-target-makefile-objectcode) + "ede/proj-prog" + "Target class for building a program.") +(eieio-defclass-autoload 'ede-proj-target-makefile-archive '(ede-proj-target-makefile-objectcode) + "ede/proj-archive" + "Target class for building an archive of object code.") +(eieio-defclass-autoload 'ede-proj-target-makefile-shared-object '(ede-proj-target-makefile-program) + "ede/proj-shared" + "Target class for building a shared object.") +(eieio-defclass-autoload 'ede-proj-target-makefile-info '(ede-proj-target-makefile) + "ede/proj-info" + "Target class for info files.") + +;; Not in ede/ , but part of semantic. +(eieio-defclass-autoload 'semantic-ede-proj-target-grammar '(ede-proj-target-elisp) + "semantic/ede-grammar" + "Target classfor Semantic grammar files.") + ;;; Class Definitions: (defclass ede-proj-target (ede-target) ((auxsource :initarg :auxsource @@ -181,8 +214,10 @@ This enables the creation of your target type." (setq ede-proj-target-alist (cons (cons name class) ede-proj-target-alist))))) -(defclass ede-proj-project (ede-project) - ((makefile-type :initarg :makefile-type +(defclass ede-proj-project (eieio-persistent ede-project) + ((extension :initform ".ede") + (file-header-line :initform ";; EDE Project Files are auto generated: Do Not Edit") + (makefile-type :initarg :makefile-type :initform Makefile :type symbol :custom (choice (const Makefile) @@ -259,23 +294,16 @@ If optional ROOTPROJ is provided then ROOTPROJ is the root project for the tree being read in. If ROOTPROJ is nil, then assume that the PROJECT being read in is the root project." (save-excursion - (let ((ret nil) + (let ((ret (eieio-persistent-read (concat project "Project.ede") + ede-proj-project)) (subdirs (directory-files project nil "[^.].*" nil))) - (set-buffer (get-buffer-create " *tmp proj read*")) - (unwind-protect - (progn - (insert-file-contents (concat project "Project.ede") - nil nil nil t) - (goto-char (point-min)) - (setq ret (read (current-buffer))) - (if (not (eq (car ret) 'ede-proj-project)) - (error "Corrupt project file")) - (setq ret (eval ret)) - (oset ret file (concat project "Project.ede")) - (oset ret directory project) - (oset ret rootproject rootproj) - ) - (kill-buffer " *tmp proj read*")) + (if (not (object-of-class-p ret 'ede-proj-project)) + (error "Corrupt project file")) + (oset ret directory project) + (oset ret rootproject rootproj) + + ;; Load the project file of each subdirectory containing a + ;; loadable Project.ede. (while subdirs (let ((sd (file-name-as-directory (expand-file-name (car subdirs) project)))) @@ -291,22 +319,13 @@ the PROJECT being read in is the root project." "Write out object PROJECT into its file." (save-excursion (if (not project) (setq project (ede-current-project))) - (let ((b (set-buffer (get-buffer-create " *tmp proj write*"))) - (cfn (oref project file)) - (cdir (oref project directory))) + (let ((cdir (oref project directory))) (unwind-protect - (save-excursion - (erase-buffer) - (let ((standard-output (current-buffer))) - (oset project file (file-name-nondirectory cfn)) - (slot-makeunbound project :directory) - (object-write project ";; EDE project file.")) - (write-file cfn nil) - ) - ;; Restore the :file on exit. - (oset project file cfn) - (oset project directory cdir) - (kill-buffer b))))) + (progn + (slot-makeunbound project :directory) + (eieio-persistent-save project)) + ;; Restore the directory slot + (oset project directory cdir))) )) (defmethod ede-commit-local-variables ((proj ede-proj-project)) "Commit change to local variables in PROJ." @@ -670,6 +689,8 @@ Optional argument FORCE will force items to be regenerated." (let ((root (or (ede-project-root this) this)) ) (setq ede-projects (delq root ede-projects)) + ;; NOTE : parent function double-checks that this dir was + ;; already in memory once. (ede-load-project-file (ede-project-root-directory root)) )) diff --git a/lisp/cedet/ede/project-am.el b/lisp/cedet/ede/project-am.el index e951598ba55..5053701192e 100644 --- a/lisp/cedet/ede/project-am.el +++ b/lisp/cedet/ede/project-am.el @@ -205,7 +205,7 @@ OT is the object target. DIR is the directory to start in." (oref amf targets)) nil t)))) ;; The input target might be new. See if we can find it. - (amf (ede-load-project-file (oref ot path))) + (amf (ede-target-parent ot)) (ot (object-assoc target 'name (oref amf targets))) (ofn (file-name-nondirectory (buffer-file-name)))) (if (not ot) diff --git a/lisp/cedet/ede/util.el b/lisp/cedet/ede/util.el index 05688aa56ff..489c4d3dbf1 100644 --- a/lisp/cedet/ede/util.el +++ b/lisp/cedet/ede/util.el @@ -87,7 +87,7 @@ their sources to VERSION." If BUFFER isn't specified, use the current buffer." (save-excursion (if buffer (set-buffer buffer)) - (toggle-read-only -1))) + (setq buffer-read-only nil))) (provide 'ede/util) diff --git a/lisp/cedet/inversion.el b/lisp/cedet/inversion.el index 877ed54566c..6a13a12e8e1 100644 --- a/lisp/cedet/inversion.el +++ b/lisp/cedet/inversion.el @@ -79,15 +79,20 @@ (defconst inversion-decoders '( - (alpha "^\\([0-9]+\\)\\.\\([0-9]+\\)\\s-*\\.?alpha\\([0-9]+\\)?$" 3) - (beta "^\\([0-9]+\\)\\.\\([0-9]+\\)\\s-*\\.?beta\\([0-9]+\\)?$" 3) - (beta "^\\([0-9]+\\)\\.\\([0-9]+\\)\\s-*(beta\\([0-9]+\\)?)" 3) + (alpha "^\\([0-9]+\\)\\.\\([0-9]+\\)\\.?\\([0-9]*\\)?\\s-*\\.?alpha\\([0-9]+\\)?$" 4) + (beta "^\\([0-9]+\\)\\.\\([0-9]+\\)\\.?\\([0-9]*\\)?\\s-*\\.?beta\\([0-9]+\\)?$" 4) + (beta "^\\([0-9]+\\)\\.\\([0-9]+\\)\\.?\\([0-9]*\\)?\\s-*\\.?(beta\\([0-9]+\\)?)$" 4) + (beta "^[^/]+/\\w+--\\w+--\\([0-9]+\\)\\.\\([0-9]+\\)\\.\\([0-9]+\\)--patch-\\([0-9]+\\)" 4) + (beta "^\\w+: v\\([0-9]+\\)\\.\\([0-9]+\\)\\.\\([0-9]+\\)-\\([0-9]+\\)-\\(.*\\)" 5) (prerelease "^\\([0-9]+\\)\\.\\([0-9]+\\)\\s-*\\.?pre\\([0-9]+\\)?$" 3) - (full "^\\([0-9]+\\)\\.\\([0-9]+\\)$" 2) + (full "^\\([0-9]+\\)\\.\\([0-9]+\\)\\.?\\([0-9]+\\)?$" 3) (fullsingle "^\\([0-9]+\\)$" 1) - (patch "^\\([0-9]+\\)\\.\\([0-9]+\\) (patch \\([0-9]+\\))" 3) + (patch "^\\([0-9]+\\)\\.\\([0-9]+\\)\\.?\\([0-9]+\\)?\\s-*(patch \\([0-9]+\\))" 4) (point "^\\([0-9]+\\)\\.\\([0-9]+\\)\\.\\([0-9]+\\)$" 3) + (point "^\\w+: v\\([0-9]+\\)\\.\\([0-9]+\\)\\.\\([0-9]+\\)-\\(0\\)-\\(.*\\)" 5) (build "^\\([0-9]+\\)\\.\\([0-9]+\\)\\.\\([0-9]+\\).\\([0-9]+\\)$" 4) + (full "^[^/]+/\\w+--\\w+--\\([0-9]+\\)\\.\\([0-9]+\\)\\.\\([0-9]+\\)--version-\\([0-9]+\\)" 4) + (full "^\\w+: v\\([0-9]+\\)\\.\\([0-9]+\\)\\.\\([0-9]+\\)" 5) ) "List of decoders for version strings. Each decoder is of the form: @@ -140,7 +145,7 @@ where RELEASE is a symbol such as `full', or `beta'." ;; Decode the code (setq code (inversion-decode-version ver)) (unless code - (error "%S-version value cannot be decoded" package)) + (error "%S-version value (%s) cannot be decoded" package ver)) code)) (defun inversion-package-incompatibility-version (package) @@ -195,24 +200,25 @@ not an indication of new features or bug fixes." (v2-3 (nth 3 ver2)) (v2-4 (nth 4 ver2)) ) - (or (and (= v1-0 v2-0) - (= v1-1 v2-1) - (= v1-2 v2-2) - (= v1-3 v2-3) - v1-4 v2-4 ; all or nothing if elt - is = + + (cond ((and (equal (list v1-1 v1-2 v1-3 v1-4) + (list v2-1 v2-2 v2-3 v2-4)) + v1-0 v2-0) + (< v1-0 v2-0)) + ((and (equal v1-1 v2-1) + (equal v1-2 v2-2) + (equal v1-3 v2-3) + v1-4 v2-4) ; all or nothing if elt - is = (< v1-4 v2-4)) - (and (= v1-0 v2-0) - (= v1-1 v2-1) - (= v1-2 v2-2) - v1-3 v2-3 ; all or nothing if elt - is = + ((and (equal v1-1 v2-1) + (equal v1-2 v2-2) + v1-3 v2-3) ; all or nothing if elt - is = (< v1-3 v2-3)) - (and (= v1-1 v2-1) + ((and (equal v1-1 v2-1) + v1-2 v2-2) (< v1-2 v2-2)) - (and (< v1-1 v2-1)) - (and (< v1-0 v2-0) - (= v1-1 v2-1) - (= v1-2 v2-2) - ) + ((and v1-1 v2-1) + (< v1-1 v2-1)) ))) (defun inversion-check-version (version incompatible-version @@ -340,13 +346,17 @@ Optional argument RESERVED is saved for later use." ;; Return the package symbol that was required. package)) -(defun inversion-require-emacs (emacs-ver xemacs-ver) - "Declare that you need either EMACS-VER, or XEMACS-VER. +;;;###autoload +(defun inversion-require-emacs (emacs-ver xemacs-ver sxemacs-ver) + "Declare that you need either EMACS-VER, XEMACS-VER or SXEMACE-ver. Only checks one based on which kind of Emacs is being run." (let ((err (inversion-test 'emacs - (if (featurep 'xemacs) - xemacs-ver - emacs-ver)))) + (cond ((featurep 'sxemacs) + sxemacs-ver) + ((featurep 'xemacs) + xemacs-ver) + (t + emacs-ver))))) (if err (error err) ;; Something nice... t))) diff --git a/lisp/cedet/semantic.el b/lisp/cedet/semantic.el index aeb5241b2d0..5182a38327c 100644 --- a/lisp/cedet/semantic.el +++ b/lisp/cedet/semantic.el @@ -38,7 +38,7 @@ (require 'semantic/tag) (require 'semantic/lex) -(defvar semantic-version "2.0" +(defvar semantic-version "2.1beta" "Current version of Semantic.") (declare-function inversion-test "inversion") @@ -273,7 +273,9 @@ setup to use Semantic." (js-mode . wisent-javascript-setup-parser) (python-mode . wisent-python-default-setup) (scheme-mode . semantic-default-scheme-setup) + (f90-mode . semantic-default-f90-setup) (srecode-template-mode . srecode-template-setup-parser) + (texinfo-mode . semantic-default-texi-setup) (makefile-automake-mode . semantic-default-make-setup) (makefile-gmake-mode . semantic-default-make-setup) (makefile-makepp-mode . semantic-default-make-setup) @@ -623,16 +625,18 @@ was marked unparseable, then do nothing, and return the cache." ;;;; Parse the whole system. ((semantic-parse-tree-needs-rebuild-p) - ;; Use Emacs's built-in progress-reporter - (let ((semantic--progress-reporter - (and (>= (point-max) semantic-minimum-working-buffer-size) - (eq semantic-working-type 'percent) - (make-progress-reporter - (semantic-parser-working-message (buffer-name)) - 0 100)))) - (setq res (semantic-parse-region (point-min) (point-max))) - (if semantic--progress-reporter - (progress-reporter-done semantic--progress-reporter))) + ;; Use Emacs's built-in progress-reporter (only interactive). + (if noninteractive + (setq res (semantic-parse-region (point-min) (point-max))) + (let ((semantic--progress-reporter + (and (>= (point-max) semantic-minimum-working-buffer-size) + (eq semantic-working-type 'percent) + (make-progress-reporter + (semantic-parser-working-message (buffer-name)) + 0 100)))) + (setq res (semantic-parse-region (point-min) (point-max))) + (if semantic--progress-reporter + (progress-reporter-done semantic--progress-reporter)))) ;; Clear the caches when we see there were no errors. ;; But preserve the unmatched syntax cache and warnings! @@ -986,6 +990,12 @@ Throw away all the old tags, and recreate the tag database." :help "Highlight the tag at point" :visible semantic-mode :button (:toggle . global-semantic-highlight-func-mode))) + (define-key cedet-menu-map [global-semantic-stickyfunc-mode] + '(menu-item "Stick Top Tag to Headerline" global-semantic-stickyfunc-mode + :help "Stick the tag scrolled off the top of the buffer into the header line" + :visible semantic-mode + :button (:toggle . (bound-and-true-p + global-semantic-stickyfunc-mode)))) (define-key cedet-menu-map [global-semantic-decoration-mode] '(menu-item "Decorate Tags" global-semantic-decoration-mode :help "Decorate tags based on tag attributes" @@ -1031,7 +1041,12 @@ Prevent this load system from loading files in twice.") global-semantic-idle-scheduler-mode global-semanticdb-minor-mode global-semantic-idle-summary-mode - global-semantic-mru-bookmark-mode) + global-semantic-mru-bookmark-mode + global-cedet-m3-minor-mode + global-semantic-idle-local-symbol-highlight-mode + global-semantic-highlight-edits-mode + global-semantic-show-unmatched-syntax-mode + global-semantic-show-parser-state-mode) "List of auxiliary minor modes in the Semantic package.") ;;;###autoload @@ -1048,7 +1063,17 @@ The possible elements of this list include the following: `global-semantic-highlight-func-mode' - Highlight the current tag. `global-semantic-stickyfunc-mode' - Show current fun in header line. `global-semantic-mru-bookmark-mode' - Provide `switch-to-buffer'-like - keybinding for tag names." + keybinding for tag names. + `global-cedet-m3-minor-mode' - A mouse 3 context menu. + `global-semantic-idle-local-symbol-highlight-mode' - Highlight references + of the symbol under point. +The following modes are more targeted at people who want to see + some internal information of the semantic parser in action: + `global-semantic-highlight-edits-mode' - Visualize incremental parser by + highlighting not-yet parsed changes. + `global-semantic-show-unmatched-syntax-mode' - Highlight unmatched lexical + syntax tokens. + `global-semantic-show-parser-state-mode' - Display the parser cache state." :group 'semantic :type `(set ,@(mapcar (lambda (c) (list 'const c)) semantic-submode-list))) @@ -1095,16 +1120,27 @@ Semantic mode. (dolist (b (buffer-list)) (with-current-buffer b (semantic-new-buffer-fcn)))) - ;; Disable all Semantic features. + ;; Disable Semantic features. Removing everything Semantic has + ;; introduced in the buffer is pretty much futile, but we have to + ;; clean the hooks and delete Semantic-related overlays, so that + ;; Semantic can be re-activated cleanly. (remove-hook 'mode-local-init-hook 'semantic-new-buffer-fcn) (remove-hook 'completion-at-point-functions 'semantic-completion-at-point-function) + (remove-hook 'after-change-functions + 'semantic-change-function) (define-key cedet-menu-map [cedet-menu-separator] nil) (define-key cedet-menu-map [semantic-options-separator] nil) ;; FIXME: handle semanticdb-load-ebrowse-caches (dolist (mode semantic-submode-list) (if (and (boundp mode) (eval mode)) - (funcall mode -1))))) + (funcall mode -1))) + ;; Unlink buffer and clear cache + (semantic--tag-unlink-cache-from-buffer) + (setq semantic--buffer-cache nil) + ;; Make sure we run the setup function if Semantic gets + ;; re-activated. + (setq semantic-new-buffer-fcn-was-run nil))) (defun semantic-completion-at-point-function () 'semantic-ia-complete-symbol) @@ -1141,6 +1177,11 @@ minor mode can be turned on only if semantic feature is available and the current buffer was set up for parsing. Return non-nil if the minor mode is enabled." t nil) +(autoload 'global-semantic-idle-local-symbol-highlight-mode "semantic/idle" + "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." t nil) + (autoload 'srecode-template-setup-parser "srecode/srecode-template" "Set up buffer for parsing SRecode template files." t nil) diff --git a/lisp/cedet/semantic/analyze/debug.el b/lisp/cedet/semantic/analyze/debug.el index 5fe0078478d..19c61cb74c7 100644 --- a/lisp/cedet/semantic/analyze/debug.el +++ b/lisp/cedet/semantic/analyze/debug.el @@ -443,7 +443,7 @@ or implementing a version specific to ") (semanticdb-file-table-object fileinner t)))) (cond ((not fileinner) (setq unknown (1+ unknown))) - ((number-or-marker-p (oref tableinner pointmax)) + ((and tableinner (number-or-marker-p (oref tableinner pointmax))) (setq ok (1+ ok))) (t (setq unparsed (1+ unparsed)))))) diff --git a/lisp/cedet/semantic/analyze/fcn.el b/lisp/cedet/semantic/analyze/fcn.el index a27356c784b..d780327b7e9 100644 --- a/lisp/cedet/semantic/analyze/fcn.el +++ b/lisp/cedet/semantic/analyze/fcn.el @@ -37,24 +37,6 @@ ;; ;; These queries allow a major mode to help the analyzer make decisions. ;; -(define-overloadable-function semantic-analyze-tag-prototype-p (tag) - "Non-nil if TAG is a prototype." - ) - -(defun semantic-analyze-tag-prototype-p-default (tag) - "Non-nil if TAG is a prototype." - (let ((p (semantic-tag-get-attribute tag :prototype-flag))) - (cond - ;; Trust the parser author. - (p p) - ;; Empty types might be a prototype. - ((eq (semantic-tag-class tag) 'type) - (not (semantic-tag-type-members tag))) - ;; No other heuristics. - (t nil)) - )) - -;;------------------------------------------------------------ (define-overloadable-function semantic-analyze-split-name (name) "Split a tag NAME into a sequence. @@ -219,7 +201,7 @@ used by the analyzer debugger." (if (and type-declaration (semantic-tag-p type-declaration) (semantic-tag-of-class-p type-declaration 'type) - (not (semantic-analyze-tag-prototype-p type-declaration)) + (not (semantic-tag-prototype-p type-declaration)) ) ;; We have an anonymous type for TAG with children. ;; Use this type directly. @@ -312,7 +294,7 @@ SCOPE is the current scope." (when (and (semantic-tag-p ans) (eq (semantic-tag-class ans) 'type)) ;; We have a tag. - (if (semantic-analyze-tag-prototype-p ans) + (if (semantic-tag-prototype-p ans) ;; It is a prototype.. find the real one. (or (and scope (car-safe diff --git a/lisp/cedet/semantic/analyze/refs.el b/lisp/cedet/semantic/analyze/refs.el index 09a4c08c059..05ac56eac69 100644 --- a/lisp/cedet/semantic/analyze/refs.el +++ b/lisp/cedet/semantic/analyze/refs.el @@ -87,7 +87,7 @@ Use `semantic-analyze-current-tag' to debug this fcn." (semantic-go-to-tag tag db) (setq scope (semantic-calculate-scope)) - (setq allhits (semantic--analyze-refs-full-lookup tag scope)) + (setq allhits (semantic--analyze-refs-full-lookup tag scope t)) (semantic-analyze-references (semantic-tag-name tag) :tag tag @@ -115,7 +115,10 @@ Optional argument IN-BUFFER indicates that the returned tag should be in an acti (aDB (car ans)) ) (when (and (not (semantic-tag-prototype-p aT)) - (semantic-tag-similar-p tag aT :prototype-flag :parent)) + (semantic-tag-similar-p tag aT + :prototype-flag + :parent + :typemodifiers)) (when in-buffer (save-excursion (semantic-go-to-tag aT aDB))) (push aT impl)))) allhits) @@ -135,7 +138,10 @@ Optional argument IN-BUFFER indicates that the returned tag should be in an acti (aDB (car ans)) ) (when (and (semantic-tag-prototype-p aT) - (semantic-tag-similar-p tag aT :prototype-flag :parent)) + (semantic-tag-similar-p tag aT + :prototype-flag + :parent + :typemodifiers)) (when in-buffer (save-excursion (semantic-go-to-tag aT aDB))) (push aT proto)))) allhits) @@ -143,14 +149,15 @@ Optional argument IN-BUFFER indicates that the returned tag should be in an acti ;;; LOOKUP ;; -(defun semantic--analyze-refs-full-lookup (tag scope) +(defun semantic--analyze-refs-full-lookup (tag scope &optional noerror) "Perform a full lookup for all occurrences of TAG in the current project. TAG should be the tag currently under point. 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." +derived. If SCOPE does not have parents, then only a simple lookup is done. +Optional argument NOERROR means don't error if the lookup fails." (if (not (oref scope parents)) ;; If this tag has some named parent, but is not - (semantic--analyze-refs-full-lookup-simple tag) + (semantic--analyze-refs-full-lookup-simple tag noerror) ;; We have some sort of lineage we need to consider when we do ;; our side lookup of tags. diff --git a/lisp/cedet/semantic/bovine/c-by.el b/lisp/cedet/semantic/bovine/c-by.el index b47dac49a52..96e12bba900 100644 --- a/lisp/cedet/semantic/bovine/c-by.el +++ b/lisp/cedet/semantic/bovine/c-by.el @@ -19,17 +19,21 @@ ;;; Commentary: ;; -;; This file was generated from etc/grammars/c.by. +;; This file was generated from admin/grammars/c.by. ;;; Code: (require 'semantic/lex) (eval-when-compile (require 'semantic/bovine)) - + +;;; Prologue +;; (declare-function semantic-c-reconstitute-token "semantic/bovine/c") (declare-function semantic-c-reconstitute-template "semantic/bovine/c") (declare-function semantic-expand-c-tag "semantic/bovine/c") - + +;;; Declarations +;; (defconst semantic-c-by--keyword-table (semantic-lex-make-keyword-table '(("extern" . EXTERN) @@ -42,6 +46,7 @@ ("inline" . INLINE) ("virtual" . VIRTUAL) ("mutable" . MUTABLE) + ("explicit" . EXPLICIT) ("struct" . STRUCT) ("union" . UNION) ("enum" . ENUM) @@ -124,6 +129,7 @@ ("enum" summary "Enumeration Type Declaration: enum [name] { ... };") ("union" summary "Union Type Declaration: union [name] { ... };") ("struct" summary "Structure Type Declaration: struct [name] { ... };") + ("explicit" summary "Forbids implicit type conversion: explicit <constructor>") ("mutable" summary "Member Declaration Modifier: mutable <type> <name> ...") ("virtual" summary "Method Modifier: virtual <type> <name>(...) ...") ("inline" summary "Function Modifier: inline <return type> <name>(...) {...};") @@ -486,6 +492,12 @@ ) (template) (using) + (spp-include + ,(semantic-lambda + (semantic-tag + (nth 0 vals) + 'include :inside-ns t)) + ) ( ;;EMPTY ) ) ;; end namespacesubparts @@ -1987,6 +1999,15 @@ "*" (nth 2 vals)))) ) + (open-paren + "(" + symbol + close-paren + ")" + ,(semantic-lambda + (list + (nth 1 vals))) + ) ) ;; end function-pointer (fun-or-proto-end @@ -2186,6 +2207,10 @@ semantic-flex-keywords-obarray semantic-c-by--keyword-table semantic-equivalent-major-modes '(c-mode c++-mode) )) + + +;;; Analyzers +;; ;;; Epilogue ;; diff --git a/lisp/cedet/semantic/bovine/c.el b/lisp/cedet/semantic/bovine/c.el index 886b15d183e..871bcdd6176 100644 --- a/lisp/cedet/semantic/bovine/c.el +++ b/lisp/cedet/semantic/bovine/c.el @@ -27,10 +27,13 @@ (require 'semantic) (require 'semantic/analyze) +(require 'semantic/bovine) (require 'semantic/bovine/gcc) (require 'semantic/idle) (require 'semantic/lex-spp) (require 'semantic/bovine/c-by) +(require 'semantic/db-find) +(require 'hideif) (eval-when-compile (require 'semantic/find)) @@ -103,8 +106,13 @@ NOTE: In process of obsoleting this." '( ("__THROW" . "") ("__const" . "const") ("__restrict" . "") + ("__attribute_pure__" . "") + ("__attribute_malloc__" . "") + ("__nonnull" . "") + ("__wur" . "") ("__declspec" . ((spp-arg-list ("foo") 1 . 2))) ("__attribute__" . ((spp-arg-list ("foo") 1 . 2))) + ("__asm" . ((spp-arg-list ("foo") 1 . 2))) ) "List of symbols to include by default.") @@ -118,7 +126,15 @@ part of the preprocessor map.") (defun semantic-c-reset-preprocessor-symbol-map () "Reset the C preprocessor symbol map based on all input variables." - (when (featurep 'semantic/bovine/c) + (when (and semantic-mode + (featurep 'semantic/bovine/c)) + (remove-hook 'mode-local-init-hook 'semantic-c-reset-preprocessor-symbol-map) + ;; Initialize semantic-lex-spp-macro-symbol-obarray with symbols. + (setq-mode-local c-mode + semantic-lex-spp-macro-symbol-obarray + (semantic-lex-make-spp-table + (append semantic-lex-c-preprocessor-symbol-map-builtin + semantic-lex-c-preprocessor-symbol-map))) (let ((filemap nil) ) (when (and (not semantic-c-in-reset-preprocessor-table) @@ -141,17 +157,17 @@ part of the preprocessor map.") (error (message "Error updating tables for %S" (object-name table))))) (setq filemap (append filemap (oref table lexical-table))) - ) - )))) - - (setq-mode-local c-mode - semantic-lex-spp-macro-symbol-obarray - (semantic-lex-make-spp-table - (append semantic-lex-c-preprocessor-symbol-map-builtin - semantic-lex-c-preprocessor-symbol-map - filemap)) - ) - ))) + ;; Update symbol obarray + (setq-mode-local c-mode + semantic-lex-spp-macro-symbol-obarray + (semantic-lex-make-spp-table + (append semantic-lex-c-preprocessor-symbol-map-builtin + semantic-lex-c-preprocessor-symbol-map + filemap))))))))))) + +;; Make sure the preprocessor symbols are set up when mode-local kicks +;; in. +(add-hook 'mode-local-init-hook 'semantic-c-reset-preprocessor-symbol-map) (defcustom semantic-lex-c-preprocessor-symbol-map nil "Table of C Preprocessor keywords used by the Semantic C lexer. @@ -236,6 +252,7 @@ Return the defined symbol as a special spp lex token." nil (let* ((name (buffer-substring-no-properties (match-beginning 1) (match-end 1))) + (beginning-of-define (match-end 1)) (with-args (save-excursion (goto-char (match-end 0)) (looking-at "("))) @@ -246,7 +263,13 @@ Return the defined symbol as a special spp lex token." (raw-stream (semantic-lex-spp-stream-for-macro (save-excursion (semantic-c-end-of-macro) - (point)))) + ;; HACK - If there's a C comment after + ;; the macro, do not parse it. + (if (looking-back "/\\*.*" beginning-of-define) + (progn + (goto-char (match-beginning 0)) + (1- (point))) + (point))))) ) ;; Only do argument checking if the paren was immediately after @@ -295,8 +318,10 @@ 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)) + (if (fboundp 'c-scan-conditionals) + (goto-char (c-scan-conditionals 1)) + ;; For older Emacsen, but this will set the mark. + (c-forward-conditional 1))) ((looking-at "^\\s-*#\\s-*elif") ;; We need to let the preprocessor analyze this one. (beginning-of-line) @@ -315,34 +340,207 @@ Moves completely over balanced #if blocks." ;; We found an elif. Stop here. (setq done t)))))) +;;; HIDEIF USAGE: +;; NOTE: All hideif using code was contributed by Brian Carlson as +;; copies from hideif plus modifications and additions. +;; Eric then converted things to use hideif functions directly, +;; deleting most of that code, and added the advice. + +;;; SPP SYM EVAL +;; +;; Convert SPP symbols into values usable by hideif. +;; +;; @TODO - can these conversion fcns be a part of semantic-lex-spp.el? +;; -- TRY semantic-lex-spp-one-token-to-txt +(defun semantic-c-convert-spp-value-to-hideif-value (symbol macrovalue) + "Convert an spp macro SYMBOL MACROVALUE, to something that hideif can use. +Take the first interesting thing and convert it." + ;; Just warn for complex macros. + (when (> (length macrovalue) 1) + (semantic-push-parser-warning + (format "Complex macro value (%s) may be improperly evaluated. " + symbol) 0 0)) + + (let* ((lextoken (car macrovalue)) + (key (semantic-lex-token-class lextoken)) + (value (semantic-lex-token-text lextoken))) + (cond + ((eq key 'number) (string-to-number value)) + ((eq key 'symbol) (semantic-c-evaluate-symbol-for-hideif value)) + ((eq key 'string) + (if (string-match "^[0-9]+L?$" value) + ;; If it matches a number expression, then + ;; convert to a number. + (string-to-number value) + value)) + (t (semantic-push-parser-warning + (format "Unknown macro value. Token class = %s value = %s. " key value) + 0 0) + nil) + ))) + +(defun semantic-c-evaluate-symbol-for-hideif (spp-symbol) + "Lookup the symbol SPP-SYMBOL (a string) to something hideif can use. +Pulls out the symbol list, and call `semantic-c-convert-spp-value-to-hideif-value'." + (interactive "sSymbol name: ") + (when (symbolp spp-symbol) (setq spp-symbol (symbol-name spp-symbol))) + + (if (semantic-lex-spp-symbol-p spp-symbol ) + ;; Convert the symbol into a stream of tokens from the macro which we + ;; can then interpret. + (let ((stream (semantic-lex-spp-symbol-stream spp-symbol))) + (cond + ;; Empyt string means defined, so t. + ((null stream) t) + ;; A list means a parsed macro stream. + ((listp stream) + ;; Convert the macro to something we can return. + (semantic-c-convert-spp-value-to-hideif-value spp-symbol stream)) + + ;; Strings might need to be turned into numbers + ((stringp stream) + (if (string-match "^[0-9]+L?$" stream) + ;; If it matches a number expression, then convert to a + ;; number. + (string-to-number stream) + stream)) + + ;; Just return the stream. A user might have just stuck some + ;; value in it directly. + (t stream) + )) + ;; Else, store an error, return nil. + (progn + (semantic-push-parser-warning + (format "SPP Symbol %s not available" spp-symbol) + (point) (point)) + nil))) + +;;; HIDEIF HACK support fcns +;; +;; These fcns can replace the impl of some hideif features. +;; +;; @TODO - Should hideif and semantic-c merge? +;; I picture a grammar just for CPP that expands into +;; a second token stream for the parser. +(defun semantic-c-hideif-lookup (var) + "Replacement for `hif-lookup'. +I think it just gets the value for some CPP variable VAR." + (let ((val (semantic-c-evaluate-symbol-for-hideif + (cond + ((stringp var) var) + ((symbolp var) (symbol-name var)) + (t "Unable to determine var"))))) + (if val + val + ;; Real hideif will return the right undefined symbol. + nil))) + +(defun semantic-c-hideif-defined (var) + "Replacement for `hif-defined'. +I think it just returns t/nil dependent on if VAR has been defined." + (let ((var-symbol-name + (cond + ((symbolp var) (symbol-name var)) + ((stringp var) var) + (t "Not A Symbol")))) + (if (not (semantic-lex-spp-symbol-p var-symbol-name)) + (progn + (semantic-push-parser-warning + (format "Skip %s" (buffer-substring-no-properties + (point-at-bol) (point-at-eol))) + (point-at-bol) (point-at-eol)) + nil) + t))) + +;;; HIDEIF ADVICE +;; +;; Advise hideif functions to use our lexical tables instead. +(defvar semantic-c-takeover-hideif nil + "Non-nil when Semantic is taking over hideif features.") + +;; (defadvice hif-defined (around semantic-c activate) +;; "Is the variable defined?" +;; (if semantic-c-takeover-hideif +;; (setq ad-return-value +;; (semantic-c-hideif-defined (ad-get-arg 0))) +;; ad-do-it)) + +;; (defadvice hif-lookup (around semantic-c activate) +;; "Is the argument defined? Return true or false." +;; (let ((ans nil)) +;; (when semantic-c-takeover-hideif +;; (setq ans (semantic-c-hideif-lookup (ad-get-arg 0)))) +;; (if (null ans) +;; ad-do-it +;; (setq ad-return-value ans)))) + +;;; #if macros +;; +;; Support #if macros by evaluating the values via use of hideif +;; logic. See above for hacks to make this work. (define-lex-regex-analyzer semantic-lex-c-if "Code blocks wrapped up in #if, or #ifdef. Uses known macro tables in SPP to determine what block to skip." - "^\\s-*#\\s-*\\(if\\|ifndef\\|ifdef\\|elif\\)\\s-+\\(!?defined(\\|\\)\\s-*\\(\\(\\sw\\|\\s_\\)+\\)\\(\\s-*)\\)?\\s-*$" + "^\\s-*#\\s-*\\(if\\|elif\\).*$" (semantic-c-do-lex-if)) (defun semantic-c-do-lex-if () + "Handle lexical CPP if statements. +Enables a takeover of some hideif functions, then uses hideif to +evaluate the #if expression and enables us to make decisions on which +code to parse." + ;; Enable our advice, and use hideif to parse. + (let* ((semantic-c-takeover-hideif t) + (hif-ifx-regexp (concat hif-cpp-prefix "\\(elif\\|if\\(n?def\\)?\\)[ \t]+")) + (parsedtokelist + (condition-case nil + ;; This is imperfect, so always assume on error. + (hif-canonicalize) + (error nil)))) + + (let ((eval-form (eval parsedtokelist))) + (if (or (not eval-form) + (and (numberp eval-form) + (equal eval-form 0)));; ifdefline resulted in false + + ;; The if indicates to skip this preprocessor section + (let ((pt nil)) + (semantic-push-parser-warning (format "Skip %s" (buffer-substring-no-properties (point-at-bol) (point-at-eol))) + (point-at-bol) (point-at-eol)) + (beginning-of-line) + (setq pt (point)) + ;; This skips only a section of a conditional. Once that section + ;; is opened, encountering any new #else or related conditional + ;; should be skipped. + (semantic-c-skip-conditional-section) + (setq semantic-lex-end-point (point)) + + ;; @TODO -somewhere around here, we also need to skip + ;; other sections of the conditional. + + nil) + ;; Else, don't ignore it, but do handle the internals. + (end-of-line) + (setq semantic-lex-end-point (point)) + nil)))) + +(define-lex-regex-analyzer semantic-lex-c-ifdef + "Code blocks wrapped up in #ifdef. +Uses known macro tables in SPP to determine what block to skip." + "^\\s-*#\\s-*\\(ifndef\\|ifdef\\)\\s-+\\(\\(\\sw\\|\\s_\\)+\\)$" + (semantic-c-do-lex-ifdef)) + +(defun semantic-c-do-lex-ifdef () "Handle lexical CPP if statements." (let* ((sym (buffer-substring-no-properties - (match-beginning 3) (match-end 3))) - (defstr (buffer-substring-no-properties - (match-beginning 2) (match-end 2))) - (defined (string= defstr "defined(")) - (notdefined (string= defstr "!defined(")) + (match-beginning 2) (match-end 2))) (ift (buffer-substring-no-properties (match-beginning 1) (match-end 1))) - (ifdef (or (string= ift "ifdef") - (and (string= ift "if") defined) - (and (string= ift "elif") defined) - )) - (ifndef (or (string= ift "ifndef") - (and (string= ift "if") notdefined) - (and (string= ift "elif") notdefined) - )) + (ifdef (string= ift "ifdef")) + (ifndef (string= ift "ifndef")) ) - (if (or (and (or (string= ift "if") (string= ift "elif")) - (string= sym "0")) - (and ifdef (not (semantic-lex-spp-symbol-p sym))) + (if (or (and ifdef (not (semantic-lex-spp-symbol-p sym))) (and ifndef (semantic-lex-spp-symbol-p sym))) ;; The if indicates to skip this preprocessor section. (let ((pt nil)) @@ -556,6 +754,7 @@ Use semantic-cpp-lexer for parsing text inside a CPP macro." ;; C preprocessor features semantic-lex-cpp-define semantic-lex-cpp-undef + semantic-lex-c-ifdef semantic-lex-c-if semantic-lex-c-macro-else semantic-lex-c-macrobits @@ -724,6 +923,8 @@ the regular parser." ;; Hack in mode-local (activate-mode-local-bindings) + ;; Setup C parser + (semantic-default-c-setup) ;; 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. @@ -800,51 +1001,18 @@ now. ) ;; Expand an EXTERN C first. (when (eq (semantic-tag-class tag) 'extern) - (let* ((mb (semantic-tag-get-attribute tag :members)) - (ret mb)) - (while mb - (let ((mods (semantic-tag-get-attribute (car mb) :typemodifiers))) - (setq mods (cons "extern" (cons "\"C\"" mods))) - (semantic-tag-put-attribute (car mb) :typemodifiers mods)) - (setq mb (cdr mb))) - (setq return-list ret))) + (setq return-list (semantic-expand-c-extern-C tag)) + ;; The members will be expanded in the next iteration. The + ;; 'extern' tag itself isn't needed anymore. + (setq tag nil)) - ;; Function or variables that have a :type that is some complex - ;; thing, extract it, and replace it with a reference. - ;; - ;; Thus, struct A { int a; } B; - ;; - ;; will create 2 toplevel tags, one is type A, and the other variable B - ;; where the :type of B is just a type tag A that is a prototype, and - ;; the actual struct info of A is its own toplevel tag. + ;; Check if we have a complex type (when (or (semantic-tag-of-class-p tag 'function) (semantic-tag-of-class-p tag 'variable)) - (let* ((basetype (semantic-tag-type tag)) - (typeref nil) - (tname (when (consp basetype) - (semantic-tag-name basetype)))) - ;; Make tname be a string. - (when (consp tname) (setq tname (car (car tname)))) - ;; Is the basetype a full type with a name of its own? - (when (and basetype (semantic-tag-p basetype) - (not (semantic-tag-prototype-p basetype)) - tname - (not (string= tname ""))) - ;; a type tag referencing the type we are extracting. - (setq typeref (semantic-tag-new-type - (semantic-tag-name basetype) - (semantic-tag-type basetype) - nil nil - :prototype t)) - ;; Convert original tag to only have a reference. - (setq tag (semantic-tag-copy tag)) - (semantic-tag-put-attribute tag :type typeref) - ;; Convert basetype to have the location information. - (semantic--tag-copy-properties tag basetype) - (semantic--tag-set-overlay basetype - (semantic-tag-overlay tag)) - ;; Store the base tag as part of the return list. - (setq return-list (cons basetype return-list))))) + (setq tag (semantic-expand-c-complex-type tag)) + ;; Extract new basetag + (setq return-list (car tag)) + (setq tag (cdr tag))) ;; Name of the tag is a list, so expand it. Tag lists occur ;; for variables like this: int var1, var2, var3; @@ -865,13 +1033,63 @@ now. ;; If we didn't have a list, but the return-list is non-empty, ;; that means we still need to take our existing tag, and glom ;; it onto our extracted type. - (if (consp return-list) + (if (and tag (consp return-list)) (setq return-list (cons tag return-list))) ) ;; Default, don't change the tag means returning nil. return-list)) +(defun semantic-expand-c-extern-C (tag) + "Expand TAG containing an 'extern \"C\"' statement. +This will return all members of TAG with 'extern \"C\"' added to +the typemodifiers attribute." + (when (eq (semantic-tag-class tag) 'extern) + (let* ((mb (semantic-tag-get-attribute tag :members)) + (ret mb)) + (while mb + (let ((mods (semantic-tag-get-attribute (car mb) :typemodifiers))) + (setq mods (cons "extern" (cons "\"C\"" mods))) + (semantic-tag-put-attribute (car mb) :typemodifiers mods)) + (setq mb (cdr mb))) + (nreverse ret)))) + +(defun semantic-expand-c-complex-type (tag) + "Check if TAG has a full :type with a name on its own. +If so, extract it, and replace it with a reference to that type. +Thus, 'struct A { int a; } B;' will create 2 toplevel tags, one +is type A, and the other variable B where the :type of B is just +a type tag A that is a prototype, and the actual struct info of A +is its own toplevel tag. This function will return (cons A B)." + (let* ((basetype (semantic-tag-type tag)) + (typeref nil) + (ret nil) + (tname (when (consp basetype) + (semantic-tag-name basetype)))) + ;; Make tname be a string. + (when (consp tname) (setq tname (car (car tname)))) + ;; Is the basetype a full type with a name of its own? + (when (and basetype (semantic-tag-p basetype) + (not (semantic-tag-prototype-p basetype)) + tname + (not (string= tname ""))) + ;; a type tag referencing the type we are extracting. + (setq typeref (semantic-tag-new-type + (semantic-tag-name basetype) + (semantic-tag-type basetype) + nil nil + :prototype t)) + ;; Convert original tag to only have a reference. + (setq tag (semantic-tag-copy tag)) + (semantic-tag-put-attribute tag :type typeref) + ;; Convert basetype to have the location information. + (semantic--tag-copy-properties tag basetype) + (semantic--tag-set-overlay basetype + (semantic-tag-overlay tag)) + ;; Store the base tag as part of the return list. + (setq ret (cons basetype ret))) + (cons ret tag))) + (defun semantic-expand-c-tag-namelist (tag) "Expand TAG whose name is a list into a list of tags, or nil." (cond ((semantic-tag-of-class-p tag 'variable) @@ -1238,6 +1456,22 @@ Override function for `semantic-tag-protection'." 'public nil)))) +(define-mode-local-override semantic-find-tags-included c-mode + (&optional table) + "Find all tags in TABLE that are of the 'include class. +TABLE is a tag table. See `semantic-something-to-tag-table'. +For C++, we also have to search namespaces for include tags." + (let ((tags (semantic-find-tags-by-class 'include table)) + (namespaces (semantic-find-tags-by-type "namespace" table))) + (dolist (cur namespaces) + (setq tags + (append tags + (semantic-find-tags-by-class + 'include + (semantic-tag-get-attribute cur :members))))) + tags)) + + (define-mode-local-override semantic-tag-components c-mode (tag) "Return components for TAG." (if (and (eq (semantic-tag-class tag) 'type) @@ -1342,7 +1576,7 @@ SCOPE is not used, and TYPE-DECLARATION is used only if TYPE is not a typedef." (string= (semantic-tag-type type) "typedef")) (let ((dt (semantic-tag-get-attribute type :typedef))) (cond ((and (semantic-tag-p dt) - (not (semantic-analyze-tag-prototype-p dt))) + (not (semantic-tag-prototype-p dt))) ;; In this case, DT was declared directly. We need ;; to clone DT and apply a filename to it. (let* ((fname (semantic-tag-file-name type)) @@ -1656,6 +1890,58 @@ For types with a :parent, create faux namespaces to put TAG into." ;; Else, return tag unmodified. tag))) +(define-mode-local-override semanticdb-find-table-for-include c-mode + (includetag &optional table) + "For a single INCLUDETAG found in TABLE, find a `semanticdb-table' object +INCLUDETAG is a semantic TAG of class 'include. +TABLE is a semanticdb table that identifies where INCLUDETAG came from. +TABLE is optional if INCLUDETAG has an overlay of :filename attribute. + +For C++, we also have to check if the include is inside a +namespace, since this means all tags inside this include will +have to be wrapped in that namespace." + (let ((inctable (semanticdb-find-table-for-include-default includetag table)) + (inside-ns (semantic-tag-get-attribute includetag :inside-ns)) + tags newtags namespaces prefix parenttable newtable) + (if (or (null inside-ns) + (not inctable) + (not (slot-boundp inctable 'tags))) + inctable + (when (and (eq inside-ns t) + ;; Get the table which has this include. + (setq parenttable + (semanticdb-find-table-for-include-default + (semantic-tag-new-include + (semantic--tag-get-property includetag :filename) nil))) + table) + ;; Find the namespace where this include is located. + (setq namespaces + (semantic-find-tags-by-type "namespace" parenttable)) + (when (and namespaces + (slot-boundp inctable 'tags)) + (dolist (cur namespaces) + (when (semantic-find-tags-by-name + (semantic-tag-name includetag) + (semantic-tag-get-attribute cur :members)) + (setq inside-ns (semantic-tag-name cur)) + ;; Cache the namespace value. + (semantic-tag-put-attribute includetag :inside-ns inside-ns))))) + (unless (semantic-find-tags-by-name + inside-ns + (semantic-find-tags-by-type "namespace" inctable)) + (setq tags (oref inctable tags)) + ;; Wrap tags inside namespace tag + (setq newtags + (list (semantic-tag-new-type inside-ns "namespace" tags nil))) + ;; Create new semantic-table for the wrapped tags, since we don't want + ;; the namespace to actually be a part of the header file. + (setq newtable (semanticdb-table "include with context")) + (oset newtable tags newtags) + (oset newtable parent-db (oref inctable parent-db)) + (oset newtable file (oref inctable file))) + newtable))) + + (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)) @@ -1693,6 +1979,52 @@ For types with a :parent, create faux namespaces to put TAG into." txt) (semantic-idle-summary-current-symbol-info-default)))) +(define-mode-local-override semantic--tag-similar-names-p c-mode (tag1 tag2 blankok) + "Compare the names of TAG1 and TAG2. +If BLANKOK is false, then the names must exactly match. +If BLANKOK is true, then always return t, as for C, the names don't matter +for arguments compared." + (if blankok t (semantic--tag-similar-names-p-default tag1 tag2 nil))) + +(define-mode-local-override semantic--tag-similar-types-p c-mode (tag1 tag2) + "For c-mode, deal with TAG1 and TAG2 being used in different namespaces. +In this case, one type will be shorter than the other. Instead +of fully resolving all namespaces currently in scope for both +types, we simply compare as many elements as the shorter type +provides." + ;; First, we see if the default method fails + (if (semantic--tag-similar-types-p-default tag1 tag2) + t + (let* ((names + (mapcar + (lambda (tag) + (let ((type (semantic-tag-type tag))) + (unless (stringp type) + (setq type (semantic-tag-name type))) + (setq type (semantic-analyze-split-name type)) + (when (stringp type) + (setq type (list type))) + type)) + (list tag1 tag2))) + (len1 (length (car names))) + (len2 (length (cadr names)))) + (cond + ((<= len1 len2) + (equal (nthcdr len1 (cadr names)) (car names))) + ((< len2 len1) + (equal (nthcdr len2 (car names)) (cadr names))))))) + + +(define-mode-local-override semantic--tag-attribute-similar-p c-mode + (attr value1 value2 ignorable-attributes) + "For c-mode, allow function :arguments to ignore the :name attributes." + (cond ((eq attr :arguments) + (semantic--tag-attribute-similar-p-default attr value1 value2 + (cons :name ignorable-attributes))) + (t + (semantic--tag-attribute-similar-p-default attr value1 value2 + ignorable-attributes)))) + (defvar-mode-local c-mode semantic-orphaned-member-metaparent-type "struct" "When lost members are found in the class hierarchy generator, use a struct.") @@ -1725,6 +2057,12 @@ For types with a :parent, create faux namespaces to put TAG into." (defvar-mode-local c-mode senator-step-at-tag-classes '(function variable) "Tag classes where senator will stop at the end.") +(defvar-mode-local c-mode semantic-tag-similar-ignorable-attributes + '(:prototype-flag :parent :typemodifiers) + "Tag attributes to ignore during similarity tests. +:parent is here because some tags might specify a parent, while others are +actually in their parent which is not accessible.") + ;;;###autoload (defun semantic-default-c-setup () "Set up a buffer for semantic parsing of the C language." @@ -1736,6 +2074,8 @@ For types with a :parent, create faux namespaces to put TAG into." (setq semantic-lex-analyzer #'semantic-c-lexer) (add-hook 'semantic-lex-reset-hooks 'semantic-lex-spp-reset-hook nil t) + (when (eq major-mode 'c++-mode) + (add-to-list 'semantic-lex-c-preprocessor-symbol-map '("__cplusplus" . ""))) ) ;;;###autoload @@ -1759,7 +2099,7 @@ For types with a :parent, create faux namespaces to put TAG into." (defun semantic-c-describe-environment () "Describe the Semantic features of the current C environment." (interactive) - (if (not (or (eq major-mode 'c-mode) (eq major-mode 'c++-mode))) + (if (not (member 'c-mode (mode-local-equivalent-mode-p major-mode))) (error "Not useful to query C mode in %s mode" major-mode)) (let ((gcc (when (boundp 'semantic-gcc-setup-data) semantic-gcc-setup-data)) @@ -1780,13 +2120,20 @@ For types with a :parent, create faux namespaces to put TAG into." (princ "\n\nInclude Path Summary:\n") (when (and (boundp 'ede-object) ede-object) (princ "\n This file's project include is handled by:\n") - (princ " ") - (princ (object-print ede-object)) - (princ "\n with the system path:\n") - (dolist (dir (ede-system-include-path ede-object)) - (princ " ") - (princ dir) - (princ "\n")) + (let ((objs (if (listp ede-object) + ede-object + (list ede-object)))) + (dolist (O objs) + (princ " EDE : ") + (princ (object-print O)) + (let ((ipath (ede-system-include-path O))) + (if (not ipath) + (princ "\n with NO specified system include path.\n") + (princ "\n with the system path:\n") + (dolist (dir ipath) + (princ " ") + (princ dir) + (princ "\n")))))) ) (when semantic-dependency-include-path diff --git a/lisp/cedet/semantic/bovine/el.el b/lisp/cedet/semantic/bovine/el.el index 818b8b581a4..7bad1483dc3 100644 --- a/lisp/cedet/semantic/bovine/el.el +++ b/lisp/cedet/semantic/bovine/el.el @@ -944,8 +944,6 @@ ELisp variables can be pretty long, so track this one too.") "Setup hook function for Emacs Lisp files and Semantic." ) -(add-hook 'emacs-lisp-mode-hook 'semantic-default-elisp-setup) - ;;; LISP MODE ;; ;; @TODO: Lisp supports syntaxes that Emacs Lisp does not. @@ -956,7 +954,7 @@ ELisp variables can be pretty long, so track this one too.") ;; (add-hook 'lisp-mode-hook 'semantic-default-elisp-setup) -(eval-after-load "semanticdb" +(eval-after-load "semantic/db" '(require 'semantic/db-el) ) diff --git a/lisp/cedet/semantic/bovine/gcc.el b/lisp/cedet/semantic/bovine/gcc.el index 8b47ae14eee..842ef0914fd 100644 --- a/lisp/cedet/semantic/bovine/gcc.el +++ b/lisp/cedet/semantic/bovine/gcc.el @@ -33,30 +33,32 @@ ;;; Code: (defun semantic-gcc-query (gcc-cmd &rest gcc-options) - "Return program output to both standard output and standard error. + "Return program output or error code in case error happens. GCC-CMD is the program to execute and GCC-OPTIONS are the options to give to the program." ;; $ gcc -v ;; - (let ((buff (get-buffer-create " *gcc-query*")) - (old-lc-messages (getenv "LC_ALL"))) + (let* ((buff (get-buffer-create " *gcc-query*")) + (old-lc-messages (getenv "LC_ALL")) + (options `(,nil ,(cons buff t) ,nil ,@gcc-options)) + (err 0)) (with-current-buffer buff (erase-buffer) (setenv "LC_ALL" "C") (condition-case nil - (apply 'call-process gcc-cmd nil (cons buff t) nil gcc-options) + (setq err (apply 'call-process gcc-cmd options)) (error ;; Some bogus directory for the first time perhaps? (let ((default-directory (expand-file-name "~/"))) (condition-case nil - (apply 'call-process gcc-cmd nil (cons buff t) nil gcc-options) + (setq err (apply 'call-process gcc-cmd options)) (error ;; gcc doesn't exist??? nil))))) (setenv "LC_ALL" old-lc-messages) (prog1 - (buffer-string) - (kill-buffer buff) - ) - ))) + (if (zerop err) + (buffer-string) + err) + (kill-buffer buff))))) ;;(semantic-gcc-get-include-paths "c") ;;(semantic-gcc-get-include-paths "c++") @@ -148,7 +150,14 @@ It should also include other symbols GCC was compiled with.") (interactive) (let* ((fields (or semantic-gcc-setup-data (semantic-gcc-fields (semantic-gcc-query "gcc" "-v")))) - (defines (semantic-cpp-defs (semantic-gcc-query "cpp" "-E" "-dM" "-x" "c++" null-device))) + (cpp-options `("-E" "-dM" "-x" "c++" ,null-device)) + (query (let ((q (apply 'semantic-gcc-query "cpp" cpp-options))) + (if (stringp q) + q + ;; `cpp' command in `semantic-gcc-setup' doesn't work on + ;; Mac, try `gcc'. + (apply 'semantic-gcc-query "gcc" cpp-options)))) + (defines (semantic-cpp-defs query)) (ver (cdr (assoc 'version fields))) (host (or (cdr (assoc 'target fields)) (cdr (assoc '--target fields)) @@ -156,13 +165,14 @@ It should also include other symbols GCC was compiled with.") (prefix (cdr (assoc '--prefix fields))) ;; gcc output supplied paths (c-include-path (semantic-gcc-get-include-paths "c")) - (c++-include-path (semantic-gcc-get-include-paths "c++"))) + (c++-include-path (semantic-gcc-get-include-paths "c++")) + (gcc-exe (locate-file "gcc" exec-path exec-suffixes 'executable)) + ) ;; Remember so we don't have to call GCC twice. (setq semantic-gcc-setup-data fields) - (unless c-include-path + (when (and (not c-include-path) gcc-exe) ;; Fallback to guesses (let* ( ;; gcc include dirs - (gcc-exe (locate-file "gcc" exec-path exec-suffixes 'executable)) (gcc-root (expand-file-name ".." (file-name-directory gcc-exe))) (gcc-include (expand-file-name "include" gcc-root)) (gcc-include-c++ (expand-file-name "c++" gcc-include)) @@ -196,20 +206,24 @@ It should also include other symbols GCC was compiled with.") (semantic-add-system-include D 'c-mode)) (dolist (D (semantic-gcc-get-include-paths "c++")) (semantic-add-system-include D 'c++-mode) - (let ((cppconfig (concat D "/bits/c++config.h"))) - ;; Presumably there will be only one of these files in the try-paths list... - (when (file-readable-p cppconfig) + (let ((cppconfig (list (concat D "/bits/c++config.h") (concat D "/sys/cdefs.h")))) + (dolist (cur cppconfig) + ;; Presumably there will be only one of these files in the try-paths list... + (when (file-readable-p cur) ;; Add it to the symbol file (if (boundp 'semantic-lex-c-preprocessor-symbol-file) ;; Add to the core macro header list - (add-to-list 'semantic-lex-c-preprocessor-symbol-file cppconfig) + (add-to-list 'semantic-lex-c-preprocessor-symbol-file cur) ;; Setup the core macro header - (setq semantic-lex-c-preprocessor-symbol-file (list cppconfig))) - ))) + (setq semantic-lex-c-preprocessor-symbol-file (list cur))) + )))) (if (not (boundp 'semantic-lex-c-preprocessor-symbol-map)) (setq semantic-lex-c-preprocessor-symbol-map nil)) (dolist (D defines) (add-to-list 'semantic-lex-c-preprocessor-symbol-map D)) + ;; Needed for parsing OS X libc + (when (eq system-type 'darwin) + (add-to-list 'semantic-lex-c-preprocessor-symbol-map '("__i386__" . ""))) (when (featurep 'semantic/bovine/c) (semantic-c-reset-preprocessor-symbol-map)) nil)) diff --git a/lisp/cedet/semantic/bovine/make-by.el b/lisp/cedet/semantic/bovine/make-by.el index ac38d1707c3..59738188bbe 100644 --- a/lisp/cedet/semantic/bovine/make-by.el +++ b/lisp/cedet/semantic/bovine/make-by.el @@ -19,13 +19,12 @@ ;;; Commentary: ;; -;; This file was generated from etc/grammars/make.by. +;; This file was generated from admin/grammars/make.by. ;;; Code: (require 'semantic/lex) (eval-when-compile (require 'semantic/bovine)) - ;;; Prologue ;; @@ -380,6 +379,13 @@ semantic-flex-keywords-obarray semantic-make-by--keyword-table )) + +;;; Analyzers +;; + +;;; Epilogue +;; + (provide 'semantic/bovine/make-by) ;;; semantic/bovine/make-by.el ends here diff --git a/lisp/cedet/semantic/bovine/make.el b/lisp/cedet/semantic/bovine/make.el index 4098b2c0374..041e1f11902 100644 --- a/lisp/cedet/semantic/bovine/make.el +++ b/lisp/cedet/semantic/bovine/make.el @@ -27,6 +27,7 @@ (require 'make-mode) (require 'semantic) +(require 'semantic/bovine) (require 'semantic/bovine/make-by) (require 'semantic/analyze) (require 'semantic/dep) diff --git a/lisp/cedet/semantic/bovine/scm-by.el b/lisp/cedet/semantic/bovine/scm-by.el index d580a5fb22e..476945fa8a3 100644 --- a/lisp/cedet/semantic/bovine/scm-by.el +++ b/lisp/cedet/semantic/bovine/scm-by.el @@ -1,4 +1,4 @@ -;;; semantic-scm-by.el --- Generated parser support file +;;; semantic/bovine/scm-by.el --- Generated parser support file ;; Copyright (C) 2001, 2003, 2009-2012 Free Software Foundation, Inc. @@ -19,12 +19,11 @@ ;;; Commentary: ;; -;; This file was generated from etc/grammars/scm.by. +;; This file was generated from admin/grammars/scm.by. ;;; Code: (require 'semantic/lex) - (eval-when-compile (require 'semantic/bovine)) ;;; Prologue @@ -185,6 +184,13 @@ semantic-flex-keywords-obarray semantic-scm-by--keyword-table )) + +;;; Analyzers +;; + +;;; Epilogue +;; + (provide 'semantic/bovine/scm-by) ;;; semantic/bovine/scm-by.el ends here diff --git a/lisp/cedet/semantic/bovine/scm.el b/lisp/cedet/semantic/bovine/scm.el index 5c4e2ae6d60..cf2b1f0e212 100644 --- a/lisp/cedet/semantic/bovine/scm.el +++ b/lisp/cedet/semantic/bovine/scm.el @@ -24,6 +24,7 @@ ;; Use the Semantic Bovinator for Scheme (guile) (require 'semantic) +(require 'semantic/bovine) (require 'semantic/bovine/scm-by) (require 'semantic/format) (require 'semantic/dep) @@ -37,7 +38,7 @@ This should probably do some sort of search to see what is actually on the local machine.") -(define-mode-local-override semantic-format-tag-prototype scheme-mode (tag) +(define-mode-local-override semantic-format-tag-prototype scheme-mode (tag &optional parent color) "Return a prototype for the Emacs Lisp nonterminal TAG." (let* ((tok (semantic-tag-class tag)) (args (semantic-tag-components tag)) @@ -46,7 +47,7 @@ actually on the local machine.") (concat (semantic-tag-name tag) " (" (mapconcat (lambda (a) a) args " ") ")") - (semantic-format-tag-prototype-default tag)))) + (semantic-format-tag-prototype-default tag parent color)))) (define-mode-local-override semantic-documentation-for-tag scheme-mode (tag &optional nosnarf) "Return the documentation string for TAG. diff --git a/lisp/cedet/semantic/complete.el b/lisp/cedet/semantic/complete.el index 18d4052eb43..f666491d667 100644 --- a/lisp/cedet/semantic/complete.el +++ b/lisp/cedet/semantic/complete.el @@ -113,6 +113,7 @@ (require 'semantic/ctxt) (require 'semantic/decorate) (require 'semantic/format) +(require 'semantic/idle) (eval-when-compile ;; For the semantic-find-tags-for-completion macro. @@ -685,7 +686,7 @@ a reasonable distance." (cond ;; EXIT when we are no longer in a good place. ((or (not (eq b (current-buffer))) - (< (point) s) + (<= (point) s) (> (point) e)) ;;(message "Exit: %S %S %S" s e (point)) (semantic-complete-inline-exit) @@ -904,13 +905,44 @@ a completion displayor object, and tracking the current progress of a completion." :abstract t) +;;; Smart completion collector +(defclass semantic-collector-analyze-completions (semantic-collector-abstract) + ((context :initarg :context + :type semantic-analyze-context + :documentation "An analysis context. +Specifies some context location from whence completion lists will be drawn." + ) + (first-pass-completions :type list + :documentation "List of valid completion tags. +This list of tags is generated when completion starts. All searches +derive from this list.") + ) + "Completion engine that uses the context analyzer to provide options. +The only options available for completion are those which can be logically +inserted into the current context.") + +(defmethod semantic-collector-calculate-completions-raw + ((obj semantic-collector-analyze-completions) prefix completionlist) + "calculate the completions for prefix from completionlist." + ;; if there are no completions yet, calculate them. + (if (not (slot-boundp obj 'first-pass-completions)) + (oset obj first-pass-completions + (semantic-analyze-possible-completions (oref obj context)))) + ;; search our cached completion list. make it look like a semanticdb + ;; results type. + (list (cons (with-current-buffer (oref (oref obj context) buffer) + semanticdb-current-table) + (semantic-find-tags-for-completion + prefix + (oref obj first-pass-completions))))) + (defmethod semantic-collector-cleanup ((obj semantic-collector-abstract)) "Clean up any mess this collector may have." nil) (defmethod semantic-collector-next-action ((obj semantic-collector-abstract) partial) - "What should we do next? OBJ can predict a next good action. + "What should we do next? OBJ can be used to determine the next action. PARTIAL indicates if we are doing a partial completion." (if (and (slot-boundp obj 'last-completion) (string= (semantic-completion-text) (oref obj last-completion))) @@ -966,21 +998,38 @@ Output must be in semanticdb Find result format." "Calculate completions for prefix as setup for other queries." (let* ((case-fold-search semantic-case-fold) (same-prefix-p (semantic-collector-last-prefix= obj prefix)) + (last-prefix (and (slot-boundp obj 'last-prefix) + (oref obj last-prefix))) (completionlist - (if (or same-prefix-p - (and (slot-boundp obj 'last-prefix) - (eq (compare-strings (oref obj last-prefix) 0 nil - prefix 0 (length prefix)) - t))) - ;; New prefix is subset of old prefix - (oref obj last-all-completions) - (semantic-collector-get-cache obj))) + (cond ((or same-prefix-p + (and last-prefix (eq (compare-strings + last-prefix 0 nil + prefix 0 (length last-prefix)) t))) + ;; We have the same prefix, or last-prefix is a + ;; substring of the of new prefix, in which case we are + ;; refining our symbol so just re-use cache. + (oref obj last-all-completions)) + ((and last-prefix + (> (length prefix) 1) + (eq (compare-strings + prefix 0 nil + last-prefix 0 (length prefix)) t)) + ;; The new prefix is a substring of the old + ;; prefix, and it's longer than one character. + ;; Perform a full search to pull in additional + ;; matches. + (let ((context (semantic-analyze-current-context (point)))) + ;; Set new context and make first-pass-completions + ;; unbound so that they are newly calculated. + (oset obj context context) + (when (slot-boundp obj 'first-pass-completions) + (slot-makeunbound obj 'first-pass-completions))) + nil))) ;; Get the result (answer (if same-prefix-p completionlist (semantic-collector-calculate-completions-raw - obj prefix completionlist)) - ) + obj prefix completionlist))) (completion nil) (complete-not-uniq nil) ) @@ -1153,7 +1202,7 @@ NEWCACHE is the new tag table, but we ignore it." (semantic-collector-buffer-abstract) () "Completion engine for tags in the current buffer. -When searching for a tag, uses semantic deep searche functions. +When searching for a tag, uses semantic deep search functions. Basics search only in the current buffer.") (defmethod semantic-collector-calculate-cache @@ -1225,37 +1274,6 @@ Uses semanticdb for searching all tags in the current project." (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 - :documentation "An analysis context. -Specifies some context location from whence completion lists will be drawn." - ) - (first-pass-completions :type list - :documentation "List of valid completion tags. -This list of tags is generated when completion starts. All searches -derive from this list.") - ) - "Completion engine that uses the context analyzer to provide options. -The only options available for completion are those which can be logically -inserted into the current context.") - -(defmethod semantic-collector-calculate-completions-raw - ((obj semantic-collector-analyze-completions) prefix completionlist) - "calculate the completions for prefix from completionlist." - ;; if there are no completions yet, calculate them. - (if (not (slot-boundp obj 'first-pass-completions)) - (oset obj first-pass-completions - (semantic-analyze-possible-completions (oref obj context)))) - ;; search our cached completion list. make it look like a semanticdb - ;; results type. - (list (cons (with-current-buffer (oref (oref obj context) buffer) - semanticdb-current-table) - (semantic-find-tags-for-completion - prefix - (oref obj first-pass-completions))))) - ;;; ------------------------------------------------------------ ;;; Tag List Display Engines @@ -1300,8 +1318,9 @@ a collector, and tracking tables of completion to display." (defmethod semantic-displayor-next-action ((obj semantic-displayor-abstract)) "The next action to take on the minibuffer related to display." (if (and (slot-boundp obj 'last-prefix) - (string= (oref obj last-prefix) (semantic-completion-text)) - (eq last-command this-command)) + (or (eq this-command 'semantic-complete-inline-TAB) + (and (string= (oref obj last-prefix) (semantic-completion-text)) + (eq last-command this-command)))) 'scroll 'display)) @@ -1477,7 +1496,7 @@ one in the source buffer." (nt (semanticdb-normalize-one-tag rtable rtag)) (tag (cdr nt)) (table (car nt)) - ) + (curwin (selected-window))) ;; If we fail to normalize, reset. (when (not tag) (setq table rtable tag rtag)) ;; Do the focus. @@ -1502,17 +1521,14 @@ one in the source buffer." (switch-to-buffer-other-window buf t) (select-window (get-buffer-window buf))) ;; Now do some positioning - (unwind-protect - (if (semantic-tag-with-position-p tag) - ;; Full tag positional information available - (progn - (goto-char (semantic-tag-start tag)) - ;; This avoids a dangerous problem if we just loaded a tag - ;; from a file, but the original position was not updated - ;; in the TAG variable we are currently using. - (semantic-momentary-highlight-tag (semantic-current-tag)) - )) - (select-window (minibuffer-window))) + (when (semantic-tag-with-position-p tag) + ;; Full tag positional information available + (goto-char (semantic-tag-start tag)) + ;; This avoids a dangerous problem if we just loaded a tag + ;; from a file, but the original position was not updated + ;; in the TAG variable we are currently using. + (semantic-momentary-highlight-tag (semantic-current-tag))) + (select-window curwin) ;; Calculate text difference between contents and the focus item. (let* ((mbc (semantic-completion-text)) (ftn (semantic-tag-name tag)) @@ -1530,32 +1546,64 @@ one in the source buffer." ;; * Safe compatibility for tooltip free systems. ;; * Don't use 'avoid package for tooltip positioning. +;;;###autoload +(defcustom semantic-displayor-tooltip-mode 'standard + "Mode for the tooltip inline completion. + +Standard: Show only `semantic-displayor-tooltip-initial-max-tags' +number of completions initially. Pressing TAB will show the +extended set. + +Quiet: Only show completions when we have narrowed all +posibilities down to a maximum of +`semantic-displayor-tooltip-initial-max-tags' tags. Pressing TAB +multiple times will also show completions. + +Verbose: Always show all completions available. + +The absolute maximum number of completions for all mode is +determined through `semantic-displayor-tooltip-max-tags'." + :group 'semantic + :type '(choice (const :tag "Standard" standard) + (const :tag "Quiet" quiet) + (const :tag "Verbose" verbose))) + +;;;###autoload +(defcustom semantic-displayor-tooltip-initial-max-tags 5 + "Maximum number of tags to be displayed initially. +See doc-string of `semantic-displayor-tooltip-mode' for details." + :group 'semantic + :type 'integer) + +(defcustom semantic-displayor-tooltip-max-tags 25 + "The maximum number of tags to be displayed. +Maximum number of completions where we have activated the +extended completion list through typing TAB or SPACE multiple +times. This limit needs to fit on your screen! + +Note: If available, customizing this variable increases +'x-max-tooltip-size' to force over-sized tooltips when necessary. +This will not happen if you directly set this variable via +`setq'." + :group 'semantic + :type 'integer + :set '(lambda (sym var) + (set-default sym var) + (when (boundp 'x-max-tooltip-size) + (setcdr x-max-tooltip-size (max (1+ var) (cdr x-max-tooltip-size)))))) + + (defclass semantic-displayor-tooltip (semantic-displayor-traditional) - ((max-tags :type integer - :initarg :max-tags - :initform 5 - :custom integer - :documentation - "Max number of tags displayed on tooltip at once. -If `force-show' is 1, this value is ignored with typing tab or space twice continuously. -if `force-show' is 0, this value is always ignored.") - (force-show :type integer - :initarg :force-show - :initform 1 - :custom (choice (const - :tag "Show when double typing" - 1) - (const - :tag "Show always" - 0) - (const - :tag "Show if the number of tags is less than `max-tags'." - -1)) - :documentation - "Control the behavior of the number of tags is greater than `max-tags'. --1 means tags are never shown. -0 means the tags are always shown. -1 means tags are shown if space or tab is typed twice continuously.") + ((mode :initarg :mode + :initform + (symbol-value 'semantic-displayor-tooltip-mode) + :documentation + "See `semantic-displayor-tooltip-mode'.") + (max-tags-initial :initarg max-tags-initial + :initform + (symbol-value 'semantic-displayor-tooltip-initial-max-tags) + :documentation + "See `semantic-displayor-tooltip-initial-max-tags'.") (typing-count :type integer :initform 0 :documentation @@ -1563,7 +1611,7 @@ if `force-show' is 0, this value is always ignored.") (shown :type boolean :initform nil :documentation - "Flag representing whether tags is shown once or not.") + "Flag representing whether tooltip has been shown yet.") ) "Display completions options in a tooltip. Display mechanism using tooltip for a list of possible completions.") @@ -1583,50 +1631,63 @@ Display mechanism using tooltip for a list of possible completions.") (call-next-method) (let* ((tablelong (semanticdb-strip-find-results (oref obj table))) (table (semantic-unique-tag-table-by-name tablelong)) - (l (mapcar semantic-completion-displayor-format-tag-function table)) - (ll (length l)) + (completions (mapcar semantic-completion-displayor-format-tag-function table)) + (numcompl (length completions)) (typing-count (oref obj typing-count)) - (force-show (oref obj force-show)) + (mode (oref obj mode)) + (max-tags (oref obj max-tags-initial)) (matchtxt (semantic-completion-text)) - msg) - (if (or (oref obj shown) - (< ll (oref obj max-tags)) - (and (<= 0 force-show) - (< (1- force-show) typing-count))) - (progn - (oset obj typing-count 0) - (oset obj shown t) - (if (eq 1 ll) - ;; We Have only one possible match. There could be two cases. - ;; 1) input text != single match. - ;; --> Show it! - ;; 2) input text == single match. - ;; --> Complain about it, but still show the match. - (if (string= matchtxt (semantic-tag-name (car table))) - (setq msg (concat "[COMPLETE]\n" (car l))) - (setq msg (car l))) - ;; Create the long message. - (setq msg (mapconcat 'identity l "\n")) - ;; If there is nothing, say so! - (if (eq 0 (length msg)) - (setq msg "[NO MATCH]"))) - (semantic-displayor-tooltip-show msg)) - ;; The typing count determines if the user REALLY REALLY - ;; wanted to show that much stuff. Only increment - ;; if the current command is a completion command. - (if (and (stringp (this-command-keys)) - (string= (this-command-keys) "\C-i")) - (oset obj typing-count (1+ typing-count))) - ;; At this point, we know we have too many items. - ;; Let's be brave, and truncate l - (setcdr (nthcdr (oref obj max-tags) l) nil) - (setq msg (mapconcat 'identity l "\n")) + msg msg-tail) + ;; Keep a count of the consecutive completion commands entered by the user. + (if (and (stringp (this-command-keys)) + (string= (this-command-keys) "\C-i")) + (oset obj typing-count (1+ (oref obj typing-count))) + (oset obj typing-count 0)) + (cond + ((eq mode 'quiet) + ;; Switch back to standard mode if user presses key more than 5 times. + (when (>= (oref obj typing-count) 5) + (oset obj mode 'standard) + (setq mode 'standard) + (message "Resetting inline-mode to 'standard'.")) + (when (and (> numcompl max-tags) + (< (oref obj typing-count) 2)) + ;; Discretely hint at completion availability. + (setq msg "..."))) + ((eq mode 'verbose) + ;; Always show extended match set. + (oset obj max-tags semantic-displayor-tooltip-max-tags) + (setq max-tags semantic-displayor-tooltip-max-tags))) + (unless msg + (oset obj shown t) (cond - ((= force-show -1) - (semantic-displayor-tooltip-show (concat msg "\n..."))) - ((= force-show 1) - (semantic-displayor-tooltip-show (concat msg "\n(TAB for more)"))) - ))))) + ((> numcompl max-tags) + ;; We have too many items, be brave and truncate 'completions'. + (setcdr (nthcdr (1- max-tags) completions) nil) + (if (= max-tags semantic-displayor-tooltip-initial-max-tags) + (setq msg-tail (concat "\n[<TAB> " (number-to-string (- numcompl max-tags)) " more]")) + (setq msg-tail (concat "\n[<n/a> " (number-to-string (- numcompl max-tags)) " more]")) + (when (>= (oref obj typing-count) 2) + (message "Refine search to display results beyond the '%s' limit" + (symbol-name 'semantic-complete-inline-max-tags-extended))))) + ((= numcompl 1) + ;; two possible cases + ;; 1. input text != single match - we found a unique completion! + ;; 2. input text == single match - we found no additional matches, it's just the input text! + (when (string= matchtxt (semantic-tag-name (car table))) + (setq msg "[COMPLETE]\n"))) + ((zerop numcompl) + (oset obj shown nil) + ;; No matches, say so if in verbose mode! + (when semantic-idle-scheduler-verbose-flag + (setq msg "[NO MATCH]")))) + ;; Create the tooltip text. + (setq msg (concat msg (mapconcat 'identity completions "\n")))) + ;; Add any tail info. + (setq msg (concat msg msg-tail)) + ;; Display tooltip. + (when (not (eq msg "")) + (semantic-displayor-tooltip-show msg))))) ;;; Compatibility ;; @@ -1644,8 +1705,10 @@ Display mechanism using tooltip for a list of possible completions.") "Return the location of POINT as positioned on the selected frame. Return a cons cell (X . Y)" (let* ((frame (selected-frame)) - (left (frame-parameter frame 'left)) - (top (frame-parameter frame 'top)) + (left (or (car-safe (cdr-safe (frame-parameter frame 'left))) + (frame-parameter frame 'left))) + (top (or (car-safe (cdr-safe (frame-parameter frame 'top))) + (frame-parameter frame 'top))) (point-pix-pos (posn-x-y (posn-at-point))) (edges (window-inside-pixel-edges (selected-window)))) (cons (+ (car point-pix-pos) (car edges) left) @@ -1668,7 +1731,7 @@ Return a cons cell (X . Y)" (defmethod semantic-displayor-scroll-request ((obj semantic-displayor-tooltip)) "A request to for the displayor to scroll the completion list (if needed)." ;; Do scrolling in the tooltip. - (oset obj max-tags 30) + (oset obj max-tags-initial 30) (semantic-displayor-show-request obj) ) @@ -2151,6 +2214,23 @@ use `semantic-complete-analyze-inline' to complete." (error nil)) )) +;;;;###autoload +(defun semantic-complete-inline-project () + "Perform inline completion for any symbol in the current project. +`semantic-analyze-possible-completions' is used to determine the +possible values. +The function returns immediately, leaving the buffer in a mode that +will perform the completion." + (interactive) + ;; Only do this if we are not already completing something. + (if (not (semantic-completion-inline-active-p)) + (semantic-complete-inline-tag-project)) + ;; Report a message if things didn't startup. + (if (and (called-interactively-p 'interactive) + (not (semantic-completion-inline-active-p))) + (message "Inline completion not needed.")) + ) + (provide 'semantic/complete) ;; Local variables: @@ -2159,3 +2239,4 @@ use `semantic-complete-analyze-inline' to complete." ;; End: ;;; semantic/complete.el ends here + diff --git a/lisp/cedet/semantic/db-el.el b/lisp/cedet/semantic/db-el.el index 23410b1eb1b..281479045ea 100644 --- a/lisp/cedet/semantic/db-el.el +++ b/lisp/cedet/semantic/db-el.el @@ -39,6 +39,7 @@ (require 'eieio-base)) (declare-function semantic-elisp-desymbolify "semantic/bovine/el") +(declare-function semantic-tag-similar-p "semantic/tag-ls") ;;; Code: @@ -57,6 +58,11 @@ It does not need refreshing." "Return nil, we never need a refresh." nil) +(defmethod object-print ((obj semanticdb-table-emacs-lisp) &rest strings) + "Pretty printer extension for `semanticdb-table-emacs-lisp'. +Adds the number of tags in this file to the object print name." + (apply 'call-next-method obj (cons " (proxy)" strings))) + (defclass semanticdb-project-database-emacs-lisp (semanticdb-project-database eieio-singleton) ((new-table-class :initform semanticdb-table-emacs-lisp @@ -66,6 +72,15 @@ It does not need refreshing." ) "Database representing Emacs core.") +(defmethod object-print ((obj semanticdb-project-database-emacs-lisp) &rest strings) + "Pretty printer extension for `semanticdb-table-emacs-lisp'. +Adds the number of tags in this file to the object print name." + (let ((count 0)) + (mapatoms (lambda (sym) (setq count (1+ count)))) + (apply 'call-next-method obj (cons + (format " (%d known syms)" count) + strings)))) + ;; Create the database, and add it to searchable databases for Emacs Lisp mode. (defvar-mode-local emacs-lisp-mode semanticdb-project-system-databases (list @@ -159,9 +174,9 @@ If Emacs cannot resolve this symbol to a particular file, then return nil." (setq file (concat file ".gz")))) (let* ((tab (semanticdb-file-table-object file)) - (alltags (semanticdb-get-tags tab)) - (newtags (semanticdb-find-tags-by-name-method - tab (semantic-tag-name tag))) + (alltags (when tab (semanticdb-get-tags tab))) + (newtags (when tab (semanticdb-find-tags-by-name-method + tab (semantic-tag-name tag)))) (match nil)) ;; Find the best match. (dolist (T newtags) @@ -171,32 +186,12 @@ If Emacs cannot resolve this symbol to a particular file, then return nil." (when (not match) (setq match (car newtags))) ;; Return it. - (cons tab match))))) - -(defun semanticdb-elisp-sym-function-arglist (sym) - "Get the argument list for SYM. -Deal with all different forms of function. -This was snarfed out of eldoc." - (let* ((prelim-def - (let ((sd (and (fboundp sym) - (symbol-function sym)))) - (and (symbolp sd) - (condition-case err - (setq sd (indirect-function sym)) - (error (setq sd nil)))) - sd)) - (def (if (eq (car-safe prelim-def) 'macro) - (cdr prelim-def) - prelim-def)) - (arglist (cond ((null def) nil) - ((byte-code-function-p def) - ;; This is an eieio compatibility function. - ;; We depend on EIEIO, so use this. - (eieio-compiled-function-arglist def)) - ((eq (car-safe def) 'lambda) - (nth 1 def)) - (t nil)))) - arglist)) + (when tab (cons tab match)))))) + +(autoload 'help-function-arglist "help-fns") +(defalias 'semanticdb-elisp-sym-function-arglist 'help-function-arglist) +(make-obsolete 'semanticdb-elisp-sym-function-arglist + 'help-function-arglist "CEDET 1.1") (defun semanticdb-elisp-sym->tag (sym &optional toktype) "Convert SYM into a semantic tag. @@ -210,7 +205,7 @@ TOKTYPE is a hint to the type of tag desired." (symbol-name sym) nil ;; return type (semantic-elisp-desymbolify - (semanticdb-elisp-sym-function-arglist sym)) ;; arg-list + (help-function-arglist sym)) ;; arg-list :user-visible-flag (condition-case nil (interactive-form sym) (error nil)) diff --git a/lisp/cedet/semantic/db-file.el b/lisp/cedet/semantic/db-file.el index c487e39c7b2..7b4a47bd260 100644 --- a/lisp/cedet/semantic/db-file.el +++ b/lisp/cedet/semantic/db-file.el @@ -29,6 +29,9 @@ (require 'semantic/db) (require 'cedet-files) +(eval-when-compile + (require 'data-debug)) + (defvar semanticdb-file-version semantic-version "Version of semanticdb we are writing files to disk with.") (defvar semanticdb-file-incompatible-version "1.4" @@ -140,7 +143,7 @@ If DIRECTORY doesn't exist, create a new one." directory)) "/") :file fn :tables nil - :semantic-tag-version semantic-version + :semantic-tag-version semantic-tag-version :semanticdb-version semanticdb-file-version))) ;; Set this up here. We can't put it in the constructor because it ;; would be saved, and we want DB files to be portable. @@ -154,7 +157,7 @@ If DIRECTORY doesn't exist, create a new one." (defun semanticdb-load-database (filename) "Load the database FILENAME." (condition-case foo - (let* ((r (eieio-persistent-read filename)) + (let* ((r (eieio-persistent-read filename semanticdb-project-database-file)) (c (semanticdb-get-database-tables r)) (tv (oref r semantic-tag-version)) (fv (oref r semanticdb-version)) diff --git a/lisp/cedet/semantic/db-find.el b/lisp/cedet/semantic/db-find.el index 15ef3b09238..d42ecf7c4fc 100644 --- a/lisp/cedet/semantic/db-find.el +++ b/lisp/cedet/semantic/db-find.el @@ -123,6 +123,7 @@ (defvar data-debug-thing-alist) (declare-function data-debug-insert-stuff-list "data-debug") +(declare-function data-debug-new-buffer "data-debug") ;;;(declare-function data-debug-insert-tag-list "adebug") (declare-function semantic-scope-reset-cache "semantic/scope") (declare-function semanticdb-typecache-notify-reset "semantic/db-typecache") @@ -167,6 +168,8 @@ the following keys: :group 'semanticdb :type semanticdb-find-throttle-custom-list) +(make-variable-buffer-local 'semanticdb-find-default-throttle) + (defun semanticdb-find-throttle-active-p (access-type) "Non-nil if ACCESS-TYPE is an active throttle type." (or (memq access-type semanticdb-find-default-throttle) @@ -879,8 +882,9 @@ instead." ;; Find-file-match allows a tool to make sure the tag is ;; 'live', somewhere in a buffer. (cond ((eq find-file-match 'name) - (let ((f (semanticdb-full-filename nametable))) - (semantic--tag-put-property ntag :filename f))) + (or (semantic--tag-get-property ntag :filename) + (let ((f (semanticdb-full-filename nametable))) + (semantic--tag-put-property ntag :filename f)))) ((and find-file-match ntab) (semanticdb-get-buffer ntab)) ) @@ -1322,7 +1326,12 @@ Returns a table of all matching tags." "In TABLE, find all occurrences of tags of CLASS. Optional argument TAGS is a list of tags to search. Returns a table of all matching tags." - (semantic-find-tags-by-class class (or tags (semanticdb-get-tags table)))) + ;; Delegate 'include' to the overridable + ;; `semantic-find-tags-included', which by default will just call + ;; `semantic-find-tags-by-class'. + (if (eq class 'include) + (semantic-find-tags-included (or tags (semanticdb-get-tags table))) + (semantic-find-tags-by-class class (or tags (semanticdb-get-tags table))))) (defmethod semanticdb-find-tags-external-children-of-type-method ((table semanticdb-abstract-table) parent &optional tags) "In TABLE, find all occurrences of tags whose parent is the PARENT type. diff --git a/lisp/cedet/semantic/db-global.el b/lisp/cedet/semantic/db-global.el index eceb830341f..0d144483cb9 100644 --- a/lisp/cedet/semantic/db-global.el +++ b/lisp/cedet/semantic/db-global.el @@ -40,10 +40,17 @@ ;;; Code: ;;;###autoload -(defun semanticdb-enable-gnu-global-databases (mode) +(defun semanticdb-enable-gnu-global-databases (mode &optional noerror) "Enable the use of the GNU Global SemanticDB back end for all files of MODE. This will add an instance of a GNU Global database to each buffer -in a GNU Global supported hierarchy." +in a GNU Global supported hierarchy. + +Two sanity checks are performed to assure (a) that GNU global program exists +and (b) that the GNU global program version is compatibility with the database +version. If optional NOERROR is nil, then an error may be signalled on version +mismatch. If NOERROR is not nil, then no error will be signlled. Instead +return value will indicate success or failure with non-nil or nil respective +values." (interactive (list (completing-read "Enable in Mode: " obarray @@ -51,17 +58,18 @@ in a GNU Global supported hierarchy." t (symbol-name major-mode)))) ;; First, make sure the version is ok. - (cedet-gnu-global-version-check) - - ;; Make sure mode is a symbol. - (when (stringp mode) - (setq mode (intern mode))) - - (let ((ih (mode-local-value mode 'semantic-init-mode-hook))) - (eval `(setq-mode-local - ,mode semantic-init-mode-hook - (cons 'semanticdb-enable-gnu-global-hook ih)))) - + (if (not (cedet-gnu-global-version-check noerror)) + nil + ;; Make sure mode is a symbol. + (when (stringp mode) + (setq mode (intern mode))) + + (let ((ih (mode-local-value mode 'semantic-init-mode-hook))) + (eval `(setq-mode-local + ,mode semantic-init-mode-hook + (cons 'semanticdb-enable-gnu-global-hook ih)))) + t + ) ) (defun semanticdb-enable-gnu-global-hook () @@ -72,6 +80,8 @@ MODE is the major mode to support." (defclass semanticdb-project-database-global ;; @todo - convert to one DB per directory. (semanticdb-project-database eieio-instance-tracker) + + ;; @todo - use instance tracker symbol. () "Database representing a GNU Global tags file.") @@ -102,6 +112,11 @@ if optional DONT-ERR-IF-NOT-AVAILABLE is non-nil; else throw an error." ) "A table for returning search results from GNU Global.") +(defmethod object-print ((obj semanticdb-table-global) &rest strings) + "Pretty printer extension for `semanticdb-table-global'. +Adds the number of tags in this file to the object print name." + (apply 'call-next-method obj (cons " (proxy)" strings))) + (defmethod semanticdb-equivalent-mode ((table semanticdb-table-global) &optional buffer) "Return t, pretend that this table's mode is equivalent to BUFFER. Equivalent modes are specified by the `semantic-equivalent-major-modes' diff --git a/lisp/cedet/semantic/db-typecache.el b/lisp/cedet/semantic/db-typecache.el index 4698949b5e0..94999a2797b 100644 --- a/lisp/cedet/semantic/db-typecache.el +++ b/lisp/cedet/semantic/db-typecache.el @@ -483,6 +483,11 @@ found tag to be loaded." (setq ans nil))) ) + ;; The typecache holds all the known types and elements. Some databases + ;; may provide tags that are simplified by name, and are proxies. These + ;; proxies must be resolved in order to extract type members. + (setq ans (semantic-tag-resolve-proxy ans)) + (push ans calculated-scope) ;; Track most recent file. @@ -577,7 +582,11 @@ If there isn't one, create it. (interactive) (let* ((path (semanticdb-find-translate-path nil nil))) (dolist (P path) - (oset P pointmax nil) + (condition-case nil + (oset P pointmax nil) + ;; Pointmax may not exist for all tables disovered in the + ;; path. + (error nil)) (semantic-reset (semanticdb-get-typecache P))))) (defun semanticdb-typecache-dump () diff --git a/lisp/cedet/semantic/db.el b/lisp/cedet/semantic/db.el index 4e09f9fc3f2..afac974d7fb 100644 --- a/lisp/cedet/semantic/db.el +++ b/lisp/cedet/semantic/db.el @@ -33,8 +33,15 @@ (require 'eieio-base) (require 'semantic) +(eval-when-compile + (require 'semantic/find)) + (declare-function semantic-lex-spp-save-table "semantic/lex-spp") +;; Use autoload to avoid recursive require of semantic/db-ref +(autoload 'semanticdb-refresh-references "semantic/db-ref" + "Refresh references to DBT in other files.") + ;;; Variables: (defgroup semanticdb nil "Parser Generator Persistent Database interface." @@ -80,6 +87,11 @@ same major mode as the current buffer.") :accessor semanticdb-get-tags :printer semantic-tag-write-list-slot-value :documentation "The tags belonging to this table.") + (db-refs :initform nil + :documentation + "List of `semanticdb-table' objects refering to this one. +These aren't saved, but are instead recalculated after load. +See the file semanticdb-ref.el for how this slot is used.") (index :type semanticdb-abstract-search-index :documentation "The search index. Used by semanticdb-find to store additional information about @@ -148,13 +160,16 @@ them to convert TAG into a more complete form." (cons obj tag)) (defmethod object-print ((obj semanticdb-abstract-table) &rest strings) - "Pretty printer extension for `semanticdb-table'. + "Pretty printer extension for `semanticdb-abstract-table'. Adds the number of tags in this file to the object print name." - (apply 'call-next-method obj - (cons (format " (%d tags)" - (length (semanticdb-get-tags obj)) - ) - strings))) + (if (or (not strings) + (and (= (length strings) 1) (stringp (car strings)) + (string= (car strings) ""))) + ;; Else, add a tags quantifier. + (call-next-method obj (format " (%d tags)" (length (semanticdb-get-tags obj)))) + ;; Pass through. + (apply 'call-next-method obj strings) + )) ;;; Index Cache ;; @@ -201,8 +216,7 @@ If one doesn't exist, create it." ;; a semanticdb-table associated with a file. ;; (defclass semanticdb-search-results-table (semanticdb-abstract-table) - ( - ) + () "Table used for search results when there is no file or table association. Examples include search results from external sources such as from Emacs's own symbol table, or from external libraries.") @@ -299,7 +313,8 @@ If OBJ's file is not loaded, read it in first." "Pretty printer extension for `semanticdb-table'. Adds the number of tags in this file to the object print name." (apply 'call-next-method obj - (cons (if (oref obj dirty) ", DIRTY" "") strings))) + (cons (format " (%d tags)" (length (semanticdb-get-tags obj))) + (cons (if (oref obj dirty) ", DIRTY" "") strings)))) ;;; DATABASE BASE CLASS ;; @@ -324,7 +339,7 @@ so your cache will need to be recalculated at runtime. Note: This index will not be saved in a persistent file.") (tables :initarg :tables - :type list + :type semanticdb-abstract-table-list ;; Need this protection so apps don't try to access ;; the tables without using the accessor. :accessor semanticdb-get-database-tables @@ -416,7 +431,7 @@ If FILENAME exists in the database already, return that. If there is no database for the table to live in, create one." (let ((cdb nil) (tbl nil) - (dd (file-name-directory filename)) + (dd (file-name-directory (file-truename filename))) ) ;; Allow a database override function (setq cdb (semanticdb-create-database semanticdb-new-database-class @@ -555,7 +570,7 @@ This will call `semantic-fetch-tags' if that file is in memory." ;; semanticdb-create-table-for-file-not-in-buffer (save-excursion (let ((buff (semantic-find-file-noselect - (semanticdb-full-filename obj)))) + (semanticdb-full-filename obj) t))) (set-buffer buff) (semantic-fetch-tags) ;; Kill off the buffer if it didn't exist when we were called. @@ -620,7 +635,7 @@ The file associated with OBJ does not need to be in a buffer." ) ;; Update cross references - ;; (semanticdb-refresh-references table) + (semanticdb-refresh-references table) ) (defmethod semanticdb-partial-synchronize ((table semanticdb-abstract-table) @@ -650,8 +665,8 @@ The file associated with OBJ does not need to be in a buffer." ) ;; Update cross references - ;;(when (semantic-find-tags-by-class 'include new-tags) - ;; (semanticdb-refresh-references table)) + (when (semantic-find-tags-by-class 'include new-tags) + (semanticdb-refresh-references table)) ) ;;; SAVE/LOAD @@ -667,9 +682,11 @@ form." (defun semanticdb-save-current-db () "Save the current tag database." (interactive) - (message "Saving current tag summaries...") + (unless noninteractive + (message "Saving current tag summaries...")) (semanticdb-save-db semanticdb-current-database) - (message "Saving current tag summaries...done")) + (unless noninteractive + (message "Saving current tag summaries...done"))) ;; This prevents Semanticdb from querying multiple times if the users ;; answers "no" to creating the Semanticdb directory. @@ -678,10 +695,12 @@ form." (defun semanticdb-save-all-db () "Save all semantic tag databases." (interactive) - (message "Saving tag summaries...") + (unless noninteractive + (message "Saving tag summaries...")) (let ((semanticdb--inhibit-make-directory nil)) (mapc 'semanticdb-save-db semanticdb-database-list)) - (message "Saving tag summaries...done")) + (unless noninteractive + (message "Saving tag summaries...done"))) (defun semanticdb-save-all-db-idle () "Save all semantic tag databases from idle time. diff --git a/lisp/cedet/semantic/debug.el b/lisp/cedet/semantic/debug.el index e88517b15ce..3c0bf877728 100644 --- a/lisp/cedet/semantic/debug.el +++ b/lisp/cedet/semantic/debug.el @@ -308,13 +308,13 @@ Argument ONOFF is non-nil when we are entering debug mode. ;; Install our map onto this buffer (use-local-map semantic-debug-mode-map) ;; Make the buffer read only - (toggle-read-only 1) + (setq buffer-read-only t) (set-buffer (oref iface source-buffer)) ;; Use our map in the source buffer also (use-local-map semantic-debug-mode-map) ;; Make the buffer read only - (toggle-read-only 1) + (setq buffer-read-only t) ;; Hooks (run-hooks 'semantic-debug-mode-hook) ) diff --git a/lisp/cedet/semantic/decorate/include.el b/lisp/cedet/semantic/decorate/include.el index 50b50398e16..ede5c890163 100644 --- a/lisp/cedet/semantic/decorate/include.el +++ b/lisp/cedet/semantic/decorate/include.el @@ -175,6 +175,69 @@ Used by the decoration style: `semantic-decoration-on-unknown-includes'." :help "Add an include path for this session." ]) )) +;;; Includes with no file, but a table +;; +(defface semantic-decoration-on-fileless-includes + '((((class color) (background dark)) + (:background "#009000")) + (((class color) (background light)) + (:background "#f0fdf0"))) + "*Face used to show includes that have no file, but do have a DB table. +Used by the decoration style: `semantic-decoration-on-fileless-includes'." + :group 'semantic-faces) + +(defvar semantic-decoration-on-fileless-include-map + (let ((km (make-sparse-keymap))) + ;(define-key km [ mouse-2 ] 'semantic-decoration-fileless-include-describe) + (define-key km semantic-decoratiton-mouse-3 'semantic-decoration-fileless-include-menu) + km) + "Keymap used on unparsed includes.") + +(defvar semantic-decoration-on-fileless-include-menu nil + "Menu used for unparsed include headers.") + +(easy-menu-define + semantic-decoration-on-fileless-include-menu + semantic-decoration-on-fileless-include-map + "Fileless Include Menu" + (list + "Fileless Include" + (semantic-menu-item + ["What Is This?" semantic-decoration-fileless-include-describe + :active t + :help "Describe why this include has been marked this way." ]) + (semantic-menu-item + ["List all unknown includes" semanticdb-find-adebug-lost-includes + :active t + :help "Show a list of all includes semantic cannot find for this file." ]) + "---" + (semantic-menu-item + ["Summarize includes current buffer" semantic-decoration-all-include-summary + :active t + :help "Show a summary for the current buffer containing this include." ]) + (semantic-menu-item + ["List found includes (load unparsed)" semanticdb-find-test-translate-path + :active t + :help "List all includes found for this file, and parse unparsed files." ]) + (semantic-menu-item + ["List found includes (no loading)" semanticdb-find-test-translate-path-no-loading + :active t + :help "List all includes found for this file, do not parse unparsed files." ]) + "---" + (semantic-menu-item + ["Customize System Include Path" semantic-customize-system-include-path + :active (get 'semantic-dependency-system-include-path major-mode) + :help "Run customize for the system include path for this major mode." ]) + (semantic-menu-item + ["Add a System Include Path" semantic-add-system-include + :active t + :help "Add an include path for this session." ]) + (semantic-menu-item + ["Remove a System Include Path" semantic-remove-system-include + :active t + :help "Add an include path for this session." ]) + )) + ;;; Includes that need to be parsed. ;; (defface semantic-decoration-on-unparsed-includes @@ -272,17 +335,22 @@ This mode provides a nice context menu on the include statements." (defun semantic-decoration-on-includes-highlight-default (tag) "Highlight the include TAG to show that semantic can't find it." (let* ((file (semantic-dependency-tag-file tag)) - (table (when file - (semanticdb-file-table-object file t))) + (table (semanticdb-find-table-for-include tag (current-buffer))) (face nil) (map nil) ) (cond - ((not file) + ((and (not file) (not table)) ;; Cannot find this header. (setq face 'semantic-decoration-on-unknown-includes map semantic-decoration-on-unknown-include-map) ) + ((and (not file) table) + ;; There is no file, but the language supports a table for this + ;; include. Import perhaps? System include with no file? + (setq face 'semantic-decoration-on-fileless-includes + map semantic-decoration-on-fileless-include-map) + ) ((and table (number-or-marker-p (oref table pointmax))) ;; A found and parsed file. (setq face 'semantic-decoration-on-includes @@ -319,7 +387,7 @@ This mode provides a nice context menu on the include statements." ;;; Regular Include Functions ;; (defun semantic-decoration-include-describe () - "Describe what unparsed includes are in the current buffer. + "Describe the current include tag. Argument EVENT is the mouse clicked event." (interactive) (let* ((tag (or (semantic-current-tag) @@ -421,7 +489,7 @@ Argument EVENT describes the event that caused this function to be called." ;;; Unknown Include functions ;; (defun semantic-decoration-unknown-include-describe () - "Describe what unknown includes are in the current buffer. + "Describe the current unknown include. Argument EVENT is the mouse clicked event." (interactive) (let ((tag (semantic-current-tag)) @@ -484,7 +552,7 @@ See the Semantic manual node on SemanticDB for more about search paths.") ))) (defun semantic-decoration-unknown-include-menu (event) - "Popup a menu that can help a user understand unparsed includes. + "Popup a menu that can help a user understand unknown includes. Argument EVENT describes the event that caused this function to be called." (interactive "e") (let* ((startwin (selected-window)) @@ -501,6 +569,49 @@ Argument EVENT describes the event that caused this function to be called." (select-window startwin))) +;;; Fileless Include functions +;; +(defun semantic-decoration-fileless-include-describe () + "Describe the current fileless include. +Argument EVENT is the mouse clicked event." + (interactive) + (let* ((tag (semantic-current-tag)) + (table (semanticdb-find-table-for-include tag (current-buffer))) + (mm major-mode)) + (with-output-to-temp-buffer (help-buffer) ; "*Help*" + (help-setup-xref (list #'semantic-decoration-fileless-include-describe) + (called-interactively-p 'interactive)) + (princ "Include Tag: ") + (princ (semantic-format-tag-name tag nil t)) + (princ "\n\n") + (princ "This header tag has been marked \"Fileless\". +This means that Semantic cannot find a file associated with this tag +on disk, but a database table of tags has been associated with it. + +This means that the include will still be used to find tags for +searches, but you connot visit this include.\n\n") + (princ "This Header is now represented by the following database table:\n\n ") + (princ (object-print table)) + ))) + +(defun semantic-decoration-fileless-include-menu (event) + "Popup a menu that can help a user understand fileless includes. +Argument EVENT describes the event that caused this function to be called." + (interactive "e") + (let* ((startwin (selected-window)) + ;; This line has an issue in XEmacs. + (win (semantic-event-window event)) + ) + (select-window win t) + (save-excursion + ;(goto-char (window-start win)) + (mouse-set-point event) + (sit-for 0) + (semantic-popup-menu semantic-decoration-on-fileless-include-menu) + ) + (select-window startwin))) + + ;;; Interactive parts of unparsed includes ;; (defun semantic-decoration-unparsed-include-describe () @@ -667,6 +778,9 @@ Argument EVENT describes the event that caused this function to be called." (dolist (tag unk) (princ " ") (princ (semantic-tag-name tag)) + (when (not (eq (semantic-tag-name tag) (semantic-tag-include-filename tag))) + (princ " -> ") + (princ (semantic-tag-include-filename tag))) (princ "\n")) )) diff --git a/lisp/cedet/semantic/decorate/mode.el b/lisp/cedet/semantic/decorate/mode.el index f67978a2620..69dfa119167 100644 --- a/lisp/cedet/semantic/decorate/mode.el +++ b/lisp/cedet/semantic/decorate/mode.el @@ -265,6 +265,8 @@ minor mode is enabled." (semantic-make-local-hook 'semantic-after-toplevel-cache-change-hook) (add-hook 'semantic-after-toplevel-cache-change-hook 'semantic-decorate-tags-after-full-reparse nil t) + ;; Decorate includes by default + (require 'semantic/decorate/include) ;; Add decorations to available tags. The above hooks ensure ;; that new tags will be decorated when they become available. (semantic-decorate-add-decorations (semantic-fetch-available-tags))) diff --git a/lisp/cedet/semantic/doc.el b/lisp/cedet/semantic/doc.el index ddf1518f539..8a4e61fbad2 100644 --- a/lisp/cedet/semantic/doc.el +++ b/lisp/cedet/semantic/doc.el @@ -115,7 +115,10 @@ If NOSNARF is 'lex, then return the lex token." ;; In case it's a real string, STRIPIT. (while (string-match "\\s-*\\s\"+\\s-*" ct) (setq ct (concat (substring ct 0 (match-beginning 0)) - (substring ct (match-end 0)))))) + (substring ct (match-end 0))))) + ;; Remove comment delimiter at the end of the string. + (when (string-match (concat (regexp-quote comment-end) "$") ct) + (setq ct (substring ct 0 (match-beginning 0))))) ;; Now return the text. ct)))) diff --git a/lisp/cedet/semantic/ede-grammar.el b/lisp/cedet/semantic/ede-grammar.el index 0fc1829566c..c92fcabecb1 100644 --- a/lisp/cedet/semantic/ede-grammar.el +++ b/lisp/cedet/semantic/ede-grammar.el @@ -32,7 +32,7 @@ (require 'semantic/grammar) ;;; Code: -(defclass semantic-ede-proj-target-grammar (ede-proj-target-makefile) +(defclass semantic-ede-proj-target-grammar (ede-proj-target-elisp) ((menu :initform nil) (keybindings :initform nil) (phony :initform t) @@ -44,15 +44,33 @@ (semantic-ede-grammar-compiler-wisent semantic-ede-grammar-compiler-bovine )) + (aux-packages :initform '("semantic" "cedet-compat")) + (pre-load-packages :initform '("cedet-compat" "semantic/grammar" "semantic/bovine/grammar" "semantic/wisent/grammar")) ) "This target consists of a group of grammar files. A grammar target consists of grammar files that build Emacs Lisp programs for parsing different languages.") +(defmethod ede-proj-makefile-dependencies ((this semantic-ede-proj-target-grammar)) + "Return a string representing the dependencies for THIS. +Some compilers only use the first element in the dependencies, others +have a list of intermediates (object files), and others don't care. +This allows customization of how these elements appear. +For Emacs Lisp, return addsuffix command on source files." + (let ((source (car (oref this source)))) + (cond + ((string-match "\\.wy$" source) + (format "$(addsuffix -wy.elc, $(basename $(%s)))" + (ede-proj-makefile-sourcevar this))) + ((string-match "\\.by$" source) + (format "$(addsuffix -by.elc, $(basename $(%s)))" + (ede-proj-makefile-sourcevar this)))))) + (defvar semantic-ede-source-grammar-wisent (ede-sourcecode "semantic-ede-grammar-source-wisent" :name "Wisent Grammar" :sourcepattern "\\.wy$" + :garbagepattern '("*-wy.el") ) "Semantic Grammar source code definition for wisent.") @@ -64,21 +82,17 @@ parsing different languages.") (semantic-ede-grammar-compiler-class "ede-emacs-wisent-compiler" :name "emacs" - :variables '(("EMACS" . "emacs")) - :commands - '( - "@echo \"(add-to-list 'load-path nil)\" > grammar-make-script" - "@for loadpath in . ${LOADPATH}; do \\" - " echo \"(add-to-list 'load-path \\\"$$loadpath\\\")\" >> grammar-make-script; \\" - "done;" - "@echo \"(require 'semantic/load)\" >> grammar-make-script" - "@echo \"(require 'semantic/grammar)\" >> grammar-make-script" - ;; "@echo \"(setq debug-on-error t)\" >> grammar-make-script" - "\"$(EMACS)\" -batch --no-site-file -l grammar-make-script -f semantic-grammar-batch-build-packages $^" - ) - ;; :autoconf '("AM_PATH_LISPDIR") + :variables '(("EMACS" . "emacs") + ("EMACSFLAGS" . "-batch --no-site-file --eval '(setq debug-on-error t)'") + ("require" . "$(foreach r,$(1),(require (quote $(r))))")) + :rules (list (ede-makefile-rule + "elisp-inference-rule" + :target "%-wy.el" + :dependencies "%.wy" + :rules '("$(EMACS) $(EMACSFLAGS) $(addprefix -L ,$(LOADPATH)) \ +--eval '(progn $(call require,$(PRELOADS)))' -f semantic-grammar-batch-build-packages $^"))) :sourcetype '(semantic-ede-source-grammar-wisent) - :objectextention "-wy.elc" + :objectextention "-wy.el" ) "Compile Emacs Lisp programs.") @@ -87,6 +101,7 @@ parsing different languages.") (ede-sourcecode "semantic-ede-grammar-source-bovine" :name "Bovine Grammar" :sourcepattern "\\.by$" + :garbagepattern '("*-by.el") ) "Semantic Grammar source code definition for the bovinator.") @@ -94,21 +109,17 @@ parsing different languages.") (semantic-ede-grammar-compiler-class "ede-emacs-wisent-compiler" :name "emacs" - :variables '(("EMACS" . "emacs")) - :commands - '( - "@echo \"(add-to-list 'load-path nil)\" > grammar-make-script" - "@for loadpath in . ${LOADPATH}; do \\" - " echo \"(add-to-list 'load-path \\\"$$loadpath\\\")\" >> grammar-make-script; \\" - "done;" - "@echo \"(require 'semantic/load)\" >> grammar-make-script" - "@echo \"(require 'semantic/grammar)\" >> grammar-make-script" - ;; "@echo \"(setq debug-on-error t)\" >> grammar-make-script" - "\"$(EMACS)\" -batch --no-site-file -l grammar-make-script -f semantic-grammar-batch-build-packages $^" - ) - ;; :autoconf '("AM_PATH_LISPDIR") + :variables '(("EMACS" . "emacs") + ("EMACSFLAGS" . "-batch --no-site-file --eval '(setq debug-on-error t)'") + ("require" . "$(foreach r,$(1),(require (quote $(r))))")) + :rules (list (ede-makefile-rule + "elisp-inference-rule" + :target "%-by.el" + :dependencies "%.by" + :rules '("$(EMACS) $(EMACSFLAGS) $(addprefix -L ,$(LOADPATH)) \ +--eval '(progn $(call require,$(PRELOADS)))' -f semantic-grammar-batch-build-packages $^"))) :sourcetype '(semantic-ede-source-grammar-bovine) - :objectextention "-by.elc" + :objectextention "-by.el" ) "Compile Emacs Lisp programs.") @@ -127,15 +138,34 @@ Lays claim to all -by.el, and -wy.el files." "Compile all sources in a Lisp target OBJ." (let* ((cb (current-buffer)) (proj (ede-target-parent obj)) - (default-directory (oref proj directory))) + (default-directory (oref proj directory)) + (comp 0) + (utd 0)) (mapc (lambda (src) (with-current-buffer (find-file-noselect src) (save-excursion (semantic-grammar-create-package)) + ;; After compile, the current buffer is the compiled grammar. + ;; Save and compile it. (save-buffer) - (byte-recompile-file (concat (semantic-grammar-package) ".el") nil 0))) - (oref obj source))) - (message "All Semantic Grammar sources are up to date in %s" (object-name obj))) + (let* ((src (buffer-file-name)) + (csrc (concat (file-name-sans-extension src) ".elc"))) + (if (< emacs-major-version 24) + ;; Does not have `byte-recompile-file' + (if (or (not (file-exists-p csrc)) + (file-newer-than-file-p src csrc)) + (progn + (setq comp (1+ comp)) + (byte-compile-file src)) + (setq utd (1+ utd))) + ;; Emacs 24 and newer + (with-no-warnings + (if (eq (byte-recompile-file src nil 0) t) + (setq comp (1+ comp)) + (setq utd (1+ utd)))))))) + (oref obj source)) + (message "All Semantic Grammar sources are up to date in %s" (object-name obj)) + (cons comp utd))) ;;; Makefile generation functions ;; @@ -164,18 +194,13 @@ Lays claim to all -by.el, and -wy.el files." " "))) ) -(defmethod ede-proj-makefile-insert-rules ((this semantic-ede-proj-target-grammar)) - "Insert rules needed by THIS target." - ;; Add in some dependencies. -;; (mapc (lambda (src) -;; (let ((nm (file-name-sans-extension src))) -;; (insert nm "-wy.el: " src "\n" -;; nm "-wy.elc: " nm "-wy.el\n\n") -;; )) -;; (oref this source)) - ;; Call the normal insertion of rules. - (call-next-method) - ) +(defmethod ede-proj-makefile-insert-rules :after ((this semantic-ede-proj-target-grammar)) + "Insert rules needed by THIS target. +This raises `max-specpdl-size' and `max-lisp-eval-depth', which can be +needed for the compilation of the resulting parsers." + (insert (format "%s: EMACSFLAGS+= --eval '(setq max-specpdl-size 1500 \ +max-lisp-eval-depth 700)'\n" + (oref this name)))) (defmethod ede-proj-makefile-insert-dist-dependencies ((this semantic-ede-proj-target-grammar)) "Insert dist dependencies, or intermediate targets. diff --git a/lisp/cedet/semantic/find.el b/lisp/cedet/semantic/find.el index ce7ba9926d2..5c724a96d40 100644 --- a/lisp/cedet/semantic/find.el +++ b/lisp/cedet/semantic/find.el @@ -49,6 +49,7 @@ (require 'semantic/tag) (declare-function semantic-tag-protected-p "semantic/tag-ls") +(declare-function semantic-tag-package-protected-p "semantic/tag-ls") ;;; Overlay Search Routines ;; @@ -362,12 +363,19 @@ See `semantic-tag-protected-p' for details on which tags are returned." table (require 'semantic/tag-ls) (semantic--find-tags-by-macro - (not (semantic-tag-protected-p (car tags) scopeprotection parent)) + (not (and (semantic-tag-protected-p (car tags) scopeprotection parent) + (semantic-tag-package-protected-p (car tags) parent))) table))) -(defsubst semantic-find-tags-included (&optional table) +;;;###autoload +(define-overloadable-function semantic-find-tags-included (&optional table) "Find all tags in TABLE that are of the 'include class. -TABLE is a tag table. See `semantic-something-to-tag-table'." +TABLE is a tag table. See `semantic-something-to-tag-table'.") + +(defun semantic-find-tags-included-default (&optional table) + "Find all tags in TABLE that are of the 'include class. +TABLE is a tag table. See `semantic-something-to-tag-table'. +By default, just call `semantic-find-tags-by-class'." (semantic-find-tags-by-class 'include table)) ;;; Deep Searches diff --git a/lisp/cedet/semantic/fw.el b/lisp/cedet/semantic/fw.el index 851d5cd9e8e..c14ffb77169 100644 --- a/lisp/cedet/semantic/fw.el +++ b/lisp/cedet/semantic/fw.el @@ -33,42 +33,140 @@ (load "semantic/loaddefs" nil 'nomessage) ;;; Compatibility - -(defalias 'semantic-buffer-local-value 'buffer-local-value) -(defalias 'semantic-overlay-live-p 'overlay-buffer) -(defalias 'semantic-make-overlay 'make-overlay) -(defalias 'semantic-overlay-put 'overlay-put) -(defalias 'semantic-overlay-get 'overlay-get) -(defalias 'semantic-overlay-properties 'overlay-properties) -(defalias 'semantic-overlay-move 'move-overlay) -(defalias 'semantic-overlay-delete 'delete-overlay) -(defalias 'semantic-overlays-at 'overlays-at) -(defalias 'semantic-overlays-in 'overlays-in) -(defalias 'semantic-overlay-buffer 'overlay-buffer) -(defalias 'semantic-overlay-start 'overlay-start) -(defalias 'semantic-overlay-end 'overlay-end) -(defalias 'semantic-overlay-size 'overlay-size) -(defalias 'semantic-overlay-next-change 'next-overlay-change) -(defalias 'semantic-overlay-previous-change 'previous-overlay-change) -(defalias 'semantic-overlay-lists 'overlay-lists) -(defalias 'semantic-overlay-p 'overlayp) -(defalias 'semantic-read-event 'read-event) -(defalias 'semantic-popup-menu 'popup-menu) -(defalias 'semantic-make-local-hook 'identity) -(defalias 'semantic-mode-line-update 'force-mode-line-update) -(defalias 'semantic-run-mode-hooks 'run-mode-hooks) -(defalias 'semantic-compile-warn 'byte-compile-warn) -(defalias 'semantic-menu-item 'identity) - -(defun semantic-event-window (event) - "Extract the window from EVENT." - (car (car (cdr event)))) +;; +(eval-and-compile + (if (featurep 'xemacs) + (progn + (defalias 'semantic-buffer-local-value 'symbol-value-in-buffer) + (defalias 'semantic-overlay-live-p + (lambda (o) + (and (extent-live-p o) + (not (extent-detached-p o)) + (bufferp (extent-buffer o))))) + (defalias 'semantic-make-overlay + (lambda (beg end &optional buffer &rest rest) + "Xemacs `make-extent', supporting the front/rear advance options." + (let ((ol (make-extent beg end buffer))) + (when rest + (set-extent-property ol 'start-open (car rest)) + (setq rest (cdr rest))) + (when rest + (set-extent-property ol 'end-open (car rest))) + ol))) + (defalias 'semantic-overlay-put 'set-extent-property) + (defalias 'semantic-overlay-get 'extent-property) + (defalias 'semantic-overlay-properties 'extent-properties) + (defalias 'semantic-overlay-move 'set-extent-endpoints) + (defalias 'semantic-overlay-delete 'delete-extent) + (defalias 'semantic-overlays-at + (lambda (pos) + (condition-case nil + (extent-list nil pos pos) + (error nil)) + )) + (defalias 'semantic-overlays-in + (lambda (beg end) (extent-list nil beg end))) + (defalias 'semantic-overlay-buffer 'extent-buffer) + (defalias 'semantic-overlay-start 'extent-start-position) + (defalias 'semantic-overlay-end 'extent-end-position) + (defalias 'semantic-overlay-size 'extent-length) + (defalias 'semantic-overlay-next-change 'next-extent-change) + (defalias 'semantic-overlay-previous-change 'previous-extent-change) + (defalias 'semantic-overlay-lists + (lambda () (list (extent-list)))) + (defalias 'semantic-overlay-p 'extentp) + (defalias 'semantic-event-window 'event-window) + (defun semantic-read-event () + (let ((event (next-command-event))) + (if (key-press-event-p event) + (let ((c (event-to-character event))) + (if (char-equal c (quit-char)) + (keyboard-quit) + c))) + event)) + (defun semantic-popup-menu (menu) + "Blockinig version of `popup-menu'" + (popup-menu menu) + ;; Wait... + (while (popup-up-p) (dispatch-event (next-event)))) + ) + ;; Emacs Bindings + (defalias 'semantic-overlay-live-p 'overlay-buffer) + (defalias 'semantic-make-overlay 'make-overlay) + (defalias 'semantic-overlay-put 'overlay-put) + (defalias 'semantic-overlay-get 'overlay-get) + (defalias 'semantic-overlay-properties 'overlay-properties) + (defalias 'semantic-overlay-move 'move-overlay) + (defalias 'semantic-overlay-delete 'delete-overlay) + (defalias 'semantic-overlays-at 'overlays-at) + (defalias 'semantic-overlays-in 'overlays-in) + (defalias 'semantic-overlay-buffer 'overlay-buffer) + (defalias 'semantic-overlay-start 'overlay-start) + (defalias 'semantic-overlay-end 'overlay-end) + (defalias 'semantic-overlay-next-change 'next-overlay-change) + (defalias 'semantic-overlay-previous-change 'previous-overlay-change) + (defalias 'semantic-overlay-lists 'overlay-lists) + (defalias 'semantic-overlay-p 'overlayp) + (defalias 'semantic-read-event 'read-event) + (defalias 'semantic-popup-menu 'popup-menu) + (defun semantic-event-window (event) + "Extract the window from EVENT." + (car (car (cdr event)))) + + (if (> emacs-major-version 21) + (defalias 'semantic-buffer-local-value 'buffer-local-value) + + (defun semantic-buffer-local-value (sym &optional buf) + "Get the value of SYM from buffer local variable in BUF." + (cdr (assoc sym (buffer-local-variables buf))))) + ) + + + (if (and (not (featurep 'xemacs)) + (>= emacs-major-version 21)) + (defalias 'semantic-make-local-hook 'identity) + (defalias 'semantic-make-local-hook 'make-local-hook) + ) + + (if (featurep 'xemacs) + (defalias 'semantic-mode-line-update 'redraw-modeline) + (defalias 'semantic-mode-line-update 'force-mode-line-update)) + + ;; Since Emacs 22 major mode functions should use `run-mode-hooks' to + ;; run major mode hooks. + (defalias 'semantic-run-mode-hooks + (if (fboundp 'run-mode-hooks) + 'run-mode-hooks + 'run-hooks)) + + ;; Fancy compat useage now handled in cedet-compat + (defalias 'semantic-subst-char-in-string 'subst-char-in-string) + ) (defun semantic-delete-overlay-maybe (overlay) "Delete OVERLAY if it is a semantic token overlay." (if (semantic-overlay-get overlay 'semantic) (semantic-overlay-delete overlay))) +;;; Menu Item compatibility +;; +(defun semantic-menu-item (item) + "Build an XEmacs compatible menu item from vector ITEM. +That is remove the unsupported :help stuff." + (if (featurep 'xemacs) + (let ((n (length item)) + (i 0) + slot l) + (while (< i n) + (setq slot (aref item i)) + (if (and (keywordp slot) + (eq slot :help)) + (setq i (1+ i)) + (setq l (cons slot l))) + (setq i (1+ i))) + (apply #'vector (nreverse l))) + item)) + ;;; Positional Data Cache ;; (defvar semantic-cache-data-overlays nil @@ -138,6 +236,23 @@ Remove self from `post-command-hook' if it is empty." (when ans (semantic-overlay-get ans 'cached-value))))) +(defun semantic-test-data-cache () + "Test the data cache." + (interactive) + (let ((data '(a b c))) + (save-current-buffer + (set-buffer (get-buffer-create " *semantic-test-data-cache*")) + (save-excursion + (erase-buffer) + (insert "The Moose is Loose") + (goto-char (point-min)) + (semantic-cache-data-to-buffer (current-buffer) (point) (+ (point) 5) + data 'moose 'exit-cache-zone) + (if (equal (semantic-get-cache-data 'moose) data) + (message "Successfully retrieved cached data.") + (error "Failed to retrieve cached data")) + )))) + ;;; Obsoleting various functions & variables ;; (defun semantic-overload-symbol-from-function (name) @@ -161,7 +276,7 @@ will throw a warning when it encounters this symbol." (not (string-match "cedet" byte-compile-current-file)) ) (make-obsolete-overload oldfnalias newfn when) - (semantic-compile-warn + (byte-compile-warn "%s: `%s' obsoletes overload `%s'" byte-compile-current-file newfn @@ -179,7 +294,7 @@ will throw a warning when it encounters this symbol." ;; Only throw this warning when byte compiling things. (when (and (boundp 'byte-compile-current-file) byte-compile-current-file) - (semantic-compile-warn + (byte-compile-warn "variable `%s' obsoletes, but isn't alias of `%s'" newvar oldvaralias) )))) @@ -276,6 +391,17 @@ calling this one." "Call `find-file-noselect' with various features turned off. Use this when referencing a file that will be soon deleted. FILE, NOWARN, RAWFILE, and WILDCARDS are passed into `find-file-noselect'" + ;; Hack - + ;; Check if we are in set-auto-mode, and if so, warn about this. + (when (or (and (featurep 'emacs) (boundp 'keep-mode-if-same)) + (and (featurep 'xemacs) (boundp 'just-from-file-name))) + (let ((filename (or (and (boundp 'filename) filename) + "(unknown)"))) + (message "WARNING: semantic-find-file-noselect called for \ +%s while in set-auto-mode for %s. You should call the responsible function \ +into `mode-local-init-hook'." file filename) + (sit-for 1))) + (let* ((recentf-exclude '( (lambda (f) t) )) ;; This is a brave statement. Don't waste time loading in ;; lots of modes. Especially decoration mode can waste a lot @@ -285,8 +411,11 @@ FILE, NOWARN, RAWFILE, and WILDCARDS are passed into `find-file-noselect'" (ede-auto-add-method 'never) ;; Ask font-lock to not colorize these buffers, nor to ;; whine about it either. - (font-lock-maximum-size 0) + (global-font-lock-mode nil) (font-lock-verbose nil) + ;; This forces flymake to ignore this buffer on find-file, and + ;; prevents flymake processes from being started. + (flymake-start-syntax-check-on-find-file nil) ;; Disable revision control (vc-handled-backends nil) ;; Don't prompt to insert a template if we visit an empty file diff --git a/lisp/cedet/semantic/grammar-wy.el b/lisp/cedet/semantic/grammar-wy.el index 7408dd6702e..8a33c8c8a1a 100644 --- a/lisp/cedet/semantic/grammar-wy.el +++ b/lisp/cedet/semantic/grammar-wy.el @@ -2,9 +2,6 @@ ;; Copyright (C) 2002-2004, 2009-2012 Free Software Foundation, Inc. -;; Author: David Ponce <david@dponce.com> -;; Keywords: syntax - ;; This file is part of GNU Emacs. ;; GNU Emacs is free software: you can redistribute it and/or modify @@ -27,6 +24,10 @@ ;;; Code: (require 'semantic/lex) +(eval-when-compile (require 'semantic/bovine)) + +;;; Prologue +;; (defvar semantic-grammar-lex-c-char-re) ;; Current parsed nonterminal name. @@ -45,6 +46,7 @@ ("%left" . LEFT) ("%nonassoc" . NONASSOC) ("%package" . PACKAGE) + ("%provide" . PROVIDE) ("%prec" . PREC) ("%put" . PUT) ("%quotemode" . QUOTEMODE) @@ -109,7 +111,7 @@ (eval-when-compile (require 'semantic/wisent/comp)) (wisent-compile-grammar - '((DEFAULT-PREC NO-DEFAULT-PREC KEYWORD LANGUAGEMODE LEFT NONASSOC PACKAGE PREC PUT QUOTEMODE RIGHT SCOPESTART START TOKEN TYPE USE-MACROS STRING SYMBOL PERCENT_PERCENT CHARACTER PREFIXED_LIST SEXP PROLOGUE EPILOGUE PAREN_BLOCK BRACE_BLOCK LPAREN RPAREN LBRACE RBRACE COLON SEMI OR LT GT) + '((DEFAULT-PREC NO-DEFAULT-PREC KEYWORD LANGUAGEMODE LEFT NONASSOC PACKAGE PROVIDE PREC PUT QUOTEMODE RIGHT SCOPESTART START TOKEN TYPE USE-MACROS STRING SYMBOL PERCENT_PERCENT CHARACTER PREFIXED_LIST SEXP PROLOGUE EPILOGUE PAREN_BLOCK BRACE_BLOCK LPAREN RPAREN LBRACE RBRACE COLON SEMI OR LT GT) nil (grammar ((prologue)) @@ -133,6 +135,7 @@ ((no_default_prec_decl)) ((languagemode_decl)) ((package_decl)) + ((provide_decl)) ((precedence_decl)) ((put_decl)) ((quotemode_decl)) @@ -161,6 +164,10 @@ ((PACKAGE SYMBOL) `(wisent-raw-tag (semantic-tag-new-package ',$2 nil)))) + (provide_decl + ((PROVIDE SYMBOL) + `(wisent-raw-tag + (semantic-tag ',$2 'provide)))) (precedence_decl ((associativity token_type_opt items) `(wisent-raw-tag @@ -411,31 +418,17 @@ '((parse-stream . wisent-parse-stream))) (setq semantic-parser-name "LALR" semantic--parse-table semantic-grammar-wy--parse-table - semantic-debug-parser-source "semantic-grammar.wy" + semantic-debug-parser-source "grammar.wy" semantic-flex-keywords-obarray semantic-grammar-wy--keyword-table semantic-lex-types-obarray semantic-grammar-wy--token-table) ;; Collect unmatched syntax lexical tokens (semantic-make-local-hook 'wisent-discarding-token-functions) (add-hook 'wisent-discarding-token-functions - 'wisent-collect-unmatched-syntax nil t)) + 'wisent-collect-unmatched-syntax nil t)) ;;; Analyzers - -(define-lex-sexp-type-analyzer semantic-grammar-wy--<sexp>-sexp-analyzer - "sexp analyzer for <sexp> tokens." - "\\=" - 'SEXP) - -(define-lex-sexp-type-analyzer semantic-grammar-wy--<qlist>-sexp-analyzer - "sexp analyzer for <qlist> tokens." - "\\s'\\s-*(" - 'PREFIXED_LIST) - -(define-lex-keyword-type-analyzer semantic-grammar-wy--<keyword>-keyword-analyzer - "keyword analyzer for <keyword> tokens." - "\\(\\sw\\|\\s_\\)+") - +;; (define-lex-block-type-analyzer semantic-grammar-wy--<block>-block-analyzer "block analyzer for <block> tokens." "\\s(\\|\\s)" @@ -451,17 +444,22 @@ nil 'CHARACTER) -(define-lex-sexp-type-analyzer semantic-grammar-wy--<string>-sexp-analyzer - "sexp analyzer for <string> tokens." - "\\s\"" - 'STRING) - (define-lex-regex-type-analyzer semantic-grammar-wy--<symbol>-regexp-analyzer "regexp analyzer for <symbol> tokens." ":?\\(\\sw\\|\\s_\\)+" '((PERCENT_PERCENT . "\\`%%\\'")) 'SYMBOL) +(define-lex-sexp-type-analyzer semantic-grammar-wy--<qlist>-sexp-analyzer + "sexp analyzer for <qlist> tokens." + "\\s'\\s-*(" + 'PREFIXED_LIST) + +(define-lex-sexp-type-analyzer semantic-grammar-wy--<string>-sexp-analyzer + "sexp analyzer for <string> tokens." + "\\s\"" + 'STRING) + (define-lex-string-type-analyzer semantic-grammar-wy--<punctuation>-string-analyzer "string analyzer for <punctuation> tokens." "\\(\\s.\\|\\s$\\|\\s'\\)+" @@ -472,6 +470,22 @@ (COLON . ":")) 'punctuation) +(define-lex-keyword-type-analyzer semantic-grammar-wy--<keyword>-keyword-analyzer + "keyword analyzer for <keyword> tokens." + "\\(\\sw\\|\\s_\\)+") + +(define-lex-sexp-type-analyzer semantic-grammar-wy--<sexp>-sexp-analyzer + "sexp analyzer for <sexp> tokens." + "\\=" + 'SEXP) + + +;;; Epilogue +;; + + + + (provide 'semantic/grammar-wy) ;;; semantic/grammar-wy.el ends here diff --git a/lisp/cedet/semantic/grammar.el b/lisp/cedet/semantic/grammar.el index ac28702787d..b85396a79ae 100644 --- a/lisp/cedet/semantic/grammar.el +++ b/lisp/cedet/semantic/grammar.el @@ -30,10 +30,12 @@ ;;; Code: (require 'semantic) +(require 'semantic/wisent) (require 'semantic/ctxt) (require 'semantic/format) (require 'semantic/grammar-wy) (require 'semantic/idle) + (declare-function semantic-momentary-highlight-tag "semantic/decorate") (declare-function semantic-analyze-context "semantic/analyze") (declare-function semantic-analyze-tags-of-class-list @@ -42,7 +44,8 @@ (eval-when-compile (require 'eldoc) (require 'semantic/edit) - (require 'semantic/find)) + (require 'semantic/find) + (require 'semantic/db)) ;;;; @@ -488,33 +491,27 @@ Also load the specified macro libraries." ;;;; (defvar semantic--grammar-input-buffer nil) (defvar semantic--grammar-output-buffer nil) +(defvar semantic--grammar-package nil) +(defvar semantic--grammar-provide nil) (defsubst semantic-grammar-keywordtable () "Return the variable name of the keyword table." - (concat (file-name-sans-extension - (semantic-grammar-buffer-file - semantic--grammar-output-buffer)) + (concat semantic--grammar-package "--keyword-table")) (defsubst semantic-grammar-tokentable () "Return the variable name of the token table." - (concat (file-name-sans-extension - (semantic-grammar-buffer-file - semantic--grammar-output-buffer)) + (concat semantic--grammar-package "--token-table")) (defsubst semantic-grammar-parsetable () "Return the variable name of the parse table." - (concat (file-name-sans-extension - (semantic-grammar-buffer-file - semantic--grammar-output-buffer)) + (concat semantic--grammar-package "--parse-table")) (defsubst semantic-grammar-setupfunction () "Return the name of the parser setup function." - (concat (file-name-sans-extension - (semantic-grammar-buffer-file - semantic--grammar-output-buffer)) + (concat semantic--grammar-package "--install-parser")) (defmacro semantic-grammar-as-string (object) @@ -592,6 +589,9 @@ Typically a DEFINE expression should look like this: ;; ;;; Code: + +(require 'semantic/lex) +(eval-when-compile (require 'semantic/bovine)) ") "Generated header template. The symbols in the template are local variables in @@ -642,7 +642,8 @@ The symbols in the list are local variables in "Return text of a generated standard footer." (let* ((file (semantic-grammar-buffer-file semantic--grammar-output-buffer)) - (libr (file-name-sans-extension file)) + (libr (or semantic--grammar-provide + semantic--grammar-package)) (out "")) (dolist (S semantic-grammar-footer-template) (cond ((stringp S) @@ -748,9 +749,7 @@ Block definitions are read from the current table of lexical types." ;; explicitly declared in a %type statement, and if at least the ;; syntax property has been provided. (when (and declared syntax) - (setq prefix (file-name-sans-extension - (semantic-grammar-buffer-file - semantic--grammar-output-buffer)) + (setq prefix semantic--grammar-package mtype (or (get type 'matchdatatype) 'regexp) name (intern (format "%s--<%s>-%s-analyzer" prefix type mtype)) doc (format "%s analyzer for <%s> tokens." mtype type)) @@ -801,7 +800,6 @@ Block definitions are read from the current table of lexical types." (with-current-buffer semantic--grammar-input-buffer (setq tokens (semantic-grammar-tokens) props (semantic-grammar-token-properties tokens))) - (insert "(require 'semantic/lex)\n\n") (let ((semantic-lex-types-obarray (semantic-lex-make-type-table tokens props)) semantic-grammar--lex-block-specs) @@ -833,10 +831,14 @@ Lisp code." ;; Values of the following local variables are obtained from ;; the grammar parsed tree in current buffer, that is before ;; switching to the output file. - (package (semantic-grammar-package)) - (output (concat package ".el")) + (semantic--grammar-package (semantic-grammar-package)) + (semantic--grammar-provide (semantic-grammar-first-tag-name 'provide)) + (output (concat (or semantic--grammar-provide + semantic--grammar-package) ".el")) (semantic--grammar-input-buffer (current-buffer)) - (semantic--grammar-output-buffer (find-file-noselect output)) + (semantic--grammar-output-buffer + (find-file-noselect + (file-name-nondirectory output))) (header (semantic-grammar-header)) (prologue (semantic-grammar-prologue)) (epilogue (semantic-grammar-epilogue)) @@ -847,7 +849,7 @@ Lisp code." (file-newer-than-file-p (buffer-file-name semantic--grammar-output-buffer) (buffer-file-name semantic--grammar-input-buffer))) - (message "Package `%s' is up to date." package) + (message "Package `%s' is up to date." semantic--grammar-package) ;; Create the package (set-buffer semantic--grammar-output-buffer) ;; Use Unix EOLs, so that the file is portable to all platforms. @@ -965,7 +967,11 @@ Return non-nil if there were no errors, nil if errors." (let ((packagename (condition-case err (with-current-buffer (find-file-noselect file) - (semantic-grammar-create-package)) + (let ((semantic-new-buffer-setup-functions nil) + (vc-handled-backends nil)) + (setq semanticdb-new-database-class 'semanticdb-project-database) + (semantic-mode 1) + (semantic-grammar-create-package))) (error (message "%s" (error-message-string err)) nil)))) @@ -1000,7 +1006,6 @@ See also the variable `semantic-grammar-file-regexp'." ;; Remove vc from find-file-hook. It causes bad stuff to ;; happen in Emacs 20. (find-file-hook (delete 'vc-find-file-hook find-file-hook))) - (message "Compiling Grammars from: %s" (locate-library "semantic-grammar")) (dolist (arg command-line-args-left) (unless (and arg (file-exists-p arg)) (error "Argument %s is not a valid file name" arg)) diff --git a/lisp/cedet/semantic/ia.el b/lisp/cedet/semantic/ia.el index 1aedc7b6d45..9f6a82159e8 100644 --- a/lisp/cedet/semantic/ia.el +++ b/lisp/cedet/semantic/ia.el @@ -37,9 +37,10 @@ (require 'semantic/analyze) (require 'semantic/format) (require 'pulse) +(require 'semantic/senator) +(require 'semantic/analyze/refs) (eval-when-compile (require 'semantic/analyze) - (require 'semantic/analyze/refs) (require 'semantic/find)) (declare-function imenu--mouse-menu "imenu") @@ -143,11 +144,50 @@ Completion options are calculated with `semantic-analyze-possible-completions'." (mapcar semantic-ia-completion-format-tag-function syms))))))))) (defcustom semantic-ia-completion-menu-format-tag-function - 'semantic-uml-concise-prototype-nonterminal + 'semantic-format-tag-uml-concise-prototype "*Function used to convert a tag to a string during completion." :group 'semantic :type semantic-format-tag-custom-list) +;;;###autoload +(defun semantic-ia-complete-symbol-menu (point) + "Complete the current symbol via a menu based at POINT. +Completion options are calculated with `semantic-analyze-possible-completions'." + (interactive "d") + (require 'imenu) + (let* ((a (semantic-analyze-current-context point)) + (syms (semantic-analyze-possible-completions a)) + ) + ;; Complete this symbol. + (if (not syms) + (progn + (message "No smart completions found. Trying Senator.") + (when (semantic-analyze-context-p a) + ;; This is a quick way of getting a nice completion list + ;; in the menu if the regular context mechanism fails. + (senator-completion-menu-popup))) + + (let* ((menu + (mapcar + (lambda (tag) + (cons + (funcall semantic-ia-completion-menu-format-tag-function tag) + (vector tag))) + syms)) + (ans + (imenu--mouse-menu + ;; XEmacs needs that the menu has at least 2 items. So, + ;; include a nil item that will be ignored by imenu. + (cons nil menu) + (senator-completion-menu-point-as-event) + "Completions"))) + (when ans + (if (not (semantic-tag-p ans)) + (setq ans (aref (cdr ans) 0))) + (delete-region (car (oref a bounds)) (cdr (oref a bounds))) + (semantic-ia-insert-tag ans)) + )))) + ;;; Completions Tip ;; ;; This functions shows how to get the list of completions, diff --git a/lisp/cedet/semantic/idle.el b/lisp/cedet/semantic/idle.el index 7ed1612d592..57cb17a233e 100644 --- a/lisp/cedet/semantic/idle.el +++ b/lisp/cedet/semantic/idle.el @@ -41,6 +41,7 @@ (require 'semantic/format) (require 'semantic/tag) (require 'timer) +;;(require 'working) ;; For the semantic-find-tags-by-name macro. (eval-when-compile (require 'semantic/find)) @@ -150,12 +151,18 @@ all buffers regardless of their size." "Return non-nil if idle-scheduler is enabled for this buffer. idle-scheduler is disabled when debugging or if the buffer size exceeds the `semantic-idle-scheduler-max-buffer-size' threshold." - (and semantic-idle-scheduler-mode - (not (and (boundp 'semantic-debug-enabled) - semantic-debug-enabled)) - (not semantic-lex-debug) - (or (<= semantic-idle-scheduler-max-buffer-size 0) - (< (buffer-size) semantic-idle-scheduler-max-buffer-size)))) + (let* ((remote-file? (when (stringp buffer-file-name) (file-remote-p buffer-file-name)))) + (and semantic-idle-scheduler-mode + (not (and (boundp 'semantic-debug-enabled) + semantic-debug-enabled)) + (not semantic-lex-debug) + ;; local file should exist on disk + ;; remote file should have active connection + (or (and (null remote-file?) (stringp buffer-file-name) + (file-exists-p buffer-file-name)) + (and remote-file? (file-remote-p buffer-file-name nil t))) + (or (<= semantic-idle-scheduler-max-buffer-size 0) + (< (buffer-size) semantic-idle-scheduler-max-buffer-size))))) ;;;###autoload (define-minor-mode semantic-idle-scheduler-mode @@ -554,10 +561,11 @@ FORMS will be called during idle time after the current buffer's semantic tag information has been updated. This routine creates the following functions and variables:" (let ((global (intern (concat "global-" (symbol-name name) "-mode"))) - (mode (intern (concat (symbol-name name) "-mode"))) - (hook (intern (concat (symbol-name name) "-mode-hook"))) - (map (intern (concat (symbol-name name) "-mode-map"))) - (func (intern (concat (symbol-name name) "-idle-function")))) + (mode (intern (concat (symbol-name name) "-mode"))) + (hook (intern (concat (symbol-name name) "-mode-hook"))) + (map (intern (concat (symbol-name name) "-mode-map"))) + (setup (intern (concat (symbol-name name) "-mode-setup"))) + (func (intern (concat (symbol-name name) "-idle-function")))) `(eval-and-compile (define-minor-mode ,global @@ -607,7 +615,10 @@ turned on in every Semantic-supported buffer.") (symbol-name mode) "'.") ,@forms)))) (put 'define-semantic-idle-service 'lisp-indent-function 1) - +(add-hook 'edebug-setup-hook + (lambda () + (def-edebug-spec define-semantic-idle-service + (&define name stringp def-body)))) ;;; SUMMARY MODE ;; @@ -878,7 +889,7 @@ Call `semantic-symref-hits-in-region' to identify local references." ;; We use pulse, but we don't want the flashy version, ;; just the stable version. (pulse-flag nil)) - (when ctxt + (when (and ctxt tag) ;; Highlight the original tag? Protect against problems. (condition-case nil (semantic-idle-symbol-maybe-highlight target) @@ -932,15 +943,18 @@ doing fancy completions." "Calculate and display a list of completions." (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 + ;; This mode can be fragile, hence don't raise errors, and only + ;; report problems if semantic-idle-scheduler-verbose-flag is + ;; non-nil. If something doesn't do what you expect, run the + ;; below command by hand instead. + (condition-case err (semanticdb-without-unloaded-file-searches ;; Use idle version. (semantic-complete-analyze-inline-idle) ) - (error nil)) + (error + (when semantic-idle-scheduler-verbose-flag + (message " %s" (error-message-string err))))) )) (define-semantic-idle-service semantic-idle-completions @@ -1133,7 +1147,7 @@ be called." ;; :active t ;; :style 'toggle ;; :selected '(let ((tag (semantic-current-tag))) - ;; (and tag (semantic-tag-folded-p tag))) + ;; (and tag (semantic-tag-folded-p tag))) ;; :help "Fold the current tag to one line")) "---" (semantic-menu-item @@ -1168,17 +1182,19 @@ be called." ;; 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))))) + (replace-regexp-in-string ;; Since % is interpreted in the + "\\(%\\)" "%\\1" ;; mode/header line format, we + (concat ;; have to escape all occurrences. + 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)) @@ -1192,7 +1208,9 @@ TODO 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))) + (replace-regexp-in-string ;; see comment in + "\\(%\\)" "%\\1" ;; `semantic-idle-breadcrumbs--display-in-header-line' + (semantic-idle-breadcrumbs--format-tag-list tag-list width)))) (force-mode-line-update)) diff --git a/lisp/cedet/semantic/java.el b/lisp/cedet/semantic/java.el index 8747d793ab8..e560e6ecab2 100644 --- a/lisp/cedet/semantic/java.el +++ b/lisp/cedet/semantic/java.el @@ -121,6 +121,7 @@ corresponding compound declaration." (setq clone (semantic-tag-clone tag (car dim)) xpand (cons clone xpand)) (semantic-tag-put-attribute clone :dereference (cdr dim))) + ((eq class 'variable) (or (consp elts) (setq elts (list (list elts)))) (setq dim (semantic-java-dim (semantic-tag-get-attribute tag :type)) @@ -139,7 +140,20 @@ corresponding compound declaration." (semantic-tag-put-attribute clone :type type) (semantic-tag-put-attribute clone :dereference (+ dim0 (cdr dim))) (semantic-tag-set-bounds clone start end))) - ) + + ((and (eq class 'type) (string-match "\\." (semantic-tag-name tag))) + ;; javap outputs files where the package name is stuck onto the class or interface + ;; name. To make this more regular, we extract the package name into a package statement, + ;; then make the class name regular. + (let* ((name (semantic-tag-name tag)) + (rsplit (nreverse (split-string name "\\." t))) + (newclassname (car rsplit)) + (newpkg (mapconcat 'identity (reverse (cdr rsplit)) "."))) + (semantic-tag-set-name tag newclassname) + (setq xpand + (list tag + (semantic-tag-new-package newpkg nil)))) + )) xpand)) ;;; Environment @@ -159,6 +173,15 @@ corresponding compound declaration." (semantic-find-tags-by-class 'type (semantic-find-tag-by-overlay point)))) +;; Tag Protection +;; +(define-mode-local-override semantic-tag-protection + java-mode (tag &optional parent) + "Return the protection of TAG in PARENT. +Override function for `semantic-tag-protection'." + (let ((prot (semantic-tag-protection-default tag parent))) + (or prot 'package))) + ;; Prototype handler ;; (defun semantic-java-prototype-function (tag &optional parent color) @@ -242,7 +265,6 @@ Optional argument COLOR indicates that color should be mixed in." (let ((name (semantic-tag-name tag))) (concat (mapconcat 'identity (split-string name "\\.") "/") ".java"))) - ;; Documentation handler ;; (defsubst semantic-java-skip-spaces-backward () diff --git a/lisp/cedet/semantic/lex-spp.el b/lisp/cedet/semantic/lex-spp.el index 5f121d88ac6..5fe900452a0 100644 --- a/lisp/cedet/semantic/lex-spp.el +++ b/lisp/cedet/semantic/lex-spp.el @@ -497,7 +497,7 @@ and what valid VAL values are." ;; (symbol "name" 569 . 573) ;; (semantic-list "(int in)" 574 . 582)) ;; - ;; In the second case, a macro with an argument list as the a rgs as the + ;; In the second case, a macro with an argument list as the args as the ;; first entry. ;; ;; CASE 3: Symbol text merge @@ -577,13 +577,7 @@ and what valid VAL values are." (cond ;; CASE 3: Merge symbols together. ((eq (semantic-lex-token-class v) 'spp-symbol-merge) - ;; We need to merge the tokens in the 'text segment together, - ;; and produce a single symbol from it. - (let ((newsym - (mapconcat (lambda (tok) - (semantic-lex-spp-one-token-to-txt tok)) - txt - ""))) + (let ((newsym (semantic-lex-spp-symbol-merge txt))) (semantic-lex-push-token (semantic-lex-token 'symbol beg end newsym)) )) @@ -637,6 +631,27 @@ and what valid VAL values are." (semantic-lex-spp-symbol-pop A)) )) +(defun semantic-lex-spp-symbol-merge (txt) + "Merge the tokens listed in TXT. +TXT might contain further 'spp-symbol-merge, which will +be merged recursively." + ;; We need to merge the tokens in the 'text segment together, + ;; and produce a single symbol from it. + (mapconcat (lambda (tok) + (cond + ((eq (car tok) 'symbol) + (semantic-lex-spp-one-token-to-txt tok)) + ((eq (car tok) 'spp-symbol-merge) + ;; Call recursively for multiple merges, like + ;; #define FOO(a) foo##a##bar + (semantic-lex-spp-symbol-merge (cadr tok))) + (t + (message "Invalid merge macro ecountered; \ +will return empty string instead.") + ""))) + txt + "")) + ;;; Macro Merging ;; ;; Used when token streams from different macros include each other. @@ -869,7 +884,14 @@ Parsing starts inside the parens, and ends at the end of TOKEN." (forward-char 1) (setq fresh-toks (semantic-lex-spp-stream-for-macro (1- end))) (dolist (tok fresh-toks) - (when (memq (semantic-lex-token-class tok) '(symbol semantic-list)) + ;; march 2011: This is too restrictive! For example "void" + ;; can't get through. What elements was I trying to expunge + ;; to put this in here in the first place? If I comment it + ;; out, does anything new break? + ;(when (memq (semantic-lex-token-class tok) '(symbol semantic-list)) + ;; It appears the commas need to be dumped. perhaps this is better, + ;; but will it cause more problems later? + (unless (eq (semantic-lex-token-class tok) 'punctuation) (setq toks (cons tok toks)))) (nreverse toks))))) @@ -890,6 +912,7 @@ and variable state from the current buffer." (fresh-toks nil) (toks nil) (origbuff (current-buffer)) + (analyzer semantic-lex-analyzer) (important-vars '(semantic-lex-spp-macro-symbol-obarray semantic-lex-spp-project-macro-symbol-obarray semantic-lex-spp-dynamic-macro-symbol-obarray @@ -913,6 +936,11 @@ and variable state from the current buffer." ;; Hack in mode-local (activate-mode-local-bindings) + ;; Call the major mode's setup function + (let ((entry (assq major-mode semantic-new-buffer-setup-functions))) + (when entry + (funcall (cdr entry)))) + ;; 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. diff --git a/lisp/cedet/semantic/lex.el b/lisp/cedet/semantic/lex.el index e47cc1eaee9..d7ab5911a67 100644 --- a/lisp/cedet/semantic/lex.el +++ b/lisp/cedet/semantic/lex.el @@ -691,20 +691,6 @@ Return the overlay." (semantic-overlay-put o 'face 'highlight) o)) -(defsubst semantic-lex-debug-break (token) - "Break during lexical analysis at TOKEN." - (when semantic-lex-debug - (let ((o nil)) - (unwind-protect - (progn - (when token - (setq o (semantic-lex-highlight-token token))) - (semantic-read-event - (format "%S :: SPC - continue" token)) - ) - (when o - (semantic-overlay-delete o)))))) - ;;; Lexical analyzer creation ;; ;; Code for creating a lex function from lists of analyzers. @@ -754,6 +740,20 @@ a LOCAL option.") ;;(defvar semantic-lex-timeout 5 ;; "*Number of sections of lexing before giving up.") +(defsubst semantic-lex-debug-break (token) + "Break during lexical analysis at TOKEN." + (when semantic-lex-debug + (let ((o nil)) + (unwind-protect + (progn + (when token + (setq o (semantic-lex-highlight-token token))) + (semantic-read-event + (format "%S :: Depth: %d :: SPC - continue" token semantic-lex-current-depth)) + ) + (when o + (semantic-overlay-delete o)))))) + (defmacro define-lex (name doc &rest analyzers) "Create a new lexical analyzer with NAME. DOC is a documentation string describing this analyzer. @@ -1205,11 +1205,13 @@ symbols returned in open and close tokens." )) )) ((setq match (assoc text ',clist)) - (setq semantic-lex-current-depth (1- semantic-lex-current-depth)) - (semantic-lex-push-token - (semantic-lex-token - (nth 1 match) - (match-beginning 0) (match-end 0))))))) + (if (> semantic-lex-current-depth 0) + (progn + (setq semantic-lex-current-depth (1- semantic-lex-current-depth)) + (semantic-lex-push-token + (semantic-lex-token + (nth 1 match) + (match-beginning 0) (match-end 0))))))))) ))) ;;; Analyzers diff --git a/lisp/cedet/semantic/mru-bookmark.el b/lisp/cedet/semantic/mru-bookmark.el index 4216e099857..d042ba42582 100644 --- a/lisp/cedet/semantic/mru-bookmark.el +++ b/lisp/cedet/semantic/mru-bookmark.el @@ -53,6 +53,7 @@ (declare-function data-debug-new-buffer "data-debug") (declare-function data-debug-insert-object-slots "eieio-datadebug") (declare-function semantic-momentary-highlight-tag "semantic/decorate") +(declare-function semantic-tag-similar-p "semantic/tag-ls") ;;; TRACKING CORE ;; diff --git a/lisp/cedet/semantic/scope.el b/lisp/cedet/semantic/scope.el index c5b07b9d440..0882120fc65 100644 --- a/lisp/cedet/semantic/scope.el +++ b/lisp/cedet/semantic/scope.el @@ -56,6 +56,7 @@ (declare-function semantic-analyze-princ-sequence "semantic/analyze") (declare-function semanticdb-typecache-merge-streams "semantic/db-typecache") (declare-function semanticdb-typecache-add-dependant "semantic/db-typecache") +(declare-function semantic-tag-similar-p "semantic/tag-ls") ;;; Code: @@ -158,7 +159,7 @@ If nil, then the typescope is reset." ;; tag can be passed in and a scope derived from it. (defun semantic-scope-tag-clone-with-scope (tag scopetags) - "Close TAG, and return it. Add SCOPETAGS as a tag-local scope. + "Clone TAG, and return it. Add SCOPETAGS as a tag-local scope. Stores the SCOPETAGS as a set of tag properties on the cloned tag." (let ((clone (semantic-tag-clone tag)) ) @@ -197,7 +198,7 @@ Use `semantic-ctxt-scoped-types' to find types." (semanticdb-typecache-find (car sp))) ;(semantic-analyze-find-tag (car sp) 'type)) ((semantic-tag-p (car sp)) - (if (semantic-analyze-tag-prototype-p (car sp)) + (if (semantic-tag-prototype-p (car sp)) (semanticdb-typecache-find (semantic-tag-name (car sp))) ;;(semantic-analyze-find-tag (semantic-tag-name (car sp)) 'type) (car sp))) @@ -271,9 +272,11 @@ are from nesting data types." (setq stack (reverse stack)) ;; Add things to STACK until we cease finding tags of class type. (while (and stack (eq (semantic-tag-class (car stack)) 'type)) - ;; Otherwise, just add this to the returnlist. - (setq returnlist (cons (car stack) returnlist)) - (setq stack (cdr stack))) + ;; Otherwise, just add this to the returnlist, but make + ;; sure we didn't already have that tag in scopetypes + (unless (member (car stack) scopetypes) + (setq returnlist (cons (car stack) returnlist))) + (setq stack (cdr stack))) (setq returnlist (nreverse returnlist)) )) diff --git a/lisp/cedet/semantic/symref.el b/lisp/cedet/semantic/symref.el index 1c8063134d6..540c766cc94 100644 --- a/lisp/cedet/semantic/symref.el +++ b/lisp/cedet/semantic/symref.el @@ -185,7 +185,7 @@ to perform the search. This was added for use by a test harness." ;;;###autoload (defun semantic-symref-find-tags-by-name (name &optional scope) - "Find a list of references to NAME in the current project. + "Find a list of tags by NAME in the current project. Optional SCOPE specifies which file set to search. Defaults to 'project. Refers to `semantic-symref-tool', to determine the reference tool to use for the current buffer. @@ -389,9 +389,11 @@ already." (forward-line (1- line)) ;; Search forward for the matching text - (re-search-forward (regexp-quote txt) - (point-at-eol) - t) + (when (re-search-forward (regexp-quote txt) + (point-at-eol) + t) + (goto-char (match-beginning 0)) + ) (setq tag (semantic-current-tag)) diff --git a/lisp/cedet/semantic/symref/filter.el b/lisp/cedet/semantic/symref/filter.el index 57d628b2681..c294fd1727e 100644 --- a/lisp/cedet/semantic/symref/filter.el +++ b/lisp/cedet/semantic/symref/filter.el @@ -85,6 +85,27 @@ Search occurs in the current buffer between START and END." (funcall hookfcn start end prefix))))) (point))))))) +(defun semantic-symref-test-count-hits-in-tag () + "Lookup in the current tag the symbol under point. +the count all the other references to the same symbol within the +tag that contains point, and return that." + (interactive) + (let* ((ctxt (semantic-analyze-current-context)) + (target (car (reverse (oref ctxt prefix)))) + (tag (semantic-current-tag)) + (start (current-time)) + (Lcount 0)) + (when (semantic-tag-p target) + (semantic-symref-hits-in-region + target (lambda (start end prefix) (setq Lcount (1+ Lcount))) + (semantic-tag-start tag) + (semantic-tag-end tag)) + (when (called-interactively-p 'interactive) + (message "Found %d occurances of %s in %.2f seconds" + Lcount (semantic-tag-name target) + (semantic-elapsed-time start (current-time)))) + Lcount))) + (defun semantic-symref-rename-local-variable () "Fancy way to rename the local variable under point. Depends on the SRecode Field editing API." diff --git a/lisp/cedet/semantic/symref/list.el b/lisp/cedet/semantic/symref/list.el index 9a3cb1f524a..55ccf1c103f 100644 --- a/lisp/cedet/semantic/symref/list.el +++ b/lisp/cedet/semantic/symref/list.el @@ -120,6 +120,7 @@ Display the references in`semantic-symref-results-mode'." (defvar semantic-symref-results-mode-map (let ((km (make-sparse-keymap))) + (suppress-keymap km) (define-key km "\C-i" 'forward-button) (define-key km "\M-C-i" 'backward-button) (define-key km " " 'push-button) diff --git a/lisp/cedet/semantic/tag-ls.el b/lisp/cedet/semantic/tag-ls.el index e4c248934c3..d6d2c203aa8 100644 --- a/lisp/cedet/semantic/tag-ls.el +++ b/lisp/cedet/semantic/tag-ls.el @@ -30,9 +30,217 @@ ;; the information. (require 'semantic) +(require 'semantic/find) ;;; Code: +;;; TAG SIMILARITY: +;; +;; Two tags that represent the same thing are "similar", but not the "same". +;; Similar tags might have the same name, but one is a :prototype, while +;; the other is an implementation. +;; +;; Each language will have different things that can be ignored +;; between two "similar" tags, so similarity checks involve a series +;; of mode overridable features. Some are "internal" features. +(defvar semantic-tag-similar-ignorable-attributes '(:prototype-flag) + "The tag attributes that can be ignored during a similarity test.") + +(define-overloadable-function semantic--tag-similar-names-p (tag1 tag2 blankok) + "Compare the names of TAG1 and TAG2. +If BLANKOK is false, then the names must exactly match. +If BLANKOK is true, then if either of TAG1 or TAG2 has blank +names, then that is ok, and this returns true, but if they both +have values, they must still match.") + +(defun semantic--tag-similar-names-p-default (tag1 tag2 blankok) + "Compare the names of TAG1 and TAG2. +If BLANKOK is false, then the names must exactly match. +If BLANKOK is true, then if either of TAG1 or TAG2 has blank +names, then that is ok, and this returns true, but if they both +have values, they must still match." + (let ((n1 (semantic-tag-name tag1)) + (n2 (semantic-tag-name tag2))) + (or (and blankok (or (null n1) (null n2) (string= n1 "") (string= n2 ""))) + (string= n1 n2)))) + +(define-overloadable-function semantic--tag-similar-types-p (tag1 tag2) + "Compare the types of TAG1 and TAG2. +This functions can be overriden, for example to compare a fully +qualified with an unqualified type." + (cond + ((and (null (semantic-tag-type tag1)) + (null (semantic-tag-type tag2))) + t) + ((or (null (semantic-tag-type tag1)) + (null (semantic-tag-type tag2))) + nil) + (t + (:override)))) + +(defun semantic--tag-similar-types-p-default (tag1 tag2) + "Compare the types of TAG1 and TAG2. +This functions can be overriden, for example to compare a fully +qualified with an unqualified type." + (semantic-tag-of-type-p tag1 (semantic-tag-type tag2))) + +(define-overloadable-function semantic--tag-attribute-similar-p (attr value1 value2 ignorable-attributes) + "Test to see if attribute ATTR is similar for VALUE1 and VALUE2. +IGNORABLE-ATTRIBUTES is described in `semantic-tag-similar-p'. +This function is internal, but allows customization of `semantic-tag-similar-p' +for a given mode at a more granular level. + +Note that :type, :name, and anything in IGNORABLE-ATTRIBUTES will +not be passed to this function. + +Modes that override this function can call `semantic--tag-attribute-similar-p-default' +to do the default equality tests if ATTR is not special for that mode.") + +(defun semantic--tag-attribute-similar-p-default (attr value1 value2 ignorable-attributes) + "For ATTR, VALUE1, VALUE2 and IGNORABLE-ATTRIBUTES, test for similarness." + (cond + ;; Tag sublists require special testing. + ((and (listp value1) (semantic-tag-p (car value1)) + (listp value2) (semantic-tag-p (car value2))) + (let ((ans t) + (taglist1 value1) + (taglist2 value2)) + (when (not (eq (length taglist1) (length taglist2))) + (setq ans nil)) + (while (and ans taglist1 taglist2) + (setq ans (apply 'semantic-tag-similar-p + (car taglist1) (car taglist2) + ignorable-attributes) + taglist1 (cdr taglist1) + taglist2 (cdr taglist2))) + ans)) + + ;; The attributes are not the same? + ((not (equal value1 value2)) + nil) + + (t t)) + ) + +(define-overloadable-function semantic-tag-similar-p (tag1 tag2 &rest ignorable-attributes) + "Test to see if TAG1 and TAG2 are similar. +Two tags are similar if their name, datatype, and various attributes +are the same. + +Similar tags that have sub-tags such as arg lists or type members, +are similar w/out checking the sub-list of tags. +Optional argument IGNORABLE-ATTRIBUTES are attributes to ignore while comparing similarity. +By default, `semantic-tag-similar-ignorable-attributes' is referenced for +attributes, and IGNOREABLE-ATTRIBUTES will augment this list. + +Note that even though :name is not an attribute, it can be used to +to indicate lax comparison of names via `semantic--tag-similar-names-p'") + +;; Note: optional thing is because overloadable fcns don't handle this +;; quite right. +(defun semantic-tag-similar-p-default (tag1 tag2 &optional ignorable-attributes) + "Test to see if TAG1 and TAG2 are similar. +Two tags are similar if their name, datatype, and various attributes +are the same. + +IGNORABLE-ATTRIBUTES are tag attributes that can be ignored. + +See `semantic-tag-similar-p' for details." + (let* ((ignore (append ignorable-attributes semantic-tag-similar-ignorable-attributes)) + (A1 (and (semantic--tag-similar-names-p tag1 tag2 (memq :name ignore)) + (semantic--tag-similar-types-p tag1 tag2) + (semantic-tag-of-class-p tag1 (semantic-tag-class tag2)))) + (attr1 (semantic-tag-attributes tag1)) + (attr2 (semantic-tag-attributes tag2)) + (A2 t) + (A3 t) + ) + ;; Test if there are non-ignorable attributes in A2 which are not present in A1 + (while (and A2 attr2) + (let ((a (car attr2))) + (unless (or (eq a :type) (memq a ignore)) + (setq A2 (semantic-tag-get-attribute tag1 a))) + (setq attr2 (cdr (cdr attr2))))) + (while (and A2 attr1 A3) + (let ((a (car attr1))) + + (cond ((or (eq a :type) ;; already tested above. + (memq a ignore)) ;; Ignore them... + nil) + + (t + (setq A3 + (semantic--tag-attribute-similar-p + a (car (cdr attr1)) (semantic-tag-get-attribute tag2 a) + ignorable-attributes))) + )) + (setq attr1 (cdr (cdr attr1)))) + (and A1 A2 A3))) + +;;; FULL NAMES +;; +;; For programmer convenience, a full name is not specified in source +;; code. Instead some abbreviation is made, and the local environment +;; will contain the info needed to determine the full name. +(define-overloadable-function semantic-tag-full-package (tag &optional stream-or-buffer) + "Return the fully qualified package name of TAG in a package hierarchy. +STREAM-OR-BUFFER can be anything convertible by `semantic-something-to-stream', +but must be a toplevel semantic tag stream that contains TAG. +A Package Hierarchy is defined in UML by the way classes and methods +are organized on disk. Some languages use this concept such that a +class can be accessed via it's fully qualified name, (such as Java.) +Other languages qualify names within a Namespace (such as C++) which +result in a different package like structure. + +Languages which do not override this function will just search the +stream for a tag of class 'package, and return that." + (let ((stream (semantic-something-to-tag-table + (or stream-or-buffer tag)))) + (:override-with-args (tag stream)))) + +(defun semantic-tag-full-package-default (tag stream) + "Default method for `semantic-tag-full-package' for TAG. +Return the name of the first tag of class `package' in STREAM." + (let ((pack (car-safe (semantic-find-tags-by-class 'package stream)))) + (when (and pack (semantic-tag-p pack)) + (semantic-tag-name pack)))) + +(define-overloadable-function semantic-tag-full-name (tag &optional stream-or-buffer) + "Return the fully qualified name of TAG in the package hierarchy. +STREAM-OR-BUFFER can be anything convertable by `semantic-something-to-stream', +but must be a toplevel semantic tag stream that contains TAG. +A Package Hierarchy is defined in UML by the way classes and methods +are organized on disk. Some languages use this concept such that a +class can be accessed via it's fully qualified name, (such as Java.) +Other languages qualify names within a Namespace (such as C++) which +result in a different package like structure. + +Languages which do not override this function with +`tag-full-name' will combine `semantic-tag-full-package' and +`semantic-tag-name', separated with language separator character. +Override functions only need to handle STREAM-OR-BUFFER with a +tag stream value, or nil. + +TODO - this function should probably also take a PARENT to TAG to +resolve issues where a method in a class in a package is present." + (let ((stream (semantic-something-to-tag-table + (or stream-or-buffer tag)))) + (:override-with-args (tag stream)))) + +(make-obsolete-overload 'semantic-nonterminal-full-name + 'semantic-tag-full-name "23.2") + +(defun semantic-tag-full-name-default (tag stream) + "Default method for `semantic-tag-full-name'. +Return the name of TAG found in the toplevel STREAM." + (let ((pack (semantic-tag-full-package tag stream)) + (name (semantic-tag-name tag))) + (if pack + (concat pack + (car semantic-type-relation-separator-character) + name) + name))) + ;;; UML features: ;; ;; UML can represent several types of features of a tag @@ -93,10 +301,38 @@ See `semantic-tag-protection'." ((string= s "private") 'private) ((string= s "protected") - 'protected))))) + 'protected) + ((string= s "package") + 'package) + )))) (setq mods (cdr mods))) prot)) +(defun semantic-tag-package-protected-p (tag &optional parent currentpackage) + "Non-nil if TAG is not available via package access control. +For languages (such as Java) where a method is package protected, +this method will return nil if TAG, as found in PARENT is available +for access from a file in CURRENTPACKAGE. +If TAG is not protected by PACKAGE, also return t. Use +`semantic-tag-protected-p' instead. +If PARENT is not provided, it will be derived when passed to +`semantic-tag-protection'. +If CURRENTPACKAGE is not provided, it will be derived from the current +buffer." + (let ((tagpro (semantic-tag-protection tag parent))) + (if (not (eq tagpro 'package)) + t ;; protected + + ;; package protection, so check currentpackage. + ;; Deriving the package is better from the parent, as TAG is + ;; probably a field or method. + (if (not currentpackage) + (setq currentpackage (semantic-tag-full-package nil (current-buffer)))) + (let ((tagpack (semantic-tag-full-package (or parent tag)))) + (if (string= currentpackage tagpack) + nil + t)) ))) + (defun semantic-tag-protected-p (tag protection &optional parent) "Non-nil if TAG is protected. PROTECTION is a symbol which can be returned by the method @@ -213,36 +449,6 @@ something without an implementation." (t nil)) )) -;;; FULL NAMES -;; -;; For programmer convenience, a full name is not specified in source -;; code. Instead some abbreviation is made, and the local environment -;; will contain the info needed to determine the full name. - -(define-overloadable-function semantic-tag-full-name (tag &optional stream-or-buffer) - "Return the fully qualified name of TAG in the package hierarchy. -STREAM-OR-BUFFER can be anything convertible by `semantic-something-to-stream', -but must be a toplevel semantic tag stream that contains TAG. -A Package Hierarchy is defined in UML by the way classes and methods -are organized on disk. Some language use this concept such that a -class can be accessed via it's fully qualified name, (such as Java.) -Other languages qualify names within a Namespace (such as C++) which -result in a different package like structure. Languages which do not -override this function with `tag-full-name' will use -`semantic-tag-name'. Override functions only need to handle -STREAM-OR-BUFFER with a tag stream value, or nil." - (let ((stream (semantic-something-to-tag-table - (or stream-or-buffer tag)))) - (:override-with-args (tag stream)))) - -(make-obsolete-overload 'semantic-nonterminal-full-name - 'semantic-tag-full-name "23.2") - -(defun semantic-tag-full-name-default (tag stream) - "Default method for `semantic-tag-full-name'. -Return the name of TAG found in the toplevel STREAM." - (semantic-tag-name tag)) - (provide 'semantic/tag-ls) ;; Local variables: diff --git a/lisp/cedet/semantic/tag-write.el b/lisp/cedet/semantic/tag-write.el index 757609fac3f..69d26245850 100644 --- a/lisp/cedet/semantic/tag-write.el +++ b/lisp/cedet/semantic/tag-write.el @@ -41,12 +41,12 @@ INDENT is the amount of indentation to use for this tag." (signal 'wrong-type-argument (list tag 'semantic-tag-p))) (when (not indent) (setq indent 0)) ;(princ (make-string indent ? )) - (princ "(\"") + (princ "(") ;; Base parts (let ((name (semantic-tag-name tag)) (class (semantic-tag-class tag))) - (princ name) - (princ "\" ") + (prin1 name) + (princ " ") (princ (symbol-name class)) ) (let ((attr (semantic-tag-attributes tag)) diff --git a/lisp/cedet/semantic/tag.el b/lisp/cedet/semantic/tag.el index 29e83cd558b..08fe467b367 100644 --- a/lisp/cedet/semantic/tag.el +++ b/lisp/cedet/semantic/tag.el @@ -51,6 +51,7 @@ (declare-function semantic-analyze-split-name "semantic/analyze/fcn") (declare-function semantic-fetch-tags "semantic") (declare-function semantic-clear-toplevel-cache "semantic") +(declare-function semantic-tag-similar-p "semantic/tag-ls") (defconst semantic-tag-version "2.0" "Version string of semantic tags made with this code.") @@ -362,45 +363,6 @@ of different cons cells." (equal (semantic-tag-bounds tag1) (semantic-tag-bounds tag2)))))) -(defun semantic-tag-similar-p (tag1 tag2 &rest ignorable-attributes) - "Test to see if TAG1 and TAG2 are similar. -Two tags are similar if their name, datatype, and various attributes -are the same. - -Similar tags that have sub-tags such as arg lists or type members, -are similar w/out checking the sub-list of tags. -Optional argument IGNORABLE-ATTRIBUTES are attributes to ignore while comparing similarity." - (let* ((A1 (and (equal (semantic-tag-name tag1) (semantic-tag-name tag2)) - (semantic-tag-of-class-p tag1 (semantic-tag-class tag2)) - (semantic-tag-of-type-p tag1 (semantic-tag-type tag2)))) - (attr1 (semantic-tag-attributes tag1)) - (A2 (= (length attr1) (length (semantic-tag-attributes tag2)))) - (A3 t) - ) - (when (and (not A2) ignorable-attributes) - (setq A2 t)) - (while (and A2 attr1 A3) - (let ((a (car attr1)) - (v (car (cdr attr1)))) - - (cond ((or (eq a :type) ;; already tested above. - (memq a ignorable-attributes)) ;; Ignore them... - nil) - - ;; Don't test sublists of tags - ((and (listp v) (semantic-tag-p (car v))) - nil) - - ;; The attributes are not the same? - ((not (equal v (semantic-tag-get-attribute tag2 a))) - (setq A3 nil)) - (t - nil)) - ) - (setq attr1 (cdr (cdr attr1)))) - - (and A1 A2 A3) - )) (defun semantic-tag-similar-with-subtags-p (tag1 tag2 &rest ignorable-attributes) "Test to see if TAG1 and TAG2 are similar. @@ -408,28 +370,8 @@ Uses `semantic-tag-similar-p' but also recurses through sub-tags, such as argument lists and type members. Optional argument IGNORABLE-ATTRIBUTES is passed down to `semantic-tag-similar-p'." - (let ((C1 (semantic-tag-components tag1)) - (C2 (semantic-tag-components tag2)) - ) - (if (or (/= (length C1) (length C2)) - (not (semantic-tag-similar-p tag1 tag2 ignorable-attributes)) - ) - ;; Basic test fails. - nil - ;; Else, check component lists. - (catch 'component-dissimilar - (while C1 - - (if (not (semantic-tag-similar-with-subtags-p - (car C1) (car C2) ignorable-attributes)) - (throw 'component-dissimilar nil)) - - (setq C1 (cdr C1)) - (setq C2 (cdr C2)) - ) - ;; If we made it this far, we are ok. - t) ))) - + ;; DEPRECATE THIS. + (semantic-tag-similar-p tag1 tag2 ignorable-attributes)) (defun semantic-tag-of-type-p (tag type) "Compare TAG's type against TYPE. Non nil if equivalent. @@ -612,6 +554,51 @@ You can identify a faux tag with `semantic-tag-faux-p'" "Set TAG name to NAME." (setcar tag name)) +;;; TAG Proxys +;; +;; A new kind of tag is a TAG PROXY. These are tags that have some +;; minimal number of features set, such as name and class, but have a +;; marker in them that indicates how to complete them. +;; +;; To make the tags easier to view, the proxy is stored as custom +;; symbol that is not in the global obarray, but has properties set on +;; it. This prevents saving of massive amounts of proxy data. +(defun semantic-create-tag-proxy (function data) + "Create a tag proxy symbol. +FUNCTION will be used to resolve the proxy. It should take 3 +two arguments, DATA and TAG. TAG is a proxy tag that needs +to be resolved, and DATA is the DATA passed into this function. +DATA is data to help resolve the proxy. DATA can be an EIEIO object, +such that FUNCTION is a method. +FUNCTION should return a list of tags, preferrably one tag." + (let ((sym (make-symbol ":tag-proxy"))) + (put sym 'proxy-function function) + (put sym 'proxy-data data) + sym)) + +(defun semantic-tag-set-proxy (tag proxy &optional filename) + "Set TAG to be a proxy. The proxy can be resolved with PROXY. +This function will also make TAG be a faux tag with +`semantic-tag-set-faux', and possibly set the tag's +:filename with FILENAME. +To create a proxy, see `semantic-create-tag-proxy'." + (semantic-tag-set-faux tag) + (semantic--tag-put-property tag :proxy proxy) + (when filename + (semantic--tag-put-property tag :filename filename))) + +(defun semantic-tag-resolve-proxy (tag) + "Resolve the proxy in TAG. +The return value is whatever format the proxy was setup as. +It should be a list of complete tags. +If TAG has no proxy, then just return tag." + (let* ((proxy (semantic--tag-get-property tag :proxy)) + (function (get proxy 'proxy-function)) + (data (get proxy 'proxy-data))) + (if proxy + (funcall function data tag) + tag))) + ;;; Copying and cloning tags. ;; (defsubst semantic-tag-clone (tag &optional name) @@ -1350,6 +1337,7 @@ of parent classes. The `cdr' of the list is the list of interfaces, or abstract classes which are parents of TAG." (cons (semantic-tag-get-attribute tag :superclasses) (semantic-tag-type-interfaces tag))) + (make-obsolete 'semantic-token-type-parent "\ use `semantic-tag-type-superclass' \ diff --git a/lisp/cedet/semantic/texi.el b/lisp/cedet/semantic/texi.el index 36c14ce7c2a..9380940282f 100644 --- a/lisp/cedet/semantic/texi.el +++ b/lisp/cedet/semantic/texi.el @@ -451,6 +451,7 @@ that start with that symbol." (defvar semantic-imenu-bucketize-file) (defvar semantic-imenu-bucketize-type-members) +;;;###autoload (defun semantic-default-texi-setup () "Set up a buffer for parsing of Texinfo files." ;; This will use our parser. @@ -687,4 +688,9 @@ If TAG is nil, it is derived from the deffn under POINT." (provide 'semantic/texi) +;; Local variables: +;; generated-autoload-file: "loaddefs.el" +;; generated-autoload-load-name: "semantic/texi" +;; End: + ;;; semantic/texi.el ends here diff --git a/lisp/cedet/semantic/util.el b/lisp/cedet/semantic/util.el index 1cc4d898a34..65201c4fd12 100644 --- a/lisp/cedet/semantic/util.el +++ b/lisp/cedet/semantic/util.el @@ -298,6 +298,7 @@ If TAG is not specified, use the tag at point." semantic-dump-parse semantic-type-relation-separator-character semantic-command-separation-character + semantic-new-buffer-fcn-was-run ))) (dolist (V vars) (semantic-describe-buffer-var-helper V buff))) diff --git a/lisp/cedet/semantic/wisent/comp.el b/lisp/cedet/semantic/wisent/comp.el index 30dbafaa6cc..388c8f332a4 100644 --- a/lisp/cedet/semantic/wisent/comp.el +++ b/lisp/cedet/semantic/wisent/comp.el @@ -134,8 +134,11 @@ If optional LEFT is non-nil insert spaces on left." ;;;; ------------------------ (defconst wisent-BITS-PER-WORD - (let ((i 1)) - (while (not (zerop (lsh 1 i))) + (let ((i 1) + (do-shift (if (boundp 'most-positive-fixnum) + (lambda (i) (lsh most-positive-fixnum (- i))) + (lambda (i) (lsh 1 i))))) + (while (not (zerop (funcall do-shift i))) (setq i (1+ i))) i)) @@ -3539,4 +3542,12 @@ See also `wisent-compile-grammar' for more details on AUTOMATON." (provide 'semantic/wisent/comp) +;; Disable messages with regards to lexical scoping, since this will +;; produce a bunch of 'lacks a prefix' warnings with the +;; `wisent-defcontext' trickery above. + +;; Local variables: +;; byte-compile-warnings: (not lexical) +;; End: + ;;; semantic/wisent/comp.el ends here diff --git a/lisp/cedet/semantic/wisent/java-tags.el b/lisp/cedet/semantic/wisent/java-tags.el index 6bdc2736b1b..a85935ad83b 100644 --- a/lisp/cedet/semantic/wisent/java-tags.el +++ b/lisp/cedet/semantic/wisent/java-tags.el @@ -59,6 +59,7 @@ Parse the current context for `field_declaration' nonterminals to collect tags, such as local variables or prototypes. This function override `get-local-variables'." (let ((vars nil) + (ct (semantic-current-tag)) ;; We want nothing to do with funny syntaxing while doing this. (semantic-unmatched-syntax-hook nil)) (while (not (semantic-up-context (point) 'function)) @@ -71,8 +72,31 @@ This function override `get-local-variables'." 'field_declaration 0 t) vars)))) + ;; Add 'this' if in a fcn + (when (semantic-tag-of-class-p ct 'function) + ;; Append a new tag THIS into our space. + (setq vars (cons (semantic-tag-new-variable + "this" (semantic-tag-name (semantic-current-tag-parent)) + nil) + vars))) vars)) +;;; +;;; Analyzer and type cache support +;;; +(define-mode-local-override semantic-analyze-split-name java-mode (name) + "Split up tag names on colon . boundaries." + (let ((ans (split-string name "\\."))) + (if (= (length ans) 1) + name + (delete "" ans)))) + +(define-mode-local-override semantic-analyze-unsplit-name java-mode (namelist) + "Assemble the list of names NAMELIST into a namespace name." + (mapconcat 'identity namelist ".")) + + + ;;;; ;;;; Semantic integration of the Java LALR parser ;;;; @@ -109,6 +133,10 @@ Use the alternate LALR(1) parser." (package . "Package"))) ;; navigation inside 'type children senator-step-at-tag-classes '(function variable) + ;; Remove 'recursive from the default semanticdb find throttle + ;; since java imports never recurse. + semanticdb-find-default-throttle + (remq 'recursive (default-value 'semanticdb-find-default-throttle)) ) ;; Setup javadoc stuff (semantic-java-doc-setup)) diff --git a/lisp/cedet/semantic/wisent/javascript.el b/lisp/cedet/semantic/wisent/javascript.el index 8ed83e87bce..610df0edc86 100644 --- a/lisp/cedet/semantic/wisent/javascript.el +++ b/lisp/cedet/semantic/wisent/javascript.el @@ -51,8 +51,8 @@ to this variable NAME." start (if elts (car (cddr elt)) (semantic-tag-start tag)) end (if xpand (cdr (cddr elt)) (semantic-tag-end tag)) xpand (cons clone xpand)) - ;; Set the definition of the cloned tag - (semantic-tag-put-attribute clone :default-value value) + ;; Set the definition of the cloned tag + (semantic-tag-put-attribute clone :default-value value) ;; Set the bounds of the cloned tag with those of the name ;; element. (semantic-tag-set-bounds clone start end)) @@ -70,10 +70,56 @@ This function overrides `get-local-variables'." ;; Does javascript have identifiable local variables? nil) +(define-mode-local-override semantic-tag-protection javascript-mode (tag &optional parent) + "Return protection information about TAG with optional PARENT. +This function returns on of the following symbols: + nil - No special protection. Language dependent. + 'public - Anyone can access this TAG. + 'private - Only methods in the local scope can access TAG. + 'protected - Like private for outside scopes, like public for child + classes. +Some languages may choose to provide additional return symbols specific +to themselves. Use of this function should allow for this. + +The default behavior (if not overridden with `tag-protection' +is to return a symbol based on type modifiers." + nil) + +(define-mode-local-override semantic-analyze-scope-calculate-access javascript-mode (type scope) + "Calculate the access class for TYPE as defined by the current SCOPE. +Access is related to the :parents in SCOPE. If type is a member of SCOPE +then access would be 'private. If TYPE is inherited by a member of SCOPE, +the access would be 'protected. Otherwise, access is 'public." + nil) +(define-mode-local-override semantic-ctxt-current-symbol javascript-mode (&optional point) + "Return the current symbol the cursor is on at POINT in a list. +This is a very simple implementation for Javascript symbols. It +will at maximum do one split, so that the first part is seen as +one type. For example: $('#sel').foo.bar will return (\"$('sel').foo\" \"bar\"). +This is currently needed for the mozrepl omniscient database." + (save-excursion + (if point (goto-char point)) + (let* ((case-fold-search semantic-case-fold) + symlist tmp end) + (with-syntax-table semantic-lex-syntax-table + (save-excursion + (when (looking-at "\\w\\|\\s_") + (forward-sexp 1)) + (setq end (point)) + (unless (re-search-backward "\\s-" (point-at-bol) t) + (beginning-of-line)) + (setq tmp (buffer-substring-no-properties (point) end)) + (if (string-match "\\(.+\\)\\." tmp) + (setq symlist (list (match-string 1 tmp) + (substring tmp (1+ (match-end 1)) (length tmp)))) + (setq symlist (list tmp)))))))) + ;;; Setup Function ;; -;; This sets up the javascript parser +;; Since javascript-mode is an alias for js-mode, let it inherit all +;; the overrides. +(define-child-mode js-mode javascript-mode) ;; Since javascript-mode is an alias for js-mode, let it inherit all ;; the overrides. diff --git a/lisp/cedet/semantic/wisent/javat-wy.el b/lisp/cedet/semantic/wisent/javat-wy.el Binary files differindex 1f0a480d554..01f80d3c598 100644 --- a/lisp/cedet/semantic/wisent/javat-wy.el +++ b/lisp/cedet/semantic/wisent/javat-wy.el diff --git a/lisp/cedet/semantic/wisent/js-wy.el b/lisp/cedet/semantic/wisent/js-wy.el index 05346b02c8d..92c5aa6b0d2 100644 --- a/lisp/cedet/semantic/wisent/js-wy.el +++ b/lisp/cedet/semantic/wisent/js-wy.el @@ -60,6 +60,7 @@ ;;; Code: (require 'semantic/lex) +(eval-when-compile (require 'semantic/bovine)) ;;; Prologue ;; @@ -416,6 +417,29 @@ ;;; Analyzers +;; +(define-lex-block-type-analyzer wisent-javascript-jv-wy--<block>-block-analyzer + "block analyzer for <block> tokens." + "\\s(\\|\\s)" + '((("(" OPEN_PARENTHESIS PAREN_BLOCK) + ("{" START_BLOCK BRACE_BLOCK) + ("[" OPEN_SQ_BRACKETS BRACK_BLOCK)) + (")" CLOSE_PARENTHESIS) + ("}" END_BLOCK) + ("]" CLOSE_SQ_BRACKETS)) + ) + +(define-lex-regex-type-analyzer wisent-javascript-jv-wy--<symbol>-regexp-analyzer + "regexp analyzer for <symbol> tokens." + "\\(\\sw\\|\\s_\\)+" + nil + 'VARIABLE) + +(define-lex-regex-type-analyzer wisent-javascript-jv-wy--<number>-regexp-analyzer + "regexp analyzer for <number> tokens." + semantic-lex-number-expression + nil + 'NUMBER) (define-lex-string-type-analyzer wisent-javascript-jv-wy--<punctuation>-string-analyzer "string analyzer for <punctuation> tokens." @@ -462,29 +486,6 @@ (ASSIGN_SYMBOL . "=")) 'punctuation) -(define-lex-block-type-analyzer wisent-javascript-jv-wy--<block>-block-analyzer - "block analyzer for <block> tokens." - "\\s(\\|\\s)" - '((("(" OPEN_PARENTHESIS PAREN_BLOCK) - ("{" START_BLOCK BRACE_BLOCK) - ("[" OPEN_SQ_BRACKETS BRACK_BLOCK)) - (")" CLOSE_PARENTHESIS) - ("}" END_BLOCK) - ("]" CLOSE_SQ_BRACKETS)) - ) - -(define-lex-regex-type-analyzer wisent-javascript-jv-wy--<symbol>-regexp-analyzer - "regexp analyzer for <symbol> tokens." - "\\(\\sw\\|\\s_\\)+" - nil - 'VARIABLE) - -(define-lex-regex-type-analyzer wisent-javascript-jv-wy--<number>-regexp-analyzer - "regexp analyzer for <number> tokens." - semantic-lex-number-expression - nil - 'NUMBER) - (define-lex-sexp-type-analyzer wisent-javascript-jv-wy--<string>-sexp-analyzer "sexp analyzer for <string> tokens." "\\s\"" diff --git a/lisp/cedet/semantic/wisent/python-wy.el b/lisp/cedet/semantic/wisent/python-wy.el index e8229dcd9ea..d215a4b2414 100644 --- a/lisp/cedet/semantic/wisent/python-wy.el +++ b/lisp/cedet/semantic/wisent/python-wy.el @@ -1,6 +1,6 @@ ;;; semantic/wisent/python-wy.el --- Generated parser support file -;; Copyright (C) 2002-2004, 2007, 2010-2012 Free Software Foundation, Inc. +;; Copyright (C) 2002-2012 Free Software Foundation, Inc. ;; Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, ;; 2009, 2010 Python Software Foundation; All Rights Reserved @@ -77,9 +77,12 @@ ;;; Code: (require 'semantic/lex) +(eval-when-compile (require 'semantic/bovine)) ;;; Prologue ;; +(declare-function wisent-python-reconstitute-function-tag "semantic/wisent/python") +(declare-function wisent-python-reconstitute-class-tag "semantic/wisent/python") ;;; Declarations ;; @@ -114,8 +117,10 @@ ("return" . RETURN) ("try" . TRY) ("while" . WHILE) + ("with" . WITH) ("yield" . YIELD)) '(("yield" summary "Create a generator function") + ("with" summary "Start statement with an associated context object") ("while" summary "Start a 'while' loop") ("try" summary "Start of statements protected by exception handlers") ("return" summary "Return from a function") @@ -156,6 +161,7 @@ ("string" (STRING_LITERAL)) ("punctuation" + (AT . "@") (BACKQUOTE . "`") (ASSIGN . "=") (COMMA . ",") @@ -226,7 +232,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 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) + '((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 AT 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 WITH YIELD) nil (goal ((NEWLINE)) @@ -364,8 +370,10 @@ (wisent-raw-tag (semantic-tag-new-include $2 nil)))) (dotted_as_name_list - ((dotted_as_name)) - ((dotted_as_name_list COMMA dotted_as_name))) + ((dotted_as_name_list COMMA dotted_as_name) + (cons $3 $1)) + ((dotted_as_name) + (list $1))) (star_or_import_as_name_list ((MULT) nil) @@ -417,6 +425,7 @@ ((while_stmt)) ((for_stmt)) ((try_stmt)) + ((with_stmt)) ((funcdef)) ((class_declaration))) (if_stmt @@ -476,10 +485,36 @@ (nil) ((test zero_or_one_comma_test) nil)) + (with_stmt + ((WITH test COLON suite) + (wisent-raw-tag + (semantic-tag-new-code $1 nil))) + ((WITH test with_var COLON suite) + (wisent-raw-tag + (semantic-tag-new-code $1 nil)))) + (with_var + ((AS expr) + nil)) + (decorator + ((AT dotted_name varargslist_opt NEWLINE) + (wisent-raw-tag + (semantic-tag-new-function $2 "decorator" $3)))) + (decorators + ((decorator) + (list $1)) + ((decorator decorators) + (cons $1 $2))) (funcdef ((DEF NAME function_parameter_list COLON suite) - (wisent-raw-tag - (semantic-tag-new-function $2 nil $3)))) + (wisent-python-reconstitute-function-tag + (wisent-raw-tag + (semantic-tag-new-function $2 nil $3)) + $5)) + ((decorators DEF NAME function_parameter_list COLON suite) + (wisent-python-reconstitute-function-tag + (wisent-raw-tag + (semantic-tag-new-function $3 nil $4 :decorators $1)) + $6))) (function_parameter_list ((PAREN_BLOCK) (let @@ -505,9 +540,10 @@ (semantic-tag-new-variable $2 nil nil)))) (class_declaration ((CLASS NAME paren_class_list_opt COLON suite) - (wisent-raw-tag - (semantic-tag-new-type $2 $1 $5 - (cons $3 nil))))) + (wisent-python-reconstitute-class-tag + (wisent-raw-tag + (semantic-tag-new-type $2 $1 $5 + (cons $3 nil)))))) (paren_class_list_opt (nil) ((paren_class_list))) @@ -726,7 +762,7 @@ ;;; Analyzers - +;; (define-lex-block-type-analyzer wisent-python-wy--<block>-block-analyzer "block analyzer for <block> tokens." "\\s(\\|\\s)" @@ -738,10 +774,23 @@ ("]" RBRACK)) ) +(define-lex-regex-type-analyzer wisent-python-wy--<symbol>-regexp-analyzer + "regexp analyzer for <symbol> tokens." + "\\(\\sw\\|\\s_\\)+" + nil + 'NAME) + +(define-lex-regex-type-analyzer wisent-python-wy--<number>-regexp-analyzer + "regexp analyzer for <number> tokens." + semantic-lex-number-expression + nil + 'NUMBER_LITERAL) + (define-lex-string-type-analyzer wisent-python-wy--<punctuation>-string-analyzer "string analyzer for <punctuation> tokens." "\\(\\s.\\|\\s$\\|\\s'\\)+" - '((BACKQUOTE . "`") + '((AT . "@") + (BACKQUOTE . "`") (ASSIGN . "=") (COMMA . ",") (SEMICOLON . ";") @@ -781,18 +830,6 @@ (LTLTEQ . "<<=")) 'punctuation) -(define-lex-regex-type-analyzer wisent-python-wy--<symbol>-regexp-analyzer - "regexp analyzer for <symbol> tokens." - "\\(\\sw\\|\\s_\\)+" - nil - 'NAME) - -(define-lex-regex-type-analyzer wisent-python-wy--<number>-regexp-analyzer - "regexp analyzer for <number> tokens." - semantic-lex-number-expression - nil - 'NUMBER_LITERAL) - (define-lex-keyword-type-analyzer wisent-python-wy--<keyword>-keyword-analyzer "keyword analyzer for <keyword> tokens." "\\(\\sw\\|\\s_\\)+") diff --git a/lisp/cedet/semantic/wisent/python.el b/lisp/cedet/semantic/wisent/python.el index fef22b16995..ea603f251bb 100644 --- a/lisp/cedet/semantic/wisent/python.el +++ b/lisp/cedet/semantic/wisent/python.el @@ -28,27 +28,90 @@ ;;; Code: +(require 'rx) + +;; Try to load python support, but fail silently since it is only used +;; for optional functionality +(require 'python nil t) + (require 'semantic/wisent) (require 'semantic/wisent/python-wy) +(require 'semantic/find) (require 'semantic/dep) (require 'semantic/ctxt) +(eval-when-compile + (require 'cl)) + +;;; Customization +;; + +(defun semantic-python-get-system-include-path () + "Evaluate some Python code that determines the system include path." + (python-proc) + (if python-buffer + (with-current-buffer python-buffer + (set (make-local-variable 'python-preoutput-result) nil) + (python-send-string + "import sys; print '_emacs_out ' + '\\0'.join(sys.path)") + (accept-process-output (python-proc) 2) + (if python-preoutput-result + (split-string python-preoutput-result "[\0\n]" t) + ;; Try a second, Python3k compatible shot + (python-send-string + "import sys; print('_emacs_out ' + '\\0'.join(sys.path))") + (accept-process-output (python-proc) 2) + (if python-preoutput-result + (split-string python-preoutput-result "[\0\n]" t) + (message "Timeout while querying Python for system include path.") + nil))) + (message "Python seems to be unavailable on this system."))) + +(defcustom-mode-local-semantic-dependency-system-include-path + python-mode semantic-python-dependency-system-include-path + (when (and (featurep 'python) + ;; python-mode and batch somehow often hangs. + (not noninteractive)) + (semantic-python-get-system-include-path)) + "The system include path used by Python language.") ;;; Lexical analysis ;; ;; Python strings are delimited by either single quotes or double -;; quotes, e.g., "I'm a string" and 'I too am s string'. +;; quotes, e.g., "I'm a string" and 'I too am a string'. ;; In addition a string can have either a 'r' and/or 'u' prefix. ;; The 'r' prefix means raw, i.e., normal backslash substitutions are ;; to be suppressed. For example, r"01\n34" is a string with six ;; characters 0, 1, \, n, 3 and 4. The 'u' prefix means the following ;; string is Unicode. -(defconst wisent-python-string-re - (concat (regexp-opt '("r" "u" "ur" "R" "U" "UR" "Ur" "uR") t) - "?['\"]") +(defconst wisent-python-string-start-re "[uU]?[rR]?['\"]" "Regexp matching beginning of a Python string.") +(defconst wisent-python-string-re + (rx + (opt (any "uU")) (opt (any "rR")) + (or + ;; Triple-quoted string using apostrophes + (: "'''" (zero-or-more (or "\\'" + (not (any "'")) + (: (repeat 1 2 "'") (not (any "'"))))) + "'''") + ;; String using apostrophes + (: "'" (zero-or-more (or "\\'" + (not (any "'")))) + "'") + ;; Triple-quoted string using quotation marks. + (: "\"\"\"" (zero-or-more (or "\\\"" + (not (any "\"")) + (: (repeat 1 2 "\"") (not (any "\""))))) + "\"\"\"") + ;; String using quotation marks. + (: "\"" (zero-or-more (or "\\\"" + (not (any "\"")))) + "\""))) + "Regexp matching a complete Python string.") + (defvar wisent-python-EXPANDING-block nil "Non-nil when expanding a paren block for Python lexical analyzer.") @@ -60,16 +123,46 @@ curly braces." (defsubst wisent-python-forward-string () "Move point at the end of the Python string at point." - (when (looking-at wisent-python-string-re) - ;; skip the prefix - (and (match-end 1) (goto-char (match-end 1))) - ;; skip the quoted part - (cond - ((looking-at "\"\"\"[^\"]") - (search-forward "\"\"\"" nil nil 2)) - ((looking-at "'''[^']") - (search-forward "'''" nil nil 2)) - ((forward-sexp 1))))) + (if (looking-at wisent-python-string-re) + (let ((start (match-beginning 0)) + (end (match-end 0))) + ;; Incomplete triple-quoted string gets matched instead as a + ;; complete single quoted string. (This special case would be + ;; unnecessary if Emacs regular expressions had negative + ;; look-ahead assertions.) + (when (and (= (- end start) 2) + (looking-at "\"\\{3\\}\\|'\\{3\\}")) + (error "unterminated syntax")) + (goto-char end)) + (error "unterminated syntax"))) + +(defun wisent-python-forward-balanced-expression () + "Move point to the end of the balanced expression at point. +Here 'balanced expression' means anything matched by Emacs' +open/close parenthesis syntax classes. We can't use forward-sexp +for this because that Emacs built-in can't parse Python's +triple-quoted string syntax." + (let ((end-char (cdr (syntax-after (point))))) + (forward-char 1) + (while (not (or (eobp) (eq (char-after (point)) end-char))) + (cond + ;; Skip over python strings. + ((looking-at wisent-python-string-start-re) + (wisent-python-forward-string)) + ;; At a comment start just goto end of line. + ((looking-at "\\s<") + (end-of-line)) + ;; Skip over balanced expressions. + ((looking-at "\\s(") + (wisent-python-forward-balanced-expression)) + ;; Skip over white space, word, symbol, punctuation, paired + ;; delimiter (backquote) characters, line continuation, and end + ;; of comment characters (AKA newline characters in Python). + ((zerop (skip-syntax-forward "-w_.$\\>")) + (error "can't figure out how to go forward from here")))) + ;; Skip closing character. As a last resort this should raise an + ;; error if we hit EOB before we find our closing character.. + (forward-char 1))) (defun wisent-python-forward-line () "Move point to the beginning of the next logical line. @@ -83,14 +176,14 @@ line ends at the end of the buffer, leave the point there." (progn (cond ;; Skip over python strings. - ((looking-at wisent-python-string-re) + ((looking-at wisent-python-string-start-re) (wisent-python-forward-string)) ;; At a comment start just goto end of line. ((looking-at "\\s<") (end-of-line)) - ;; Skip over generic lists and strings. - ((looking-at "\\(\\s(\\|\\s\"\\)") - (forward-sexp 1)) + ;; Skip over balanced expressions. + ((looking-at "\\s(") + (wisent-python-forward-balanced-expression)) ;; At the explicit line continuation character ;; (backslash) move to next line. ((looking-at "\\s\\") @@ -107,8 +200,8 @@ line ends at the end of the buffer, leave the point there." (defun wisent-python-forward-line-skip-indented () "Move point to the next logical line, skipping indented lines. -That is the next line whose indentation is less than or equal to the -indentation of the current line." +That is the next line whose indentation is less than or equal to +the indentation of the current line." (let ((indent (current-indentation))) (while (progn (wisent-python-forward-line) (and (not (eobp)) @@ -185,17 +278,18 @@ indentation of the current line." ;; Loop lexer to handle tokens in current line. t) ;; Indentation decreased - (t - ;; Pop items from indentation stack - (while (< curr-indent last-indent) - (pop wisent-python-indent-stack) - (setq semantic-lex-current-depth (1- semantic-lex-current-depth) - last-indent (car wisent-python-indent-stack)) - (semantic-lex-push-token - (semantic-lex-token 'DEDENT last-pos (point)))) + ((progn + ;; Pop items from indentation stack + (while (< curr-indent last-indent) + (pop wisent-python-indent-stack) + (setq semantic-lex-current-depth (1- semantic-lex-current-depth) + last-indent (car wisent-python-indent-stack)) + (semantic-lex-push-token + (semantic-lex-token 'DEDENT last-pos (point)))) + (= last-pos (point))) ;; If pos did not change, then we must return nil so that ;; other lexical analyzers can be run. - (/= last-pos (point)))))) + nil)))) ;; All the work was done in the above analyzer matching condition. ) @@ -211,7 +305,7 @@ continuation of current line." (define-lex-regex-analyzer wisent-python-lex-string "Detect and create python string tokens." - wisent-python-string-re + wisent-python-string-start-re (semantic-lex-push-token (semantic-lex-token 'STRING_LITERAL @@ -250,9 +344,113 @@ elsewhere on a line outside a string literal." semantic-lex-ignore-comments ;; Signal error on unhandled syntax. semantic-lex-default-action) + + +;;; Parsing +;; + +(defun wisent-python-reconstitute-function-tag (tag suite) + "Move a docstring from TAG's members into its :documentation attribute. +Set attributes for constructors, special, private and static methods." + ;; Analyze first statement to see whether it is a documentation + ;; string. + (let ((first-statement (car suite))) + (when (semantic-python-docstring-p first-statement) + (semantic-tag-put-attribute + tag :documentation + (semantic-python-extract-docstring first-statement)))) + + ;; TODO HACK: we try to identify methods using the following + ;; heuristic: + ;; + at least one argument + ;; + first argument is self + (when (and (> (length (semantic-tag-function-arguments tag)) 0) + (string= (semantic-tag-name + (first (semantic-tag-function-arguments tag))) + "self")) + (semantic-tag-put-attribute tag :parent "dummy")) + + ;; Identify constructors, special and private functions + (cond + ;; TODO only valid when the function resides inside a class + ((string= (semantic-tag-name tag) "__init__") + (semantic-tag-put-attribute tag :constructor-flag t) + (semantic-tag-put-attribute tag :suite suite)) + + ((semantic-python-special-p tag) + (semantic-tag-put-attribute tag :special-flag t)) + + ((semantic-python-private-p tag) + (semantic-tag-put-attribute tag :protection "private"))) + + ;; If there is a staticmethod decorator, add a static typemodifier + ;; for the function. + (when (semantic-find-tags-by-name + "staticmethod" + (semantic-tag-get-attribute tag :decorators)) + (semantic-tag-put-attribute + tag :typemodifiers + (cons "static" + (semantic-tag-get-attribute tag :typemodifiers)))) + + ;; TODO + ;; + check for decorators classmethod + ;; + check for operators + tag) + +(defun wisent-python-reconstitute-class-tag (tag) + "Move a docstring from TAG's members into its :documentation attribute." + ;; The first member of TAG may be a documentation string. If that is + ;; the case, remove of it from the members list and stick its + ;; content into the :documentation attribute. + (let ((first-member (car (semantic-tag-type-members tag)))) + (when (semantic-python-docstring-p first-member) + (semantic-tag-put-attribute + tag :members + (cdr (semantic-tag-type-members tag))) + (semantic-tag-put-attribute + tag :documentation + (semantic-python-extract-docstring first-member)))) + + ;; Try to find the constructor, determine the name of the instance + ;; parameter, find assignments to instance variables and add + ;; corresponding variable tags to the list of members. + (dolist (member (semantic-tag-type-members tag)) + (when (semantic-tag-function-constructor-p member) + (let ((self (semantic-tag-name + (car (semantic-tag-function-arguments member))))) + (dolist (statement (semantic-tag-get-attribute member :suite)) + (when (semantic-python-instance-variable-p statement self) + (let ((variable (semantic-tag-clone + statement + (substring (semantic-tag-name statement) 5))) + (members (semantic-tag-get-attribute tag :members))) + (when (semantic-python-private-p variable) + (semantic-tag-put-attribute variable :protection "private")) + (setcdr (last members) (list variable)))))))) + + ;; TODO remove the :suite attribute + tag) + +(defun semantic-python-expand-tag (tag) + "Expand compound declarations found in TAG into separate tags. +TAG contains compound declaration if the NAME part of the tag is +a list. In python, this can happen with `import' statements." + (let ((class (semantic-tag-class tag)) + (elts (semantic-tag-name tag)) + (expand nil)) + (cond + ((and (eq class 'include) (listp elts)) + (dolist (E elts) + (setq expand (cons (semantic-tag-clone tag E) expand))) + (setq expand (nreverse expand))) + ))) + + ;;; Overridden Semantic API. ;; + (define-mode-local-override semantic-lex python-mode (start end &optional depth length) "Lexically analyze Python code in current buffer. @@ -274,10 +472,11 @@ what remains in the `wisent-python-indent-stack'." To be implemented for Python! For now just return nil." nil) -(defcustom-mode-local-semantic-dependency-system-include-path - python-mode semantic-python-dependency-system-include-path - nil - "The system include path used by Python language.") +;; Adapted from the semantic Java support by Andrey Torba +(define-mode-local-override semantic-tag-include-filename python-mode (tag) + "Return a suitable path for (some) Python imports." + (let ((name (semantic-tag-name tag))) + (concat (mapconcat 'identity (split-string name "\\.") "/") ".py"))) ;;; Enable Semantic in `python-mode'. ;; @@ -287,13 +486,15 @@ To be implemented for Python! For now just return nil." "Setup buffer for parse." (wisent-python-wy--install-parser) (set (make-local-variable 'parse-sexp-ignore-comments) t) + ;; Give python modes the possibility to overwrite this: + (if (not comment-start-skip) + (set (make-local-variable 'comment-start-skip) "#+\\s-*")) (setq - ;; Character used to separation a parent/child relationship + ;; Character used to separation a parent/child relationship semantic-type-relation-separator-character '(".") semantic-command-separation-character ";" - ;; The following is no more necessary as semantic-lex is overridden - ;; in python-mode. - ;; semantic-lex-analyzer 'wisent-python-lexer + ;; Parsing + semantic-tag-expand-function 'semantic-python-expand-tag ;; Semantic to take over from the one provided by python. ;; The python one, if it uses the senator advice, will hang @@ -320,8 +521,56 @@ To be implemented for Python! For now just return nil." (define-child-mode python-3-mode python-mode "Python 3 mode") +;;; Utility functions +;; + +(defun semantic-python-special-p (tag) + "Return non-nil if the name of TAG is a special identifier of +the form __NAME__. " + (string-match + (rx (seq string-start "__" (1+ (syntax symbol)) "__" string-end)) + (semantic-tag-name tag))) + +(defun semantic-python-private-p (tag) + "Return non-nil if the name of TAG follows the convention _NAME +for private names." + (string-match + (rx (seq string-start "_" (0+ (syntax symbol)) string-end)) + (semantic-tag-name tag))) + +(defun semantic-python-instance-variable-p (tag &optional self) + "Return non-nil if TAG is an instance variable of the instance +SELF or the instance name \"self\" if SELF is nil." + (when (semantic-tag-of-class-p tag 'variable) + (let ((name (semantic-tag-name tag))) + (when (string-match + (rx-to-string + `(seq string-start ,(or self "self") ".")) + name) + (not (string-match "\\." (substring name 5))))))) + +(defun semantic-python-docstring-p (tag) + "Return non-nil, when TAG is a Python documentation string." + ;; TAG is considered to be a documentation string if the first + ;; member is of class 'code and its name looks like a documentation + ;; string. + (let ((class (semantic-tag-class tag)) + (name (semantic-tag-name tag))) + (and (eq class 'code) + (string-match + (rx (seq string-start "\"\"\"" (0+ anything) "\"\"\"" string-end)) + name)))) + +(defun semantic-python-extract-docstring (tag) + "Return the Python documentation string contained in TAG." + ;; Strip leading and trailing """ + (let ((name (semantic-tag-name tag))) + (substring name 3 -3))) + + ;;; Test ;; + (defun wisent-python-lex-buffer () "Run `wisent-python-lexer' on current buffer." (interactive) diff --git a/lisp/cedet/srecode.el b/lisp/cedet/srecode.el index f973ee9065e..73a67737cca 100644 --- a/lisp/cedet/srecode.el +++ b/lisp/cedet/srecode.el @@ -4,7 +4,6 @@ ;; Author: Eric M. Ludlam <zappo@gnu.org> ;; Keywords: codegeneration -;; Version: 1.0pre7 ;; This file is part of GNU Emacs. diff --git a/lisp/cedet/srecode/compile.el b/lisp/cedet/srecode/compile.el index d5389a97f03..8a1291f8d72 100644 --- a/lisp/cedet/srecode/compile.el +++ b/lisp/cedet/srecode/compile.el @@ -210,6 +210,7 @@ Arguments ESCAPE-START and ESCAPE-END are the current escape sequences in use." (buffer-file-name)))) (mode nil) (application nil) + (framework nil) (priority nil) (project nil) (vars nil) @@ -253,6 +254,8 @@ Arguments ESCAPE-START and ESCAPE-END are the current escape sequences in use." ) ((string= name "application") (setq application (read firstvalue))) + ((string= name "framework") + (setq framework (read firstvalue))) ((string= name "priority") (setq priority (read firstvalue))) ((string= name "project") @@ -319,7 +322,7 @@ 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 project vars) + (srecode-compile-template-table table mode priority application framework project vars) ) ) @@ -376,8 +379,8 @@ It is hard if the previous inserter is a newline object." (while (and comp (stringp (car comp))) (setq comp (cdr comp))) (or (not comp) - (require 'srecode/insert) - (srecode-template-inserter-newline-child-p (car comp)))) + (progn (require 'srecode/insert) + (srecode-template-inserter-newline-child-p (car comp))))) (defun srecode-compile-split-code (tag str STATE &optional end-name) @@ -522,12 +525,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 project vars) +(defun srecode-compile-template-table (templates mode priority application framework 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. +FRAMEWORK is the name of the framework 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 @@ -569,6 +573,7 @@ A list of defined variables VARS provides a variable table." :major-mode mode :priority priority :application application + :framework framework :project project)) (tmpl (oref table templates))) ;; Loop over all the templates, and xref. diff --git a/lisp/cedet/srecode/cpp.el b/lisp/cedet/srecode/cpp.el index 12bfd3af903..d63e1a7a49f 100644 --- a/lisp/cedet/srecode/cpp.el +++ b/lisp/cedet/srecode/cpp.el @@ -47,16 +47,16 @@ buffer contains a using NAMESPACE; statement " :group 'srecode-cpp :type '(repeat string)) -;;; :cpp ARGUMENT HANDLING +;;; :c ARGUMENT HANDLING ;; -;; When a :cpp argument is required, fill the dictionary with -;; information about the current C++ file. +;; When a :c argument is required, fill the dictionary with +;; information about the current C file. ;; -;; Error if not in a C++ mode. +;; Error if not in a C mode. ;;;###autoload -(defun srecode-semantic-handle-:cpp (dict) - "Add macros into the dictionary DICT based on the current c++ file. +(defun srecode-semantic-handle-:c (dict) + "Add macros into the dictionary DICT based on the current c file. Adds the following: FILENAME_SYMBOL - filename converted into a C compat symbol. HEADER - Shown section if in a header file." @@ -76,6 +76,21 @@ HEADER - Shown section if in a header file." ) ) +;;; :cpp ARGUMENT HANDLING +;; +;; When a :cpp argument is required, fill the dictionary with +;; information about the current C++ file. +;; +;; Error if not in a C++ mode. +;;;###autoload +(defun srecode-semantic-handle-:cpp (dict) + "Add macros into the dictionary DICT based on the current c file. +Calls `srecode-semantic-handle-:c. +Also adds the following: + - nothing -" + (srecode-semantic-handle-:c dict) + ) + (defun srecode-semantic-handle-:using-namespaces (dict) "Add macros into the dictionary DICT based on used namespaces. Adds the following: @@ -94,10 +109,15 @@ PREFIX_NAMESPACE - for each NAMESPACE in `srecode-cpp-namespaces'." ) (define-mode-local-override srecode-semantic-apply-tag-to-dict - c++-mode (tag-wrapper dict) - "Apply C++ specific features from TAG-WRAPPER into DICT. + c-mode (tag-wrapper dict) + "Apply C and C++ specific features from TAG-WRAPPER into DICT. Calls `srecode-semantic-apply-tag-to-dict-default' first. Adds -special behavior for tag of classes include, using and function." +special behavior for tag of classes include, using and function. + +This function cannot be split into C and C++ specific variants, as +the way the tags are created from the parser does not distinguish +either. The side effect is that you could get some C++ tag properties +specified in a C file." ;; Use default implementation to fill in the basic properties. (srecode-semantic-apply-tag-to-dict-default tag-wrapper dict) @@ -150,14 +170,20 @@ special behavior for tag of classes include, using and function." (templates (semantic-tag-get-attribute tag :template)) (modifiers (semantic-tag-modifiers tag))) - ;; Add modifiers into the dictionary + ;; Mark constructors and destructors as such. + (when (semantic-tag-function-constructor-p tag) + (srecode-dictionary-show-section dict "CONSTRUCTOR")) + (when (semantic-tag-function-destructor-p tag) + (srecode-dictionary-show-section dict "DESTRUCTOR")) + + ;; Add modifiers into the dictionary. (dolist (modifier modifiers) (let ((modifier-dict (srecode-dictionary-add-section-dictionary dict "MODIFIERS"))) (srecode-dictionary-set-value modifier-dict "NAME" modifier))) ;; Add templates into child dictionaries. - (srecode-cpp-apply-templates dict templates) + (srecode-c-apply-templates dict templates) ;; When the function is a member function, it can have ;; additional modifiers. @@ -171,8 +197,7 @@ special behavior for tag of classes include, using and function." ;; If the member function is pure virtual, add a dictionary ;; entry. (when (semantic-tag-get-attribute tag :pure-virtual-flag) - (srecode-dictionary-show-section dict "PURE")) - ))) + (srecode-dictionary-show-section dict "PURE"))))) ;; ;; CLASS @@ -184,7 +209,7 @@ special behavior for tag of classes include, using and function." ;; Add templates into child dictionaries. (let ((templates (semantic-tag-get-attribute tag :template))) - (srecode-cpp-apply-templates dict templates)))) + (srecode-c-apply-templates dict templates)))) )) ) @@ -192,7 +217,7 @@ special behavior for tag of classes include, using and function." ;;; Helper functions ;; -(defun srecode-cpp-apply-templates (dict templates) +(defun srecode-c-apply-templates (dict templates) "Add section dictionaries for TEMPLATES to DICT." (when templates (let ((templates-dict (srecode-dictionary-add-section-dictionary diff --git a/lisp/cedet/srecode/dictionary.el b/lisp/cedet/srecode/dictionary.el index 5b65284660f..6262383c397 100644 --- a/lisp/cedet/srecode/dictionary.el +++ b/lisp/cedet/srecode/dictionary.el @@ -117,8 +117,8 @@ Makes sure that :value is compiled." (cons (car fields) newfields)))) (setq fields (cdr (cdr fields)))) - (when (not state) - (error "Cannot create compound variable without :state")) + ;;(when (not state) + ;; (error "Cannot create compound variable outside of sectiondictionary")) (call-next-method this (nreverse newfields)) (when (not (slot-boundp this 'compiled)) @@ -220,7 +220,10 @@ associated with a buffer or parent." "Insert into DICT the variables found in table TPL. TPL is an object representing a compiled template file." (when tpl - (let ((tabs (oref tpl :tables))) + ;; Tables are sorted with highest priority first, useful for looking + ;; up templates, but this means we need to install the variables in + ;; reverse order so higher priority variables override lower ones. + (let ((tabs (reverse (oref tpl :tables)))) (require 'srecode/find) ; For srecode-template-table-in-project-p (while tabs (when (srecode-template-table-in-project-p (car tabs)) @@ -546,40 +549,6 @@ inserted with a new editable field.") ;;; Higher level dictionary functions ;; -(defun srecode-create-section-dictionary (sectiondicts STATE) - "Create a dictionary with section entries for a template. -The format for SECTIONDICTS is what is emitted from the template parsers. -STATE is the current compiler state." - (when sectiondicts - (let ((new (srecode-create-dictionary t))) - ;; Loop over each section. The section is a macro w/in the - ;; template. - (while sectiondicts - (let* ((sect (car (car sectiondicts))) - (entries (cdr (car sectiondicts))) - (subdict (srecode-dictionary-add-section-dictionary new sect)) - ) - ;; Loop over each entry. This is one variable in the - ;; section dictionary. - (while entries - (let ((tname (semantic-tag-name (car entries))) - (val (semantic-tag-variable-default (car entries)))) - (if (eq val t) - (srecode-dictionary-show-section subdict tname) - (cond - ((and (stringp (car val)) - (= (length val) 1)) - (setq val (car val))) - (t - (setq val (srecode-dictionary-compound-variable - tname :value val :state STATE)))) - (srecode-dictionary-set-value - subdict tname val)) - (setq entries (cdr entries)))) - ) - (setq sectiondicts (cdr sectiondicts))) - new))) - (defun srecode-create-dictionaries-from-tags (tags state) "Create a dictionary with entries according to TAGS. diff --git a/lisp/cedet/srecode/find.el b/lisp/cedet/srecode/find.el index befdb4731c2..f621c5e82d5 100644 --- a/lisp/cedet/srecode/find.el +++ b/lisp/cedet/srecode/find.el @@ -220,32 +220,37 @@ tables that do not belong to an application will be searched." (defvar srecode-read-template-name-history nil "History for completing reads for template names.") -(defun srecode-all-template-hash (&optional mode hash) +(defun srecode-user-template-p (template) + "Non-nil if TEMPLATE is intended for user insertion. +Templates not matching this predicate are used for code +generation or other internal purposes." + t) + +(defun srecode-all-template-hash (&optional mode hash predicate) "Create a hash table of all the currently available templates. Optional argument MODE is the major mode to look for. -Optional argument HASH is the hash table to fill in." - (let* ((mhash (or hash (make-hash-table :test 'equal))) - (mmode (or mode major-mode)) - (mp (get-mode-local-parent mmode)) - ) +Optional argument HASH is the hash table to fill in. +Optional argument PREDICATE can be used to filter the returned +templates." + (let* ((mhash (or hash (make-hash-table :test 'equal))) + (mmode (or mode major-mode)) + (parent-mode (get-mode-local-parent mmode))) ;; Get the parent hash table filled into our current hash. - (when (not (eq mode 'default)) - (if mp - (srecode-all-template-hash mp mhash) - (srecode-all-template-hash 'default mhash))) + (unless (eq mode 'default) + (srecode-all-template-hash (or parent-mode 'default) mhash)) + ;; Load up the hash table for our current mode. - (let* ((mt (srecode-get-mode-table mmode)) - (tabs (when mt (oref mt :tables))) - ) - (while tabs + (let* ((mt (srecode-get-mode-table mmode)) + (tabs (when mt (oref mt :tables)))) + (dolist (tab tabs) ;; Exclude templates for a particular application. - (when (and (not (oref (car tabs) :application)) - (srecode-template-table-in-project-p (car tabs))) + (when (and (not (oref tab :application)) + (srecode-template-table-in-project-p tab)) (maphash (lambda (key temp) - (puthash key temp mhash) - ) - (oref (car tabs) namehash))) - (setq tabs (cdr tabs))) + (when (or (not predicate) + (funcall predicate temp)) + (puthash key temp mhash))) + (oref tab namehash)))) mhash))) (defun srecode-calculate-default-template-string (hash) diff --git a/lisp/cedet/srecode/getset.el b/lisp/cedet/srecode/getset.el index 5155044e386..49d913a099a 100644 --- a/lisp/cedet/srecode/getset.el +++ b/lisp/cedet/srecode/getset.el @@ -298,10 +298,10 @@ Base selection on the field related to POINT." (let* ((kids (semantic-find-tags-by-class 'variable (semantic-tag-type-members class))) (sel (completing-read "Use Field: " kids)) - ) - - (or (semantic-find-tags-by-name sel kids) - sel) + (fields (semantic-find-tags-by-name sel kids))) + (if fields + (car fields) + sel) )) (defun srecode-auto-choose-class (point) diff --git a/lisp/cedet/srecode/insert.el b/lisp/cedet/srecode/insert.el index 7d300614c08..726aa41cffd 100644 --- a/lisp/cedet/srecode/insert.el +++ b/lisp/cedet/srecode/insert.el @@ -195,6 +195,32 @@ Buffer based features related to change hooks is handled one level up." ;; area. Return value is not important. )) +(defun srecode-insert-show-error-report (dictionary format &rest args) + "Display an error report based on DICTIONARY, FORMAT and ARGS. +This is intended to diagnose problems with failed template +insertions." + (with-current-buffer (data-debug-new-buffer "*SRECODE INSERTION ERROR*") + (erase-buffer) + ;; Insert the stack of templates that are currently being + ;; inserted. + (insert (propertize "Template Stack" 'face '(:weight bold)) + (propertize " (most recent at bottom)" 'face '(:slant italic)) + ":\n") + (data-debug-insert-stuff-list + (reverse (oref srecode-template active)) "> ") + ;; Show the current dictionary. + (insert (propertize "Dictionary" 'face '(:weight bold)) "\n") + (data-debug-insert-thing dictionary "" "> ") + ;; Show the error message. + (insert (propertize "Error" 'face '(:weight bold)) "\n") + (insert (apply #'format format args)) + (pop-to-buffer (current-buffer)))) + +(defun srecode-insert-report-error (dictionary format &rest args) + ;; TODO only display something when inside an interactive call? + (srecode-insert-show-error-report dictionary format args) + (apply #'error format args)) + ;;; TEMPLATE ARGUMENTS ;; ;; Some templates have arguments. Each argument is associated with @@ -435,8 +461,10 @@ If SECONDNAME is nil, return VALUE." (let ((srecode-inserter-variable-current-dictionary dictionary)) (funcall fcnpart value)) ;; Else, warn. - (error "Variable insertion second arg %s is not a function" - secondname))) + (srecode-insert-report-error + dictionary + "Variable inserter %s: second argument `%s' is not a function" + (object-print sti) secondname))) value)) (defmethod srecode-insert-method ((sti srecode-template-inserter-variable) @@ -467,19 +495,20 @@ If SECONDNAME is nil, return VALUE." ;; If the value returned is nil, then it may be a special ;; field inserter that requires us to set do-princ to nil. (when (not val) - (setq do-princ nil) - ) - ) + (setq do-princ nil))) + ;; Dictionaries... not allowed in this style ((srecode-dictionary-child-p val) - (error "Macro %s cannot insert a dictionary - use section macros instead" - name)) + (srecode-insert-report-error + dictionary + "Macro %s cannot insert a dictionary - use section macros instead" + name)) + ;; Other stuff... convert (t - (error "Macro %s cannot insert arbitrary data" name) - ;;(if (and val (not (stringp val))) - ;; (setq val (format "%S" val)))) - )) + (srecode-insert-report-error + dictionary + "Macro %s cannot insert arbitrary data" name))) ;; Output the dumb thing unless the type of thing specifically ;; did the inserting for us. (when do-princ @@ -559,19 +588,25 @@ Loop over the prompts to see if we have a match." "Derive the default value for an askable inserter STI. DICTIONARY is used to derive some values." (let ((defaultfcn (oref sti :defaultfcn))) - (cond ((stringp defaultfcn) - defaultfcn) - ((functionp defaultfcn) - (funcall defaultfcn)) - ((and (listp defaultfcn) - (eq (car defaultfcn) 'macro)) - (srecode-dictionary-lookup-name - dictionary (cdr defaultfcn))) - ((null defaultfcn) - "") - (t - (error "Unknown default for prompt: %S" - defaultfcn))))) + (cond + ((stringp defaultfcn) + defaultfcn) + + ((functionp defaultfcn) + (funcall defaultfcn)) + + ((and (listp defaultfcn) + (eq (car defaultfcn) 'macro)) + (srecode-dictionary-lookup-name + dictionary (cdr defaultfcn))) + + ((null defaultfcn) + "") + + (t + (srecode-insert-report-error + dictionary + "Unknown default for prompt: %S" defaultfcn))))) (defmethod srecode-insert-method-ask ((sti srecode-template-inserter-ask) dictionary) @@ -647,26 +682,33 @@ spaces to the right.") "For VALUE handle WIDTH behaviors for this variable inserter. Return the result as a string. By default, treat as a function name." - (if width - ;; Trim or pad to new length - (let* ((split (split-string width ":")) - (width (string-to-number (nth 0 split))) - (second (nth 1 split)) - (pad (cond ((or (null second) (string= "right" second)) - 'right) - ((string= "left" second) - 'left) - (t - (error "Unknown pad type %s" second))))) - (if (>= (length value) width) - ;; Simple case - too long. - (substring value 0 width) - ;; We need to pad on one side or the other. - (let ((padchars (make-string (- width (length value)) ? ))) - (if (eq pad 'left) - (concat padchars value) - (concat value padchars))))) - (error "Width not specified for variable/width inserter"))) + ;; Cannot work without width. + (unless width + (srecode-insert-report-error + dictionary + "Width not specified for variable/width inserter")) + + ;; Trim or pad to new length + (let* ((split (split-string width ":")) + (width (string-to-number (nth 0 split))) + (second (nth 1 split)) + (pad (cond + ((or (null second) (string= "right" second)) + 'right) + ((string= "left" second) + 'left) + (t + (srecode-insert-report-error + dictionary + "Unknown pad type %s" second))))) + (if (>= (length value) width) + ;; Simple case - too long. + (substring value 0 width) + ;; We need to pad on one side or the other. + (let ((padchars (make-string (- width (length value)) ? ))) + (if (eq pad 'left) + (concat padchars value) + (concat value padchars)))))) (defmethod srecode-inserter-prin-example :STATIC ((ins srecode-template-inserter-width) escape-start escape-end) @@ -758,13 +800,15 @@ Arguments ESCAPE-START and ESCAPE-END are the current escape sequences in use." (defmethod srecode-insert-subtemplate ((sti srecode-template-inserter-subtemplate) dict slot) "Insert a subtemplate for the inserter STI with dictionary DICT." - ;; make sure that only dictionaries are used. - (when (not (srecode-dictionary-child-p dict)) - (error "Only section dictionaries allowed for %s" - (object-name-string sti))) + ;; Make sure that only dictionaries are used. + (unless (srecode-dictionary-child-p dict) + (srecode-insert-report-error + dict + "Only section dictionaries allowed for `%s'" + (object-name-string sti))) + ;; Output the code from the sub-template. - (srecode-insert-method (slot-value sti slot) dict) - ) + (srecode-insert-method (slot-value sti slot) dict)) (defmethod srecode-insert-method-helper ((sti srecode-template-inserter-subtemplate) dictionary slot) @@ -774,14 +818,18 @@ 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))) + (srecode-insert-report-error + dictionary + "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-report-error + dictionary + "Cannot insert section %S from non-section variable." + (oref sti :object-name))) (srecode-insert-subtemplate sti (car dicts) slot) (setq dicts (cdr dicts))))) @@ -876,11 +924,13 @@ Arguments ESCAPE-START and ESCAPE-END are the current escape sequences in use." "For the template inserter STI, lookup the template to include. Finds the template with this macro function part and stores it in this template instance." - (let* ((templatenamepart (oref sti :secondname)) - ) - ;; If there was no template name, throw an error - (if (not templatenamepart) - (error "Include macro %s needs a template name" (oref sti :object-name))) + (let ((templatenamepart (oref sti :secondname))) + ;; If there was no template name, throw an error. + (unless templatenamepart + (srecode-insert-report-error + dictionary + "Include macro `%s' needs a template name" + (oref sti :object-name))) ;; 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 @@ -920,11 +970,12 @@ this template instance." ;; 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. - (error "No template \"%s\" found for include macro `%s'" - templatenamepart (oref sti :object-name))) - )) + (unless (oref sti includedtemplate) + ;; @todo - Call into a debugger to help find the template in question. + (srecode-insert-report-error + dictionary + "No template \"%s\" found for include macro `%s'" + templatenamepart (oref sti :object-name))))) (defmethod srecode-insert-method ((sti srecode-template-inserter-include) dictionary) diff --git a/lisp/cedet/srecode/java.el b/lisp/cedet/srecode/java.el index 58d8efc41e2..3635a39d383 100644 --- a/lisp/cedet/srecode/java.el +++ b/lisp/cedet/srecode/java.el @@ -26,6 +26,10 @@ ;;; Code: (require 'srecode/dictionary) +(require 'semantic/tag) + +(eval-when-compile + (require 'semantic/find)) ;;;###autoload (defun srecode-semantic-handle-:java (dict) @@ -33,7 +37,7 @@ Adds the following: FILENAME_AS_PACKAGE - file/dir converted into a java package name. FILENAME_AS_CLASS - file converted to a Java class name." - ;; A symbol representing + ;; Symbols needed by empty files. (let* ((fsym (file-name-nondirectory (buffer-file-name))) (fnox (file-name-sans-extension fsym)) (dir (file-name-directory (buffer-file-name))) @@ -44,12 +48,18 @@ FILENAME_AS_CLASS - file converted to a Java class name." (if (string-match "src/" dir) (setq dir (substring dir (match-end 0))) (setq dir (file-name-nondirectory (directory-file-name dir)))) + (setq dir (directory-file-name dir)) (while (string-match "/" dir) - (setq dir (replace-match "_" t t dir))) - (srecode-dictionary-set-value dict "FILENAME_AS_PACKAGE" - (concat dir "." fpak)) + (setq dir (replace-match "." t t dir))) + (srecode-dictionary-set-value dict "FILENAME_AS_PACKAGE" dir) (srecode-dictionary-set-value dict "FILENAME_AS_CLASS" fnox) - )) + ) + ;; Symbols needed for most other files with stuff in them. + (let ((pkg (semantic-find-tags-by-class 'package (current-buffer)))) + (when pkg + (srecode-dictionary-set-value dict "CURRENT_PACKAGE" (semantic-tag-name (car pkg))) + )) + ) (provide 'srecode/java) diff --git a/lisp/cedet/srecode/map.el b/lisp/cedet/srecode/map.el index 3f891092d7d..d6613ee1b02 100644 --- a/lisp/cedet/srecode/map.el +++ b/lisp/cedet/srecode/map.el @@ -297,7 +297,7 @@ if that file is NEW, otherwise assume the mode has not changed." (when (not srecode-current-map) (condition-case nil (setq srecode-current-map - (eieio-persistent-read srecode-map-save-file)) + (eieio-persistent-read srecode-map-save-file srecode-map)) (error ;; There was an error loading the old map. Create a new one. (setq srecode-current-map diff --git a/lisp/cedet/srecode/mode.el b/lisp/cedet/srecode/mode.el index e2c07a0863e..805e324a8bd 100644 --- a/lisp/cedet/srecode/mode.el +++ b/lisp/cedet/srecode/mode.el @@ -32,8 +32,11 @@ (require 'srecode/map) (require 'semantic/decorate) (require 'semantic/wisent) +(require 'semantic/senator) +(require 'semantic/wisent) -(eval-when-compile (require 'semantic/find)) +(eval-when-compile + (require 'semantic/find)) ;;; Code: @@ -154,13 +157,22 @@ minor mode is enabled. :keymap srecode-mode-map ;; If we are turning things on, make sure we have templates for ;; this mode first. - (when srecode-minor-mode - (when (not (apply + (if srecode-minor-mode + (if (not (apply 'append (mapcar (lambda (map) (srecode-map-entries-for-mode map major-mode)) (srecode-get-maps)))) - (setq srecode-minor-mode nil)))) + (setq srecode-minor-mode nil) + ;; Else, we have success, do stuff + (add-hook 'cedet-m3-menu-do-hooks 'srecode-m3-items nil t) + ) + (remove-hook 'cedet-m3-menu-do-hooks 'srecode-m3-items t) + ) + ;; Run hooks if we are turning this on. + (when srecode-minor-mode + (run-hooks 'srecode-minor-mode-hook)) + srecode-minor-mode) ;;;###autoload (define-minor-mode global-srecode-minor-mode diff --git a/lisp/cedet/srecode/semantic.el b/lisp/cedet/srecode/semantic.el index 827979f786a..877f6796c76 100644 --- a/lisp/cedet/srecode/semantic.el +++ b/lisp/cedet/srecode/semantic.el @@ -351,6 +351,12 @@ as `function' will leave point where code might be inserted." (setq temp (srecode-semantic-find-template "variable-const" prototype ctxt)) ) + + ((and (semantic-tag-of-class-p tag 'include) + (semantic-tag-get-attribute tag :system-flag)) + (setq temp (srecode-semantic-find-template + "system-include" prototype ctxt)) + ) ) (when (not temp) diff --git a/lisp/cedet/srecode/srt-mode.el b/lisp/cedet/srecode/srt-mode.el index 48eeab2408f..12fc08b90e4 100644 --- a/lisp/cedet/srecode/srt-mode.el +++ b/lisp/cedet/srecode/srt-mode.el @@ -70,13 +70,17 @@ (3 font-lock-builtin-face )) ("^\\(sectiondictionary\\)\\s-+\"" (1 font-lock-keyword-face)) + ("^\\s\s*\\(section\\)\\s-+\"" + (1 font-lock-keyword-face)) + ("^\\s\s*\\(end\\)" + (1 font-lock-keyword-face)) ("^\\(bind\\)\\s-+\"" (1 font-lock-keyword-face)) ;; Variable type setting - ("^\\(set\\)\\s-+\\(\\w+\\)\\s-+" + ("^\\s\s*\\(set\\)\\s-+\\(\\w+\\)\\s-+" (1 font-lock-keyword-face) (2 font-lock-variable-name-face)) - ("^\\(show\\)\\s-+\\(\\w+\\)\\s-*$" + ("^\\s\s*\\(show\\)\\s-+\\(\\w+\\)\\s-*$" (1 font-lock-keyword-face) (2 font-lock-variable-name-face)) ("\\<\\(macro\\)\\s-+\"" diff --git a/lisp/cedet/srecode/srt-wy.el b/lisp/cedet/srecode/srt-wy.el index 8beeb04940d..6f5d73aa312 100644 --- a/lisp/cedet/srecode/srt-wy.el +++ b/lisp/cedet/srecode/srt-wy.el @@ -24,6 +24,7 @@ ;;; Code: (require 'semantic/lex) +(eval-when-compile (require 'semantic/bovine)) ;;; Prologue ;; @@ -38,6 +39,8 @@ ("context" . CONTEXT) ("template" . TEMPLATE) ("sectiondictionary" . SECTIONDICTIONARY) + ("section" . SECTION) + ("end" . END) ("prompt" . PROMPT) ("default" . DEFAULT) ("defaultmacro" . DEFAULTMACRO) @@ -48,6 +51,8 @@ ("defaultmacro" summary "prompt <symbol> \"Describe Symbol: \" [default[macro] <lispsym>|\"valuetext\"] [read <lispsym>]") ("default" summary "prompt <symbol> \"Describe Symbol: \" [default[macro] <lispsym>|\"valuetext\"] [read <lispsym>]") ("prompt" summary "prompt <symbol> \"Describe Symbol: \" [default[macro] <lispsym>|\"valuetext\"] [read <lispsym>]") + ("end" summary "section ... end") + ("section" summary "section <name>\\n <dictionary entries>\\n end") ("sectiondictionary" summary "sectiondictionary <name>\\n <dictionary entries>") ("template" summary "template <name>\\n <template definition>") ("context" summary "context <name>") @@ -73,6 +78,7 @@ '(("number" :declared t) ("string" :declared t) ("symbol" :declared t) + ("property" syntax ":\\(\\w\\|\\s_\\)*") ("property" :declared t) ("newline" :declared t) ("punctuation" syntax "\\s.+") @@ -85,7 +91,7 @@ (eval-when-compile (require 'semantic/wisent/comp)) (wisent-compile-grammar - '((SET SHOW MACRO CONTEXT TEMPLATE SECTIONDICTIONARY PROMPT DEFAULT DEFAULTMACRO READ BIND newline TEMPLATE_BLOCK property symbol string number) + '((SET SHOW MACRO CONTEXT TEMPLATE SECTIONDICTIONARY SECTION END PROMPT DEFAULT DEFAULTMACRO READ BIND newline TEMPLATE_BLOCK property symbol string number) nil (template_file ((newline) @@ -141,7 +147,7 @@ (cons 'macro (read $2)))) (template - ((TEMPLATE templatename opt-dynamic-arguments newline opt-string opt-section-dictionaries TEMPLATE_BLOCK newline opt-bind) + ((TEMPLATE templatename opt-dynamic-arguments newline opt-string section-dictionary-list TEMPLATE_BLOCK newline opt-bind) (wisent-raw-tag (semantic-tag-new-function $2 nil $3 :documentation $5 :code $7 :dictionaries $6 :binding $9)))) (templatename @@ -162,26 +168,40 @@ ((string newline) (read $1)) (nil nil)) - (opt-section-dictionaries - (nil nil) - ((section-dictionary-list))) (section-dictionary-list - ((one-section-dictionary) - (list $1)) - ((section-dictionary-list one-section-dictionary) + (nil nil) + ((section-dictionary-list flat-section-dictionary) + (append $1 + (list $2))) + ((section-dictionary-list section-dictionary) (append $1 (list $2)))) - (one-section-dictionary - ((SECTIONDICTIONARY string newline variable-list) + (flat-section-dictionary + ((SECTIONDICTIONARY string newline flat-dictionary-entry-list) + (cons + (read $2) + $4))) + (flat-dictionary-entry-list + (nil nil) + ((flat-dictionary-entry-list flat-dictionary-entry) + (append $1 $2))) + (flat-dictionary-entry + ((variable) + (wisent-cook-tag $1))) + (section-dictionary + ((SECTION string newline dictionary-entry-list END newline) (cons (read $2) $4))) - (variable-list + (dictionary-entry-list + (nil nil) + ((dictionary-entry-list dictionary-entry) + (append $1 $2))) + (dictionary-entry ((variable) (wisent-cook-tag $1)) - ((variable-list variable) - (append $1 - (wisent-cook-tag $2)))) + ((section-dictionary) + (list $1))) (opt-bind ((BIND string newline) (read $2)) @@ -205,12 +225,12 @@ ;;; Analyzers - -(define-lex-string-type-analyzer srecode-template-wy--<punctuation>-string-analyzer - "string analyzer for <punctuation> tokens." - "\\s.+" +;; +(define-lex-regex-type-analyzer srecode-template-wy--<property>-regexp-analyzer + "regexp analyzer for <property> tokens." + ":\\(\\w\\|\\s_\\)*" nil - 'punctuation) + 'property) (define-lex-regex-type-analyzer srecode-template-wy--<symbol>-regexp-analyzer "regexp analyzer for <symbol> tokens." @@ -224,6 +244,12 @@ nil 'number) +(define-lex-string-type-analyzer srecode-template-wy--<punctuation>-string-analyzer + "string analyzer for <punctuation> tokens." + "\\s.+" + nil + 'punctuation) + (define-lex-sexp-type-analyzer srecode-template-wy--<string>-sexp-analyzer "sexp analyzer for <string> tokens." "\\s\"" diff --git a/lisp/cedet/srecode/table.el b/lisp/cedet/srecode/table.el index fb7ce6bad2f..37403c4fb9e 100644 --- a/lisp/cedet/srecode/table.el +++ b/lisp/cedet/srecode/table.el @@ -68,6 +68,15 @@ If this is nil, then this template table belongs to a set of generic templates that can be used with no additional dictionary values. When it is non-nil, it is assumed the template macros need specialized Emacs Lisp code to fill in the dictionary.") + (framework :initarg :framework + :type symbol + :documentation + "Tracks the name of the framework these templates belong to. +If nil, then this template table belongs to any framework, or can be +considered generic for all files of this language. +A framework might be a specific library or build environment for which +special templates are desired. OpenGL might be a framework that +exists for multiple languages.") (priority :initarg :priority :type number :documentation @@ -113,23 +122,39 @@ Tracks various lookup hash tables.") (major-mode :initarg :major-mode :documentation "Table of template tables for this major-mode.") + (modetables :initarg :modetables + :documentation + "All that tables unique to this major mode.") (tables :initarg :tables :documentation - "All the tables that have been defined for this major mode.") + "All the tables that can be used for this major mode.") ) "Track template tables for a particular major mode. Tracks all the template-tables for a specific major mode.") (defun srecode-get-mode-table (mode) "Get the SRecoder mode table for the major mode MODE. -Optional argument SOFT indicates to not make a new one if a table -was not found." - (let ((ans nil)) - (while (and (not ans) mode) - (setq ans (eieio-instance-tracker-find - mode 'major-mode 'srecode-mode-table-list) - mode (get-mode-local-parent mode))) - ans)) +This will find the mode table specific to MODE, and then +calculate all inherited templates from parent modes." + (let ((table nil) + (tmptable nil)) + (while mode + (setq tmptable (eieio-instance-tracker-find + mode 'major-mode 'srecode-mode-table-list) + mode (get-mode-local-parent mode)) + (when tmptable + (if (not table) + (progn + ;; If this is the first, update tables to have + ;; all the mode specific tables in it. + (setq table tmptable) + (oset table tables (oref table modetables))) + ;; If there already is a table, then reset the tables + ;; slot to include all the tables belonging to this new child node. + (oset table tables (append (oref table modetables) + (oref tmptable modetables))))) + ) + table)) (defun srecode-make-mode-table (mode) "Get the SRecoder mode table for the major mode MODE." @@ -140,6 +165,7 @@ was not found." (let* ((ms (if (stringp mode) mode (symbol-name mode))) (new (srecode-mode-table ms :major-mode mode + :modetables nil :tables nil))) ;; Save this new mode table in that mode's variable. (eval `(setq-mode-local ,mode srecode-table ,new)) @@ -149,7 +175,7 @@ was not found." (defmethod srecode-mode-table-find ((mt srecode-mode-table) file) "Look in the mode table MT for a template table from FILE. Return nil if there was none." - (object-assoc file 'file (oref mt tables))) + (object-assoc file 'file (oref mt modetables))) (defun srecode-mode-table-new (mode file &rest init) "Create a new template table for MODE in FILE. @@ -166,16 +192,16 @@ INIT are the initialization parameters for the new template table." init ))) ;; Whack the old table. - (when old (object-remove-from-list mt 'tables old)) + (when old (object-remove-from-list mt 'modetables old)) ;; Add the new table - (object-add-to-list mt 'tables new) + (object-add-to-list mt 'modetables new) ;; Sort the list in reverse order. When other routines ;; go front-to-back, the highest priority items are put ;; into the search table first, allowing lower priority items ;; to be the items found in the search table. - (object-sort-list mt 'tables (lambda (a b) - (> (oref a :priority) - (oref b :priority)))) + (object-sort-list mt 'modetables (lambda (a b) + (> (oref a :priority) + (oref b :priority)))) ;; Return it. new)) @@ -231,6 +257,9 @@ Use PREDICATE is the same as for the `sort' function." (when (oref tab :application) (princ "\nApplication: ") (princ (oref tab :application))) + (when (oref tab :framework) + (princ "\nFramework: ") + (princ (oref tab :framework))) (when (oref tab :project) (require 'srecode/find) ; For srecode-template-table-in-project-p (princ "\nProject Directory: ") diff --git a/lisp/emacs-lisp/eieio-base.el b/lisp/emacs-lisp/eieio-base.el index b5600560cdd..6677e2c3abb 100644 --- a/lisp/emacs-lisp/eieio-base.el +++ b/lisp/emacs-lisp/eieio-base.el @@ -4,7 +4,6 @@ ;;; Free Software Foundation, Inc. ;; Author: Eric M. Ludlam <zappo@gnu.org> -;; Version: 0.2 ;; Keywords: OO, lisp ;; Package: eieio @@ -225,8 +224,16 @@ a file. Optional argument NAME specifies a default file name." )))) (oref this file)) -(defun eieio-persistent-read (filename) - "Read a persistent object from FILENAME, and return it." +(defun eieio-persistent-read (filename &optional class allow-subclass) + "Read a persistent object from FILENAME, and return it. +Signal an error if the object in FILENAME is not a constructor +for CLASS. Optional ALLOW-SUBCLASS says that it is ok for +`eieio-peristent-read' to load in subclasses of class instead of +being pendantic." + (unless class + (message "Unsafe call to `eieio-persistent-read'.")) + (when (and class (not (class-p class))) + (signal 'wrong-type-argument (list 'class-p class))) (let ((ret nil) (buffstr nil)) (unwind-protect @@ -239,13 +246,171 @@ a file. Optional argument NAME specifies a default file name." ;; so that any initialize-instance calls that depend on ;; the current buffer will work. (setq ret (read buffstr)) - (if (not (child-of-class-p (car ret) 'eieio-persistent)) - (error "Corrupt object on disk")) - (setq ret (eval ret)) + (when (not (child-of-class-p (car ret) 'eieio-persistent)) + (error "Corrupt object on disk: Unknown saved object")) + (when (and class + (not (or (eq (car ret) class ) ; same class + (and allow-subclass + (child-of-class-p (car ret) class)) ; subclasses + ))) + (error "Corrupt object on disk: Invalid saved class")) + (setq ret (eieio-persistent-convert-list-to-object ret)) (oset ret file filename)) (kill-buffer " *tmp eieio read*")) ret)) +(defun eieio-persistent-convert-list-to-object (inputlist) + "Convert the INPUTLIST, representing object creation to an object. +While it is possible to just `eval' the INPUTLIST, this code instead +validates the existing list, and explicitly creates objects instead of +calling eval. This avoids the possibility of accidentally running +malicious code. + +Note: This function recurses when a slot of :type of some object is +identified, and needing more object creation." + (let ((objclass (nth 0 inputlist)) + (objname (nth 1 inputlist)) + (slots (nthcdr 2 inputlist)) + (createslots nil)) + + ;; If OBJCLASS is an eieio autoload object, then we need to load it. + (eieio-class-un-autoload objclass) + + (while slots + (let ((name (car slots)) + (value (car (cdr slots)))) + + ;; Make sure that the value proposed for SLOT is valid. + ;; In addition, strip out quotes, list functions, and update + ;; object constructors as needed. + (setq value (eieio-persistent-validate/fix-slot-value + objclass name value)) + + (push name createslots) + (push value createslots) + ) + + (setq slots (cdr (cdr slots)))) + + (apply 'make-instance objclass objname (nreverse createslots)) + + ;;(eval inputlist) + )) + +(defun eieio-persistent-validate/fix-slot-value (class slot proposed-value) + "Validate that in CLASS, the SLOT with PROPOSED-VALUE is good, then fix. +A limited number of functions, such as quote, list, and valid object +constructor functions are considered valid. +Secondarilly, any text properties will be stripped from strings." + (cond ((consp proposed-value) + ;; Lists with something in them need special treatment. + (let ((slot-idx (eieio-slot-name-index class nil slot)) + (type nil) + (classtype nil)) + (setq slot-idx (- slot-idx 3)) + (setq type (aref (aref (class-v class) class-public-type) + slot-idx)) + + (setq classtype (eieio-persistent-slot-type-is-class-p + type)) + + (cond ((eq (car proposed-value) 'quote) + (car (cdr proposed-value))) + + ;; An empty list sometimes shows up as (list), which is dumb, but + ;; we need to support it for backward compat. + ((and (eq (car proposed-value) 'list) + (= (length proposed-value) 1)) + nil) + + ;; We have a slot with a single object that can be + ;; saved here. Recurse and evaluate that + ;; sub-object. + ((and classtype (class-p classtype) + (child-of-class-p (car proposed-value) classtype)) + (eieio-persistent-convert-list-to-object + proposed-value)) + + ;; List of object constructors. + ((and (eq (car proposed-value) 'list) + ;; 2nd item is a list. + (consp (car (cdr proposed-value))) + ;; 1st elt of 2nd item is a class name. + (class-p (car (car (cdr proposed-value)))) + ) + + ;; Check the value against the input class type. + ;; If something goes wrong, issue a smart warning + ;; about how a :type is needed for this to work. + (unless (and + ;; Do we have a type? + (consp classtype) (class-p (car classtype))) + (error "In save file, list of object constructors found, but no :type specified for slot %S" + slot)) + + ;; We have a predicate, but it doesn't satisfy the predicate? + (dolist (PV (cdr proposed-value)) + (unless (child-of-class-p (car PV) (car classtype)) + (error "Corrupt object on disk"))) + + ;; We have a list of objects here. Lets load them + ;; in. + (let ((objlist nil)) + (dolist (subobj (cdr proposed-value)) + (push (eieio-persistent-convert-list-to-object subobj) + objlist)) + ;; return the list of objects ... reversed. + (nreverse objlist))) + (t + proposed-value)))) + + ((stringp proposed-value) + ;; Else, check for strings, remove properties. + (substring-no-properties proposed-value)) + + (t + ;; Else, just return whatever the constant was. + proposed-value)) + ) + +(defun eieio-persistent-slot-type-is-class-p (type) + "Return the class refered to in TYPE. +If no class is referenced there, then return nil." + (cond ((class-p type) + ;; If the type is a class, then return it. + type) + + ((and (symbolp type) (string-match "-child$" (symbol-name type)) + (class-p (intern-soft (substring (symbol-name type) 0 + (match-beginning 0))))) + ;; If it is the predicate ending with -child, then return + ;; that class. Unfortunately, in EIEIO, typep of just the + ;; class is the same as if we used -child, so no further work needed. + (intern-soft (substring (symbol-name type) 0 + (match-beginning 0)))) + + ((and (symbolp type) (string-match "-list$" (symbol-name type)) + (class-p (intern-soft (substring (symbol-name type) 0 + (match-beginning 0))))) + ;; If it is the predicate ending with -list, then return + ;; that class and the predicate to use. + (cons (intern-soft (substring (symbol-name type) 0 + (match-beginning 0))) + type)) + + ((and (consp type) (eq (car type) 'or)) + ;; If type is a list, and is an or, it is possibly something + ;; like (or null myclass), so check for that. + (let ((ans nil)) + (dolist (subtype (cdr type)) + (setq ans (eieio-persistent-slot-type-is-class-p + subtype))) + ans)) + + (t + ;; No match, not a class. + nil))) + (defmethod object-write ((this eieio-persistent) &optional comment) "Write persistent object THIS out to the current stream. Optional argument COMMENT is a header line comment." diff --git a/lisp/emacs-lisp/eieio-custom.el b/lisp/emacs-lisp/eieio-custom.el index 59aeb161d8e..cab9caad108 100644 --- a/lisp/emacs-lisp/eieio-custom.el +++ b/lisp/emacs-lisp/eieio-custom.el @@ -332,6 +332,16 @@ Argument OBJ is the object that has been customized." Optional argument GROUP is the sub-group of slots to display." (eieio-customize-object obj group)) +(defvar eieio-custom-mode-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map widget-keymap) + map) + "Keymap for EIEIO Custom mode") + +(define-derived-mode eieio-custom-mode fundamental-mode "EIEIO Custom" + "Major mode for customizing EIEIO objects. +\\{eieio-custom-mode-map}") + (defmethod eieio-customize-object ((obj eieio-default-superclass) &optional group) "Customize OBJ in a specialized custom buffer. @@ -347,6 +357,7 @@ These groups are specified with the `:group' slot flag." (symbol-name g) "*"))) (setq buffer-read-only nil) (kill-all-local-variables) + (eieio-custom-mode) (erase-buffer) (let ((all (overlay-lists))) ;; Delete all the overlays. @@ -363,7 +374,6 @@ These groups are specified with the `:group' slot flag." (widget-insert "\n") (eieio-custom-object-apply-reset obj) ;; Now initialize the buffer - (use-local-map widget-keymap) (widget-setup) ;;(widget-minor-mode) (goto-char (point-min)) @@ -461,8 +471,4 @@ Return the symbol for the group, or nil" (provide 'eieio-custom) -;; Local variables: -;; generated-autoload-file: "eieio.el" -;; End: - ;;; eieio-custom.el ends here diff --git a/lisp/emacs-lisp/eieio-datadebug.el b/lisp/emacs-lisp/eieio-datadebug.el index b7f0deb0ee2..ec470d21bf3 100644 --- a/lisp/emacs-lisp/eieio-datadebug.el +++ b/lisp/emacs-lisp/eieio-datadebug.el @@ -92,12 +92,11 @@ PREBUTTONTEXT is some text between PREFIX and the object button." "Class: ") ;; Loop over all the public slots (let ((publa (aref cv class-public-a)) - (publd (aref cv class-public-d)) ) (while publa (if (slot-boundp obj (car publa)) - (let ((i (class-slot-initarg cl (car publa))) - (v (eieio-oref obj (car publa)))) + (let* ((i (class-slot-initarg cl (car publa))) + (v (eieio-oref obj (car publa)))) (data-debug-insert-thing v prefix (concat (if i (symbol-name i) @@ -112,7 +111,7 @@ PREBUTTONTEXT is some text between PREFIX and the object button." " ") 'font-lock-keyword-face)) ) - (setq publa (cdr publa) publd (cdr publd)))))) + (setq publa (cdr publa)))))) ;;; Augment the Data debug thing display list. (data-debug-add-specialized-thing (lambda (thing) (object-p thing)) diff --git a/lisp/emacs-lisp/eieio-opt.el b/lisp/emacs-lisp/eieio-opt.el index a899839f68a..64b240b9d5d 100644 --- a/lisp/emacs-lisp/eieio-opt.el +++ b/lisp/emacs-lisp/eieio-opt.el @@ -4,7 +4,6 @@ ;; Free Software Foundation, Inc. ;; Author: Eric M. Ludlam <zappo@gnu.org> -;; Version: 0.2 ;; Keywords: OO, lisp ;; Package: eieio @@ -30,6 +29,9 @@ ;; (require 'eieio) +(require 'button) +(require 'help-mode) +(require 'find-func) ;;; Code: ;;;###autoload @@ -85,11 +87,16 @@ Optional HEADERFCN should be called to insert a few bits of info first." (called-interactively-p 'interactive)) (when headerfcn (funcall headerfcn)) - - (if (class-option class :abstract) - (princ "Abstract ")) - (princ "Class ") (prin1 class) + (princ " is a") + (if (class-option class :abstract) + (princ "n abstract")) + (princ " class") + ;; Print file location + (when (get class 'class-location) + (princ " in `") + (princ (file-name-nondirectory (get class 'class-location))) + (princ "'")) (terpri) ;; Inheritance tree information (let ((pl (class-parents class))) @@ -251,8 +258,13 @@ Uses `eieio-describe-class' to describe the class being constructed." (eieio-describe-class fcn (lambda () ;; Describe the constructor part. - (princ "Object Constructor Function: ") (prin1 fcn) + (princ " is an object constructor function") + ;; Print file location + (when (get fcn 'class-location) + (princ " in `") + (princ (file-name-nondirectory (get fcn 'class-location))) + (princ "'")) (terpri) (princ "Creates an object of class ") (prin1 fcn) @@ -262,6 +274,16 @@ Uses `eieio-describe-class' to describe the class being constructed." )) ) +(defun eieio-build-class-list (class) + "Return a list of all classes that inherit from CLASS." + (if (class-p class) + (apply #'append + (mapcar + (lambda (c) + (append (list c) (eieio-build-class-list c))) + (class-children-fast class))) + (list class))) + (defun eieio-build-class-alist (&optional class instantiable-only buildlist) "Return an alist of all currently active classes for completion purposes. Optional argument CLASS is the class to start with. @@ -270,8 +292,9 @@ are not abstract, otherwise allow all classes. Optional argument BUILDLIST is more list to attach and is used internally." (let* ((cc (or class eieio-default-superclass)) (sublst (aref (class-v cc) class-children))) - (if (or (not instantiable-only) (not (class-abstract-p cc))) - (setq buildlist (cons (cons (symbol-name cc) 1) buildlist))) + (unless (assoc (symbol-name cc) buildlist) + (when (or (not instantiable-only) (not (class-abstract-p cc))) + (setq buildlist (cons (cons (symbol-name cc) 1) buildlist)))) (while sublst (setq buildlist (eieio-build-class-alist (car sublst) instantiable-only buildlist)) @@ -342,10 +365,10 @@ Also extracts information about all methods specific to this generic." (princ "Implementations:") (terpri) (terpri) - (let ((i 3) + (let ((i 4) (prefix [ ":STATIC" ":BEFORE" ":PRIMARY" ":AFTER" ] )) ;; Loop over fanciful generics - (while (< i 6) + (while (< i 7) (let ((gm (aref (get generic 'eieio-method-tree) i))) (when gm (princ "Generic ") @@ -357,8 +380,9 @@ Also extracts information about all methods specific to this generic." (setq i (1+ i))) (setq i 0) ;; Loop over defined class-specific methods - (while (< i 3) - (let ((gm (reverse (aref (get generic 'eieio-method-tree) i)))) + (while (< i 4) + (let ((gm (reverse (aref (get generic 'eieio-method-tree) i))) + location) (while gm (princ "`") (prin1 (car (car gm))) @@ -375,6 +399,13 @@ Also extracts information about all methods specific to this generic." ;; 3 because of cdr (princ (or (documentation (cdr (car gm))) "Undocumented")) + ;; Print file location if available + (when (and (setq location (get generic 'method-locations)) + (setq location (assoc (caar gm) location))) + (setq location (cadr location)) + (princ "\n\nDefined in `") + (princ (file-name-nondirectory location)) + (princ "'\n")) (setq gm (cdr gm)) (terpri) (terpri))) @@ -554,7 +585,65 @@ Optional argument HISTORYVAR is the variable to use as history." ;;; HELP AUGMENTATION ;; -;;;###autoload +(define-button-type 'eieio-method-def + :supertype 'help-xref + 'help-function (lambda (class method file) + (eieio-help-find-method-definition class method file)) + 'help-echo (purecopy "mouse-2, RET: find method's definition")) + +(define-button-type 'eieio-class-def + :supertype 'help-xref + 'help-function (lambda (class file) + (eieio-help-find-class-definition class file)) + 'help-echo (purecopy "mouse-2, RET: find class definition")) + +(defun eieio-help-find-method-definition (class method file) + (let ((filename (find-library-name file)) + location buf) + (when (null filename) + (error "Cannot find library %s" file)) + (setq buf (find-file-noselect filename)) + (with-current-buffer buf + (goto-char (point-min)) + (when + (re-search-forward + ;; Regexp for searching methods. + (concat "(defmethod[ \t\r\n]+" method + "\\([ \t\r\n]+:[a-zA-Z]+\\)?" + "[ \t\r\n]+(\\s-*(\\(\\sw\\|\\s_\\)+\\s-+" + class + "\\s-*)") + nil t) + (setq location (match-beginning 0)))) + (if (null location) + (message "Unable to find location in file") + (pop-to-buffer buf) + (goto-char location) + (recenter) + (beginning-of-line)))) + +(defun eieio-help-find-class-definition (class file) + (let ((filename (find-library-name file)) + location buf) + (when (null filename) + (error "Cannot find library %s" file)) + (setq buf (find-file-noselect filename)) + (with-current-buffer buf + (goto-char (point-min)) + (when + (re-search-forward + ;; Regexp for searching a class. + (concat "(defclass[ \t\r\n]+" class "[ \t\r\n]+") + nil t) + (setq location (match-beginning 0)))) + (if (null location) + (message "Unable to find location in file") + (pop-to-buffer buf) + (goto-char location) + (recenter) + (beginning-of-line)))) + + (defun eieio-help-mode-augmentation-maybee (&rest unused) "For buffers thrown into help mode, augment for EIEIO. Arguments UNUSED are not used." @@ -597,6 +686,26 @@ Arguments UNUSED are not used." (goto-char (point-min)) (while (re-search-forward "^\\(Private \\)?Slot:" nil t) (put-text-property (match-beginning 0) (match-end 0) 'face 'bold)) + (goto-char (point-min)) + (cond + ((looking-at "\\(.+\\) is a generic function") + (let ((mname (match-string 1)) + cname) + (while (re-search-forward "^`\\(.+\\)'[^\0]+?Defined in `\\(.+\\)'" nil t) + (setq cname (match-string-no-properties 1)) + (help-xref-button 2 'eieio-method-def cname + mname + (cadr (assoc (intern cname) + (get (intern mname) + 'method-locations))))))) + ((looking-at "\\(.+\\) is an object constructor function in `\\(.+\\)'") + (let ((cname (match-string-no-properties 1))) + (help-xref-button 2 'eieio-class-def cname + (get (intern cname) 'class-location)))) + ((looking-at "\\(.+\\) is a\\(n abstract\\)? class in `\\(.+\\)'") + (let ((cname (match-string-no-properties 1))) + (help-xref-button 3 'eieio-class-def cname + (get (intern cname) 'class-location))))) )))) ;;; SPEEDBAR SUPPORT @@ -698,8 +807,4 @@ INDENT is the current indentation level." (provide 'eieio-opt) -;; Local variables: -;; generated-autoload-file: "eieio.el" -;; End: - ;;; eieio-opt.el ends here diff --git a/lisp/emacs-lisp/eieio-speedbar.el b/lisp/emacs-lisp/eieio-speedbar.el index f169e3f0cd2..327e5ced0e3 100644 --- a/lisp/emacs-lisp/eieio-speedbar.el +++ b/lisp/emacs-lisp/eieio-speedbar.el @@ -3,7 +3,6 @@ ;; Copyright (C) 1999-2002, 2005, 2007-2012 Free Software Foundation, Inc. ;; Author: Eric M. Ludlam <zappo@gnu.org> -;; Version: 0.2 ;; Keywords: OO, tools ;; Package: eieio @@ -191,23 +190,24 @@ that path." ;;; DEFAULT SUPERCLASS baseline methods ;; -;; First, define methods onto the superclass so all classes -;; will have some minor support. +;; First, define methods with no class defined. These will work as if +;; on the default superclass. Specifying no class will allow these to be used +;; when no other methods are found, allowing multiple inheritance to work +;; reliably with eieio-speedbar. -(defmethod eieio-speedbar-description ((object eieio-default-superclass)) +(defmethod eieio-speedbar-description (object) "Return a string describing OBJECT." (object-name-string object)) -(defmethod eieio-speedbar-derive-line-path ((object eieio-default-superclass)) +(defmethod eieio-speedbar-derive-line-path (object) "Return the path which OBJECT has something to do with." nil) -(defmethod eieio-speedbar-object-buttonname ((object eieio-default-superclass)) +(defmethod eieio-speedbar-object-buttonname (object) "Return a string to use as a speedbar button for OBJECT." (object-name-string object)) -(defmethod eieio-speedbar-make-tag-line ((object eieio-default-superclass) - depth) +(defmethod eieio-speedbar-make-tag-line (object depth) "Insert a tag line into speedbar at point for OBJECT. By default, all objects appear as simple TAGS with no need to inherit from the special `eieio-speedbar' classes. Child classes should redefine this @@ -220,7 +220,7 @@ Argument DEPTH is the depth at which the tag line is inserted." 'speedbar-tag-face depth)) -(defmethod eieio-speedbar-handle-click ((object eieio-default-superclass)) +(defmethod eieio-speedbar-handle-click (object) "Handle a click action on OBJECT in speedbar. Any object can be represented as a tag in SPEEDBAR without special attributes. These default objects will be pulled up in a custom diff --git a/lisp/emacs-lisp/eieio.el b/lisp/emacs-lisp/eieio.el index 9304f0e3918..5feaa151fb8 100644 --- a/lisp/emacs-lisp/eieio.el +++ b/lisp/emacs-lisp/eieio.el @@ -4,7 +4,6 @@ ;; Copyright (C) 1995-1996, 1998-2012 Free Software Foundation, Inc. ;; Author: Eric M. Ludlam <zappo@gnu.org> -;; Version: 1.3 ;; Keywords: OO, lisp ;; This file is part of GNU Emacs. @@ -94,21 +93,6 @@ default setting for optimization purposes.") (defvar eieio-optimize-primary-methods-flag t "Non-nil means to optimize the method dispatch on primary methods.") -;; State Variables -;; FIXME: These two constants below should have an `eieio-' prefix added!! -(defvar this nil - "Inside a method, this variable is the object in question. -DO NOT SET THIS YOURSELF unless you are trying to simulate friendly slots. - -Note: Embedded methods are no longer supported. The variable THIS is -still set for CLOS methods for the sake of routines like -`call-next-method'.") - -(defvar scoped-class nil - "This is set to a class when a method is running. -This is so we know we are allowed to check private parts or how to -execute a `call-next-method'. DO NOT SET THIS YOURSELF!") - (defvar eieio-initializing-object nil "Set to non-nil while initializing an object.") @@ -410,6 +394,7 @@ It creates an autoload function for CNAME's constructor." (autoload cname filename doc nil nil) (autoload (intern (concat (symbol-name cname) "-p")) filename "" nil nil) (autoload (intern (concat (symbol-name cname) "-child-p")) filename "" nil nil) + (autoload (intern (concat (symbol-name cname) "-list-p")) filename "" nil nil) )))) @@ -539,6 +524,23 @@ See `defclass' for more information." (and (eieio-object-p obj) (object-of-class-p obj ,cname)))) + ;; Create a handy list of the class test too + (let ((csym (intern (concat (symbol-name cname) "-list-p")))) + (fset csym + `(lambda (obj) + ,(format + "Test OBJ to see if it a list of objects which are a child of type %s" + cname) + (when (listp obj) + (let ((ans t)) ;; nil is valid + ;; Loop over all the elements of the input list, test + ;; each to make sure it is a child of the desired object class. + (while (and obj ans) + (setq ans (and (eieio-object-p (car obj)) + (object-of-class-p (car obj) ,cname))) + (setq obj (cdr obj))) + ans))))) + ;; When using typep, (typep OBJ 'myclass) returns t for objects which ;; are subclasses of myclass. For our predicates, however, it is ;; important for EIEIO to be backwards compatible, where @@ -781,6 +783,16 @@ See `defclass' for more information." (put cname 'variable-documentation (class-option-assoc options :documentation)) + ;; Save the file location where this class is defined. + (let ((fname (if load-in-progress + load-file-name + buffer-file-name)) + loc) + (when fname + (when (string-match "\\.elc$" fname) + (setq fname (substring fname 0 (1- (length fname))))) + (put cname 'class-location fname))) + ;; We have a list of custom groups. Store them into the options. (let ((g (class-option-assoc options :custom-groups))) (mapc (lambda (cg) (add-to-list 'g cg)) groups) @@ -1254,8 +1266,10 @@ IMPL is the symbol holding the method implementation." (eieio-generic-call-methodname ',method) (eieio-generic-call-arglst local-args) ) - (apply #',impl local-args) - ;;(,impl local-args) + ,(if (< emacs-major-version 24) + `(apply ,(list 'quote impl) local-args) + `(apply #',impl local-args)) + ;(,impl local-args) ))))))) (defsubst eieio-defgeneric-reset-generic-form-primary-only-one (method) @@ -2008,13 +2022,13 @@ reverse-lookup that name, and recurse with the associated slot value." ((not (get fsym 'protection)) (+ 3 fsi)) ((and (eq (get fsym 'protection) 'protected) - scoped-class + (bound-and-true-p scoped-class) (or (child-of-class-p class scoped-class) (and (eieio-object-p obj) (child-of-class-p class (object-class obj))))) (+ 3 fsi)) ((and (eq (get fsym 'protection) 'private) - (or (and scoped-class + (or (and (bound-and-true-p scoped-class) (eieio-slot-originating-class-p scoped-class slot)) eieio-initializing-object)) (+ 3 fsi)) @@ -2319,7 +2333,7 @@ If REPLACEMENT-ARGS is non-nil, then use them instead of arguments passed in at the top level. Use `next-method-p' to find out if there is a next method to call." - (if (not scoped-class) + (if (not (bound-and-true-p scoped-class)) (error "`call-next-method' not called within a class specific method")) (if (and (/= eieio-generic-call-key method-primary) (/= eieio-generic-call-key method-static)) @@ -2403,6 +2417,18 @@ CLASS is the class this method is associated with." (if (< key method-num-lists) (let ((nsym (intern (symbol-name class) (aref emto key)))) (fset nsym method))) + ;; Save the defmethod file location in a symbol property. + (let ((fname (if load-in-progress + load-file-name + buffer-file-name)) + loc) + (when fname + (when (string-match "\\.elc$" fname) + (setq fname (substring fname 0 (1- (length fname))))) + (setq loc (get method-name 'method-locations)) + (add-to-list 'loc + (list class fname)) + (put method-name 'method-locations loc))) ;; Now optimize the entire obarray (if (< key method-num-lists) (let ((eieiomt-optimizing-obarray (aref emto key))) @@ -2807,9 +2833,9 @@ this object." (princ (make-string (* eieio-print-depth 2) ? )) (princ "(") (princ (symbol-name (class-constructor (object-class this)))) - (princ " \"") - (princ (object-name-string this)) - (princ "\"\n") + (princ " ") + (prin1 (object-name-string this)) + (princ "\n") ;; Loop over all the public slots (let ((publa (aref cv class-public-a)) (publd (aref cv class-public-d)) @@ -2876,7 +2902,6 @@ of `eq'." ) - ;;; Obsolete backward compatibility functions. ;; Needed to run byte-code compiled with the EIEIO of Emacs-23. |