1 ;;; srecode/document.el --- Documentation (comment) generation
3 ;; Copyright (C) 2008-2013 Free Software Foundation, Inc.
5 ;; Author: Eric M. Ludlam <eric@siege-engine.com>
7 ;; This file is part of GNU Emacs.
9 ;; GNU Emacs is free software: you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation, either version 3 of the License, or
12 ;; (at your option) any later version.
14 ;; GNU Emacs is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;; GNU General Public License for more details.
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
24 ;; Routines for fabricating human readable text from function and
25 ;; variable names as base-text for function comments. Document is not
26 ;; meant to generate end-text for any function. It is merely meant to
27 ;; provide some useful base words and text, and as a framework for
32 ;; Document was first written w/ cparse, a custom regexp based c parser.
34 ;; Document was then ported to cedet/semantic using sformat (super
35 ;; format) as the templating engine.
37 ;; Document has now been ported to srecode, using the semantic recoder
38 ;; as the templating engine.
40 ;; This file combines srecode/document.el and srecode/document-vars.el
41 ;; from the CEDET repository.
43 (require 'srecode
/args
)
44 (require 'srecode
/dictionary
)
45 (require 'srecode
/extract
)
46 (require 'srecode
/insert
)
47 (require 'srecode
/semantic
)
50 (require 'semantic
/tag
)
51 (require 'semantic
/doc
)
56 (defgroup document nil
57 "File and tag browser frame."
61 (defcustom srecode-document-autocomment-common-nouns-abbrevs
63 ("sock\\(et\\)?" .
"socket")
64 ("addr\\(ess\\)?" .
"address")
65 ("buf\\(f\\(er\\)?\\)?" .
"buffer")
66 ("cur\\(r\\(ent\\)?\\)?" .
"current")
67 ("dev\\(ice\\)?" .
"device")
69 ("i18n" .
"internationalization")
72 ("l10n" .
"localization")
73 ("msg\\|message" .
"message")
75 ("next\\|nxt" .
"next")
76 ("num\\(ber\\)?" .
"number")
79 ("obj\\|object" .
"object")
80 ("previous\\|prev" .
"previous")
81 ("str\\(ing\\)?" .
"string")
83 ("\\(^\\|\\s-\\)id\\($\\|\\s-\\)" .
"Identifier") ;complex cause ;common syllable
85 "List of common English abbreviations or full words.
86 These are nouns (as opposed to verbs) for use in creating expanded
87 versions of names. This is an alist with each element of the form:
89 MATCH is a regexp to match in the type field.
92 :type
'(repeat (cons (string :tag
"Regexp")
93 (string :tag
"Doc Text"))))
95 (defcustom srecode-document-autocomment-function-alist
97 ("abort" .
"Aborts the")
98 ;; trick to get re-alloc and alloc to pair into one sentence.
99 ("realloc" .
"moves or ")
100 ("alloc\\(ate\\)?" .
"Allocates and initializes a new ")
101 ("clean" .
"Cleans up the")
102 ("clobber" .
"Removes")
103 ("close" .
"Cleanly closes")
104 ("check" .
"Checks the")
105 ("comp\\(are\\)?" .
"Compares the")
106 ("create" .
"Creates a new ")
108 ("free" .
"Frees up space")
109 ("gen\\(erate\\)?" .
"Generates a new ")
110 ("get\\|find" .
"Looks for the given ")
111 ("gobble" .
"Removes")
112 ("he?lp" .
"Provides help for")
113 ("li?ste?n" .
"Listens for ")
114 ("connect" .
"Connects to ")
115 ("acc?e?pt" .
"Accepts a ")
116 ("load" .
"Loads in ")
117 ("match" .
"Check that parameters match")
118 ("name" .
"Provides a name which ")
119 ("new" .
"Allocates a ")
120 ("parse" .
"Parses the parameters and returns ")
121 ("print\\|display" .
"Prints out")
122 ("read" .
"Reads from")
123 ("reset" .
"Resets the parameters and returns")
124 ("scan" .
"Scans the ")
125 ("setup\\|init\\(ialize\\)?" .
"Initializes the ")
126 ("select" .
"Chooses the ")
128 ("re?c\\(v\\|ieves?\\)" .
"Receives a ")
130 ("update" .
"Updates the ")
131 ("wait" .
"Waits for ")
132 ("write" .
"Writes to")
134 "List of names to string match against the function name.
135 This is an alist with each element of the form:
137 MATCH is a regexp to match in the type field.
140 Certain prefixes may always mean the same thing, and the same comment
141 can be used as a beginning for the description. Regexp should be
142 lower case since the string they are compared to is downcased.
143 A string may end in a space, in which case, last-alist is searched to
144 see how best to describe what can be returned.
145 Doesn't always work correctly, but that is just because English
146 doesn't always work correctly."
148 :type
'(repeat (cons (string :tag
"Regexp")
149 (string :tag
"Doc Text"))))
151 (defcustom srecode-document-autocomment-common-nouns-abbrevs
153 ("sock\\(et\\)?" .
"socket")
154 ("addr\\(ess\\)?" .
"address")
155 ("buf\\(f\\(er\\)?\\)?" .
"buffer")
156 ("cur\\(r\\(ent\\)?\\)?" .
"current")
157 ("dev\\(ice\\)?" .
"device")
160 ("msg\\|message" .
"message")
162 ("next\\|nxt" .
"next")
165 ("obj\\|object" .
"object")
166 ("previous\\|prev" .
"previous")
167 ("str\\(ing\\)?" .
"string")
169 ("num\\(ber\\)?" .
"number")
170 ("\\(^\\|\\s-\\)id\\($\\|\\s-\\)" .
"Identifier") ;complex cause ;common syllable
172 "List of common English abbreviations or full words.
173 These are nouns (as opposed to verbs) for use in creating expanded
174 versions of names. This is an alist with each element of the form:
176 MATCH is a regexp to match in the type field.
179 :type
'(repeat (cons (string :tag
"Regexp")
180 (string :tag
"Doc Text"))))
182 (defcustom srecode-document-autocomment-return-first-alist
184 ;; Static must be first in the list to provide the intro to the sentence
185 ("static" .
"Locally defined function which ")
186 ("Bool\\|BOOL" .
"Status of ")
188 "List of regexp matches for types.
189 They provide a little bit of text when typing information is
191 This is an alist with each element of the form:
193 MATCH is a regexp to match in the type field.
196 :type
'(repeat (cons (string :tag
"Regexp")
197 (string :tag
"Doc Text"))))
199 (defcustom srecode-document-autocomment-return-last-alist
201 ("static[ \t\n]+struct \\([a-zA-Z0-9_]+\\)" .
"%s")
202 ("struct \\([a-zA-Z0-9_]+\\)" .
"%s")
203 ("static[ \t\n]+union \\([a-zA-Z0-9_]+\\)" .
"%s")
204 ("union \\([a-zA-Z0-9_]+\\)" .
"%s")
205 ("static[ \t\n]+enum \\([a-zA-Z0-9_]+\\)" .
"%s")
206 ("enum \\([a-zA-Z0-9_]+\\)" .
"%s")
207 ("static[ \t\n]+\\([a-zA-Z0-9_]+\\)" .
"%s")
208 ("\\([a-zA-Z0-9_]+\\)" .
"of type %s")
210 "List of regexps which provide the type of the return value.
211 This is an alist with each element of the form:
213 MATCH is a regexp to match in the type field.
214 RESULT is a string, which can contain %s, which is replaced with
217 :type
'(repeat (cons (string :tag
"Regexp")
218 (string :tag
"Doc Text"))))
220 (defcustom srecode-document-autocomment-param-alist
221 '( ("[Cc]txt" .
"Context")
222 ("[Ii]d" .
"Identifier of")
223 ("[Tt]ype" .
"Type of")
224 ("[Nn]ame" .
"Name of")
225 ("argc" .
"Number of arguments")
226 ("argv" .
"Argument vector")
227 ("envp" .
"Environment variable vector")
229 "Alist of common variable names appearing as function parameters.
230 This is an alist with each element of the form:
232 MATCH is a regexp to match in the type field.
233 RESULT is a string of text to use to describe MATCH.
234 When one is encountered, document-insert-parameters will automatically
235 place this comment after the parameter name."
237 :type
'(repeat (cons (string :tag
"Regexp")
238 (string :tag
"Doc Text"))))
240 (defcustom srecode-document-autocomment-param-type-alist
241 '(("const" .
"Constant")
243 ("char[ ]*\\*" .
"String ")
244 ("\\*\\*" .
"Pointer to ")
246 ("char[ ]*\\([^ \t*]\\|$\\)" .
"Character")
247 ("int\\|long" .
"Number of")
249 ("float\\|double" .
"Value of")
250 ;; How about some X things?
251 ("Bool\\|BOOL" .
"Flag")
252 ("Window" .
"Window")
253 ("GC" .
"Graphic Context")
254 ("Widget" .
"Widget")
256 "Alist of input parameter types and strings describing them.
257 This is an alist with each element of the form:
259 MATCH is a regexp to match in the type field.
262 :type
'(repeat (cons (string :tag
"Regexp")
263 (string :tag
"Doc Text"))))
266 (defun srecode-document-insert-comment ()
267 "Insert some comments.
268 Whack any comments that may be in the way and replace them.
269 If the region is active, then insert group function comments.
270 If the cursor is in a comment, figure out what kind of comment it is
272 If the cursor is in a function, insert a function comment.
273 If the cursor is on a one line prototype, then insert post-fcn comments."
275 (semantic-fetch-tags)
276 (let ((ctxt (srecode-calculate-context)))
277 (if ;; Active region stuff.
278 (or srecode-handle-region-when-non-active-flag
279 (eq last-command
'mouse-drag-region
)
280 (and transient-mark-mode mark-active
))
281 (if (> (point) (mark))
282 (srecode-document-insert-group-comments (mark) (point))
283 (srecode-document-insert-group-comments (point) (mark)))
286 ;; A declaration comment. Find what it documents.
287 (when (equal ctxt
'("declaration" "comment"))
289 ;; If we are on a one line tag/comment, go to that fcn.
290 (if (save-excursion (back-to-indentation)
291 (semantic-current-tag))
292 (back-to-indentation)
294 ;; Else, do we have a fcn following us?
295 (let ((tag (semantic-find-tag-by-overlay-next)))
296 (when tag
(semantic-go-to-tag tag
))))
299 ;; Now analyze the tag we may be on.
301 (if (semantic-current-tag)
303 ;; A one-line variable
304 ((and (semantic-tag-of-class-p (semantic-current-tag) 'variable
)
305 (srecode-document-one-line-tag-p (semantic-current-tag)))
306 (srecode-document-insert-variable-one-line-comment))
308 ((semantic-tag-of-class-p (semantic-current-tag) 'function
)
309 (srecode-document-insert-function-comment))
312 (error "Not sure what to comment"))
315 ;; ELSE, no tag. Perhaps we should just insert a nice section
318 (let ((title (read-string "Section Title (RET to skip): ")))
320 (when (and (stringp title
) (not (= (length title
) 0)))
321 (srecode-document-insert-section-comment title
)))
325 (defun srecode-document-insert-section-comment (&optional title
)
326 "Insert a section comment with TITLE."
327 (interactive "sSection Title: ")
329 (srecode-load-tables-for-mode major-mode
)
330 (srecode-load-tables-for-mode major-mode
'document
)
332 (if (not (srecode-table))
333 (error "No template table found for mode %s" major-mode
))
335 (let* ((dict (srecode-create-dictionary))
336 (temp (srecode-template-get-table (srecode-table)
341 (error "No templates for inserting section comments"))
344 (srecode-dictionary-set-value
347 (srecode-insert-fcn temp dict
)
351 (defun srecode-document-trim-whitespace (str)
352 "Strip stray whitespace from around STR."
353 (when (string-match "^\\(\\s-\\|\n\\)+" str
)
354 (setq str
(replace-match "" t t str
)))
355 (when (string-match "\\(\\s-\\|\n\\)+$" str
)
356 (setq str
(replace-match "" t t str
)))
360 (defun srecode-document-insert-function-comment (&optional fcn-in
)
361 "Insert or replace a function comment.
362 FCN-IN is the Semantic tag of the function to add a comment too.
363 If FCN-IN is not provided, the current tag is used instead.
364 It is assumed that the comment occurs just in front of FCN-IN."
367 (srecode-load-tables-for-mode major-mode
)
368 (srecode-load-tables-for-mode major-mode
'document
)
370 (if (not (srecode-table))
371 (error "No template table found for mode %s" major-mode
))
373 (let* ((dict (srecode-create-dictionary))
374 (temp (srecode-template-get-table (srecode-table)
379 (error "No templates for inserting function comments"))
381 ;; Try to figure out the tag we want to use.
383 (semantic-fetch-tags)
384 (setq fcn-in
(semantic-current-tag)))
386 (when (or (not fcn-in
)
387 (not (semantic-tag-of-class-p fcn-in
'function
)))
388 (error "No tag of class 'function to insert comment for"))
390 (if (not (eq (current-buffer) (semantic-tag-buffer fcn-in
)))
391 (error "Only insert comments for tags in the current buffer"))
393 ;; Find any existing doc strings.
394 (semantic-go-to-tag fcn-in
)
398 (let ((lextok (semantic-documentation-comment-preceeding-tag fcn-in
'lex
))
400 (srecode-document-function-name-comment fcn-in
))
404 (let* ((s (semantic-lex-token-start lextok
))
405 (e (semantic-lex-token-end lextok
))
407 (srecode-document-trim-whitespace
410 (semantic-doc-snarf-comment-for-tag nil
))))
411 (extract (condition-case nil
412 (srecode-extract temp s e
)
415 (distance (count-lines e
(semantic-tag-start fcn-in
)))
416 (belongelsewhere (save-excursion
418 (back-to-indentation)
419 (semantic-current-tag)))
422 (when (not belongelsewhere
)
424 (pulse-momentary-highlight-region s e
)
426 ;; There are many possible states that comment could be in.
427 ;; Take a guess about what the user would like to do, and ask
428 ;; the right kind of question.
429 (when (or (not (> distance
2))
430 (y-or-n-p "Replace this comment? "))
434 (delete-horizontal-space)
435 (delete-blank-lines))
438 ((and plaintext
(not extract
))
439 (if (y-or-n-p "Convert old-style comment to Template with old text? ")
440 (setq doctext plaintext
))
444 (when (y-or-n-p "Refresh pre-existing comment (recycle old doc)? ")
448 (srecode-document-trim-whitespace
449 (srecode-dictionary-lookup-name extract
"DOC")))))
455 ;; Perform the insertion
456 (let ((srecode-semantic-selected-tag fcn-in
)
457 (srecode-semantic-apply-tag-augment-hook
459 (srecode-dictionary-set-value
463 (srecode-document-parameter-comment tag
))
466 (srecode-insert-fcn temp dict
)
471 (defun srecode-document-insert-variable-one-line-comment (&optional var-in
)
472 "Insert or replace a variable comment.
473 VAR-IN is the Semantic tag of the function to add a comment too.
474 If VAR-IN is not provided, the current tag is used instead.
475 It is assumed that the comment occurs just after VAR-IN."
478 (srecode-load-tables-for-mode major-mode
)
479 (srecode-load-tables-for-mode major-mode
'document
)
481 (if (not (srecode-table))
482 (error "No template table found for mode %s" major-mode
))
484 (let* ((dict (srecode-create-dictionary))
485 (temp (srecode-template-get-table (srecode-table)
486 "variable-same-line-comment"
490 (error "No templates for inserting variable comments"))
492 ;; Try to figure out the tag we want to use.
494 (semantic-fetch-tags)
495 (setq var-in
(semantic-current-tag)))
497 (when (or (not var-in
)
498 (not (semantic-tag-of-class-p var-in
'variable
)))
499 (error "No tag of class 'variable to insert comment for"))
501 (if (not (eq (current-buffer) (semantic-tag-buffer var-in
)))
502 (error "Only insert comments for tags in the current buffer"))
504 ;; Find any existing doc strings.
505 (goto-char (semantic-tag-end var-in
))
506 (skip-syntax-forward "-" (point-at-eol))
507 (let ((lextok (semantic-doc-snarf-comment-for-tag 'lex
))
511 (let ((s (semantic-lex-token-start lextok
))
512 (e (semantic-lex-token-end lextok
)))
514 (pulse-momentary-highlight-region s e
)
516 (when (not (y-or-n-p "A comment already exists. Replace? "))
519 ;; Extract text from the existing comment.
520 (srecode-extract temp s e
)
523 (goto-char s
) ;; To avoid adding a CR.
527 ;; Clean up the end of the line and use handy comment-column.
529 (delete-horizontal-space)
530 (move-to-column comment-column t
)
531 (when (< (point) (point-at-eol)) (end-of-line))
533 ;; Perform the insertion
534 (let ((srecode-semantic-selected-tag var-in
)
535 (srecode-semantic-apply-tag-augment-hook
537 (srecode-dictionary-set-value
538 dict
"DOC" (srecode-document-parameter-comment
541 (srecode-insert-fcn temp dict
)
546 (defun srecode-document-insert-group-comments (beg end
)
547 "Insert group comments around the active between BEG and END.
548 If the region includes only parts of some tags, expand out
549 to the beginning and end of the tags on the region.
550 If there is only one tag in the region, complain."
552 (srecode-load-tables-for-mode major-mode
)
553 (srecode-load-tables-for-mode major-mode
'document
)
555 (if (not (srecode-table))
556 (error "No template table found for mode %s" major-mode
))
558 (let* ((dict (srecode-create-dictionary))
559 (context "declaration")
562 (tag-start (save-excursion
564 (or (semantic-current-tag)
565 (semantic-find-tag-by-overlay-next))))
566 (tag-end (save-excursion
568 (or (semantic-current-tag)
569 (semantic-find-tag-by-overlay-prev))))
575 ;; If beg/end wrapped nothing, then tag-start,end would actually
576 ;; point at some odd stuff that is out of order.
577 (when (or (not tag-start
) (not tag-end
)
578 (> (semantic-tag-end tag-start
)
579 (semantic-tag-start tag-end
)))
584 ;; If tag-start and -end are the same, and it is a class or
585 ;; struct, try to find child tags inside the classdecl.
587 ((and (eq tag-start tag-end
)
589 (semantic-tag-of-class-p tag-start
'type
))
590 (setq parent-tag tag-start
)
591 (setq tag-start
(semantic-find-tag-by-overlay-next beg
)
592 tag-end
(semantic-find-tag-by-overlay-prev end
))
594 ((eq (semantic-find-tag-parent-by-overlay tag-start
) tag-end
)
595 (setq parent-tag tag-end
)
596 (setq tag-end
(semantic-find-tag-by-overlay-prev end
))
598 ((eq tag-start
(semantic-find-tag-parent-by-overlay tag-end
))
599 (setq parent-tag tag-start
)
600 (setq tag-start
(semantic-find-tag-by-overlay-next beg
))
605 ;; We are probably in a classdecl
606 ;; @todo -could I really use (srecode-calculate-context) ?
608 (setq context
"classdecl")
611 ;; Derive start and end locations based on the tags.
612 (setq first-pos
(semantic-tag-start tag-start
)
613 second-pos
(semantic-tag-end tag-end
))
615 ;; Now load the templates
616 (setq temp-start
(srecode-template-get-table (srecode-table)
617 "group-comment-start"
620 temp-end
(srecode-template-get-table (srecode-table)
625 (when (or (not temp-start
) (not temp-end
))
626 (error "No templates for inserting group comments"))
628 ;; Setup the name of this group ahead of time.
630 ;; @todo - guess at a name based on common strings
631 ;; of the tags in the group.
632 (srecode-dictionary-set-value
634 (read-string "Name of group: "))
636 ;; Perform the insertion
637 ;; Do the end first so we don't need to recalculate anything.
639 (goto-char second-pos
)
641 (srecode-insert-fcn temp-end dict
)
643 (goto-char first-pos
)
645 (srecode-insert-fcn temp-start dict
)
650 ;;; Document Generation Functions
652 ;; Routines for making up English style comments.
654 (defun srecode-document-function-name-comment (tag)
655 "Create documentation for the function defined in TAG.
656 If we can identify a verb in the list followed by some
657 name part then check the return value to see if we can use that to
658 finish off the sentence. That is, any function with 'alloc' in it will be
659 allocating something based on its type."
660 (let ((al srecode-document-autocomment-return-first-alist
)
664 (fname (semantic-tag-name tag
))
665 (retval (or (semantic-tag-type tag
) "")))
667 ;; convert a type list into a long string to analyze.
668 (setq retval
(car retval
)))
669 ;; check for modifiers like static
671 (if (string-match (car (car al
)) (downcase retval
))
673 (setq news
(concat news
(cdr (car al
))))
677 ;; check for verb parts!
678 (setq al srecode-document-autocomment-function-alist
)
680 (if (string-match (car (car al
)) (downcase fname
))
683 (concat news
(if dropit
(downcase (cdr (car al
)))
685 ;; if we end in a space, then we are expecting a potential
687 (if (= ?
(aref news
(1- (length news
))))
691 ;; check for noun parts!
692 (setq al srecode-document-autocomment-common-nouns-abbrevs
)
694 (if (string-match (car (car al
)) (downcase fname
))
697 (concat news
(if dropit
(downcase (cdr (car al
)))
701 ;; add trailers to names which are obviously returning something.
704 (setq al srecode-document-autocomment-return-last-alist
)
706 (if (string-match (car (car al
)) (downcase retval
))
710 ;; this one may use parts of the return value.
711 (format (cdr (car al
))
712 (srecode-document-programmer->english
713 (substring retval
(match-beginning 1)
716 (setq al
(cdr al
)))))
719 (defun srecode-document-parameter-comment (param &optional commentlist
)
720 "Convert tag or string PARAM into a name,comment pair.
721 Optional COMMENTLIST is list of previously existing comments to
722 use instead in alist form. If the name doesn't appear in the list of
723 standard names, then english it instead."
725 (aso srecode-document-autocomment-param-alist
)
727 (name (if (stringp param
) param
(semantic-tag-name param
)))
728 (tt (if (stringp param
) nil
(semantic-tag-type param
))))
729 ;; Make sure the type is a string.
731 (setq tt
(semantic-tag-name tt
)))
732 ;; Find name description parts.
734 (if (string-match (car (car aso
)) name
)
737 (setq cmt
(concat cmt
(cdr (car aso
))))))
738 (setq aso
(cdr aso
)))
739 (if (/= (length cmt
) 0)
741 ;; finally check for array parts
742 (if (and (not (stringp param
)) (semantic-tag-modifiers param
))
743 (setq cmt
(concat cmt
"array of ")))
744 (setq aso srecode-document-autocomment-param-type-alist
)
746 (if (string-match (car (car aso
)) tt
)
747 (setq cmt
(concat cmt
(cdr (car aso
)))))
748 (setq aso
(cdr aso
))))
749 ;; Convert from programmer to english.
751 (setq cmt
(concat cmt
" "
752 (srecode-document-programmer->english name
))))
755 (defun srecode-document-programmer->english
(programmer)
756 "Take PROGRAMMER and convert it into English.
757 Works with the following rules:
758 1) convert all _ into spaces.
759 2) inserts spaces between CamelCasing word breaks.
760 3) expands noun names based on common programmer nouns.
762 This function is designed for variables, not functions. This does
763 not account for verb parts."
764 (if (string= "" programmer
)
766 (let ((ind 0) ;index in string
767 (llow nil
) ;lower/upper case flag
768 (newstr nil
) ;new string being generated
769 (al nil
)) ;autocomment list
771 ;; 1) Convert underscores
773 (while (< ind
(length programmer
))
774 (setq newstr
(concat newstr
775 (if (= (aref programmer ind
) ?_
)
776 " " (char-to-string (aref programmer ind
)))))
778 (setq programmer newstr
782 ;; 2) Find word breaks between case changes
784 (while (< ind
(length programmer
))
787 (let ((tc (aref programmer ind
)))
788 (if (and (>= tc ?a
) (<= tc ?z
))
795 (concat " " (char-to-string tc
)))
796 (char-to-string tc
))))))
799 ;; 3) Expand the words if possible
805 (while (string-match (concat "^\\s-*\\([^ \t\n]+\\)") programmer
)
806 (let ((ts (substring programmer
(match-beginning 1) (match-end 1)))
808 (setq al srecode-document-autocomment-common-nouns-abbrevs
)
811 (if (string-match (car (car al
)) (downcase ts
))
813 (setq newstr
(concat newstr
(cdr (car al
))))
814 ;; don't terminate because we may actually have 2 words
815 ;; next to each other we didn't identify before
818 (if (not llow
) (setq newstr
(concat newstr ts
)))
819 (setq newstr
(concat newstr
" "))
820 (setq programmer
(substring programmer end
))))
825 (defun srecode-document-one-line-tag-p (tag)
826 "Does TAG fit on one line with space on the end?"
828 (semantic-go-to-tag tag
)
829 (and (<= (semantic-tag-end tag
) (point-at-eol))
830 (goto-char (semantic-tag-end tag
))
831 (< (current-column) 70))))
833 (provide 'srecode
/document
)
836 ;; generated-autoload-file: "loaddefs.el"
837 ;; generated-autoload-load-name: "srecode/document"
840 ;;; srecode/document.el ends here