Following up on a thread from May '08...
"Eric M. Ludlam" <eric@...> writes:
>>>> David <de_bb@...> seems to think that:
>>OK, I managed to scan all the tags in my Matlab files with
>>semanticdb-mk.el. This works nicely for completing/searching tags for
>>files in the current directory, but how do I get CEDET/semantic to also
>>use the tags in all the subdirectories? As you said, Matlab doesn't have
>>an 'include' statement, so I guess I would somehow have to specify
>>"manually" which subdirectories should be included?
>
> Since MATLAB doesn't conform to the C like mechanisms, getting this
> sort of thing to work requires overloading all the functions that are
> too C centric. For example, `semanticdb-find-tag-by-name' calls
> something that builds a `path'. That semanticdb-find-translate-path
> should be overridden to include the local file, anything in private
> with the specified name, and anything on the MATLAB path with the
> specified name. (Find-translate-path builds a map of DB tables to
> search, and is different from a what might be considered an include
> path.)
OK, after some Emacs Lisp I now got back to Matlab. :-) Matlab doesn't
have an include mechanism, instead you could say it simply includes
every function it finds in its path. So I overloaded
semantidb-find-translate-path for matlab-mode to make semantic believe a
M-file just does that. The Matlab path is for now simply specified by a
new variable (semantic-matlab-include-paths), but should be better
replaced by what you already suggested:
> A second thing is to write a simple EDE project for MATLAB that knows
> how to look at a MATLAB install, and extract the file path.
But since not everyone uses EDE, I guess it also makes sense to have a
variable to manually specify the search path.
I attached to this message how far I've come. This is all pretty crude
yet and needs some serious cleaning up; I just copied most of the stuff
from semantidb-find.el, but it already works reasonably well, with the
notable exception of caching. First, caching seems to work: If I
initiate a completion, the find-translate-path function gets called, the
M-files are scanned, and in the subsequent calls to find-translate-path
(still for the same completion) the cached values are used. However,
every time I initiate a *new* completion, the files get
re-scanned. Somehow the include-path in the tag object is not saved
between completions. Maybe you immediately know what the problem is
here, otherwise I'll further have to dig into it.
I don't know if these is even a good way to do this. Maybe one should
better use an omniscient databases for this, like in Emacs Lisp mode?
Thanks for your help,
David
Here's the code I put into semantic-matlab.el:
(defvar semantic-matlab-include-paths
'("/usr/matlab/7.4/toolbox/matlab/general"
"/home/david/someproject")
"Directories which should be scanned for m-files.")
(defun semantic-matlab-generate-include-tags (dirs)
"Create include tags with m-files in DIRS.
DIRS is a list of directories."
(let (tags)
(dolist (dir dirs)
(dolist (cur (directory-files dir t "\\.m$" t))
(push (semantic-tag-new-include cur nil) tags)))
tags))
(define-mode-local-override semanticdb-find-translate-path
matlab-mode (path brutish)
"Translate PATH into a list of semantic tables."
(if (semanticdb-find-results-p path)
;; Perform the search over these results.
nil
(if brutish
(semanticdb-find-translate-path-brutish-default path)
(let ((table (cond ((null path)
semanticdb-current-table)
((semanticdb-abstract-table-child-p path)
path)
(t nil))))
(if table
;; If we were passed in something related to a TABLE,
;; do a caching lookup.
(let ((index (semanticdb-get-table-index table)))
(if (semanticdb-find-need-cache-update-p table)
;; Lets go look up our indicies
(let ((ans (semantic-matlab-translate-path-includes--internal path)))
(oset index include-path ans)
;; Once we have our new indicies set up, notify those
;; who depend on us if we found something for them to
;; depend on.
(when ans (semanticdb-refresh-references table))
ans)
;; ELSE
;;
;; Just return the cache.
(oref index include-path)))
;; If we were passed in something like a tag list, or other boring
;; searchable item, then instead do the regular thing without caching.
(semantic-matlab-translate-path-includes--internal path))))))
(defun semantic-matlab-translate-path-includes--internal (path)
"Include all m-files found in `semantic-matlab-include-paths' in PATH."
(let ((includetags nil)
(curtable nil)
(matchedtables (list semanticdb-current-table))
(matchedincludes nil)
(lostincludes nil)
(scannedincludes nil)
(incfname nil)
nexttable)
(setq includetags (semantic-matlab-generate-include-tags semantic-matlab-include-paths))
(cond ((null path)
(setq curtable semanticdb-current-table
incfname (buffer-file-name))
)
((semanticdb-table-p path)
(setq curtable path
incfname (semanticdb-full-filename path))
)
((bufferp path)
(setq curtable (save-excursion (set-buffer path)
semanticdb-current-table)
incfname (buffer-file-name path)))
(t
(when includetags
;; If we have some tags, derive a table from them.
;; else we will do nothing, so the table is useless.
;; @todo - derive some tables
(message "Need to derive tables for %S in translate-path-includes--default."
path)
)))
;; Make sure each found include tag has an originating file name associated
;; with it.
(when incfname
(dolist (it includetags)
(semantic--tag-put-property it :filename incfname)))
;; Loop over all include tags adding to matchedtables
(while includetags
(semantic-throw-on-input 'semantic-find-translate-path-includes-default)
;; If we've seen this include string before, lets skip it.
(if (member (semantic-tag-name (car includetags)) matchedincludes)
(progn
(setq nexttable nil)
(push (cons 'duplicate (semantic-tag-clone (car includetags)))
scannedincludes)
)
(setq nexttable (semanticdb-find-table-for-include (car includetags) curtable))
(when (not nexttable)
;; Save the lost include.
(push (car includetags) lostincludes)
(push (cons 'lost (semantic-tag-clone (car includetags)))
scannedincludes)
)
)
;; Push the include file, so if we can't find it, we only
;; can't find it once.
(push (semantic-tag-name (car includetags)) matchedincludes)
(message "Scanning %s" (semantic-tag-name (car includetags)))
(when (and nexttable
(not (memq nexttable matchedtables))
(semanticdb-equivalent-mode-for-search nexttable
(current-buffer))
)
;; Add to list of tables
(push nexttable matchedtables)
)
(setq includetags (cdr includetags)))
(setq semanticdb-find-lost-includes lostincludes)
(setq semanticdb-find-scanned-include-tags (reverse scannedincludes))
(nreverse matchedtables)))
|