windows sucks because it does.
so, clji.bat:
@echo off
setlocal
set CLOJURE_HOME=%~dp0\clojure
set CLASS_PATH=%CLOJURE_HOME%\jline-0.9.94.jar;%CLOJURE_HOME%\clojure.jar;%CLOJURE_HOME%\clojure-contrib.jar
java -Djline.words="%CLOJURE_HOME%\all_names.txt" -cp "%CLASS_PATH%" jline.ConsoleRunner clojure.main %*
endlocal
clj.bat:
@echo off
setlocal
set CLOJURE_HOME=%~dp0\clojure
set CLASS_PATH=%CLOJURE_HOME%\jline-0.9.94.jar;%CLOJURE_HOME%\clojure.jar;%CLOJURE_HOME%\clojure-contrib.jar
IF (%1)==() (
java -Djline.words="%CLOJURE_HOME%\all_names.txt" -cp "%CLASS_PATH%" jline.ConsoleRunner clojure.main
) ELSE (
java -Djline.words="%CLOJURE_HOME%\all_names.txt" -cp "%CLASS_PATH%" clojure.main %1 -- %*
)
endlocal
clji.bat always starts repl. clj.bat starts repl when no argument is passed. otherwise, it runs the first argument (should be .clj script).
it expects there's clojure/
directory at the same level of the batch files.
the directory should have some jar files (clojure.jar, clojure-contrib.jar, jline..)
and also clojure/
contains allnames.txt that is generated by allnames.clj:
(def all-names (concat (map (fn [p] (keys (ns-publics (find-ns p))))
'(clojure.core clojure.set clojure.xml clojure.zip))))
(println (apply str
(interleave (reduce concat all-names)
(repeat "\n"))))
to run it:
$ clj all_names.clj > all_names.txt
now, modified ConsoleRunner.java (from http://jline.sf.net) that'll actually use all_names.txt:
/*
* Copyright (c) 2002-2007, Marc Prud'hommeaux. All rights reserved.
*
* This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software.
*/
package jline;
import java.io.*;
import java.util.*;
/**
* <p>
* A pass-through application that sets the system input stream to a
* {@link ConsoleReader} and invokes the specified main method.
* </p>
* @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
*/
public class ConsoleRunner {
public static final String HISTORY = "jline.history";
public static final String WORDS = "jline.words";
public static String[] getWords(String wordsFile) {
List result = new ArrayList();
try {
BufferedReader input = new BufferedReader(
new FileReader(wordsFile)
);
try {
String line = null;
while (null != (line = input.readLine())) {
result.add(line);
}
} finally {
input.close();
}
} catch (FileNotFoundException err) {
err.printStackTrace();
} catch (IOException err) {
err.printStackTrace();
}
String[] array = new String[result.size()];
result.toArray(array);
return array;
}
public static void main(final String[] args) throws Exception {
String historyFileName = null;
List argList = new ArrayList(Arrays.asList(args));
if (argList.size() == 0) {
usage();
return;
}
historyFileName = System.getProperty(ConsoleRunner.HISTORY, null);
// invoke the main() method
String mainClass = (String) argList.remove(0);
// setup the inpout stream
ConsoleReader reader = new ConsoleReader();
if (historyFileName != null) {
reader.setHistory(new History (new File
(System.getProperty("user.home"),
".jline-" + mainClass
+ "." + historyFileName + ".history")));
} else {
reader.setHistory(new History(new File
(System.getProperty("user.home"),
".jline-" + mainClass + ".history")));
}
String wordsFileName = System.getProperty(WORDS, null);
if (null != wordsFileName) {
//List list = new ArrayList();
//list.add(new SimpleCompletor(getWords(wordsFileName)));
//list.add(new FileNameCompletor());
//list.add(new NullCompletor());
Completor completor =
new MultiCompletor(new Completor[] {
new SimpleCompletor(getWords(wordsFileName))
, new FileNameCompletor()
});
reader.addCompletor(
new ArgumentCompletor(new Completor[] {
completor
, completor
}, new SExpr())
);
} else {
}
String completors = System.getProperty
(ConsoleRunner.class.getName() + ".completors", "");
List completorList = new ArrayList();
for (StringTokenizer tok = new StringTokenizer(completors, ",");
tok.hasMoreTokens();) {
completorList.add
((Completor) Class.forName(tok.nextToken()).newInstance());
}
if (completorList.size() > 0) {
reader.addCompletor(new ArgumentCompletor(completorList));
}
//reader.setCompletionHandler(new CandidateListCompletionHandler());
ConsoleReaderInputStream.setIn(reader);
try {
Class.forName(mainClass).
getMethod("main", new Class[] { String[].class }).
invoke(null, new Object[] { argList.toArray(new String[0]) });
} finally {
// just in case this main method is called from another program
ConsoleReaderInputStream.restoreIn();
}
}
private static void usage() {
System.out.println("Usage: \n java " + "[-Djline.history='name'] "
+ "[-Djline.words=<path to words file for autocompletion>] "
+ ConsoleRunner.class.getName()
+ " <target class name> [args]"
+ "\n\nThe -Djline.history option will avoid history"
+ "\nmangling when running ConsoleRunner on the same application."
+ "\n\nargs will be passed directly to the target class name.");
}
}
class SExpr
extends ArgumentCompletor.AbstractArgumentDelimiter {
public boolean isDelimiterChar(String buffer, int pos) {
String c = buffer.substring(pos, pos+1);
return c.matches("[^\\w-*<>=?]");
}
}
if -Djline.words=path/to/file/that/has/word/list
is passed, it'll use that
file to do tab completion.
it's quick and dirty. i don't get how jline works.
somehow, i had to pass completor (new MultiCompletor(...)) twice to ArgumentCompletor so that
tab completion works into middle of line.
Also, SExpr is argument delimiter that considers things other than [\w-*<>=?]
a delimiter.
so, run mvn package to build jline jar. then put jline jar file under clojure/
.
then clj.bat and clji.bat would work.
i always spend time to set up development environment then lose interest :P