diff lisp/cedet/srecode/document.el @ 104498:41dc39934483

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.
author Chong Yidong <cyd@stupidchicken.com>
date Sun, 20 Sep 2009 21:06:41 +0000
parents
children 2f2bc20297c6
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/cedet/srecode/document.el	Sun Sep 20 21:06:41 2009 +0000
@@ -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