1. Lynn Rees
  2. wikdShell

Commits

Lynn Rees  committed 5a1d46c

- extend

  • Participants
  • Parent commits adf4b76
  • Branches default

Comments (0)

Files changed (8)

File README.rst

View file
-wikdShell
+org.hardknots.wikd.wikdshell
 =========
 
 Groovy console for interacting with a running Freeplane instance

File scripts/org/hardknots/wikd/wikdshell/WikdShell.groovy

View file
+/*
+ * Copyright 2003-2012 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hardknots.wikd.wikdshell
+
+import groovy.swing.SwingBuilder
+import groovy.transform.InheritConstructors
+import groovy.transform.ThreadInterrupt
+import groovy.ui.Console
+import groovy.ui.ConsoleActions
+import groovy.ui.ConsoleView
+
+import javax.swing.*
+
+import org.codehaus.groovy.control.CompilerConfiguration
+import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer
+import org.codehaus.groovy.tools.LoaderConfiguration
+import org.codehaus.groovy.tools.RootLoader
+import org.freeplane.core.resources.ResourceController
+import org.freeplane.plugin.script.ScriptingConfiguration
+
+/**
+ * Freeplane Groovy Swing console.
+ *
+ * Allows user to interactively enter and execute Groovy within Freeplane.
+ */
+@InheritConstructors
+class WikdShell extends Console {
+
+	static String MAP_NAME
+	final static String DEFAULT_WINDOW_TITLE = 'wikdShell'
+	File currentFileChooserDir = new File(ResourceController.getResourceController().getFreeplaneUserDirectory() + '/scripts')
+
+	static def frameWikdShellDelegates = [
+		rootContainerDelegate: {
+			frame(
+					title: "${MAP_NAME} - ${DEFAULT_WINDOW_TITLE}",
+					//location: [100,100], // in groovy 2.0 use platform default location
+					iconImage: imageIcon('/groovy/ui/ConsoleIcon.png').image,
+					defaultCloseOperation: JFrame.DO_NOTHING_ON_CLOSE,
+					) {
+						try {
+							current.locationByPlatform = true
+						} catch (Exception e) {
+							current.location = [
+								100,
+								100] // for 1.4 compatibility
+						}
+						containingWindows += current
+					}
+		},
+		menuBarDelegate: { arg ->
+			current.JMenuBar = build(arg) }
+	]
+
+	@Override
+	void run(String title) {
+		MAP_NAME = title
+		run(frameWikdShellDelegates)
+	}
+
+	// Start a new window with a copy of current variables
+	@Override
+	void fileNewWindow(EventObject evt = null) {
+		WikdShell consoleController = new WikdShell(
+			new Binding(new HashMap(shell.context.variables)))
+		consoleController.systemOutInterceptor = systemOutInterceptor
+		consoleController.systemErrorInterceptor = systemErrorInterceptor
+		SwingBuilder swing = new SwingBuilder()
+		consoleController.swing = swing
+		frameWikdShellDelegates.each {k, v -> swing[k] = v}
+		swing.controller = consoleController
+		swing.build(ConsoleActions)
+		swing.build(ConsoleView)
+		installInterceptor()
+		nativeFullScreenForMac(swing.consoleFrame)
+		swing.consoleFrame.pack()
+		swing.consoleFrame.show()
+		swing.doLater swing.inputArea.&requestFocus
+	}
+
+	@Override
+	void newScript(ClassLoader parent, Binding binding) {
+		config = new CompilerConfiguration()
+		if (threadInterrupt) config.addCompilationCustomizers(new ASTTransformationCustomizer(ThreadInterrupt))
+		def lc = new LoaderConfiguration()
+		new ScriptingConfiguration().getClasspath().each { lc.addFile(it) }
+		shell = new GroovyShell(new RootLoader(lc), binding, config)
+	}
+
+	// Return false if use elected to cancel
+	@Override
+	boolean askToSaveFile() {
+		if (scriptFile == null || !dirty)
+			return true
+		switch (JOptionPane.showConfirmDialog(
+		frame,
+		"Save changes to ${scriptFile.name}?",
+		DEFAULT_WINDOW_TITLE,
+		JOptionPane.YES_NO_CANCEL_OPTION)) {
+			case JOptionPane.YES_OPTION:
+				return fileSave()
+			case JOptionPane.NO_OPTION:
+				return true
+			default:
+				return false
+		}
+	}
+
+	// If at exit time, a script is running, the user is given an option to interrupt it first
+	@Override
+	def askToInterruptScript() {
+		if(!scriptRunning) return true
+		def rc = JOptionPane.showConfirmDialog(
+				frame,
+				"Script executing. Press 'OK' to attempt to interrupt it before exiting.",
+				DEFAULT_WINDOW_TITLE,
+				JOptionPane.OK_CANCEL_OPTION
+		)
+		if (rc == JOptionPane.OK_OPTION) {
+			doInterrupt()
+			return true
+		} else {
+			return false
+		}
+	}
+
+	@Override
+	void showAbout(EventObject evt = null) {
+		def version = GroovySystem.getVersion()
+		def pane = swing.optionPane()
+		// work around GROOVY-1048
+		pane.setMessage("Welcome to the ${DEFAULT_WINDOW_TITLE} for evaluating Groovy scripts\nVersion ${version}")
+		def dialog = pane.createDialog(frame, "About ${DEFAULT_WINDOW_TITLE}")
+		dialog.show()
+	}
+
+	@Override
+	void updateTitle() {
+		if (frame.properties.containsKey('title')) {
+			if (scriptFile != null)
+				frame.title = "${scriptFile.name} ${(dirty ? ' * ': '')} - ${DEFAULT_WINDOW_TITLE}"
+			else
+				frame.title = "${MAP_NAME} - ${DEFAULT_WINDOW_TITLE}"
+		}
+	}
+
+}

File scripts/wikdShell.groovy

View file
 // @CacheScriptContent(true)
 // @ExecutionModes({ON_SINGLE_NODE})
 
-import groovy.ui.Console
+import org.freeplane.plugin.script.FreeplaneScriptBaseClass
+import org.hardknots.wikd.wikdshell.WikdShell
 
-import org.codehaus.groovy.tools.LoaderConfiguration
-import org.codehaus.groovy.tools.RootLoader
-import org.freeplane.core.resources.ResourceController;
-import org.freeplane.plugin.script.FreeplaneScriptBaseClass
-import org.freeplane.plugin.script.ScriptingConfiguration
-
-def lc = new LoaderConfiguration()
-
-new ScriptingConfiguration().getClasspath().each { lc.addFile(it) }
-
-def console = new Console(new RootLoader(lc), getBinding())
-
+WikdShell console = new WikdShell(getBinding())
 console.setVariable('base', FreeplaneScriptBaseClass)
 console.setVariable('map', node.map)
 console.setVariable('root', node.map.root)
-console.currentFileChooserDir = new File(
-	ResourceController.getResourceController().getFreeplaneUserDirectory() + '/scripts'
-)
-
-console.run()
+console.run(node.map.name)

File scripts/wikdShell/JSConsole.java

-package wikdShell;
-

File scripts/wikdShell/WikdSearch.java

-package wikdShell;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.List;
-
-import org.apache.lucene.analysis.standard.StandardAnalyzer;
-import org.apache.lucene.document.Document;
-import org.apache.lucene.document.Field;
-import org.apache.lucene.document.TextField;
-import org.apache.lucene.index.DirectoryReader;
-import org.apache.lucene.index.IndexWriter;
-import org.apache.lucene.index.IndexWriterConfig;
-import org.apache.lucene.queryparser.classic.ParseException;
-import org.apache.lucene.queryparser.classic.QueryParser;
-import org.apache.lucene.search.IndexSearcher;
-import org.apache.lucene.search.Query;
-import org.apache.lucene.search.ScoreDoc;
-import org.apache.lucene.store.RAMDirectory;
-import org.apache.lucene.util.Version;
-import org.freeplane.features.filter.Filter;
-import org.freeplane.features.filter.FilterController;
-import org.freeplane.features.filter.condition.ICondition;
-import org.freeplane.features.map.NodeModel;
-import org.freeplane.features.mode.Controller;
-import org.freeplane.features.note.NoteModel;
-import org.freeplane.features.text.DetailTextModel;
-
-public class WikdSearch {
-
-	private static RAMDirectory ramdir = new RAMDirectory();
-	@SuppressWarnings("deprecation")
-	private static StandardAnalyzer analyzer = new StandardAnalyzer(Version.LUCENE_CURRENT);
-	@SuppressWarnings("deprecation")
-	private static IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_CURRENT, analyzer);
-
-	private static List<NodeModel> all(List<NodeModel> matches, NodeModel node) {
-		matches.add(node);
-		final Enumeration<NodeModel> children = node.children();
-		while (children.hasMoreElements()) {
-			final NodeModel child = children.nextElement();
-			matches.addAll(all(matches, child));
-		}
-		return matches;
-	}
-
-	public static void index() throws IOException {
-		List<NodeModel> matches = new ArrayList<NodeModel>();
-		IndexWriter iwriter = new IndexWriter(ramdir, config);
-		for (NodeModel node: all(matches, Controller.getCurrentController().getMap().getRootNode())) {
-			Document doc = new Document();
-			doc.add(new Field("id", node.getID(), TextField.TYPE_STORED));
-			doc.add(new Field("core", node.getText(), TextField.TYPE_STORED));
-			String details = DetailTextModel.getDetailTextText(node);
-			if (details != null)
-				doc.add(new Field("details", details, TextField.TYPE_STORED));
-			String note = NoteModel.getNoteText(node);
-			if (note != null)
-				doc.add(new Field("note", note, TextField.TYPE_STORED));
-			iwriter.addDocument(doc);
-		}
-		iwriter.close();
-	}
-
-	public static void search(String text) throws IOException, ParseException {
-		DirectoryReader ireader = DirectoryReader.open(ramdir);
-		IndexSearcher isearcher = new IndexSearcher(ireader);
-		@SuppressWarnings("deprecation")
-		QueryParser parser = new QueryParser(Version.LUCENE_CURRENT, "core", analyzer);
-		Query query = parser.parse(text);
-		ScoreDoc[] hits = isearcher.search(query, null, 1000).scoreDocs;
-		final List<String> ids = new ArrayList<String>();
-		for (ScoreDoc item : hits)
-			ids.add(isearcher.doc(item.doc).get("id"));
-		FilterController controller = FilterController.getCurrentFilterController();
-		ICondition condition = new ICondition() {
-			public boolean checkNode(NodeModel node) {
-				return ids.contains(node);
-			}
-		};
-		Filter filter = new Filter(condition, false, true, false);
-		controller.applyFilter(filter, Controller.getCurrentController().getMap(), true);
-		ireader.close();
-	}
-
-}

File wikdShell-screenshot-1.svg

View file
Old
Old image
New
New image

File wikdShell.mm

View file
 <map version="freeplane 1.2.0">
 <!--To view this file, download free mind mapping software Freeplane from http://freeplane.sourceforge.net -->
-<node TEXT="wikdShell" FOLDED="false" ID="ID_1723255651" CREATED="1283093380553" MODIFIED="1363705219123" BACKGROUND_COLOR="#97c7dc">
+<node TEXT="wikdShell" FOLDED="false" ID="ID_1723255651" CREATED="1283093380553" MODIFIED="1363824363680" BACKGROUND_COLOR="#97c7dc">
 <font SIZE="16" BOLD="true" ITALIC="true"/>
 <hook NAME="MapStyle">
     <properties show_icon_for_attributes="true" show_note_icons="true"/>
 </map_styles>
 </hook>
 <hook NAME="AutomaticEdgeColor" COUNTER="10"/>
-<attribute_layout NAME_WIDTH="103" VALUE_WIDTH="103"/>
+<attribute_layout NAME_WIDTH="103" VALUE_WIDTH="138"/>
 <attribute NAME="name" VALUE="wikdShell"/>
 <attribute NAME="version" VALUE="0.2.0"/>
 <attribute NAME="author" VALUE="L. C. Rees"/>
     </ul>
   </body>
 </html>
-
 </richcontent>
 <hook NAME="FlexibleLayout" VALUE="CHILDREN"/>
-<node TEXT="description" POSITION="left" ID="ID_1476543373" CREATED="1358397138392" MODIFIED="1363705219152">
+<node TEXT="description" POSITION="left" ID="ID_1476543373" CREATED="1358397138392" MODIFIED="1363824363694">
 <edge COLOR="#ff0000"/>
 <richcontent TYPE="NOTE">
 
     </p>
   </body>
 </html>
-
 </richcontent>
 <attribute_layout NAME_WIDTH="100" VALUE_WIDTH="100"/>
 <node TEXT="Groovy console for interacting with a running Freeplane instance" ID="ID_829083199" CREATED="1358480280068" MODIFIED="1358494181519">
 <attribute_layout NAME_WIDTH="100" VALUE_WIDTH="100"/>
 </node>
 </node>
-<node TEXT="changes" POSITION="left" ID="ID_26360570" CREATED="1358397138400" MODIFIED="1363705219155">
+<node TEXT="changes" POSITION="left" ID="ID_26360570" CREATED="1358397138400" MODIFIED="1363824363698">
 <edge COLOR="#0000ff"/>
 <richcontent TYPE="NOTE">
 
     </p>
   </body>
 </html>
-
 </richcontent>
 <attribute_layout NAME_WIDTH="100" VALUE_WIDTH="100"/>
 <node TEXT="0.1.0" ID="ID_1427326428" CREATED="1358480304748" MODIFIED="1363657342348">
 </node>
 </node>
 </node>
-<node TEXT="license" POSITION="left" ID="ID_584948500" CREATED="1358397138405" MODIFIED="1363705219160">
+<node TEXT="license" POSITION="left" ID="ID_584948500" CREATED="1358397138405" MODIFIED="1363824363703">
 <edge COLOR="#00ff00"/>
 <richcontent TYPE="NOTE">
 
     </p>
   </body>
 </html>
-
 </richcontent>
 <node TEXT="&#xa;This add-on is free software: you can redistribute it and/or modify&#xa;it under the terms of the GNU General Public License as published by&#xa;the Free Software Foundation, either version 2 of the License, or&#xa;(at your option) any later version.&#xa;&#xa;This program is distributed in the hope that it will be useful,&#xa;but WITHOUT ANY WARRANTY; without even the implied warranty of&#xa;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.&#xa0;&#xa0;See the&#xa;GNU General Public License for more details.&#xa;" ID="ID_1182518149" CREATED="1358397138412" MODIFIED="1358397138412">
 <attribute_layout NAME_WIDTH="100" VALUE_WIDTH="100"/>
 </node>
 </node>
-<node TEXT="preferences.xml" POSITION="left" ID="ID_892155711" CREATED="1358397138421" MODIFIED="1363705219166">
+<node TEXT="preferences.xml" POSITION="left" ID="ID_892155711" CREATED="1358397138421" MODIFIED="1363824363709">
 <edge COLOR="#ff00ff"/>
 <richcontent TYPE="NOTE">
 
     </p>
   </body>
 </html>
-
 </richcontent>
 <attribute_layout NAME_WIDTH="100" VALUE_WIDTH="100"/>
 </node>
-<node TEXT="default.properties" POSITION="left" ID="ID_762310990" CREATED="1358397138437" MODIFIED="1363705219170">
+<node TEXT="default.properties" POSITION="left" ID="ID_762310990" CREATED="1358397138437" MODIFIED="1363824363714">
 <edge COLOR="#00ffff"/>
 <richcontent TYPE="NOTE">
 
     </p>
   </body>
 </html>
-
 </richcontent>
 <attribute_layout NAME_WIDTH="100" VALUE_WIDTH="100"/>
 </node>
-<node TEXT="translations" POSITION="left" ID="ID_1542326927" CREATED="1358397138442" MODIFIED="1363705219174">
+<node TEXT="translations" POSITION="left" ID="ID_1542326927" CREATED="1358397138442" MODIFIED="1363824363719">
 <edge COLOR="#ffff00"/>
 <richcontent TYPE="NOTE">
 
     </p>
   </body>
 </html>
-
 </richcontent>
 <attribute_layout NAME_WIDTH="100" VALUE_WIDTH="100"/>
-<node TEXT="en" ID="ID_502342550" CREATED="1358397138447" MODIFIED="1358480613945">
+<node TEXT="en" ID="ID_502342550" CREATED="1358397138447" MODIFIED="1363837250303">
 <attribute_layout NAME_WIDTH="76" VALUE_WIDTH="76"/>
 <attribute NAME="addons.${name}" VALUE="wikdShell"/>
 <attribute NAME="shellName" VALUE="Groovy Console"/>
 </node>
-<node TEXT="de" ID="ID_1868805079" CREATED="1358480213382" MODIFIED="1358480634300">
+<node TEXT="de" ID="ID_1868805079" CREATED="1358480213382" MODIFIED="1363837252206">
 <attribute_layout NAME_WIDTH="76" VALUE_WIDTH="78"/>
 <attribute NAME="addons.${name}" VALUE="wikdShell"/>
 <attribute NAME="shellName" VALUE="Groovy-Konsole"/>
 </node>
 </node>
-<node TEXT="deinstall" POSITION="left" ID="ID_1716047542" CREATED="1358397138451" MODIFIED="1363705220226">
+<node TEXT="deinstall" POSITION="left" ID="ID_1716047542" CREATED="1358397138451" MODIFIED="1363824401029">
 <edge COLOR="#7c0000"/>
 <richcontent TYPE="NOTE">
 
     </p>
   </body>
 </html>
-
 </richcontent>
 <attribute_layout NAME_WIDTH="30" VALUE_WIDTH="309"/>
 <attribute NAME="delete" VALUE="${installationbase}/addons/${name}.script.xml"/>
 <attribute NAME="delete" VALUE="${installationbase}/resources/images/wikdShell.png"/>
 <attribute NAME="delete" VALUE="${installationbase}/resources/images/wikdShell-icon.png"/>
 <attribute NAME="delete" VALUE="${installationbase}/resources/images/wikdShell-screenshot-1.png"/>
-<attribute NAME="delete" VALUE="${installationbase}/resources/images/lucene-queryparser.jar"/>
-<attribute NAME="delete" VALUE="${installationbase}/resources/images/lucene-core.jar"/>
-<attribute NAME="delete" VALUE="${installationbase}/resources/images/lucene-analyzers-common.jar"/>
-<attribute NAME="delete" VALUE="${installationbase}/resources/images/lucene-codecs.jar"/>
-<attribute NAME="delete" VALUE="${installationbase}/scripts/wikdSearch.groovy"/>
+<attribute NAME="delete" VALUE="${installationbase}/resources/images/wikdshell.jar"/>
 </node>
-<node TEXT="scripts" POSITION="right" ID="ID_1656924893" CREATED="1358397138459" MODIFIED="1363705219197">
+<node TEXT="scripts" POSITION="right" ID="ID_1656924893" CREATED="1358397138459" MODIFIED="1363824363736">
 <edge COLOR="#00007c"/>
 <richcontent TYPE="NOTE">
 
     </p>
   </body>
 </html>
-
 </richcontent>
 <attribute_layout NAME_WIDTH="100" VALUE_WIDTH="100"/>
-<node TEXT="wikdShell.groovy" ID="ID_705079003" CREATED="1358480127293" MODIFIED="1358490064035">
+<node TEXT="wikdShell.groovy" ID="ID_705079003" CREATED="1358480127293" MODIFIED="1363824267737">
 <attribute_layout NAME_WIDTH="206" VALUE_WIDTH="206"/>
 <attribute NAME="menuTitleKey" VALUE="shellName"/>
 <attribute NAME="menuLocation" VALUE="main_menu_scripting"/>
 <attribute NAME="execute_scripts_without_exec_restriction" VALUE="false"/>
 <attribute NAME="execute_scripts_without_network_restriction" VALUE="false"/>
 </node>
-<node TEXT="wikdSearch.groovy" ID="ID_184469178" CREATED="1363705207598" MODIFIED="1363705243865">
-<attribute_layout NAME_WIDTH="206" VALUE_WIDTH="206"/>
-<attribute NAME="menuTitleKey" VALUE="Search"/>
-<attribute NAME="menuLocation" VALUE="main_menu_scripting"/>
-<attribute NAME="executionMode" VALUE="on_single_node"/>
-<attribute NAME="keyboardShortcut" VALUE=""/>
-<attribute NAME="execute_scripts_without_asking" VALUE="true"/>
-<attribute NAME="execute_scripts_without_file_restriction" VALUE="true"/>
-<attribute NAME="execute_scripts_without_write_restriction" VALUE="false"/>
-<attribute NAME="execute_scripts_without_exec_restriction" VALUE="false"/>
-<attribute NAME="execute_scripts_without_network_restriction" VALUE="false"/>
 </node>
-</node>
-<node TEXT="zips" POSITION="right" ID="ID_686396268" CREATED="1358397138476" MODIFIED="1363705219371">
+<node TEXT="zips" POSITION="right" ID="ID_686396268" CREATED="1358397138476" MODIFIED="1363824363745">
 <edge COLOR="#007c00"/>
 <richcontent TYPE="NOTE">
 
     </p>
   </body>
 </html>
-
 </richcontent>
+<attribute_layout NAME_WIDTH="100" VALUE_WIDTH="100"/>
 </node>
-<node TEXT="images" POSITION="right" ID="ID_1421584650" CREATED="1358397138484" MODIFIED="1363705219379">
+<node TEXT="images" POSITION="right" ID="ID_1421584650" CREATED="1358397138484" MODIFIED="1363824363752">
 <edge COLOR="#7c007c"/>
 <richcontent TYPE="NOTE">
 
     </p>
   </body>
 </html>
-
 </richcontent>
 <attribute_layout NAME_WIDTH="100" VALUE_WIDTH="100"/>
 <node TEXT="${name}.png" ID="ID_473909841" CREATED="1357854883609" MODIFIED="1357866785018">
 <node TEXT="${name}-screenshot-1.png" ID="ID_1706510600" CREATED="1357855573438" MODIFIED="1357866791195">
 <attribute_layout NAME_WIDTH="100" VALUE_WIDTH="100"/>
 </node>
-<node TEXT="lucene-queryparser.jar" ID="ID_377333485" CREATED="1363594268255" MODIFIED="1363669539248">
+<node TEXT="wikdshell.jar" ID="ID_1221660213" CREATED="1363824242643" MODIFIED="1363824245560">
 <attribute_layout NAME_WIDTH="100" VALUE_WIDTH="100"/>
 </node>
-<node TEXT="lucene-core.jar" ID="ID_1537490320" CREATED="1363594268257" MODIFIED="1363669543181">
-<attribute_layout NAME_WIDTH="100" VALUE_WIDTH="100"/>
-</node>
-<node TEXT="lucene-analyzers-common.jar" ID="ID_83662927" CREATED="1363594268258" MODIFIED="1363669546933">
-<attribute_layout NAME_WIDTH="100" VALUE_WIDTH="100"/>
-</node>
-<node TEXT="lucene-codecs.jar" ID="ID_790266965" CREATED="1363594268258" MODIFIED="1363669550072">
-<attribute_layout NAME_WIDTH="100" VALUE_WIDTH="100"/>
-</node>
 </node>
 </node>
 </map>

File wikdshell.jardesc

View file
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<jardesc>
+    <jar path="wikdShell/images/wikdshell.jar"/>
+    <options buildIfNeeded="true" compress="true" descriptionLocation="/wikdShell/wikdshell.jardesc" exportErrors="true" exportWarnings="true" includeDirectoryEntries="false" overwrite="true" saveDescription="true" storeRefactorings="false" useSourceFolders="false"/>
+    <storedRefactorings deprecationInfo="true" structuralOnly="false"/>
+    <selectedProjects/>
+    <manifest generateManifest="true" manifestLocation="" manifestVersion="1.0" reuseManifest="false" saveManifest="false" usesManifest="true">
+        <sealing sealJar="false">
+            <packagesToSeal/>
+            <packagesToUnSeal/>
+        </sealing>
+    </manifest>
+    <selectedElements exportClassFiles="true" exportJavaFiles="false" exportOutputFolder="false">
+        <javaElement handleIdentifier="=wikdShell/scripts&lt;org.hardknots.wikd.wikdshell{WikdShell.groovy"/>
+    </selectedElements>
+</jardesc>