lisp/cedet/srecode.el:
lisp/cedet/srecode/*.el: test/cedet/srecode-tests.el: New files lisp/files.el (auto-mode-alist): Use srecode-template-mode for .srt files. lisp/cedet/semantic/bovine/scm.el: Add local vars section for autoloading.
This commit is contained in:
parent
70702e9b0e
commit
4d902e6f13
29 changed files with 8633 additions and 0 deletions
|
@ -9,6 +9,7 @@
|
|||
* progmodes/autoconf.el: Provide autoconf as well.
|
||||
|
||||
* files.el (auto-mode-alist): Use emacs-lisp-mode for Project.ede.
|
||||
(auto-mode-alist): Use srecode-template-mode for .srt files.
|
||||
|
||||
* cedet/semantic/bovine/gcc.el (semantic-gcc-test-output-parser)
|
||||
(semantic-gcc-test-output-parser-this-machine):
|
||||
|
|
|
@ -115,4 +115,10 @@ syntax as specified by the syntax table."
|
|||
|
||||
(provide 'semantic/bovine/scm)
|
||||
|
||||
;; Local variables:
|
||||
;; generated-autoload-file: "../loaddefs.el"
|
||||
;; generated-autoload-feature: semantic/loaddefs
|
||||
;; generated-autoload-load-name: "semantic/bovine/scm"
|
||||
;; End:
|
||||
|
||||
;;; semantic/bovine/scm.el ends here
|
||||
|
|
53
lisp/cedet/srecode.el
Normal file
53
lisp/cedet/srecode.el
Normal file
|
@ -0,0 +1,53 @@
|
|||
;;; srecode.el --- Semantic buffer evaluator.
|
||||
|
||||
;;; Copyright (C) 2005, 2007, 2008, 2009 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Eric M. Ludlam <zappo@gnu.org>
|
||||
;; Keywords: codegeneration
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; Semantic does the job of converting source code into useful tag
|
||||
;; information. The set of `semantic-format-tag' functions has one
|
||||
;; function that will create a prototype of a tag, which has severe
|
||||
;; issues of complexity (in the format tag file itself) and inaccuracy
|
||||
;; (for the purpose of C++ code.)
|
||||
;;
|
||||
;; Contemplation of the simplistic problem within the scope of
|
||||
;; semantic showed that the solution was more complex than could
|
||||
;; possibly be handled in semantic-format.el. Semantic Recode, or
|
||||
;; srecode is a rich API for generating code out of semantic tags, or
|
||||
;; recoding the tags.
|
||||
;;
|
||||
;; See the srecode manual for specific details.
|
||||
|
||||
(require 'eieio)
|
||||
(require 'mode-local)
|
||||
(require 'srecode/loaddefs)
|
||||
|
||||
(defvar srecode-version "1.0pre7"
|
||||
"Current version of the Semantic Recoder.")
|
||||
|
||||
;;; Code:
|
||||
(defgroup srecode nil
|
||||
"Semantic Recoder."
|
||||
:group 'tools)
|
||||
|
||||
(provide 'srecode)
|
||||
|
||||
;;; srecode.el ends here
|
188
lisp/cedet/srecode/args.el
Normal file
188
lisp/cedet/srecode/args.el
Normal file
|
@ -0,0 +1,188 @@
|
|||
;;; srecode/args.el --- Provide some simple template arguments
|
||||
|
||||
;;; Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Eric M. Ludlam <eric@siege-engine.com>
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; Srecode templates can accept arguments. These arguments represent
|
||||
;; sets of dictionary words that need to be derived. This file contains
|
||||
;; a set of simple arguments for srecode templates.
|
||||
|
||||
(require 'srecode/insert)
|
||||
|
||||
;;; Code:
|
||||
|
||||
;;; :blank
|
||||
;;
|
||||
;; Using :blank means that the template should force blank lines
|
||||
;; before and after the template, reguardless of where the insertion
|
||||
;; is occuring.
|
||||
(defun srecode-semantic-handle-:blank (dict)
|
||||
"Add macros into the dictionary DICT specifying blank line spacing.
|
||||
The wrapgap means make sure the first and last lines of the macro
|
||||
do not contain any text from preceeding or following text."
|
||||
;; This won't actually get used, but it might be nice
|
||||
;; to know about it.
|
||||
(srecode-dictionary-set-value dict "BLANK" t)
|
||||
)
|
||||
|
||||
;;; :indent ARGUMENT HANDLING
|
||||
;;
|
||||
;; When a :indent argument is required, the default is to indent
|
||||
;; for the current major mode.
|
||||
(defun srecode-semantic-handle-:indent (dict)
|
||||
"Add macros into the dictionary DICT for indentation."
|
||||
(srecode-dictionary-set-value dict "INDENT" t)
|
||||
)
|
||||
|
||||
;;; :region ARGUMENT HANDLING
|
||||
;;
|
||||
;; When a :region argument is required, provide macros that
|
||||
;; deal with that active region.
|
||||
;;
|
||||
;; Regions allow a macro to wrap the region text within the
|
||||
;; template bounds.
|
||||
;;
|
||||
(defvar srecode-handle-region-when-non-active-flag nil
|
||||
"Non-nil means do region handling w/out the region being active.")
|
||||
|
||||
(defun srecode-semantic-handle-:region (dict)
|
||||
"Add macros into the dictionary DICT based on the current :region."
|
||||
;; Only enable the region section if we can clearly show that
|
||||
;; the user is intending to do something with the region.
|
||||
(when (or srecode-handle-region-when-non-active-flag
|
||||
(eq last-command 'mouse-drag-region)
|
||||
(and transient-mark-mode mark-active))
|
||||
;; Show the region section
|
||||
(srecode-dictionary-show-section dict "REGION")
|
||||
(srecode-dictionary-set-value
|
||||
dict "REGIONTEXT" (buffer-substring-no-properties (point) (mark)))
|
||||
;; Only whack the region if our template output
|
||||
;; is also destined for the current buffer.
|
||||
(when (eq standard-output (current-buffer))
|
||||
(kill-region (point) (mark))))
|
||||
)
|
||||
|
||||
;;; :user ARGUMENT HANDLING
|
||||
;;
|
||||
;; When a :user argument is required, fill the dictionary with
|
||||
;; information about the current Emacs user.
|
||||
(defun srecode-semantic-handle-:user (dict)
|
||||
"Add macros into the dictionary DICT based on the current :user."
|
||||
(srecode-dictionary-set-value dict "AUTHOR" (user-full-name))
|
||||
(srecode-dictionary-set-value dict "LOGIN" (user-login-name))
|
||||
(srecode-dictionary-set-value dict "EMAIL" user-mail-address)
|
||||
(srecode-dictionary-set-value dict "EMACSINITFILE" user-init-file)
|
||||
(srecode-dictionary-set-value dict "UID" (user-uid))
|
||||
)
|
||||
|
||||
;;; :time ARGUMENT HANDLING
|
||||
;;
|
||||
;; When a :time argument is required, fill the dictionary with
|
||||
;; information about the current Emacs time.
|
||||
(defun srecode-semantic-handle-:time (dict)
|
||||
"Add macros into the dictionary DICT based on the current :time."
|
||||
;; DATE Values
|
||||
(srecode-dictionary-set-value
|
||||
dict "YEAR" (format-time-string "%Y" (current-time)))
|
||||
(srecode-dictionary-set-value
|
||||
dict "MONTHNAME" (format-time-string "%B" (current-time)))
|
||||
(srecode-dictionary-set-value
|
||||
dict "MONTH" (format-time-string "%m" (current-time)))
|
||||
(srecode-dictionary-set-value
|
||||
dict "DAY" (format-time-string "%d" (current-time)))
|
||||
(srecode-dictionary-set-value
|
||||
dict "WEEKDAY" (format-time-string "%a" (current-time)))
|
||||
;; Time Values
|
||||
(srecode-dictionary-set-value
|
||||
dict "HOUR" (format-time-string "%H" (current-time)))
|
||||
(srecode-dictionary-set-value
|
||||
dict "HOUR12" (format-time-string "%l" (current-time)))
|
||||
(srecode-dictionary-set-value
|
||||
dict "AMPM" (format-time-string "%p" (current-time)))
|
||||
(srecode-dictionary-set-value
|
||||
dict "MINUTE" (format-time-string "%M" (current-time)))
|
||||
(srecode-dictionary-set-value
|
||||
dict "SECOND" (format-time-string "%S" (current-time)))
|
||||
(srecode-dictionary-set-value
|
||||
dict "TIMEZONE" (format-time-string "%Z" (current-time)))
|
||||
;; Convenience pre-packed date/time
|
||||
(srecode-dictionary-set-value
|
||||
dict "DATE" (format-time-string "%D" (current-time)))
|
||||
(srecode-dictionary-set-value
|
||||
dict "TIME" (format-time-string "%X" (current-time)))
|
||||
)
|
||||
|
||||
;;; :file ARGUMENT HANDLING
|
||||
;;
|
||||
;; When a :file argument is required, fill the dictionary with
|
||||
;; information about the file Emacs is editing at the time of
|
||||
;; insertion.
|
||||
(defun srecode-semantic-handle-:file (dict)
|
||||
"Add macros into the dictionary DICT based on the current :file."
|
||||
(let* ((bfn (buffer-file-name))
|
||||
(file (file-name-nondirectory bfn))
|
||||
(dir (file-name-directory bfn)))
|
||||
(srecode-dictionary-set-value dict "FILENAME" file)
|
||||
(srecode-dictionary-set-value dict "FILE" (file-name-sans-extension file))
|
||||
(srecode-dictionary-set-value dict "EXTENSION" (file-name-extension file))
|
||||
(srecode-dictionary-set-value dict "DIRECTORY" dir)
|
||||
(srecode-dictionary-set-value dict "MODE" (symbol-name major-mode))
|
||||
(srecode-dictionary-set-value
|
||||
dict "SHORTMODE"
|
||||
(let* ((mode-name (symbol-name major-mode))
|
||||
(match (string-match "-mode" mode-name)))
|
||||
(if match
|
||||
(substring mode-name 0 match)
|
||||
mode-name)))
|
||||
(if (or (file-exists-p "CVS")
|
||||
(file-exists-p "RCS"))
|
||||
(srecode-dictionary-show-section dict "RCS")
|
||||
)))
|
||||
|
||||
;;; :system ARGUMENT HANDLING
|
||||
;;
|
||||
;; When a :system argument is required, fill the dictionary with
|
||||
;; information about the computer Emacs is running on.
|
||||
(defun srecode-semantic-handle-:system (dict)
|
||||
"Add macros into the dictionary DICT based on the current :system."
|
||||
(srecode-dictionary-set-value dict "SYSTEMCONF" system-configuration)
|
||||
(srecode-dictionary-set-value dict "SYSTEMTYPE" system-type)
|
||||
(srecode-dictionary-set-value dict "SYSTEMNAME" (system-name))
|
||||
(srecode-dictionary-set-value dict "MAILHOST" (or mail-host-address
|
||||
(system-name)))
|
||||
)
|
||||
|
||||
;;; :kill ARGUMENT HANDLING
|
||||
;;
|
||||
;; When a :kill argument is required, fill the dictionary with
|
||||
;; information about the current kill ring.
|
||||
(defun srecode-semantic-handle-:kill (dict)
|
||||
"Add macros into the dictionary DICT based on the kill ring."
|
||||
(srecode-dictionary-set-value dict "KILL" (car kill-ring))
|
||||
(srecode-dictionary-set-value dict "KILL2" (nth 1 kill-ring))
|
||||
(srecode-dictionary-set-value dict "KILL3" (nth 2 kill-ring))
|
||||
(srecode-dictionary-set-value dict "KILL4" (nth 3 kill-ring))
|
||||
)
|
||||
|
||||
(provide 'srecode/args)
|
||||
|
||||
;;; srecode/args.el ends here
|
||||
|
640
lisp/cedet/srecode/compile.el
Normal file
640
lisp/cedet/srecode/compile.el
Normal file
|
@ -0,0 +1,640 @@
|
|||
;;; srecode/compile --- Compilation of srecode template files.
|
||||
|
||||
;;; Copyright (C) 2005, 2007, 2008, 2009 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Eric M. Ludlam <zappo@gnu.org>
|
||||
;; Keywords: codegeneration
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; Compile a Semantic Recoder template file.
|
||||
;;
|
||||
;; Template files are parsed using a Semantic/Wisent parser into
|
||||
;; a tag table. The code therin is then further parsed down using
|
||||
;; a regular expression parser.
|
||||
;;
|
||||
;; The output are a series of EIEIO objects which represent the
|
||||
;; templates in a way that could be inserted later.
|
||||
|
||||
(require 'semantic)
|
||||
(require 'eieio)
|
||||
(require 'eieio-base)
|
||||
(require 'srecode)
|
||||
(require 'srecode/table)
|
||||
|
||||
(declare-function srecode-template-inserter-newline-child-p "srecode/insert")
|
||||
(declare-function srecode-create-section-dictionary "srecode/dictionary")
|
||||
(declare-function srecode-dictionary-compound-variable "srecode/dictionary")
|
||||
|
||||
;;; Code:
|
||||
|
||||
;;; Template Class
|
||||
;;
|
||||
;; Templatets describe a patter of text that can be inserted into a
|
||||
;; buffer.
|
||||
;;
|
||||
(defclass srecode-template (eieio-named)
|
||||
((context :initarg :context
|
||||
:initform nil
|
||||
:documentation
|
||||
"Context this template belongs to.")
|
||||
(args :initarg :args
|
||||
:documentation
|
||||
"List of arguments that this template requires.")
|
||||
(code :initarg :code
|
||||
:documentation
|
||||
"Compiled text from the template.")
|
||||
(dictionary :initarg :dictionary
|
||||
:type (or null srecode-dictionary)
|
||||
:documentation
|
||||
"List of section dictinaries.
|
||||
The compiled template can contain lists of section dictionaries,
|
||||
or values that are expected to be passed down into different
|
||||
section macros. The template section dictionaries are merged in with
|
||||
any incomming dictionaries values.")
|
||||
(binding :initarg :binding
|
||||
:documentation
|
||||
"Preferred keybinding for this template in `srecode-minor-mode-map'.")
|
||||
(active :allocation :class
|
||||
:initform nil
|
||||
:documentation
|
||||
"During template insertion, this is the stack of active templates.
|
||||
The top-most template is the 'active' template. Use the accessor methods
|
||||
for push, pop, and peek for the active template.")
|
||||
(table :initarg :table
|
||||
:documentation
|
||||
"The table this template lives in.")
|
||||
)
|
||||
"Class defines storage for semantic recoder templates.")
|
||||
|
||||
(defun srecode-flush-active-templates ()
|
||||
"Flush the active template storage.
|
||||
Useful if something goes wrong in SRecode, and the active tempalte
|
||||
stack is broken."
|
||||
(interactive)
|
||||
(if (oref srecode-template active)
|
||||
(when (y-or-n-p (format "%d active templates. Flush? "
|
||||
(length (oref srecode-template active))))
|
||||
(oset-default srecode-template active nil))
|
||||
(message "No active templates to flush."))
|
||||
)
|
||||
|
||||
;;; Inserters
|
||||
;;
|
||||
;; Each inserter object manages a different thing that
|
||||
;; might be inserted into a template output stream.
|
||||
;;
|
||||
;; The 'srecode-insert-method' on each inserter does the actual
|
||||
;; work, and the smaller, simple inserter object is saved in
|
||||
;; the compiled templates.
|
||||
;;
|
||||
;; See srecode-insert.el for the specialized classes.
|
||||
;;
|
||||
(defclass srecode-template-inserter (eieio-named)
|
||||
((secondname :initarg :secondname
|
||||
:type (or null string)
|
||||
:documentation
|
||||
"If there is a colon in the inserter's name, it represents
|
||||
additional static argument data."))
|
||||
"This represents an item to be inserted via a template macro.
|
||||
Plain text strings are not handled via this baseclass."
|
||||
:abstract t)
|
||||
|
||||
(defmethod srecode-parse-input ((ins srecode-template-inserter)
|
||||
tag input STATE)
|
||||
"For the template inserter INS, parse INPUT.
|
||||
Shorten input only by the amount needed.
|
||||
Return the remains of INPUT.
|
||||
STATE is the current compilation state."
|
||||
input)
|
||||
|
||||
(defmethod srecode-match-end ((ins srecode-template-inserter) name)
|
||||
"For the template inserter INS, do I end a section called NAME?"
|
||||
nil)
|
||||
|
||||
(defmethod srecode-inserter-apply-state ((ins srecode-template-inserter) STATE)
|
||||
"For the template inserter INS, apply information from STATE."
|
||||
nil)
|
||||
|
||||
(defmethod srecode-inserter-prin-example :STATIC ((ins srecode-template-inserter)
|
||||
escape-start escape-end)
|
||||
"Insert an example using inserter INS.
|
||||
Arguments ESCAPE-START and ESCAPE-END are the current escape sequences in use."
|
||||
(princ " ")
|
||||
(princ escape-start)
|
||||
(when (and (slot-exists-p ins 'key) (oref ins key))
|
||||
(princ (format "%c" (oref ins key))))
|
||||
(princ "VARNAME")
|
||||
(princ escape-end)
|
||||
(terpri)
|
||||
)
|
||||
|
||||
|
||||
;;; Compile State
|
||||
(defclass srecode-compile-state ()
|
||||
((context :initform "declaration"
|
||||
:documentation "The active context.")
|
||||
(prompts :initform nil
|
||||
:documentation "The active prompts.")
|
||||
(escape_start :initform "{{"
|
||||
:documentation "The starting escape sequence.")
|
||||
(escape_end :initform "}}"
|
||||
:documentation "The ending escape sequence.")
|
||||
)
|
||||
"Current state of the compile.")
|
||||
|
||||
(defmethod srecode-compile-add-prompt ((state srecode-compile-state)
|
||||
prompttag)
|
||||
"Add PROMPTTAG to the current list of prompts."
|
||||
(with-slots (prompts) state
|
||||
(let ((match (assoc (semantic-tag-name prompttag) prompts))
|
||||
(newprompts prompts))
|
||||
(when match
|
||||
(let ((tmp prompts))
|
||||
(setq newprompts nil)
|
||||
(while tmp
|
||||
(when (not (string= (car (car tmp))
|
||||
(car prompttag)))
|
||||
(setq newprompts (cons (car tmp)
|
||||
newprompts)))
|
||||
(setq tmp (cdr tmp)))))
|
||||
(setq prompts (cons prompttag newprompts)))
|
||||
))
|
||||
|
||||
;;; TEMPLATE COMPILER
|
||||
;;
|
||||
(defun srecode-compile-file (fname)
|
||||
"Compile the templates from the file FNAME."
|
||||
(let ((peb (get-file-buffer fname)))
|
||||
(save-excursion
|
||||
;; Make whatever it is local.
|
||||
(if (not peb)
|
||||
(set-buffer (semantic-find-file-noselect fname))
|
||||
(set-buffer peb))
|
||||
;; Do the compile.
|
||||
(srecode-compile-templates)
|
||||
;; Trash the buffer if we had to read it in.
|
||||
(if (not peb)
|
||||
(kill-buffer (current-buffer)))
|
||||
)))
|
||||
|
||||
;;;###autoload
|
||||
(defun srecode-compile-templates ()
|
||||
"Compile a semantic recode template file into a mode-local variable."
|
||||
(interactive)
|
||||
(require 'srecode-insert)
|
||||
(message "Compiling template %s..."
|
||||
(file-name-nondirectory (buffer-file-name)))
|
||||
(let ((tags (semantic-fetch-tags))
|
||||
(tag nil)
|
||||
(class nil)
|
||||
(table nil)
|
||||
(STATE (srecode-compile-state (file-name-nondirectory
|
||||
(buffer-file-name))))
|
||||
(mode nil)
|
||||
(application nil)
|
||||
(priority nil)
|
||||
(vars nil)
|
||||
)
|
||||
|
||||
;;
|
||||
;; COMPILE
|
||||
;;
|
||||
(while tags
|
||||
(setq tag (car tags)
|
||||
class (semantic-tag-class tag))
|
||||
;; What type of item is it?
|
||||
(cond
|
||||
;; CONTEXT tags specify the context all future tags
|
||||
;; belong to.
|
||||
((eq class 'context)
|
||||
(oset STATE context (semantic-tag-name tag))
|
||||
)
|
||||
|
||||
;; PROMPT tags specify prompts for dictionary ? inserters
|
||||
;; which appear in the following templates
|
||||
((eq class 'prompt)
|
||||
(srecode-compile-add-prompt STATE tag)
|
||||
)
|
||||
|
||||
;; VARIABLE tags can specify operational control
|
||||
((eq class 'variable)
|
||||
(let* ((name (semantic-tag-name tag))
|
||||
(value (semantic-tag-variable-default tag))
|
||||
(firstvalue (car value)))
|
||||
;; If it is a single string, and one value, then
|
||||
;; look to see if it is one of our special variables.
|
||||
(if (and (= (length value) 1) (stringp firstvalue))
|
||||
(cond ((string= name "mode")
|
||||
(setq mode (intern firstvalue)))
|
||||
((string= name "escape_start")
|
||||
(oset STATE escape_start firstvalue)
|
||||
)
|
||||
((string= name "escape_end")
|
||||
(oset STATE escape_end firstvalue)
|
||||
)
|
||||
((string= name "application")
|
||||
(setq application (read firstvalue)))
|
||||
((string= name "priority")
|
||||
(setq priority (read firstvalue)))
|
||||
(t
|
||||
;; Assign this into some table of variables.
|
||||
(setq vars (cons (cons name firstvalue) vars))
|
||||
))
|
||||
;; If it isn't a single string, then the value of the
|
||||
;; variable belongs to a compound dictionary value.
|
||||
;;
|
||||
;; Create a compound dictionary value from "value".
|
||||
(require 'srecode/dictionary)
|
||||
(let ((cv (srecode-dictionary-compound-variable
|
||||
name :value value)))
|
||||
(setq vars (cons (cons name cv) vars)))
|
||||
))
|
||||
)
|
||||
|
||||
;; FUNCTION tags are really templates.
|
||||
((eq class 'function)
|
||||
(setq table (cons (srecode-compile-one-template-tag tag STATE)
|
||||
table))
|
||||
)
|
||||
|
||||
;; Ooops
|
||||
(t (error "Unknown TAG class %s" class))
|
||||
)
|
||||
;; Continue
|
||||
(setq tags (cdr tags)))
|
||||
|
||||
;; MSG - Before install since nreverse whacks our list.
|
||||
(message "%d templates compiled for %s"
|
||||
(length table) mode)
|
||||
|
||||
;;
|
||||
;; APPLY TO MODE
|
||||
;;
|
||||
(if (not mode)
|
||||
(error "You must specify a MODE for your templates"))
|
||||
|
||||
;;
|
||||
;; Calculate priority
|
||||
;;
|
||||
(if (not priority)
|
||||
(let ((d (file-name-directory (buffer-file-name)))
|
||||
(sd (file-name-directory (locate-library "srecode")))
|
||||
(defaultdelta (if (eq mode 'default) 20 0)))
|
||||
(if (string= d sd)
|
||||
(setq priority (+ 80 defaultdelta))
|
||||
(setq priority (+ 30 defaultdelta)))
|
||||
(message "Templates %s has estimated priority of %d"
|
||||
(file-name-nondirectory (buffer-file-name))
|
||||
priority))
|
||||
(message "Compiling templates %s priority %d... done!"
|
||||
(file-name-nondirectory (buffer-file-name))
|
||||
priority))
|
||||
|
||||
;; Save it up!
|
||||
(srecode-compile-template-table table mode priority application vars)
|
||||
)
|
||||
)
|
||||
|
||||
(defun srecode-compile-one-template-tag (tag STATE)
|
||||
"Compile a template tag TAG into an srecode template class.
|
||||
STATE is the current compile state as an object `srecode-compile-state'."
|
||||
(require 'srecode/dictionary)
|
||||
(let* ((context (oref STATE context))
|
||||
(codeout (srecode-compile-split-code
|
||||
tag (semantic-tag-get-attribute tag :code)
|
||||
STATE))
|
||||
(code (cdr codeout))
|
||||
(args (semantic-tag-function-arguments tag))
|
||||
(binding (semantic-tag-get-attribute tag :binding))
|
||||
(rawdicts (semantic-tag-get-attribute tag :dictionaries))
|
||||
(sdicts (srecode-create-section-dictionary rawdicts STATE))
|
||||
(addargs nil)
|
||||
)
|
||||
; (message "Compiled %s to %d codes with %d args and %d prompts."
|
||||
; (semantic-tag-name tag)
|
||||
; (length code)
|
||||
; (length args)
|
||||
; (length prompts))
|
||||
(while args
|
||||
(setq addargs (cons (intern (car args)) addargs))
|
||||
(when (eq (car addargs) :blank)
|
||||
;; If we have a wrap, then put wrap inserters on both
|
||||
;; ends of the code.
|
||||
(setq code (append
|
||||
(list (srecode-compile-inserter "BLANK"
|
||||
"\r"
|
||||
STATE
|
||||
:secondname nil
|
||||
:where 'begin))
|
||||
code
|
||||
(list (srecode-compile-inserter "BLANK"
|
||||
"\r"
|
||||
STATE
|
||||
:secondname nil
|
||||
:where 'end))
|
||||
)))
|
||||
(setq args (cdr args)))
|
||||
(srecode-template (semantic-tag-name tag)
|
||||
:context context
|
||||
:args (nreverse addargs)
|
||||
:dictionary sdicts
|
||||
:binding binding
|
||||
:code code)
|
||||
))
|
||||
|
||||
(defun srecode-compile-do-hard-newline-p (comp)
|
||||
"Examine COMP to decide if the upcoming newline should be hard.
|
||||
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))))
|
||||
|
||||
(defun srecode-compile-split-code (tag str STATE
|
||||
&optional end-name)
|
||||
"Split the code for TAG into something templatable.
|
||||
STR is the string of code from TAG to split.
|
||||
STATE is the current compile state.
|
||||
ESCAPE_START and ESCAPE_END are regexps that indicate the beginning
|
||||
escape character, and end escape character pattern for expandable
|
||||
macro names.
|
||||
Optional argument END-NAME specifies the name of a token upon which
|
||||
parsing should stop.
|
||||
If END-NAME is specified, and the input string"
|
||||
(let* ((what str)
|
||||
(end-token nil)
|
||||
(comp nil)
|
||||
(regex (concat "\n\\|" (regexp-quote (oref STATE escape_start))))
|
||||
(regexend (regexp-quote (oref STATE escape_end)))
|
||||
)
|
||||
(while (and what (not end-token))
|
||||
(cond
|
||||
((string-match regex what)
|
||||
(let* ((prefix (substring what 0 (match-beginning 0)))
|
||||
(match (substring what
|
||||
(match-beginning 0)
|
||||
(match-end 0)))
|
||||
(namestart (match-end 0))
|
||||
(junk (string-match regexend what namestart))
|
||||
end tail name)
|
||||
;; Add string to compiled output
|
||||
(when (> (length prefix) 0)
|
||||
(setq comp (cons prefix comp)))
|
||||
(if (string= match "\n")
|
||||
;; Do newline thingy.
|
||||
(let ((new-inserter
|
||||
(srecode-compile-inserter
|
||||
"INDENT"
|
||||
"\n"
|
||||
STATE
|
||||
:secondname nil
|
||||
;; This newline is "hard" meaning ALWAYS do it
|
||||
;; if the previous entry is also a newline.
|
||||
;; Without it, user entered blank lines will be
|
||||
;; ignored.
|
||||
:hard (srecode-compile-do-hard-newline-p comp)
|
||||
)))
|
||||
;; Trim WHAT back.
|
||||
(setq what (substring what namestart))
|
||||
(when (> (length what) 0)
|
||||
;; make the new inserter, but only if we aren't last.
|
||||
(setq comp (cons new-inserter comp))
|
||||
))
|
||||
;; Regular inserter thingy.
|
||||
(setq end (if junk
|
||||
(match-beginning 0)
|
||||
(error "Could not find end escape for %s"
|
||||
(semantic-tag-name tag)))
|
||||
tail (match-end 0))
|
||||
(cond ((not end)
|
||||
(error "No matching escape end for %s"
|
||||
(semantic-tag-name tag)))
|
||||
((<= end namestart)
|
||||
(error "Stray end escape for %s"
|
||||
(semantic-tag-name tag)))
|
||||
)
|
||||
;; Add string to compiled output
|
||||
(setq name (substring what namestart end)
|
||||
key nil)
|
||||
;; Trim WHAT back.
|
||||
(setq what (substring what tail))
|
||||
;; Get the inserter
|
||||
(let ((new-inserter
|
||||
(srecode-compile-parse-inserter name STATE))
|
||||
)
|
||||
;; If this is an end inserter, then assign into
|
||||
;; the end-token.
|
||||
(if (srecode-match-end new-inserter end-name)
|
||||
(setq end-token new-inserter))
|
||||
;; Add the inserter to our compilation stream.
|
||||
(setq comp (cons new-inserter comp))
|
||||
;; Allow the inserter an opportunity to modify
|
||||
;; the input stream.
|
||||
(setq what (srecode-parse-input new-inserter tag what
|
||||
STATE))
|
||||
)
|
||||
)))
|
||||
(t
|
||||
(if end-name
|
||||
(error "Unmatched section end %s" end-name))
|
||||
(setq comp (cons what comp)
|
||||
what nil))))
|
||||
(cons what (nreverse comp))))
|
||||
|
||||
(defun srecode-compile-parse-inserter (txt STATE)
|
||||
"Parse the inserter TXT with the current STATE.
|
||||
Return an inserter object."
|
||||
(let ((key (aref txt 0))
|
||||
)
|
||||
(if (and (or (< key ?A) (> key ?Z))
|
||||
(or (< key ?a) (> key ?z)) )
|
||||
(setq name (substring txt 1))
|
||||
(setq name txt
|
||||
key nil))
|
||||
(let* ((junk (string-match ":" name))
|
||||
(namepart (if junk
|
||||
(substring name 0 (match-beginning 0))
|
||||
name))
|
||||
(secondname (if junk
|
||||
(substring name (match-end 0))
|
||||
nil))
|
||||
(new-inserter (srecode-compile-inserter
|
||||
namepart key STATE
|
||||
:secondname secondname
|
||||
)))
|
||||
;; Return the new inserter
|
||||
new-inserter)))
|
||||
|
||||
(defun srecode-compile-inserter (name key STATE &rest props)
|
||||
"Create an srecode inserter object for some macro NAME.
|
||||
KEY indicates a single character key representing a type
|
||||
of inserter to create.
|
||||
STATE is the current compile state.
|
||||
PROPS are additional properties that might need to be passed
|
||||
to the inserter constructor."
|
||||
;;(message "Compile: %s %S" name props)
|
||||
(if (not key)
|
||||
(apply 'srecode-template-inserter-variable name props)
|
||||
(let ((classes (class-children srecode-template-inserter))
|
||||
(new nil))
|
||||
;; Loop over the various subclasses and
|
||||
;; create the correct inserter.
|
||||
(while (and (not new) classes)
|
||||
(setq classes (append classes (class-children (car classes))))
|
||||
;; Do we have a match?
|
||||
(when (and (not (class-abstract-p (car classes)))
|
||||
(equal (oref (car classes) key) key))
|
||||
;; Create the new class, and apply state.
|
||||
(setq new (apply (car classes) name props))
|
||||
(srecode-inserter-apply-state new STATE)
|
||||
)
|
||||
(setq classes (cdr classes)))
|
||||
(if (not new) (error "SRECODE: Unknown macro code %S" key))
|
||||
new)))
|
||||
|
||||
(defun srecode-compile-template-table (templates mode priority application 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.
|
||||
A list of defined variables VARS provides a variable table."
|
||||
(let ((namehash (make-hash-table :test 'equal
|
||||
:size (length templates)))
|
||||
(contexthash (make-hash-table :test 'equal :size 10))
|
||||
(lp templates)
|
||||
)
|
||||
|
||||
(while lp
|
||||
|
||||
(let* ((objname (oref (car lp) :object-name))
|
||||
(context (oref (car lp) :context))
|
||||
(globalname (concat context ":" objname))
|
||||
)
|
||||
|
||||
;; Place this template object into the global name hash.
|
||||
(puthash globalname (car lp) namehash)
|
||||
|
||||
;; Place this template into the specific context name hash.
|
||||
(let ((hs (gethash context contexthash)))
|
||||
;; Make a new context if none was available.
|
||||
(when (not hs)
|
||||
(setq hs (make-hash-table :test 'equal :size 20))
|
||||
(puthash context hs contexthash))
|
||||
;; Put into that contenxt's hash.
|
||||
(puthash objname (car lp) hs)
|
||||
)
|
||||
|
||||
(setq lp (cdr lp))))
|
||||
|
||||
(let* ((table (srecode-mode-table-new mode (buffer-file-name)
|
||||
:templates (nreverse templates)
|
||||
:namehash namehash
|
||||
:contexthash contexthash
|
||||
:variables vars
|
||||
:major-mode mode
|
||||
:priority priority
|
||||
:application application))
|
||||
(tmpl (oref table templates)))
|
||||
;; Loop over all the templates, and xref.
|
||||
(while tmpl
|
||||
(oset (car tmpl) :table table)
|
||||
(setq tmpl (cdr tmpl))))
|
||||
))
|
||||
|
||||
|
||||
|
||||
;;; DEBUG
|
||||
;;
|
||||
;; Dump out information about the current srecoder compiled templates.
|
||||
;;
|
||||
|
||||
(defmethod srecode-dump ((tmp srecode-template))
|
||||
"Dump the contents of the SRecode template tmp."
|
||||
(princ "== Template \"")
|
||||
(princ (object-name-string tmp))
|
||||
(princ "\" in context ")
|
||||
(princ (oref tmp context))
|
||||
(princ "\n")
|
||||
(when (oref tmp args)
|
||||
(princ " Arguments: ")
|
||||
(prin1 (oref tmp args))
|
||||
(princ "\n"))
|
||||
(when (oref tmp dictionary)
|
||||
(princ " Section Dictionaries:\n")
|
||||
(srecode-dump (oref tmp dictionary) 4)
|
||||
;(princ "\n")
|
||||
)
|
||||
(when (and (slot-boundp tmp 'binding) (oref tmp binding))
|
||||
(princ " Binding: ")
|
||||
(prin1 (oref tmp binding))
|
||||
(princ "\n"))
|
||||
(princ " Compiled Codes:\n")
|
||||
(srecode-dump-code-list (oref tmp code) " ")
|
||||
(princ "\n\n")
|
||||
)
|
||||
|
||||
(defun srecode-dump-code-list (code indent)
|
||||
"Dump the CODE from a template code list to standard output.
|
||||
Argument INDENT specifies the indentation level for the list."
|
||||
(let ((i 1))
|
||||
(while code
|
||||
(princ indent)
|
||||
(prin1 i)
|
||||
(princ ") ")
|
||||
(cond ((stringp (car code))
|
||||
(prin1 (car code)))
|
||||
((srecode-template-inserter-child-p (car code))
|
||||
(srecode-dump (car code) indent))
|
||||
(t
|
||||
(princ "Unknown Code: ")
|
||||
(prin1 (car code))))
|
||||
(setq code (cdr code)
|
||||
i (1+ i))
|
||||
(when code
|
||||
(princ "\n"))))
|
||||
)
|
||||
|
||||
(defmethod srecode-dump ((ins srecode-template-inserter) indent)
|
||||
"Dump the state of the SRecode template inserter INS."
|
||||
(princ "INS: \"")
|
||||
(princ (object-name-string ins))
|
||||
(when (oref ins :secondname)
|
||||
(princ "\" : \"")
|
||||
(princ (oref ins :secondname)))
|
||||
(princ "\" type \"")
|
||||
(let* ((oc (symbol-name (object-class ins)))
|
||||
(junk (string-match "srecode-template-inserter-" oc))
|
||||
(on (if junk
|
||||
(substring oc (match-end 0))
|
||||
oc)))
|
||||
(princ on))
|
||||
(princ "\"")
|
||||
)
|
||||
|
||||
(provide 'srecode/compile)
|
||||
|
||||
;; Local variables:
|
||||
;; generated-autoload-file: "loaddefs.el"
|
||||
;; generated-autoload-feature: srecode/loaddefs
|
||||
;; generated-autoload-load-name: "srecode/compile"
|
||||
;; End:
|
||||
|
||||
;;; srecode/compile.el ends here
|
149
lisp/cedet/srecode/cpp.el
Normal file
149
lisp/cedet/srecode/cpp.el
Normal file
|
@ -0,0 +1,149 @@
|
|||
;;; srecode/cpp.el --- C++ specific handlers for Semantic Recoder
|
||||
|
||||
;; Copyright (C) 2007, 2009 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Eric M. Ludlam <eric@siege-engine.com>
|
||||
;; Jan Moringen <scymtym@users.sourceforge.net>
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; Supply some C++ specific dictionary fillers and helpers
|
||||
|
||||
;;; Code:
|
||||
|
||||
;;; :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.
|
||||
|
||||
(require 'srecode)
|
||||
(require 'srecode/dictionary)
|
||||
(require 'srecode/semantic)
|
||||
|
||||
;;;###autoload
|
||||
(defun srecode-semantic-handle-:cpp (dict)
|
||||
"Add macros into the dictionary DICT based on the current c++ file.
|
||||
Adds the following:
|
||||
FILENAME_SYMBOL - filename converted into a C compat symbol.
|
||||
HEADER - Shown section if in a header file."
|
||||
;; A symbol representing
|
||||
(let ((fsym (file-name-nondirectory (buffer-file-name)))
|
||||
(case-fold-search t))
|
||||
|
||||
;; Are we in a header file?
|
||||
(if (string-match "\\.\\(h\\|hh\\|hpp\\|h\\+\\+\\)$" fsym)
|
||||
(srecode-dictionary-show-section dict "HEADER")
|
||||
(srecode-dictionary-show-section dict "NOTHEADER"))
|
||||
|
||||
;; Strip out bad characters
|
||||
(while (string-match "\\.\\| " fsym)
|
||||
(setq fsym (replace-match "_" t t fsym)))
|
||||
(srecode-dictionary-set-value dict "FILENAME_SYMBOL" fsym)
|
||||
)
|
||||
)
|
||||
|
||||
(define-mode-local-override srecode-semantic-apply-tag-to-dict
|
||||
c++-mode (tag-wrapper dict)
|
||||
"Apply 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."
|
||||
|
||||
;; Use default implementation to fill in the basic properties.
|
||||
(srecode-semantic-apply-tag-to-dict-default tag-wrapper dict)
|
||||
|
||||
;; Pull out the tag for the individual pieces.
|
||||
(let* ((tag (oref tag-wrapper :prime))
|
||||
(class (semantic-tag-class tag)))
|
||||
|
||||
;; Add additional information based on the class of the tag.
|
||||
(cond
|
||||
;;
|
||||
;; INCLUDE
|
||||
;;
|
||||
((eq class 'include)
|
||||
;; For include tags, we have to discriminate between system-wide
|
||||
;; and local includes.
|
||||
(if (semantic-tag-include-system-p tag)
|
||||
(srecode-dictionary-show-section dict "SYSTEM")
|
||||
(srecode-dictionary-show-section dict "LOCAL")))
|
||||
|
||||
;;
|
||||
;; USING
|
||||
;;
|
||||
((eq class 'using)
|
||||
;; Insert the subject (a tag) of the include statement as VALUE
|
||||
;; entry into the dictionary.
|
||||
(let ((value-tag (semantic-tag-get-attribute tag :value))
|
||||
(value-dict (srecode-dictionary-add-section-dictionary
|
||||
dict "VALUE")))
|
||||
(srecode-semantic-apply-tag-to-dict
|
||||
(srecode-semantic-tag (semantic-tag-name value-tag)
|
||||
:prime value-tag)
|
||||
value-dict))
|
||||
;; Discriminate using statements referring to namespaces and
|
||||
;; types.
|
||||
(when (eq (semantic-tag-get-attribute tag :kind) 'namespace)
|
||||
(srecode-dictionary-show-section dict "NAMESPACE")))
|
||||
|
||||
;;
|
||||
;; FUNCTION
|
||||
;;
|
||||
((eq class 'function)
|
||||
;; @todo It would be nice to distinguish member functions from
|
||||
;; free functions and only apply the const and pure modifiers,
|
||||
;; when they make sense. My best bet would be
|
||||
;; (semantic-tag-function-parent tag), but it is not there, when
|
||||
;; the function is defined in the scope of a class.
|
||||
(let ((member 't)
|
||||
(modifiers (semantic-tag-modifiers tag)))
|
||||
|
||||
;; 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)))
|
||||
|
||||
;; When the function is a member function, it can have
|
||||
;; additional modifiers.
|
||||
(when member
|
||||
|
||||
;; For member functions, constness is called
|
||||
;; 'methodconst-flag'.
|
||||
(when (semantic-tag-get-attribute tag :methodconst-flag)
|
||||
(srecode-dictionary-show-section dict "CONST"))
|
||||
|
||||
;; 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"))
|
||||
)
|
||||
))
|
||||
))
|
||||
)
|
||||
|
||||
(provide 'srecode/cpp)
|
||||
|
||||
;; Local variables:
|
||||
;; generated-autoload-file: "loaddefs.el"
|
||||
;; generated-autoload-feature: srecode/loaddefs
|
||||
;; generated-autoload-load-name: "srecode/cpp"
|
||||
;; End:
|
||||
|
||||
;;; srecode/cpp.el ends here
|
247
lisp/cedet/srecode/ctxt.el
Normal file
247
lisp/cedet/srecode/ctxt.el
Normal file
|
@ -0,0 +1,247 @@
|
|||
;;; srecode/ctxt.el --- Derive a context from the source buffer.
|
||||
|
||||
;; Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Eric M. Ludlam <eric@siege-engine.com>
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; Manage context calculations for Semantic Recoder.
|
||||
;;
|
||||
;; SRecode templates are always bound to a context. By calculating
|
||||
;; the current context, we can narrow down the selection of possible
|
||||
;; templates to something reasonable.
|
||||
;;
|
||||
;; Alternately, code here will find a context for templates that
|
||||
;; require different pieces of code placed in multiple areas.
|
||||
|
||||
(require 'semantic)
|
||||
(require 'semantic/tag-ls)
|
||||
|
||||
(declare-function srecode-dictionary-show-section "srecode/dictionary")
|
||||
(declare-function srecode-dictionary-set-value "srecode/dictionary")
|
||||
|
||||
;;; Code:
|
||||
|
||||
(define-overload srecode-calculate-context ()
|
||||
"Calculate the context at the current point.
|
||||
The returned context is a list, with the top-most context first.
|
||||
Each returned context is a string that that would show up in a `context'
|
||||
statement in an `.srt' file.
|
||||
|
||||
Some useful context values used by the provided srecode templates are:
|
||||
\"file\" - Templates that for a file (such as an empty file.)
|
||||
\"empty\" - The file is empty
|
||||
\"declaration\" - Top-level declarations in a file.
|
||||
\"include\" - In or near include statements
|
||||
\"package\" - In or near provide statements
|
||||
\"function\" - In or near function statements
|
||||
\"NAME\" - Near functions within NAME namespace or class
|
||||
\"variable\" - In or near variable statements.
|
||||
\"type\" - In or near type declarations.
|
||||
\"comment\" - In a comment
|
||||
\"classdecl\" - Declarations within a class/struct/etc.
|
||||
\"variable\" - In or near class fields
|
||||
\"function\" - In or near methods/functions
|
||||
\"virtual\" - Nearby items are virtual
|
||||
\"pure\" - and those virtual items are pure virtual
|
||||
\"type\" - In or near type declarations.
|
||||
\"comment\" - In a comment in a block of code
|
||||
-- these items show up at the end of the context list. --
|
||||
\"public\", \"protected\", \"private\" -
|
||||
In or near a section of public/pritected/private entries.
|
||||
\"code\" - In a block of code.
|
||||
\"string\" - In a string in a block of code
|
||||
\"comment\" - In a comment in a block of code
|
||||
|
||||
... More later."
|
||||
)
|
||||
|
||||
(defun srecode-calculate-nearby-things ()
|
||||
;; NOTE: May need to add bounes to this FCN
|
||||
"Calculate the CONTEXT type items nearby the current point.
|
||||
Assume that what we want to insert next is based on what is just
|
||||
before point. If there is nothing, then assume it is whatever is
|
||||
after point."
|
||||
;; @todo - ADD BOUNDS TO THE PREV/NEXT TAG SEARCH
|
||||
;; thus classdecl "near" stuff cannot be
|
||||
;; outside the bounds of the type in question.
|
||||
(let ((near (semantic-find-tag-by-overlay-prev))
|
||||
(prot nil)
|
||||
(ans nil))
|
||||
(if (not near)
|
||||
(setq near (semantic-find-tag-by-overlay-next)))
|
||||
(when near
|
||||
;; Calculate the type of thing we are near.
|
||||
(if (not (semantic-tag-of-class-p near 'function))
|
||||
(setq ans (cons (symbol-name (semantic-tag-class near)) ans))
|
||||
;; if the symbol NEAR has a parent,
|
||||
(let ((p (semantic-tag-function-parent near)))
|
||||
(setq ans (cons (symbol-name (semantic-tag-class near)) ans))
|
||||
(cond ((semantic-tag-p p)
|
||||
(setq ans (cons (semantic-tag-name p) ans)))
|
||||
((stringp p)
|
||||
(setq ans (cons p ans)))
|
||||
(t nil)))
|
||||
;; Was it virtual?
|
||||
(when (semantic-tag-get-attribute near :virtual)
|
||||
(setq ans (cons "virtual" ans)))
|
||||
;; Was it pure?
|
||||
(when (semantic-tag-get-attribute near :pure-virtual-flag)
|
||||
(setq ans (cons "pure" ans)))
|
||||
)
|
||||
;; Calculate the protection
|
||||
(setq prot (semantic-tag-protection near))
|
||||
(when (and prot (not (eq prot 'unknown)))
|
||||
(setq ans (cons (symbol-name prot) ans)))
|
||||
)
|
||||
(nreverse ans)))
|
||||
|
||||
(defun srecode-calculate-context-font-lock ()
|
||||
"Calculate an srecode context by using font-lock."
|
||||
(let ((face (get-text-property (point) 'face))
|
||||
)
|
||||
(cond ((member face '(font-lock-string-face
|
||||
font-lock-doc-face))
|
||||
(list "string"))
|
||||
((member face '(font-lock-comment-face
|
||||
font-lock-comment-delimiter-face))
|
||||
(list "comment"))
|
||||
)
|
||||
))
|
||||
|
||||
(defun srecode-calculate-context-default ()
|
||||
"Generic method for calculating a context for srecode."
|
||||
(if (= (point-min) (point-max))
|
||||
(list "file" "empty")
|
||||
|
||||
(semantic-fetch-tags)
|
||||
(let ((ct (semantic-find-tag-by-overlay))
|
||||
)
|
||||
(cond ((or (not ct)
|
||||
;; Ok, below is a bit C specific.
|
||||
(and (eq (semantic-tag-class (car ct)) 'type)
|
||||
(string= (semantic-tag-type (car ct)) "namespace")))
|
||||
(cons "declaration"
|
||||
(or (srecode-calculate-context-font-lock)
|
||||
(srecode-calculate-nearby-things)
|
||||
))
|
||||
)
|
||||
((eq (semantic-tag-class (car ct)) 'function)
|
||||
(cons "code" (srecode-calculate-context-font-lock))
|
||||
)
|
||||
((eq (semantic-tag-class (car ct)) 'type) ; We know not namespace
|
||||
(cons "classdecl"
|
||||
(or (srecode-calculate-context-font-lock)
|
||||
(srecode-calculate-nearby-things)))
|
||||
)
|
||||
((and (car (cdr ct))
|
||||
(eq (semantic-tag-class (car (cdr ct))) 'type))
|
||||
(list "classdecl"
|
||||
(symbol-name (semantic-tag-class (car ct))))
|
||||
)
|
||||
)
|
||||
)))
|
||||
|
||||
|
||||
;;; HANDLERS
|
||||
;;
|
||||
;; The calculated context is one thing, but more info is often available.
|
||||
;; The context handlers can add info into the active dictionary that is
|
||||
;; based on the context, such as a method parent name, protection scheme,
|
||||
;; or other feature.
|
||||
|
||||
(defun srecode-semantic-handle-:ctxt (dict &optional template)
|
||||
"Add macros into the dictionary DICT based on the current Emacs Lisp file.
|
||||
Argument TEMPLATE is the template object adding context dictionary
|
||||
entries.
|
||||
This might add the following:
|
||||
VIRTUAL - show a section if a function is virtual
|
||||
PURE - show a section if a function is pure virtual.
|
||||
PARENT - The name of a parent type for functions.
|
||||
PROTECTION - Show a protection section, and what the protection is."
|
||||
(require 'srecode/dictionary)
|
||||
(when template
|
||||
|
||||
(let ((name (oref template object-name))
|
||||
(cc (if (boundp 'srecode-insertion-start-context)
|
||||
srecode-insertion-start-context))
|
||||
;(context (oref template context))
|
||||
)
|
||||
|
||||
; (when (and cc
|
||||
; (null (string= (car cc) context))
|
||||
; )
|
||||
; ;; No current context, or the base is different, then
|
||||
; ;; this is the section where we need to recalculate
|
||||
; ;; the context based on user choice, if possible.
|
||||
; ;;
|
||||
; ;; The recalculation is complex, as there are many possibilities
|
||||
; ;; that need to be divined. Set "cc" to the new context
|
||||
; ;; at the end.
|
||||
; ;;
|
||||
; ;; @todo -
|
||||
;
|
||||
; )
|
||||
|
||||
;; The various context all have different features.
|
||||
(let ((ct (nth 0 cc))
|
||||
(it (nth 1 cc))
|
||||
(last (last cc))
|
||||
(parent nil)
|
||||
)
|
||||
(cond ((string= it "function")
|
||||
(setq parent (nth 2 cc))
|
||||
(when parent
|
||||
(cond ((string= parent "virtual")
|
||||
(srecode-dictionary-show-section dict "VIRTUAL")
|
||||
(when (nth 3 cc)
|
||||
(srecode-dictionary-show-section dict "PURE"))
|
||||
)
|
||||
(t
|
||||
(srecode-dictionary-set-value dict "PARENT" parent))))
|
||||
)
|
||||
((and (string= it "type")
|
||||
(or (string= name "function") (string= name "method")))
|
||||
;; If we have a type, but we insert a fcn, then use that type
|
||||
;; as the function parent.
|
||||
(let ((near (semantic-find-tag-by-overlay-prev)))
|
||||
(when (and near (semantic-tag-of-class-p near 'type))
|
||||
(srecode-dictionary-set-value
|
||||
dict "PARENT" (semantic-tag-name near))))
|
||||
)
|
||||
((string= ct "code")
|
||||
;;(let ((analyzer (semantic-analyze-current-context)))
|
||||
;; @todo - Use the analyze to setup things like local
|
||||
;; variables we might use or something.
|
||||
nil
|
||||
;;)
|
||||
)
|
||||
(t
|
||||
nil))
|
||||
(when (member last '("public" "private" "protected"))
|
||||
;; Hey, fancy that, we can do both.
|
||||
(srecode-dictionary-set-value dict "PROTECTION" parent)
|
||||
(srecode-dictionary-show-section dict "PROTECTION"))
|
||||
))
|
||||
))
|
||||
|
||||
|
||||
(provide 'srecode/ctxt)
|
||||
|
||||
;;; srecode/ctxt.el ends here
|
565
lisp/cedet/srecode/dictionary.el
Normal file
565
lisp/cedet/srecode/dictionary.el
Normal file
|
@ -0,0 +1,565 @@
|
|||
;;; srecode-dictionary.el --- Dictionary code for the semantic recoder.
|
||||
|
||||
;; Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Eric M. Ludlam <eric@siege-engine.com>
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; Dictionaries contain lists of names and their assocaited values.
|
||||
;; These dictionaries are used to fill in macros from recoder templates.
|
||||
|
||||
;;; Code:
|
||||
|
||||
;;; CLASSES
|
||||
|
||||
(require 'eieio)
|
||||
(require 'srecode)
|
||||
(require 'srecode/table)
|
||||
(eval-when-compile (require 'semantic))
|
||||
|
||||
(declare-function srecode-compile-parse-inserter "srecode/compile")
|
||||
(declare-function srecode-dump-code-list "srecode/compile")
|
||||
(declare-function srecode-load-tables-for-mode "srecode/find")
|
||||
(declare-function srecode-insert-code-stream "srecode/insert")
|
||||
(declare-function data-debug-new-buffer "data-debug")
|
||||
(declare-function data-debug-insert-object-slots "eieio-datadebug")
|
||||
(declare-function srecode-field "srecode/fields")
|
||||
|
||||
(defclass srecode-dictionary ()
|
||||
((namehash :initarg :namehash
|
||||
:documentation
|
||||
"Hash table containing the names of all the templates.")
|
||||
(buffer :initarg :buffer
|
||||
:documentation
|
||||
"The buffer this dictionary was initialized with.")
|
||||
(parent :initarg :parent
|
||||
:type (or null srecode-dictionary)
|
||||
:documentation
|
||||
"The parent dictionary.
|
||||
Symbols not appearing in this dictionary will be checked against the
|
||||
parent dictionary.")
|
||||
(origin :initarg :origin
|
||||
:type string
|
||||
:documentation
|
||||
"A string representing the origin of this dictionary.
|
||||
Useful only while debugging.")
|
||||
)
|
||||
"Dictionary of symbols and what they mean.
|
||||
Dictionaries are used to look up named symbols from
|
||||
templates to decide what to do with those symbols.")
|
||||
|
||||
(defclass srecode-dictionary-compound-value ()
|
||||
()
|
||||
"A compound dictionary value.
|
||||
Values stored in a dictionary must be a STRING,
|
||||
a dictionary for showing sections, or an instance of a subclass
|
||||
of this class.
|
||||
|
||||
Compound dictionary values derive from this class, and must
|
||||
provide a sequence of method implementations to convert into
|
||||
a string."
|
||||
:abstract t)
|
||||
|
||||
(defclass srecode-dictionary-compound-variable
|
||||
(srecode-dictionary-compound-value)
|
||||
((value :initarg :value
|
||||
:documentation
|
||||
"The value of this template variable.
|
||||
Variables in template files are usually a single string
|
||||
which can be inserted into a dictionary directly.
|
||||
|
||||
Some variables may be more complex and involve dictionary
|
||||
lookups, strings, concatenation, or the like.
|
||||
|
||||
The format of VALUE is determined by current template
|
||||
formatting rules.")
|
||||
(compiled :initarg :compiled
|
||||
:type list
|
||||
:documentation
|
||||
"The compiled version of VALUE.")
|
||||
)
|
||||
"A compound dictionary value for template file variables.
|
||||
You can declare a variable in a template like this:
|
||||
|
||||
set NAME \"str\" macro \"OTHERNAME\"
|
||||
|
||||
with appending various parts together in a list.")
|
||||
|
||||
(defmethod initialize-instance ((this srecode-dictionary-compound-variable)
|
||||
&optional fields)
|
||||
"Initialize the compound variable THIS.
|
||||
Makes sure that :value is compiled."
|
||||
(let ((newfields nil)
|
||||
(state nil))
|
||||
(while fields
|
||||
;; Strip out :state
|
||||
(if (eq (car fields) :state)
|
||||
(setq state (car (cdr fields)))
|
||||
(setq newfields (cons (car (cdr fields))
|
||||
(cons (car fields) newfields))))
|
||||
(setq fields (cdr (cdr fields))))
|
||||
|
||||
(when (not state)
|
||||
(error "Cannot create compound variable without :state"))
|
||||
|
||||
(call-next-method this (nreverse newfields))
|
||||
(when (not (slot-boundp this 'compiled))
|
||||
(let ((val (oref this :value))
|
||||
(comp nil))
|
||||
(while val
|
||||
(let ((nval (car val))
|
||||
)
|
||||
(cond ((stringp nval)
|
||||
(setq comp (cons nval comp)))
|
||||
((and (listp nval)
|
||||
(equal (car nval) 'macro))
|
||||
(require 'srecode/compile)
|
||||
(setq comp (cons
|
||||
(srecode-compile-parse-inserter
|
||||
(cdr nval)
|
||||
state)
|
||||
comp)))
|
||||
(t
|
||||
(error "Don't know how to handle variable value %S" nval)))
|
||||
)
|
||||
(setq val (cdr val)))
|
||||
(oset this :compiled (nreverse comp))))))
|
||||
|
||||
;;; DICTIONARY METHODS
|
||||
;;
|
||||
|
||||
(defun srecode-create-dictionary (&optional buffer-or-parent)
|
||||
"Create a dictionary for BUFFER.
|
||||
If BUFFER-OR-PARENT is not specified, assume a buffer, and
|
||||
use the current buffer.
|
||||
If BUFFER-OR-PARENT is another dictionary, then remember the
|
||||
parent within the new dictionary, and assume that BUFFER
|
||||
is the same as belongs to the parent dictionary.
|
||||
The dictionary is initialized with variables setup for that
|
||||
buffer's table.
|
||||
If BUFFER-OR-PARENT is t, then this dictionary should not be
|
||||
assocated with a buffer or parent."
|
||||
(save-excursion
|
||||
(let ((parent nil)
|
||||
(buffer nil)
|
||||
(origin nil)
|
||||
(initfrombuff nil))
|
||||
(cond ((bufferp buffer-or-parent)
|
||||
(set-buffer buffer-or-parent)
|
||||
(setq buffer buffer-or-parent
|
||||
origin (buffer-name buffer-or-parent)
|
||||
initfrombuff t))
|
||||
((srecode-dictionary-child-p buffer-or-parent)
|
||||
(setq parent buffer-or-parent
|
||||
buffer (oref buffer-or-parent buffer)
|
||||
origin (concat (object-name buffer-or-parent) " in "
|
||||
(if buffer (buffer-name buffer)
|
||||
"no buffer")))
|
||||
(when buffer
|
||||
(set-buffer buffer)))
|
||||
((eq buffer-or-parent t)
|
||||
(setq buffer nil
|
||||
origin "Unspecified Origin"))
|
||||
(t
|
||||
(setq buffer (current-buffer)
|
||||
origin (concat "Unspecified. Assume "
|
||||
(buffer-name buffer))
|
||||
initfrombuff t)
|
||||
)
|
||||
)
|
||||
(let ((dict (srecode-dictionary
|
||||
major-mode
|
||||
:buffer buffer
|
||||
:parent parent
|
||||
:namehash (make-hash-table :test 'equal
|
||||
:size 20)
|
||||
:origin origin)))
|
||||
;; Only set up the default variables if we are being built
|
||||
;; directroy for a particular buffer.
|
||||
(when initfrombuff
|
||||
;; Variables from the table we are inserting from.
|
||||
;; @todo - get a better tree of tables.
|
||||
(let ((mt (srecode-get-mode-table major-mode))
|
||||
(def (srecode-get-mode-table 'default)))
|
||||
;; Each table has multiple template tables.
|
||||
;; Do DEF first so that MT can override any values.
|
||||
(srecode-dictionary-add-template-table dict def)
|
||||
(srecode-dictionary-add-template-table dict mt)
|
||||
))
|
||||
dict))))
|
||||
|
||||
(defmethod srecode-dictionary-add-template-table ((dict srecode-dictionary)
|
||||
tpl)
|
||||
"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)))
|
||||
(while tabs
|
||||
(let ((vars (oref (car tabs) variables)))
|
||||
(while vars
|
||||
(srecode-dictionary-set-value
|
||||
dict (car (car vars)) (cdr (car vars)))
|
||||
(setq vars (cdr vars))))
|
||||
(setq tabs (cdr tabs))))))
|
||||
|
||||
|
||||
(defmethod srecode-dictionary-set-value ((dict srecode-dictionary)
|
||||
name value)
|
||||
"In dictionary DICT, set NAME to have VALUE."
|
||||
;; Validate inputs
|
||||
(if (not (stringp name))
|
||||
(signal 'wrong-type-argument (list name 'stringp)))
|
||||
;; Add the value.
|
||||
(with-slots (namehash) dict
|
||||
(puthash name value namehash))
|
||||
)
|
||||
|
||||
(defmethod srecode-dictionary-add-section-dictionary ((dict srecode-dictionary)
|
||||
name &optional show-only)
|
||||
"In dictionary DICT, add a section dictionary for section macro NAME.
|
||||
Return the new dictionary.
|
||||
|
||||
You can add several dictionaries to the same section macro.
|
||||
For each dictionary added to a macro, the block of codes in the
|
||||
template will be repeated.
|
||||
|
||||
If optional argument SHOW-ONLY is non-nil, then don't add a new dictionarly
|
||||
if there is already one in place. Also, don't add FIRST/LAST entries.
|
||||
These entries are not needed when we are just showing a section.
|
||||
|
||||
Each dictionary added will automatically get values for positional macros
|
||||
which will enable SECTIONS to be enabled.
|
||||
|
||||
* FIRST - The first entry in the table.
|
||||
* NOTFIRST - Not the first entry in the table.
|
||||
* LAST - The last entry in the table
|
||||
* NOTLAST - Not the last entry in the table.
|
||||
|
||||
Adding a new dictionary will alter these values in previously
|
||||
inserted dictionaries."
|
||||
;; Validate inputs
|
||||
(if (not (stringp name))
|
||||
(signal 'wrong-type-argument (list name 'stringp)))
|
||||
(let ((new (srecode-create-dictionary dict))
|
||||
(ov (srecode-dictionary-lookup-name dict name)))
|
||||
|
||||
(when (not show-only)
|
||||
;; Setup the FIRST/NOTFIRST and LAST/NOTLAST entries.
|
||||
(if (null ov)
|
||||
(progn
|
||||
(srecode-dictionary-show-section new "FIRST")
|
||||
(srecode-dictionary-show-section new "LAST"))
|
||||
;; Not the very first one. Lets clean up CAR.
|
||||
(let ((tail (car (last ov))))
|
||||
(srecode-dictionary-hide-section tail "LAST")
|
||||
(srecode-dictionary-show-section tail "NOTLAST")
|
||||
)
|
||||
(srecode-dictionary-show-section new "NOTFIRST")
|
||||
(srecode-dictionary-show-section new "LAST"))
|
||||
)
|
||||
|
||||
(when (or (not show-only) (null ov))
|
||||
(srecode-dictionary-set-value dict name (append ov (list new))))
|
||||
;; Return the new sub-dictionary.
|
||||
new))
|
||||
|
||||
(defmethod srecode-dictionary-show-section ((dict srecode-dictionary) name)
|
||||
"In dictionary DICT, indicate that the section NAME should be exposed."
|
||||
;; Validate inputs
|
||||
(if (not (stringp name))
|
||||
(signal 'wrong-type-argument (list name 'stringp)))
|
||||
;; Showing a section is just like making a section dictionary, but
|
||||
;; with no dictionary values to add.
|
||||
(srecode-dictionary-add-section-dictionary dict name t)
|
||||
nil)
|
||||
|
||||
(defmethod srecode-dictionary-hide-section ((dict srecode-dictionary) name)
|
||||
"In dictionary DICT, indicate that the section NAME should be hidden."
|
||||
;; We need to find the has value, and then delete it.
|
||||
;; Validate inputs
|
||||
(if (not (stringp name))
|
||||
(signal 'wrong-type-argument (list name 'stringp)))
|
||||
;; Add the value.
|
||||
(with-slots (namehash) dict
|
||||
(remhash name namehash))
|
||||
nil)
|
||||
|
||||
(defmethod srecode-dictionary-merge ((dict srecode-dictionary) otherdict)
|
||||
"Merge into DICT the dictionary entries from OTHERDICT."
|
||||
(when otherdict
|
||||
(maphash
|
||||
(lambda (key entry)
|
||||
;; Only merge in the new values if there was no old value.
|
||||
;; This protects applications from being whacked, and basically
|
||||
;; makes these new section dictionary entries act like
|
||||
;; "defaults" instead of overrides.
|
||||
(when (not (srecode-dictionary-lookup-name dict key))
|
||||
(cond ((and (listp entry) (srecode-dictionary-p (car entry)))
|
||||
;; A list of section dictionaries.
|
||||
;; We need to merge them in.
|
||||
(while entry
|
||||
(let ((new-sub-dict
|
||||
(srecode-dictionary-add-section-dictionary
|
||||
dict key)))
|
||||
(srecode-dictionary-merge new-sub-dict (car entry)))
|
||||
(setq entry (cdr entry)))
|
||||
)
|
||||
|
||||
(t
|
||||
(srecode-dictionary-set-value dict key entry)))
|
||||
))
|
||||
(oref otherdict namehash))))
|
||||
|
||||
(defmethod srecode-dictionary-lookup-name ((dict srecode-dictionary)
|
||||
name)
|
||||
"Return information about the current DICT's value for NAME."
|
||||
(if (not (slot-boundp dict 'namehash))
|
||||
nil
|
||||
;; Get the value of this name from the dictionary
|
||||
(or (with-slots (namehash) dict
|
||||
(gethash name namehash))
|
||||
(and (not (member name '("FIRST" "LAST" "NOTFIRST" "NOTLAST")))
|
||||
(oref dict parent)
|
||||
(srecode-dictionary-lookup-name (oref dict parent) name))
|
||||
)))
|
||||
|
||||
(defmethod srecode-root-dictionary ((dict srecode-dictionary))
|
||||
"For dictionary DICT, return the root dictionary.
|
||||
The root dictionary is usually for a current or active insertion."
|
||||
(let ((ans dict))
|
||||
(while (oref ans parent)
|
||||
(setq ans (oref ans parent)))
|
||||
ans))
|
||||
|
||||
;;; COMPOUND VALUE METHODS
|
||||
;;
|
||||
;; Compound values must provide at least the toStriong method
|
||||
;; for use in converting the compound value into sometehing insertable.
|
||||
|
||||
(defmethod srecode-compound-toString ((cp srecode-dictionary-compound-value)
|
||||
function
|
||||
dictionary)
|
||||
"Convert the compound dictionary value CP to a string.
|
||||
If FUNCTION is non-nil, then FUNCTION is somehow applied to an aspect
|
||||
of the compound value. The FUNCTION could be a fraction
|
||||
of some function symbol with a logical prefix excluded.
|
||||
|
||||
If you subclass `srecode-dictionary-compound-value' then this
|
||||
method could return nil, but if it does that, it must insert
|
||||
the value itself using `princ', or by detecting if the current
|
||||
standard out is a buffer, and using `insert'."
|
||||
(object-name cp))
|
||||
|
||||
(defmethod srecode-dump ((cp srecode-dictionary-compound-value)
|
||||
&optional indent)
|
||||
"Display information about this compound value."
|
||||
(princ (object-name cp))
|
||||
)
|
||||
|
||||
(defmethod srecode-compound-toString ((cp srecode-dictionary-compound-variable)
|
||||
function
|
||||
dictionary)
|
||||
"Convert the compound dictionary variable value CP into a string.
|
||||
FUNCTION and DICTIONARY are as for the baseclass."
|
||||
(require 'srecode/insert)
|
||||
(srecode-insert-code-stream (oref cp compiled) dictionary))
|
||||
|
||||
|
||||
(defmethod srecode-dump ((cp srecode-dictionary-compound-variable)
|
||||
&optional indent)
|
||||
"Display information about this compound value."
|
||||
(require 'srecode/compile)
|
||||
(princ "# Compound Variable #\n")
|
||||
(let ((indent (+ 4 (or indent 0)))
|
||||
(cmp (oref cp compiled))
|
||||
)
|
||||
(srecode-dump-code-list cmp (make-string indent ? ))
|
||||
))
|
||||
|
||||
;;; FIELD EDITING COMPOUND VALUE
|
||||
;;
|
||||
;; This is an interface to using field-editing objects
|
||||
;; instead of asking questions. This provides the basics
|
||||
;; behind this compound value.
|
||||
|
||||
(defclass srecode-field-value (srecode-dictionary-compound-value)
|
||||
((firstinserter :initarg :firstinserter
|
||||
:documentation
|
||||
"The inserter object for the first occurance of this field.")
|
||||
(defaultvalue :initarg :defaultvalue
|
||||
:documentation
|
||||
"The default value for this inserter.")
|
||||
)
|
||||
"When inserting values with editable field mode, a dictionary value.
|
||||
Compound values allow a field to be stored in the dictionary for when
|
||||
it is referenced a second time. This compound value can then be
|
||||
inserted with a new editable field.")
|
||||
|
||||
(defmethod srecode-compound-toString((cp srecode-field-value)
|
||||
function
|
||||
dictionary)
|
||||
"Convert this field into an insertable string."
|
||||
(require 'srecode/fields)
|
||||
;; If we are not in a buffer, then this is not supported.
|
||||
(when (not (bufferp standard-output))
|
||||
(error "FIELDS invoked while inserting template to non-buffer."))
|
||||
|
||||
(if function
|
||||
(error "@todo: Cannot mix field insertion with functions.")
|
||||
|
||||
;; No function. Perform a plain field insertion.
|
||||
;; We know we are in a buffer, so we can perform the insertion.
|
||||
(let* ((dv (oref cp defaultvalue))
|
||||
(sti (oref cp firstinserter))
|
||||
(start (point))
|
||||
(name (oref sti :object-name)))
|
||||
|
||||
(if (or (not dv) (string= dv ""))
|
||||
(insert name)
|
||||
(insert dv))
|
||||
|
||||
(srecode-field name :name name
|
||||
:start start
|
||||
:end (point)
|
||||
:prompt (oref sti prompt)
|
||||
:read-fcn (oref sti read-fcn)
|
||||
)
|
||||
))
|
||||
;; Returning nil is a signal that we have done the insertion ourselves.
|
||||
nil)
|
||||
|
||||
|
||||
;;; 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)))
|
||||
|
||||
;;; DUMP DICTIONARY
|
||||
;;
|
||||
;; Make a dictionary, and dump it's contents.
|
||||
|
||||
(defun srecode-adebug-dictionary ()
|
||||
"Run data-debug on this mode's dictionary."
|
||||
(interactive)
|
||||
(require 'eieio-datadebug)
|
||||
(require 'semantic)
|
||||
(require 'srecode/find)
|
||||
(let* ((modesym major-mode)
|
||||
(start (current-time))
|
||||
(junk (or (progn (srecode-load-tables-for-mode modesym)
|
||||
(srecode-get-mode-table modesym))
|
||||
(error "No table found for mode %S" modesym)))
|
||||
(dict (srecode-create-dictionary (current-buffer)))
|
||||
(end (current-time))
|
||||
)
|
||||
(message "Creating a dictionary took %.2f seconds."
|
||||
(semantic-elapsed-time start end))
|
||||
(data-debug-new-buffer "*SRECODE ADEBUG*")
|
||||
(data-debug-insert-object-slots dict "*")))
|
||||
|
||||
(defun srecode-dictionary-dump ()
|
||||
"Dump a typical fabricated dictionary."
|
||||
(interactive)
|
||||
(require 'srecode/find)
|
||||
(let ((modesym major-mode))
|
||||
;; This load allows the dictionary access to inherited
|
||||
;; and stacked dictionary entries.
|
||||
(srecode-load-tables-for-mode modesym)
|
||||
(let ((tmp (srecode-get-mode-table modesym))
|
||||
)
|
||||
(if (not tmp)
|
||||
(error "No table found for mode %S" modesym))
|
||||
;; Now make the dictionary.
|
||||
(let ((dict (srecode-create-dictionary (current-buffer))))
|
||||
(with-output-to-temp-buffer "*SRECODE DUMP*"
|
||||
(princ "DICTIONARY FOR ")
|
||||
(princ major-mode)
|
||||
(princ "\n--------------------------------------------\n")
|
||||
(srecode-dump dict))
|
||||
))))
|
||||
|
||||
(defmethod srecode-dump ((dict srecode-dictionary) &optional indent)
|
||||
"Dump a dictionary."
|
||||
(if (not indent) (setq indent 0))
|
||||
(maphash (lambda (key entry)
|
||||
(princ (make-string indent ? ))
|
||||
(princ " ")
|
||||
(princ key)
|
||||
(princ " ")
|
||||
(cond ((and (listp entry)
|
||||
(srecode-dictionary-p (car entry)))
|
||||
(let ((newindent (if indent
|
||||
(+ indent 4)
|
||||
4)))
|
||||
(while entry
|
||||
(princ " --> SUBDICTIONARY ")
|
||||
(princ (object-name dict))
|
||||
(princ "\n")
|
||||
(srecode-dump (car entry) newindent)
|
||||
(setq entry (cdr entry))
|
||||
))
|
||||
(princ "\n")
|
||||
)
|
||||
((srecode-dictionary-compound-value-child-p entry)
|
||||
(srecode-dump entry indent)
|
||||
(princ "\n")
|
||||
)
|
||||
(t
|
||||
(prin1 entry)
|
||||
;(princ "\n")
|
||||
))
|
||||
(terpri)
|
||||
)
|
||||
(oref dict namehash))
|
||||
)
|
||||
|
||||
(provide 'srecode/dictionary)
|
||||
|
||||
;;; srecode/dictionary.el ends here
|
841
lisp/cedet/srecode/document.el
Normal file
841
lisp/cedet/srecode/document.el
Normal file
|
@ -0,0 +1,841 @@
|
|||
;;; srecode/document.el --- Documentation (comment) generation
|
||||
|
||||
;; Copyright (C) 2008, 2009 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Eric M. Ludlam <eric@siege-engine.com>
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; Routines for fabricating human readable text from function and
|
||||
;; variable names as base-text for function comments. Document is not
|
||||
;; meant to generate end-text for any function. It is merely meant to
|
||||
;; provide some useful base words and text, and as a framework for
|
||||
;; managing comments.
|
||||
;;
|
||||
;;; Origins:
|
||||
;;
|
||||
;; Document was first written w/ cparse, a custom regexp based c parser.
|
||||
;;
|
||||
;; Document was then ported to cedet/semantic using sformat (super
|
||||
;; format) as the templating engine.
|
||||
;;
|
||||
;; Document has now been ported to srecode, using the semantic recoder
|
||||
;; as the templating engine.
|
||||
|
||||
;; This file combines srecode-document.el and srecode-document-vars.el
|
||||
;; from the CEDET repository.
|
||||
|
||||
(require 'srecode/args)
|
||||
(require 'srecode/dictionary)
|
||||
(require 'srecode/extract)
|
||||
(require 'srecode/insert)
|
||||
(require 'srecode/semantic)
|
||||
|
||||
(require 'semantic)
|
||||
(require 'semantic/tag)
|
||||
(require 'semantic/doc)
|
||||
(require 'pulse)
|
||||
|
||||
;;; Code:
|
||||
|
||||
(defgroup document nil
|
||||
"File and tag browser frame."
|
||||
:group 'texinfo
|
||||
:group 'srecode)
|
||||
|
||||
(defcustom srecode-document-autocomment-common-nouns-abbrevs
|
||||
'(
|
||||
("sock\\(et\\)?" . "socket")
|
||||
("addr\\(ess\\)?" . "address")
|
||||
("buf\\(f\\(er\\)?\\)?" . "buffer")
|
||||
("cur\\(r\\(ent\\)?\\)?" . "current")
|
||||
("dev\\(ice\\)?" . "device")
|
||||
("doc" . "document")
|
||||
("i18n" . "internationalization")
|
||||
("file" . "file")
|
||||
("line" . "line")
|
||||
("l10n" . "localization")
|
||||
("msg\\|message" . "message")
|
||||
("name" . "name")
|
||||
("next\\|nxt" . "next")
|
||||
("num\\(ber\\)?" . "number")
|
||||
("port" . "port")
|
||||
("host" . "host")
|
||||
("obj\\|object" . "object")
|
||||
("previous\\|prev" . "previous")
|
||||
("str\\(ing\\)?" . "string")
|
||||
("use?r" . "user")
|
||||
("\\(^\\|\\s-\\)id\\($\\|\\s-\\)" . "Identifier") ;complex cause ;common syllable
|
||||
)
|
||||
"List of common English abbreviations or full words.
|
||||
These are nouns (as opposed to verbs) for use in creating expanded
|
||||
versions of names.This is an alist with each element of the form:
|
||||
(MATCH . RESULT)
|
||||
MATCH is a regexp to match in the type field.
|
||||
RESULT is a string."
|
||||
:group 'document
|
||||
:type '(repeat (cons (string :tag "Regexp")
|
||||
(string :tag "Doc Text"))))
|
||||
|
||||
(defcustom srecode-document-autocomment-function-alist
|
||||
'(
|
||||
("abort" . "Aborts the")
|
||||
;; trick to get re-alloc and alloc to pair into one sentence.
|
||||
("realloc" . "moves or ")
|
||||
("alloc\\(ate\\)?" . "Allocates and initializes a new ")
|
||||
("clean" . "Cleans up the")
|
||||
("clobber" . "Removes")
|
||||
("close" . "Cleanly closes")
|
||||
("check" . "Checks the")
|
||||
("comp\\(are\\)?" . "Compares the")
|
||||
("create" . "Creates a new ")
|
||||
("find" . "Finds ")
|
||||
("free" . "Frees up space")
|
||||
("gen\\(erate\\)?" . "Generates a new ")
|
||||
("get\\|find" . "Looks for the given ")
|
||||
("gobble" . "Removes")
|
||||
("he?lp" . "Provides help for")
|
||||
("li?ste?n" . "Listens for ")
|
||||
("connect" . "Connects to ")
|
||||
("acc?e?pt" . "Accepts a ")
|
||||
("load" . "Loads in ")
|
||||
("match" . "Check that parameters match")
|
||||
("name" . "Provides a name which ")
|
||||
("new" . "Allocates a ")
|
||||
("parse" . "Parses the parameters and returns ")
|
||||
("print\\|display" . "Prints out")
|
||||
("read" . "Reads from")
|
||||
("reset" . "Resets the parameters and returns")
|
||||
("scan" . "Scans the ")
|
||||
("setup\\|init\\(iallize\\)?" . "Initializes the ")
|
||||
("select" . "Chooses the ")
|
||||
("send" . "Sends a")
|
||||
("re?c\\(v\\|ieves?\\)" . "Receives a ")
|
||||
("to" . "Converts ")
|
||||
("update" . "Updates the ")
|
||||
("wait" . "Waits for ")
|
||||
("write" . "Writes to")
|
||||
)
|
||||
"List of names to string match against the function name.
|
||||
This is an alist with each element of the form:
|
||||
(MATCH . RESULT)
|
||||
MATCH is a regexp to match in the type field.
|
||||
RESULT is a string.
|
||||
|
||||
Certain prefixes may always mean the same thing, and the same comment
|
||||
can be used as a beginning for the description. Regexp should be
|
||||
lower case since the string they are compared to is downcased.
|
||||
A string may end in a space, in which case, last-alist is searched to
|
||||
see how best to describe what can be returned.
|
||||
Doesn't always work correctly, but that is just because English
|
||||
doesn't always work correctly."
|
||||
:group 'document
|
||||
:type '(repeat (cons (string :tag "Regexp")
|
||||
(string :tag "Doc Text"))))
|
||||
|
||||
(defcustom srecode-document-autocomment-common-nouns-abbrevs
|
||||
'(
|
||||
("sock\\(et\\)?" . "socket")
|
||||
("addr\\(ess\\)?" . "address")
|
||||
("buf\\(f\\(er\\)?\\)?" . "buffer")
|
||||
("cur\\(r\\(ent\\)?\\)?" . "current")
|
||||
("dev\\(ice\\)?" . "device")
|
||||
("file" . "file")
|
||||
("line" . "line")
|
||||
("msg\\|message" . "message")
|
||||
("name" . "name")
|
||||
("next\\|nxt" . "next")
|
||||
("port" . "port")
|
||||
("host" . "host")
|
||||
("obj\\|object" . "object")
|
||||
("previous\\|prev" . "previous")
|
||||
("str\\(ing\\)?" . "string")
|
||||
("use?r" . "user")
|
||||
("num\\(ber\\)?" . "number")
|
||||
("\\(^\\|\\s-\\)id\\($\\|\\s-\\)" . "Identifier") ;complex cause ;commen sylable
|
||||
)
|
||||
"List of common English abbreviations or full words.
|
||||
These are nouns (as opposed to verbs) for use in creating expanded
|
||||
versions of names.This is an alist with each element of the form:
|
||||
(MATCH . RESULT)
|
||||
MATCH is a regexp to match in the type field.
|
||||
RESULT is a string."
|
||||
:group 'document
|
||||
:type '(repeat (cons (string :tag "Regexp")
|
||||
(string :tag "Doc Text"))))
|
||||
|
||||
(defcustom srecode-document-autocomment-return-first-alist
|
||||
'(
|
||||
;; Static must be first in the list to provide the intro to the sentence
|
||||
("static" . "Locally defined function which ")
|
||||
("Bool\\|BOOL" . "Status of ")
|
||||
)
|
||||
"List of regexp matches for types.
|
||||
They provide a little bit of text when typing information is
|
||||
described.
|
||||
This is an alist with each element of the form:
|
||||
(MATCH . RESULT)
|
||||
MATCH is a regexp to match in the type field.
|
||||
RESULT is a string."
|
||||
:group 'document
|
||||
:type '(repeat (cons (string :tag "Regexp")
|
||||
(string :tag "Doc Text"))))
|
||||
|
||||
(defcustom srecode-document-autocomment-return-last-alist
|
||||
'(
|
||||
("static[ \t\n]+struct \\([a-zA-Z0-9_]+\\)" . "%s")
|
||||
("struct \\([a-zA-Z0-9_]+\\)" . "%s")
|
||||
("static[ \t\n]+union \\([a-zA-Z0-9_]+\\)" . "%s")
|
||||
("union \\([a-zA-Z0-9_]+\\)" . "%s")
|
||||
("static[ \t\n]+enum \\([a-zA-Z0-9_]+\\)" . "%s")
|
||||
("enum \\([a-zA-Z0-9_]+\\)" . "%s")
|
||||
("static[ \t\n]+\\([a-zA-Z0-9_]+\\)" . "%s")
|
||||
("\\([a-zA-Z0-9_]+\\)" . "of type %s")
|
||||
)
|
||||
"List of regexps which provide the type of the return value.
|
||||
This is an alist with each element of the form:
|
||||
(MATCH . RESULT)
|
||||
MATCH is a regexp to match in the type field.
|
||||
RESULT is a string, which can contain %s, whih is replaced with
|
||||
`match-string' 1."
|
||||
:group 'document
|
||||
:type '(repeat (cons (string :tag "Regexp")
|
||||
(string :tag "Doc Text"))))
|
||||
|
||||
(defcustom srecode-document-autocomment-param-alist
|
||||
'( ("[Cc]txt" . "Context")
|
||||
("[Ii]d" . "Identifier of")
|
||||
("[Tt]ype" . "Type of")
|
||||
("[Nn]ame" . "Name of")
|
||||
("argc" . "Number of arguments")
|
||||
("argv" . "Argument vector")
|
||||
("envp" . "Environment variable vector")
|
||||
)
|
||||
"Alist of common variable names appearing as function parameters.
|
||||
This is an alist with each element of the form:
|
||||
(MATCH . RESULT)
|
||||
MATCH is a regexp to match in the type field.
|
||||
RESULT is a string of text to use to describe MATCH.
|
||||
When one is encountered, document-insert-parameters will automatically
|
||||
place this comment after the parameter name."
|
||||
:group 'document
|
||||
:type '(repeat (cons (string :tag "Regexp")
|
||||
(string :tag "Doc Text"))))
|
||||
|
||||
(defcustom srecode-document-autocomment-param-type-alist
|
||||
'(("const" . "Constant")
|
||||
("void" . "Empty")
|
||||
("char[ ]*\\*" . "String ")
|
||||
("\\*\\*" . "Pointer to ")
|
||||
("\\*" . "Pointer ")
|
||||
("char[ ]*\\([^ \t*]\\|$\\)" . "Character")
|
||||
("int\\|long" . "Number of")
|
||||
("FILE" . "File of")
|
||||
("float\\|double" . "Value of")
|
||||
;; How about some X things?
|
||||
("Bool\\|BOOL" . "Flag")
|
||||
("Window" . "Window")
|
||||
("GC" . "Graphic Context")
|
||||
("Widget" . "Widget")
|
||||
)
|
||||
"Alist of input parameter types and strings desribing them.
|
||||
This is an alist with each element of the form:
|
||||
(MATCH . RESULT)
|
||||
MATCH is a regexp to match in the type field.
|
||||
RESULT is a string."
|
||||
:group 'document
|
||||
:type '(repeat (cons (string :tag "Regexp")
|
||||
(string :tag "Doc Text"))))
|
||||
|
||||
;;;###autoload
|
||||
(defun srecode-document-insert-comment ()
|
||||
"Insert some comments.
|
||||
Whack any comments that may be in the way and replace them.
|
||||
If the region is active, then insert group function comments.
|
||||
If the cursor is in a comment, figure out what kind of comment it is
|
||||
and replace it.
|
||||
If the cursor is in a function, insert a function comment.
|
||||
If the cursor is on a one line prototype, then insert post-fcn comments."
|
||||
(interactive)
|
||||
(semantic-fetch-tags)
|
||||
(let ((ctxt (srecode-calculate-context)))
|
||||
(if ;; Active region stuff.
|
||||
(or srecode-handle-region-when-non-active-flag
|
||||
(eq last-command 'mouse-drag-region)
|
||||
(and transient-mark-mode mark-active))
|
||||
(if (> (point) (mark))
|
||||
(srecode-document-insert-group-comments (mark) (point))
|
||||
(srecode-document-insert-group-comments (point) (mark)))
|
||||
;; ELSE
|
||||
|
||||
;; A declaration comment. Find what it documents.
|
||||
(when (equal ctxt '("declaration" "comment"))
|
||||
|
||||
;; If we are on a one line tag/comment, go to that fcn.
|
||||
(if (save-excursion (back-to-indentation)
|
||||
(semantic-current-tag))
|
||||
(back-to-indentation)
|
||||
|
||||
;; Else, do we have a fcn following us?
|
||||
(let ((tag (semantic-find-tag-by-overlay-next)))
|
||||
(when tag (semantic-go-to-tag tag))))
|
||||
)
|
||||
|
||||
;; Now analyze the tag we may be on.
|
||||
|
||||
(if (semantic-current-tag)
|
||||
(cond
|
||||
;; A one-line variable
|
||||
((and (semantic-tag-of-class-p (semantic-current-tag) 'variable)
|
||||
(srecode-document-one-line-tag-p (semantic-current-tag)))
|
||||
(srecode-document-insert-variable-one-line-comment))
|
||||
;; A plain function
|
||||
((semantic-tag-of-class-p (semantic-current-tag) 'function)
|
||||
(srecode-document-insert-function-comment))
|
||||
;; Don't know.
|
||||
(t
|
||||
(error "Not sure what to comment"))
|
||||
)
|
||||
|
||||
;; ELSE, no tag. Perhaps we should just insert a nice section
|
||||
;; header??
|
||||
|
||||
(let ((title (read-string "Section Title (RET to skip): ")))
|
||||
|
||||
(when (and (stringp title) (not (= (length title) 0)))
|
||||
(srecode-document-insert-section-comment title)))
|
||||
|
||||
))))
|
||||
|
||||
(defun srecode-document-insert-section-comment (&optional title)
|
||||
"Insert a section comment with TITLE."
|
||||
(interactive "sSection Title: ")
|
||||
|
||||
(srecode-load-tables-for-mode major-mode)
|
||||
(srecode-load-tables-for-mode major-mode 'document)
|
||||
|
||||
(if (not (srecode-table))
|
||||
(error "No template table found for mode %s" major-mode))
|
||||
|
||||
(let* ((dict (srecode-create-dictionary))
|
||||
(temp (srecode-template-get-table (srecode-table)
|
||||
"section-comment"
|
||||
"declaration"
|
||||
'document)))
|
||||
(if (not temp)
|
||||
(error "No templates for inserting section comments"))
|
||||
|
||||
(when title
|
||||
(srecode-dictionary-set-value
|
||||
dict "TITLE" title))
|
||||
|
||||
(srecode-insert-fcn temp dict)
|
||||
))
|
||||
|
||||
|
||||
(defun srecode-document-trim-whitespace (str)
|
||||
"Strip stray whitespace from around STR."
|
||||
(when (string-match "^\\(\\s-\\|\n\\)+" str)
|
||||
(setq str (replace-match "" t t str)))
|
||||
(when (string-match "\\(\\s-\\|\n\\)+$" str)
|
||||
(setq str (replace-match "" t t str)))
|
||||
str)
|
||||
|
||||
;;;###autoload
|
||||
(defun srecode-document-insert-function-comment (&optional fcn-in)
|
||||
"Insert or replace a function comment.
|
||||
FCN-IN is the Semantic tag of the function to add a comment too.
|
||||
If FCN-IN is not provied, the current tag is used instead.
|
||||
It is assumed that the comment occurs just in front of FCN-IN."
|
||||
(interactive)
|
||||
|
||||
(srecode-load-tables-for-mode major-mode)
|
||||
(srecode-load-tables-for-mode major-mode 'document)
|
||||
|
||||
(if (not (srecode-table))
|
||||
(error "No template table found for mode %s" major-mode))
|
||||
|
||||
(let* ((dict (srecode-create-dictionary))
|
||||
(temp (srecode-template-get-table (srecode-table)
|
||||
"function-comment"
|
||||
"declaration"
|
||||
'document)))
|
||||
(if (not temp)
|
||||
(error "No templates for inserting function comments"))
|
||||
|
||||
;; Try to figure out the tag we want to use.
|
||||
(when (not fcn-in)
|
||||
(semantic-fetch-tags)
|
||||
(setq fcn-in (semantic-current-tag)))
|
||||
|
||||
(when (or (not fcn-in)
|
||||
(not (semantic-tag-of-class-p fcn-in 'function)))
|
||||
(error "No tag of class 'function to insert comment for"))
|
||||
|
||||
(if (not (eq (current-buffer) (semantic-tag-buffer fcn-in)))
|
||||
(error "Only insert comments for tags in the current buffer"))
|
||||
|
||||
;; Find any existing doc strings.
|
||||
(semantic-go-to-tag fcn-in)
|
||||
(beginning-of-line)
|
||||
(forward-char -1)
|
||||
|
||||
(let ((lextok (semantic-documentation-comment-preceeding-tag fcn-in 'lex))
|
||||
(doctext
|
||||
(srecode-document-function-name-comment fcn-in))
|
||||
)
|
||||
|
||||
(when lextok
|
||||
(let* ((s (semantic-lex-token-start lextok))
|
||||
(e (semantic-lex-token-end lextok))
|
||||
(plaintext
|
||||
(srecode-document-trim-whitespace
|
||||
(save-excursion
|
||||
(goto-char s)
|
||||
(semantic-doc-snarf-comment-for-tag nil))))
|
||||
(extract (condition-case nil
|
||||
(srecode-extract temp s e)
|
||||
(error nil))
|
||||
)
|
||||
(distance (count-lines e (semantic-tag-start fcn-in)))
|
||||
(belongelsewhere (save-excursion
|
||||
(goto-char s)
|
||||
(back-to-indentation)
|
||||
(semantic-current-tag)))
|
||||
)
|
||||
|
||||
(when (not belongelsewhere)
|
||||
|
||||
(pulse-momentary-highlight-region s e)
|
||||
|
||||
;; There are many possible states that comment could be in.
|
||||
;; Take a guess about what the user would like to do, and ask
|
||||
;; the right kind of question.
|
||||
(when (or (not (> distance 2))
|
||||
(y-or-n-p "Replace this comment? "))
|
||||
|
||||
(when (> distance 2)
|
||||
(goto-char e)
|
||||
(delete-horizontal-space)
|
||||
(delete-blank-lines))
|
||||
|
||||
(cond
|
||||
((and plaintext (not extract))
|
||||
(if (y-or-n-p "Convert old-style comment to Template with old text? ")
|
||||
(setq doctext plaintext))
|
||||
(delete-region s e)
|
||||
(goto-char s))
|
||||
(extract
|
||||
(when (y-or-n-p "Refresh pre-existing comment (recycle old doc)? ")
|
||||
(delete-region s e)
|
||||
(goto-char s)
|
||||
(setq doctext
|
||||
(srecode-document-trim-whitespace
|
||||
(srecode-dictionary-lookup-name extract "DOC")))))
|
||||
))
|
||||
)))
|
||||
|
||||
(beginning-of-line)
|
||||
|
||||
;; Perform the insertion
|
||||
(let ((srecode-semantic-selected-tag fcn-in)
|
||||
(srecode-semantic-apply-tag-augment-hook
|
||||
(lambda (tag dict)
|
||||
(srecode-dictionary-set-value
|
||||
dict "DOC"
|
||||
(if (eq tag fcn-in)
|
||||
doctext
|
||||
(srecode-document-parameter-comment tag))
|
||||
)))
|
||||
)
|
||||
(srecode-insert-fcn temp dict)
|
||||
))
|
||||
))
|
||||
|
||||
;;;###autoload
|
||||
(defun srecode-document-insert-variable-one-line-comment (&optional var-in)
|
||||
"Insert or replace a variable comment.
|
||||
VAR-IN is the Semantic tag of the function to add a comment too.
|
||||
If VAR-IN is not provied, the current tag is used instead.
|
||||
It is assumed that the comment occurs just after VAR-IN."
|
||||
(interactive)
|
||||
|
||||
(srecode-load-tables-for-mode major-mode)
|
||||
(srecode-load-tables-for-mode major-mode 'document)
|
||||
|
||||
(if (not (srecode-table))
|
||||
(error "No template table found for mode %s" major-mode))
|
||||
|
||||
(let* ((dict (srecode-create-dictionary))
|
||||
(temp (srecode-template-get-table (srecode-table)
|
||||
"variable-same-line-comment"
|
||||
"declaration"
|
||||
'document)))
|
||||
(if (not temp)
|
||||
(error "No templates for inserting variable comments"))
|
||||
|
||||
;; Try to figure out the tag we want to use.
|
||||
(when (not var-in)
|
||||
(semantic-fetch-tags)
|
||||
(setq var-in (semantic-current-tag)))
|
||||
|
||||
(when (or (not var-in)
|
||||
(not (semantic-tag-of-class-p var-in 'variable)))
|
||||
(error "No tag of class 'variable to insert comment for"))
|
||||
|
||||
(if (not (eq (current-buffer) (semantic-tag-buffer var-in)))
|
||||
(error "Only insert comments for tags in the current buffer"))
|
||||
|
||||
;; Find any existing doc strings.
|
||||
(goto-char (semantic-tag-end var-in))
|
||||
(skip-syntax-forward "-" (point-at-eol))
|
||||
(let ((lextok (semantic-doc-snarf-comment-for-tag 'lex))
|
||||
)
|
||||
|
||||
(when lextok
|
||||
(let ((s (semantic-lex-token-start lextok))
|
||||
(e (semantic-lex-token-end lextok)))
|
||||
|
||||
(pulse-momentary-highlight-region s e)
|
||||
|
||||
(when (not (y-or-n-p "A comment already exists. Replace? "))
|
||||
(error "Quit"))
|
||||
|
||||
;; Extract text from the existing comment.
|
||||
(srecode-extract temp s e)
|
||||
|
||||
(delete-region s e)
|
||||
(goto-char s) ;; To avoid adding a CR.
|
||||
))
|
||||
)
|
||||
|
||||
;; Clean up the end of the line and use handy comment-column.
|
||||
(end-of-line)
|
||||
(delete-horizontal-space)
|
||||
(move-to-column comment-column t)
|
||||
(when (< (point) (point-at-eol)) (end-of-line))
|
||||
|
||||
;; Perform the insertion
|
||||
(let ((srecode-semantic-selected-tag var-in)
|
||||
(srecode-semantic-apply-tag-augment-hook
|
||||
(lambda (tag dict)
|
||||
(srecode-dictionary-set-value
|
||||
dict "DOC" (srecode-document-parameter-comment
|
||||
tag))))
|
||||
)
|
||||
(srecode-insert-fcn temp dict)
|
||||
))
|
||||
)
|
||||
|
||||
;;;###autoload
|
||||
(defun srecode-document-insert-group-comments (beg end)
|
||||
"Insert group comments around the active between BEG and END.
|
||||
If the region includes only parts of some tags, expand out
|
||||
to the beginning and end of the tags on the region.
|
||||
If there is only one tag in the region, complain."
|
||||
(interactive "r")
|
||||
(srecode-load-tables-for-mode major-mode)
|
||||
(srecode-load-tables-for-mode major-mode 'document)
|
||||
|
||||
(if (not (srecode-table))
|
||||
(error "No template table found for mode %s" major-mode))
|
||||
|
||||
(let* ((dict (srecode-create-dictionary))
|
||||
(context "declaration")
|
||||
(temp-start nil)
|
||||
(temp-end nil)
|
||||
(tag-start (save-excursion
|
||||
(goto-char beg)
|
||||
(or (semantic-current-tag)
|
||||
(semantic-find-tag-by-overlay-next))))
|
||||
(tag-end (save-excursion
|
||||
(goto-char end)
|
||||
(or (semantic-current-tag)
|
||||
(semantic-find-tag-by-overlay-prev))))
|
||||
(parent-tag nil)
|
||||
(first-pos beg)
|
||||
(second-pos end)
|
||||
)
|
||||
|
||||
;; If beg/end wrapped nothing, then tag-start,end would actually
|
||||
;; point at some odd stuff that is out of order.
|
||||
(when (or (not tag-start) (not tag-end)
|
||||
(> (semantic-tag-end tag-start)
|
||||
(semantic-tag-start tag-end)))
|
||||
(setq tag-start nil
|
||||
tag-end nil))
|
||||
|
||||
(when tag-start
|
||||
;; If tag-start and -end are the same, and it is a class or
|
||||
;; struct, try to find child tags inside the classdecl.
|
||||
(cond
|
||||
((and (eq tag-start tag-end)
|
||||
tag-start
|
||||
(semantic-tag-of-class-p tag-start 'type))
|
||||
(setq parent-tag tag-start)
|
||||
(setq tag-start (semantic-find-tag-by-overlay-next beg)
|
||||
tag-end (semantic-find-tag-by-overlay-prev end))
|
||||
)
|
||||
((eq (semantic-find-tag-parent-by-overlay tag-start) tag-end)
|
||||
(setq parent-tag tag-end)
|
||||
(setq tag-end (semantic-find-tag-by-overlay-prev end))
|
||||
)
|
||||
((eq tag-start (semantic-find-tag-parent-by-overlay tag-end))
|
||||
(setq parent-tag tag-start)
|
||||
(setq tag-start (semantic-find-tag-by-overlay-next beg))
|
||||
)
|
||||
)
|
||||
|
||||
(when parent-tag
|
||||
;; We are probably in a classdecl
|
||||
;; @todo -could I really use (srecode-calculate-context) ?
|
||||
|
||||
(setq context "classdecl")
|
||||
)
|
||||
|
||||
;; Derive start and end locations based on the tags.
|
||||
(setq first-pos (semantic-tag-start tag-start)
|
||||
second-pos (semantic-tag-end tag-end))
|
||||
)
|
||||
;; Now load the templates
|
||||
(setq temp-start (srecode-template-get-table (srecode-table)
|
||||
"group-comment-start"
|
||||
context
|
||||
'document)
|
||||
temp-end (srecode-template-get-table (srecode-table)
|
||||
"group-comment-end"
|
||||
context
|
||||
'document))
|
||||
|
||||
(when (or (not temp-start) (not temp-end))
|
||||
(error "No templates for inserting group comments"))
|
||||
|
||||
;; Setup the name of this group ahead of time.
|
||||
|
||||
;; @todo - guess at a name based on common strings
|
||||
;; of the tags in the group.
|
||||
(srecode-dictionary-set-value
|
||||
dict "GROUPNAME"
|
||||
(read-string "Name of group: "))
|
||||
|
||||
;; Perform the insertion
|
||||
;; Do the end first so we don't need to recalculate anything.
|
||||
;;
|
||||
(goto-char second-pos)
|
||||
(end-of-line)
|
||||
(srecode-insert-fcn temp-end dict)
|
||||
|
||||
(goto-char first-pos)
|
||||
(beginning-of-line)
|
||||
(srecode-insert-fcn temp-start dict)
|
||||
|
||||
))
|
||||
|
||||
|
||||
;;; Document Generation Functions
|
||||
;;
|
||||
;; Routines for making up English style comments.
|
||||
|
||||
(defun srecode-document-function-name-comment (tag)
|
||||
"Create documentation for the function defined in TAG.
|
||||
If we can identify a verb in the list followed by some
|
||||
name part then check the return value to see if we can use that to
|
||||
finish off the sentence. ie. any function with 'alloc' in it will be
|
||||
allocating something based on its type."
|
||||
(let ((al srecode-document-autocomment-return-first-alist)
|
||||
(dropit nil)
|
||||
(tailit nil)
|
||||
(news "")
|
||||
(fname (semantic-tag-name tag))
|
||||
(retval (or (semantic-tag-type tag) "")))
|
||||
(if (listp retval)
|
||||
;; convert a type list into a long string to analyze.
|
||||
(setq retval (car retval)))
|
||||
;; check for modifiers like static
|
||||
(while al
|
||||
(if (string-match (car (car al)) (downcase retval))
|
||||
(progn
|
||||
(setq news (concat news (cdr (car al))))
|
||||
(setq dropit t)
|
||||
(setq al nil)))
|
||||
(setq al (cdr al)))
|
||||
;; check for verb parts!
|
||||
(setq al srecode-document-autocomment-function-alist)
|
||||
(while al
|
||||
(if (string-match (car (car al)) (downcase fname))
|
||||
(progn
|
||||
(setq news
|
||||
(concat news (if dropit (downcase (cdr (car al)))
|
||||
(cdr (car al)))))
|
||||
;; if we end in a space, then we are expecting a potential
|
||||
;; return value.
|
||||
(if (= ? (aref news (1- (length news))))
|
||||
(setq tailit t))
|
||||
(setq al nil)))
|
||||
(setq al (cdr al)))
|
||||
;; check for noun parts!
|
||||
(setq al srecode-document-autocomment-common-nouns-abbrevs)
|
||||
(while al
|
||||
(if (string-match (car (car al)) (downcase fname))
|
||||
(progn
|
||||
(setq news
|
||||
(concat news (if dropit (downcase (cdr (car al)))
|
||||
(cdr (car al)))))
|
||||
(setq al nil)))
|
||||
(setq al (cdr al)))
|
||||
;; add tailers to names which are obviously returning something.
|
||||
(if tailit
|
||||
(progn
|
||||
(setq al srecode-document-autocomment-return-last-alist)
|
||||
(while al
|
||||
(if (string-match (car (car al)) (downcase retval))
|
||||
(progn
|
||||
(setq news
|
||||
(concat news " "
|
||||
;; this one may use parts of the return value.
|
||||
(format (cdr (car al))
|
||||
(srecode-document-programmer->english
|
||||
(substring retval (match-beginning 1)
|
||||
(match-end 1))))))
|
||||
(setq al nil)))
|
||||
(setq al (cdr al)))))
|
||||
news))
|
||||
|
||||
(defun srecode-document-parameter-comment (param &optional commentlist)
|
||||
"Convert tag or string PARAM into a name,comment pair.
|
||||
Optional COMMENTLIST is list of previously existing comments to
|
||||
use instead in alist form. If the name doesn't appear in the list of
|
||||
standard names, then englishify it instead."
|
||||
(let ((cmt "")
|
||||
(aso srecode-document-autocomment-param-alist)
|
||||
(fnd nil)
|
||||
(name (if (stringp param) param (semantic-tag-name param)))
|
||||
(tt (if (stringp param) nil (semantic-tag-type param))))
|
||||
;; Make sure the type is a string.
|
||||
(if (listp tt)
|
||||
(setq tt (semantic-tag-name tt)))
|
||||
;; Find name description parts.
|
||||
(while aso
|
||||
(if (string-match (car (car aso)) name)
|
||||
(progn
|
||||
(setq fnd t)
|
||||
(setq cmt (concat cmt (cdr (car aso))))))
|
||||
(setq aso (cdr aso)))
|
||||
(if (/= (length cmt) 0)
|
||||
nil
|
||||
;; finally check for array parts
|
||||
(if (and (not (stringp param)) (semantic-tag-modifiers param))
|
||||
(setq cmt (concat cmt "array of ")))
|
||||
(setq aso srecode-document-autocomment-param-type-alist)
|
||||
(while (and aso tt)
|
||||
(if (string-match (car (car aso)) tt)
|
||||
(setq cmt (concat cmt (cdr (car aso)))))
|
||||
(setq aso (cdr aso))))
|
||||
;; Convert from programmer to english.
|
||||
(if (not fnd)
|
||||
(setq cmt (concat cmt " "
|
||||
(srecode-document-programmer->english name))))
|
||||
cmt))
|
||||
|
||||
(defun srecode-document-programmer->english (programmer)
|
||||
"Take PROGRAMMER and convert it into English.
|
||||
Works with the following rules:
|
||||
1) convert all _ into spaces.
|
||||
2) inserts spaces between CamelCasing word breaks.
|
||||
3) expands noun names based on common programmer nouns.
|
||||
|
||||
This function is designed for variables, not functions. This does
|
||||
not account for verb parts."
|
||||
(if (string= "" programmer)
|
||||
""
|
||||
(let ((ind 0) ;index in string
|
||||
(llow nil) ;lower/upper case flag
|
||||
(newstr nil) ;new string being generated
|
||||
(al nil)) ;autocomment list
|
||||
;;
|
||||
;; 1) Convert underscores
|
||||
;;
|
||||
(while (< ind (length programmer))
|
||||
(setq newstr (concat newstr
|
||||
(if (= (aref programmer ind) ?_)
|
||||
" " (char-to-string (aref programmer ind)))))
|
||||
(setq ind (1+ ind)))
|
||||
(setq programmer newstr
|
||||
newstr nil
|
||||
ind 0)
|
||||
;;
|
||||
;; 2) Find word breaks between case changes
|
||||
;;
|
||||
(while (< ind (length programmer))
|
||||
(setq newstr
|
||||
(concat newstr
|
||||
(let ((tc (aref programmer ind)))
|
||||
(if (and (>= tc ?a) (<= tc ?z))
|
||||
(progn
|
||||
(setq llow t)
|
||||
(char-to-string tc))
|
||||
(if llow
|
||||
(progn
|
||||
(setq llow nil)
|
||||
(concat " " (char-to-string tc)))
|
||||
(char-to-string tc))))))
|
||||
(setq ind (1+ ind)))
|
||||
;;
|
||||
;; 3) Expand the words if possible
|
||||
;;
|
||||
(setq llow nil
|
||||
ind 0
|
||||
programmer newstr
|
||||
newstr nil)
|
||||
(while (string-match (concat "^\\s-*\\([^ \t\n]+\\)") programmer)
|
||||
(let ((ts (substring programmer (match-beginning 1) (match-end 1)))
|
||||
(end (match-end 1)))
|
||||
(setq al srecode-document-autocomment-common-nouns-abbrevs)
|
||||
(setq llow nil)
|
||||
(while al
|
||||
(if (string-match (car (car al)) (downcase ts))
|
||||
(progn
|
||||
(setq newstr (concat newstr (cdr (car al))))
|
||||
;; don't terminate because we may actuall have 2 words
|
||||
;; next to eachother we didn't identify before
|
||||
(setq llow t)))
|
||||
(setq al (cdr al)))
|
||||
(if (not llow) (setq newstr (concat newstr ts)))
|
||||
(setq newstr (concat newstr " "))
|
||||
(setq programmer (substring programmer end))))
|
||||
newstr)))
|
||||
|
||||
;;; UTILS
|
||||
;;
|
||||
(defun srecode-document-one-line-tag-p (tag)
|
||||
"Does TAG fit on one line with space on the end?"
|
||||
(save-excursion
|
||||
(semantic-go-to-tag tag)
|
||||
(and (<= (semantic-tag-end tag) (point-at-eol))
|
||||
(goto-char (semantic-tag-end tag))
|
||||
(< (current-column) 70))))
|
||||
|
||||
(provide 'srecode/document)
|
||||
|
||||
;; Local variables:
|
||||
;; generated-autoload-file: "loaddefs.el"
|
||||
;; generated-autoload-feature: srecode/loaddefs
|
||||
;; generated-autoload-load-name: "srecode/document"
|
||||
;; End:
|
||||
|
||||
;;; srecode/document.el ends here
|
113
lisp/cedet/srecode/el.el
Normal file
113
lisp/cedet/srecode/el.el
Normal file
|
@ -0,0 +1,113 @@
|
|||
;;; srecode/el.el --- Emacs Lisp specific arguments
|
||||
|
||||
;; Copyright (C) 2008 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Eric M. Ludlam <eric@siege-engine.com>
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; Emacs Lisp specific handlers. To use these handlers in your
|
||||
;; template, add the :name part to your template argument list.
|
||||
;;
|
||||
;; Error if not in a Emacs Lisp mode
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'srecode)
|
||||
(require 'srecode/semantic)
|
||||
|
||||
(declare-function semanticdb-brute-find-tags-by-class "semantic/db-find")
|
||||
|
||||
;;;###autoload
|
||||
(defun srecode-semantic-handle-:el (dict)
|
||||
"Add macros into the dictionary DICT based on the current Emacs Lisp file.
|
||||
Adds the following:
|
||||
PRENAME - The common name prefix of this file."
|
||||
(let* ((names (append (semantic-find-tags-by-class 'function (current-buffer))
|
||||
(semantic-find-tags-by-class 'variable (current-buffer)))
|
||||
)
|
||||
(common (try-completion "" names)))
|
||||
|
||||
(srecode-dictionary-set-value dict "PRENAME" common)
|
||||
))
|
||||
|
||||
;;;###autoload
|
||||
(defun srecode-semantic-handle-:el-custom (dict)
|
||||
"Add macros into the dictionary DICT based on the current Emacs Lisp file.
|
||||
Adds the following:
|
||||
GROUP - The 'defgroup' name we guess you want for variables.
|
||||
FACEGROUP - The `defgroup' name you might want for faces."
|
||||
(require 'semantic/db-find)
|
||||
(let ((groups (semanticdb-strip-find-results
|
||||
(semanticdb-brute-find-tags-by-class 'customgroup)))
|
||||
(varg nil)
|
||||
(faceg nil)
|
||||
)
|
||||
|
||||
;; Pick the best group
|
||||
(while groups
|
||||
(cond ((string-match "face" (semantic-tag-name (car groups)))
|
||||
(setq faceg (car groups)))
|
||||
((not varg)
|
||||
(setq varg (car groups)))
|
||||
(t
|
||||
;; What about other groups?
|
||||
))
|
||||
(setq groups (cdr groups)))
|
||||
|
||||
;; Double check the facegroup.
|
||||
(setq faceg (or faceg varg))
|
||||
|
||||
;; Setup some variables
|
||||
(srecode-dictionary-set-value dict "GROUP" (semantic-tag-name varg))
|
||||
(srecode-dictionary-set-value dict "FACEGROUP" (semantic-tag-name faceg))
|
||||
|
||||
))
|
||||
|
||||
(define-mode-local-override srecode-semantic-apply-tag-to-dict
|
||||
emacs-lisp-mode (tagobj dict)
|
||||
"Apply Emacs Lisp specific features from TAGOBJ into DICT.
|
||||
Calls `srecode-semantic-apply-tag-to-dict-default' first."
|
||||
(srecode-semantic-apply-tag-to-dict-default tagobj dict)
|
||||
|
||||
;; Pull out the tag for the individual pieces.
|
||||
(let* ((tag (oref tagobj :prime))
|
||||
(doc (semantic-tag-docstring tag)))
|
||||
|
||||
;; It is much more common to have doc on ELisp.
|
||||
(srecode-dictionary-set-value dict "DOC" doc)
|
||||
|
||||
(cond
|
||||
;;
|
||||
;; FUNCTION
|
||||
;;
|
||||
((eq (semantic-tag-class tag) 'function)
|
||||
(if (semantic-tag-get-attribute tag :user-visible-flag)
|
||||
(srecode-dictionary-set-value dict "INTERACTIVE" " (interactive)\n ")
|
||||
(srecode-dictionary-set-value dict "INTERACTIVE" ""))))))
|
||||
|
||||
|
||||
(provide 'srecode/el)
|
||||
|
||||
;; Local variables:
|
||||
;; generated-autoload-file: "loaddefs.el"
|
||||
;; generated-autoload-feature: srecode/loaddefs
|
||||
;; generated-autoload-load-name: "srecode/el"
|
||||
;; End:
|
||||
|
||||
;;; srecode/el.el ends here
|
132
lisp/cedet/srecode/expandproto.el
Normal file
132
lisp/cedet/srecode/expandproto.el
Normal file
|
@ -0,0 +1,132 @@
|
|||
;;; srecode/expandproto.el --- Expanding prototypes.
|
||||
|
||||
;; Copyright (C) 2007 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Eric M. Ludlam <eric@siege-engine.com>
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; Methods for expanding a prototype into an implementation.
|
||||
|
||||
(require 'ring)
|
||||
(require 'semantic)
|
||||
(require 'semantic/analyze)
|
||||
(require 'srecode/insert)
|
||||
(require 'srecode/dictionary)
|
||||
|
||||
(declare-function semantic-brute-find-tag-by-attribute-value "semantic/find")
|
||||
|
||||
;;; Code:
|
||||
(defcustom srecode-expandproto-template-file-alist
|
||||
'( ( c++-mode . "srecode-expandproto-cpp.srt" )
|
||||
)
|
||||
;; @todo - Make this variable auto-generated from the Makefile.
|
||||
"Associate template files for expanding prototypes to a major mode."
|
||||
:group 'srecode
|
||||
:type '(repeat (cons (sexp :tag "Mode")
|
||||
(sexp :tag "Filename"))
|
||||
))
|
||||
|
||||
;;;###autoload
|
||||
(defun srecode-insert-prototype-expansion ()
|
||||
"Insert get/set methods for the current class."
|
||||
(interactive)
|
||||
|
||||
(srecode-load-tables-for-mode major-mode)
|
||||
(srecode-load-tables-for-mode major-mode
|
||||
srecode-expandproto-template-file-alist)
|
||||
|
||||
(if (not (srecode-table))
|
||||
(error "No template table found for mode %s" major-mode))
|
||||
|
||||
(let ((proto
|
||||
;; Step 1: Find the prototype, or prototype list to expand.
|
||||
(srecode-find-prototype-for-expansion)))
|
||||
|
||||
(if (not proto)
|
||||
(error "Could not find prototype to expand"))
|
||||
|
||||
;; Step 2: Insert implementations of the prototypes.
|
||||
|
||||
|
||||
))
|
||||
|
||||
(defun srecode-find-prototype-for-expansion ()
|
||||
"Find a prototype to use for expanding into an implementation."
|
||||
;; We may find a prototype tag in one of several places.
|
||||
;; Search in order of logical priority.
|
||||
(let ((proto nil)
|
||||
)
|
||||
|
||||
;; 1) A class full of prototypes under point.
|
||||
(let ((tag (semantic-current-tag)))
|
||||
(when tag
|
||||
(when (not (semantic-tag-of-class-p tag 'type))
|
||||
(setq tag (semantic-current-tag-parent))))
|
||||
(when (and tag (semantic-tag-of-class-p tag 'type))
|
||||
;; If the current class has prototype members, then
|
||||
;; we will do the whole class!
|
||||
(require 'semantic/find)
|
||||
(if (semantic-brute-find-tag-by-attribute-value
|
||||
:prototype t
|
||||
(semantic-tag-type-members tag))
|
||||
(setq proto tag)))
|
||||
)
|
||||
|
||||
;; 2) A prototype under point.
|
||||
(when (not proto)
|
||||
(let ((tag (semantic-current-tag)))
|
||||
(when (and tag
|
||||
(and
|
||||
(semantic-tag-of-class-p tag 'function)
|
||||
(semantic-tag-get-attribute tag :prototype)))
|
||||
(setq proto tag))))
|
||||
|
||||
;; 3) A tag in the kill ring that is a prototype
|
||||
(when (not proto)
|
||||
(if (ring-empty-p senator-tag-ring)
|
||||
nil ;; Not for us.
|
||||
(let ((tag (ring-ref senator-tag-ring 0))
|
||||
)
|
||||
(when
|
||||
(and tag
|
||||
(or
|
||||
(and
|
||||
(semantic-tag-of-class-p tag 'function)
|
||||
(semantic-tag-get-attribute tag :prototype))
|
||||
(and
|
||||
(semantic-tag-of-class-p tag 'type)
|
||||
(require 'semantic/find)
|
||||
(semantic-brute-find-tag-by-attribute-value
|
||||
:prototype t
|
||||
(semantic-tag-type-members tag))))
|
||||
)
|
||||
(setq proto tag))
|
||||
)))
|
||||
|
||||
proto))
|
||||
|
||||
(provide 'srecode-expandproto)
|
||||
|
||||
;; Local variables:
|
||||
;; generated-autoload-file: "loaddefs.el"
|
||||
;; generated-autoload-feature: srecode/loaddefs
|
||||
;; generated-autoload-load-name: "srecode/expandproto"
|
||||
;; End:
|
||||
|
||||
;;; srecode/expandproto.el ends here
|
242
lisp/cedet/srecode/extract.el
Normal file
242
lisp/cedet/srecode/extract.el
Normal file
|
@ -0,0 +1,242 @@
|
|||
;;; srecode/extract.el --- Extract content from previously inserted macro.
|
||||
|
||||
;; Copyright (C) 2008, 2009 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Eric M. Ludlam <eric@siege-engine.com>
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; Extract content from a previously inserted macro.
|
||||
;;
|
||||
;; The extraction routines can be handy if you want to extract users
|
||||
;; added text from the middle of a template inserted block of text.
|
||||
;; This code will not work for all templates. It will only work for
|
||||
;; templates with unique static text between all the different insert
|
||||
;; macros.
|
||||
;;
|
||||
;; That said, it will handle include and section templates, so complex
|
||||
;; or deep template calls can be extracted.
|
||||
;;
|
||||
;; This code was specifically written for srecode-document, which
|
||||
;; wants to extract user written text, and re-use it in a reformatted
|
||||
;; comment.
|
||||
|
||||
(require 'srecode)
|
||||
(require 'srecode/compile)
|
||||
(require 'srecode/insert)
|
||||
|
||||
;;; Code:
|
||||
|
||||
(defclass srecode-extract-state ()
|
||||
((anchor :initform nil
|
||||
:documentation
|
||||
"The last known plain-text end location.")
|
||||
(lastinserter :initform nil
|
||||
:documentation
|
||||
"The last inserter with 'later extraction type.")
|
||||
(lastdict :initform nil
|
||||
:documentation
|
||||
"The dictionary associated with lastinserter.")
|
||||
)
|
||||
"The current extraction state.")
|
||||
|
||||
(defmethod srecode-extract-state-set ((st srecode-extract-state) ins dict)
|
||||
"Set onto the extract state ST a new inserter INS and dictinary DICT."
|
||||
(oset st lastinserter ins)
|
||||
(oset st lastdict dict))
|
||||
|
||||
(defmethod srecode-extract-state-set-anchor ((st srecode-extract-state))
|
||||
"Reset the achor point on extract state ST."
|
||||
(oset st anchor (point)))
|
||||
|
||||
(defmethod srecode-extract-state-extract ((st srecode-extract-state)
|
||||
endpoint)
|
||||
"Perform an extraction on the extract state ST with ENDPOITNT.
|
||||
If there was no waiting inserter, do nothing."
|
||||
(when (oref st lastinserter)
|
||||
(save-match-data
|
||||
(srecode-inserter-extract (oref st lastinserter)
|
||||
(oref st anchor)
|
||||
endpoint
|
||||
(oref st lastdict)
|
||||
st))
|
||||
;; Clear state.
|
||||
(srecode-extract-state-set st nil nil)))
|
||||
|
||||
;;; Extraction
|
||||
;l
|
||||
(defun srecode-extract (template start end)
|
||||
"Extract TEMPLATE from between START and END in the current buffer.
|
||||
Uses TEMPLATE's constant strings to break up the text and guess what
|
||||
the dictionary entries were for that block of text."
|
||||
(save-excursion
|
||||
(save-restriction
|
||||
(narrow-to-region start end)
|
||||
(let ((dict (srecode-create-dictionary t))
|
||||
(state (srecode-extract-state "state"))
|
||||
)
|
||||
(goto-char start)
|
||||
(srecode-extract-method template dict state)
|
||||
dict))))
|
||||
|
||||
(defmethod srecode-extract-method ((st srecode-template) dictionary
|
||||
state)
|
||||
"Extract template ST and store extracted text in DICTIONARY.
|
||||
Optional STARTRETURN is a symbol in which the start of the first
|
||||
plain-text match occured."
|
||||
(srecode-extract-code-stream (oref st code) dictionary state))
|
||||
|
||||
(defun srecode-extract-code-stream (code dictionary state)
|
||||
"Extract CODE from buffer text into DICTIONARY.
|
||||
Uses string constants in CODE to split up the buffer.
|
||||
Uses STATE to maintain the current extraction state."
|
||||
(while code
|
||||
(cond
|
||||
|
||||
;; constant strings need mark the end of old inserters that
|
||||
;; need to extract values, or are just there.
|
||||
((stringp (car code))
|
||||
(srecode-extract-state-set-anchor state)
|
||||
;; When we have a string, find it in the collection, then extract
|
||||
;; that start point as the end point of the inserter
|
||||
(unless (re-search-forward (regexp-quote (car code))
|
||||
(point-max) t)
|
||||
(error "Unable to extract all dictionary entries"))
|
||||
|
||||
(srecode-extract-state-extract state (match-beginning 0))
|
||||
(goto-char (match-end 0))
|
||||
)
|
||||
|
||||
;; Some inserters are simple, and need to be extracted after
|
||||
;; we find our next block of static text.
|
||||
((eq (srecode-inserter-do-extract-p (car code)) 'later)
|
||||
(srecode-extract-state-set state (car code) dictionary)
|
||||
)
|
||||
|
||||
;; Some inserter want to start extraction now, such as sections.
|
||||
;; We can't predict the end point till we parse out the middle.
|
||||
((eq (srecode-inserter-do-extract-p (car code)) 'now)
|
||||
(srecode-extract-state-set-anchor state)
|
||||
(srecode-inserter-extract (car code) (point) nil dictionary state))
|
||||
)
|
||||
(setq code (cdr code))
|
||||
))
|
||||
|
||||
;;; Inserter Base Extractors
|
||||
;;
|
||||
(defmethod srecode-inserter-do-extract-p ((ins srecode-template-inserter))
|
||||
"Return non-nil if this inserter can extract values."
|
||||
nil)
|
||||
|
||||
(defmethod srecode-inserter-extract ((ins srecode-template-inserter)
|
||||
start end dict state)
|
||||
"Extract text from START/END and store in DICT.
|
||||
Return nil as this inserter will extract nothing."
|
||||
nil)
|
||||
|
||||
;;; Variable extractor is simple and can extract later.
|
||||
;;
|
||||
(defmethod srecode-inserter-do-extract-p ((ins srecode-template-inserter-variable))
|
||||
"Return non-nil if this inserter can extract values."
|
||||
'later)
|
||||
|
||||
(defmethod srecode-inserter-extract ((ins srecode-template-inserter-variable)
|
||||
start end vdict state)
|
||||
"Extract text from START/END and store in VDICT.
|
||||
Return t if something was extracted.
|
||||
Return nil if this inserter doesn't need to extract anything."
|
||||
(srecode-dictionary-set-value vdict
|
||||
(oref ins :object-name)
|
||||
(buffer-substring-no-properties
|
||||
start end)
|
||||
)
|
||||
t)
|
||||
|
||||
;;; Section Inserter
|
||||
;;
|
||||
(defmethod srecode-inserter-do-extract-p ((ins srecode-template-inserter-section-start))
|
||||
"Return non-nil if this inserter can extract values."
|
||||
'now)
|
||||
|
||||
(defmethod srecode-inserter-extract ((ins srecode-template-inserter-section-start)
|
||||
start end indict state)
|
||||
"Extract text from START/END and store in INDICT.
|
||||
Return the starting location of the first plain-text match.
|
||||
Return nil if nothing was extracted."
|
||||
(let ((name (oref ins :object-name))
|
||||
(subdict (srecode-create-dictionary indict))
|
||||
(allsubdict nil)
|
||||
)
|
||||
|
||||
;; Keep extracting till we can extract no more.
|
||||
(while (condition-case nil
|
||||
(progn
|
||||
(srecode-extract-method
|
||||
(oref ins template) subdict state)
|
||||
t)
|
||||
(error nil))
|
||||
|
||||
;; Success means keep this subdict, and also make a new one for
|
||||
;; the next iteration.
|
||||
(setq allsubdict (cons subdict allsubdict))
|
||||
(setq subdict (srecode-create-dictionary indict))
|
||||
)
|
||||
|
||||
(srecode-dictionary-set-value indict name (nreverse allsubdict))
|
||||
|
||||
nil))
|
||||
|
||||
;;; Include Extractor must extract now.
|
||||
;;
|
||||
(defmethod srecode-inserter-do-extract-p ((ins srecode-template-inserter-include))
|
||||
"Return non-nil if this inserter can extract values."
|
||||
'now)
|
||||
|
||||
(defmethod srecode-inserter-extract ((ins srecode-template-inserter-include)
|
||||
start end dict state)
|
||||
"Extract text from START/END and store in DICT.
|
||||
Return the starting location of the first plain-text match.
|
||||
Return nil if nothing was extracted."
|
||||
(goto-char start)
|
||||
(srecode-insert-include-lookup ins dict)
|
||||
;; There are two modes for includes. One is with no dict,
|
||||
;; so it is inserted straight. If the dict has a name, then
|
||||
;; we need to run once per dictionary occurance.
|
||||
(if (not (string= (oref ins :object-name) ""))
|
||||
;; With a name, do the insertion.
|
||||
(let ((subdict (srecode-dictionary-add-section-dictionary
|
||||
dict (oref ins :object-name))))
|
||||
(error "Need to implement include w/ name extractor.")
|
||||
;; Recurse into the new template while no errors.
|
||||
(while (condition-case nil
|
||||
(progn
|
||||
(srecode-extract-method
|
||||
(oref ins includedtemplate) subdict
|
||||
state)
|
||||
t)
|
||||
(error nil))))
|
||||
|
||||
;; No stream, do the extraction into the current dictionary.
|
||||
(srecode-extract-method (oref ins includedtemplate) dict
|
||||
state))
|
||||
)
|
||||
|
||||
|
||||
(provide 'srecode/extract)
|
||||
|
||||
;;; srecode/extract.el ends here
|
438
lisp/cedet/srecode/fields.el
Normal file
438
lisp/cedet/srecode/fields.el
Normal file
|
@ -0,0 +1,438 @@
|
|||
;;; srecode/fields.el --- Handling type-in fields in a buffer.
|
||||
;;
|
||||
;; Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
;;
|
||||
;; Author: Eric M. Ludlam <eric@siege-engine.com>
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; Idea courtesy of yasnippets.
|
||||
;;
|
||||
;; If someone prefers not to type unknown dictionary entries into
|
||||
;; mini-buffer prompts, it could instead use in-buffer fields.
|
||||
;;
|
||||
;; A template-region specifies an area in which the fields exist. If
|
||||
;; the cursor exits the region, all fields are cleared.
|
||||
;;
|
||||
;; Each field is independent, but some are linked together by name.
|
||||
;; Typing in one will cause the matching ones to change in step.
|
||||
;;
|
||||
;; Each field has 2 overlays. The second overlay allows control in
|
||||
;; the character just after the field, but does not highlight it.
|
||||
|
||||
;; Keep this library independent of SRecode proper.
|
||||
(require 'eieio)
|
||||
|
||||
;;; Code:
|
||||
(defvar srecode-field-archive nil
|
||||
"While inserting a set of fields, collect in this variable.
|
||||
Once an insertion set is done, these fields will be activated.")
|
||||
|
||||
(defface srecode-field-face
|
||||
'((((class color) (background dark))
|
||||
(:underline "green"))
|
||||
(((class color) (background light))
|
||||
(:underline "green4")))
|
||||
"*Face used to specify editable fields from a template."
|
||||
:group 'semantic-faces)
|
||||
|
||||
;;; BASECLASS
|
||||
;;
|
||||
;; Fields and the template region share some basic overlay features.
|
||||
|
||||
(defclass srecode-overlaid ()
|
||||
((overlay :documentation
|
||||
"Overlay representing this field.
|
||||
The overlay will crossreference this object.")
|
||||
)
|
||||
"An object that gets automatically bound to an overlay.
|
||||
Has virtual :start and :end initializers.")
|
||||
|
||||
(defmethod initialize-instance ((olaid srecode-overlaid) &optional args)
|
||||
"Initialize OLAID, being sure it archived."
|
||||
;; Extract :start and :end from the olaid list.
|
||||
(let ((newargs nil)
|
||||
(olay nil)
|
||||
start end
|
||||
)
|
||||
|
||||
(while args
|
||||
(cond ((eq (car args) :start)
|
||||
(setq args (cdr args))
|
||||
(setq start (car args))
|
||||
(setq args (cdr args))
|
||||
)
|
||||
((eq (car args) :end)
|
||||
(setq args (cdr args))
|
||||
(setq end (car args))
|
||||
(setq args (cdr args))
|
||||
)
|
||||
(t
|
||||
(push (car args) newargs)
|
||||
(setq args (cdr args))
|
||||
(push (car args) newargs)
|
||||
(setq args (cdr args)))
|
||||
))
|
||||
|
||||
;; Create a temporary overlay now. We have to use an overlay and
|
||||
;; not a marker becaues of the in-front insertion rules. The rules
|
||||
;; are backward from what is wanted while typing.
|
||||
(setq olay (make-overlay start end (current-buffer) t nil))
|
||||
(overlay-put olay 'srecode-init-only t)
|
||||
|
||||
(oset olaid overlay olay)
|
||||
(call-next-method olaid (nreverse newargs))
|
||||
|
||||
))
|
||||
|
||||
(defmethod srecode-overlaid-activate ((olaid srecode-overlaid))
|
||||
"Activate the overlaid area."
|
||||
(let* ((ola (oref olaid overlay))
|
||||
(start (overlay-start ola))
|
||||
(end (overlay-end ola))
|
||||
;; Create a new overlay here.
|
||||
(ol (make-overlay start end (current-buffer) nil t)))
|
||||
|
||||
;; Remove the old one.
|
||||
(delete-overlay ola)
|
||||
|
||||
(overlay-put ol 'srecode olaid)
|
||||
|
||||
(oset olaid overlay ol)
|
||||
|
||||
))
|
||||
|
||||
(defmethod srecode-delete ((olaid srecode-overlaid))
|
||||
"Delete the overlay from OLAID."
|
||||
(delete-overlay (oref olaid overlay))
|
||||
(slot-makeunbound olaid 'overlay)
|
||||
)
|
||||
|
||||
(defmethod srecode-empty-region-p ((olaid srecode-overlaid))
|
||||
"Return non-nil if the region covered by OLAID is of length 0."
|
||||
(= 0 (srecode-region-size olaid)))
|
||||
|
||||
(defmethod srecode-region-size ((olaid srecode-overlaid))
|
||||
"Return the length of region covered by OLAID."
|
||||
(let ((start (overlay-start (oref olaid overlay)))
|
||||
(end (overlay-end (oref olaid overlay))))
|
||||
(- end start)))
|
||||
|
||||
(defmethod srecode-point-in-region-p ((olaid srecode-overlaid))
|
||||
"Return non-nil if point is in the region of OLAID."
|
||||
(let ((start (overlay-start (oref olaid overlay)))
|
||||
(end (overlay-end (oref olaid overlay))))
|
||||
(and (>= (point) start) (<= (point) end))))
|
||||
|
||||
(defun srecode-overlaid-at-point (class)
|
||||
"Return a list of overlaid fields of type CLASS at point."
|
||||
(let ((ol (overlays-at (point)))
|
||||
(ret nil))
|
||||
(while ol
|
||||
(let ((tmp (overlay-get (car ol) 'srecode)))
|
||||
(when (and tmp (object-of-class-p tmp class))
|
||||
(setq ret (cons tmp ret))))
|
||||
(setq ol (cdr ol)))
|
||||
(car (nreverse ret))))
|
||||
|
||||
(defmethod srecode-overlaid-text ((olaid srecode-overlaid) &optional set-to)
|
||||
"Return the text under OLAID.
|
||||
If SET-TO is a string, then replace the text of OLAID wit SET-TO."
|
||||
(let* ((ol (oref olaid overlay))
|
||||
(start (overlay-start ol)))
|
||||
(if (not (stringp set-to))
|
||||
;; Just return it.
|
||||
(buffer-substring-no-properties start (overlay-end ol))
|
||||
;; Replace it.
|
||||
(save-excursion
|
||||
(delete-region start (overlay-end ol))
|
||||
(goto-char start)
|
||||
(insert set-to)
|
||||
(move-overlay ol start (+ start (length set-to))))
|
||||
nil)))
|
||||
|
||||
;;; INSERTED REGION
|
||||
;;
|
||||
;; Managing point-exit, and flushing fields.
|
||||
|
||||
(defclass srecode-template-inserted-region (srecode-overlaid)
|
||||
((fields :documentation
|
||||
"A list of field overlays in this region.")
|
||||
(active-region :allocation :class
|
||||
:initform nil
|
||||
:documentation
|
||||
"The template region currently being handled.")
|
||||
)
|
||||
"Manage a buffer region in which fields exist.")
|
||||
|
||||
(defmethod initialize-instance ((ir srecode-template-inserted-region)
|
||||
&rest args)
|
||||
"Initialize IR, capturing the active fields, and creating the overlay."
|
||||
;; Fill in the fields
|
||||
(oset ir fields srecode-field-archive)
|
||||
(setq srecode-field-archive nil)
|
||||
|
||||
;; Initailize myself first.
|
||||
(call-next-method)
|
||||
)
|
||||
|
||||
(defmethod srecode-overlaid-activate ((ir srecode-template-inserted-region))
|
||||
"Activate the template area for IR."
|
||||
;; Activate all our fields
|
||||
|
||||
(dolist (F (oref ir fields))
|
||||
(srecode-overlaid-activate F))
|
||||
|
||||
;; Activate our overlay.
|
||||
(call-next-method)
|
||||
|
||||
;; Position the cursor at the first field
|
||||
(let ((first (car (oref ir fields))))
|
||||
(goto-char (overlay-start (oref first overlay))))
|
||||
|
||||
;; Set ourselves up as 'active'
|
||||
(oset ir active-region ir)
|
||||
|
||||
;; Setup the post command hook.
|
||||
(add-hook 'post-command-hook 'srecode-field-post-command t t)
|
||||
)
|
||||
|
||||
(defmethod srecode-delete ((ir srecode-template-inserted-region))
|
||||
"Call into our base, but also clear out the fields."
|
||||
;; Clear us out of the baseclass.
|
||||
(oset ir active-region nil)
|
||||
;; Clear our fields.
|
||||
(mapc 'srecode-delete (oref ir fields))
|
||||
;; Call to our base
|
||||
(call-next-method)
|
||||
;; Clear our hook.
|
||||
(remove-hook 'post-command-hook 'srecode-field-post-command t)
|
||||
)
|
||||
|
||||
(defsubst srecode-active-template-region ()
|
||||
"Return the active region for template fields."
|
||||
(oref srecode-template-inserted-region active-region))
|
||||
|
||||
(defun srecode-field-post-command ()
|
||||
"Srecode field handler in the post command hook."
|
||||
(let ((ar (srecode-active-template-region))
|
||||
)
|
||||
(if (not ar)
|
||||
;; Find a bug and fix it.
|
||||
(remove-hook 'post-command-hook 'srecode-field-post-command t)
|
||||
(if (srecode-point-in-region-p ar)
|
||||
nil ;; Keep going
|
||||
;; We moved out of the temlate. Cancel the edits.
|
||||
(srecode-delete ar)))
|
||||
))
|
||||
|
||||
;;; FIELDS
|
||||
|
||||
(defclass srecode-field (srecode-overlaid)
|
||||
((tail :documentation
|
||||
"Overlay used on character just after this field.
|
||||
Used to provide useful keybindings there.")
|
||||
(name :initarg :name
|
||||
:documentation
|
||||
"The name of this field.
|
||||
Usually initialized from the dictionary entry name that
|
||||
the users needs to edit.")
|
||||
(prompt :initarg :prompt
|
||||
:documentation
|
||||
"A prompt string to use if this were in the minibuffer.
|
||||
Display when the cursor enters this field.")
|
||||
(read-fcn :initarg :read-fcn
|
||||
:documentation
|
||||
"A function that would be used to read a string.
|
||||
Try to use this to provide useful completion when available.")
|
||||
)
|
||||
"Representation of one field.")
|
||||
|
||||
(defvar srecode-field-keymap
|
||||
(let ((km (make-sparse-keymap)))
|
||||
(define-key km "\C-i" 'srecode-field-next)
|
||||
(define-key km "\M-\C-i" 'srecode-field-prev)
|
||||
(define-key km "\C-e" 'srecode-field-end)
|
||||
(define-key km "\C-a" 'srecode-field-start)
|
||||
(define-key km "\M-m" 'srecode-field-start)
|
||||
(define-key km "\C-c\C-c" 'srecode-field-exit-ask)
|
||||
km)
|
||||
"Keymap applied to field overlays.")
|
||||
|
||||
(defmethod initialize-instance ((field srecode-field) &optional args)
|
||||
"Initialize FIELD, being sure it archived."
|
||||
(add-to-list 'srecode-field-archive field t)
|
||||
(call-next-method)
|
||||
)
|
||||
|
||||
(defmethod srecode-overlaid-activate ((field srecode-field))
|
||||
"Activate the FIELD area."
|
||||
(call-next-method)
|
||||
|
||||
(let* ((ol (oref field overlay))
|
||||
(end nil)
|
||||
(tail nil))
|
||||
(overlay-put ol 'face 'srecode-field-face)
|
||||
(overlay-put ol 'keymap srecode-field-keymap)
|
||||
(overlay-put ol 'modification-hooks '(srecode-field-mod-hook))
|
||||
(overlay-put ol 'insert-behind-hooks '(srecode-field-behind-hook))
|
||||
(overlay-put ol 'insert-in-front-hooks '(srecode-field-mod-hook))
|
||||
|
||||
(setq end (overlay-end ol))
|
||||
(setq tail (make-overlay end (+ end 1) (current-buffer)))
|
||||
|
||||
(overlay-put tail 'srecode field)
|
||||
(overlay-put tail 'keymap srecode-field-keymap)
|
||||
(overlay-put tail 'face 'srecode-field-face)
|
||||
(oset field tail tail)
|
||||
)
|
||||
)
|
||||
|
||||
(defmethod srecode-delete ((olaid srecode-field))
|
||||
"Delete our secondary overlay."
|
||||
;; Remove our spare overlay
|
||||
(delete-overlay (oref olaid tail))
|
||||
(slot-makeunbound olaid 'tail)
|
||||
;; Do our baseclass work.
|
||||
(call-next-method)
|
||||
)
|
||||
|
||||
(defvar srecode-field-replication-max-size 100
|
||||
"Maximum size of a field before cancelling replication.")
|
||||
|
||||
(defun srecode-field-mod-hook (ol after start end &optional pre-len)
|
||||
"Modification hook for the field overlay.
|
||||
OL is the overlay.
|
||||
AFTER is non-nil if it is called after the change.
|
||||
START and END are the bounds of the change.
|
||||
PRE-LEN is used in the after mode for the length of the changed text."
|
||||
(when (and after (not undo-in-progress))
|
||||
(let* ((field (overlay-get ol 'srecode))
|
||||
(inhibit-point-motion-hooks t)
|
||||
(inhibit-modification-hooks t)
|
||||
)
|
||||
;; Sometimes a field is deleted, but we might still get a stray
|
||||
;; event. Lets just ignore those events.
|
||||
(when (slot-boundp field 'overlay)
|
||||
;; First, fixup the two overlays, in case they got confused.
|
||||
(let ((main (oref field overlay))
|
||||
(tail (oref field tail)))
|
||||
(move-overlay main
|
||||
(overlay-start main)
|
||||
(1- (overlay-end tail)))
|
||||
(move-overlay tail
|
||||
(1- (overlay-end tail))
|
||||
(overlay-end tail)))
|
||||
;; Now capture text from the main overlay, and propagate it.
|
||||
(let* ((new-text (srecode-overlaid-text field))
|
||||
(region (srecode-active-template-region))
|
||||
(allfields (when region (oref region fields)))
|
||||
(name (oref field name)))
|
||||
(dolist (F allfields)
|
||||
(when (and (not (eq F field))
|
||||
(string= name (oref F name)))
|
||||
(if (> (length new-text) srecode-field-replication-max-size)
|
||||
(message "Field size too large for replication.")
|
||||
;; If we find other fields with the same name, then keep
|
||||
;; then all together. Disable change hooks to make sure
|
||||
;; we don't get a recursive edit.
|
||||
(srecode-overlaid-text F new-text)
|
||||
))))
|
||||
))))
|
||||
|
||||
(defun srecode-field-behind-hook (ol after start end &optional pre-len)
|
||||
"Modification hook for the field overlay.
|
||||
OL is the overlay.
|
||||
AFTER is non-nil if it is called after the change.
|
||||
START and END are the bounds of the change.
|
||||
PRE-LEN is used in the after mode for the length of the changed text."
|
||||
(when after
|
||||
(let* ((field (overlay-get ol 'srecode))
|
||||
)
|
||||
(move-overlay ol (overlay-start ol) end)
|
||||
(srecode-field-mod-hook ol after start end pre-len))
|
||||
))
|
||||
|
||||
(defmethod srecode-field-goto ((field srecode-field))
|
||||
"Goto the FIELD."
|
||||
(goto-char (overlay-start (oref field overlay))))
|
||||
|
||||
(defun srecode-field-next ()
|
||||
"Move to the next field."
|
||||
(interactive)
|
||||
(let* ((f (srecode-overlaid-at-point 'srecode-field))
|
||||
(tr (srecode-overlaid-at-point 'srecode-template-inserted-region))
|
||||
)
|
||||
(when (not f) (error "Not in a field"))
|
||||
(when (not tr) (error "Not in a template region"))
|
||||
|
||||
(let ((fields (oref tr fields)))
|
||||
(while fields
|
||||
;; Loop over fields till we match. Then move to the next one.
|
||||
(when (eq f (car fields))
|
||||
(if (cdr fields)
|
||||
(srecode-field-goto (car (cdr fields)))
|
||||
(srecode-field-goto (car (oref tr fields))))
|
||||
(setq fields nil)
|
||||
)
|
||||
(setq fields (cdr fields))))
|
||||
))
|
||||
|
||||
(defun srecode-field-prev ()
|
||||
"Move to the prev field."
|
||||
(interactive)
|
||||
(let* ((f (srecode-overlaid-at-point 'srecode-field))
|
||||
(tr (srecode-overlaid-at-point 'srecode-template-inserted-region))
|
||||
)
|
||||
(when (not f) (error "Not in a field"))
|
||||
(when (not tr) (error "Not in a template region"))
|
||||
|
||||
(let ((fields (reverse (oref tr fields))))
|
||||
(while fields
|
||||
;; Loop over fields till we match. Then move to the next one.
|
||||
(when (eq f (car fields))
|
||||
(if (cdr fields)
|
||||
(srecode-field-goto (car (cdr fields)))
|
||||
(srecode-field-goto (car (oref tr fields))))
|
||||
(setq fields nil)
|
||||
)
|
||||
(setq fields (cdr fields))))
|
||||
))
|
||||
|
||||
(defun srecode-field-end ()
|
||||
"Move to the end of this field."
|
||||
(interactive)
|
||||
(let* ((f (srecode-overlaid-at-point 'srecode-field)))
|
||||
(goto-char (overlay-end (oref f overlay)))))
|
||||
|
||||
(defun srecode-field-start ()
|
||||
"Move to the end of this field."
|
||||
(interactive)
|
||||
(let* ((f (srecode-overlaid-at-point 'srecode-field)))
|
||||
(goto-char (overlay-start (oref f overlay)))))
|
||||
|
||||
(defun srecode-field-exit-ask ()
|
||||
"Ask if the user wants to exit field-editing mini-mode."
|
||||
(interactive)
|
||||
(when (y-or-n-p "Exit field-editing mode? ")
|
||||
(srecode-delete (srecode-active-template-region))))
|
||||
|
||||
|
||||
(provide 'srecode/fields)
|
||||
|
||||
;;; srecode/fields.el ends here
|
56
lisp/cedet/srecode/filters.el
Normal file
56
lisp/cedet/srecode/filters.el
Normal file
|
@ -0,0 +1,56 @@
|
|||
;;; srecode/filters.el --- Filters for use in template variables.
|
||||
|
||||
;; Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Eric M. Ludlam <eric@siege-engine.com>
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; Various useful srecoder template functions.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'newcomment)
|
||||
(require 'srecode/table)
|
||||
(require 'srecode/insert)
|
||||
|
||||
(defun srecode-comment-prefix (str)
|
||||
"Prefix each line of STR with the comment prefix characters."
|
||||
(let* ((dict srecode-inserter-variable-current-dictionary)
|
||||
;; Derive the comment characters to put in front of each line.
|
||||
(cs (or (and dict
|
||||
(srecode-dictionary-lookup-name dict "comment_prefix"))
|
||||
(and comment-multi-line comment-continue)
|
||||
(and (not comment-multi-line) comment-start)))
|
||||
(strs (split-string str "\n"))
|
||||
(newstr "")
|
||||
)
|
||||
(while strs
|
||||
(cond ((and (not comment-multi-line) (string= (car strs) ""))
|
||||
; (setq newstr (concat newstr "\n")))
|
||||
)
|
||||
(t
|
||||
(setq newstr (concat newstr cs " " (car strs)))))
|
||||
(setq strs (cdr strs))
|
||||
(when strs (setq newstr (concat newstr "\n"))))
|
||||
newstr))
|
||||
|
||||
(provide 'srecode/filters)
|
||||
|
||||
;;; srecode/filters.el ends here
|
||||
|
261
lisp/cedet/srecode/find.el
Normal file
261
lisp/cedet/srecode/find.el
Normal file
|
@ -0,0 +1,261 @@
|
|||
;;;; srecode/find.el --- Tools for finding templates in the database.
|
||||
|
||||
;; Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Eric M. Ludlam <eric@siege-engine.com>
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; Various routines that search through various template tables
|
||||
;; in search of the right template.
|
||||
|
||||
(require 'srecode/ctxt)
|
||||
(require 'srecode/table)
|
||||
(require 'srecode/map)
|
||||
|
||||
(declare-function srecode-compile-file "srecode/compile")
|
||||
|
||||
;;; Code:
|
||||
|
||||
(defun srecode-table (&optional mode)
|
||||
"Return the currently active Semantic Recoder table for this buffer.
|
||||
Optional argument MODE specifies the mode table to use."
|
||||
(let* ((modeq (or mode major-mode))
|
||||
(table (srecode-get-mode-table modeq)))
|
||||
|
||||
;; If there isn't one, keep searching backwards for a table.
|
||||
(while (and (not table) (setq modeq (get-mode-local-parent modeq)))
|
||||
(setq table (srecode-get-mode-table modeq)))
|
||||
|
||||
;; Last ditch effort.
|
||||
(when (not table)
|
||||
(setq table (srecode-get-mode-table 'default)))
|
||||
|
||||
table))
|
||||
|
||||
;;; TRACKER
|
||||
;;
|
||||
;; Template file tracker for between sessions.
|
||||
;;
|
||||
(defun srecode-load-tables-for-mode (mmode &optional appname)
|
||||
"Load all the template files for MMODE.
|
||||
Templates are found in the SRecode Template Map.
|
||||
See `srecode-get-maps' for more.
|
||||
APPNAME is the name of an application. In this case,
|
||||
all template files for that application will be loaded."
|
||||
(require 'srecode/compile)
|
||||
(let ((files
|
||||
(if appname
|
||||
(apply 'append
|
||||
(mapcar
|
||||
(lambda (map)
|
||||
(srecode-map-entries-for-app-and-mode map appname mmode))
|
||||
(srecode-get-maps)))
|
||||
(apply 'append
|
||||
(mapcar
|
||||
(lambda (map)
|
||||
(srecode-map-entries-for-mode map mmode))
|
||||
(srecode-get-maps)))))
|
||||
)
|
||||
;; Don't recurse if we are already the 'default state.
|
||||
(when (not (eq mmode 'default))
|
||||
;; Are we a derived mode? If so, get the parent mode's
|
||||
;; templates loaded too.
|
||||
(if (get-mode-local-parent mmode)
|
||||
(srecode-load-tables-for-mode (get-mode-local-parent mmode)
|
||||
appname)
|
||||
;; No parent mode, all templates depend on the defaults being
|
||||
;; loaded in, so get that in instead.
|
||||
(srecode-load-tables-for-mode 'default appname)))
|
||||
|
||||
;; Load in templates for our major mode.
|
||||
(dolist (f files)
|
||||
(let ((mt (srecode-get-mode-table mmode))
|
||||
)
|
||||
(when (or (not mt) (not (srecode-mode-table-find mt (car f))))
|
||||
(srecode-compile-file (car f)))
|
||||
))
|
||||
))
|
||||
|
||||
;;; SEARCH
|
||||
;;
|
||||
;; Find a given template based on name, and features of the current
|
||||
;; buffer.
|
||||
(defmethod srecode-template-get-table ((tab srecode-template-table)
|
||||
template-name &optional
|
||||
context application)
|
||||
"Find in the template in table TAB, the template with TEMPLATE-NAME.
|
||||
Optional argument CONTEXT specifies that the template should part
|
||||
of a particular context.
|
||||
The APPLICATION argument is unused."
|
||||
(if context
|
||||
;; If a context is specified, then look it up there.
|
||||
(let ((ctxth (gethash context (oref tab contexthash))))
|
||||
(when ctxth
|
||||
(gethash template-name ctxth)))
|
||||
;; No context, perhaps a merged name?
|
||||
(gethash template-name (oref tab namehash))))
|
||||
|
||||
(defmethod srecode-template-get-table ((tab srecode-mode-table)
|
||||
template-name &optional
|
||||
context application)
|
||||
"Find in the template in mode table TAB, the template with TEMPLATE-NAME.
|
||||
Optional argument CONTEXT specifies a context a particular template
|
||||
would belong to.
|
||||
Optional argument APPLICATION restricts searches to only template tables
|
||||
belonging to a specific application. If APPLICATION is nil, then only
|
||||
tables that do not belong to an application will be searched."
|
||||
(let* ((mt tab)
|
||||
(tabs (oref mt :tables))
|
||||
(ans nil))
|
||||
(while (and (not ans) tabs)
|
||||
(let ((app (oref (car tabs) :application)))
|
||||
(when (or (and (not application) (null app))
|
||||
(and application (eq app application)))
|
||||
(setq ans (srecode-template-get-table (car tabs) template-name
|
||||
context)))
|
||||
(setq tabs (cdr tabs))))
|
||||
(or ans
|
||||
;; Recurse to the default.
|
||||
(when (not (equal (oref tab :major-mode) 'default))
|
||||
(srecode-template-get-table (srecode-get-mode-table 'default)
|
||||
template-name context application)))))
|
||||
|
||||
;;
|
||||
;; Find a given template based on a key binding.
|
||||
;;
|
||||
(defmethod srecode-template-get-table-for-binding
|
||||
((tab srecode-template-table) binding &optional context)
|
||||
"Find in the template name in table TAB, the template with BINDING.
|
||||
Optional argument CONTEXT specifies that the template should part
|
||||
of a particular context."
|
||||
(let* ((keyout nil)
|
||||
(hashfcn (lambda (key value)
|
||||
(when (and (slot-boundp value 'binding)
|
||||
(oref value binding)
|
||||
(= (aref (oref value binding) 0) binding))
|
||||
(setq keyout key))))
|
||||
(contextstr (cond ((listp context)
|
||||
(car-safe context))
|
||||
((stringp context)
|
||||
context)
|
||||
(t nil)))
|
||||
)
|
||||
(if context
|
||||
(let ((ctxth (gethash contextstr (oref tab contexthash))))
|
||||
(when ctxth
|
||||
;; If a context is specified, then look it up there.
|
||||
(maphash hashfcn ctxth)
|
||||
;; Context hashes EXCLUDE the context prefix which
|
||||
;; we need to include, so concat it here
|
||||
(when keyout
|
||||
(setq keyout (concat contextstr ":" keyout)))
|
||||
)))
|
||||
(when (not keyout)
|
||||
;; No context, or binding in context. Try full hash.
|
||||
(maphash hashfcn (oref tab namehash)))
|
||||
keyout))
|
||||
|
||||
(defmethod srecode-template-get-table-for-binding
|
||||
((tab srecode-mode-table) binding &optional context application)
|
||||
"Find in the template name in mode table TAB, the template with BINDING.
|
||||
Optional argument CONTEXT specifies a context a particular template
|
||||
would belong to.
|
||||
Optional argument APPLICATION restricts searches to only template tables
|
||||
belonging to a specific application. If APPLICATION is nil, then only
|
||||
tables that do not belong to an application will be searched."
|
||||
(let* ((mt tab)
|
||||
(tabs (oref mt :tables))
|
||||
(ans nil))
|
||||
(while (and (not ans) tabs)
|
||||
(let ((app (oref (car tabs) :application)))
|
||||
(when (or (and (not application) (null app))
|
||||
(and application (eq app application)))
|
||||
(setq ans (srecode-template-get-table-for-binding
|
||||
(car tabs) binding context)))
|
||||
(setq tabs (cdr tabs))))
|
||||
(or ans
|
||||
;; Recurse to the default.
|
||||
(when (not (equal (oref tab :major-mode) 'default))
|
||||
(srecode-template-get-table-for-binding
|
||||
(srecode-get-mode-table 'default) binding context)))))
|
||||
;;; Interactive
|
||||
;;
|
||||
;; Interactive queries into the template data.
|
||||
;;
|
||||
(defvar srecode-read-template-name-history nil
|
||||
"History for completing reads for template names.")
|
||||
|
||||
(defun srecode-all-template-hash (&optional mode hash)
|
||||
"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))
|
||||
)
|
||||
;; 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)))
|
||||
;; Load up the hash table for our current mode.
|
||||
(let* ((mt (srecode-get-mode-table mmode))
|
||||
(tabs (when mt (oref mt :tables)))
|
||||
)
|
||||
(while tabs
|
||||
;; Exclude templates for a perticular application.
|
||||
(when (not (oref (car tabs) :application))
|
||||
(maphash (lambda (key temp)
|
||||
(puthash key temp mhash)
|
||||
)
|
||||
(oref (car tabs) namehash)))
|
||||
(setq tabs (cdr tabs)))
|
||||
mhash)))
|
||||
|
||||
(defun srecode-calculate-default-template-string (hash)
|
||||
"Calculate the name of the template to use as a DEFAULT.
|
||||
Templates are read from HASH.
|
||||
Context into which the template is inserted is calculated
|
||||
with `srecode-calculate-context'."
|
||||
(let* ((ctxt (srecode-calculate-context))
|
||||
(ans (concat (nth 0 ctxt) ":" (nth 1 ctxt))))
|
||||
(if (gethash ans hash)
|
||||
ans
|
||||
;; No hash at the specifics, at least offer
|
||||
;; the prefix for the completing read
|
||||
(concat (nth 0 ctxt) ":"))))
|
||||
|
||||
(defun srecode-read-template-name (prompt &optional initial hist default)
|
||||
"Completing read for Semantic Recoder template names.
|
||||
PROMPT is used to query for the name of the template desired.
|
||||
INITIAL is the initial string to use.
|
||||
HIST is a history variable to use.
|
||||
DEFAULT is what to use if the user presses RET."
|
||||
(srecode-load-tables-for-mode major-mode)
|
||||
(let* ((hash (srecode-all-template-hash))
|
||||
(def (or initial
|
||||
(srecode-calculate-default-template-string hash))))
|
||||
(completing-read prompt hash
|
||||
nil t def
|
||||
(or hist
|
||||
'srecode-read-template-name-history))))
|
||||
|
||||
(provide 'srecode/find)
|
||||
|
||||
;;; srecode/find.el ends here
|
366
lisp/cedet/srecode/getset.el
Normal file
366
lisp/cedet/srecode/getset.el
Normal file
|
@ -0,0 +1,366 @@
|
|||
;;; srecode/getset.el --- Package for inserting new get/set methods.
|
||||
|
||||
;; Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Eric M. Ludlam <eric@siege-engine.com>
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; SRecoder application for inserting new get/set methods into a class.
|
||||
|
||||
(require 'semantic)
|
||||
(require 'semantic/analyze)
|
||||
(require 'semantic/find)
|
||||
(require 'srecode/insert)
|
||||
(require 'srecode/dictionary)
|
||||
|
||||
;;; Code:
|
||||
(defvar srecode-insert-getset-fully-automatic-flag nil
|
||||
"Non-nil means accept choices srecode comes up with without asking.")
|
||||
|
||||
;;;###autoload
|
||||
(defun srecode-insert-getset (&optional class-in field-in)
|
||||
"Insert get/set methods for the current class.
|
||||
CLASS-IN is the semantic tag of the class to update.
|
||||
FIELD-IN is the semantic tag, or string name, of the field to add.
|
||||
If you do not specify CLASS-IN or FIELD-IN then a class and field
|
||||
will be derived."
|
||||
(interactive)
|
||||
|
||||
(srecode-load-tables-for-mode major-mode)
|
||||
(srecode-load-tables-for-mode major-mode 'getset)
|
||||
|
||||
(if (not (srecode-table))
|
||||
(error "No template table found for mode %s" major-mode))
|
||||
|
||||
(if (not (srecode-template-get-table (srecode-table)
|
||||
"getset-in-class"
|
||||
"declaration"
|
||||
'getset))
|
||||
(error "No templates for inserting get/set"))
|
||||
|
||||
;; Step 1: Try to derive the tag for the class we will use
|
||||
(let* ((class (or class-in (srecode-auto-choose-class (point))))
|
||||
(tagstart (semantic-tag-start class))
|
||||
(inclass (eq (semantic-current-tag-of-class 'type) class))
|
||||
(field nil)
|
||||
)
|
||||
|
||||
(when (not class)
|
||||
(error "Move point to a class and try again"))
|
||||
|
||||
;; Step 2: Select a name for the field we will use.
|
||||
(when field-in
|
||||
(setq field field-in))
|
||||
|
||||
(when (and inclass (not field))
|
||||
(setq field (srecode-auto-choose-field (point))))
|
||||
|
||||
(when (not field)
|
||||
(setq field (srecode-query-for-field class)))
|
||||
|
||||
;; Step 3: Insert a new field if needed
|
||||
(when (stringp field)
|
||||
|
||||
(goto-char (point))
|
||||
(srecode-position-new-field class inclass)
|
||||
|
||||
(let* ((dict (srecode-create-dictionary))
|
||||
(temp (srecode-template-get-table (srecode-table)
|
||||
"getset-field"
|
||||
"declaration"
|
||||
'getset))
|
||||
)
|
||||
(when (not temp)
|
||||
(error "Getset templates for %s not loaded!" major-mode))
|
||||
(srecode-resolve-arguments temp dict)
|
||||
(srecode-dictionary-set-value dict "NAME" field)
|
||||
(when srecode-insert-getset-fully-automatic-flag
|
||||
(srecode-dictionary-set-value dict "TYPE" "int"))
|
||||
(srecode-insert-fcn temp dict)
|
||||
|
||||
(semantic-fetch-tags)
|
||||
(save-excursion
|
||||
(goto-char tagstart)
|
||||
;; Refresh our class tag.
|
||||
(setq class (srecode-auto-choose-class (point)))
|
||||
)
|
||||
|
||||
(let ((tmptag (semantic-deep-find-tags-by-name-regexp
|
||||
field (current-buffer))))
|
||||
(setq tmptag (semantic-find-tags-by-class 'variable tmptag))
|
||||
|
||||
(if tmptag
|
||||
(setq field (car tmptag))
|
||||
(error "Could not find new field %s" field)))
|
||||
)
|
||||
|
||||
;; Step 3.5: Insert an initializer if needed.
|
||||
;; ...
|
||||
|
||||
|
||||
;; Set up for the rest.
|
||||
)
|
||||
|
||||
(if (not (semantic-tag-p field))
|
||||
(error "Must specify field for get/set. (parts may not be impl'd yet.)"))
|
||||
|
||||
;; Set 4: Position for insertion of methods
|
||||
(srecode-position-new-methods class field)
|
||||
|
||||
;; Step 5: Insert the get/set methods
|
||||
(if (not (eq (semantic-current-tag) class))
|
||||
;; We are positioned on top of something else.
|
||||
;; insert a /n
|
||||
(insert "\n"))
|
||||
|
||||
(let* ((dict (srecode-create-dictionary))
|
||||
(srecode-semantic-selected-tag field)
|
||||
(temp (srecode-template-get-table (srecode-table)
|
||||
"getset-in-class"
|
||||
"declaration"
|
||||
'getset))
|
||||
)
|
||||
(if (not temp)
|
||||
(error "Getset templates for %s not loaded!" major-mode))
|
||||
(srecode-resolve-arguments temp dict)
|
||||
(srecode-dictionary-set-value dict "GROUPNAME"
|
||||
(concat (semantic-tag-name field)
|
||||
" Accessors"))
|
||||
(srecode-dictionary-set-value dict "NICENAME"
|
||||
(srecode-strip-fieldname
|
||||
(semantic-tag-name field)))
|
||||
(srecode-insert-fcn temp dict)
|
||||
)))
|
||||
|
||||
(defun srecode-strip-fieldname (name)
|
||||
"Strip the fieldname NAME of polish notation things."
|
||||
(cond ((string-match "[a-z]\\([A-Z]\\w+\\)" name)
|
||||
(substring name (match-beginning 1)))
|
||||
;; Add more rules here.
|
||||
(t
|
||||
name)))
|
||||
|
||||
(defun srecode-position-new-methods (class field)
|
||||
"Position the cursor in CLASS where new getset methods should go.
|
||||
FIELD is the field for the get sets.
|
||||
INCLASS specifies if the cursor is already in CLASS or not."
|
||||
(semantic-go-to-tag field)
|
||||
|
||||
(let ((prev (semantic-find-tag-by-overlay-prev))
|
||||
(next (semantic-find-tag-by-overlay-next))
|
||||
(setname nil)
|
||||
(aftertag nil)
|
||||
)
|
||||
(cond
|
||||
((and prev (semantic-tag-of-class-p prev 'variable))
|
||||
(setq setname
|
||||
(concat "set"
|
||||
(srecode-strip-fieldname (semantic-tag-name prev))))
|
||||
)
|
||||
((and next (semantic-tag-of-class-p next 'variable))
|
||||
(setq setname
|
||||
(concat "set"
|
||||
(srecode-strip-fieldname (semantic-tag-name prev)))))
|
||||
(t nil))
|
||||
|
||||
(setq aftertag (semantic-find-first-tag-by-name
|
||||
setname (semantic-tag-type-members class)))
|
||||
|
||||
(when (not aftertag)
|
||||
(setq aftertag (car-safe
|
||||
(semantic--find-tags-by-macro
|
||||
(semantic-tag-get-attribute (car tags) :destructor-flag)
|
||||
(semantic-tag-type-members class))))
|
||||
;; Make sure the tag is public
|
||||
(when (not (eq (semantic-tag-protection aftertag class) 'public))
|
||||
(setq aftertag nil))
|
||||
)
|
||||
|
||||
(if (not aftertag)
|
||||
(setq aftertag (car-safe
|
||||
(semantic--find-tags-by-macro
|
||||
(semantic-tag-get-attribute (car tags) :constructor-flag)
|
||||
(semantic-tag-type-members class))))
|
||||
;; Make sure the tag is public
|
||||
(when (not (eq (semantic-tag-protection aftertag class) 'public))
|
||||
(setq aftertag nil))
|
||||
)
|
||||
|
||||
(when (not aftertag)
|
||||
(setq aftertag (semantic-find-first-tag-by-name
|
||||
"public" (semantic-tag-type-members class))))
|
||||
|
||||
(when (not aftertag)
|
||||
(setq aftertag (car (semantic-tag-type-members class))))
|
||||
|
||||
(if aftertag
|
||||
(let ((te (semantic-tag-end aftertag)))
|
||||
(when (not te)
|
||||
(message "Unknown location for tag-end in %s:" (semantic-tag-name aftertag)))
|
||||
(goto-char te)
|
||||
;; If there is a comment immediatly after aftertag, skip over it.
|
||||
(when (looking-at (concat "\\s-*\n?\\s-*" semantic-lex-comment-regex))
|
||||
(let ((pos (point))
|
||||
(rnext (semantic-find-tag-by-overlay-next (point))))
|
||||
(forward-comment 1)
|
||||
;; Make sure the comment we skipped didn't say anything about
|
||||
;; the rnext tag.
|
||||
(when (and rnext
|
||||
(re-search-backward
|
||||
(regexp-quote (semantic-tag-name rnext)) pos t))
|
||||
;; It did mention rnext, so go back to our starting position.
|
||||
(goto-char pos)
|
||||
)
|
||||
))
|
||||
)
|
||||
|
||||
;; At the very beginning of the class.
|
||||
(goto-char (semantic-tag-end class))
|
||||
(forward-sexp -1)
|
||||
(forward-char 1)
|
||||
|
||||
)
|
||||
|
||||
(end-of-line)
|
||||
(forward-char 1)
|
||||
))
|
||||
|
||||
(defun srecode-position-new-field (class inclass)
|
||||
"Select a position for a new field for CLASS.
|
||||
If INCLASS is non-nil, then the cursor is already in the class
|
||||
and should not be moved during point selection."
|
||||
|
||||
;; If we aren't in the class, get the cursor there, pronto!
|
||||
(when (not inclass)
|
||||
|
||||
(error "You must position the cursor where to insert the new field")
|
||||
|
||||
(let ((kids (semantic-find-tags-by-class
|
||||
'variable (semantic-tag-type-members class))))
|
||||
(cond (kids
|
||||
(semantic-go-to-tag (car kids) class))
|
||||
(t
|
||||
(semantic-go-to-tag class)))
|
||||
)
|
||||
|
||||
(switch-to-buffer (current-buffer))
|
||||
|
||||
;; Once the cursor is in our class, ask the user to position
|
||||
;; the cursor to keep going.
|
||||
)
|
||||
|
||||
(if (or srecode-insert-getset-fully-automatic-flag
|
||||
(y-or-n-p "Insert new field here? "))
|
||||
nil
|
||||
(error "You must position the cursor where to insert the new field first"))
|
||||
)
|
||||
|
||||
|
||||
|
||||
(defun srecode-auto-choose-field (point)
|
||||
"Choose a field for the get/set methods.
|
||||
Base selection on the field related to POINT."
|
||||
(save-excursion
|
||||
(when point
|
||||
(goto-char point))
|
||||
|
||||
(let ((field (semantic-current-tag-of-class 'variable)))
|
||||
|
||||
;; If we get a field, make sure the user gets a chance to choose.
|
||||
(when field
|
||||
(if srecode-insert-getset-fully-automatic-flag
|
||||
nil
|
||||
(when (not (y-or-n-p
|
||||
(format "Use field %s? " (semantic-tag-name field))))
|
||||
(setq field nil))
|
||||
))
|
||||
field)))
|
||||
|
||||
(defun srecode-query-for-field (class)
|
||||
"Query for a field in CLASS."
|
||||
(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)
|
||||
))
|
||||
|
||||
(defun srecode-auto-choose-class (point)
|
||||
"Choose a class based on locatin of POINT."
|
||||
(save-excursion
|
||||
(when point
|
||||
(goto-char point))
|
||||
|
||||
(let ((tag (semantic-current-tag-of-class 'type)))
|
||||
|
||||
(when (or (not tag)
|
||||
(not (string= (semantic-tag-type tag) "class")))
|
||||
;; The current tag is not a class. Are we in a fcn
|
||||
;; that is a method?
|
||||
(setq tag (semantic-current-tag-of-class 'function))
|
||||
|
||||
(when (and tag
|
||||
(semantic-tag-function-parent tag))
|
||||
(let ((p (semantic-tag-function-parent tag)))
|
||||
;; @TODO : Copied below out of semantic-analyze
|
||||
;; Turn into a routine.
|
||||
|
||||
(let* ((searchname (cond ((stringp p) p)
|
||||
((semantic-tag-p p)
|
||||
(semantic-tag-name p))
|
||||
((and (listp p) (stringp (car p)))
|
||||
(car p))))
|
||||
(ptag (semantic-analyze-find-tag searchname
|
||||
'type nil)))
|
||||
(when ptag (setq tag ptag ))
|
||||
))))
|
||||
|
||||
(when (or (not tag)
|
||||
(not (semantic-tag-of-class-p tag 'type))
|
||||
(not (string= (semantic-tag-type tag) "class")))
|
||||
;; We are not in a class that needs a get/set method.
|
||||
;; Analyze the current context, and derive a class name.
|
||||
(let* ((ctxt (semantic-analyze-current-context))
|
||||
(pfix nil)
|
||||
(ans nil))
|
||||
(when ctxt
|
||||
(setq pfix (reverse (oref ctxt prefix)))
|
||||
(while (and (not ans) pfix)
|
||||
;; Start at the end and back up to the first class.
|
||||
(when (and (semantic-tag-p (car pfix))
|
||||
(semantic-tag-of-class-p (car pfix) 'type)
|
||||
(string= (semantic-tag-type (car pfix))
|
||||
"class"))
|
||||
(setq ans (car pfix)))
|
||||
(setq pfix (cdr pfix))))
|
||||
(setq tag ans)))
|
||||
|
||||
tag)))
|
||||
|
||||
(provide 'srecode/getset)
|
||||
|
||||
;; Local variables:
|
||||
;; generated-autoload-file: "loaddefs.el"
|
||||
;; generated-autoload-feature: srecode/loaddefs
|
||||
;; generated-autoload-load-name: "srecode/getset"
|
||||
;; End:
|
||||
|
||||
;;; srecode/getset.el ends here
|
983
lisp/cedet/srecode/insert.el
Normal file
983
lisp/cedet/srecode/insert.el
Normal file
|
@ -0,0 +1,983 @@
|
|||
;;; srecode/insert --- Insert srecode templates to an output stream.
|
||||
|
||||
;;; Copyright (C) 2005, 2007, 2008, 2009 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Eric M. Ludlam <zappo@gnu.org>
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; Define and implements specific inserter objects.
|
||||
;;
|
||||
;; Manage the insertion process for a template.
|
||||
;;
|
||||
|
||||
(require 'srecode/compile)
|
||||
(require 'srecode/find)
|
||||
(require 'srecode/dictionary)
|
||||
|
||||
(defvar srecode-template-inserter-point)
|
||||
(declare-function srecode-overlaid-activate "srecode/fields")
|
||||
(declare-function srecode-template-inserted-region "srecode/fields")
|
||||
|
||||
;;; Code:
|
||||
|
||||
(defcustom srecode-insert-ask-variable-method 'ask
|
||||
"Determine how to ask for a dictionary value when inserting a template.
|
||||
Only the ASK style inserter will query the user for a value.
|
||||
Dictionary value references that ask begin with the ? character.
|
||||
Possible values are:
|
||||
'ask - Prompt in the minibuffer as the value is inserted.
|
||||
'field - Use the dictionary macro name as the inserted value,
|
||||
and place a field there. Matched fields change together.
|
||||
|
||||
NOTE: The field feature does not yet work with XEmacs."
|
||||
:group 'srecode
|
||||
:type '(choice (const :tag "Ask" ask)
|
||||
(cons :tag "Field" field)))
|
||||
|
||||
(defvar srecode-insert-with-fields-in-progress nil
|
||||
"Non-nil means that we are actively inserting a template with fields.")
|
||||
|
||||
;;; INSERTION COMMANDS
|
||||
;;
|
||||
;; User level commands for inserting stuff.
|
||||
(defvar srecode-insertion-start-context nil
|
||||
"The context that was at point at the beginning of the template insertion.")
|
||||
|
||||
(defun srecode-insert-again ()
|
||||
"Insert the previously inserted template (by name) again."
|
||||
(interactive)
|
||||
(let ((prev (car srecode-read-template-name-history)))
|
||||
(if prev
|
||||
(srecode-insert prev)
|
||||
(call-interactively 'srecode-insert))))
|
||||
|
||||
;;;###autoload
|
||||
(defun srecode-insert (template-name &rest dict-entries)
|
||||
"Inesrt the template TEMPLATE-NAME into the current buffer at point.
|
||||
DICT-ENTRIES are additional dictionary values to add."
|
||||
(interactive (list (srecode-read-template-name "Template Name: ")))
|
||||
(if (not (srecode-table))
|
||||
(error "No template table found for mode %s" major-mode))
|
||||
(let ((newdict (srecode-create-dictionary))
|
||||
(temp (srecode-template-get-table (srecode-table) template-name))
|
||||
(srecode-insertion-start-context (srecode-calculate-context))
|
||||
)
|
||||
(if (not temp)
|
||||
(error "No Template named %s" template-name))
|
||||
(while dict-entries
|
||||
(srecode-dictionary-set-value newdict
|
||||
(car dict-entries)
|
||||
(car (cdr dict-entries)))
|
||||
(setq dict-entries (cdr (cdr dict-entries))))
|
||||
;;(srecode-resolve-arguments temp newdict)
|
||||
(srecode-insert-fcn temp newdict)
|
||||
;; Don't put code here. We need to return the end-mark
|
||||
;; for this insertion step.
|
||||
))
|
||||
|
||||
(defun srecode-insert-fcn (template dictionary &optional stream skipresolver)
|
||||
"Insert TEMPLATE using DICTIONARY into STREAM.
|
||||
Optional SKIPRESOLVER means to avoid refreshing the tag list,
|
||||
or resolving any template arguments. It is assumed the caller
|
||||
has set everything up already."
|
||||
;; Perform the insertion.
|
||||
(let ((standard-output (or stream (current-buffer)))
|
||||
(end-mark nil))
|
||||
(unless skipresolver
|
||||
;; Make sure the semantic tags are up to date.
|
||||
(semantic-fetch-tags)
|
||||
;; Resolve the arguments
|
||||
(srecode-resolve-arguments template dictionary))
|
||||
;; Insert
|
||||
(if (bufferp standard-output)
|
||||
;; If there is a buffer, turn off various hooks. This will cause
|
||||
;; the mod hooks to be buffered up during the insert, but
|
||||
;; prevent tools like font-lock from fontifying mid-template.
|
||||
;; Especialy important during insertion of complex comments that
|
||||
;; cause the new font-lock to comment-color stuff after the inserted
|
||||
;; comment.
|
||||
;;
|
||||
;; I'm not sure about the motion hooks. It seems like a good
|
||||
;; idea though.
|
||||
;;
|
||||
;; Borrowed these concepts out of font-lock.
|
||||
;;
|
||||
;; I tried `combine-after-change-calls', but it did not have
|
||||
;; the effect I wanted.
|
||||
(let ((start (point)))
|
||||
(let ((inhibit-point-motion-hooks t)
|
||||
(inhibit-modification-hooks t)
|
||||
)
|
||||
(srecode--insert-into-buffer template dictionary)
|
||||
)
|
||||
;; Now call those after change functions.
|
||||
(run-hook-with-args 'after-change-functions
|
||||
start (point) 0)
|
||||
)
|
||||
(srecode-insert-method template dictionary))
|
||||
;; Handle specialization of the POINT inserter.
|
||||
(when (and (bufferp standard-output)
|
||||
(slot-boundp 'srecode-template-inserter-point 'point)
|
||||
)
|
||||
(set-buffer standard-output)
|
||||
(setq end-mark (point-marker))
|
||||
(goto-char (oref srecode-template-inserter-point point)))
|
||||
(oset-default 'srecode-template-inserter-point point eieio-unbound)
|
||||
|
||||
;; Return the end-mark.
|
||||
(or end-mark (point)))
|
||||
)
|
||||
|
||||
(defun srecode--insert-into-buffer (template dictionary)
|
||||
"Insert a TEMPLATE with DICTIONARY into a buffer.
|
||||
Do not call this function yourself. Instead use:
|
||||
`srecode-insert' - Inserts by name.
|
||||
`srecode-insert-fcn' - Insert with objects.
|
||||
This function handles the case from one of the above functions when
|
||||
the template is inserted into a buffer. It looks
|
||||
at `srecode-insert-ask-variable-method' to decide if unbound dictionary
|
||||
entries ask questions or insert editable fields.
|
||||
|
||||
Buffer based features related to change hooks is handled one level up."
|
||||
;; This line prevents the field archive from being let bound
|
||||
;; while the field insert tool is loaded via autoloads during
|
||||
;; the insert.
|
||||
(when (eq srecode-insert-ask-variable-method 'field)
|
||||
(require 'srecode-fields))
|
||||
|
||||
(let ((srecode-field-archive nil) ; Prevent field leaks during insert
|
||||
(start (point)) ; Beginning of the region.
|
||||
)
|
||||
;; This sub-let scopes the 'in-progress' piece so we know
|
||||
;; when to setup the end-template.
|
||||
(let ((srecode-insert-with-fields-in-progress
|
||||
(if (eq srecode-insert-ask-variable-method 'field) t nil))
|
||||
)
|
||||
(srecode-insert-method template dictionary)
|
||||
)
|
||||
;; If we are not in-progress, and we insert fields, then
|
||||
;; create the end-template with fields editable area.
|
||||
(when (and (not srecode-insert-with-fields-in-progress)
|
||||
(eq srecode-insert-ask-variable-method 'field) ; Only if user asked
|
||||
srecode-field-archive ; Only if there were fields created
|
||||
)
|
||||
(let ((reg
|
||||
;; Create the field-driven editable area.
|
||||
(srecode-template-inserted-region
|
||||
"TEMPLATE" :start start :end (point))))
|
||||
(srecode-overlaid-activate reg))
|
||||
)
|
||||
;; We return with 'point being the end of the template insertion
|
||||
;; area. Return value is not important.
|
||||
))
|
||||
|
||||
;;; TEMPLATE ARGUMENTS
|
||||
;;
|
||||
;; Some templates have arguments. Each argument is assocaited with
|
||||
;; a function that can resolve the inputs needed.
|
||||
(defun srecode-resolve-arguments (temp dict)
|
||||
"Resolve all the arguments needed by the template TEMP.
|
||||
Apply anything learned to the dictionary DICT."
|
||||
(srecode-resolve-argument-list (oref temp args) dict temp))
|
||||
|
||||
(defun srecode-resolve-argument-list (args dict &optional temp)
|
||||
"Resolve arguments in the argument list ARGS.
|
||||
ARGS is a list of symbols, such as :blank, or :file.
|
||||
Apply values to DICT.
|
||||
Optional argument TEMP is the template that is getting it's arguments resolved."
|
||||
(let ((fcn nil))
|
||||
(while args
|
||||
(setq fcn (intern-soft (concat "srecode-semantic-handle-"
|
||||
(symbol-name (car args)))))
|
||||
(if (not fcn)
|
||||
(error "Error resolving template argument %S" (car args)))
|
||||
(if temp
|
||||
(condition-case nil
|
||||
;; Allow some to accept a 2nd argument optionally.
|
||||
;; They throw an error if not available, so try again.
|
||||
(funcall fcn dict temp)
|
||||
(wrong-number-of-arguments (funcall fcn dict)))
|
||||
(funcall fcn dict))
|
||||
(setq args (cdr args)))
|
||||
))
|
||||
|
||||
;;; INSERTION STACK & METHOD
|
||||
;;
|
||||
;; Code managing the top-level insert method and the current
|
||||
;; insertion stack.
|
||||
;;
|
||||
(defmethod srecode-push ((st srecode-template))
|
||||
"Push the srecoder template ST onto the active stack."
|
||||
(oset st active (cons st (oref st active))))
|
||||
|
||||
(defmethod srecode-pop :STATIC ((st srecode-template))
|
||||
"Pop the srecoder template ST onto the active stack.
|
||||
ST can be a class, or an object."
|
||||
(oset st active (cdr (oref st active))))
|
||||
|
||||
(defmethod srecode-peek :STATIC ((st srecode-template))
|
||||
"Fetch the topmost active template record. ST can be a class."
|
||||
(car (oref st active)))
|
||||
|
||||
(defmethod srecode-insert-method ((st srecode-template) dictionary)
|
||||
"Insert the srecoder template ST."
|
||||
;; Merge any template entries into the input dictionary.
|
||||
(when (slot-boundp st 'dictionary)
|
||||
(srecode-dictionary-merge dictionary (oref st dictionary)))
|
||||
;; Do an insertion.
|
||||
(unwind-protect
|
||||
(let ((c (oref st code)))
|
||||
(srecode-push st)
|
||||
(srecode-insert-code-stream c dictionary))
|
||||
;; Poping the stack is protected
|
||||
(srecode-pop st)))
|
||||
|
||||
(defun srecode-insert-code-stream (code dictionary)
|
||||
"Insert the CODE from a template into `standard-output'.
|
||||
Use DICTIONARY to resolve any macros."
|
||||
(while code
|
||||
(cond ((stringp (car code))
|
||||
(princ (car code)))
|
||||
(t
|
||||
(srecode-insert-method (car code) dictionary)))
|
||||
(setq code (cdr code))))
|
||||
|
||||
;;; INSERTERS
|
||||
;;
|
||||
;; Specific srecode inserters.
|
||||
;; The base class is from srecode-compile.
|
||||
;;
|
||||
;; Each inserter handles various macro codes from the temlate.
|
||||
;; The `code' slot specifies a character used to identify which
|
||||
;; inserter is to be created.
|
||||
;;
|
||||
(defclass srecode-template-inserter-newline (srecode-template-inserter)
|
||||
((key :initform "\n"
|
||||
:allocation :class
|
||||
:documentation
|
||||
"The character code used to identify inserters of this style.")
|
||||
(hard :initform nil
|
||||
:initarg :hard
|
||||
:documentation
|
||||
"Is this a hard newline (always inserted) or optional?
|
||||
Optional newlines don't insert themselves if they are on a blank line
|
||||
by themselves.")
|
||||
)
|
||||
"Insert a newline, and possibly do indenting.
|
||||
Specify the :indent argument to enable automatic indentation when newlines
|
||||
occur in your template.")
|
||||
|
||||
(defmethod srecode-insert-method ((sti srecode-template-inserter-newline)
|
||||
dictionary)
|
||||
"Insert the STI inserter."
|
||||
;; To be safe, indent the previous line since the template will
|
||||
;; change what is there to indent
|
||||
(let ((i (srecode-dictionary-lookup-name dictionary "INDENT"))
|
||||
(inbuff (bufferp standard-output))
|
||||
(doit t)
|
||||
(pm (point-marker)))
|
||||
(when (and inbuff (not (oref sti hard)))
|
||||
;; If this is not a hard newline, we need do the calculation
|
||||
;; and set "doit" to nil.
|
||||
(beginning-of-line)
|
||||
(save-restriction
|
||||
(narrow-to-region (point) pm)
|
||||
(when (looking-at "\\s-*$")
|
||||
(setq doit nil)))
|
||||
(goto-char pm)
|
||||
)
|
||||
;; Do indentation reguardless of the newline.
|
||||
(when (and (eq i t) inbuff)
|
||||
(indent-according-to-mode)
|
||||
(goto-char pm))
|
||||
|
||||
(when doit
|
||||
(princ "\n")
|
||||
;; Indent after the newline, particularly for numeric indents.
|
||||
(cond ((and (eq i t) (bufferp standard-output))
|
||||
;; WARNING - indent according to mode requires that standard-output
|
||||
;; is a buffer!
|
||||
;; @todo - how to indent in a string???
|
||||
(setq pm (point-marker))
|
||||
(indent-according-to-mode)
|
||||
(goto-char pm))
|
||||
((numberp i)
|
||||
(princ (make-string i " ")))
|
||||
((stringp i)
|
||||
(princ i))))))
|
||||
|
||||
(defmethod srecode-dump ((ins srecode-template-inserter-newline) indent)
|
||||
"Dump the state of the SRecode template inserter INS."
|
||||
(call-next-method)
|
||||
(when (oref ins hard)
|
||||
(princ " : hard")
|
||||
))
|
||||
|
||||
(defclass srecode-template-inserter-blank (srecode-template-inserter)
|
||||
((key :initform "\r"
|
||||
:allocation :class
|
||||
:documentation
|
||||
"The character represeinting this inserter style.
|
||||
Can't be blank, or it might be used by regular variable insertion.")
|
||||
(where :initform 'begin
|
||||
:initarg :where
|
||||
:documentation
|
||||
"This should be 'begin or 'end, indicating where to insrt a CR.
|
||||
When set to 'begin, it will insert a CR if we are not at 'bol'.
|
||||
When set to 'end it will insert a CR if we are not at 'eol'")
|
||||
;; @TODO - Add slot and control for the number of blank
|
||||
;; lines before and after point.
|
||||
)
|
||||
"Insert a newline before and after a template, and possibly do indenting.
|
||||
Specify the :blank argument to enable this inserter.")
|
||||
|
||||
(defmethod srecode-insert-method ((sti srecode-template-inserter-blank)
|
||||
dictionary)
|
||||
"Make sure there is no text before or after point."
|
||||
(let ((i (srecode-dictionary-lookup-name dictionary "INDENT"))
|
||||
(inbuff (bufferp standard-output))
|
||||
(pm (point-marker)))
|
||||
(when (and inbuff
|
||||
;; Don't do this if we are not the active template.
|
||||
(= (length (oref srecode-template active)) 1))
|
||||
|
||||
(when (and (eq i t) inbuff (not (eq (oref sti where) 'begin)))
|
||||
(indent-according-to-mode)
|
||||
(goto-char pm))
|
||||
|
||||
(cond ((and (eq (oref sti where) 'begin) (not (bolp)))
|
||||
(princ "\n"))
|
||||
((eq (oref sti where) 'end)
|
||||
;; If there is whitespace after pnt, then clear it out.
|
||||
(when (looking-at "\\s-*$")
|
||||
(delete-region (point) (point-at-eol)))
|
||||
(when (not (eolp))
|
||||
(princ "\n")))
|
||||
)
|
||||
(setq pm (point-marker))
|
||||
(when (and (eq i t) inbuff (not (eq (oref sti where) 'end)))
|
||||
(indent-according-to-mode)
|
||||
(goto-char pm))
|
||||
)))
|
||||
|
||||
(defclass srecode-template-inserter-comment (srecode-template-inserter)
|
||||
((key :initform ?!
|
||||
:allocation :class
|
||||
:documentation
|
||||
"The character code used to identify inserters of this style.")
|
||||
)
|
||||
"Allow comments within template coding. This inserts nothing.")
|
||||
|
||||
(defmethod srecode-inserter-prin-example :STATIC ((ins srecode-template-inserter-comment)
|
||||
escape-start escape-end)
|
||||
"Insert an example using inserter INS.
|
||||
Arguments ESCAPE-START and ESCAPE-END are the current escape sequences in use."
|
||||
(princ " ")
|
||||
(princ escape-start)
|
||||
(princ "! Miscellaneous text commenting in your template. ")
|
||||
(princ escape-end)
|
||||
(terpri)
|
||||
)
|
||||
|
||||
(defmethod srecode-insert-method ((sti srecode-template-inserter-comment)
|
||||
dictionary)
|
||||
"Don't insert anything for comment macros in STI."
|
||||
nil)
|
||||
|
||||
|
||||
(defclass srecode-template-inserter-variable (srecode-template-inserter)
|
||||
((key :initform nil
|
||||
:allocation :class
|
||||
:documentation
|
||||
"The character code used to identify inserters of this style."))
|
||||
"Insert the value of a dictionary entry
|
||||
If there is no entry, insert nothing.")
|
||||
|
||||
(defvar srecode-inserter-variable-current-dictionary nil
|
||||
"The active dictionary when calling a variable filter.")
|
||||
|
||||
(defmethod srecode-insert-variable-secondname-handler
|
||||
((sti srecode-template-inserter-variable) dictionary value secondname)
|
||||
"For VALUE handle SECONDNAME behaviors for this variable inserter.
|
||||
Return the result as a string.
|
||||
By default, treat as a function name.
|
||||
If SECONDNAME is nil, return VALUE."
|
||||
(if secondname
|
||||
(let ((fcnpart (read secondname)))
|
||||
(if (fboundp fcnpart)
|
||||
(let ((srecode-inserter-variable-current-dictionary dictionary))
|
||||
(funcall fcnpart value))
|
||||
;; Else, warn.
|
||||
(error "Variable insertion second arg %s is not a function."
|
||||
secondname)))
|
||||
value))
|
||||
|
||||
(defmethod srecode-insert-method ((sti srecode-template-inserter-variable)
|
||||
dictionary)
|
||||
"Insert the STI inserter."
|
||||
;; Convert the name into a name/fcn pair
|
||||
(let* ((name (oref sti :object-name))
|
||||
(fcnpart (oref sti :secondname))
|
||||
(val (srecode-dictionary-lookup-name
|
||||
dictionary name))
|
||||
(do-princ t)
|
||||
)
|
||||
;; Alert if a macro wasn't found.
|
||||
(when (not val)
|
||||
(message "Warning: macro %S was not found in the dictionary." name)
|
||||
(setq val ""))
|
||||
;; If there was a functional part, call that function.
|
||||
(cond ;; Strings
|
||||
((stringp val)
|
||||
(setq val (srecode-insert-variable-secondname-handler
|
||||
sti dictionary val fcnpart)))
|
||||
;; Compound data value
|
||||
((srecode-dictionary-compound-value-child-p val)
|
||||
;; Force FCN to be a symbol
|
||||
(when fcnpart (setq fcnpart (read fcnpart)))
|
||||
;; Convert compound value to a string with the fcn.
|
||||
(setq val (srecode-compound-toString val fcnpart dictionary))
|
||||
;; 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)
|
||||
)
|
||||
)
|
||||
;; Dictionaries... not allowed in this style
|
||||
((srecode-dictionary-child-p val)
|
||||
(error "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))))
|
||||
))
|
||||
;; Output the dumb thing unless the type of thing specifically
|
||||
;; did the inserting forus.
|
||||
(when do-princ
|
||||
(princ val))))
|
||||
|
||||
(defclass srecode-template-inserter-ask (srecode-template-inserter-variable)
|
||||
((key :initform ??
|
||||
:allocation :class
|
||||
:documentation
|
||||
"The character code used to identify inserters of this style.")
|
||||
(prompt :initarg :prompt
|
||||
:initform nil
|
||||
:documentation
|
||||
"The prompt used to query for this dictionary value.")
|
||||
(defaultfcn :initarg :defaultfcn
|
||||
:initform nil
|
||||
:documentation
|
||||
"The function which can calculate a default value.")
|
||||
(read-fcn :initarg :read-fcn
|
||||
:initform 'read-string
|
||||
:documentation
|
||||
"The function used to read in the text for this prompt.")
|
||||
)
|
||||
"Insert the value of a dictionary entry
|
||||
If there is no entry, prompt the user for the value to use.
|
||||
The prompt text used is derived from the previous PROMPT command in the
|
||||
template file.")
|
||||
|
||||
(defmethod srecode-inserter-apply-state ((ins srecode-template-inserter-ask) STATE)
|
||||
"For the template inserter INS, apply information from STATE.
|
||||
Loop over the prompts to see if we have a match."
|
||||
(let ((prompts (oref STATE prompts))
|
||||
)
|
||||
(while prompts
|
||||
(when (string= (semantic-tag-name (car prompts))
|
||||
(oref ins :object-name))
|
||||
(oset ins :prompt
|
||||
(semantic-tag-get-attribute (car prompts) :text))
|
||||
(oset ins :defaultfcn
|
||||
(semantic-tag-get-attribute (car prompts) :default))
|
||||
(oset ins :read-fcn
|
||||
(or (semantic-tag-get-attribute (car prompts) :read)
|
||||
'read-string))
|
||||
)
|
||||
(setq prompts (cdr prompts)))
|
||||
))
|
||||
|
||||
(defmethod srecode-insert-method ((sti srecode-template-inserter-ask)
|
||||
dictionary)
|
||||
"Insert the STI inserter."
|
||||
(let ((val (srecode-dictionary-lookup-name
|
||||
dictionary (oref sti :object-name))))
|
||||
(if val
|
||||
;; Does some extra work. Oh well.
|
||||
(call-next-method)
|
||||
|
||||
;; How is our -ask value determined?
|
||||
(if srecode-insert-with-fields-in-progress
|
||||
;; Setup editable fields.
|
||||
(setq val (srecode-insert-method-field sti dictionary))
|
||||
;; Ask the question...
|
||||
(setq val (srecode-insert-method-ask sti dictionary)))
|
||||
|
||||
;; After asking, save in the dictionary so that
|
||||
;; the user can use the same name again later.
|
||||
(srecode-dictionary-set-value
|
||||
(srecode-root-dictionary dictionary)
|
||||
(oref sti :object-name) val)
|
||||
|
||||
;; Now that this value is safely stowed in the dictionary,
|
||||
;; we can do what regular inserters do.
|
||||
(call-next-method))))
|
||||
|
||||
(defmethod srecode-insert-ask-default ((sti srecode-template-inserter-ask)
|
||||
dictionary)
|
||||
"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)))))
|
||||
|
||||
(defmethod srecode-insert-method-ask ((sti srecode-template-inserter-ask)
|
||||
dictionary)
|
||||
"Do the \"asking\" for the template inserter STI.
|
||||
Use DICTIONARY to resolve values."
|
||||
(let* ((prompt (oref sti prompt))
|
||||
(default (srecode-insert-ask-default sti dictionary))
|
||||
(reader (oref sti :read-fcn))
|
||||
(val nil)
|
||||
)
|
||||
(cond ((eq reader 'y-or-n-p)
|
||||
(if (y-or-n-p (or prompt
|
||||
(format "%s? "
|
||||
(oref sti :object-name))))
|
||||
(setq val default)
|
||||
(setq val "")))
|
||||
((eq reader 'read-char)
|
||||
(setq val (format
|
||||
"%c"
|
||||
(read-char (or prompt
|
||||
(format "Char for %s: "
|
||||
(oref sti :object-name))))))
|
||||
)
|
||||
(t
|
||||
(save-excursion
|
||||
(setq val (funcall reader
|
||||
(or prompt
|
||||
(format "Specify %s: "
|
||||
(oref sti :object-name)))
|
||||
default
|
||||
)))))
|
||||
;; Return our derived value.
|
||||
val)
|
||||
)
|
||||
|
||||
(defmethod srecode-insert-method-field ((sti srecode-template-inserter-ask)
|
||||
dictionary)
|
||||
"Create an editable field for the template inserter STI.
|
||||
Use DICTIONARY to resolve values."
|
||||
(let* ((default (srecode-insert-ask-default sti dictionary))
|
||||
(compound-value
|
||||
(srecode-field-value (oref sti :object-name)
|
||||
:firstinserter sti
|
||||
:defaultvalue default))
|
||||
)
|
||||
;; Return this special compound value as the thing to insert.
|
||||
;; This special compound value will repeat our asked question
|
||||
;; across multiple locations.
|
||||
compound-value))
|
||||
|
||||
(defmethod srecode-dump ((ins srecode-template-inserter-ask) indent)
|
||||
"Dump the state of the SRecode template inserter INS."
|
||||
(call-next-method)
|
||||
(princ " : \"")
|
||||
(princ (oref ins prompt))
|
||||
(princ "\"")
|
||||
)
|
||||
|
||||
(defclass srecode-template-inserter-width (srecode-template-inserter-variable)
|
||||
((key :initform ?|
|
||||
:allocation :class
|
||||
:documentation
|
||||
"The character code used to identify inserters of this style.")
|
||||
)
|
||||
"Inserts the value of a dictionary variable with a specific width.
|
||||
The second argument specifies the width, and a pad, seperated by a colon.
|
||||
thus a specification of `10:left' will insert the value of A
|
||||
to 10 characters, with spaces added to the left. Use `right' for adding
|
||||
spaces to the right.")
|
||||
|
||||
(defmethod srecode-insert-variable-secondname-handler
|
||||
((sti srecode-template-inserter-width) dictionary value width)
|
||||
"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.")))
|
||||
|
||||
(defmethod srecode-inserter-prin-example :STATIC ((ins srecode-template-inserter-width)
|
||||
escape-start escape-end)
|
||||
"Insert an example using inserter INS.
|
||||
Arguments ESCAPE-START and ESCAPE-END are the current escape sequences in use."
|
||||
(princ " ")
|
||||
(princ escape-start)
|
||||
(princ "|A:10:right")
|
||||
(princ escape-end)
|
||||
(terpri)
|
||||
)
|
||||
|
||||
(defvar srecode-template-inserter-point-override nil
|
||||
"When non-nil, the point inserter will do this functin instead.")
|
||||
|
||||
(defclass srecode-template-inserter-point (srecode-template-inserter)
|
||||
((key :initform ?^
|
||||
:allocation :class
|
||||
:documentation
|
||||
"The character code used to identify inserters of this style.")
|
||||
(point :type (or null marker)
|
||||
:allocation :class
|
||||
:documentation
|
||||
"Record the value of (point) in this class slot.
|
||||
It is the responsibility of the inserter algorithm to clear this
|
||||
after a successful insertion."))
|
||||
"Record the value of (point) when inserted.
|
||||
The cursor is placed at the ^ macro after insertion.
|
||||
Some inserter macros, such as `srecode-template-inserter-include-wrap'
|
||||
will place text at the ^ macro from the included macro.")
|
||||
|
||||
(defmethod srecode-inserter-prin-example :STATIC ((ins srecode-template-inserter-point)
|
||||
escape-start escape-end)
|
||||
"Insert an example using inserter INS.
|
||||
Arguments ESCAPE-START and ESCAPE-END are the current escape sequences in use."
|
||||
(princ " ")
|
||||
(princ escape-start)
|
||||
(princ "^")
|
||||
(princ escape-end)
|
||||
(terpri)
|
||||
)
|
||||
|
||||
(defmethod srecode-insert-method ((sti srecode-template-inserter-point)
|
||||
dictionary)
|
||||
"Insert the STI inserter.
|
||||
Save point in the class allocated 'point' slot.
|
||||
If `srecode-template-inserter-point-override' then this generalized
|
||||
marker will do something else. See `srecode-template-inserter-include-wrap'
|
||||
as an example."
|
||||
(if srecode-template-inserter-point-override
|
||||
;; Disable the old override while we do this.
|
||||
(let ((over srecode-template-inserter-point-override)
|
||||
(srecode-template-inserter-point-override nil))
|
||||
(funcall over dictionary)
|
||||
)
|
||||
(oset sti point (point-marker))
|
||||
))
|
||||
|
||||
(defclass srecode-template-inserter-subtemplate (srecode-template-inserter)
|
||||
()
|
||||
"Wrap a section of a template under the control of a macro."
|
||||
:abstract t)
|
||||
|
||||
(defmethod srecode-inserter-prin-example :STATIC ((ins srecode-template-inserter-subtemplate)
|
||||
escape-start escape-end)
|
||||
"Insert an example using inserter INS.
|
||||
Arguments ESCAPE-START and ESCAPE-END are the current escape sequences in use."
|
||||
(call-next-method)
|
||||
(princ " Template Text to control")
|
||||
(terpri)
|
||||
(princ " ")
|
||||
(princ escape-start)
|
||||
(princ "/VARNAME")
|
||||
(princ escape-end)
|
||||
(terpri)
|
||||
)
|
||||
|
||||
(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)))
|
||||
;; Output the code from the sub-template.
|
||||
(srecode-insert-method (slot-value sti slot) dict)
|
||||
)
|
||||
|
||||
(defmethod srecode-insert-method-helper ((sti srecode-template-inserter-subtemplate)
|
||||
dictionary slot)
|
||||
"Do the work for inserting the STI inserter.
|
||||
Loops over the embedded CODE which was saved here during compilation.
|
||||
The template to insert is stored in SLOT."
|
||||
(let ((dicts (srecode-dictionary-lookup-name
|
||||
dictionary (oref sti :object-name))))
|
||||
;; If there is no section dictionary, then don't output anything
|
||||
;; from this section.
|
||||
(while dicts
|
||||
(srecode-insert-subtemplate sti (car dicts) slot)
|
||||
(setq dicts (cdr dicts)))))
|
||||
|
||||
(defmethod srecode-insert-method ((sti srecode-template-inserter-subtemplate)
|
||||
dictionary)
|
||||
"Insert the STI inserter.
|
||||
Calls back to `srecode-insert-method-helper' for this class."
|
||||
(srecode-insert-method-helper sti dictionary 'template))
|
||||
|
||||
|
||||
(defclass srecode-template-inserter-section-start (srecode-template-inserter-subtemplate)
|
||||
((key :initform ?#
|
||||
:allocation :class
|
||||
:documentation
|
||||
"The character code used to identify inserters of this style.")
|
||||
(template :initarg :template
|
||||
:documentation
|
||||
"A Template used to frame the codes from this inserter.")
|
||||
)
|
||||
"Apply values from a sub-dictionary to a template section.
|
||||
The dictionary saved at the named dictionary entry will be
|
||||
applied to the text between the section start and the
|
||||
`srecode-template-inserter-section-end' macro.")
|
||||
|
||||
(defmethod srecode-parse-input ((ins srecode-template-inserter-section-start)
|
||||
tag input STATE)
|
||||
"For the section inserter INS, parse INPUT.
|
||||
Shorten input until the END token is found.
|
||||
Return the remains of INPUT."
|
||||
(let* ((out (srecode-compile-split-code tag input STATE
|
||||
(oref ins :object-name))))
|
||||
(oset ins template (srecode-template
|
||||
(object-name-string ins)
|
||||
:context nil
|
||||
:args nil
|
||||
:code (cdr out)))
|
||||
(car out)))
|
||||
|
||||
(defmethod srecode-dump ((ins srecode-template-inserter-section-start) indent)
|
||||
"Dump the state of the SRecode template inserter INS."
|
||||
(call-next-method)
|
||||
(princ "\n")
|
||||
(srecode-dump-code-list (oref (oref ins template) code)
|
||||
(concat indent " "))
|
||||
)
|
||||
|
||||
(defclass srecode-template-inserter-section-end (srecode-template-inserter)
|
||||
((key :initform ?/
|
||||
:allocation :class
|
||||
:documentation
|
||||
"The character code used to identify inserters of this style.")
|
||||
)
|
||||
"All template segments between the secion-start and section-end
|
||||
are treated specially.")
|
||||
|
||||
(defmethod srecode-insert-method ((sti srecode-template-inserter-section-end)
|
||||
dictionary)
|
||||
"Insert the STI inserter."
|
||||
)
|
||||
|
||||
(defmethod srecode-match-end ((ins srecode-template-inserter-section-end) name)
|
||||
|
||||
"For the template inserter INS, do I end a section called NAME?"
|
||||
(string= name (oref ins :object-name)))
|
||||
|
||||
(defclass srecode-template-inserter-include (srecode-template-inserter-subtemplate)
|
||||
((key :initform ?>
|
||||
:allocation :class
|
||||
:documentation
|
||||
"The character code used to identify inserters of this style.")
|
||||
(includedtemplate
|
||||
:initarg :includedtemplate
|
||||
:documentation
|
||||
"The template included for this inserter."))
|
||||
"Include a different template into this one.
|
||||
The included template will have additional dictionary entries from the subdictionary
|
||||
stored specified by this macro.")
|
||||
|
||||
(defmethod srecode-inserter-prin-example :STATIC ((ins srecode-template-inserter-include)
|
||||
escape-start escape-end)
|
||||
"Insert an example using inserter INS.
|
||||
Arguments ESCAPE-START and ESCAPE-END are the current escape sequences in use."
|
||||
(princ " ")
|
||||
(princ escape-start)
|
||||
(princ ">DICTNAME:contextname:templatename")
|
||||
(princ escape-end)
|
||||
(terpri)
|
||||
)
|
||||
|
||||
(defmethod srecode-insert-include-lookup ((sti srecode-template-inserter-include)
|
||||
dictionary)
|
||||
"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)))
|
||||
;; Find the template by name, and save it.
|
||||
(if (or (not (slot-boundp sti 'includedtemplate))
|
||||
(not (oref sti includedtemplate)))
|
||||
(let ((tmpl (srecode-template-get-table (srecode-table)
|
||||
templatenamepart))
|
||||
(active (oref srecode-template active))
|
||||
ctxt)
|
||||
(when (not tmpl)
|
||||
;; If it isn't just available, scan back through
|
||||
;; the active template stack, searching for a matching
|
||||
;; context.
|
||||
(while (and (not tmpl) active)
|
||||
(setq ctxt (oref (car active) context))
|
||||
(setq tmpl (srecode-template-get-table (srecode-table)
|
||||
templatenamepart
|
||||
ctxt))
|
||||
(when (not tmpl)
|
||||
(when (slot-boundp (car active) 'table)
|
||||
(let ((app (oref (oref (car active) table) application)))
|
||||
(when app
|
||||
(setq tmpl (srecode-template-get-table
|
||||
(srecode-table)
|
||||
templatenamepart
|
||||
ctxt app)))
|
||||
)))
|
||||
(setq active (cdr active)))
|
||||
(when (not tmpl)
|
||||
;; If it wasn't in this context, look to see if it
|
||||
;; defines it's own context
|
||||
(setq tmpl (srecode-template-get-table (srecode-table)
|
||||
templatenamepart)))
|
||||
)
|
||||
(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)))
|
||||
))
|
||||
|
||||
(defmethod srecode-insert-method ((sti srecode-template-inserter-include)
|
||||
dictionary)
|
||||
"Insert the STI inserter.
|
||||
Finds the template with this macro function part, and inserts it
|
||||
with the dictionaries found in the dictinary."
|
||||
(srecode-insert-include-lookup sti dictionary)
|
||||
;; Insert the template.
|
||||
;; Our baseclass has a simple way to do this.
|
||||
(if (srecode-dictionary-lookup-name dictionary (oref sti :object-name))
|
||||
;; If we have a value, then call the next method
|
||||
(srecode-insert-method-helper sti dictionary 'includedtemplate)
|
||||
;; If we don't have a special dictitonary, then just insert with the
|
||||
;; current dictionary.
|
||||
(srecode-insert-subtemplate sti dictionary 'includedtemplate))
|
||||
)
|
||||
|
||||
;;
|
||||
;; This template combines the include template and the sectional template.
|
||||
;; It will first insert the included template, then insert the embedded
|
||||
;; template wherever the $^$ in the included template was.
|
||||
;;
|
||||
;; Since it uses dual inheretance, it will magically get the end-matching
|
||||
;; behavior of #, with the including feature of >.
|
||||
;;
|
||||
(defclass srecode-template-inserter-include-wrap (srecode-template-inserter-include srecode-template-inserter-section-start)
|
||||
((key :initform ?<
|
||||
:allocation :class
|
||||
:documentation
|
||||
"The character code used to identify inserters of this style.")
|
||||
)
|
||||
"Include a different template into this one, and add text at the ^ macro.
|
||||
The included template will have additional dictionary entries from the subdictionary
|
||||
stored specified by this macro. If the included macro includes a ^ macro,
|
||||
then the text between this macro and the end macro will be inserted at
|
||||
the ^ macro.")
|
||||
|
||||
(defmethod srecode-inserter-prin-example :STATIC ((ins srecode-template-inserter-include-wrap)
|
||||
escape-start escape-end)
|
||||
"Insert an example using inserter INS.
|
||||
Arguments ESCAPE-START and ESCAPE-END are the current escape sequences in use."
|
||||
(princ " ")
|
||||
(princ escape-start)
|
||||
(princ "<DICTNAME:contextname:templatename")
|
||||
(princ escape-end)
|
||||
(terpri)
|
||||
(princ " Template Text to insert at ^ macro")
|
||||
(terpri)
|
||||
(princ " ")
|
||||
(princ escape-start)
|
||||
(princ "/DICTNAME")
|
||||
(princ escape-end)
|
||||
(terpri)
|
||||
)
|
||||
|
||||
(defmethod srecode-insert-method ((sti srecode-template-inserter-include-wrap)
|
||||
dictionary)
|
||||
"Insert the template STI.
|
||||
This will first insert the include part via inheritance, then
|
||||
insert the section it wraps into the location in the included
|
||||
template where a ^ inserter occurs."
|
||||
;; Step 1: Look up the included inserter
|
||||
(srecode-insert-include-lookup sti dictionary)
|
||||
;; Step 2: Temporarilly override the point inserter.
|
||||
(let* ((vaguely-unique-name sti)
|
||||
(srecode-template-inserter-point-override
|
||||
(lambda (dict2)
|
||||
(if (srecode-dictionary-lookup-name
|
||||
dict2 (oref vaguely-unique-name :object-name))
|
||||
;; Insert our sectional part with looping.
|
||||
(srecode-insert-method-helper
|
||||
vaguely-unique-name dict2 'template)
|
||||
;; Insert our sectional part just once.
|
||||
(srecode-insert-subtemplate vaguely-unique-name
|
||||
dict2 'template))
|
||||
)))
|
||||
;; Do a regular insertion for an include, but with our override in
|
||||
;; place.
|
||||
(call-next-method)
|
||||
))
|
||||
|
||||
(provide 'srecode/insert)
|
||||
|
||||
;; Local variables:
|
||||
;; generated-autoload-file: "loaddefs.el"
|
||||
;; generated-autoload-feature: srecode/loaddefs
|
||||
;; generated-autoload-load-name: "srecode/insert"
|
||||
;; End:
|
||||
|
||||
;;; srecode/insert.el ends here
|
62
lisp/cedet/srecode/java.el
Normal file
62
lisp/cedet/srecode/java.el
Normal file
|
@ -0,0 +1,62 @@
|
|||
;;; srecode-java.el --- Srecode Java support
|
||||
|
||||
;; Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Eric M. Ludlam <eric@siege-engine.com>
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; Special support for the Java language.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'srecode/dictionary)
|
||||
|
||||
;;;###autoload
|
||||
(defun srecode-semantic-handle-:java (dict)
|
||||
"Add macros into the dictionary DICT based on the current java file.
|
||||
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
|
||||
(let* ((fsym (file-name-nondirectory (buffer-file-name)))
|
||||
(fnox (file-name-sans-extension fsym))
|
||||
(dir (file-name-directory (buffer-file-name)))
|
||||
(fpak fsym)
|
||||
)
|
||||
(while (string-match "\\.\\| " fpak)
|
||||
(setq fpak (replace-match "_" t t fpak)))
|
||||
(if (string-match "src/" dir)
|
||||
(setq dir (substring dir (match-end 0)))
|
||||
(setq dir (file-name-nondirectory (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))
|
||||
(srecode-dictionary-set-value dict "FILENAME_AS_CLASS" fnox)
|
||||
))
|
||||
|
||||
(provide 'srecode/java)
|
||||
|
||||
;; Local variables:
|
||||
;; generated-autoload-file: "loaddefs.el"
|
||||
;; generated-autoload-feature: srecode/loaddefs
|
||||
;; generated-autoload-load-name: "srecode/java"
|
||||
;; End:
|
||||
|
||||
;;; srecode/java.el ends here
|
415
lisp/cedet/srecode/map.el
Normal file
415
lisp/cedet/srecode/map.el
Normal file
|
@ -0,0 +1,415 @@
|
|||
;;; srecode/map.el --- Manage a template file map
|
||||
|
||||
;; Copyright (C) 2008, 2009 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Eric M. Ludlam <eric@siege-engine.com>
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; Read template files, and build a map of where they can be found.
|
||||
;; Save the map to disk, and refer to it when bootstrapping a new
|
||||
;; Emacs session with srecode.
|
||||
|
||||
(require 'semantic)
|
||||
(require 'eieio-base)
|
||||
(require 'srecode)
|
||||
|
||||
;;; Code:
|
||||
|
||||
;; The defcustom is given at the end of the file.
|
||||
(defvar srecode-map-load-path)
|
||||
|
||||
(defun srecode-map-base-template-dir ()
|
||||
"Find the base template directory for SRecode."
|
||||
(let* ((lib (locate-library "srecode.el"))
|
||||
(dir (file-name-directory lib)))
|
||||
(expand-file-name "templates/" dir)
|
||||
))
|
||||
|
||||
;;; Current MAP
|
||||
;;
|
||||
|
||||
(defvar srecode-current-map nil
|
||||
"The current map for global SRecode templtes.")
|
||||
|
||||
(defcustom srecode-map-save-file (expand-file-name "~/.srecode/srecode-map")
|
||||
"The save location for SRecode's map file.
|
||||
If the save file is nil, then the MAP is not saved between sessions."
|
||||
:group 'srecode
|
||||
:type 'file)
|
||||
|
||||
(defclass srecode-map (eieio-persistent)
|
||||
((fileheaderline :initform ";; SRECODE TEMPLATE MAP")
|
||||
(files :initarg :files
|
||||
:initform nil
|
||||
:type list
|
||||
:documentation
|
||||
"An alist of files and the major-mode that they cover.")
|
||||
(apps :initarg :apps
|
||||
:initform nil
|
||||
:type list
|
||||
:documentation
|
||||
"An alist of applications.
|
||||
Each app keys to an alist of files and modes (as above.)")
|
||||
)
|
||||
"A map of srecode templates.")
|
||||
|
||||
(defmethod srecode-map-entry-for-file ((map srecode-map) file)
|
||||
"Return the entry in MAP for FILE."
|
||||
(assoc file (oref map files)))
|
||||
|
||||
(defmethod srecode-map-entries-for-mode ((map srecode-map) mode)
|
||||
"Return the entries in MAP for major MODE."
|
||||
(let ((ans nil))
|
||||
(dolist (f (oref map files))
|
||||
(when (mode-local-use-bindings-p mode (cdr f))
|
||||
(setq ans (cons f ans))))
|
||||
ans))
|
||||
|
||||
(defmethod srecode-map-entry-for-app ((map srecode-map) app)
|
||||
"Return the entry in MAP for APP'lication."
|
||||
(assoc app (oref map apps))
|
||||
)
|
||||
|
||||
(defmethod srecode-map-entries-for-app-and-mode ((map srecode-map) app mode)
|
||||
"Return the entries in MAP for major MODE."
|
||||
(let ((ans nil)
|
||||
(appentry (srecode-map-entry-for-app map app)))
|
||||
(dolist (f (cdr appentry))
|
||||
(when (eq (cdr f) mode)
|
||||
(setq ans (cons f ans))))
|
||||
ans))
|
||||
|
||||
(defmethod srecode-map-entry-for-file-anywhere ((map srecode-map) file)
|
||||
"Search in all entry points in MAP for FILE.
|
||||
Return a list ( APP . FILE-ASSOC ) where APP is nil
|
||||
in the global map."
|
||||
(or
|
||||
;; Look in the global entry
|
||||
(let ((globalentry (srecode-map-entry-for-file map file)))
|
||||
(when globalentry
|
||||
(cons nil globalentry)))
|
||||
;; Look in each app.
|
||||
(let ((match nil))
|
||||
(dolist (app (oref map apps))
|
||||
(let ((appmatch (assoc file (cdr app))))
|
||||
(when appmatch
|
||||
(setq match (cons app appmatch)))))
|
||||
match)
|
||||
;; Other?
|
||||
))
|
||||
|
||||
(defmethod srecode-map-delete-file-entry ((map srecode-map) file)
|
||||
"Update MAP to exclude FILE from the file list."
|
||||
(let ((entry (srecode-map-entry-for-file map file)))
|
||||
(when entry
|
||||
(object-remove-from-list map 'files entry))))
|
||||
|
||||
(defmethod srecode-map-update-file-entry ((map srecode-map) file mode)
|
||||
"Update a MAP entry for FILE to be used with MODE.
|
||||
Return non-nil if the MAP was changed."
|
||||
(let ((entry (srecode-map-entry-for-file map file))
|
||||
(dirty t))
|
||||
(cond
|
||||
;; It is already a match.. do nothing.
|
||||
((and entry (eq (cdr entry) mode))
|
||||
(setq dirty nil))
|
||||
;; We have a non-matching entry. Change the cdr.
|
||||
(entry
|
||||
(setcdr entry mode))
|
||||
;; No entry, just add it to the list.
|
||||
(t
|
||||
(object-add-to-list map 'files (cons file mode))
|
||||
))
|
||||
dirty))
|
||||
|
||||
(defmethod srecode-map-delete-file-entry-from-app ((map srecode-map) file app)
|
||||
"Delete from MAP the FILE entry within the APP'lication."
|
||||
(let* ((appe (srecode-map-entry-for-app map app))
|
||||
(fentry (assoc file (cdr appe))))
|
||||
(setcdr appe (delete fentry (cdr appe))))
|
||||
)
|
||||
|
||||
(defmethod srecode-map-update-app-file-entry ((map srecode-map) file mode app)
|
||||
"Update the MAP entry for FILE to be used with MODE within APP.
|
||||
Return non-nil if the map was changed."
|
||||
(let* ((appentry (srecode-map-entry-for-app map app))
|
||||
(appfileentry (assoc file (cdr appentry)))
|
||||
(dirty t)
|
||||
)
|
||||
(cond
|
||||
;; Option 1 - We have this file in this application already
|
||||
;; with the correct mode.
|
||||
((and appfileentry (eq (cdr appfileentry) mode))
|
||||
(setq dirty nil)
|
||||
)
|
||||
;; Option 2 - We have a non-matching entry. Change Cdr.
|
||||
(appfileentry
|
||||
(setcdr appfileentry mode))
|
||||
(t
|
||||
;; For option 3 & 4 - remove the entry from any other lists
|
||||
;; we can find.
|
||||
(let ((any (srecode-map-entry-for-file-anywhere map file)))
|
||||
(when any
|
||||
(if (null (car any))
|
||||
;; Global map entry
|
||||
(srecode-map-delete-file-entry map file)
|
||||
;; Some app
|
||||
(let ((appentry (srecode-map-entry-for-app map app)))
|
||||
(setcdr appentry (delete (cdr any) (cdr appentry))))
|
||||
)))
|
||||
;; Now do option 3 and 4
|
||||
(cond
|
||||
;; Option 3 - No entry for app. Add to the list.
|
||||
(appentry
|
||||
(setcdr appentry (cons (cons file mode) (cdr appentry)))
|
||||
)
|
||||
;; Option 4 - No app entry. Add app to list with this file.
|
||||
(t
|
||||
(object-add-to-list map 'apps (list app (cons file mode)))
|
||||
)))
|
||||
)
|
||||
dirty))
|
||||
|
||||
|
||||
;;; MAP Updating
|
||||
;;
|
||||
;;;###autoload
|
||||
(defun srecode-get-maps (&optional reset)
|
||||
"Get a list of maps relevant to the current buffer.
|
||||
Optional argument RESET forces a reset of the current map."
|
||||
(interactive "P")
|
||||
;; Always update the map, but only do a full reset if
|
||||
;; the user asks for one.
|
||||
(srecode-map-update-map (not reset))
|
||||
|
||||
(if (interactive-p)
|
||||
;; Dump this map.
|
||||
(with-output-to-temp-buffer "*SRECODE MAP*"
|
||||
(princ " -- SRecode Global map --\n")
|
||||
(srecode-maps-dump-file-list (oref srecode-current-map files))
|
||||
(princ "\n -- Application Maps --\n")
|
||||
(dolist (ap (oref srecode-current-map apps))
|
||||
(let ((app (car ap))
|
||||
(files (cdr ap)))
|
||||
(princ app)
|
||||
(princ " :\n")
|
||||
(srecode-maps-dump-file-list files))
|
||||
(princ "\n"))
|
||||
(princ "\nUse:\n\n M-x customize-variable RET srecode-map-load-path RET")
|
||||
(princ "\n To change the path where SRecode loads templates from.")
|
||||
)
|
||||
;; Eventually, I want to return many maps to search through.
|
||||
(list srecode-current-map)))
|
||||
|
||||
(eval-when-compile (require 'data-debug))
|
||||
|
||||
(defun srecode-adebug-maps ()
|
||||
"Run ADEBUG on the output of `srecode-get-maps'."
|
||||
(interactive)
|
||||
(require 'data-debug)
|
||||
(let ((start (current-time))
|
||||
(p (srecode-get-maps t)) ;; Time the reset.
|
||||
(end (current-time))
|
||||
)
|
||||
(message "Updating the map took %.2f seconds."
|
||||
(semantic-elapsed-time start end))
|
||||
(data-debug-new-buffer "*SRECODE ADEBUG*")
|
||||
(data-debug-insert-stuff-list p "*")))
|
||||
|
||||
(defun srecode-maps-dump-file-list (flist)
|
||||
"Dump a file list FLIST to `standard-output'."
|
||||
(princ "Mode\t\t\tFilename\n")
|
||||
(princ "------\t\t\t------------------\n")
|
||||
(dolist (fe flist)
|
||||
(prin1 (cdr fe))
|
||||
(princ "\t")
|
||||
(when (> (* 2 8) (length (symbol-name (cdr fe))))
|
||||
(princ "\t"))
|
||||
(when (> 8 (length (symbol-name (cdr fe))))
|
||||
(princ "\t"))
|
||||
(princ (car fe))
|
||||
(princ "\n")
|
||||
))
|
||||
|
||||
(defun srecode-map-file-still-valid-p (filename map)
|
||||
"Return t if FILENAME should be in MAP still."
|
||||
(let ((valid nil))
|
||||
(and (file-exists-p filename)
|
||||
(progn
|
||||
(dolist (p srecode-map-load-path)
|
||||
(when (and (< (length p) (length filename))
|
||||
(string= p (substring filename 0 (length p))))
|
||||
(setq valid t))
|
||||
)
|
||||
valid))
|
||||
))
|
||||
|
||||
(defun srecode-map-update-map (&optional fast)
|
||||
"Update the current map from `srecode-map-load-path'.
|
||||
Scans all the files on the path, and makes sure we have entries
|
||||
for them.
|
||||
If option FAST is non-nil, then only parse a file for the mode-string
|
||||
if that file is NEW, otherwise assume the mode has not changed."
|
||||
(interactive)
|
||||
|
||||
;; When no map file, we are configured to not use a save file.
|
||||
(if (not srecode-map-save-file)
|
||||
;; 0) Create a MAP when in no save file mode.
|
||||
(when (not srecode-current-map)
|
||||
(setq srecode-current-map (srecode-map "SRecode Map"))
|
||||
(message "SRecode map created in non-save mode.")
|
||||
)
|
||||
|
||||
;; 1) Do we even have a MAP or save file?
|
||||
(when (and (not srecode-current-map)
|
||||
(not (file-exists-p srecode-map-save-file)))
|
||||
(when (not (file-exists-p (file-name-directory srecode-map-save-file)))
|
||||
;; Only bother with this interactively, not during a build
|
||||
;; or test.
|
||||
(when (not noninteractive)
|
||||
;; No map, make the dir?
|
||||
(if (y-or-n-p (format "Create dir %s? "
|
||||
(file-name-directory srecode-map-save-file)))
|
||||
(make-directory (file-name-directory srecode-map-save-file))
|
||||
;; No make, change save file
|
||||
(customize-variable 'srecode-map-save-file)
|
||||
(error "Change your SRecode map file"))))
|
||||
;; Have a dir. Make the object.
|
||||
(setq srecode-current-map
|
||||
(srecode-map "SRecode Map"
|
||||
:file srecode-map-save-file)))
|
||||
|
||||
;; 2) Do we not have a current map? If so load.
|
||||
(when (not srecode-current-map)
|
||||
(setq srecode-current-map
|
||||
(eieio-persistent-read srecode-map-save-file))
|
||||
)
|
||||
|
||||
)
|
||||
|
||||
;;
|
||||
;; We better have a MAP object now.
|
||||
;;
|
||||
(let ((dirty nil))
|
||||
;; 3) - Purge dead files from the file list.
|
||||
(dolist (entry (copy-sequence (oref srecode-current-map files)))
|
||||
(when (not (srecode-map-file-still-valid-p
|
||||
(car entry) srecode-current-map))
|
||||
(srecode-map-delete-file-entry srecode-current-map (car entry))
|
||||
(setq dirty t)
|
||||
))
|
||||
(dolist (app (copy-sequence (oref srecode-current-map apps)))
|
||||
(dolist (entry (copy-sequence (cdr app)))
|
||||
(when (not (srecode-map-file-still-valid-p
|
||||
(car entry) srecode-current-map))
|
||||
(srecode-map-delete-file-entry-from-app
|
||||
srecode-current-map (car entry) (car app))
|
||||
(setq dirty t)
|
||||
)))
|
||||
;; 4) - Find new files and add them to the map.
|
||||
(dolist (dir srecode-map-load-path)
|
||||
(when (file-exists-p dir)
|
||||
(dolist (f (directory-files dir t "\\.srt$"))
|
||||
(when (and (not (backup-file-name-p f))
|
||||
(not (auto-save-file-name-p f))
|
||||
(file-readable-p f))
|
||||
(let ((fdirty (srecode-map-validate-file-for-mode f fast)))
|
||||
(setq dirty (or dirty fdirty))))
|
||||
)))
|
||||
;; Only do the save if we are dirty, or if we are in an interactive
|
||||
;; Emacs.
|
||||
(when (and dirty (not noninteractive)
|
||||
(slot-boundp srecode-current-map :file))
|
||||
(eieio-persistent-save srecode-current-map))
|
||||
))
|
||||
|
||||
(defun srecode-map-validate-file-for-mode (file fast)
|
||||
"Read and validate FILE via the parser. Return the mode.
|
||||
Argument FAST implies that the file should not be reparsed if there
|
||||
is already an entry for it.
|
||||
Return non-nil if the map changed."
|
||||
(when (or (not fast)
|
||||
(not (srecode-map-entry-for-file-anywhere srecode-current-map file)))
|
||||
(let ((buff-orig (get-file-buffer file))
|
||||
(dirty nil))
|
||||
(save-excursion
|
||||
(if buff-orig
|
||||
(set-buffer buff-orig)
|
||||
(set-buffer (get-buffer-create " *srecode-map-tmp*"))
|
||||
(insert-file-contents file nil nil nil t)
|
||||
;; Force it to be ready to parse.
|
||||
(srecode-template-mode)
|
||||
(let ((semantic-init-hooks nil))
|
||||
(semantic-new-buffer-fcn))
|
||||
)
|
||||
|
||||
(semantic-fetch-tags)
|
||||
(let* ((mode-tag
|
||||
(semantic-find-first-tag-by-name "mode" (current-buffer)))
|
||||
(val nil)
|
||||
(app-tag
|
||||
(semantic-find-first-tag-by-name "application" (current-buffer)))
|
||||
(app nil))
|
||||
(if mode-tag
|
||||
(setq val (car (semantic-tag-variable-default mode-tag)))
|
||||
(error "There should be a mode declaration in %s" file))
|
||||
(when app-tag
|
||||
(setq app (car (semantic-tag-variable-default app-tag))))
|
||||
|
||||
(setq dirty
|
||||
(if app
|
||||
(srecode-map-update-app-file-entry srecode-current-map
|
||||
file
|
||||
(read val)
|
||||
(read app))
|
||||
(srecode-map-update-file-entry srecode-current-map
|
||||
file
|
||||
(read val))))
|
||||
)
|
||||
)
|
||||
dirty)))
|
||||
|
||||
|
||||
;;; THE PATH
|
||||
;;
|
||||
;; We need to do this last since the setter needs the above code.
|
||||
|
||||
(defun srecode-map-load-path-set (sym val)
|
||||
"Set SYM to the new VAL, then update the srecode map."
|
||||
(set-default sym val)
|
||||
(srecode-map-update-map t))
|
||||
|
||||
(defcustom srecode-map-load-path
|
||||
(list (srecode-map-base-template-dir)
|
||||
(expand-file-name "~/.srecode/")
|
||||
)
|
||||
"*Global load path for SRecode template files."
|
||||
:group 'srecode
|
||||
:type '(repeat file)
|
||||
:set 'srecode-map-load-path-set)
|
||||
|
||||
(provide 'srecode/map)
|
||||
|
||||
;; Local variables:
|
||||
;; generated-autoload-file: "loaddefs.el"
|
||||
;; generated-autoload-feature: srecode/loaddefs
|
||||
;; generated-autoload-load-name: "srecode/map"
|
||||
;; End:
|
||||
|
||||
;;; srecode/map.el ends here
|
420
lisp/cedet/srecode/mode.el
Normal file
420
lisp/cedet/srecode/mode.el
Normal file
|
@ -0,0 +1,420 @@
|
|||
;;; srecode/mode.el --- Minor mode for managing and using SRecode templates
|
||||
|
||||
;; Copyright (C) 2008, 2009 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Eric M. Ludlam <eric@siege-engine.com>
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; Minor mode for working with SRecode template files.
|
||||
;;
|
||||
;; Depends on Semantic for minor-mode convenience functions.
|
||||
|
||||
(require 'mode-local)
|
||||
(require 'srecode)
|
||||
(require 'srecode/insert)
|
||||
(require 'srecode/find)
|
||||
(require 'srecode/map)
|
||||
;; (require 'senator)
|
||||
(require 'semantic/decorate)
|
||||
(require 'semantic/wisent)
|
||||
|
||||
(eval-when-compile (require 'semantic/find))
|
||||
|
||||
;;; Code:
|
||||
|
||||
(defcustom global-srecode-minor-mode nil
|
||||
"Non-nil in buffers with Semantic Recoder macro keybindings."
|
||||
:group 'srecode
|
||||
:type 'boolean
|
||||
:require 'srecode-mode
|
||||
:initialize 'custom-initialize-default
|
||||
:set (lambda (sym val)
|
||||
(global-srecode-minor-mode (if val 1 -1))))
|
||||
|
||||
(defvar srecode-minor-mode nil
|
||||
"Non-nil in buffers with Semantic Recoder macro keybindings.")
|
||||
(make-variable-buffer-local 'srecode-minor-mode)
|
||||
|
||||
(defcustom srecode-minor-mode-hook nil
|
||||
"Hook run at the end of the function `srecode-minor-mode'."
|
||||
:group 'srecode
|
||||
:type 'hook)
|
||||
|
||||
;; We don't want to waste space. There is a menu after all.
|
||||
;;(add-to-list 'minor-mode-alist '(srecode-minor-mode ""))
|
||||
|
||||
(defvar srecode-prefix-key [(control ?c) ?/]
|
||||
"The common prefix key in srecode minor mode.")
|
||||
|
||||
(defvar srecode-prefix-map
|
||||
(let ((km (make-sparse-keymap)))
|
||||
;; Basic template codes
|
||||
(define-key km "/" 'srecode-insert)
|
||||
(define-key km [insert] 'srecode-insert)
|
||||
(define-key km "." 'srecode-insert-again)
|
||||
(define-key km "E" 'srecode-edit)
|
||||
;; Template indirect binding
|
||||
(let ((k ?a))
|
||||
(while (<= k ?z)
|
||||
(define-key km (format "%c" k) 'srecode-bind-insert)
|
||||
(setq k (1+ k))))
|
||||
km)
|
||||
"Keymap used behind the srecode prefix key in in srecode minor mode.")
|
||||
|
||||
(defvar srecode-menu-bar
|
||||
(list
|
||||
"SRecoder"
|
||||
(senator-menu-item
|
||||
["Insert Template"
|
||||
srecode-insert
|
||||
:active t
|
||||
:help "Insert a template by name."
|
||||
])
|
||||
(senator-menu-item
|
||||
["Insert Template Again"
|
||||
srecode-insert-again
|
||||
:active t
|
||||
:help "Run the same template as last time again."
|
||||
])
|
||||
(senator-menu-item
|
||||
["Edit Template"
|
||||
srecode-edit
|
||||
:active t
|
||||
:help "Edit a template for this language by name."
|
||||
])
|
||||
"---"
|
||||
'( "Insert ..." :filter srecode-minor-mode-templates-menu )
|
||||
`( "Generate ..." :filter srecode-minor-mode-generate-menu )
|
||||
"---"
|
||||
(senator-menu-item
|
||||
["Customize..."
|
||||
(customize-group "srecode")
|
||||
:active t
|
||||
:help "Customize SRecode options"
|
||||
])
|
||||
(list
|
||||
"Debugging Tools..."
|
||||
(senator-menu-item
|
||||
["Dump Template MAP"
|
||||
srecode-get-maps
|
||||
:active t
|
||||
:help "Calculate (if needed) and display the current template file map."
|
||||
])
|
||||
(senator-menu-item
|
||||
["Dump Tables"
|
||||
srecode-dump-templates
|
||||
:active t
|
||||
:help "Dump the current template table."
|
||||
])
|
||||
(senator-menu-item
|
||||
["Dump Dictionary"
|
||||
srecode-dictionary-dump
|
||||
:active t
|
||||
:help "Calculate a dump a dictionary for point."
|
||||
])
|
||||
)
|
||||
)
|
||||
"Menu for srecode minor mode.")
|
||||
|
||||
(defvar srecode-minor-menu nil
|
||||
"Menu keymap build from `srecode-menu-bar'.")
|
||||
|
||||
(defcustom srecode-takeover-INS-key nil
|
||||
"Use the insert key for inserting templates."
|
||||
:group 'srecode
|
||||
:type 'boolean)
|
||||
|
||||
(defvar srecode-mode-map
|
||||
(let ((km (make-sparse-keymap)))
|
||||
(define-key km srecode-prefix-key srecode-prefix-map)
|
||||
(easy-menu-define srecode-minor-menu km "Srecode Minor Mode Menu"
|
||||
srecode-menu-bar)
|
||||
(when srecode-takeover-INS-key
|
||||
(define-key km [insert] srecode-prefix-map))
|
||||
km)
|
||||
"Keymap for srecode minor mode.")
|
||||
|
||||
;;;###autoload
|
||||
(defun srecode-minor-mode (&optional arg)
|
||||
"Toggle srecode minor mode.
|
||||
With prefix argument ARG, turn on if positive, otherwise off. The
|
||||
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.
|
||||
|
||||
\\{srecode-mode-map}"
|
||||
(interactive
|
||||
(list (or current-prefix-arg
|
||||
(if srecode-minor-mode 0 1))))
|
||||
;; Flip the bits.
|
||||
(setq srecode-minor-mode
|
||||
(if arg
|
||||
(>
|
||||
(prefix-numeric-value arg)
|
||||
0)
|
||||
(not srecode-minor-mode)))
|
||||
;; If we are turning things on, make sure we have templates for
|
||||
;; this mode first.
|
||||
(when srecode-minor-mode
|
||||
(when (not (apply
|
||||
'append
|
||||
(mapcar (lambda (map)
|
||||
(srecode-map-entries-for-mode map major-mode))
|
||||
(srecode-get-maps))))
|
||||
(setq srecode-minor-mode nil))
|
||||
)
|
||||
;; Run hooks if we are turning this on.
|
||||
(when srecode-minor-mode
|
||||
(run-hooks 'srecode-minor-mode-hook))
|
||||
srecode-minor-mode)
|
||||
|
||||
;;;###autoload
|
||||
(defun global-srecode-minor-mode (&optional arg)
|
||||
"Toggle global use of srecode minor mode.
|
||||
If ARG is positive, enable, if it is negative, disable.
|
||||
If ARG is nil, then toggle."
|
||||
(interactive "P")
|
||||
(setq global-srecode-minor-mode
|
||||
(semantic-toggle-minor-mode-globally
|
||||
'srecode-minor-mode arg)))
|
||||
|
||||
;; Use the semantic minor mode magic stuff.
|
||||
(semantic-add-minor-mode 'srecode-minor-mode "" srecode-mode-map)
|
||||
|
||||
;;; Menu Filters
|
||||
;;
|
||||
(defun srecode-minor-mode-templates-menu (menu-def)
|
||||
"Create a menu item of cascading filters active for this mode.
|
||||
MENU-DEF is the menu to bind this into."
|
||||
;; Doing this SEGVs Emacs on windows.
|
||||
;;(srecode-load-tables-for-mode major-mode)
|
||||
|
||||
(let* ((modetable (srecode-get-mode-table major-mode))
|
||||
(subtab (when modetable (oref modetable :tables)))
|
||||
(context nil)
|
||||
(active nil)
|
||||
(ltab nil)
|
||||
(temp nil)
|
||||
(alltabs nil)
|
||||
)
|
||||
(if (not subtab)
|
||||
;; No tables, show a "load the tables" option.
|
||||
(list (vector "Load Mode Tables..."
|
||||
(lambda ()
|
||||
(interactive)
|
||||
(srecode-load-tables-for-mode major-mode))
|
||||
))
|
||||
;; Build something
|
||||
(setq context (car-safe (srecode-calculate-context)))
|
||||
|
||||
(while subtab
|
||||
(setq ltab (oref (car subtab) templates))
|
||||
(while ltab
|
||||
(setq temp (car ltab))
|
||||
|
||||
;; Do something with this template.
|
||||
|
||||
(let* ((ctxt (oref temp context))
|
||||
(ctxtcons (assoc ctxt alltabs))
|
||||
(bind (if (slot-boundp temp 'binding)
|
||||
(oref temp binding)))
|
||||
(name (object-name-string temp)))
|
||||
|
||||
(when (not ctxtcons)
|
||||
(if (string= context ctxt)
|
||||
;; If this context is not in the current list of contexts
|
||||
;; is equal to the current context, then manage the
|
||||
;; active list instead
|
||||
(setq active
|
||||
(setq ctxtcons (or active (cons ctxt nil))))
|
||||
;; This is not an active context, add it to alltabs.
|
||||
(setq ctxtcons (cons ctxt nil))
|
||||
(setq alltabs (cons ctxtcons alltabs))))
|
||||
|
||||
(let ((new (vector
|
||||
(if bind
|
||||
(concat name " (" bind ")")
|
||||
name)
|
||||
`(lambda () (interactive)
|
||||
(srecode-insert (concat ,ctxt ":" ,name)))
|
||||
t)))
|
||||
|
||||
(setcdr ctxtcons (cons
|
||||
new
|
||||
(cdr ctxtcons)))))
|
||||
|
||||
(setq ltab (cdr ltab)))
|
||||
(setq subtab (cdr subtab)))
|
||||
|
||||
;; Now create the menu
|
||||
(easy-menu-filter-return
|
||||
(easy-menu-create-menu
|
||||
"Semantic Recoder Filters"
|
||||
(append (cdr active)
|
||||
alltabs)
|
||||
))
|
||||
)))
|
||||
|
||||
(defvar srecode-minor-mode-generators nil
|
||||
"List of code generators to be displayed in the srecoder menu.")
|
||||
|
||||
(defun srecode-minor-mode-generate-menu (menu-def)
|
||||
"Create a menu item of cascading filters active for this mode.
|
||||
MENU-DEF is the menu to bind this into."
|
||||
;; Doing this SEGVs Emacs on windows.
|
||||
;;(srecode-load-tables-for-mode major-mode)
|
||||
(let ((allgeneratorapps nil))
|
||||
|
||||
(dolist (gen srecode-minor-mode-generators)
|
||||
(setq allgeneratorapps
|
||||
(cons (vector (cdr gen) (car gen))
|
||||
allgeneratorapps))
|
||||
(message "Adding %S to srecode menu" (car gen))
|
||||
)
|
||||
|
||||
(easy-menu-filter-return
|
||||
(easy-menu-create-menu
|
||||
"Semantic Recoder Generate Filters"
|
||||
allgeneratorapps)))
|
||||
)
|
||||
|
||||
;;; Minor Mode commands
|
||||
;;
|
||||
(defun srecode-bind-insert ()
|
||||
"Bound insert for Srecode macros.
|
||||
This command will insert whichever srecode template has a binding
|
||||
to the current key."
|
||||
(interactive)
|
||||
(let* ((k last-command-event)
|
||||
(ctxt (srecode-calculate-context))
|
||||
;; Find the template with the binding K
|
||||
(template (srecode-template-get-table-for-binding
|
||||
(srecode-table) k ctxt)))
|
||||
;; test it.
|
||||
(when (not template)
|
||||
(error "No template bound to %c" k))
|
||||
;; insert
|
||||
(srecode-insert template)
|
||||
))
|
||||
|
||||
(defun srecode-edit (template-name)
|
||||
"Switch to the template buffer for TEMPLATE-NAME.
|
||||
Template is chosen based on the mode of the starting buffer."
|
||||
;; @todo - Get a template stack from the last run template, and show
|
||||
;; those too!
|
||||
(interactive (list (srecode-read-template-name
|
||||
"Template Name: "
|
||||
(car srecode-read-template-name-history))))
|
||||
(if (not (srecode-table))
|
||||
(error "No template table found for mode %s" major-mode))
|
||||
(let ((temp (srecode-template-get-table (srecode-table) template-name)))
|
||||
(if (not temp)
|
||||
(error "No Template named %s" template-name))
|
||||
;; We need a template specific table, since tables chain.
|
||||
(let ((tab (oref temp :table))
|
||||
(names nil)
|
||||
)
|
||||
(find-file (oref tab :file))
|
||||
(setq names (semantic-find-tags-by-name (oref temp :object-name)
|
||||
(current-buffer)))
|
||||
(cond ((= (length names) 1)
|
||||
(semantic-go-to-tag (car names))
|
||||
(semantic-momentary-highlight-tag (car names)))
|
||||
((> (length names) 1)
|
||||
(let* ((ctxt (semantic-find-tags-by-name (oref temp :context)
|
||||
(current-buffer)))
|
||||
(cls (semantic-find-tags-by-class 'context ctxt))
|
||||
)
|
||||
(while (and names
|
||||
(< (semantic-tag-start (car names))
|
||||
(semantic-tag-start (car cls))))
|
||||
(setq names (cdr names)))
|
||||
(if names
|
||||
(progn
|
||||
(semantic-go-to-tag (car names))
|
||||
(semantic-momentary-highlight-tag (car names)))
|
||||
(error "Can't find template %s" template-name))
|
||||
))
|
||||
(t (error "Can't find template %s" template-name)))
|
||||
)))
|
||||
|
||||
(defun srecode-add-code-generator (function name &optional binding)
|
||||
"Add the srecoder code generator FUNCTION with NAME to the menu.
|
||||
Optional BINDING specifies the keybinding to use in the srecoder map.
|
||||
BINDING should be a capital letter. Lower case letters are reserved
|
||||
for individual templates.
|
||||
Optional MODE specifies a major mode this function applies to.
|
||||
Do not specify a mode if this function could be applied to most
|
||||
programming modes."
|
||||
;; Update the menu generating part.
|
||||
(let ((remloop nil))
|
||||
(while (setq remloop (assoc function srecode-minor-mode-generators))
|
||||
(setq srecode-minor-mode-generators
|
||||
(remove remloop srecode-minor-mode-generators))))
|
||||
|
||||
(add-to-list 'srecode-minor-mode-generators
|
||||
(cons function name))
|
||||
|
||||
;; Remove this function from any old bindings.
|
||||
(when binding
|
||||
(let ((oldkey (where-is-internal function
|
||||
(list srecode-prefix-map)
|
||||
t t t)))
|
||||
(if (or (not oldkey)
|
||||
(and (= (length oldkey) 1)
|
||||
(= (length binding) 1)
|
||||
(= (aref oldkey 0) (aref binding 0))))
|
||||
;; Its the same.
|
||||
nil
|
||||
;; Remove the old binding
|
||||
(define-key srecode-prefix-map oldkey nil)
|
||||
)))
|
||||
|
||||
;; Update Keybings
|
||||
(let ((oldbinding (lookup-key srecode-prefix-map binding)))
|
||||
|
||||
;; During development, allow overrides.
|
||||
(when (and oldbinding
|
||||
(not (eq oldbinding function))
|
||||
(or (eq this-command 'eval-defun) (eq this-command 'checkdoc-eval-defun))
|
||||
(y-or-n-p (format "Override old binding %s? " oldbinding)))
|
||||
(setq oldbinding nil))
|
||||
|
||||
(if (not oldbinding)
|
||||
(define-key srecode-prefix-map binding function)
|
||||
(if (eq function oldbinding)
|
||||
nil
|
||||
;; Not the same.
|
||||
(message "Conflict binding %S binding to srecode map."
|
||||
binding))))
|
||||
)
|
||||
|
||||
;; Add default code generators:
|
||||
(srecode-add-code-generator 'srecode-document-insert-comment "Comments" "C")
|
||||
(srecode-add-code-generator 'srecode-insert-getset "Get/Set" "G")
|
||||
|
||||
(provide 'srecode/mode)
|
||||
|
||||
;; Local variables:
|
||||
;; generated-autoload-file: "loaddefs.el"
|
||||
;; generated-autoload-feature: srecode/loaddefs
|
||||
;; generated-autoload-load-name: "srecode/mode"
|
||||
;; End:
|
||||
|
||||
;;; srecode/mode.el ends here
|
431
lisp/cedet/srecode/semantic.el
Normal file
431
lisp/cedet/srecode/semantic.el
Normal file
|
@ -0,0 +1,431 @@
|
|||
;;; srecode/semantic.el --- Semantic specific extensions to SRecode.
|
||||
|
||||
;; Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Eric M. Ludlam <eric@siege-engine.com>
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; Semantic specific extensions to the Semantic Recoder.
|
||||
;;
|
||||
;; I realize it is the "Semantic Recoder", but most of srecode
|
||||
;; is a template library and set of user interfaces unrelated to
|
||||
;; semantic in the specific.
|
||||
;;
|
||||
;; This file defines the following:
|
||||
;; - :tag argument handling.
|
||||
;; - <more goes here>
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'srecode/insert)
|
||||
(require 'srecode/dictionary)
|
||||
(require 'semantic/find)
|
||||
(require 'semantic/format)
|
||||
(require 'ring)
|
||||
;;(require 'senator)
|
||||
|
||||
|
||||
;;; The SEMANTIC TAG inserter
|
||||
;;
|
||||
;; Put a tag into the dictionary that can be used w/ arbitrary
|
||||
;; lisp expressions.
|
||||
|
||||
(defclass srecode-semantic-tag (srecode-dictionary-compound-value)
|
||||
((prime :initarg :prime
|
||||
:type semantic-tag
|
||||
:documentation
|
||||
"This is the primary insertion tag.")
|
||||
)
|
||||
"Wrap up a collection of semantic tag information.
|
||||
This class will be used to derive dictionary values.")
|
||||
|
||||
(defmethod srecode-compound-toString((cp srecode-semantic-tag)
|
||||
function
|
||||
dictionary)
|
||||
"Convert the compound dictionary value CP to a string.
|
||||
If FUNCTION is non-nil, then FUNCTION is somehow applied to an
|
||||
aspect of the compound value."
|
||||
(if (not function)
|
||||
;; Just format it in some handy dandy way.
|
||||
(semantic-format-tag-prototype (oref cp :prime))
|
||||
;; Otherwise, apply the function to the tag itself.
|
||||
(funcall function (oref cp :prime))
|
||||
))
|
||||
|
||||
|
||||
;;; Managing the `current' tag
|
||||
;;
|
||||
|
||||
(defvar srecode-semantic-selected-tag nil
|
||||
"The tag selected by a :tag template argument.
|
||||
If this is nil, then `senator-tag-ring' is used.")
|
||||
|
||||
(defun srecode-semantic-tag-from-kill-ring ()
|
||||
"Create an `srecode-semantic-tag' from the senator kill ring."
|
||||
(if (ring-empty-p senator-tag-ring)
|
||||
(error "You must use `senator-copy-tag' to provide a tag to this template"))
|
||||
(ring-ref senator-tag-ring 0))
|
||||
|
||||
|
||||
;;; TAG in a DICTIONARY
|
||||
;;
|
||||
(defvar srecode-semantic-apply-tag-augment-hook nil
|
||||
"A function called for each tag added to a dictionary.
|
||||
The hook is called with two arguments, the TAG and DICT
|
||||
to be augmented.")
|
||||
|
||||
(define-overload srecode-semantic-apply-tag-to-dict (tagobj dict)
|
||||
"Insert fewatures of TAGOBJ into the dictionary DICT.
|
||||
TAGOBJ is an object of class `srecode-semantic-tag'. This class
|
||||
is a compound inserter value.
|
||||
DICT is a dictionary object.
|
||||
At a minimum, this function will create dictionary macro for NAME.
|
||||
It is also likely to create macros for TYPE (data type), function arguments,
|
||||
variable default values, and other things."
|
||||
)
|
||||
|
||||
(defun srecode-semantic-apply-tag-to-dict-default (tagobj dict)
|
||||
"Insert features of TAGOBJ into dictionary DICT."
|
||||
;; Store the sst into the dictionary.
|
||||
(srecode-dictionary-set-value dict "TAG" tagobj)
|
||||
|
||||
;; Pull out the tag for the individual pieces.
|
||||
(let ((tag (oref tagobj :prime)))
|
||||
|
||||
(srecode-dictionary-set-value dict "NAME" (semantic-tag-name tag))
|
||||
(srecode-dictionary-set-value dict "TYPE" (semantic-format-tag-type tag nil))
|
||||
|
||||
(run-hook-with-args 'srecode-semantic-apply-tag-augment-hook tag dict)
|
||||
|
||||
(cond
|
||||
;;
|
||||
;; FUNCTION
|
||||
;;
|
||||
((eq (semantic-tag-class tag) 'function)
|
||||
;; FCN ARGS
|
||||
(let ((args (semantic-tag-function-arguments tag)))
|
||||
(while args
|
||||
(let ((larg (car args))
|
||||
(subdict (srecode-dictionary-add-section-dictionary
|
||||
dict "ARGS")))
|
||||
;; Clean up elements in the arg list.
|
||||
(if (stringp larg)
|
||||
(setq larg (semantic-tag-new-variable
|
||||
larg nil nil)))
|
||||
;; Apply the sub-argument to the subdictionary.
|
||||
(srecode-semantic-apply-tag-to-dict
|
||||
(srecode-semantic-tag (semantic-tag-name larg)
|
||||
:prime larg)
|
||||
subdict)
|
||||
)
|
||||
;; Next!
|
||||
(setq args (cdr args))))
|
||||
;; PARENTS
|
||||
(let ((p (semantic-tag-function-parent tag)))
|
||||
(when p
|
||||
(srecode-dictionary-set-value dict "PARENT" p)
|
||||
))
|
||||
;; EXCEPTIONS (java/c++)
|
||||
(let ((exceptions (semantic-tag-get-attribute tag :throws)))
|
||||
(while exceptions
|
||||
(let ((subdict (srecode-dictionary-add-section-dictionary
|
||||
dict "THROWS")))
|
||||
(srecode-dictionary-set-value subdict "NAME" (car exceptions))
|
||||
)
|
||||
(setq exceptions (cdr exceptions)))
|
||||
)
|
||||
)
|
||||
;;
|
||||
;; VARIABLE
|
||||
;;
|
||||
((eq (semantic-tag-class tag) 'variable)
|
||||
(when (semantic-tag-variable-default tag)
|
||||
(let ((subdict (srecode-dictionary-add-section-dictionary
|
||||
dict "HAVEDEFAULT")))
|
||||
(srecode-dictionary-set-value
|
||||
subdict "VALUE" (semantic-tag-variable-default tag))))
|
||||
)
|
||||
;;
|
||||
;; TYPE
|
||||
;;
|
||||
((eq (semantic-tag-class tag) 'type)
|
||||
(dolist (p (semantic-tag-type-superclasses tag))
|
||||
(let ((sd (srecode-dictionary-add-section-dictionary
|
||||
dict "PARENTS")))
|
||||
(srecode-dictionary-set-value sd "NAME" p)
|
||||
))
|
||||
(dolist (i (semantic-tag-type-interfaces tag))
|
||||
(let ((sd (srecode-dictionary-add-section-dictionary
|
||||
dict "INTERFACES")))
|
||||
(srecode-dictionary-set-value sd "NAME" i)
|
||||
))
|
||||
; NOTE : The members are too complicated to do via a template.
|
||||
; do it via the insert-tag solution instead.
|
||||
;
|
||||
; (dolist (mem (semantic-tag-type-members tag))
|
||||
; (let ((subdict (srecode-dictionary-add-section-dictionary
|
||||
; dict "MEMBERS")))
|
||||
; (when (stringp mem)
|
||||
; (setq mem (semantic-tag-new-variable mem nil nil)))
|
||||
; (srecode-semantic-apply-tag-to-dict
|
||||
; (srecode-semantic-tag (semantic-tag-name mem)
|
||||
; :prime mem)
|
||||
; subdict)))
|
||||
))))
|
||||
|
||||
|
||||
;;; ARGUMENT HANDLERS
|
||||
|
||||
;;; :tag ARGUMENT HANDLING
|
||||
;;
|
||||
;; When a :tag argument is required, identify the current :tag,
|
||||
;; and apply it's parts into the dictionary.
|
||||
(defun srecode-semantic-handle-:tag (dict)
|
||||
"Add macroes into the dictionary DICT based on the current :tag."
|
||||
;; We have a tag, start adding "stuff" into the dictionary.
|
||||
(let ((tag (or srecode-semantic-selected-tag
|
||||
(srecode-semantic-tag-from-kill-ring))))
|
||||
(when (not tag)
|
||||
"No tag for current template. Use the semantic kill-ring.")
|
||||
(srecode-semantic-apply-tag-to-dict
|
||||
(srecode-semantic-tag (semantic-tag-name tag)
|
||||
:prime tag)
|
||||
dict)))
|
||||
|
||||
;;; :tagtype ARGUMENT HANDLING
|
||||
;;
|
||||
;; When a :tagtype argument is required, identify the current tag, of
|
||||
;; cf class 'type. Apply those parameters to the dictionary.
|
||||
|
||||
(defun srecode-semantic-handle-:tagtype (dict)
|
||||
"Add macroes into the dictionary DICT based on a tag of class type at point.
|
||||
Assumes the cursor is in a tag of class type. If not, throw an error."
|
||||
(let ((typetag (or srecode-semantic-selected-tag
|
||||
(semantic-current-tag-of-class 'type))))
|
||||
(when (not typetag)
|
||||
(error "Cursor is not in a TAG of class 'type"))
|
||||
(srecode-semantic-apply-tag-to-dict
|
||||
typetag
|
||||
dict)))
|
||||
|
||||
|
||||
;;; INSERT A TAG API
|
||||
;;
|
||||
;; Routines that take a tag, and insert into a buffer.
|
||||
(define-overload srecode-semantic-find-template (class prototype ctxt)
|
||||
"Find a template for a tag of class CLASS based on context.
|
||||
PROTOTYPE is non-nil if we want a prototype template instead."
|
||||
)
|
||||
|
||||
(defun srecode-semantic-find-template-default (class prototype ctxt)
|
||||
"Find a template for tag CLASS based on context.
|
||||
PROTOTYPE is non-nil if we need a prototype.
|
||||
CTXT is the pre-calculated context."
|
||||
(let* ((top (car ctxt))
|
||||
(tname (if (stringp class)
|
||||
class
|
||||
(symbol-name class)))
|
||||
(temp nil)
|
||||
)
|
||||
;; Try to find a template.
|
||||
(setq temp (or
|
||||
(when prototype
|
||||
(srecode-template-get-table (srecode-table)
|
||||
(concat tname "-tag-prototype")
|
||||
top))
|
||||
(when prototype
|
||||
(srecode-template-get-table (srecode-table)
|
||||
(concat tname "-prototype")
|
||||
top))
|
||||
(srecode-template-get-table (srecode-table)
|
||||
(concat tname "-tag")
|
||||
top)
|
||||
(srecode-template-get-table (srecode-table)
|
||||
tname
|
||||
top)
|
||||
(when (and (not (string= top "declaration"))
|
||||
prototype)
|
||||
(srecode-template-get-table (srecode-table)
|
||||
(concat tname "-prototype")
|
||||
"declaration"))
|
||||
(when (and (not (string= top "declaration"))
|
||||
prototype)
|
||||
(srecode-template-get-table (srecode-table)
|
||||
(concat tname "-tag-prototype")
|
||||
"declaration"))
|
||||
(when (not (string= top "declaration"))
|
||||
(srecode-template-get-table (srecode-table)
|
||||
(concat tname "-tag")
|
||||
"declaration"))
|
||||
(when (not (string= top "declaration"))
|
||||
(srecode-template-get-table (srecode-table)
|
||||
tname
|
||||
"declaration"))
|
||||
))
|
||||
temp))
|
||||
|
||||
(defun srecode-semantic-insert-tag (tag &optional style-option
|
||||
point-insert-fcn
|
||||
&rest dict-entries)
|
||||
"Insert TAG into a buffer useing srecode templates at point.
|
||||
|
||||
Optional STYLE-OPTION is a list of minor configuration of styles,
|
||||
such as the symbol 'prototype for prototype functions, or
|
||||
'system for system includes, and 'doxygen, for a doxygen style
|
||||
comment.
|
||||
|
||||
Optional third argument POINT-INSERT-FCN is a hook that is run after
|
||||
TAG is inserted that allows an opportunity to fill in the body of
|
||||
some thing. This hook function is called with one argument, the TAG
|
||||
being inserted.
|
||||
|
||||
The rest of the arguments are DICT-ENTRIES. DICT-ENTRIES
|
||||
is of the form ( NAME1 VALUE1 NAME2 VALUE2 ... NAMEn VALUEn).
|
||||
|
||||
The exact template used is based on the current context.
|
||||
The template used is found within the toplevel context as calculated
|
||||
by `srecode-calculate-context', such as `declaration', `classdecl',
|
||||
or `code'.
|
||||
|
||||
For various conditions, this function looks for a template with
|
||||
the name CLASS-tag, where CLASS is the tag class. If it cannot
|
||||
find that, it will look for that template in the
|
||||
`declaration'context (if the current context was not `declaration').
|
||||
|
||||
If PROTOTYPE is specified, it will first look for templates with
|
||||
the name CLASS-tag-prototype, or CLASS-prototype as above.
|
||||
|
||||
See `srecode-semantic-apply-tag-to-dict' for details on what is in
|
||||
the dictionary when the templates are called.
|
||||
|
||||
This function returns to location in the buffer where the
|
||||
inserted tag ENDS, and will leave point inside the inserted
|
||||
text based on any occurance of a point-inserter. Templates such
|
||||
as `function' will leave point where code might be inserted."
|
||||
(srecode-load-tables-for-mode major-mode)
|
||||
(let* ((ctxt (srecode-calculate-context))
|
||||
(top (car ctxt))
|
||||
(tname (symbol-name (semantic-tag-class tag)))
|
||||
(dict (srecode-create-dictionary))
|
||||
(temp nil)
|
||||
(errtype tname)
|
||||
(prototype (memq 'prototype style-option))
|
||||
)
|
||||
;; Try some special cases.
|
||||
(cond ((and (semantic-tag-of-class-p tag 'function)
|
||||
(semantic-tag-get-attribute tag :constructor-flag))
|
||||
(setq temp (srecode-semantic-find-template
|
||||
"constructor" prototype ctxt))
|
||||
)
|
||||
|
||||
((and (semantic-tag-of-class-p tag 'function)
|
||||
(semantic-tag-get-attribute tag :destructor-flag))
|
||||
(setq temp (srecode-semantic-find-template
|
||||
"destructor" prototype ctxt))
|
||||
)
|
||||
|
||||
((and (semantic-tag-of-class-p tag 'function)
|
||||
(semantic-tag-function-parent tag))
|
||||
(setq temp (srecode-semantic-find-template
|
||||
"method" prototype ctxt))
|
||||
)
|
||||
|
||||
((and (semantic-tag-of-class-p tag 'variable)
|
||||
(semantic-tag-get-attribute tag :constant-flag))
|
||||
(setq temp (srecode-semantic-find-template
|
||||
"variable-const" prototype ctxt))
|
||||
)
|
||||
)
|
||||
|
||||
(when (not temp)
|
||||
;; Try the basics
|
||||
(setq temp (srecode-semantic-find-template
|
||||
tname prototype ctxt)))
|
||||
|
||||
;; Try some backup template names.
|
||||
(when (not temp)
|
||||
(cond
|
||||
;; Types might split things up based on the type's type.
|
||||
((and (eq (semantic-tag-class tag) 'type)
|
||||
(semantic-tag-type tag))
|
||||
(setq temp (srecode-semantic-find-template
|
||||
(semantic-tag-type tag) prototype ctxt))
|
||||
(setq errtype (concat errtype " or " (semantic-tag-type tag)))
|
||||
)
|
||||
;; A function might be an externally declared method.
|
||||
((and (eq (semantic-tag-class tag) 'function)
|
||||
(semantic-tag-function-parent tag))
|
||||
(setq temp (srecode-semantic-find-template
|
||||
"method" prototype ctxt)))
|
||||
(t
|
||||
nil)
|
||||
))
|
||||
|
||||
;; Can't find one? Drat!
|
||||
(when (not temp)
|
||||
(error "Cannot find template %s in %s for inserting tag %S"
|
||||
errtype top (semantic-format-tag-summarize tag)))
|
||||
|
||||
;; Resolve Arguments
|
||||
(let ((srecode-semantic-selected-tag tag))
|
||||
(srecode-resolve-arguments temp dict))
|
||||
|
||||
;; Resolve TAG into the dictionary. We may have a :tag arg
|
||||
;; from the macro such that we don't need to do this.
|
||||
(when (not (srecode-dictionary-lookup-name dict "TAG"))
|
||||
(let ((tagobj (srecode-semantic-tag (semantic-tag-name tag) :prime tag))
|
||||
)
|
||||
(srecode-semantic-apply-tag-to-dict tagobj dict)))
|
||||
|
||||
;; Insert dict-entries into the dictionary LAST so that previous
|
||||
;; items can be overriden.
|
||||
(let ((entries dict-entries))
|
||||
(while entries
|
||||
(srecode-dictionary-set-value dict
|
||||
(car entries)
|
||||
(car (cdr entries)))
|
||||
(setq entries (cdr (cdr entries)))))
|
||||
|
||||
;; Insert the template.
|
||||
(let ((endpt (srecode-insert-fcn temp dict nil t)))
|
||||
|
||||
(run-hook-with-args 'point-insert-fcn tag)
|
||||
;;(sit-for 1)
|
||||
|
||||
(cond
|
||||
((semantic-tag-of-class-p tag 'type)
|
||||
;; Insert all the members at the current insertion point.
|
||||
(dolist (m (semantic-tag-type-members tag))
|
||||
|
||||
(when (stringp m)
|
||||
(setq m (semantic-tag-new-variable m nil nil)))
|
||||
|
||||
;; We do prototypes w/in the class decl?
|
||||
(let ((me (srecode-semantic-insert-tag m '(prototype))))
|
||||
(goto-char me))
|
||||
|
||||
))
|
||||
)
|
||||
|
||||
endpt)
|
||||
))
|
||||
|
||||
(provide 'srecode/semantic)
|
||||
|
||||
;;; srecode/semantic.el ends here
|
775
lisp/cedet/srecode/srt-mode.el
Normal file
775
lisp/cedet/srecode/srt-mode.el
Normal file
|
@ -0,0 +1,775 @@
|
|||
;;; srecode/srt-mode.el --- Major mode for writing screcode macros
|
||||
|
||||
;; Copyright (C) 2005, 2007, 2008, 2009 Free Software Foundation, Inc.
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; Originally named srecode-template-mode.el in the CEDET repository.
|
||||
|
||||
(require 'srecode/compile)
|
||||
(require 'srecode/ctxt)
|
||||
(require 'srecode/template)
|
||||
|
||||
(require 'semantic)
|
||||
(require 'semantic/analyze)
|
||||
(require 'semantic/wisent)
|
||||
(eval-when-compile
|
||||
(require 'semantic/find))
|
||||
|
||||
(declare-function srecode-create-dictionary "srecode/dictionary")
|
||||
(declare-function srecode-resolve-argument-list "srecode/insert")
|
||||
|
||||
;;; Code:
|
||||
(defvar srecode-template-mode-syntax-table
|
||||
(let ((table (make-syntax-table (standard-syntax-table))))
|
||||
(modify-syntax-entry ?\; ". 12" table) ;; SEMI, Comment start ;;
|
||||
(modify-syntax-entry ?\n ">" table) ;; Comment end
|
||||
(modify-syntax-entry ?$ "." table) ;; Punctuation
|
||||
(modify-syntax-entry ?: "." table) ;; Punctuation
|
||||
(modify-syntax-entry ?< "." table) ;; Punctuation
|
||||
(modify-syntax-entry ?> "." table) ;; Punctuation
|
||||
(modify-syntax-entry ?# "." table) ;; Punctuation
|
||||
(modify-syntax-entry ?! "." table) ;; Punctuation
|
||||
(modify-syntax-entry ?? "." table) ;; Punctuation
|
||||
(modify-syntax-entry ?\" "\"" table) ;; String
|
||||
(modify-syntax-entry ?\- "_" table) ;; Symbol
|
||||
(modify-syntax-entry ?\\ "\\" table) ;; Quote
|
||||
(modify-syntax-entry ?\` "'" table) ;; Prefix ` (backquote)
|
||||
(modify-syntax-entry ?\' "'" table) ;; Prefix ' (quote)
|
||||
(modify-syntax-entry ?\, "'" table) ;; Prefix , (comma)
|
||||
|
||||
table)
|
||||
"Syntax table used in semantic recoder macro buffers.")
|
||||
|
||||
(defface srecode-separator-face
|
||||
'((t (:weight bold :strike-through t)))
|
||||
"Face used for decorating separators in srecode template mode."
|
||||
:group 'srecode)
|
||||
|
||||
(defvar srecode-font-lock-keywords
|
||||
'(
|
||||
;; Template
|
||||
("^\\(template\\)\\s-+\\(\\w*\\)\\(\\( \\(:\\w+\\)\\|\\)+\\)$"
|
||||
(1 font-lock-keyword-face)
|
||||
(2 font-lock-function-name-face)
|
||||
(3 font-lock-builtin-face ))
|
||||
("^\\(sectiondictionary\\)\\s-+\""
|
||||
(1 font-lock-keyword-face))
|
||||
("^\\(bind\\)\\s-+\""
|
||||
(1 font-lock-keyword-face))
|
||||
;; Variable type setting
|
||||
("^\\(set\\)\\s-+\\(\\w+\\)\\s-+"
|
||||
(1 font-lock-keyword-face)
|
||||
(2 font-lock-variable-name-face))
|
||||
("^\\(show\\)\\s-+\\(\\w+\\)\\s-*$"
|
||||
(1 font-lock-keyword-face)
|
||||
(2 font-lock-variable-name-face))
|
||||
("\\<\\(macro\\)\\s-+\""
|
||||
(1 font-lock-keyword-face))
|
||||
;; Context type setting
|
||||
("^\\(context\\)\\s-+\\(\\w+\\)"
|
||||
(1 font-lock-keyword-face)
|
||||
(2 font-lock-builtin-face))
|
||||
;; Prompting setting
|
||||
("^\\(prompt\\)\\s-+\\(\\w+\\)"
|
||||
(1 font-lock-keyword-face)
|
||||
(2 font-lock-variable-name-face))
|
||||
("\\(default\\(macro\\)?\\)\\s-+\\(\\(\\w\\|\\s_\\)+\\)"
|
||||
(1 font-lock-keyword-face)
|
||||
(3 font-lock-type-face))
|
||||
("\\<\\(default\\(macro\\)?\\)\\>" (1 font-lock-keyword-face))
|
||||
("\\<\\(read\\)\\s-+\\(\\(\\w\\|\\s_\\)+\\)"
|
||||
(1 font-lock-keyword-face)
|
||||
(2 font-lock-type-face))
|
||||
|
||||
;; Macro separators
|
||||
("^----\n" 0 'srecode-separator-face)
|
||||
|
||||
;; Macro Matching
|
||||
(srecode-template-mode-macro-escape-match 1 font-lock-string-face)
|
||||
((lambda (limit)
|
||||
(srecode-template-mode-font-lock-macro-helper
|
||||
limit "\\(\\??\\w+\\)[^ \t\n{}$#@&*()]*"))
|
||||
1 font-lock-variable-name-face)
|
||||
((lambda (limit)
|
||||
(srecode-template-mode-font-lock-macro-helper
|
||||
limit "\\([#/]\\w+\\)[^ \t\n{}$#@&*()]*"))
|
||||
1 font-lock-keyword-face)
|
||||
((lambda (limit)
|
||||
(srecode-template-mode-font-lock-macro-helper
|
||||
limit "\\([<>]\\w*\\):\\(\\w+\\):\\(\\w+\\)"))
|
||||
(1 font-lock-keyword-face)
|
||||
(2 font-lock-builtin-face)
|
||||
(3 font-lock-type-face))
|
||||
((lambda (limit)
|
||||
(srecode-template-mode-font-lock-macro-helper
|
||||
limit "\\([<>?]?\\w*\\):\\(\\w+\\)"))
|
||||
(1 font-lock-keyword-face)
|
||||
(2 font-lock-type-face))
|
||||
((lambda (limit)
|
||||
(srecode-template-mode-font-lock-macro-helper
|
||||
limit "!\\([^{}$]*\\)"))
|
||||
1 font-lock-comment-face)
|
||||
|
||||
)
|
||||
"Keywords for use with srecode macros and font-lock.")
|
||||
|
||||
(defun srecode-template-mode-font-lock-macro-helper (limit expression)
|
||||
"Match against escape characters.
|
||||
Don't scan past LIMIT. Match with EXPRESSION."
|
||||
(let* ((done nil)
|
||||
(md nil)
|
||||
(es (regexp-quote (srecode-template-get-escape-start)))
|
||||
(ee (regexp-quote (srecode-template-get-escape-end)))
|
||||
(regex (concat es expression ee))
|
||||
)
|
||||
(while (not done)
|
||||
(save-match-data
|
||||
(if (re-search-forward regex limit t)
|
||||
(when (equal (car (srecode-calculate-context)) "code")
|
||||
(setq md (match-data)
|
||||
done t))
|
||||
(setq done t))))
|
||||
(set-match-data md)
|
||||
;; (when md (message "Found a match!"))
|
||||
(when md t)))
|
||||
|
||||
(defun srecode-template-mode-macro-escape-match (limit)
|
||||
"Match against escape characters.
|
||||
Don't scan past LIMIT."
|
||||
(let* ((done nil)
|
||||
(md nil)
|
||||
(es (regexp-quote (srecode-template-get-escape-start)))
|
||||
(ee (regexp-quote (srecode-template-get-escape-end)))
|
||||
(regex (concat "\\(" es "\\|" ee "\\)"))
|
||||
)
|
||||
(while (not done)
|
||||
(save-match-data
|
||||
(if (re-search-forward regex limit t)
|
||||
(when (equal (car (srecode-calculate-context)) "code")
|
||||
(setq md (match-data)
|
||||
done t))
|
||||
(setq done t))))
|
||||
(set-match-data md)
|
||||
;;(when md (message "Found a match!"))
|
||||
(when md t)))
|
||||
|
||||
(defvar srecode-font-lock-macro-keywords nil
|
||||
"Dynamically generated `font-lock' keywords for srecode templates.
|
||||
Once the escape_start, and escape_end sequences are known, then
|
||||
we can tell font lock about them.")
|
||||
|
||||
(defvar srecode-template-mode-map
|
||||
(let ((km (make-sparse-keymap)))
|
||||
(define-key km "\C-c\C-c" 'srecode-compile-templates)
|
||||
(define-key km "\C-c\C-m" 'srecode-macro-help)
|
||||
(define-key km "/" 'srecode-self-insert-complete-end-macro)
|
||||
km)
|
||||
"Keymap used in srecode mode.")
|
||||
|
||||
;;;###autoload
|
||||
(defun srecode-template-mode ()
|
||||
"Major-mode for writing srecode macros."
|
||||
(interactive)
|
||||
(kill-all-local-variables)
|
||||
(setq major-mode 'srecode-template-mode
|
||||
mode-name "SRecoder"
|
||||
comment-start ";;"
|
||||
comment-end "")
|
||||
(set (make-local-variable 'parse-sexp-ignore-comments) t)
|
||||
(set (make-local-variable 'comment-start-skip)
|
||||
"\\(\\(^\\|[^\\\\\n]\\)\\(\\\\\\\\\\)*\\);+ *")
|
||||
(set-syntax-table srecode-template-mode-syntax-table)
|
||||
(use-local-map srecode-template-mode-map)
|
||||
(set (make-local-variable 'font-lock-defaults)
|
||||
'(srecode-font-lock-keywords
|
||||
nil ;; perform string/comment fontification
|
||||
nil ;; keywords are case sensitive.
|
||||
;; This puts _ & - as a word constituant,
|
||||
;; simplifying our keywords significantly
|
||||
((?_ . "w") (?- . "w"))))
|
||||
(run-hooks 'srecode-template-mode-hook))
|
||||
|
||||
;;;###autoload
|
||||
(defalias 'srt-mode 'srecode-template-mode)
|
||||
|
||||
;;; Template Commands
|
||||
;;
|
||||
(defun srecode-self-insert-complete-end-macro ()
|
||||
"Self insert the current key, then autocomplete the end macro."
|
||||
(interactive)
|
||||
(call-interactively 'self-insert-command)
|
||||
(when (and (semantic-current-tag)
|
||||
(semantic-tag-of-class-p (semantic-current-tag) 'function)
|
||||
)
|
||||
(let* ((es (srecode-template-get-escape-start))
|
||||
(ee (srecode-template-get-escape-end))
|
||||
(name (save-excursion
|
||||
(forward-char (- (length es)))
|
||||
(forward-char -1)
|
||||
(if (looking-at (regexp-quote es))
|
||||
(srecode-up-context-get-name (point) t))))
|
||||
)
|
||||
(when name
|
||||
(insert name)
|
||||
(insert ee))))
|
||||
)
|
||||
|
||||
|
||||
(defun srecode-macro-help ()
|
||||
"Provide help for working with macros in a tempalte."
|
||||
(interactive)
|
||||
(let* ((root 'srecode-template-inserter)
|
||||
(chl (aref (class-v root) class-children))
|
||||
(ess (srecode-template-get-escape-start))
|
||||
(ees (srecode-template-get-escape-end))
|
||||
)
|
||||
(with-output-to-temp-buffer "*SRecode Macros*"
|
||||
(princ "Description of known SRecode Template Macros.")
|
||||
(terpri)
|
||||
(terpri)
|
||||
(while chl
|
||||
(let* ((C (car chl))
|
||||
(name (symbol-name C))
|
||||
(key (when (slot-exists-p C 'key)
|
||||
(oref C key)))
|
||||
(showexample t)
|
||||
)
|
||||
(setq chl (cdr chl))
|
||||
(setq chl (append (aref (class-v C) class-children) chl))
|
||||
|
||||
(catch 'skip
|
||||
(when (eq C 'srecode-template-inserter-section-end)
|
||||
(throw 'skip nil))
|
||||
|
||||
(when (class-abstract-p C)
|
||||
(throw 'skip nil))
|
||||
|
||||
(princ "`")
|
||||
(princ name)
|
||||
(princ "'")
|
||||
(when (slot-exists-p C 'key)
|
||||
(when key
|
||||
(princ " - Character Key: ")
|
||||
(if (stringp key)
|
||||
(progn
|
||||
(setq showexample nil)
|
||||
(cond ((string= key "\n")
|
||||
(princ "\"\\n\"")
|
||||
)
|
||||
(t
|
||||
(prin1 key)
|
||||
)))
|
||||
(prin1 (format "%c" key))
|
||||
)))
|
||||
(terpri)
|
||||
(princ (documentation-property C 'variable-documentation))
|
||||
(terpri)
|
||||
(when showexample
|
||||
(princ "Example:")
|
||||
(terpri)
|
||||
(srecode-inserter-prin-example C ess ees)
|
||||
)
|
||||
|
||||
(terpri)
|
||||
|
||||
) ;; catch
|
||||
);; let*
|
||||
))))
|
||||
|
||||
|
||||
;;; Misc Language Overrides
|
||||
;;
|
||||
(define-mode-local-override semantic-ia-insert-tag
|
||||
srecode-template-mode (tag)
|
||||
"Insert the SRecode TAG into the current buffer."
|
||||
(insert (semantic-tag-name tag)))
|
||||
|
||||
|
||||
;;; Local Context Parsing.
|
||||
|
||||
(defun srecode-in-macro-p (&optional point)
|
||||
"Non-nil if POINT is inside a macro bounds.
|
||||
If the ESCAPE_START and END are different sequences,
|
||||
a simple search is used. If ESCAPE_START and END are the same
|
||||
characteres, start at the beginning of the line, and find out
|
||||
how many occur."
|
||||
(let ((tag (semantic-current-tag))
|
||||
(es (regexp-quote (srecode-template-get-escape-start)))
|
||||
(ee (regexp-quote (srecode-template-get-escape-end)))
|
||||
(start (or point (point)))
|
||||
)
|
||||
(when (and tag (semantic-tag-of-class-p tag 'function))
|
||||
(if (string= es ee)
|
||||
(save-excursion
|
||||
(beginning-of-line)
|
||||
(while (re-search-forward es start t 2))
|
||||
(if (re-search-forward es start t)
|
||||
;; If there is a single, the the answer is yes.
|
||||
t
|
||||
;; If there wasn't another, then the answer is no.
|
||||
nil)
|
||||
)
|
||||
;; ES And EE are not the same.
|
||||
(save-excursion
|
||||
(and (re-search-backward es (semantic-tag-start tag) t)
|
||||
(>= (or (re-search-forward ee (semantic-tag-end tag) t)
|
||||
;; No end match means an incomplete macro.
|
||||
start)
|
||||
start)))
|
||||
))))
|
||||
|
||||
(defun srecode-up-context-get-name (&optional point find-unmatched)
|
||||
"Move up one context as for `semantic-up-context', and return the name.
|
||||
Moves point to the opening characters of the section macro text.
|
||||
If there is no upper context, return nil.
|
||||
Starts at POINT if provided.
|
||||
If FIND-UNMATCHED is specified as non-nil, then we are looking for an unmatched
|
||||
section."
|
||||
(when point (goto-char (point)))
|
||||
(let* ((tag (semantic-current-tag))
|
||||
(es (regexp-quote (srecode-template-get-escape-start)))
|
||||
(start (concat es "[#<]\\(\\w+\\)"))
|
||||
(orig (point))
|
||||
(name nil)
|
||||
(res nil))
|
||||
(when (semantic-tag-of-class-p tag 'function)
|
||||
(while (and (not res)
|
||||
(re-search-backward start (semantic-tag-start tag) t))
|
||||
(when (save-excursion
|
||||
(setq name (match-string 1))
|
||||
(let ((endr (concat es "/" name)))
|
||||
(if (re-search-forward endr (semantic-tag-end tag) t)
|
||||
(< orig (point))
|
||||
(if (not find-unmatched)
|
||||
(error "Unmatched Section Template")
|
||||
;; We found what we want.
|
||||
t))))
|
||||
(setq res (point)))
|
||||
)
|
||||
;; Restore in no result found.
|
||||
(goto-char (or res orig))
|
||||
name)))
|
||||
|
||||
(define-mode-local-override semantic-up-context
|
||||
srecode-template-mode (&optional point)
|
||||
"Move up one context in the current code.
|
||||
Moves out one named section."
|
||||
(not (srecode-up-context-get-name point)))
|
||||
|
||||
(define-mode-local-override semantic-beginning-of-context
|
||||
srecode-template-mode (&optional point)
|
||||
"Move to the beginning of the current context.
|
||||
Moves the the beginning of one named section."
|
||||
(if (semantic-up-context point)
|
||||
t
|
||||
(let ((es (regexp-quote (srecode-template-get-escape-start)))
|
||||
(ee (regexp-quote (srecode-template-get-escape-end))))
|
||||
(re-search-forward es) ;; move over the start chars.
|
||||
(re-search-forward ee) ;; Move after the end chars.
|
||||
nil)))
|
||||
|
||||
(define-mode-local-override semantic-end-of-context
|
||||
srecode-template-mode (&optional point)
|
||||
"Move to the beginning of the current context.
|
||||
Moves the the beginning of one named section."
|
||||
(let ((name (srecode-up-context-get-name point))
|
||||
(tag (semantic-current-tag))
|
||||
(es (regexp-quote (srecode-template-get-escape-start))))
|
||||
(if (not name)
|
||||
t
|
||||
(unless (re-search-forward (concat es "/" name) (semantic-tag-end tag) t)
|
||||
(error "Section %s has no end" name))
|
||||
(goto-char (match-beginning 0))
|
||||
nil)))
|
||||
|
||||
(define-mode-local-override semantic-get-local-variables
|
||||
srecode-template-mode (&optional point)
|
||||
"Get local variables from an SRecode template."
|
||||
(save-excursion
|
||||
(when point (goto-char (point)))
|
||||
(let* ((tag (semantic-current-tag))
|
||||
(name (save-excursion
|
||||
(srecode-up-context-get-name (point))))
|
||||
(subdicts (semantic-tag-get-attribute tag :dictionaries))
|
||||
(global nil)
|
||||
)
|
||||
(dolist (D subdicts)
|
||||
(setq global (cons (semantic-tag-new-variable (car D) nil)
|
||||
global)))
|
||||
(if name
|
||||
;; Lookup any subdictionaries in TAG.
|
||||
(let ((res nil))
|
||||
|
||||
(while (and (not res) subdicts)
|
||||
;; Find the subdictionary with the same name. Those variables
|
||||
;; are now local to this section.
|
||||
(when (string= (car (car subdicts)) name)
|
||||
(setq res (cdr (car subdicts))))
|
||||
(setq subdicts (cdr subdicts)))
|
||||
;; Pre-pend our global vars.
|
||||
(append global res))
|
||||
;; If we aren't in a subsection, just do the global variables
|
||||
global
|
||||
))))
|
||||
|
||||
(define-mode-local-override semantic-get-local-arguments
|
||||
srecode-template-mode (&optional point)
|
||||
"Get local arguments from an SRecode template."
|
||||
(require 'srecode/insert)
|
||||
(save-excursion
|
||||
(when point (goto-char (point)))
|
||||
(let* ((tag (semantic-current-tag))
|
||||
(args (semantic-tag-function-arguments tag))
|
||||
(argsym (mapcar 'intern args))
|
||||
(argvars nil)
|
||||
;; Create a temporary dictionary in which the
|
||||
;; arguments can be resolved so we can extract
|
||||
;; the results.
|
||||
(dict (srecode-create-dictionary t))
|
||||
)
|
||||
;; Resolve args into our temp dictionary
|
||||
(srecode-resolve-argument-list argsym dict)
|
||||
|
||||
(maphash
|
||||
(lambda (key entry)
|
||||
(setq argvars
|
||||
(cons (semantic-tag-new-variable key nil entry)
|
||||
argvars)))
|
||||
(oref dict namehash))
|
||||
|
||||
argvars)))
|
||||
|
||||
(define-mode-local-override semantic-ctxt-current-symbol
|
||||
srecode-template-mode (&optional point)
|
||||
"Return the current symbol under POINT.
|
||||
Return nil if point is not on/in a template macro."
|
||||
(let ((macro (srecode-parse-this-macro point)))
|
||||
(cdr macro))
|
||||
)
|
||||
|
||||
(defun srecode-parse-this-macro (&optional point)
|
||||
"Return the current symbol under POINT.
|
||||
Return nil if point is not on/in a template macro.
|
||||
The first element is the key for the current macro, such as # for a
|
||||
section or ? for an ask variable."
|
||||
(save-excursion
|
||||
(if point (goto-char point))
|
||||
(let ((tag (semantic-current-tag))
|
||||
(es (regexp-quote (srecode-template-get-escape-start)))
|
||||
(ee (regexp-quote (srecode-template-get-escape-end)))
|
||||
(start (point))
|
||||
(macrostart nil)
|
||||
(raw nil)
|
||||
)
|
||||
(when (and tag (semantic-tag-of-class-p tag 'function)
|
||||
(srecode-in-macro-p point)
|
||||
(re-search-backward es (semantic-tag-start tag) t))
|
||||
(setq macrostart (match-end 0))
|
||||
(goto-char macrostart)
|
||||
;; We have a match
|
||||
(when (not (re-search-forward ee (semantic-tag-end tag) t))
|
||||
(goto-char start) ;; Pretend we are ok for completion
|
||||
(set-match-data (list start start))
|
||||
)
|
||||
|
||||
(if (> start (point))
|
||||
;; If our starting point is after the found point, that
|
||||
;; means we are not inside the macro. Retur nil.
|
||||
nil
|
||||
;; We are inside the macro, extract the text so far.
|
||||
(let* ((macroend (match-beginning 0))
|
||||
(raw (buffer-substring-no-properties
|
||||
macrostart macroend))
|
||||
(STATE (srecode-compile-state "TMP"))
|
||||
(inserter (condition-case nil
|
||||
(srecode-compile-parse-inserter
|
||||
raw STATE)
|
||||
(error nil)))
|
||||
)
|
||||
(when inserter
|
||||
(let ((base
|
||||
(cons (oref inserter :object-name)
|
||||
(if (and (slot-boundp inserter :secondname)
|
||||
(oref inserter :secondname))
|
||||
(split-string (oref inserter :secondname)
|
||||
":")
|
||||
nil)))
|
||||
(key (oref inserter key)))
|
||||
(cond ((null key)
|
||||
;; A plain variable
|
||||
(cons nil base))
|
||||
(t
|
||||
;; A complex variable thingy.
|
||||
(cons (format "%c" key)
|
||||
base)))))
|
||||
)
|
||||
)))
|
||||
))
|
||||
|
||||
(define-mode-local-override semantic-analyze-current-context
|
||||
srecode-template-mode (point)
|
||||
"Provide a Semantic analysis in SRecode template mode."
|
||||
(let* ((context-return nil)
|
||||
(prefixandbounds (semantic-ctxt-current-symbol-and-bounds))
|
||||
(prefix (car prefixandbounds))
|
||||
(bounds (nth 2 prefixandbounds))
|
||||
(key (car (srecode-parse-this-macro (point))))
|
||||
(prefixsym nil)
|
||||
(prefix-var nil)
|
||||
(prefix-context nil)
|
||||
(prefix-function nil)
|
||||
(prefixclass (semantic-ctxt-current-class-list))
|
||||
(globalvar (semantic-find-tags-by-class 'variable (current-buffer)))
|
||||
(argtype 'macro)
|
||||
(scope (semantic-calculate-scope point))
|
||||
)
|
||||
|
||||
(oset scope fullscope (append (oref scope localvar) globalvar))
|
||||
|
||||
(when prefix
|
||||
;; First, try to find the variable for the first
|
||||
;; entry in the prefix list.
|
||||
(setq prefix-var (semantic-find-first-tag-by-name
|
||||
(car prefix) (oref scope fullscope)))
|
||||
|
||||
(cond
|
||||
((and (or (not key) (string= key "?"))
|
||||
(> (length prefix) 1))
|
||||
;; Variables can have lisp function names.
|
||||
(with-mode-local emacs-lisp-mode
|
||||
(let ((fcns (semanticdb-find-tags-by-name (car (last prefix)))))
|
||||
(setq prefix-function (car (semanticdb-find-result-nth fcns 0)))
|
||||
(setq argtype 'elispfcn)))
|
||||
)
|
||||
((or (string= key "<") (string= key ">"))
|
||||
;; Includes have second args that is the template name.
|
||||
(if (= (length prefix) 3)
|
||||
(let ((contexts (semantic-find-tags-by-class
|
||||
'context (current-buffer))))
|
||||
(setq prefix-context
|
||||
(or (semantic-find-first-tag-by-name
|
||||
(nth 1 prefix) contexts)
|
||||
;; Calculate from location
|
||||
(semantic-tag
|
||||
(symbol-name
|
||||
(srecode-template-current-context))
|
||||
'context)))
|
||||
(setq argtype 'template))
|
||||
(setq prefix-context
|
||||
;; Calculate from location
|
||||
(semantic-tag
|
||||
(symbol-name (srecode-template-current-context))
|
||||
'context))
|
||||
(setq argtype 'template)
|
||||
)
|
||||
;; The last one?
|
||||
(when (> (length prefix) 1)
|
||||
(let ((toc (srecode-template-find-templates-of-context
|
||||
(read (semantic-tag-name prefix-context))))
|
||||
)
|
||||
(setq prefix-function
|
||||
(or (semantic-find-first-tag-by-name
|
||||
(car (last prefix)) toc)
|
||||
;; Not in this buffer? Search the master
|
||||
;; templates list.
|
||||
nil))
|
||||
))
|
||||
)
|
||||
)
|
||||
|
||||
(setq prefixsym
|
||||
(cond ((= (length prefix) 3)
|
||||
(list (or prefix-var (nth 0 prefix))
|
||||
(or prefix-context (nth 1 prefix))
|
||||
(or prefix-function (nth 2 prefix))))
|
||||
((= (length prefix) 2)
|
||||
(list (or prefix-var (nth 0 prefix))
|
||||
(or prefix-function (nth 1 prefix))))
|
||||
((= (length prefix) 1)
|
||||
(list (or prefix-var (nth 0 prefix)))
|
||||
)))
|
||||
|
||||
(setq context-return
|
||||
(semantic-analyze-context-functionarg
|
||||
"context-for-srecode"
|
||||
:buffer (current-buffer)
|
||||
:scope scope
|
||||
:bounds bounds
|
||||
:prefix (or prefixsym
|
||||
prefix)
|
||||
:prefixtypes nil
|
||||
:prefixclass prefixclass
|
||||
:errors nil
|
||||
;; Use the functionarg analyzer class so we
|
||||
;; can save the current key, and the index
|
||||
;; into the macro part we are completing on.
|
||||
:function (list key)
|
||||
:index (length prefix)
|
||||
:argument (list argtype)
|
||||
))
|
||||
|
||||
context-return)))
|
||||
|
||||
(define-mode-local-override semantic-analyze-possible-completions
|
||||
srecode-template-mode (context)
|
||||
"Return a list of possible completions based on NONTEXT."
|
||||
(save-excursion
|
||||
(set-buffer (oref context buffer))
|
||||
(let* ((prefix (car (last (oref context :prefix))))
|
||||
(prefixstr (cond ((stringp prefix)
|
||||
prefix)
|
||||
((semantic-tag-p prefix)
|
||||
(semantic-tag-name prefix))))
|
||||
; (completetext (cond ((semantic-tag-p prefix)
|
||||
; (semantic-tag-name prefix))
|
||||
; ((stringp prefix)
|
||||
; prefix)
|
||||
; ((stringp (car prefix))
|
||||
; (car prefix))))
|
||||
(argtype (car (oref context :argument)))
|
||||
(matches nil))
|
||||
|
||||
;; Depending on what the analyzer is, we have different ways
|
||||
;; of creating completions.
|
||||
(cond ((eq argtype 'template)
|
||||
(setq matches (semantic-find-tags-for-completion
|
||||
prefixstr (current-buffer)))
|
||||
(setq matches (semantic-find-tags-by-class
|
||||
'function matches))
|
||||
)
|
||||
((eq argtype 'elispfcn)
|
||||
(with-mode-local emacs-lisp-mode
|
||||
(setq matches (semanticdb-find-tags-for-completion
|
||||
prefixstr))
|
||||
(setq matches (semantic-find-tags-by-class
|
||||
'function matches))
|
||||
)
|
||||
)
|
||||
((eq argtype 'macro)
|
||||
(let ((scope (oref context scope)))
|
||||
(setq matches
|
||||
(semantic-find-tags-for-completion
|
||||
prefixstr (oref scope fullscope))))
|
||||
)
|
||||
)
|
||||
|
||||
matches)))
|
||||
|
||||
|
||||
|
||||
;;; Utils
|
||||
;;
|
||||
(defun srecode-template-get-mode ()
|
||||
"Get the supported major mode for this template file."
|
||||
(let ((m (semantic-find-first-tag-by-name "mode" (current-buffer))))
|
||||
(when m (read (semantic-tag-variable-default m)))))
|
||||
|
||||
(defun srecode-template-get-escape-start ()
|
||||
"Get the current escape_start characters."
|
||||
(let ((es (semantic-find-first-tag-by-name "escape_start" (current-buffer)))
|
||||
)
|
||||
(if es (car (semantic-tag-get-attribute es :default-value))
|
||||
"{{")))
|
||||
|
||||
(defun srecode-template-get-escape-end ()
|
||||
"Get the current escape_end characters."
|
||||
(let ((ee (semantic-find-first-tag-by-name "escape_end" (current-buffer)))
|
||||
)
|
||||
(if ee (car (semantic-tag-get-attribute ee :default-value))
|
||||
"}}")))
|
||||
|
||||
(defun srecode-template-current-context (&optional point)
|
||||
"Calculate the context encompassing POINT."
|
||||
(save-excursion
|
||||
(when point (goto-char (point)))
|
||||
(let ((ct (semantic-current-tag)))
|
||||
(when (not ct)
|
||||
(setq ct (semantic-find-tag-by-overlay-prev)))
|
||||
|
||||
;; Loop till we find the context.
|
||||
(while (and ct (not (semantic-tag-of-class-p ct 'context)))
|
||||
(setq ct (semantic-find-tag-by-overlay-prev
|
||||
(semantic-tag-start ct))))
|
||||
|
||||
(if ct
|
||||
(read (semantic-tag-name ct))
|
||||
'declaration))))
|
||||
|
||||
(defun srecode-template-find-templates-of-context (context &optional buffer)
|
||||
"Find all the templates belonging to a particular CONTEXT.
|
||||
When optional BUFFER is provided, search that buffer."
|
||||
(save-excursion
|
||||
(when buffer (set-buffer buffer))
|
||||
(let ((tags (semantic-fetch-available-tags))
|
||||
(cc 'declaration)
|
||||
(scan nil)
|
||||
(ans nil))
|
||||
|
||||
(when (eq cc context)
|
||||
(setq scan t))
|
||||
|
||||
(dolist (T tags)
|
||||
;; Handle contexts
|
||||
(when (semantic-tag-of-class-p T 'context)
|
||||
(setq cc (read (semantic-tag-name T)))
|
||||
(when (eq cc context)
|
||||
(setq scan t)))
|
||||
|
||||
;; Scan
|
||||
(when (and scan (semantic-tag-of-class-p T 'function))
|
||||
(setq ans (cons T ans)))
|
||||
)
|
||||
|
||||
(nreverse ans))))
|
||||
|
||||
|
||||
;;; MMM-Mode support ??
|
||||
;;(condition-case nil
|
||||
;; (require 'mmm-mode)
|
||||
;; (error (message "SRecoder Template Mode: No multi-mode not support.")))
|
||||
;;
|
||||
;;(defun srecode-template-add-submode ()
|
||||
;; "Add a submode to the current template file using mmm-mode.
|
||||
;;If mmm-mode isn't available, then do nothing."
|
||||
;; (if (not (featurep 'mmm-mode))
|
||||
;; nil ;; Nothing to do.
|
||||
;; ;; Else, set up mmm-mode in this buffer.
|
||||
;; (let ((submode (semantic-find-tags-by-name "mode")))
|
||||
;; (if (not submode)
|
||||
;; nil ;; Nothing to do.
|
||||
;; ;; Well, we have a mode, lets try turning on mmm-mode.
|
||||
;;
|
||||
;; ;; (mmm-mode-on)
|
||||
;;
|
||||
;;
|
||||
;;
|
||||
;; ))))
|
||||
;;
|
||||
|
||||
(provide 'srecode/srt-mode)
|
||||
|
||||
;; The autoloads in this file must go into the global loaddefs.el, not
|
||||
;; the srecode one, so that srecode-template-mode can be called from
|
||||
;; auto-mode-alist.
|
||||
|
||||
;; Local variables:
|
||||
;; generated-autoload-load-name: "srecode/srt-mode"
|
||||
;; End:
|
||||
|
||||
;;; srecode/srt-mode.el ends here
|
277
lisp/cedet/srecode/srt-wy.el
Normal file
277
lisp/cedet/srecode/srt-wy.el
Normal file
|
@ -0,0 +1,277 @@
|
|||
;;; srecode/srt-wy.el --- Generated parser support file
|
||||
|
||||
;; Copyright (C) 2005, 2007, 2008, 2009 Free Software Foundation, Inc.
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; Generated from srecode-template.wy in the CEDET repository.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'semantic/lex)
|
||||
|
||||
|
||||
;;; Prologue
|
||||
;;
|
||||
|
||||
;;; Declarations
|
||||
;;
|
||||
(defconst srecode-template-wy--keyword-table
|
||||
(semantic-lex-make-keyword-table
|
||||
'(("set" . SET)
|
||||
("show" . SHOW)
|
||||
("macro" . MACRO)
|
||||
("context" . CONTEXT)
|
||||
("template" . TEMPLATE)
|
||||
("sectiondictionary" . SECTIONDICTIONARY)
|
||||
("prompt" . PROMPT)
|
||||
("default" . DEFAULT)
|
||||
("defaultmacro" . DEFAULTMACRO)
|
||||
("read" . READ)
|
||||
("bind" . BIND))
|
||||
'(("bind" summary "bind \"<letter>\"")
|
||||
("read" summary "prompt <symbol> \"Describe Symbol: \" [default[macro] <lispsym>|\"valuetext\"] [read <lispsym>]")
|
||||
("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>]")
|
||||
("sectiondictionary" summary "sectiondictionary <name>\\n <dictionary entries>")
|
||||
("template" summary "template <name>\\n <template definition>")
|
||||
("context" summary "context <name>")
|
||||
("macro" summary "... macro \"string\" ...")
|
||||
("show" summary "show <name> ; to show a section")
|
||||
("set" summary "set <name> <value>")))
|
||||
"Table of language keywords.")
|
||||
|
||||
(defconst srecode-template-wy--token-table
|
||||
(semantic-lex-make-type-table
|
||||
'(("number"
|
||||
(number))
|
||||
("string"
|
||||
(string))
|
||||
("symbol"
|
||||
(symbol))
|
||||
("property"
|
||||
(property))
|
||||
("separator"
|
||||
(TEMPLATE_BLOCK . "^----"))
|
||||
("newline"
|
||||
(newline)))
|
||||
'(("number" :declared t)
|
||||
("string" :declared t)
|
||||
("symbol" :declared t)
|
||||
("property" :declared t)
|
||||
("newline" :declared t)
|
||||
("punctuation" syntax "\\s.+")
|
||||
("punctuation" :declared t)
|
||||
("keyword" :declared t)))
|
||||
"Table of lexical tokens.")
|
||||
|
||||
(defconst srecode-template-wy--parse-table
|
||||
(progn
|
||||
(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)
|
||||
nil
|
||||
(template_file
|
||||
((newline)
|
||||
nil)
|
||||
((context))
|
||||
((prompt))
|
||||
((variable))
|
||||
((template)))
|
||||
(context
|
||||
((CONTEXT symbol newline)
|
||||
(wisent-raw-tag
|
||||
(semantic-tag $2 'context))))
|
||||
(prompt
|
||||
((PROMPT symbol string opt-default-fcn opt-read-fcn newline)
|
||||
(wisent-raw-tag
|
||||
(semantic-tag $2 'prompt :text
|
||||
(read $3)
|
||||
:default $4 :read $5))))
|
||||
(opt-default-fcn
|
||||
((DEFAULT symbol)
|
||||
(progn
|
||||
(read $2)))
|
||||
((DEFAULT string)
|
||||
(progn
|
||||
(read $2)))
|
||||
((DEFAULTMACRO string)
|
||||
(progn
|
||||
(cons 'macro
|
||||
(read $2))))
|
||||
(nil nil))
|
||||
(opt-read-fcn
|
||||
((READ symbol)
|
||||
(progn
|
||||
(read $2)))
|
||||
(nil nil))
|
||||
(variable
|
||||
((SET symbol insertable-string-list newline)
|
||||
(wisent-raw-tag
|
||||
(semantic-tag-new-variable $2 nil $3)))
|
||||
((SHOW symbol newline)
|
||||
(wisent-raw-tag
|
||||
(semantic-tag-new-variable $2 nil t))))
|
||||
(insertable-string-list
|
||||
((insertable-string)
|
||||
(list $1))
|
||||
((insertable-string-list insertable-string)
|
||||
(append $1
|
||||
(list $2))))
|
||||
(insertable-string
|
||||
((string)
|
||||
(read $1))
|
||||
((MACRO string)
|
||||
(cons 'macro
|
||||
(read $2))))
|
||||
(template
|
||||
((TEMPLATE templatename opt-dynamic-arguments newline opt-string opt-section-dictionaries TEMPLATE_BLOCK newline opt-bind)
|
||||
(wisent-raw-tag
|
||||
(semantic-tag-new-function $2 nil $3 :documentation $5 :code $7 :dictionaries $6 :binding $9))))
|
||||
(templatename
|
||||
((symbol))
|
||||
((PROMPT))
|
||||
((CONTEXT))
|
||||
((TEMPLATE))
|
||||
((DEFAULT))
|
||||
((MACRO))
|
||||
((DEFAULTMACRO))
|
||||
((READ))
|
||||
((SET)))
|
||||
(opt-dynamic-arguments
|
||||
((property opt-dynamic-arguments)
|
||||
(cons $1 $2))
|
||||
(nil nil))
|
||||
(opt-string
|
||||
((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)
|
||||
(append $1
|
||||
(list $2))))
|
||||
(one-section-dictionary
|
||||
((SECTIONDICTIONARY string newline variable-list)
|
||||
(cons
|
||||
(read $2)
|
||||
$4)))
|
||||
(variable-list
|
||||
((variable)
|
||||
(wisent-cook-tag $1))
|
||||
((variable-list variable)
|
||||
(append $1
|
||||
(wisent-cook-tag $2))))
|
||||
(opt-bind
|
||||
((BIND string newline)
|
||||
(read $2))
|
||||
(nil nil)))
|
||||
'(template_file)))
|
||||
"Parser table.")
|
||||
|
||||
(defun srecode-template-wy--install-parser ()
|
||||
"Setup the Semantic Parser."
|
||||
(semantic-install-function-overrides
|
||||
'((parse-stream . wisent-parse-stream)))
|
||||
(setq semantic-parser-name "LALR"
|
||||
semantic--parse-table srecode-template-wy--parse-table
|
||||
semantic-debug-parser-source "srecode-template.wy"
|
||||
semantic-flex-keywords-obarray srecode-template-wy--keyword-table
|
||||
semantic-lex-types-obarray srecode-template-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))
|
||||
|
||||
|
||||
;;; Analyzers
|
||||
;;
|
||||
(define-lex-keyword-type-analyzer srecode-template-wy--<keyword>-keyword-analyzer
|
||||
"keyword analyzer for <keyword> tokens."
|
||||
"\\(\\sw\\|\\s_\\)+")
|
||||
|
||||
(define-lex-regex-type-analyzer srecode-template-wy--<symbol>-regexp-analyzer
|
||||
"regexp analyzer for <symbol> tokens."
|
||||
"\\(\\sw\\|\\s_\\)+"
|
||||
nil
|
||||
'symbol)
|
||||
|
||||
(define-lex-sexp-type-analyzer srecode-template-wy--<string>-sexp-analyzer
|
||||
"sexp analyzer for <string> tokens."
|
||||
"\\s\""
|
||||
'string)
|
||||
|
||||
(define-lex-regex-type-analyzer srecode-template-wy--<number>-regexp-analyzer
|
||||
"regexp analyzer for <number> tokens."
|
||||
semantic-lex-number-expression
|
||||
nil
|
||||
'number)
|
||||
|
||||
(define-lex-string-type-analyzer srecode-template-wy--<punctuation>-string-analyzer
|
||||
"string analyzer for <punctuation> tokens."
|
||||
"\\s.+"
|
||||
nil
|
||||
'punctuation)
|
||||
|
||||
|
||||
;;; Epilogue
|
||||
;;
|
||||
(define-lex-simple-regex-analyzer srecode-template-property-analyzer
|
||||
"Detect and create a dynamic argument properties."
|
||||
":\\(\\w\\|\\s_\\)*" 'property 0)
|
||||
|
||||
(define-lex-regex-analyzer srecode-template-separator-block
|
||||
"Detect and create a template quote block."
|
||||
"^----\n"
|
||||
(semantic-lex-push-token
|
||||
(semantic-lex-token
|
||||
'TEMPLATE_BLOCK
|
||||
(match-end 0)
|
||||
(semantic-lex-unterminated-syntax-protection 'TEMPLATE_BLOCK
|
||||
(goto-char (match-end 0))
|
||||
(re-search-forward "^----$")
|
||||
(match-beginning 0))))
|
||||
(setq semantic-lex-end-point (point)))
|
||||
|
||||
|
||||
(define-lex wisent-srecode-template-lexer
|
||||
"Lexical analyzer that handles SRecode Template buffers.
|
||||
It ignores whitespace, newlines and comments."
|
||||
semantic-lex-newline
|
||||
semantic-lex-ignore-whitespace
|
||||
semantic-lex-ignore-newline
|
||||
semantic-lex-ignore-comments
|
||||
srecode-template-separator-block
|
||||
srecode-template-wy--<keyword>-keyword-analyzer
|
||||
srecode-template-property-analyzer
|
||||
srecode-template-wy--<symbol>-regexp-analyzer
|
||||
srecode-template-wy--<number>-regexp-analyzer
|
||||
srecode-template-wy--<string>-sexp-analyzer
|
||||
srecode-template-wy--<punctuation>-string-analyzer
|
||||
semantic-lex-default-action
|
||||
)
|
||||
|
||||
(provide 'srecode/srt-wy)
|
||||
|
||||
;;; srecode/srt-wy.el ends here
|
106
lisp/cedet/srecode/srt.el
Normal file
106
lisp/cedet/srecode/srt.el
Normal file
|
@ -0,0 +1,106 @@
|
|||
;;; srecode/srt.el --- argument handlers for SRT files
|
||||
|
||||
;; Copyright (C) 2008, 2009 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Eric M. Ludlam <eric@siege-engine.com>
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; Filters for SRT files, the Semantic Recoder template files.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'eieio)
|
||||
(require 'srecode/dictionary)
|
||||
(require 'srecode/insert)
|
||||
|
||||
(defvar srecode-read-variable-name-history nil
|
||||
"History for `srecode-read-variable-name'.")
|
||||
|
||||
(defun srecode-read-variable-name (prompt &optional initial hist default)
|
||||
"Read in the name of a declaired variable in the current SRT file.
|
||||
PROMPT is the prompt to use.
|
||||
INITIAL is the initial string.
|
||||
HIST is the history value, otherwise `srecode-read-variable-name-history'
|
||||
is used.
|
||||
DEFAULT is the default if RET is hit."
|
||||
(let* ((newdict (srecode-create-dictionary))
|
||||
(currfcn (semantic-current-tag))
|
||||
)
|
||||
(srecode-resolve-argument-list
|
||||
(mapcar 'read
|
||||
(semantic-tag-get-attribute currfcn :arguments))
|
||||
newdict)
|
||||
|
||||
(with-slots (namehash) newdict
|
||||
(completing-read prompt namehash nil nil initial
|
||||
(or hist 'srecode-read-variable-name-history)
|
||||
default))
|
||||
))
|
||||
|
||||
(defvar srecode-read-major-mode-history nil
|
||||
"History for `srecode-read-variable-name'.")
|
||||
|
||||
(defun srecode-read-major-mode-name (prompt &optional initial hist default)
|
||||
"Read in the name of a desired `major-mode'.
|
||||
PROMPT is the prompt to use.
|
||||
INITIAL is the initial string.
|
||||
HIST is the history value, otherwise `srecode-read-variable-name-history'
|
||||
is used.
|
||||
DEFAULT is the default if RET is hit."
|
||||
(completing-read prompt obarray
|
||||
(lambda (s) (string-match "-mode$" (symbol-name s)))
|
||||
nil initial (or hist 'srecode-read-major-mode-history))
|
||||
)
|
||||
|
||||
(defun srecode-semantic-handle-:srt (dict)
|
||||
"Add macros into the dictionary DICT based on the current SRT file.
|
||||
Adds the following:
|
||||
ESCAPE_START - This files value of escape_start
|
||||
ESCAPE_END - This files value of escape_end
|
||||
MODE - The mode of this buffer. If not declared yet, guess."
|
||||
(let* ((es (semantic-find-first-tag-by-name "escape_start" (current-buffer)))
|
||||
(ee (semantic-find-first-tag-by-name "escape_end" (current-buffer)))
|
||||
(mode-var (semantic-find-first-tag-by-name "mode" (current-buffer)))
|
||||
(mode (if mode-var
|
||||
(semantic-tag-variable-default mode-var)
|
||||
nil))
|
||||
)
|
||||
(srecode-dictionary-set-value dict "ESCAPE_START"
|
||||
(if es
|
||||
(car (semantic-tag-variable-default es))
|
||||
"{{"))
|
||||
(srecode-dictionary-set-value dict "ESCAPE_END"
|
||||
(if ee
|
||||
(car (semantic-tag-variable-default ee))
|
||||
"}}"))
|
||||
(when (not mode)
|
||||
(let* ((fname (file-name-nondirectory
|
||||
(buffer-file-name (current-buffer))))
|
||||
)
|
||||
(when (string-match "-\\(\\w+\\)\\.srt" fname)
|
||||
(setq mode (concat (match-string 1 fname) "-mode")))))
|
||||
|
||||
(when mode
|
||||
(srecode-dictionary-set-value dict "MAJORMODE" mode))
|
||||
|
||||
))
|
||||
|
||||
(provide 'srecode/srt)
|
||||
|
||||
;;; srecode/srt.el ends here
|
248
lisp/cedet/srecode/table.el
Normal file
248
lisp/cedet/srecode/table.el
Normal file
|
@ -0,0 +1,248 @@
|
|||
;;; srecode/table.el --- Tables of Semantic Recoders
|
||||
|
||||
;; Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Eric M. Ludlam <eric@siege-engine.com>
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; Semantic Recoder tables manage lists of templates and the major
|
||||
;; modes they are associated with.
|
||||
;;
|
||||
|
||||
(require 'eieio)
|
||||
(require 'eieio-base)
|
||||
(require 'mode-local)
|
||||
(require 'srecode)
|
||||
|
||||
(declare-function srecode-load-tables-for-mode "srecode/find")
|
||||
|
||||
;;; Code:
|
||||
|
||||
;;; TEMPLATE TABLE
|
||||
;;
|
||||
(defclass srecode-template-table ()
|
||||
(;;
|
||||
;; Raw file tracking
|
||||
;;
|
||||
(file :initarg :file
|
||||
:type string
|
||||
:documentation
|
||||
"The name of the file this table was built from.")
|
||||
(filesize :initarg :filesize
|
||||
:type number
|
||||
:documentation
|
||||
"The size of the file when it was parsed.")
|
||||
(filedate :initarg :filedate
|
||||
:type cons
|
||||
:documentation
|
||||
"Date from the inode of the file when it was last edited.
|
||||
Format is from the `file-attributes' function.")
|
||||
(major-mode :initarg :major-mode
|
||||
:documentation
|
||||
"The major mode this table of templates is associated with.")
|
||||
;;
|
||||
;; Template file sorting data
|
||||
;;
|
||||
(application :initarg :application
|
||||
:type symbol
|
||||
:documentation
|
||||
"Tracks the name of the application these templates belong to.
|
||||
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 dictoinary.")
|
||||
(priority :initarg :priority
|
||||
:type number
|
||||
:documentation
|
||||
"For file of this Major Mode, what is the priority of this file.
|
||||
When there are multiple template files with similar names, templates with
|
||||
the highest priority are scanned last, allowing them to override values in
|
||||
previous template files.")
|
||||
;;
|
||||
;; Parsed Data from the template file
|
||||
;;
|
||||
(templates :initarg :templates
|
||||
:type list
|
||||
:documentation
|
||||
"The list of templates compiled into this table.")
|
||||
(namehash :initarg :namehash
|
||||
:documentation
|
||||
"Hash table containing the names of all the templates.")
|
||||
(contexthash :initarg :contexthash
|
||||
:documentation
|
||||
"")
|
||||
(variables :initarg :variables
|
||||
:documentation
|
||||
"AList of variables.
|
||||
These variables are used to initialize dictionaries.")
|
||||
)
|
||||
"Semantic recoder template table.
|
||||
A Table contains all templates from a single .srt file.
|
||||
Tracks various lookup hash tables.")
|
||||
|
||||
;;; MODE TABLE
|
||||
;;
|
||||
(defvar srecode-mode-table-list nil
|
||||
"List of all the SRecode mode table classes that have been built.")
|
||||
|
||||
(defclass srecode-mode-table (eieio-instance-tracker)
|
||||
((tracking-symbol :initform 'srecode-mode-table-list)
|
||||
(major-mode :initarg :major-mode
|
||||
:documentation
|
||||
"Table of template tables for this major-mode.")
|
||||
(tables :initarg :tables
|
||||
:documentation
|
||||
"All the tables that have been defined 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))
|
||||
|
||||
(defun srecode-make-mode-table (mode)
|
||||
"Get the SRecoder mode table for the major mode MODE."
|
||||
(let ((old (eieio-instance-tracker-find
|
||||
mode 'major-mode 'srecode-mode-table-list)))
|
||||
(if old
|
||||
old
|
||||
(let* ((ms (if (stringp mode) mode (symbol-name mode)))
|
||||
(new (srecode-mode-table ms
|
||||
:major-mode mode
|
||||
:tables nil)))
|
||||
;; Save this new mode table in that mode's variable.
|
||||
(eval `(setq-mode-local ,mode srecode-table ,new))
|
||||
|
||||
new))))
|
||||
|
||||
(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)))
|
||||
|
||||
(defun srecode-mode-table-new (mode file &rest init)
|
||||
"Create a new template table for MODE in FILE.
|
||||
INIT are the initialization parametrs for the new template table."
|
||||
(let* ((mt (srecode-make-mode-table mode))
|
||||
(old (srecode-mode-table-find mt file))
|
||||
(attr (file-attributes file))
|
||||
(new (apply 'srecode-template-table
|
||||
(file-name-nondirectory file)
|
||||
:file file
|
||||
:filesize (nth 7 attr)
|
||||
:filedate (nth 5 attr)
|
||||
:major-mode mode
|
||||
init
|
||||
)))
|
||||
;; Whack the old table.
|
||||
(when old (object-remove-from-list mt 'tables old))
|
||||
;; Add the new table
|
||||
(object-add-to-list mt 'tables 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))))
|
||||
;; Return it.
|
||||
new))
|
||||
|
||||
(defun object-sort-list (object slot predicate)
|
||||
"Sort the items in OBJECT's SLOT.
|
||||
Use PREDICATE is the same as for the `sort' function."
|
||||
(when (slot-boundp object slot)
|
||||
(when (listp (eieio-oref object slot))
|
||||
(eieio-oset object slot (sort (eieio-oref object slot) predicate)))))
|
||||
|
||||
;;; DEBUG
|
||||
;;
|
||||
;; Dump out information about the current srecoder compiled templates.
|
||||
;;
|
||||
(defun srecode-dump-templates (mode)
|
||||
"Dump a list of the current templates for MODE."
|
||||
(interactive "sMode: ")
|
||||
(require 'srecode/find)
|
||||
(let ((modesym (cond ((string= mode "")
|
||||
major-mode)
|
||||
((not (string-match "-mode" mode))
|
||||
(intern-soft (concat mode "-mode")))
|
||||
(t
|
||||
(intern-soft mode)))))
|
||||
(srecode-load-tables-for-mode modesym)
|
||||
(let ((tmp (srecode-get-mode-table modesym))
|
||||
)
|
||||
(if (not tmp)
|
||||
(error "No table found for mode %S" modesym))
|
||||
(with-output-to-temp-buffer "*SRECODE DUMP*"
|
||||
(srecode-dump tmp))
|
||||
)))
|
||||
|
||||
(defmethod srecode-dump ((tab srecode-mode-table))
|
||||
"Dump the contents of the SRecode mode table TAB."
|
||||
(princ "MODE TABLE FOR ")
|
||||
(princ (oref tab :major-mode))
|
||||
(princ "\n--------------------------------------------\n\nNumber of tables: ")
|
||||
(let ((subtab (oref tab :tables)))
|
||||
(princ (length subtab))
|
||||
(princ "\n\n")
|
||||
(while subtab
|
||||
(srecode-dump (car subtab))
|
||||
(setq subtab (cdr subtab)))
|
||||
))
|
||||
|
||||
(defmethod srecode-dump ((tab srecode-template-table))
|
||||
"Dump the contents of the SRecode template table TAB."
|
||||
(princ "Template Table for ")
|
||||
(princ (object-name-string tab))
|
||||
(princ "\nPriority: ")
|
||||
(prin1 (oref tab :priority))
|
||||
(when (oref tab :application)
|
||||
(princ "\nApplication: ")
|
||||
(princ (oref tab :application)))
|
||||
(princ "\n\nVariables:\n")
|
||||
(let ((vars (oref tab variables)))
|
||||
(while vars
|
||||
(princ (car (car vars)))
|
||||
(princ "\t")
|
||||
(if (< (length (car (car vars))) 9)
|
||||
(princ "\t"))
|
||||
(prin1 (cdr (car vars)))
|
||||
(princ "\n")
|
||||
(setq vars (cdr vars))))
|
||||
(princ "\n\nTemplates:\n")
|
||||
(let ((temp (oref tab templates)))
|
||||
(while temp
|
||||
(srecode-dump (car temp))
|
||||
(setq temp (cdr temp))))
|
||||
)
|
||||
|
||||
|
||||
(provide 'srecode/table)
|
||||
|
||||
;;; srecode/table.el ends here
|
||||
|
69
lisp/cedet/srecode/template.el
Normal file
69
lisp/cedet/srecode/template.el
Normal file
|
@ -0,0 +1,69 @@
|
|||
;;; srecode-template.el --- SRecoder template language parser support.
|
||||
|
||||
;;; Copyright (C) 2005, 2007, 2008 Free Software Foundation, Inc.
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; Parser setup for the semantic recoder template parser.
|
||||
|
||||
;;; Code:
|
||||
(require 'semantic)
|
||||
(require 'semantic/ctxt)
|
||||
(require 'semantic/wisent)
|
||||
(require 'srecode/srt-wy)
|
||||
|
||||
(define-mode-local-override semantic-tag-components
|
||||
srecode-template-mode (tag)
|
||||
"Return sectiondictionary tags."
|
||||
(when (semantic-tag-of-class-p tag 'function)
|
||||
(let ((dicts (semantic-tag-get-attribute tag :dictionaries))
|
||||
(ans nil))
|
||||
(while dicts
|
||||
(setq ans (append ans (cdr (car dicts))))
|
||||
(setq dicts (cdr dicts)))
|
||||
ans)
|
||||
))
|
||||
|
||||
(defun srecode-template-setup-parser ()
|
||||
"Setup buffer for parse."
|
||||
(srecode-template-wy--install-parser)
|
||||
|
||||
(setq
|
||||
;; Lexical Analysis
|
||||
semantic-lex-analyzer 'wisent-srecode-template-lexer
|
||||
;; Parsing
|
||||
;; Environment
|
||||
semantic-imenu-summary-function 'semantic-format-tag-name
|
||||
imenu-create-index-function 'semantic-create-imenu-index
|
||||
semantic-command-separation-character "\n"
|
||||
semantic-lex-comment-regex ";;"
|
||||
;; Speedbar
|
||||
semantic-symbol->name-assoc-list
|
||||
'((function . "Template")
|
||||
(variable . "Variable")
|
||||
)
|
||||
;; Navigation
|
||||
senator-step-at-tag-classes '(function variable)
|
||||
))
|
||||
|
||||
;;;;###autoload
|
||||
(add-hook 'srecode-template-mode-hook 'srecode-template-setup-parser)
|
||||
|
||||
(provide 'srecode/template)
|
||||
|
||||
;;; srecode/template.el ends here
|
282
lisp/cedet/srecode/texi.el
Normal file
282
lisp/cedet/srecode/texi.el
Normal file
|
@ -0,0 +1,282 @@
|
|||
;;; srecode-texi.el --- Srecode texinfo support.
|
||||
|
||||
;; Copyright (C) 2008, 2009 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Eric M. Ludlam <eric@siege-engine.com>
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;
|
||||
;; Texinfo semantic recoder support.
|
||||
;;
|
||||
;; Contains some handlers, and a few simple texinfo srecoder applications.
|
||||
|
||||
(require 'semantic)
|
||||
(require 'semantic/texi)
|
||||
(require 'srecode/semantic)
|
||||
|
||||
;;; Code:
|
||||
|
||||
(defun srecode-texi-add-menu (newnode)
|
||||
"Add an item into the current menu. Add @node statements as well.
|
||||
Argument NEWNODE is the name of the new node."
|
||||
(interactive "sName of new node: ")
|
||||
(srecode-load-tables-for-mode major-mode)
|
||||
(semantic-fetch-tags)
|
||||
(let ((currnode (reverse (semantic-find-tag-by-overlay)))
|
||||
(nodebounds nil))
|
||||
(when (not currnode)
|
||||
(error "Cannot find node to put menu item into"))
|
||||
(setq currnode (car currnode))
|
||||
(setq nodebounds (semantic-tag-texi-section-text-bounds currnode))
|
||||
;; Step 1:
|
||||
;; Limit search within this node.
|
||||
;; Step 2:
|
||||
;; Find the menu. If there isn't one, add one to the end.
|
||||
;; Step 3:
|
||||
;; Add new item to end of menu list.
|
||||
;; Step 4:
|
||||
;; Find correct node new item should show up after, and stick
|
||||
;; the new node there.
|
||||
(if (string= (semantic-texi-current-environment) "menu")
|
||||
;; We are already in a menu, so insert the new item right here.
|
||||
(beginning-of-line)
|
||||
;; Else, try to find a menu item to append to.
|
||||
(goto-char (car nodebounds))
|
||||
(if (not (re-search-forward "^@menu" (car (cdr nodebounds)) t))
|
||||
(progn
|
||||
(goto-char (car (cdr nodebounds)))
|
||||
(if (not (y-or-n-p "Add menu here? "))
|
||||
(error "Abort"))
|
||||
(srecode-insert "declaration:menu"))
|
||||
;; Else, find the end
|
||||
(re-search-forward "@end menu")
|
||||
(beginning-of-line)))
|
||||
;; At this point, we are in a menu... or not.
|
||||
;; If we are, do stuff, else error.
|
||||
(when (string= (semantic-texi-current-environment) "menu")
|
||||
(let ((menuname newnode)
|
||||
(returnpoint nil))
|
||||
(srecode-insert "declaration:menuitem" "NAME" menuname)
|
||||
(set-mark (point))
|
||||
(setq returnpoint (make-marker))
|
||||
;; Update the bound since we added text
|
||||
(setq nodebounds (semantic-tag-texi-section-text-bounds currnode))
|
||||
(beginning-of-line)
|
||||
(forward-char -1)
|
||||
(beginning-of-line)
|
||||
(let ((end nil))
|
||||
(if (not (looking-at "\\* \\([^:]+\\):"))
|
||||
(setq end (car (cdr nodebounds)))
|
||||
(let* ((nname (match-string 1))
|
||||
(tag
|
||||
(semantic-deep-find-tags-by-name nname (current-buffer))))
|
||||
(when tag
|
||||
(setq end (semantic-tag-end (car tag))))
|
||||
))
|
||||
(when (not end)
|
||||
(goto-char returnpoint)
|
||||
(error "Could not find location for new node" ))
|
||||
(when end
|
||||
(goto-char end)
|
||||
(when (bolp) (forward-char -1))
|
||||
(insert "\n")
|
||||
(if (eq (semantic-current-tag) currnode)
|
||||
(srecode-insert "declaration:subnode" "NAME" menuname)
|
||||
(srecode-insert "declaration:node" "NAME" menuname))
|
||||
)
|
||||
)))
|
||||
))
|
||||
|
||||
;;;###autoload
|
||||
(defun srecode-semantic-handle-:texi (dict)
|
||||
"Add macros into the dictionary DICT based on the current texinfo file.
|
||||
Adds the following:
|
||||
LEVEL - chapter, section, subsection, etc
|
||||
NEXTLEVEL - One below level"
|
||||
|
||||
;; LEVEL and NEXTLEVEL calculation
|
||||
(semantic-fetch-tags)
|
||||
(let ((tags (reverse (semantic-find-tag-by-overlay)))
|
||||
(level nil))
|
||||
(while (and tags (not (semantic-tag-of-class-p (car tags) 'section)))
|
||||
(setq tags (cdr tags)))
|
||||
(when tags
|
||||
(save-excursion
|
||||
(goto-char (semantic-tag-start (car tags)))
|
||||
(when (looking-at "@node")
|
||||
(forward-line 1)
|
||||
(beginning-of-line))
|
||||
(when (looking-at "@\\(\\w+\\)")
|
||||
(setq level (match-string 1))
|
||||
)))
|
||||
(srecode-dictionary-set-value dict "LEVEL" (or level "chapter"))
|
||||
(let ((nl (assoc level '( ( nil . "top" )
|
||||
("top" . "chapter")
|
||||
("chapter" . "section")
|
||||
("section" . "subsection")
|
||||
("subsection" . "subsubsection")
|
||||
("subsubsection" . "subsubsection")
|
||||
))))
|
||||
(srecode-dictionary-set-value dict "NEXTLEVEL" (cdr nl))))
|
||||
)
|
||||
|
||||
;;;###autoload
|
||||
(defun srecode-semantic-handle-:texitag (dict)
|
||||
"Add macros into the dictionary DICT based on the current :tag file.
|
||||
Adds the following:
|
||||
TAGDOC - Texinfo formatted doc string for :tag."
|
||||
|
||||
;; If we also have a TAG, what is the doc?
|
||||
(let ((tag (srecode-dictionary-lookup-name dict "TAG"))
|
||||
(doc nil)
|
||||
)
|
||||
|
||||
;; If the user didn't apply :tag, then do so now.
|
||||
(when (not tag)
|
||||
(srecode-semantic-handle-:tag dict))
|
||||
|
||||
(setq tag (srecode-dictionary-lookup-name dict "TAG"))
|
||||
|
||||
(when (not tag)
|
||||
(error "No tag to insert for :texitag template argument"))
|
||||
|
||||
;; Extract the tag out of the compound object.
|
||||
(setq tag (oref tag :prime))
|
||||
|
||||
;; Extract the doc string
|
||||
(setq doc (semantic-documentation-for-tag tag))
|
||||
|
||||
(when doc
|
||||
(srecode-dictionary-set-value dict "TAGDOC"
|
||||
(srecode-texi-massage-to-texinfo
|
||||
tag (semantic-tag-buffer tag)
|
||||
doc)))
|
||||
))
|
||||
|
||||
;;; OVERRIDES
|
||||
;;
|
||||
;; Override some semantic and srecode features with texi specific
|
||||
;; versions.
|
||||
|
||||
(define-mode-local-override semantic-insert-foreign-tag
|
||||
texinfo-mode (foreign-tag)
|
||||
"Insert TAG from a foreign buffer in TAGFILE.
|
||||
Assume TAGFILE is a source buffer, and create a documentation
|
||||
thingy from it using the `document' tool."
|
||||
(let ((srecode-semantic-selected-tag foreign-tag))
|
||||
;; @todo - choose of the many types of tags to insert,
|
||||
;; or put all that logic into srecode.
|
||||
(srecode-insert "declaration:function")))
|
||||
|
||||
|
||||
|
||||
;;; Texinfo mangling.
|
||||
|
||||
(define-overloadable-function srecode-texi-texify-docstring
|
||||
(docstring)
|
||||
"Texify the doc string DOCSTRING.
|
||||
Takes plain text formatting that may exist, and converts it to
|
||||
using TeXinfo formatting.")
|
||||
|
||||
(defun srecode-texi-texify-docstring-default (docstring)
|
||||
"Texify the doc string DOCSTRING.
|
||||
Takes a few very generic guesses as to what the formatting is."
|
||||
(let ((case-fold-search nil)
|
||||
(start 0))
|
||||
(while (string-match
|
||||
"\\(^\\|[^{]\\)\\<\\([A-Z0-9_-]+\\)\\>\\($\\|[^}]\\)"
|
||||
docstring start)
|
||||
(let ((ms (match-string 2 docstring)))
|
||||
;(when (eq mode 'emacs-lisp-mode)
|
||||
; (setq ms (downcase ms)))
|
||||
|
||||
(when (not (or (string= ms "A")
|
||||
(string= ms "a")
|
||||
))
|
||||
(setq docstring (concat (substring docstring 0 (match-beginning 2))
|
||||
"@var{"
|
||||
ms
|
||||
"}"
|
||||
(substring docstring (match-end 2))))))
|
||||
(setq start (match-end 2)))
|
||||
;; Return our modified doc string.
|
||||
docstring))
|
||||
|
||||
(defun srecode-texi-massage-to-texinfo (tag buffer string)
|
||||
"Massage TAG's documentation from BUFFER as STRING.
|
||||
This is to take advantage of TeXinfo's markup symbols."
|
||||
(save-excursion
|
||||
(if buffer
|
||||
(progn (set-buffer buffer)
|
||||
(srecode-texi-texify-docstring string))
|
||||
;; Else, no buffer, so lets do something else
|
||||
(with-mode-local texinfo-mode
|
||||
(srecode-texi-texify-docstring string)))))
|
||||
|
||||
(define-mode-local-override srecode-texi-texify-docstring emacs-lisp-mode
|
||||
(string)
|
||||
"Take STRING, (a normal doc string), and convert it into a texinfo string.
|
||||
For instances where CLASS is the class being referenced, do not Xref
|
||||
that class.
|
||||
|
||||
`function' => @dfn{function}
|
||||
`variable' => @code{variable}
|
||||
`class' => @code{class} @xref{class}
|
||||
`unknown' => @code{unknonwn}
|
||||
\"text\" => ``text''
|
||||
'quoteme => @code{quoteme}
|
||||
non-nil => non-@code{nil}
|
||||
t => @code{t}
|
||||
:tag => @code{:tag}
|
||||
[ stuff ] => @code{[ stuff ]}
|
||||
Key => @kbd{Key} (key is C\\-h, M\\-h, SPC, RET, TAB and the like)
|
||||
... => @dots{}"
|
||||
(while (string-match "`\\([-a-zA-Z0-9<>.]+\\)'" string)
|
||||
(let* ((vs (substring string (match-beginning 1) (match-end 1)))
|
||||
(v (intern-soft vs)))
|
||||
(setq string
|
||||
(concat
|
||||
(replace-match (concat
|
||||
(if (fboundp v)
|
||||
"@dfn{" "@code{")
|
||||
vs "}")
|
||||
nil t string)))))
|
||||
(while (string-match "\\( \\|^\\)\\(nil\\|t\\|'[-a-zA-Z0-9]+\\|:[-a-zA-Z0-9]+\\)\\([. ,]\\|$\\)" string)
|
||||
(setq string (replace-match "@code{\\2}" t nil string 2)))
|
||||
(while (string-match "\\( \\|^\\)\\(\\(non-\\)\\(nil\\)\\)\\([. ,]\\|$\\)" string)
|
||||
(setq string (replace-match "\\3@code{\\4}" t nil string 2)))
|
||||
(while (string-match "\\( \\|^\\)\\(\\[[^]]+\\]\\)\\( \\|$\\)" string)
|
||||
(setq string (replace-match "@code{\\2}" t nil string 2)))
|
||||
(while (string-match "\\( \\|^\\)\\(\\(\\(C-\\|M-\\|S-\\)+\\([^ \t\n]\\|RET\\|SPC\\|TAB\\)\\)\\|\\(RET\\|SPC\\|TAB\\)\\)\\( \\|\\s.\\|$\\)" string)
|
||||
(setq string (replace-match "@kbd{\\2}" t nil string 2)))
|
||||
(while (string-match "\"\\(.+\\)\"" string)
|
||||
(setq string (replace-match "``\\1''" t nil string 0)))
|
||||
(while (string-match "\\.\\.\\." string)
|
||||
(setq string (replace-match "@dots{}" t nil string 0)))
|
||||
;; Also do base docstring type.
|
||||
(srecode-texi-texify-docstring-default string))
|
||||
|
||||
(provide 'srecode/texi)
|
||||
|
||||
;; Local variables:
|
||||
;; generated-autoload-file: "loaddefs.el"
|
||||
;; generated-autoload-feature: srecode/loaddefs
|
||||
;; generated-autoload-load-name: "srecode/texi"
|
||||
;; End:
|
||||
|
||||
;;; srecode/texi.el ends here
|
|
@ -2203,6 +2203,7 @@ since only a single case-insensitive search through the alist is made."
|
|||
("\\.f9[05]\\'" . f90-mode)
|
||||
("\\.indent\\.pro\\'" . fundamental-mode) ; to avoid idlwave-mode
|
||||
("\\.\\(pro\\|PRO\\)\\'" . idlwave-mode)
|
||||
("\\.srt\\'" . srecode-template-mode) ; in the CEDET library
|
||||
("\\.prolog\\'" . prolog-mode)
|
||||
("\\.tar\\'" . tar-mode)
|
||||
;; The list of archive file extensions should be in sync with
|
||||
|
|
266
test/cedet/srecode-tests.el
Normal file
266
test/cedet/srecode-tests.el
Normal file
|
@ -0,0 +1,266 @@
|
|||
;;; From srecode-fields:
|
||||
|
||||
(require 'srecode/fields)
|
||||
|
||||
(defvar srecode-field-utest-text
|
||||
"This is a test buffer.
|
||||
|
||||
It is filled with some text."
|
||||
"Text for tests.")
|
||||
|
||||
(defun srecode-field-utest ()
|
||||
"Test the srecode field manager."
|
||||
(interactive)
|
||||
(if (featurep 'xemacs)
|
||||
(message "There is no XEmacs support for SRecode Fields.")
|
||||
(srecode-field-utest-impl)))
|
||||
|
||||
(defun srecode-field-utest-impl ()
|
||||
"Implementation of the SRecode field utest."
|
||||
(save-excursion
|
||||
(find-file "/tmp/srecode-field-test.txt")
|
||||
|
||||
(erase-buffer)
|
||||
(goto-char (point-min))
|
||||
(insert srecode-field-utest-text)
|
||||
(set-buffer-modified-p nil)
|
||||
|
||||
;; Test basic field generation.
|
||||
(let ((srecode-field-archive nil)
|
||||
(f nil))
|
||||
|
||||
(end-of-line)
|
||||
(forward-word -1)
|
||||
|
||||
(setq f (srecode-field "Test"
|
||||
:name "TEST"
|
||||
:start 6
|
||||
:end 8))
|
||||
|
||||
(when (or (not (slot-boundp f 'overlay)) (not (oref f overlay)))
|
||||
(error "Field test: Overlay info not created for field"))
|
||||
|
||||
(when (and (overlay-p (oref f overlay))
|
||||
(not (overlay-get (oref f overlay) 'srecode-init-only)))
|
||||
(error "Field creation overlay is not tagged w/ init flag"))
|
||||
|
||||
(srecode-overlaid-activate f)
|
||||
|
||||
(when (or (not (overlay-p (oref f overlay)))
|
||||
(overlay-get (oref f overlay) 'srecode-init-only))
|
||||
(error "New field overlay not created during activation"))
|
||||
|
||||
(when (not (= (length srecode-field-archive) 1))
|
||||
(error "Field test: Incorrect number of elements in the field archive"))
|
||||
(when (not (eq f (car srecode-field-archive)))
|
||||
(error "Field test: Field did not auto-add itself to the field archive"))
|
||||
|
||||
(when (not (overlay-get (oref f overlay) 'keymap))
|
||||
(error "Field test: Overlay keymap not set"))
|
||||
|
||||
(when (not (string= "is" (srecode-overlaid-text f)))
|
||||
(error "Field test: Expected field text 'is', not %s"
|
||||
(srecode-overlaid-text f)))
|
||||
|
||||
;; Test deletion.
|
||||
(srecode-delete f)
|
||||
|
||||
(when (slot-boundp f 'overlay)
|
||||
(error "Field test: Overlay not deleted after object delete"))
|
||||
)
|
||||
|
||||
;; Test basic region construction.
|
||||
(let* ((srecode-field-archive nil)
|
||||
(reg nil)
|
||||
(fields
|
||||
(list
|
||||
(srecode-field "Test1" :name "TEST-1" :start 5 :end 10)
|
||||
(srecode-field "Test2" :name "TEST-2" :start 15 :end 20)
|
||||
(srecode-field "Test3" :name "TEST-3" :start 25 :end 30)
|
||||
|
||||
(srecode-field "Test4" :name "TEST-4" :start 35 :end 35))
|
||||
))
|
||||
|
||||
(when (not (= (length srecode-field-archive) 4))
|
||||
(error "Region Test: Found %d fields. Expected 4"
|
||||
(length srecode-field-archive)))
|
||||
|
||||
(setq reg (srecode-template-inserted-region "REG"
|
||||
:start 4
|
||||
:end 40))
|
||||
|
||||
(srecode-overlaid-activate reg)
|
||||
|
||||
;; Make sure it was cleared.
|
||||
(when srecode-field-archive
|
||||
(error "Region Test: Did not clear field archive"))
|
||||
|
||||
;; Auto-positioning.
|
||||
(when (not (eq (point) 5))
|
||||
(error "Region Test: Did not reposition on first field"))
|
||||
|
||||
;; Active region
|
||||
(when (not (eq (srecode-active-template-region) reg))
|
||||
(error "Region Test: Active region not set"))
|
||||
|
||||
;; Various sizes
|
||||
(mapc (lambda (T)
|
||||
(if (string= (object-name-string T) "Test4")
|
||||
(progn
|
||||
(when (not (srecode-empty-region-p T))
|
||||
(error "Field %s is not empty"
|
||||
(object-name T)))
|
||||
)
|
||||
(when (not (= (srecode-region-size T) 5))
|
||||
(error "Calculated size of %s was not 5"
|
||||
(object-name T)))))
|
||||
fields)
|
||||
|
||||
;; Make sure things stay up after a 'command'.
|
||||
(srecode-field-post-command)
|
||||
(when (not (eq (srecode-active-template-region) reg))
|
||||
(error "Region Test: Active region did not stay up"))
|
||||
|
||||
;; Test field movement.
|
||||
(when (not (eq (srecode-overlaid-at-point 'srecode-field)
|
||||
(nth 0 fields)))
|
||||
(error "Region Test: Field %s not under point"
|
||||
(object-name (nth 0 fields))))
|
||||
|
||||
(srecode-field-next)
|
||||
|
||||
(when (not (eq (srecode-overlaid-at-point 'srecode-field)
|
||||
(nth 1 fields)))
|
||||
(error "Region Test: Field %s not under point"
|
||||
(object-name (nth 1 fields))))
|
||||
|
||||
(srecode-field-prev)
|
||||
|
||||
(when (not (eq (srecode-overlaid-at-point 'srecode-field)
|
||||
(nth 0 fields)))
|
||||
(error "Region Test: Field %s not under point"
|
||||
(object-name (nth 0 fields))))
|
||||
|
||||
;; Move cursor out of the region and have everything cleaned up.
|
||||
(goto-char 42)
|
||||
(srecode-field-post-command)
|
||||
(when (srecode-active-template-region)
|
||||
(error "Region Test: Active region did not clear on move out"))
|
||||
|
||||
(mapc (lambda (T)
|
||||
(when (slot-boundp T 'overlay)
|
||||
(error "Overlay did not clear off of of field %s"
|
||||
(object-name T))))
|
||||
fields)
|
||||
|
||||
;; End of LET
|
||||
)
|
||||
|
||||
;; Test variable linkage.
|
||||
(let* ((srecode-field-archive nil)
|
||||
(f1 (srecode-field "Test1" :name "TEST" :start 6 :end 8))
|
||||
(f2 (srecode-field "Test2" :name "TEST" :start 28 :end 30))
|
||||
(f3 (srecode-field "Test3" :name "NOTTEST" :start 35 :end 40))
|
||||
(reg (srecode-template-inserted-region "REG" :start 4 :end 40))
|
||||
)
|
||||
(srecode-overlaid-activate reg)
|
||||
|
||||
(when (not (string= (srecode-overlaid-text f1)
|
||||
(srecode-overlaid-text f2)))
|
||||
(error "Linkage Test: Init strings are not ="))
|
||||
(when (string= (srecode-overlaid-text f1)
|
||||
(srecode-overlaid-text f3))
|
||||
(error "Linkage Test: Init string on dissimilar fields is now the same"))
|
||||
|
||||
(goto-char 7)
|
||||
(insert "a")
|
||||
|
||||
(when (not (string= (srecode-overlaid-text f1)
|
||||
(srecode-overlaid-text f2)))
|
||||
(error "Linkage Test: mid-insert strings are not ="))
|
||||
(when (string= (srecode-overlaid-text f1)
|
||||
(srecode-overlaid-text f3))
|
||||
(error "Linkage Test: mid-insert string on dissimilar fields is now the same"))
|
||||
|
||||
(goto-char 9)
|
||||
(insert "t")
|
||||
|
||||
(when (not (string= (srecode-overlaid-text f1) "iast"))
|
||||
(error "Linkage Test: tail-insert failed to captured added char"))
|
||||
(when (not (string= (srecode-overlaid-text f1)
|
||||
(srecode-overlaid-text f2)))
|
||||
(error "Linkage Test: tail-insert strings are not ="))
|
||||
(when (string= (srecode-overlaid-text f1)
|
||||
(srecode-overlaid-text f3))
|
||||
(error "Linkage Test: tail-insert string on dissimilar fields is now the same"))
|
||||
|
||||
(goto-char 6)
|
||||
(insert "b")
|
||||
|
||||
(when (not (string= (srecode-overlaid-text f1) "biast"))
|
||||
(error "Linkage Test: tail-insert failed to captured added char"))
|
||||
(when (not (string= (srecode-overlaid-text f1)
|
||||
(srecode-overlaid-text f2)))
|
||||
(error "Linkage Test: tail-insert strings are not ="))
|
||||
(when (string= (srecode-overlaid-text f1)
|
||||
(srecode-overlaid-text f3))
|
||||
(error "Linkage Test: tail-insert string on dissimilar fields is now the same"))
|
||||
|
||||
;; Cleanup
|
||||
(srecode-delete reg)
|
||||
)
|
||||
|
||||
(set-buffer-modified-p nil)
|
||||
|
||||
(message " All field tests passed.")
|
||||
))
|
||||
|
||||
;;; From srecode-document:
|
||||
|
||||
(require 'srecode/doc)
|
||||
|
||||
(defun srecode-document-function-comment-extract-test ()
|
||||
"Test old comment extraction.
|
||||
Dump out the extracted dictionary."
|
||||
(interactive)
|
||||
|
||||
(srecode-load-tables-for-mode major-mode)
|
||||
(srecode-load-tables-for-mode major-mode 'document)
|
||||
|
||||
(if (not (srecode-table))
|
||||
(error "No template table found for mode %s" major-mode))
|
||||
|
||||
(let* ((temp (srecode-template-get-table (srecode-table)
|
||||
"function-comment"
|
||||
"declaration"
|
||||
'document))
|
||||
(fcn-in (semantic-current-tag)))
|
||||
|
||||
(if (not temp)
|
||||
(error "No templates for function comments"))
|
||||
|
||||
;; Try to figure out the tag we want to use.
|
||||
(when (or (not fcn-in)
|
||||
(not (semantic-tag-of-class-p fcn-in 'function)))
|
||||
(error "No tag of class 'function to insert comment for"))
|
||||
|
||||
(let ((lextok (semantic-documentation-comment-preceeding-tag fcn-in 'lex))
|
||||
)
|
||||
|
||||
(when (not lextok)
|
||||
(error "No comment to attempt an extraction"))
|
||||
|
||||
(let ((s (semantic-lex-token-start lextok))
|
||||
(e (semantic-lex-token-end lextok))
|
||||
(extract nil))
|
||||
|
||||
(pulse-momentary-highlight-region s e)
|
||||
|
||||
;; Extract text from the existing comment.
|
||||
(setq extract (srecode-extract temp s e))
|
||||
|
||||
(with-output-to-temp-buffer "*SRECODE DUMP*"
|
||||
(princ "EXTRACTED DICTIONARY FOR ")
|
||||
(princ (semantic-tag-name fcn-in))
|
||||
(princ "\n--------------------------------------------\n")
|
||||
(srecode-dump extract))))))
|
Loading…
Add table
Reference in a new issue