" File: jcommenter.vim " Summary: Functions for documenting java-code " Author: Kalle Björklid " Last Modified: 6.7.2001 " Version: 0.4 " Modifications: " 0.4 : Recognizes now methods that have whitespaces before the '('. " The file comments can now be completely redefined (see below for " instructions) without editing the script. " The comment-skeleton for fields is changed from '/** */ to correspond " with the Sun's code conventions: " /** " * " */ " 0.3 : Added tag copying " Recognizes interfaces (same as classes) " 0.21: Improved the java-method recognition. " 0.2 : initial public release. " " Tested on Vim 5.8 " " Description: Functions for automatically generating JavaDoc compatible " documentation for java source-files. " The JCommentWriter() can produce four kinds of comments depending on the " current line/range. " - File comments. When the JCommentWriter()-function is called on the first " line of the file, a template for file comments is created. It looks like " this: " " /* Filename : " * Author : " * Summary : " * Version : " * Created : " */ " " The file name and 'Created'-date are automatically filled. The author- " field is filled with the contents of 'b:jcommenter_file_author'-variable. " The automated date insertion can be prevented by defining the " 'b:jcommenter_file_noautotime'-variable. " If you want to use another kind of skeleton for file comments, you can " define the variable 'b:jcommenter_own_file_comments', and define the " function 'OwnFileComments()' which will be called instead of the default " file comment writer-function. You can use the variable 'a:firstline' to " find out the line number where the function was called. " An example of what I have in my .vimrc: " " let b:jcommenter_own_file_comments='true' " function! OwnFileComments() " call append(a:firstline - 1, '/* File Name : ' . bufname("%")) " call append(a:firstline , ' * Author : Kalle Björklid ') " call append(a:firstline + 1, ' * Created : ' . strftime("%c")) " call append(a:firstline + 2, ' * ') " call append(a:firstline + 3, ' * Modifications:') " call append(a:firstline + 4, ' */') " endfunction " " - Class comments. When the JCommentWriter()-function is called on the " header of a class, a template for class comments is created. It looks like " this: " " /** " * " * @author " * @version " */ " public class ClassName { ... " " The @author-field is automatically filled with the contents of the " 'b:jcommenter_class_author'-variable. " The @version-field is automatically filled with the contents of the " 'b:jcommenter_class_def_version'-variable " - Method comments. JCommentWriter()-function automatically generates " the template for method comments if it is called on a header of a " method. The JavaDoc-tags are automatically generated by detecting " the parameter names, return value and exceptions that are declared " in the header of the method. An example: " " /** " * " * @param numbers " * @param str " * @return " * @throws IOException " * @throws NumberFormatException " */ " public String [] method(Integer[] numbers, String str) throws " IOException, NumberFormatException { " " Note: since the method header is on two lines, you need to specify " the range (include everything before the '{' or ';' if the method is " abstract). This can be done simply with line-wise visual selection. " - Field comments. Appends this above the field declaration: " /** " * " */ " - When executed on an existing JavaDoc tag, copy that tag under that line. " For example, when executed on the following line: " * @throws IOException If cannot read file " the result is: " * @throws IOException If cannot read file " * @throws " Not that life changing, but quite nice when you want to document those " RuntimeExceptions, or need to add another paramter. " " Installation: " I have these lines in my .vimrc: " autocmd FileType java let b:jcommenter_class_author='Kalle Björklid' " autocmd FileType java let b:jcommenter_file_author='Kalle Björklid ' " autocmd FileType java source $VIM/macros/jcommenter.vim " autocmd FileType java map :call JCommentWriter() " Now you can probably figure out what you should/could add to your .vimrc ;-) " And, of course, you need to copy this file to where the source-parameter " points. " " Usage: " If you wrote the map-line just as it is written above to your .vimrc, you " can trigger the comment-generation by pressing Alt-c (or "Meta-c"). As " described above, the cursor must be on the first line or on the same line " as the " method/class/attribute declaration in order to achieve something " useful. If the declaration extends to several lines, the range must be " specified. Range should include everything from the declaration that " comes before the '{' or ';'. Everything after either of those characters " is ignored. " " Notes: " - This is the first script for vim I've done, so be gentle ;-) " - If a method name starts with an uppercase letter, it is handled as a " constructor (no @return-tag is generated) " " TODO: better recognition for constructors " TODO: support for the umlaut-chars etc. that can be also used in java " TODO: make the script-code better. " TODO: move cursor to the start of the generated comment-template. " (How do I move the cursor in a script w/ vim 5.8 ?) " TODO: Inner classes/interfaces... " TODO: Recognise and update old method comments. " TODO: Add an option to use @exception instead of @throws (for backward " compatibility) " TODO: sort exceptions alphabetically (see " http://java.sun.com/j2se/javadoc/writingdoccomments/index.html) function! JCommentWriter() range " merge the lines of the range: let line = a:firstline let str = getline(line) let line = line + 1 while line < a:lastline + 1 let str = str . ' ' . getline(line) let line = line + 1 endwhile " decide which commneting function to use: let javaname = '[a-zA-Z_][a-zA-Z0-9_]*' let javaMethodPat = javaname . '\s*(.*)' let javaMethodPatNot = '=' let javaClassPat = '\(class\|interface\)\s\+' . javaname let brackets = '\(\s*\([\s*]\s\+\)\=\)' let javaVariablePat = javaname . brackets . '\|\(\s\+\)' . javaname . brackets . '\|\(\s*\)' . '\(;\|=.*;\)' let commentTagPat = '^\s*\*\s*@[a-zA-Z]\+' if str =~ commentTagPat call WriteCommentTag(str) elseif str =~ javaMethodPat && str !~ javaMethodPatNot call WriteMethodComments(str) elseif str =~ javaClassPat call WriteClassComments(str) elseif str =~ javaVariablePat call WriteVariableComments(str) elseif a:firstline == 1 call WriteFileComments() else echo 'Nothing to comment' endif endfunction function! WriteFileComments() let linenum = a:firstline - 1 if exists("b:jcommenter_own_file_comments") call OwnFileComments() return endif call append(linenum, '/* Filename : ' . bufname("%")) let indent = ' * ' let linenum = linenum + 1 let authorstr = ' Author : ' if exists("b:jcommenter_file_author") let authorstr = authorstr . b:jcommenter_file_author endif call append(linenum, indent . authorstr) let linenum = linenum + 1 call append(linenum, indent . ' Summary : ') let linenum = linenum + 1 call append(linenum, indent . ' Version : ') let linenum = linenum + 1 if exists("b:jcommenter_file_noautotime") let time = '' else let time = strftime("%c") endif call append(linenum, indent . ' Created : ' . time) let linenum = linenum + 1 call append(linenum, ' */') endfunction function! WriteCommentTag(str) let linenum = a:firstline let indent = GetIndent(a:str) let starPat = '^\s*\*' let tagBeginPat = starPat . '\s*@' let tagBeginPos = matchend(a:str, tagBeginPat) let posAfterStar = matchend(a:str, starPat) let afterStarIndent = strpart(a:str, posAfterStar, tagBeginPos - posAfterStar - 1) let tagEndPat = tagBeginPat . '[a-zA-Z]\+' let tagName = strpart(a:str, tagBeginPos, matchend(a:str, tagEndPat) - tagBeginPos) call append(linenum, indent . '*' . afterStarIndent . '@' . tagName) endfunction function! GetIndent(str) let indentEndPos = matchend(a:str, '^\s*') return strpart(a:str, 0 , indentEndPos) endfunction function! WriteVariableComments(argm) let str = a:argm let indent = GetIndent(str) let linenum = a:firstline - 1 call append(linenum, indent . '/**') let linenum = linenum + 1 call append(linenum, indent . ' *') let linenum = linenum + 1 call append(linenum, indent . ' */') endfunction function! WriteClassComments(argm) let str = a:argm let indent = GetIndent(str) let linenum = a:firstline - 1 call append(linenum, indent . '/**') let linenum = linenum + 1 let indent = indent . ' *' call append(linenum, indent) let linenum = linenum + 1 let authorstr = ' @author ' if exists("b:jcommenter_class_author") let authorstr = authorstr . b:jcommenter_class_author endif call append(linenum, indent . authorstr) let linenum = linenum + 1 let versionstring = ' @version ' if exists("b:jcommenter_class_def_version") let versionstring = versionstring . b:jcommenter_class_def_version endif call append(linenum, indent . versionstring ) let linenum = linenum + 1 call append(linenum, indent . '/' ) endfunction function! WriteMethodComments(argm) let str = a:argm " don't need anything aftr '[{;]' let endPat = '\s*[{;]' let endPos = match( str, endPat ) if endPos != -1 let str = strpart( str, 0, endPos ) endif " get indent-blanks from beginning: (so that the comments can be indented) let indentPat = '^\s*[a-zA-Z]' let indentEndPos = matchend( str, indentPat ) - 1 if indentEndPos > 0 let indentStr = strpart(str, 0, indentEndPos) else let indentStr = '' let indentEndPos = 0 endif " pattern for ' functionName(' let namePat = '\s\+[a-zA-Z][a-zA-Z0-9]*\s*(' let constructorPat = '\(\s\|^\)[A-Z][a-zA-Z0-9]*\s*(' " pattern for ' ReturnType functionName(' let retPat = '[a-zA-Z][a-zA-Z0-9]*\s*\(\[\s*\]\)\=' . namePat " index where the return type-str starts: let paramEndPat = retPat . '.*)' if str !~ constructorPat " get return-type: let preRetPos = match( str, retPat) let postRetPos = match(str, namePat) if preRetPos > 0 && postRetPos > 0 let returntype = strpart(str, preRetPos, postRetPos - preRetPos) if returntype == 'void' let returntype = '' endif else let returntype = '' endif else let returntype = '' " is constructor. endif " get parameters: let preParamPos = matchend(str, retPat) let postParamPos = matchend(str, paramEndPat) - 1 if preParamPos > 0 && postParamPos > preParamPos let parameterlist = strpart(str, preParamPos, postParamPos - preParamPos) else let parameterlist = '' endif let throwPat = paramEndPat . '\s*throws\s\+' " get exceptions that might be thrown let preThrowListPos = matchend(str, throwPat) if preThrowListPos > 0 let throwlist = strpart(str, preThrowListPos, strlen(str) - preThrowListPos) else let throwlist = '' endif " start the commenting let linenum = a:firstline - 1 call append(linenum, indentStr . '/**') let linenum = linenum + 1 let indentStr = indentStr . ' *' call append(linenum, indentStr) let linenum = linenum + 1 " write the parameters: let brackets = '\s*\(\[\s*\]\)' let paramStartPat = '^\s*[a-zA-Z][a-zA-Z0-9]*\(\s*\[\s*\]\)\=\s\+' " can end w/ ',' or '[] ,' or '[]' or paramEndPat might be -1 (this is handled later) let paramEndPat = brackets . '\=\s*,\|' . brackets .'\s*$' " parameterlist is now like this: 'type1 param1, type2 param2, ...' " the next loop will create ' * @param '-string for each parameter. while parameterlist !~ '^\s*$' let paramStartPos = matchend(parameterlist, paramStartPat) let paramEndPos = match(parameterlist, paramEndPat) if paramStartPos < 0 break endif if paramEndPos < 0 let paramEndPos = strlen(parameterlist) else let paramEndPos = paramEndPos endif let param = strpart(parameterlist, paramStartPos, paramEndPos - paramStartPos) call append(linenum, indentStr . ' @param ' . param) let linenum = linenum + 1 let parameterlist = strpart(parameterlist, paramEndPos + 1, strlen(parameterlist) - paramEndPos) endwhile " if has returntype (and it's not 'void'), append a ' * @return '-string. if returntype != '' call append(linenum, indentStr . ' @return ') let linenum = linenum + 1 endif " exceptions, handled much like the parameters. let exceptionStartPat = '[a-zA-Z][a-zA-Z0-9]*\s*' let exceptionEndPat = ',' while throwlist !~ '^\s*$' let exceptionStartPos = match(throwlist, exceptionStartPat) let exceptionEndPos = matchend(throwlist, exceptionEndPat) if exceptionStartPos < 0 break endif if exceptionEndPos < 0 let exceptionEndPos = strlen(throwlist) else let exceptionEndPos = exceptionEndPos - 1 endif let exception = strpart(throwlist, exceptionStartPos, exceptionEndPos - exceptionStartPos) call append(linenum, indentStr . ' @throws ' . exception) let linenum = linenum + 1 let throwlist = strpart(throwlist, exceptionEndPos + 1, strlen(throwlist) - exceptionEndPos) endwhile call append(linenum, indentStr . '/') endfunction