Index: trunk/utils/org/openstreetmap/josm/HelpTopicExtractor.groovy
===================================================================
--- trunk/utils/org/openstreetmap/josm/HelpTopicExtractor.groovy	(revision 2324)
+++ trunk/utils/org/openstreetmap/josm/HelpTopicExtractor.groovy	(revision 2324)
@@ -0,0 +1,122 @@
+
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm;
+
+import java.io.File;
+import java.io.OutputStreamWriter;
+import java.io.FileWriter;
+import java.io.PrintWriter;
+
+/**
+ * Script to extract declared help topics from JOSM source files.
+ * 
+ * Help topics are declared with the method ht(...). Example: ht("/Action/New")
+ * 
+ * Run with 
+ *   groovy org.openstreetmap.josm.HelpTopicExtractor [options] fileOrDirs
+ * 
+ */
+public class HelpTopicExtractor {
+	
+	private boolean recursive = false
+	private List<String> files = []
+	private String outputFile = null
+	private PrintWriter outputWriter = null
+
+	/**
+	 * extracts declared help topics from file and writes them to the output stream
+	 * 
+	 * @param file the file
+	 */
+	def extractHelpTopics(File file) {
+		def packageName;
+		def linenr = 0
+		file.eachLine {line ->
+			linenr++
+			def m = line =~ /^\s*package\s+(\S+)/
+			if (m.matches()) {
+				packageName = m[0][1].replace(";", "")
+			}
+			
+			m = line =~ /.*[^a-zA-Z]ht\s*\(\s*"([^"]+)"\s*\).*/
+			if (m.matches()) {
+				def topic = m[0][1]
+				outputWriter.println "${file.getPath()}\t${file.getName()}\t${linenr}\t${packageName}\t${topic}"
+			}
+		}
+	}
+
+	/**
+	 * display help information 
+	 */
+	def showHelp() {
+		println "groovy org.openstreetmap.josm.HelpTopicExtractor [options] fileOrDirs"
+		println "Options:"
+		println "  --help|-h        show help information"
+		println "  --recurive|-r    recursively extracts help topics from java files in the specified directories"
+		println "  -output-file|-o file  write to output file"
+	}
+
+	/**
+	 * processes a file or directory. If recursive processing is enabled and file is a directory, 
+	 * recursively processes child directories.
+	 * 
+	 * @param file the file 
+	 */
+	def process(File file) {
+		if (file.isFile()) {
+			extractHelpTopics(file)
+		} else if (file.isDirectory()) {
+			file.listFiles().grep(~/.*\.java$/).each { 
+			    File child ->
+				extractHelpTopics(child)
+			}
+			if (recursive) {
+				file.listFiles().grep { File child ->
+					child.isDirectory() && child.getName() != "." && child.getName() != ".."
+				}.each { File child ->
+					process(child)
+				}
+			}
+		}
+	}
+	
+	def run(String[] args) {
+		def i = 0
+		while(i<args.length) {
+			def arg = args[i]
+			if (arg == "-h" || arg == "--help") {
+				showHelp()
+				System.exit(0)
+			} else if (arg == "-r" || arg == "--recursive") {
+				recursive = true
+				i++;
+			} else if (arg == "-o" || arg == "--output-file") {
+				i++
+				if (i >= args.length) {
+					System.err.println "Missing argument for option '${args[i-1]}'"
+					System.exit(1)
+				}
+				outputFile = args[i]
+				outputWriter = new PrintWriter(new FileWriter(outputFile))
+				i++
+			} else {
+				files.add(arg)
+				i++
+			}
+			
+		}
+		if (outputFile == null) {
+			outputWriter = new PrintWriter(new OutputStreamWriter(System.out))
+		}
+		files.each {file -> process(new File(file)) }
+		outputWriter.flush()
+		if (outputFile != null) {
+		    outputWriter.close()
+		}
+	}
+	
+	public static void main(String[] args) {
+		new HelpTopicExtractor().run(args)
+	}
+}
Index: trunk/utils/org/openstreetmap/josm/HelpTopicReporter.groovy
===================================================================
--- trunk/utils/org/openstreetmap/josm/HelpTopicReporter.groovy	(revision 2324)
+++ trunk/utils/org/openstreetmap/josm/HelpTopicReporter.groovy	(revision 2324)
@@ -0,0 +1,80 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm;
+
+import java.io.BufferedReader;
+
+/**
+ * Creates a help topics report for the JOSM trac wiki.
+ * 
+ */
+public class HelpTopicReporter {
+
+    private PrintWriter  writer
+    private List<String> files = []
+    private String outputFile = null
+    private PrintWriter outputWriter = null
+
+    def String formatLine(String line) {
+        def fields = line.split("\t")
+        def repositoryPath = fields[3].replace(".", "/") + "/" + fields[1]
+        // each line is a table row according to the simple trac table syntax
+        // 
+        return "||[wiki:/Help${fields[4]} ${fields[4]}]||${fields[3]}||[source:/trunk/src/${repositoryPath}#L${fields[2]} ${fields[1]}]||"
+    }
+    
+    def process(BufferedReader reader) {
+        reader.eachLine { 
+            String line ->
+            writer.println formatLine(line)
+        }
+    }
+
+    def showHelp() {
+        println "groovy org.openstreetmap.josm.HelpTopicReporter [options] file*"
+        println "Options:"
+        println "  --help|-h        show help information"
+        println "  -output-file|-o file  write to output file"
+        println "Reads from stdin if no input file(s) in the argument list"
+    }
+
+    def run(String[] args) {
+        def i = 0
+        while(i<args.length) {
+            def arg = args[i]
+            if (arg == "-h" || arg == "--help") {
+                showHelp()
+                System.exit(0)
+            } else if (arg == "-o" || arg == "--output-file") {
+                i++
+                if (i >= args.length) {
+                    System.err.println "Missing argument for option '${args[i-1]}'"
+                    System.exit(1)
+                }
+                outputFile = args[i]
+                outputWriter = new PrintWriter(new FileWriter(outputFile))
+                i++
+            } else {
+                files.add(arg)
+                i++
+            }
+            
+        }
+        if (outputFile == null) {
+            outputWriter = new PrintWriter(new OutputStreamWriter(System.out))
+        }
+
+        if (! files.isEmpty()) {
+            files.each { process(new BufferedReader(new FileReader(new File(it)))) }
+        } else {
+            process(new BufferedReader(new InputStreamReader(System.in)))
+        }
+        outputWriter.flush()
+        if (outputFile != null) {
+            outputWriter.close()
+        }
+    }
+    
+    static public void main(String[] args) {
+        new HelpTopicReporter().run(args)
+    }
+}
