summaryrefslogtreecommitdiff
path: root/src/jline
diff options
context:
space:
mode:
Diffstat (limited to 'src/jline')
-rw-r--r--src/jline/README.md27
-rw-r--r--src/jline/pom.xml495
-rw-r--r--src/jline/src/assembly/assembly.xml55
-rw-r--r--src/jline/src/main/java/jline/ANSIBuffer.java405
-rw-r--r--src/jline/src/main/java/jline/AnsiWindowsTerminal.java90
-rw-r--r--src/jline/src/main/java/jline/ArgumentCompletor.java439
-rw-r--r--src/jline/src/main/java/jline/CandidateCycleCompletionHandler.java28
-rw-r--r--src/jline/src/main/java/jline/CandidateListCompletionHandler.java189
-rw-r--r--src/jline/src/main/java/jline/ClassNameCompletor.java146
-rw-r--r--src/jline/src/main/java/jline/CompletionHandler.java20
-rw-r--r--src/jline/src/main/java/jline/Completor.java32
-rw-r--r--src/jline/src/main/java/jline/ConsoleOperations.java276
-rw-r--r--src/jline/src/main/java/jline/ConsoleReader.java1625
-rw-r--r--src/jline/src/main/java/jline/ConsoleReaderInputStream.java108
-rw-r--r--src/jline/src/main/java/jline/ConsoleRunner.java86
-rw-r--r--src/jline/src/main/java/jline/FileNameCompletor.java133
-rw-r--r--src/jline/src/main/java/jline/History.java255
-rw-r--r--src/jline/src/main/java/jline/MultiCompletor.java83
-rw-r--r--src/jline/src/main/java/jline/NoInterruptUnixTerminal.java44
-rw-r--r--src/jline/src/main/java/jline/NullCompletor.java27
-rw-r--r--src/jline/src/main/java/jline/SimpleCompletor.java194
-rw-r--r--src/jline/src/main/java/jline/Terminal.java176
-rw-r--r--src/jline/src/main/java/jline/TerminalFactory.java173
-rw-r--r--src/jline/src/main/java/jline/TerminalSupport.java163
-rw-r--r--src/jline/src/main/java/jline/UnixTerminal.java507
-rw-r--r--src/jline/src/main/java/jline/UnsupportedTerminal.java97
-rw-r--r--src/jline/src/main/java/jline/WindowsTerminal.java719
-rw-r--r--src/jline/src/main/java/jline/console/ConsoleReader.java2103
-rw-r--r--src/jline/src/main/java/jline/console/CursorBuffer.java (renamed from src/jline/src/main/java/jline/CursorBuffer.java)85
-rw-r--r--src/jline/src/main/java/jline/console/Key.java74
-rw-r--r--src/jline/src/main/java/jline/console/Operation.java285
-rw-r--r--src/jline/src/main/java/jline/console/completer/AggregateCompleter.java108
-rw-r--r--src/jline/src/main/java/jline/console/completer/ArgumentCompleter.java398
-rw-r--r--src/jline/src/main/java/jline/console/completer/CandidateListCompletionHandler.java192
-rw-r--r--src/jline/src/main/java/jline/console/completer/Completer.java37
-rw-r--r--src/jline/src/main/java/jline/console/completer/CompletionHandler.java25
-rw-r--r--src/jline/src/main/java/jline/console/completer/EnumCompleter.java35
-rw-r--r--src/jline/src/main/java/jline/console/completer/FileNameCompleter.java133
-rw-r--r--src/jline/src/main/java/jline/console/completer/NullCompleter.java39
-rw-r--r--src/jline/src/main/java/jline/console/completer/StringsCompleter.java79
-rw-r--r--src/jline/src/main/java/jline/console/completer/package-info.java22
-rw-r--r--src/jline/src/main/java/jline/console/history/FileHistory.java106
-rw-r--r--src/jline/src/main/java/jline/console/history/History.java71
-rw-r--r--src/jline/src/main/java/jline/console/history/MemoryHistory.java318
-rw-r--r--src/jline/src/main/java/jline/console/history/PersistentHistory.java34
-rw-r--r--src/jline/src/main/java/jline/console/history/package-info.java22
-rw-r--r--src/jline/src/main/java/jline/console/package-info.java22
-rw-r--r--src/jline/src/main/java/jline/internal/Configuration.java127
-rw-r--r--src/jline/src/main/java/jline/internal/Log.java112
-rw-r--r--src/jline/src/main/java/jline/internal/ReplayPrefixOneCharInputStream.java95
-rw-r--r--src/jline/src/main/java/jline/internal/TerminalLineSettings.java217
-rw-r--r--src/jline/src/main/java/jline/internal/package-info.java22
-rw-r--r--src/jline/src/main/java/jline/package-info.java22
-rw-r--r--src/jline/src/main/java/jline/package.html9
-rw-r--r--src/jline/src/main/native/Makefile8
-rw-r--r--src/jline/src/main/native/jline_WindowsTerminal.c57
-rw-r--r--src/jline/src/main/native/jline_WindowsTerminal.h68
-rw-r--r--src/jline/src/main/resources/jline/CandidateListCompletionHandler.properties5
-rw-r--r--src/jline/src/main/resources/jline/console/completer/CandidateListCompletionHandler.properties4
-rw-r--r--src/jline/src/main/resources/jline/jline32.dllbin16069 -> 0 bytes
-rw-r--r--src/jline/src/main/resources/jline/jline64.dllbin48128 -> 0 bytes
-rw-r--r--src/jline/src/main/resources/jline/keybindings.properties61
-rw-r--r--src/jline/src/main/resources/jline/windowsbindings.properties70
-rw-r--r--src/jline/src/site/apt/building.apt39
-rw-r--r--src/jline/src/site/apt/downloads.apt39
-rw-r--r--src/jline/src/site/docbook/index.xml492
-rw-r--r--src/jline/src/site/fml/faq.fml26
-rwxr-xr-xsrc/jline/src/site/resources/css/site.css311
-rwxr-xr-xsrc/jline/src/site/resources/images/collapsed.pngbin222 -> 0 bytes
-rwxr-xr-xsrc/jline/src/site/resources/images/dotted.pngbin190 -> 0 bytes
-rwxr-xr-xsrc/jline/src/site/resources/images/expanded.pngbin198 -> 0 bytes
-rwxr-xr-xsrc/jline/src/site/resources/images/external.pngbin223 -> 0 bytes
-rw-r--r--src/jline/src/site/resources/images/ico_file_pdf.pngbin280 -> 0 bytes
-rw-r--r--src/jline/src/site/resources/images/logo.jpgbin4121 -> 0 bytes
-rwxr-xr-xsrc/jline/src/site/resources/images/newwindow.pngbin224 -> 0 bytes
-rw-r--r--src/jline/src/site/site.xml40
-rw-r--r--src/jline/src/test/java/jline/ConsoleReaderTest.java162
-rw-r--r--src/jline/src/test/java/jline/JLineTestCase.java140
-rw-r--r--src/jline/src/test/java/jline/TerminalFactoryTest.java34
-rw-r--r--src/jline/src/test/java/jline/TestCompletion.java71
-rw-r--r--src/jline/src/test/java/jline/TestEditLine.java160
-rw-r--r--src/jline/src/test/java/jline/TestHistory.java76
-rw-r--r--src/jline/src/test/java/jline/console/ConsoleReaderTest.java261
-rw-r--r--src/jline/src/test/java/jline/console/ConsoleReaderTestSupport.java142
-rw-r--r--src/jline/src/test/java/jline/console/EditLineTest.java172
-rw-r--r--src/jline/src/test/java/jline/console/completer/ArgumentCompleterTest.java46
-rw-r--r--src/jline/src/test/java/jline/console/completer/NullCompleterTest.java39
-rw-r--r--src/jline/src/test/java/jline/console/completer/StringsCompleterTest.java40
-rw-r--r--src/jline/src/test/java/jline/console/history/HistoryTest.java79
-rw-r--r--src/jline/src/test/java/jline/console/history/MemoryHistoryTest.java99
-rw-r--r--src/jline/src/test/java/jline/example/Example.java56
-rw-r--r--src/jline/src/test/java/jline/example/PasswordReader.java32
-rw-r--r--src/jline/src/test/java/jline/internal/TerminalLineSettingsTest.java146
-rw-r--r--src/jline/src/test/resources/jline/example/english.gzbin130975 -> 0 bytes
94 files changed, 7192 insertions, 7167 deletions
diff --git a/src/jline/README.md b/src/jline/README.md
new file mode 100644
index 0000000000..6d129e721d
--- /dev/null
+++ b/src/jline/README.md
@@ -0,0 +1,27 @@
+Description
+-----------
+
+JLine 2.x
+
+License
+-------
+
+BSD
+
+Building
+--------
+
+### Requirements
+
+* Maven 2+
+* Java 5+
+
+Check out and build:
+
+ git clone git://github.com/jdillon/jline2.git
+ cd jline2
+ mvn install
+
+To build the jdk14 jar:
+
+ mvn install -Dretro
diff --git a/src/jline/pom.xml b/src/jline/pom.xml
index ac0e188585..71043e32c2 100644
--- a/src/jline/pom.xml
+++ b/src/jline/pom.xml
@@ -1,224 +1,273 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!--
-To build, you need to have Maven 2 installed.
-
-To compile, run:
-
- mvn compile
-
-To run tests, run:
-
- mvn test
-
-To run one particular test, e.g. TestSomeTest, run:
-
- mvn test -Dtest=TestSomeTest
-
-To build the jars, run:
-
- mvn package
-
-To create and upload a release, run:
-
- mvn deploy
-
-To build the site and upload it, run:
-
- mvn site:deploy
-
-To perform a complete release, run:
-
- mvn clean compile package site assembly:assembly deploy site:deploy
-
-To actually upload the artifact to sourceforge, it must be manually ftp'd:
-
- lftp ftp://upload.sourceforge.net/incoming/ -e "put `ls target/jline-*.zip`"
-
-To make a bundle and request that ibilio upload it, do:
-
- mvn source:jar javadoc:jar repository:bundle-create
-
- scp target/jline-*-bundle.jar shell.sourceforge.net:/home/groups/j/jl/jline/htdocs
-
- Make a request like at http://jira.codehaus.org/browse/MAVENUPLOAD-1003
-
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
- http://maven.apache.org/maven-v4_0_0.xsd">
-
-<properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-</properties>
- <modelVersion>4.0.0</modelVersion>
- <groupId>jline</groupId>
- <artifactId>jline</artifactId>
- <packaging>jar</packaging>
- <name>JLine</name>
- <version>0.9.95-SNAPSHOT</version>
- <description>JLine is a java library for reading and editing user input in console applications. It features tab-completion, command history, password masking, customizable keybindings, and pass-through handlers to use to chain to other console applications.</description>
- <url>http://jline.sourceforge.net</url>
- <issueManagement>
- <system>sourceforge</system>
- <url>http://sourceforge.net/tracker/?group_id=64033&amp;atid=506056</url>
- </issueManagement>
- <inceptionYear>2002</inceptionYear>
- <mailingLists>
- <mailingList>
- <name>JLine users</name>
- <subscribe>https://lists.sourceforge.net/lists/listinfo/jline-users</subscribe>
- <post>jline-users@lists.sourceforge.net</post>
- <archive>http://sourceforge.net/mailarchive/forum.php?forum=jline-users</archive>
- </mailingList>
- </mailingLists>
-
- <developers>
- <developer>
- <id>mprudhom</id>
- <name>Marc Prud'hommeaux</name>
- <email>mwp1@cornell.edu</email>
- </developer>
- </developers>
- <licenses>
- <license>
- <name>BSD</name>
- <url>LICENSE.txt</url>
- </license>
- </licenses>
- <scm>
- <connection>scm:cvs:pserver:anonymous@jline.cvs.sourceforge.net:/cvsroot/jline:jline</connection>
- <developerConnection>scm:cvs:ext:${maven.username}@jline.cvs.sourceforge.net:/cvsroot/jline:jline</developerConnection>
- <url>http://jline.cvs.sourceforge.net/jline</url>
- </scm>
- <dependencies>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>3.8.1</version>
- <scope>test</scope>
- </dependency>
- </dependencies>
-
- <build>
- <plugins>
- <!--
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>jalopy-maven-plugin</artifactId>
- <version>1.0-SNAPSHOT</version>
- <configuration>
- <fileFormat>UNIX</fileFormat>
- <convention>codestyle.xml</convention>
- </configuration>
- <executions>
- <execution>
- <goals>
- <goal>format</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
- -->
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <!-- <testFailureIgnore>true</testFailureIgnore> -->
- <useFile>false</useFile>
- <trimStackTrace>false</trimStackTrace>
- </configuration>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <configuration>
- <source>1.5</source>
- <target>1.5</target>
- <showWarnings>true</showWarnings>
- <compilerArgument>-Xlint:unchecked</compilerArgument>
- </configuration>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-site-plugin</artifactId>
- <configuration>
- <stagingDirectory>../site-staging</stagingDirectory>
- </configuration>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-assembly-plugin</artifactId>
- <configuration>
- <descriptors>
- <descriptor>src/assembly/assembly.xml</descriptor>
- </descriptors>
- </configuration>
- </plugin>
- </plugins>
- </build>
-
- <reporting>
- <plugins>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>jxr-maven-plugin</artifactId>
- <configuration>
- <aggregate>true</aggregate>
- </configuration>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-javadoc-plugin</artifactId>
- <configuration>
- <aggregate>true</aggregate>
- <linksource>true</linksource>
- <links>
- <link>http://java.sun.com/j2se/1.5.0/docs/api</link>
- </links>
- </configuration>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-pmd-plugin</artifactId>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-project-info-reports-plugin</artifactId>
- <reportSets>
- <reportSet>
- <reports>
- <!-- <report>dependencies</report> -->
- <!-- <report>cim</report> -->
- <!-- <report>cobertura</report> -->
- <report>project-team</report>
- <report>mailing-list</report>
- <report>issue-tracking</report>
- <report>license</report>
- <report>scm</report>
- </reports>
- </reportSet>
- </reportSets>
- </plugin>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>surefire-report-maven-plugin</artifactId>
- </plugin>
- </plugins>
- </reporting>
- <distributionManagement>
- <repository>
- <id>jline</id>
- <url>scp://shell.sourceforge.net/home/groups/j/jl/jline/htdocs/m2repo</url>
- </repository>
- <snapshotRepository>
- <id>jline</id>
- <url>scp://shell.sourceforge.net/home/groups/j/jl/jline/htdocs/m2snapshot</url>
- </snapshotRepository>
- <site>
- <id>jline</id>
- <name>jline</name>
- <url>scpexe://shell.sourceforge.net/home/groups/j/jl/jline/htdocs/</url>
- </site>
- </distributionManagement>
-</project>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.sonatype.forge</groupId>
+ <artifactId>forge-parent</artifactId>
+ <version>6</version>
+ </parent>
+
+ <groupId>org.sonatype.jline</groupId>
+ <artifactId>jline</artifactId>
+ <name>JLine</name>
+ <version>2.6-SNAPSHOT</version>
+
+ <organization>
+ <name>Sonatype</name>
+ <url>http://sonatype.org</url>
+ </organization>
+
+ <licenses>
+ <license>
+ <name>The BSD License</name>
+ <url>http://www.opensource.org/licenses/bsd-license.php</url>
+ <distribution>repo</distribution>
+ </license>
+ </licenses>
+
+ <scm>
+ <connection>scm:git:git://github.com/jdillon/jline2.git</connection>
+ <developerConnection>scm:git:ssh://git@github.com/jdillon/jline2.git</developerConnection>
+ <url>http://github.com/jdillon/jline2</url>
+ </scm>
+
+ <ciManagement>
+ <system>Hudson</system>
+ <url>https://grid.sonatype.org/ci/job/JLine2</url>
+ </ciManagement>
+
+ <developers>
+ <developer>
+ <id>jdillon</id>
+ <name>Jason Dillon</name>
+ <email>jason@planet57.com</email>
+ <roles>
+ <role>Build Master</role>
+ <role>Developer</role>
+ </roles>
+ </developer>
+ </developers>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <!--
+ <repositories>
+ <repository>
+ <id>jansi</id>
+ <url>http://jansi.fusesource.org/repo/snapshot</url>
+ <releases>
+ <enabled>false</enabled>
+ </releases>
+ <snapshots>
+ <enabled>true</enabled>
+ </snapshots>
+ </repository>
+ </repositories>
+ -->
+
+ <dependencies>
+ <dependency>
+ <groupId>org.fusesource.jansi</groupId>
+ <artifactId>jansi</artifactId>
+ <version>1.4</version>
+ <!--<scope>provided</scope>-->
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.8.1</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <defaultGoal>install</defaultGoal>
+
+ <resources>
+ <resource>
+ <directory>${project.basedir}/src/main/resources</directory>
+ <filtering>false</filtering>
+ <includes>
+ <include>**/*</include>
+ </includes>
+ </resource>
+
+ <resource>
+ <directory>${project.basedir}/src/main/filtered-resources</directory>
+ <filtering>true</filtering>
+ <includes>
+ <include>**/*</include>
+ </includes>
+ </resource>
+ </resources>
+
+ <testResources>
+ <testResource>
+ <directory>${project.basedir}/src/test/resources</directory>
+ <filtering>false</filtering>
+ <includes>
+ <include>**/*</include>
+ </includes>
+ </testResource>
+
+ <testResource>
+ <directory>${project.basedir}/src/test/filtered-resources</directory>
+ <filtering>true</filtering>
+ <includes>
+ <include>**/*</include>
+ </includes>
+ </testResource>
+ </testResources>
+
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.6</version>
+ <configuration>
+ <redirectTestOutputToFile>true</redirectTestOutputToFile>
+ <forkMode>once</forkMode>
+ <argLine>-ea</argLine>
+ <failIfNoTests>false</failIfNoTests>
+ <workingDirectory>${project.build.directory}</workingDirectory>
+ <excludes>
+ <exclude>**/Abstract*.java</exclude>
+ <exclude>**/Test*.java</exclude>
+ </excludes>
+ <includes>
+ <include>**/*Test.java</include>
+ </includes>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.3.2</version>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>2.1.0</version>
+ <executions>
+ <execution>
+ <phase>process-classes</phase>
+ <goals>
+ <goal>manifest</goal>
+ </goals>
+ <configuration>
+ <instructions>
+ <Import-Package>!jline*,javax.swing;resolution:=optional,*</Import-Package>
+ <DynamicImport-Package>*</DynamicImport-Package>
+ </instructions>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <version>2.3.1</version>
+ <configuration>
+ <archive>
+ <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+ </archive>
+ </configuration>
+ <executions>
+ <execution>
+ <goals>
+ <goal>test-jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-scm-plugin</artifactId>
+ <version>1.4</version>
+ </plugin>
+
+ <!-- include all the dependencies into the jar so it can run standalone -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-shade-plugin</artifactId>
+ <version>1.4</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>shade</goal>
+ </goals>
+ <configuration>
+ <artifactSet>
+ <excludes>
+ <exclude>junit:junit</exclude>
+ </excludes>
+ </artifactSet>
+ <filters>
+ <filter>
+ <artifact>org.fusesource.jansi:jansi</artifact>
+ <excludes>
+ <exclude>META-INF/maven/**</exclude>
+ <exclude>*.txt</exclude>
+ <exclude>junit/**</exclude>
+ <exclude>org/junit/**</exclude>
+ <exclude>org/hamcrest/**</exclude>
+ <exclude>org/fusesource/hawtjni/runtime/Jni*</exclude>
+ <exclude>org/fusesource/hawtjni/runtime/*Flag*</exclude>
+ <exclude>org/fusesource/hawtjni/runtime/T32*</exclude>
+ <exclude>org/fusesource/hawtjni/runtime/NativeStats*</exclude>
+ </excludes>
+ </filter>
+ </filters>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+ <profiles>
+ <profile>
+ <id>retro</id>
+ <activation>
+ <property>
+ <name>retro</name>
+ <value>true</value>
+ </property>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>retrotranslator-maven-plugin</artifactId>
+ <version>1.0-alpha-4</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>translate-project</goal>
+ </goals>
+ <configuration>
+ <classifier>jdk14</classifier>
+ <attach>true</attach>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+
+</project> \ No newline at end of file
diff --git a/src/jline/src/assembly/assembly.xml b/src/jline/src/assembly/assembly.xml
deleted file mode 100644
index 216c697a53..0000000000
--- a/src/jline/src/assembly/assembly.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-<assembly>
- <id></id>
- <formats>
- <format>zip</format>
- </formats>
- <includeBaseDirectory>true</includeBaseDirectory>
- <fileSets>
- <fileSet>
- <includes>
- <include>README*</include>
- <include>LICENSE*</include>
- <include>NOTICE*</include>
- </includes>
- </fileSet>
- <fileSet>
- <directory>target</directory>
- <outputDirectory></outputDirectory>
- <includes>
- <include>*.jar</include>
- </includes>
- </fileSet>
- <fileSet>
- <directory>licenses</directory>
- <outputDirectory>/lib</outputDirectory>
- <includes>
- <include>*</include>
- </includes>
- </fileSet>
- <fileSet>
- <directory>src/test/java/jline/example</directory>
- <outputDirectory>/examples/jline/example</outputDirectory>
- </fileSet>
- <fileSet>
- <directory>src/test/resources/jline/example</directory>
- <outputDirectory>/examples/jline/example</outputDirectory>
- </fileSet>
- <fileSet>
- <directory>target/site/apidocs</directory>
- <outputDirectory>/apidocs</outputDirectory>
- </fileSet>
-
- <!-- also include sources -->
- <fileSet>
- <directory>src</directory>
- <outputDirectory>/src/src</outputDirectory>
- </fileSet>
- <fileSet>
- <directory></directory>
- <outputDirectory>/src</outputDirectory>
- <includes>
- <include>pom.xml</include>
- </includes>
- </fileSet>
- </fileSets>
-</assembly>
diff --git a/src/jline/src/main/java/jline/ANSIBuffer.java b/src/jline/src/main/java/jline/ANSIBuffer.java
deleted file mode 100644
index c2e33180bb..0000000000
--- a/src/jline/src/main/java/jline/ANSIBuffer.java
+++ /dev/null
@@ -1,405 +0,0 @@
-/*
- * 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.*;
-
-/**
- * A buffer that can contain ANSI text.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- */
-public class ANSIBuffer {
- private boolean ansiEnabled = true;
- private final StringBuffer ansiBuffer = new StringBuffer();
- private final StringBuffer plainBuffer = new StringBuffer();
-
- public ANSIBuffer() {
- }
-
- public ANSIBuffer(final String str) {
- append(str);
- }
-
- public void setAnsiEnabled(final boolean ansi) {
- this.ansiEnabled = ansi;
- }
-
- public boolean getAnsiEnabled() {
- return this.ansiEnabled;
- }
-
- public String getAnsiBuffer() {
- return ansiBuffer.toString();
- }
-
- public String getPlainBuffer() {
- return plainBuffer.toString();
- }
-
- public String toString(final boolean ansi) {
- return ansi ? getAnsiBuffer() : getPlainBuffer();
- }
-
- public String toString() {
- return toString(ansiEnabled);
- }
-
- public ANSIBuffer append(final String str) {
- ansiBuffer.append(str);
- plainBuffer.append(str);
-
- return this;
- }
-
- public ANSIBuffer attrib(final String str, final int code) {
- ansiBuffer.append(ANSICodes.attrib(code)).append(str)
- .append(ANSICodes.attrib(ANSICodes.OFF));
- plainBuffer.append(str);
-
- return this;
- }
-
- public ANSIBuffer red(final String str) {
- return attrib(str, ANSICodes.FG_RED);
- }
-
- public ANSIBuffer blue(final String str) {
- return attrib(str, ANSICodes.FG_BLUE);
- }
-
- public ANSIBuffer green(final String str) {
- return attrib(str, ANSICodes.FG_GREEN);
- }
-
- public ANSIBuffer black(final String str) {
- return attrib(str, ANSICodes.FG_BLACK);
- }
-
- public ANSIBuffer yellow(final String str) {
- return attrib(str, ANSICodes.FG_YELLOW);
- }
-
- public ANSIBuffer magenta(final String str) {
- return attrib(str, ANSICodes.FG_MAGENTA);
- }
-
- public ANSIBuffer cyan(final String str) {
- return attrib(str, ANSICodes.FG_CYAN);
- }
-
- public ANSIBuffer bold(final String str) {
- return attrib(str, ANSICodes.BOLD);
- }
-
- public ANSIBuffer underscore(final String str) {
- return attrib(str, ANSICodes.UNDERSCORE);
- }
-
- public ANSIBuffer blink(final String str) {
- return attrib(str, ANSICodes.BLINK);
- }
-
- public ANSIBuffer reverse(final String str) {
- return attrib(str, ANSICodes.REVERSE);
- }
-
- public static class ANSICodes {
- static final int OFF = 0;
- static final int BOLD = 1;
- static final int UNDERSCORE = 4;
- static final int BLINK = 5;
- static final int REVERSE = 7;
- static final int CONCEALED = 8;
- static final int FG_BLACK = 30;
- static final int FG_RED = 31;
- static final int FG_GREEN = 32;
- static final int FG_YELLOW = 33;
- static final int FG_BLUE = 34;
- static final int FG_MAGENTA = 35;
- static final int FG_CYAN = 36;
- static final int FG_WHITE = 37;
- static final char ESC = 27;
-
- /**
- * Constructor is private since this is a utility class.
- */
- private ANSICodes() {
- }
-
- /**
- * Sets the screen mode. The mode will be one of the following values:
- * <pre>
- * mode description
- * ----------------------------------------
- * 0 40 x 148 x 25 monochrome (text)
- * 1 40 x 148 x 25 color (text)
- * 2 80 x 148 x 25 monochrome (text)
- * 3 80 x 148 x 25 color (text)
- * 4 320 x 148 x 200 4-color (graphics)
- * 5 320 x 148 x 200 monochrome (graphics)
- * 6 640 x 148 x 200 monochrome (graphics)
- * 7 Enables line wrapping
- * 13 320 x 148 x 200 color (graphics)
- * 14 640 x 148 x 200 color (16-color graphics)
- * 15 640 x 148 x 350 monochrome (2-color graphics)
- * 16 640 x 148 x 350 color (16-color graphics)
- * 17 640 x 148 x 480 monochrome (2-color graphics)
- * 18 640 x 148 x 480 color (16-color graphics)
- * 19 320 x 148 x 200 color (256-color graphics)
- * </pre>
- */
- public static String setmode(final int mode) {
- return ESC + "[=" + mode + "h";
- }
-
- /**
- * Same as setmode () except for mode = 7, which disables line
- * wrapping (useful for writing the right-most column without
- * scrolling to the next line).
- */
- public static String resetmode(final int mode) {
- return ESC + "[=" + mode + "l";
- }
-
- /**
- * Clears the screen and moves the cursor to the home postition.
- */
- public static String clrscr() {
- return ESC + "[2J";
- }
-
- /**
- * Removes all characters from the current cursor position until
- * the end of the line.
- */
- public static String clreol() {
- return ESC + "[K";
- }
-
- /**
- * Moves the cursor n positions to the left. If n is greater or
- * equal to the current cursor column, the cursor is moved to the
- * first column.
- */
- public static String left(final int n) {
- return ESC + "[" + n + "D";
- }
-
- /**
- * Moves the cursor n positions to the right. If n plus the current
- * cursor column is greater than the rightmost column, the cursor
- * is moved to the rightmost column.
- */
- public static String right(final int n) {
- return ESC + "[" + n + "C";
- }
-
- /**
- * Moves the cursor n rows up without changing the current column.
- * If n is greater than or equal to the current row, the cursor is
- * placed in the first row.
- */
- public static String up(final int n) {
- return ESC + "[" + n + "A";
- }
-
- /**
- * Moves the cursor n rows down. If n plus the current row is greater
- * than the bottom row, the cursor is moved to the bottom row.
- */
- public static String down(final int n) {
- return ESC + "[" + n + "B";
- }
-
- /*
- * Moves the cursor to the given row and column. (1,1) represents
- * the upper left corner. The lower right corner of a usual DOS
- * screen is (25, 80).
- */
- public static String gotoxy(final int row, final int column) {
- return ESC + "[" + row + ";" + column + "H";
- }
-
- /**
- * Saves the current cursor position.
- */
- public static String save() {
- return ESC + "[s";
- }
-
- /**
- * Restores the saved cursor position.
- */
- public static String restore() {
- return ESC + "[u";
- }
-
- /**
- * Sets the character attribute. It will be
- * one of the following character attributes:
- *
- * <pre>
- * Text attributes
- * 0 All attributes off
- * 1 Bold on
- * 4 Underscore (on monochrome display adapter only)
- * 5 Blink on
- * 7 Reverse video on
- * 8 Concealed on
- *
- * Foreground colors
- * 30 Black
- * 31 Red
- * 32 Green
- * 33 Yellow
- * 34 Blue
- * 35 Magenta
- * 36 Cyan
- * 37 White
- *
- * Background colors
- * 40 Black
- * 41 Red
- * 42 Green
- * 43 Yellow
- * 44 Blue
- * 45 Magenta
- * 46 Cyan
- * 47 White
- * </pre>
- *
- * The attributes remain in effect until the next attribute command
- * is sent.
- */
- public static String attrib(final int attr) {
- return ESC + "[" + attr + "m";
- }
-
- /**
- * Sets the key with the given code to the given value. code must be
- * derived from the following table, value must
- * be any semicolon-separated
- * combination of String (enclosed in double quotes) and numeric values.
- * For example, to set F1 to the String "Hello F1", followed by a CRLF
- * sequence, one can use: ANSI.setkey ("0;59", "\"Hello F1\";13;10").
- * Heres's the table of key values:
- * <pre>
- * Key Code SHIFT+code CTRL+code ALT+code
- * ---------------------------------------------------------------
- * F1 0;59 0;84 0;94 0;104
- * F2 0;60 0;85 0;95 0;105
- * F3 0;61 0;86 0;96 0;106
- * F4 0;62 0;87 0;97 0;107
- * F5 0;63 0;88 0;98 0;108
- * F6 0;64 0;89 0;99 0;109
- * F7 0;65 0;90 0;100 0;110
- * F8 0;66 0;91 0;101 0;111
- * F9 0;67 0;92 0;102 0;112
- * F10 0;68 0;93 0;103 0;113
- * F11 0;133 0;135 0;137 0;139
- * F12 0;134 0;136 0;138 0;140
- * HOME (num keypad) 0;71 55 0;119 --
- * UP ARROW (num keypad) 0;72 56 (0;141) --
- * PAGE UP (num keypad) 0;73 57 0;132 --
- * LEFT ARROW (num keypad) 0;75 52 0;115 --
- * RIGHT ARROW (num keypad) 0;77 54 0;116 --
- * END (num keypad) 0;79 49 0;117 --
- * DOWN ARROW (num keypad) 0;80 50 (0;145) --
- * PAGE DOWN (num keypad) 0;81 51 0;118 --
- * INSERT (num keypad) 0;82 48 (0;146) --
- * DELETE (num keypad) 0;83 46 (0;147) --
- * HOME (224;71) (224;71) (224;119) (224;151)
- * UP ARROW (224;72) (224;72) (224;141) (224;152)
- * PAGE UP (224;73) (224;73) (224;132) (224;153)
- * LEFT ARROW (224;75) (224;75) (224;115) (224;155)
- * RIGHT ARROW (224;77) (224;77) (224;116) (224;157)
- * END (224;79) (224;79) (224;117) (224;159)
- * DOWN ARROW (224;80) (224;80) (224;145) (224;154)
- * PAGE DOWN (224;81) (224;81) (224;118) (224;161)
- * INSERT (224;82) (224;82) (224;146) (224;162)
- * DELETE (224;83) (224;83) (224;147) (224;163)
- * PRINT SCREEN -- -- 0;114 --
- * PAUSE/BREAK -- -- 0;0 --
- * BACKSPACE 8 8 127 (0)
- * ENTER 13 -- 10 (0
- * TAB 9 0;15 (0;148) (0;165)
- * NULL 0;3 -- -- --
- * A 97 65 1 0;30
- * B 98 66 2 0;48
- * C 99 66 3 0;46
- * D 100 68 4 0;32
- * E 101 69 5 0;18
- * F 102 70 6 0;33
- * G 103 71 7 0;34
- * H 104 72 8 0;35
- * I 105 73 9 0;23
- * J 106 74 10 0;36
- * K 107 75 11 0;37
- * L 108 76 12 0;38
- * M 109 77 13 0;50
- * N 110 78 14 0;49
- * O 111 79 15 0;24
- * P 112 80 16 0;25
- * Q 113 81 17 0;16
- * R 114 82 18 0;19
- * S 115 83 19 0;31
- * T 116 84 20 0;20
- * U 117 85 21 0;22
- * V 118 86 22 0;47
- * W 119 87 23 0;17
- * X 120 88 24 0;45
- * Y 121 89 25 0;21
- * Z 122 90 26 0;44
- * 1 49 33 -- 0;120
- * 2 50 64 0 0;121
- * 3 51 35 -- 0;122
- * 4 52 36 -- 0;123
- * 5 53 37 -- 0;124
- * 6 54 94 30 0;125
- * 7 55 38 -- 0;126
- * 8 56 42 -- 0;126
- * 9 57 40 -- 0;127
- * 0 48 41 -- 0;129
- * - 45 95 31 0;130
- * = 61 43 --- 0;131
- * [ 91 123 27 0;26
- * ] 93 125 29 0;27
- * 92 124 28 0;43
- * ; 59 58 -- 0;39
- * ' 39 34 -- 0;40
- * , 44 60 -- 0;51
- * . 46 62 -- 0;52
- * / 47 63 -- 0;53
- * ` 96 126 -- (0;41)
- * ENTER (keypad) 13 -- 10 (0;166)
- * / (keypad) 47 47 (0;142) (0;74)
- * * (keypad) 42 (0;144) (0;78) --
- * - (keypad) 45 45 (0;149) (0;164)
- * + (keypad) 43 43 (0;150) (0;55)
- * 5 (keypad) (0;76) 53 (0;143) --
- */
- public static String setkey(final String code, final String value) {
- return ESC + "[" + code + ";" + value + "p";
- }
- }
-
- public static void main(final String[] args) throws Exception {
- // sequence, one can use: ANSI.setkey ("0;59", "\"Hello F1\";13;10").
- BufferedReader reader =
- new BufferedReader(new InputStreamReader(System.in));
- System.out.print(ANSICodes.setkey("97", "97;98;99;13")
- + ANSICodes.attrib(ANSICodes.OFF));
- System.out.flush();
-
- String line;
-
- while ((line = reader.readLine()) != null) {
- System.out.println("GOT: " + line);
- }
- }
-}
diff --git a/src/jline/src/main/java/jline/AnsiWindowsTerminal.java b/src/jline/src/main/java/jline/AnsiWindowsTerminal.java
new file mode 100644
index 0000000000..43351952ff
--- /dev/null
+++ b/src/jline/src/main/java/jline/AnsiWindowsTerminal.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2009 the original author(s).
+ *
+ * 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.
+ *
+ * MODIFICATIONS: methods to deal with wrapping the output stream.
+ */
+
+package jline;
+
+import org.fusesource.jansi.AnsiConsole;
+import org.fusesource.jansi.AnsiOutputStream;
+import org.fusesource.jansi.WindowsAnsiOutputStream;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+
+/**
+ * ANSI-supported {@link WindowsTerminal}.
+ *
+ * @since 2.0
+ */
+public class AnsiWindowsTerminal
+ extends WindowsTerminal
+{
+ private final boolean ansiSupported = detectAnsiSupport();
+
+ @Override
+ public OutputStream wrapOutIfNeeded(OutputStream out) {
+ return wrapOutputStream(out);
+ }
+
+ /**
+ * Returns an ansi output stream handler. We return whatever was
+ * passed if we determine we cannot handle ansi based on Kernel32 calls.
+ *
+ * @return an @{link AltWindowAnsiOutputStream} instance or the passed
+ * stream.
+ */
+ private static OutputStream wrapOutputStream(final OutputStream stream) {
+ String os = System.getProperty("os.name");
+ if( os.startsWith("Windows") ) {
+ // On windows we know the console does not interpret ANSI codes..
+ try {
+ return new WindowsAnsiOutputStream(stream);
+ } catch (Throwable ignore) {
+ // this happens when JNA is not in the path.. or
+ // this happens when the stdout is being redirected to a file.
+ }
+ // Use the ANSIOutputStream to strip out the ANSI escape sequences.
+ return new AnsiOutputStream(stream);
+ }
+ return stream;
+ }
+
+ private static boolean detectAnsiSupport() {
+ OutputStream out = AnsiConsole.wrapOutputStream(new ByteArrayOutputStream());
+ try {
+ out.close();
+ }
+ catch (Exception e) {
+ // ignore;
+ }
+ return out instanceof WindowsAnsiOutputStream;
+ }
+
+ public AnsiWindowsTerminal() throws Exception {
+ super();
+ }
+
+ @Override
+ public boolean isAnsiSupported() {
+ return ansiSupported;
+ }
+
+ @Override
+ public boolean newlineAtWrapNeeded() {
+ return false;
+ }
+}
diff --git a/src/jline/src/main/java/jline/ArgumentCompletor.java b/src/jline/src/main/java/jline/ArgumentCompletor.java
deleted file mode 100644
index 2cd572ce2f..0000000000
--- a/src/jline/src/main/java/jline/ArgumentCompletor.java
+++ /dev/null
@@ -1,439 +0,0 @@
-/*
- * 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.util.*;
-
-/**
- * A {@link Completor} implementation that invokes a child completor
- * using the appropriate <i>separator</i> argument. This
- * can be used instead of the individual completors having to
- * know about argument parsing semantics.
- * <p>
- * <strong>Example 1</strong>: Any argument of the command line can
- * use file completion.
- * <p>
- * <pre>
- * consoleReader.addCompletor (new ArgumentCompletor (
- * new {@link FileNameCompletor} ()))
- * </pre>
- * <p>
- * <strong>Example 2</strong>: The first argument of the command line
- * can be completed with any of "foo", "bar", or "baz", and remaining
- * arguments can be completed with a file name.
- * <p>
- * <pre>
- * consoleReader.addCompletor (new ArgumentCompletor (
- * new {@link SimpleCompletor} (new String [] { "foo", "bar", "baz"})));
- * consoleReader.addCompletor (new ArgumentCompletor (
- * new {@link FileNameCompletor} ()));
- * </pre>
- *
- * <p>
- * When the argument index is past the last embedded completors, the last
- * completors is always used. To disable this behavior, have the last
- * completor be a {@link NullCompletor}. For example:
- * </p>
- *
- * <pre>
- * consoleReader.addCompletor (new ArgumentCompletor (
- * new {@link SimpleCompletor} (new String [] { "foo", "bar", "baz"}),
- * new {@link SimpleCompletor} (new String [] { "xxx", "yyy", "xxx"}),
- * new {@link NullCompletor}
- * ));
- * </pre>
- * <p>
- * TODO: handle argument quoting and escape characters
- * </p>
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- */
-public class ArgumentCompletor implements Completor {
- final Completor[] completors;
- final ArgumentDelimiter delim;
- boolean strict = true;
-
- /**
- * Constuctor: create a new completor with the default
- * argument separator of " ".
- *
- * @param completor the embedded completor
- */
- public ArgumentCompletor(final Completor completor) {
- this(new Completor[] {
- completor
- });
- }
-
- /**
- * Constuctor: create a new completor with the default
- * argument separator of " ".
- *
- * @param completors the List of completors to use
- */
- public ArgumentCompletor(final List<Completor> completors) {
- this((Completor[]) completors.toArray(new Completor[completors.size()]));
- }
-
- /**
- * Constuctor: create a new completor with the default
- * argument separator of " ".
- *
- * @param completors the embedded argument completors
- */
- public ArgumentCompletor(final Completor[] completors) {
- this(completors, new WhitespaceArgumentDelimiter());
- }
-
- /**
- * Constuctor: create a new completor with the specified
- * argument delimiter.
- *
- * @param completor the embedded completor
- * @param delim the delimiter for parsing arguments
- */
- public ArgumentCompletor(final Completor completor,
- final ArgumentDelimiter delim) {
- this(new Completor[] {
- completor
- }, delim);
- }
-
- /**
- * Constuctor: create a new completor with the specified
- * argument delimiter.
- *
- * @param completors the embedded completors
- * @param delim the delimiter for parsing arguments
- */
- public ArgumentCompletor(final Completor[] completors,
- final ArgumentDelimiter delim) {
- this.completors = completors;
- this.delim = delim;
- }
-
- /**
- * If true, a completion at argument index N will only succeed
- * if all the completions from 0-(N-1) also succeed.
- */
- public void setStrict(final boolean strict) {
- this.strict = strict;
- }
-
- /**
- * Returns whether a completion at argument index N will succees
- * if all the completions from arguments 0-(N-1) also succeed.
- */
- public boolean getStrict() {
- return this.strict;
- }
-
- public int complete(final String buffer, final int cursor,
- final List<String> candidates) {
- ArgumentList list = delim.delimit(buffer, cursor);
- int argpos = list.getArgumentPosition();
- int argIndex = list.getCursorArgumentIndex();
-
- if (argIndex < 0) {
- return -1;
- }
-
- final Completor comp;
-
- // if we are beyond the end of the completors, just use the last one
- if (argIndex >= completors.length) {
- comp = completors[completors.length - 1];
- } else {
- comp = completors[argIndex];
- }
-
- // ensure that all the previous completors are successful before
- // allowing this completor to pass (only if strict is true).
- for (int i = 0; getStrict() && (i < argIndex); i++) {
- Completor sub =
- completors[(i >= completors.length) ? (completors.length - 1) : i];
- String[] args = list.getArguments();
- String arg = ((args == null) || (i >= args.length)) ? "" : args[i];
-
- List<String> subCandidates = new LinkedList<String>();
-
- if (sub.complete(arg, arg.length(), subCandidates) == -1) {
- return -1;
- }
-
- if (subCandidates.size() == 0) {
- return -1;
- }
- }
-
- int ret = comp.complete(list.getCursorArgument(), argpos, candidates);
-
- if (ret == -1) {
- return -1;
- }
-
- int pos = ret + (list.getBufferPosition() - argpos);
-
- /**
- * Special case: when completing in the middle of a line, and the
- * area under the cursor is a delimiter, then trim any delimiters
- * from the candidates, since we do not need to have an extra
- * delimiter.
- *
- * E.g., if we have a completion for "foo", and we
- * enter "f bar" into the buffer, and move to after the "f"
- * and hit TAB, we want "foo bar" instead of "foo bar".
- */
- if ((cursor != buffer.length()) && delim.isDelimiter(buffer, cursor)) {
- for (int i = 0; i < candidates.size(); i++) {
- String val = candidates.get(i).toString();
-
- while ((val.length() > 0)
- && delim.isDelimiter(val, val.length() - 1)) {
- val = val.substring(0, val.length() - 1);
- }
-
- candidates.set(i, val);
- }
- }
-
- ConsoleReader.debug("Completing " + buffer + "(pos=" + cursor + ") "
- + "with: " + candidates + ": offset=" + pos);
-
- return pos;
- }
-
- /**
- * The {@link ArgumentCompletor.ArgumentDelimiter} allows custom
- * breaking up of a {@link String} into individual arguments in
- * order to dispatch the arguments to the nested {@link Completor}.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- */
- public static interface ArgumentDelimiter {
- /**
- * Break the specified buffer into individual tokens
- * that can be completed on their own.
- *
- * @param buffer the buffer to split
- * @param argumentPosition the current position of the
- * cursor in the buffer
- * @return the tokens
- */
- ArgumentList delimit(String buffer, int argumentPosition);
-
- /**
- * Returns true if the specified character is a whitespace
- * parameter.
- *
- * @param buffer the complete command buffer
- * @param pos the index of the character in the buffer
- * @return true if the character should be a delimiter
- */
- boolean isDelimiter(String buffer, int pos);
- }
-
- /**
- * Abstract implementation of a delimiter that uses the
- * {@link #isDelimiter} method to determine if a particular
- * character should be used as a delimiter.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- */
- public abstract static class AbstractArgumentDelimiter
- implements ArgumentDelimiter {
- private char[] quoteChars = new char[] { '\'', '"' };
- private char[] escapeChars = new char[] { '\\' };
-
- public void setQuoteChars(final char[] quoteChars) {
- this.quoteChars = quoteChars;
- }
-
- public char[] getQuoteChars() {
- return this.quoteChars;
- }
-
- public void setEscapeChars(final char[] escapeChars) {
- this.escapeChars = escapeChars;
- }
-
- public char[] getEscapeChars() {
- return this.escapeChars;
- }
-
- public ArgumentList delimit(final String buffer, final int cursor) {
- List<String> args = new LinkedList<String>();
- StringBuffer arg = new StringBuffer();
- int argpos = -1;
- int bindex = -1;
-
- for (int i = 0; (buffer != null) && (i <= buffer.length()); i++) {
- // once we reach the cursor, set the
- // position of the selected index
- if (i == cursor) {
- bindex = args.size();
- // the position in the current argument is just the
- // length of the current argument
- argpos = arg.length();
- }
-
- if ((i == buffer.length()) || isDelimiter(buffer, i)) {
- if (arg.length() > 0) {
- args.add(arg.toString());
- arg.setLength(0); // reset the arg
- }
- } else {
- arg.append(buffer.charAt(i));
- }
- }
-
- return new ArgumentList((String[]) args.
- toArray(new String[args.size()]), bindex, argpos, cursor);
- }
-
- /**
- * Returns true if the specified character is a whitespace
- * parameter. Check to ensure that the character is not
- * escaped by any of
- * {@link #getQuoteChars}, and is not escaped by ant of the
- * {@link #getEscapeChars}, and returns true from
- * {@link #isDelimiterChar}.
- *
- * @param buffer the complete command buffer
- * @param pos the index of the character in the buffer
- * @return true if the character should be a delimiter
- */
- public boolean isDelimiter(final String buffer, final int pos) {
- if (isQuoted(buffer, pos)) {
- return false;
- }
-
- if (isEscaped(buffer, pos)) {
- return false;
- }
-
- return isDelimiterChar(buffer, pos);
- }
-
- public boolean isQuoted(final String buffer, final int pos) {
- return false;
- }
-
- public boolean isEscaped(final String buffer, final int pos) {
- if (pos <= 0) {
- return false;
- }
-
- for (int i = 0; (escapeChars != null) && (i < escapeChars.length);
- i++) {
- if (buffer.charAt(pos) == escapeChars[i]) {
- return !isEscaped(buffer, pos - 1); // escape escape
- }
- }
-
- return false;
- }
-
- /**
- * Returns true if the character at the specified position
- * if a delimiter. This method will only be called if the
- * character is not enclosed in any of the
- * {@link #getQuoteChars}, and is not escaped by ant of the
- * {@link #getEscapeChars}. To perform escaping manually,
- * override {@link #isDelimiter} instead.
- */
- public abstract boolean isDelimiterChar(String buffer, int pos);
- }
-
- /**
- * {@link ArgumentCompletor.ArgumentDelimiter}
- * implementation that counts all
- * whitespace (as reported by {@link Character#isWhitespace})
- * as being a delimiter.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- */
- public static class WhitespaceArgumentDelimiter
- extends AbstractArgumentDelimiter {
- /**
- * The character is a delimiter if it is whitespace, and the
- * preceeding character is not an escape character.
- */
- public boolean isDelimiterChar(String buffer, int pos) {
- return Character.isWhitespace(buffer.charAt(pos));
- }
- }
-
- /**
- * The result of a delimited buffer.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- */
- public static class ArgumentList {
- private String[] arguments;
- private int cursorArgumentIndex;
- private int argumentPosition;
- private int bufferPosition;
-
- /**
- * @param arguments the array of tokens
- * @param cursorArgumentIndex the token index of the cursor
- * @param argumentPosition the position of the cursor in the
- * current token
- * @param bufferPosition the position of the cursor in
- * the whole buffer
- */
- public ArgumentList(String[] arguments, int cursorArgumentIndex,
- int argumentPosition, int bufferPosition) {
- this.arguments = arguments;
- this.cursorArgumentIndex = cursorArgumentIndex;
- this.argumentPosition = argumentPosition;
- this.bufferPosition = bufferPosition;
- }
-
- public void setCursorArgumentIndex(int cursorArgumentIndex) {
- this.cursorArgumentIndex = cursorArgumentIndex;
- }
-
- public int getCursorArgumentIndex() {
- return this.cursorArgumentIndex;
- }
-
- public String getCursorArgument() {
- if ((cursorArgumentIndex < 0)
- || (cursorArgumentIndex >= arguments.length)) {
- return null;
- }
-
- return arguments[cursorArgumentIndex];
- }
-
- public void setArgumentPosition(int argumentPosition) {
- this.argumentPosition = argumentPosition;
- }
-
- public int getArgumentPosition() {
- return this.argumentPosition;
- }
-
- public void setArguments(String[] arguments) {
- this.arguments = arguments;
- }
-
- public String[] getArguments() {
- return this.arguments;
- }
-
- public void setBufferPosition(int bufferPosition) {
- this.bufferPosition = bufferPosition;
- }
-
- public int getBufferPosition() {
- return this.bufferPosition;
- }
- }
-}
diff --git a/src/jline/src/main/java/jline/CandidateCycleCompletionHandler.java b/src/jline/src/main/java/jline/CandidateCycleCompletionHandler.java
deleted file mode 100644
index a0bf208cdc..0000000000
--- a/src/jline/src/main/java/jline/CandidateCycleCompletionHandler.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * 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 {@link CompletionHandler} that deals with multiple distinct completions
- * by cycling through each one every time tab is pressed. This
- * mimics the behavior of the
- * <a href="http://packages.qa.debian.org/e/editline.html">editline</a>
- * library.
- * </p>
- * <p><strong>This class is currently a stub; it does nothing</strong></p>
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- */
-public class CandidateCycleCompletionHandler implements CompletionHandler {
- public boolean complete(final ConsoleReader reader, final List candidates,
- final int position) throws IOException {
- throw new IllegalStateException("CandidateCycleCompletionHandler unimplemented");
- }
-}
diff --git a/src/jline/src/main/java/jline/CandidateListCompletionHandler.java b/src/jline/src/main/java/jline/CandidateListCompletionHandler.java
deleted file mode 100644
index 17f03d5e68..0000000000
--- a/src/jline/src/main/java/jline/CandidateListCompletionHandler.java
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * 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.text.MessageFormat;
-import java.util.*;
-
-/**
- * <p>
- * A {@link CompletionHandler} that deals with multiple distinct completions
- * by outputting the complete list of possibilities to the console. This
- * mimics the behavior of the
- * <a href="http://www.gnu.org/directory/readline.html">readline</a>
- * library.
- * </p>
- *
- * <strong>TODO:</strong>
- * <ul>
- * <li>handle quotes and escaped quotes</li>
- * <li>enable automatic escaping of whitespace</li>
- * </ul>
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- */
-public class CandidateListCompletionHandler implements CompletionHandler {
- private static ResourceBundle loc = ResourceBundle.
- getBundle(CandidateListCompletionHandler.class.getName());
-
- private boolean eagerNewlines = true;
-
- public void setAlwaysIncludeNewline(boolean eagerNewlines) {
- this.eagerNewlines = eagerNewlines;
- }
-
- public boolean complete(final ConsoleReader reader, final List<String> candidates,
- final int pos) throws IOException {
- CursorBuffer buf = reader.getCursorBuffer();
-
- // if there is only one completion, then fill in the buffer
- if (candidates.size() == 1) {
- String value = candidates.get(0).toString();
-
- // fail if the only candidate is the same as the current buffer
- if (value.equals(buf.toString())) {
- return false;
- }
-
- setBuffer(reader, value, pos);
-
- return true;
- } else if (candidates.size() > 1) {
- String value = getUnambiguousCompletions(candidates);
- String bufString = buf.toString();
- setBuffer(reader, value, pos);
- }
-
- if (eagerNewlines)
- reader.printNewline();
- printCandidates(reader, candidates, eagerNewlines);
-
- // redraw the current console buffer
- reader.drawLine();
-
- return true;
- }
-
- public static void setBuffer(ConsoleReader reader, String value, int offset)
- throws IOException {
- while ((reader.getCursorBuffer().cursor > offset)
- && reader.backspace()) {
- ;
- }
-
- reader.putString(value);
- reader.setCursorPosition(offset + value.length());
- }
-
- /**
- * Print out the candidates. If the size of the candidates
- * is greated than the {@link getAutoprintThreshhold},
- * they prompt with aq warning.
- *
- * @param candidates the list of candidates to print
- */
- public static final void printCandidates(ConsoleReader reader,
- Collection<String> candidates, boolean eagerNewlines)
- throws IOException {
- Set<String> distinct = new HashSet<String>(candidates);
-
- if (distinct.size() > reader.getAutoprintThreshhold()) {
- if (!eagerNewlines)
- reader.printNewline();
- reader.printString(MessageFormat.format
- (loc.getString("display-candidates"), new Object[] {
- new Integer(candidates .size())
- }) + " ");
-
- reader.flushConsole();
-
- int c;
-
- String noOpt = loc.getString("display-candidates-no");
- String yesOpt = loc.getString("display-candidates-yes");
-
- while ((c = reader.readCharacter(new char[] {
- yesOpt.charAt(0), noOpt.charAt(0) })) != -1) {
- if (noOpt.startsWith
- (new String(new char[] { (char) c }))) {
- reader.printNewline();
- return;
- } else if (yesOpt.startsWith
- (new String(new char[] { (char) c }))) {
- break;
- } else {
- reader.beep();
- }
- }
- }
-
- // copy the values and make them distinct, without otherwise
- // affecting the ordering. Only do it if the sizes differ.
- if (distinct.size() != candidates.size()) {
- Collection<String> copy = new ArrayList<String>();
-
- for (Iterator<String> i = candidates.iterator(); i.hasNext();) {
- String next = i.next();
-
- if (!(copy.contains(next))) {
- copy.add(next);
- }
- }
-
- candidates = copy;
- }
-
- reader.printNewline();
- reader.printColumns(candidates);
- }
-
- /**
- * Returns a root that matches all the {@link String} elements
- * of the specified {@link List}, or null if there are
- * no commalities. For example, if the list contains
- * <i>foobar</i>, <i>foobaz</i>, <i>foobuz</i>, the
- * method will return <i>foob</i>.
- */
- private final String getUnambiguousCompletions(final List<String> candidates) {
- if ((candidates == null) || (candidates.size() == 0)) {
- return null;
- }
-
- // convert to an array for speed
- String[] strings =
- (String[]) candidates.toArray(new String[candidates.size()]);
-
- String first = strings[0];
- StringBuffer candidate = new StringBuffer();
-
- for (int i = 0; i < first.length(); i++) {
- if (startsWith(first.substring(0, i + 1), strings)) {
- candidate.append(first.charAt(i));
- } else {
- break;
- }
- }
-
- return candidate.toString();
- }
-
- /**
- * @return true is all the elements of <i>candidates</i>
- * start with <i>starts</i>
- */
- private final boolean startsWith(final String starts,
- final String[] candidates) {
- for (int i = 0; i < candidates.length; i++) {
- if (!candidates[i].startsWith(starts)) {
- return false;
- }
- }
-
- return true;
- }
-}
diff --git a/src/jline/src/main/java/jline/ClassNameCompletor.java b/src/jline/src/main/java/jline/ClassNameCompletor.java
deleted file mode 100644
index 5c3ca87dca..0000000000
--- a/src/jline/src/main/java/jline/ClassNameCompletor.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * 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.net.*;
-import java.util.*;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
-
-/**
- * A Completor implementation that completes java class names. By default,
- * it scans the java class path to locate all the classes.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- */
-public class ClassNameCompletor extends SimpleCompletor {
-
- /**
- * Complete candidates using all the classes available in the
- * java <em>CLASSPATH</em>.
- */
- public ClassNameCompletor() throws IOException {
- this(null);
- }
-
- public ClassNameCompletor(final SimpleCompletorFilter filter)
- throws IOException {
- super(getClassNames(), filter);
- setDelimiter(".");
- }
-
- public static String[] getClassNames() throws IOException {
- Set<URL> urls = new HashSet<URL>();
-
- for (ClassLoader loader = ClassNameCompletor.class
- .getClassLoader(); loader != null;
- loader = loader.getParent()) {
- if (!(loader instanceof URLClassLoader)) {
- continue;
- }
-
- urls.addAll(Arrays.asList(((URLClassLoader) loader).getURLs()));
- }
-
- // Now add the URL that holds java.lang.String. This is because
- // some JVMs do not report the core classes jar in the list of
- // class loaders.
- Class[] systemClasses = new Class[] {
- String.class, javax.swing.JFrame.class
- };
-
- for (int i = 0; i < systemClasses.length; i++) {
- URL classURL = systemClasses[i].getResource("/"
- + systemClasses[i].getName() .replace('.', '/') + ".class");
-
- if (classURL != null) {
- URLConnection uc = (URLConnection) classURL.openConnection();
-
- if (uc instanceof JarURLConnection) {
- urls.add(((JarURLConnection) uc).getJarFileURL());
- }
- }
- }
-
- Set<String> classes = new HashSet<String>();
-
- for (Iterator i = urls.iterator(); i.hasNext();) {
- URL url = (URL) i.next();
- File file = new File(url.getFile());
-
- if (file.isDirectory()) {
- Set<String> files = getClassFiles(file.getAbsolutePath(),
- new HashSet<String>(), file, new int[] { 200 });
- classes.addAll(files);
-
- continue;
- }
-
- if ((file == null) || !file.isFile()) // TODO: handle directories
- {
- continue;
- }
-
- JarFile jf = new JarFile(file);
-
- for (Enumeration e = jf.entries(); e.hasMoreElements();) {
- JarEntry entry = (JarEntry) e.nextElement();
-
- if (entry == null) {
- continue;
- }
-
- String name = entry.getName();
-
- if (!name.endsWith(".class")) // only use class files
- {
- continue;
- }
-
- classes.add(name);
- }
- }
-
- // now filter classes by changing "/" to "." and trimming the
- // trailing ".class"
- Set<String> classNames = new TreeSet<String>();
-
- for (Iterator<String> i = classes.iterator(); i.hasNext();) {
- String name = (String) i.next();
- classNames.add(name.replace('/', '.').
- substring(0, name.length() - 6));
- }
-
- return (String[]) classNames.toArray(new String[classNames.size()]);
- }
-
- private static Set<String> getClassFiles(String root, Set<String> holder, File directory,
- int[] maxDirectories) {
- // we have passed the maximum number of directories to scan
- if (maxDirectories[0]-- < 0) {
- return holder;
- }
-
- File[] files = directory.listFiles();
-
- for (int i = 0; (files != null) && (i < files.length); i++) {
- String name = files[i].getAbsolutePath();
-
- if (!(name.startsWith(root))) {
- continue;
- } else if (files[i].isDirectory()) {
- getClassFiles(root, holder, files[i], maxDirectories);
- } else if (files[i].getName().endsWith(".class")) {
- holder.add(files[i].getAbsolutePath().
- substring(root.length() + 1));
- }
- }
-
- return holder;
- }
-}
diff --git a/src/jline/src/main/java/jline/CompletionHandler.java b/src/jline/src/main/java/jline/CompletionHandler.java
deleted file mode 100644
index 5dffdcbaae..0000000000
--- a/src/jline/src/main/java/jline/CompletionHandler.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * 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.*;
-
-/**
- * Handler for dealing with candidates for tab-completion.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- */
-public interface CompletionHandler {
- boolean complete(ConsoleReader reader, List<String> candidates, int position)
- throws IOException;
-}
diff --git a/src/jline/src/main/java/jline/Completor.java b/src/jline/src/main/java/jline/Completor.java
deleted file mode 100644
index ed1238a93d..0000000000
--- a/src/jline/src/main/java/jline/Completor.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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.util.*;
-
-/**
- * A Completor is the mechanism by which tab-completion candidates
- * will be resolved.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- */
-public interface Completor {
- /**
- * Populates <i>candidates</i> with a list of possible
- * completions for the <i>buffer</i>. The <i>candidates</i>
- * list will not be sorted before being displayed to the
- * user: thus, the complete method should sort the
- * {@link List} before returning.
- *
- *
- * @param buffer the buffer
- * @param candidates the {@link List} of candidates to populate
- * @return the index of the <i>buffer</i> for which
- * the completion will be relative
- */
- int complete(String buffer, int cursor, List<String> candidates);
-}
diff --git a/src/jline/src/main/java/jline/ConsoleOperations.java b/src/jline/src/main/java/jline/ConsoleOperations.java
deleted file mode 100644
index 585ed401d9..0000000000
--- a/src/jline/src/main/java/jline/ConsoleOperations.java
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * 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.awt.event.KeyEvent;
-
-/**
- * Symbolic constants for Console operations and virtual key bindings.
- * @see KeyEvent
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- */
-public interface ConsoleOperations {
- final String CR = System.getProperty("line.separator");
- final char BACKSPACE = '\b';
- final char RESET_LINE = '\r';
- final char KEYBOARD_BELL = '\07';
- final char CTRL_A = 1;
- final char CTRL_B = 2;
- final char CTRL_C = 3;
- final char CTRL_D = 4;
- final char CTRL_E = 5;
- final char CTRL_F = 6;
- final static char CTRL_K = 11;
- final static char CTRL_L = 12;
- final char CTRL_N = 14;
- final char CTRL_P = 16;
- final static char CTRL_OB = 27;
- final static char DELETE = 127;
- final static char CTRL_QM = 127;
-
-
- /**
- * Logical constants for key operations.
- */
-
- /**
- * Unknown operation.
- */
- final short UNKNOWN = -99;
-
- /**
- * Operation that moves to the beginning of the buffer.
- */
- final short MOVE_TO_BEG = -1;
-
- /**
- * Operation that moves to the end of the buffer.
- */
- final short MOVE_TO_END = -3;
-
- /**
- * Operation that moved to the previous character in the buffer.
- */
- final short PREV_CHAR = -4;
-
- /**
- * Operation that issues a newline.
- */
- final short NEWLINE = -6;
-
- /**
- * Operation that deletes the buffer from the current character to the end.
- */
- final short KILL_LINE = -7;
-
- /**
- * Operation that clears the screen.
- */
- final short CLEAR_SCREEN = -8;
-
- /**
- * Operation that sets the buffer to the next history item.
- */
- final short NEXT_HISTORY = -9;
-
- /**
- * Operation that sets the buffer to the previous history item.
- */
- final short PREV_HISTORY = -11;
-
- /**
- * Operation that redisplays the current buffer.
- */
- final short REDISPLAY = -13;
-
- /**
- * Operation that deletes the buffer from the cursor to the beginning.
- */
- final short KILL_LINE_PREV = -15;
-
- /**
- * Operation that deletes the previous word in the buffer.
- */
- final short DELETE_PREV_WORD = -16;
-
- /**
- * Operation that moves to the next character in the buffer.
- */
- final short NEXT_CHAR = -19;
-
- /**
- * Operation that moves to the previous character in the buffer.
- */
- final short REPEAT_PREV_CHAR = -20;
-
- /**
- * Operation that searches backwards in the command history.
- */
- final short SEARCH_PREV = -21;
-
- /**
- * Operation that repeats the character.
- */
- final short REPEAT_NEXT_CHAR = -24;
-
- /**
- * Operation that searches forward in the command history.
- */
- final short SEARCH_NEXT = -25;
-
- /**
- * Operation that moved to the previous whitespace.
- */
- final short PREV_SPACE_WORD = -27;
-
- /**
- * Operation that moved to the end of the current word.
- */
- final short TO_END_WORD = -29;
-
- /**
- * Operation that
- */
- final short REPEAT_SEARCH_PREV = -34;
-
- /**
- * Operation that
- */
- final short PASTE_PREV = -36;
-
- /**
- * Operation that
- */
- final short REPLACE_MODE = -37;
-
- /**
- * Operation that
- */
- final short SUBSTITUTE_LINE = -38;
-
- /**
- * Operation that
- */
- final short TO_PREV_CHAR = -39;
-
- /**
- * Operation that
- */
- final short NEXT_SPACE_WORD = -40;
-
- /**
- * Operation that
- */
- final short DELETE_PREV_CHAR = -41;
-
- /**
- * Operation that
- */
- final short ADD = -42;
-
- /**
- * Operation that
- */
- final short PREV_WORD = -43;
-
- /**
- * Operation that
- */
- final short CHANGE_META = -44;
-
- /**
- * Operation that
- */
- final short DELETE_META = -45;
-
- /**
- * Operation that
- */
- final short END_WORD = -46;
-
- /**
- * Operation that toggles insert/overtype
- */
- final short INSERT = -48;
-
- /**
- * Operation that
- */
- final short REPEAT_SEARCH_NEXT = -49;
-
- /**
- * Operation that
- */
- final short PASTE_NEXT = -50;
-
- /**
- * Operation that
- */
- final short REPLACE_CHAR = -51;
-
- /**
- * Operation that
- */
- final short SUBSTITUTE_CHAR = -52;
-
- /**
- * Operation that
- */
- final short TO_NEXT_CHAR = -53;
-
- /**
- * Operation that undoes the previous operation.
- */
- final short UNDO = -54;
-
- /**
- * Operation that moved to the next word.
- */
- final short NEXT_WORD = -55;
-
- /**
- * Operation that deletes the previous character.
- */
- final short DELETE_NEXT_CHAR = -56;
-
- /**
- * Operation that toggles between uppercase and lowercase.
- */
- final short CHANGE_CASE = -57;
-
- /**
- * Operation that performs completion operation on the current word.
- */
- final short COMPLETE = -58;
-
- /**
- * Operation that exits the command prompt.
- */
- final short EXIT = -59;
-
- /**
- * Operation that pastes the contents of the clipboard into the line
- */
- final short PASTE = -60;
-
- /**
- * Operation that moves the current History to the beginning.
- */
- final static short START_OF_HISTORY = -61;
-
- /**
- * Operation that moves the current History to the end.
- */
- final static short END_OF_HISTORY = -62;
-
- /**
- * Operation that clears whatever text is on the current line.
- */
- final static short CLEAR_LINE = -63;
-
-}
diff --git a/src/jline/src/main/java/jline/ConsoleReader.java b/src/jline/src/main/java/jline/ConsoleReader.java
deleted file mode 100644
index 66655cce73..0000000000
--- a/src/jline/src/main/java/jline/ConsoleReader.java
+++ /dev/null
@@ -1,1625 +0,0 @@
-/*
- * 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.awt.*;
-import java.awt.datatransfer.*;
-import java.awt.event.ActionListener;
-
-import java.io.*;
-import java.util.*;
-import java.util.List;
-
-/**
- * A reader for console applications. It supports custom tab-completion,
- * saveable command history, and command line editing. On some platforms,
- * platform-specific commands will need to be issued before the reader will
- * function properly. See {@link Terminal#initializeTerminal} for convenience
- * methods for issuing platform-specific setup commands.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- */
-public class ConsoleReader implements ConsoleOperations {
-
- final static int TAB_WIDTH = 4;
-
- String prompt;
-
- private boolean useHistory = true;
-
- private boolean usePagination = false;
-
- public static final String CR = System.getProperty("line.separator");
-
- private static ResourceBundle loc = ResourceBundle
- .getBundle(CandidateListCompletionHandler.class.getName());
-
- /**
- * Map that contains the operation name to keymay operation mapping.
- */
- public static SortedMap<String, Short> KEYMAP_NAMES;
-
- static {
- Map<String, Short> names = new TreeMap<String, Short>();
-
- names.put("MOVE_TO_BEG", new Short(MOVE_TO_BEG));
- names.put("MOVE_TO_END", new Short(MOVE_TO_END));
- names.put("PREV_CHAR", new Short(PREV_CHAR));
- names.put("NEWLINE", new Short(NEWLINE));
- names.put("KILL_LINE", new Short(KILL_LINE));
- names.put("PASTE", new Short(PASTE));
- names.put("CLEAR_SCREEN", new Short(CLEAR_SCREEN));
- names.put("NEXT_HISTORY", new Short(NEXT_HISTORY));
- names.put("PREV_HISTORY", new Short(PREV_HISTORY));
- names.put("START_OF_HISTORY", new Short(START_OF_HISTORY));
- names.put("END_OF_HISTORY", new Short(END_OF_HISTORY));
- names.put("REDISPLAY", new Short(REDISPLAY));
- names.put("KILL_LINE_PREV", new Short(KILL_LINE_PREV));
- names.put("DELETE_PREV_WORD", new Short(DELETE_PREV_WORD));
- names.put("NEXT_CHAR", new Short(NEXT_CHAR));
- names.put("REPEAT_PREV_CHAR", new Short(REPEAT_PREV_CHAR));
- names.put("SEARCH_PREV", new Short(SEARCH_PREV));
- names.put("REPEAT_NEXT_CHAR", new Short(REPEAT_NEXT_CHAR));
- names.put("SEARCH_NEXT", new Short(SEARCH_NEXT));
- names.put("PREV_SPACE_WORD", new Short(PREV_SPACE_WORD));
- names.put("TO_END_WORD", new Short(TO_END_WORD));
- names.put("REPEAT_SEARCH_PREV", new Short(REPEAT_SEARCH_PREV));
- names.put("PASTE_PREV", new Short(PASTE_PREV));
- names.put("REPLACE_MODE", new Short(REPLACE_MODE));
- names.put("SUBSTITUTE_LINE", new Short(SUBSTITUTE_LINE));
- names.put("TO_PREV_CHAR", new Short(TO_PREV_CHAR));
- names.put("NEXT_SPACE_WORD", new Short(NEXT_SPACE_WORD));
- names.put("DELETE_PREV_CHAR", new Short(DELETE_PREV_CHAR));
- names.put("ADD", new Short(ADD));
- names.put("PREV_WORD", new Short(PREV_WORD));
- names.put("CHANGE_META", new Short(CHANGE_META));
- names.put("DELETE_META", new Short(DELETE_META));
- names.put("END_WORD", new Short(END_WORD));
- names.put("NEXT_CHAR", new Short(NEXT_CHAR));
- names.put("INSERT", new Short(INSERT));
- names.put("REPEAT_SEARCH_NEXT", new Short(REPEAT_SEARCH_NEXT));
- names.put("PASTE_NEXT", new Short(PASTE_NEXT));
- names.put("REPLACE_CHAR", new Short(REPLACE_CHAR));
- names.put("SUBSTITUTE_CHAR", new Short(SUBSTITUTE_CHAR));
- names.put("TO_NEXT_CHAR", new Short(TO_NEXT_CHAR));
- names.put("UNDO", new Short(UNDO));
- names.put("NEXT_WORD", new Short(NEXT_WORD));
- names.put("DELETE_NEXT_CHAR", new Short(DELETE_NEXT_CHAR));
- names.put("CHANGE_CASE", new Short(CHANGE_CASE));
- names.put("COMPLETE", new Short(COMPLETE));
- names.put("EXIT", new Short(EXIT));
- names.put("CLEAR_LINE", new Short(CLEAR_LINE));
-
- KEYMAP_NAMES = new TreeMap<String, Short>(Collections.unmodifiableMap(names));
- }
-
- /**
- * The map for logical operations.
- */
- private final short[] keybindings;
-
- /**
- * If true, issue an audible keyboard bell when appropriate.
- */
- private boolean bellEnabled = true;
-
- /**
- * The current character mask.
- */
- private Character mask = null;
-
- /**
- * The null mask.
- */
- private static final Character NULL_MASK = new Character((char) 0);
-
- /**
- * The number of tab-completion candidates above which a warning will be
- * prompted before showing all the candidates.
- */
- private int autoprintThreshhold = Integer.getInteger(
- "jline.completion.threshold", 100).intValue(); // same default as
-
- // bash
-
- /**
- * The Terminal to use.
- */
- private final Terminal terminal;
-
- private CompletionHandler completionHandler = new CandidateListCompletionHandler();
-
- InputStream in;
-
- final Writer out;
-
- final CursorBuffer buf = new CursorBuffer();
-
- static PrintWriter debugger;
-
- History history = new History();
-
- final List<Completor> completors = new LinkedList<Completor>();
-
- private Character echoCharacter = null;
-
- private Map<Character, ActionListener> triggeredActions = new HashMap<Character, ActionListener>();
-
-
- /**
- * Adding a triggered Action allows to give another curse of action
- * if a character passed the preprocessing.
- *
- * Say you want to close the application if the user enter q.
- * addTriggerAction('q', new ActionListener(){ System.exit(0); });
- * would do the trick.
- *
- * @param c
- * @param listener
- */
- public void addTriggeredAction(char c, ActionListener listener){
- triggeredActions.put(new Character(c), listener);
- }
-
- /**
- * Create a new reader using {@link FileDescriptor#in} for input and
- * {@link System#out} for output. {@link FileDescriptor#in} is used because
- * it has a better chance of being unbuffered.
- */
- public ConsoleReader() throws IOException {
- this(new FileInputStream(FileDescriptor.in),
- new PrintWriter(
- new OutputStreamWriter(System.out,
- System.getProperty("jline.WindowsTerminal.output.encoding",System.getProperty("file.encoding")))));
- }
-
- /**
- * Create a new reader using the specified {@link InputStream} for input and
- * the specific writer for output, using the default keybindings resource.
- */
- public ConsoleReader(final InputStream in, final Writer out)
- throws IOException {
- this(in, out, null);
- }
-
- public ConsoleReader(final InputStream in, final Writer out,
- final InputStream bindings) throws IOException {
- this(in, out, bindings, Terminal.getTerminal());
- }
-
- /**
- * Create a new reader.
- *
- * @param in
- * the input
- * @param out
- * the output
- * @param bindings
- * the key bindings to use
- * @param term
- * the terminal to use
- */
- public ConsoleReader(InputStream in, Writer out, InputStream bindings,
- Terminal term) throws IOException {
- this.terminal = term;
- setInput(in);
- this.out = out;
- if (bindings == null) {
- try {
- String defaultBindingFile =
- new File(System.getProperty("user.home"),
- ".jlinebindings.properties").getAbsolutePath();
- String bindingFile = System.getProperty("jline.keybindings", defaultBindingFile);
-
- if (new File(bindingFile).isFile()) {
- bindings = new FileInputStream(new File(bindingFile));
- }
- } catch (Exception e) {
- // swallow exceptions with option debugging
- if (debugger != null) {
- e.printStackTrace(debugger);
- }
- }
- }
-
- if (bindings == null) {
- bindings = terminal.getDefaultBindings();
- }
-
- this.keybindings = new short[Character.MAX_VALUE * 2];
-
- Arrays.fill(this.keybindings, UNKNOWN);
-
- /**
- * Loads the key bindings. Bindings file is in the format:
- *
- * keycode: operation name
- */
- if (bindings != null) {
- Properties p = new Properties();
- p.load(bindings);
- bindings.close();
-
- for (Iterator i = p.keySet().iterator(); i.hasNext();) {
- String val = (String) i.next();
-
- try {
- Short code = new Short(val);
- String op = (String) p.getProperty(val);
-
- Short opval = (Short) KEYMAP_NAMES.get(op);
-
- if (opval != null) {
- keybindings[code.shortValue()] = opval.shortValue();
- }
- } catch (NumberFormatException nfe) {
- consumeException(nfe);
- }
- }
-
- // hardwired arrow key bindings
- // keybindings[VK_UP] = PREV_HISTORY;
- // keybindings[VK_DOWN] = NEXT_HISTORY;
- // keybindings[VK_LEFT] = PREV_CHAR;
- // keybindings[VK_RIGHT] = NEXT_CHAR;
- }
- }
-
- public Terminal getTerminal() {
- return this.terminal;
- }
-
- /**
- * Set the stream for debugging. Development use only.
- */
- public void setDebug(final PrintWriter debugger) {
- ConsoleReader.debugger = debugger;
- }
-
- /**
- * Set the stream to be used for console input.
- */
- public void setInput(final InputStream in) {
- this.in = in;
- }
-
- /**
- * Returns the stream used for console input.
- */
- public InputStream getInput() {
- return this.in;
- }
-
- /**
- * Read the next line and return the contents of the buffer.
- */
- public String readLine() throws IOException {
- return readLine((String) null);
- }
-
- /**
- * Read the next line with the specified character mask. If null, then
- * characters will be echoed. If 0, then no characters will be echoed.
- */
- public String readLine(final Character mask) throws IOException {
- return readLine(null, mask);
- }
-
- /**
- * @param bellEnabled
- * if true, enable audible keyboard bells if an alert is
- * required.
- */
- public void setBellEnabled(final boolean bellEnabled) {
- this.bellEnabled = bellEnabled;
- }
-
- /**
- * @return true is audible keyboard bell is enabled.
- */
- public boolean getBellEnabled() {
- return this.bellEnabled;
- }
-
- /**
- * Query the terminal to find the current width;
- *
- * @see Terminal#getTerminalWidth
- * @return the width of the current terminal.
- */
- public int getTermwidth() {
- return Terminal.setupTerminal().getTerminalWidth();
- }
-
- /**
- * Query the terminal to find the current width;
- *
- * @see Terminal#getTerminalHeight
- *
- * @return the height of the current terminal.
- */
- public int getTermheight() {
- return Terminal.setupTerminal().getTerminalHeight();
- }
-
- /**
- * @param autoprintThreshhold
- * the number of candidates to print without issuing a warning.
- */
- public void setAutoprintThreshhold(final int autoprintThreshhold) {
- this.autoprintThreshhold = autoprintThreshhold;
- }
-
- /**
- * @return the number of candidates to print without issing a warning.
- */
- public int getAutoprintThreshhold() {
- return this.autoprintThreshhold;
- }
-
- int getKeyForAction(short logicalAction) {
- for (int i = 0; i < keybindings.length; i++) {
- if (keybindings[i] == logicalAction) {
- return i;
- }
- }
-
- return -1;
- }
-
- /**
- * Clear the echoed characters for the specified character code.
- */
- int clearEcho(int c) throws IOException {
- // if the terminal is not echoing, then just return...
- if (!terminal.getEcho()) {
- return 0;
- }
-
- // otherwise, clear
- int num = countEchoCharacters((char) c);
- back(num);
- drawBuffer(num);
-
- return num;
- }
-
- int countEchoCharacters(char c) {
- // tabs as special: we need to determine the number of spaces
- // to cancel based on what out current cursor position is
- if (c == 9) {
- int tabstop = 8; // will this ever be different?
- int position = getCursorPosition();
-
- return tabstop - (position % tabstop);
- }
-
- return getPrintableCharacters(c).length();
- }
-
- /**
- * Return the number of characters that will be printed when the specified
- * character is echoed to the screen. Adapted from cat by Torbjorn Granlund,
- * as repeated in stty by David MacKenzie.
- */
- StringBuffer getPrintableCharacters(char ch) {
- StringBuffer sbuff = new StringBuffer();
-
- if (ch >= 32) {
- if (ch < 127) {
- sbuff.append(ch);
- } else if (ch == 127) {
- sbuff.append('^');
- sbuff.append('?');
- } else {
- sbuff.append('M');
- sbuff.append('-');
-
- if (ch >= (128 + 32)) {
- if (ch < (128 + 127)) {
- sbuff.append((char) (ch - 128));
- } else {
- sbuff.append('^');
- sbuff.append('?');
- }
- } else {
- sbuff.append('^');
- sbuff.append((char) (ch - 128 + 64));
- }
- }
- } else {
- sbuff.append('^');
- sbuff.append((char) (ch + 64));
- }
-
- return sbuff;
- }
-
- int getCursorPosition() {
- // FIXME: does not handle anything but a line with a prompt
- // absolute position
- return ((prompt == null) ? 0 : prompt.length()) + buf.cursor;
- }
-
- public String readLine(final String prompt) throws IOException {
- return readLine(prompt, null);
- }
-
- /**
- * The default prompt that will be issued.
- */
- public void setDefaultPrompt(String prompt) {
- this.prompt = prompt;
- }
-
- /**
- * The default prompt that will be issued.
- */
- public String getDefaultPrompt() {
- return prompt;
- }
-
- /**
- * Read a line from the <i>in</i> {@link InputStream}, and return the line
- * (without any trailing newlines).
- *
- * @param prompt
- * the prompt to issue to the console, may be null.
- * @return a line that is read from the terminal, or null if there was null
- * input (e.g., <i>CTRL-D</i> was pressed).
- */
- public String readLine(final String prompt, final Character mask)
- throws IOException {
- this.mask = mask;
- if (prompt != null)
- this.prompt = prompt;
-
- try {
- terminal.beforeReadLine(this, this.prompt, mask);
-
- if ((this.prompt != null) && (this.prompt.length() > 0)) {
- out.write(this.prompt);
- out.flush();
- }
-
- // if the terminal is unsupported, just use plain-java reading
- if (!terminal.isSupported()) {
- return readLine(in);
- }
-
- while (true) {
- int[] next = readBinding();
-
- if (next == null) {
- return null;
- }
-
- int c = next[0];
- int code = next[1];
-
- if (c == -1) {
- return null;
- }
-
- boolean success = true;
-
- switch (code) {
- case EXIT: // ctrl-d
-
- if (buf.buffer.length() == 0) {
- return null;
- }
- break;
-
- case COMPLETE: // tab
- success = complete();
- break;
-
- case MOVE_TO_BEG:
- success = setCursorPosition(0);
- break;
-
- case KILL_LINE: // CTRL-K
- success = killLine();
- break;
-
- case CLEAR_SCREEN: // CTRL-L
- success = clearScreen();
- break;
-
- case KILL_LINE_PREV: // CTRL-U
- success = resetLine();
- break;
-
- case NEWLINE: // enter
- moveToEnd();
- printNewline(); // output newline
- return finishBuffer();
-
- case DELETE_PREV_CHAR: // backspace
- success = backspace();
- break;
-
- case DELETE_NEXT_CHAR: // delete
- success = deleteCurrentCharacter();
- break;
-
- case MOVE_TO_END:
- success = moveToEnd();
- break;
-
- case PREV_CHAR:
- success = moveCursor(-1) != 0;
- break;
-
- case NEXT_CHAR:
- success = moveCursor(1) != 0;
- break;
-
- case NEXT_HISTORY:
- success = moveHistory(true);
- break;
-
- case PREV_HISTORY:
- success = moveHistory(false);
- break;
-
- case REDISPLAY:
- break;
-
- case PASTE:
- success = paste();
- break;
-
- case DELETE_PREV_WORD:
- success = deletePreviousWord();
- break;
-
- case PREV_WORD:
- success = previousWord();
- break;
-
- case NEXT_WORD:
- success = nextWord();
- break;
-
- case START_OF_HISTORY:
- success = history.moveToFirstEntry();
- if (success)
- setBuffer(history.current());
- break;
-
- case END_OF_HISTORY:
- success = history.moveToLastEntry();
- if (success)
- setBuffer(history.current());
- break;
-
- case CLEAR_LINE:
- moveInternal(-(buf.buffer.length()));
- killLine();
- break;
-
- case INSERT:
- buf.setOvertyping(!buf.isOvertyping());
- break;
-
- case UNKNOWN:
- default:
- if (c != 0) { // ignore null chars
- ActionListener action = (ActionListener) triggeredActions.get(new Character((char)c));
- if (action != null)
- action.actionPerformed(null);
- else
- putChar(c, true);
- } else
- success = false;
- }
-
- if (!(success)) {
- beep();
- }
-
- flushConsole();
- }
- } finally {
- terminal.afterReadLine(this, this.prompt, mask);
- }
- }
-
- private String readLine(InputStream in) throws IOException {
- StringBuffer buf = new StringBuffer();
-
- while (true) {
- int i = in.read();
-
- if ((i == -1) || (i == '\n') || (i == '\r')) {
- return buf.toString();
- }
-
- buf.append((char) i);
- }
-
- // return new BufferedReader (new InputStreamReader (in)).readLine ();
- }
-
- /**
- * Reads the console input and returns an array of the form [raw, key
- * binding].
- */
- private int[] readBinding() throws IOException {
- int c = readVirtualKey();
-
- if (c == -1) {
- return null;
- }
-
- // extract the appropriate key binding
- short code = keybindings[c];
-
- if (debugger != null) {
- debug(" translated: " + (int) c + ": " + code);
- }
-
- return new int[] { c, code };
- }
-
- /**
- * Move up or down the history tree.
- */
- private final boolean moveHistory(final boolean next) throws IOException {
- if (next && !history.next()) {
- return false;
- } else if (!next && !history.previous()) {
- return false;
- }
-
- setBuffer(history.current());
-
- return true;
- }
-
- /**
- * Paste the contents of the clipboard into the console buffer
- *
- * @return true if clipboard contents pasted
- */
- public boolean paste() throws IOException {
- Clipboard clipboard;
- try { // May throw ugly exception on system without X
- clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
- } catch (Exception e) {
- return false;
- }
-
- if (clipboard == null) {
- return false;
- }
-
- Transferable transferable = clipboard.getContents(null);
-
- if (transferable == null) {
- return false;
- }
-
- try {
- Object content = transferable
- .getTransferData(DataFlavor.plainTextFlavor);
-
- /*
- * This fix was suggested in bug #1060649 at
- * http://sourceforge.net/tracker/index.php?func=detail&aid=1060649&group_id=64033&atid=506056
- * to get around the deprecated DataFlavor.plainTextFlavor, but it
- * raises a UnsupportedFlavorException on Mac OS X
- */
- if (content == null) {
- try {
- content = new DataFlavor().getReaderForText(transferable);
- } catch (Exception e) {
- }
- }
-
- if (content == null) {
- return false;
- }
-
- String value;
-
- if (content instanceof Reader) {
- // TODO: we might want instead connect to the input stream
- // so we can interpret individual lines
- value = "";
-
- String line = null;
-
- for (BufferedReader read = new BufferedReader((Reader) content); (line = read
- .readLine()) != null;) {
- if (value.length() > 0) {
- value += "\n";
- }
-
- value += line;
- }
- } else {
- value = content.toString();
- }
-
- if (value == null) {
- return true;
- }
-
- putString(value);
-
- return true;
- } catch (UnsupportedFlavorException ufe) {
- if (debugger != null)
- debug(ufe + "");
-
- return false;
- }
- }
-
- /**
- * Kill the buffer ahead of the current cursor position.
- *
- * @return true if successful
- */
- public boolean killLine() throws IOException {
- int cp = buf.cursor;
- int len = buf.buffer.length();
-
- if (cp >= len) {
- return false;
- }
-
- int num = buf.buffer.length() - cp;
- clearAhead(num);
-
- for (int i = 0; i < num; i++) {
- buf.buffer.deleteCharAt(len - i - 1);
- }
-
- return true;
- }
-
- /**
- * Clear the screen by issuing the ANSI "clear screen" code.
- */
- public boolean clearScreen() throws IOException {
- if (!terminal.isANSISupported()) {
- return false;
- }
-
- // send the ANSI code to clear the screen
- printString(((char) 27) + "[2J");
- flushConsole();
-
- // then send the ANSI code to go to position 1,1
- printString(((char) 27) + "[1;1H");
- flushConsole();
-
- redrawLine();
-
- return true;
- }
-
- /**
- * Use the completors to modify the buffer with the appropriate completions.
- *
- * @return true if successful
- */
- private final boolean complete() throws IOException {
- // debug ("tab for (" + buf + ")");
- if (completors.size() == 0) {
- return false;
- }
-
- List<String> candidates = new LinkedList<String>();
- String bufstr = buf.buffer.toString();
- int cursor = buf.cursor;
-
- int position = -1;
-
- for (Iterator i = completors.iterator(); i.hasNext();) {
- Completor comp = (Completor) i.next();
-
- if ((position = comp.complete(bufstr, cursor, candidates)) != -1) {
- break;
- }
- }
-
- // no candidates? Fail.
- if (candidates.size() == 0) {
- return false;
- }
-
- return completionHandler.complete(this, candidates, position);
- }
-
- public CursorBuffer getCursorBuffer() {
- return buf;
- }
-
- /**
- * Output the specified {@link Collection} in proper columns.
- *
- * @param stuff
- * the stuff to print
- */
- public void printColumns(final Collection stuff) throws IOException {
- if ((stuff == null) || (stuff.size() == 0)) {
- return;
- }
-
- int width = getTermwidth();
- int maxwidth = 0;
-
- for (Iterator i = stuff.iterator(); i.hasNext(); maxwidth = Math.max(
- maxwidth, i.next().toString().length())) {
- ;
- }
-
- StringBuffer line = new StringBuffer();
-
- int showLines;
-
- if (usePagination)
- showLines = getTermheight() - 1; // page limit
- else
- showLines = Integer.MAX_VALUE;
-
- for (Iterator i = stuff.iterator(); i.hasNext();) {
- String cur = (String) i.next();
-
- if ((line.length() + maxwidth) > width) {
- printString(line.toString().trim());
- printNewline();
- line.setLength(0);
- if (--showLines == 0) { // Overflow
- printString(loc.getString("display-more"));
- flushConsole();
- int c = readVirtualKey();
- if (c == '\r' || c == '\n')
- showLines = 1; // one step forward
- else if (c != 'q')
- showLines = getTermheight() - 1; // page forward
-
- back(loc.getString("display-more").length());
- if (c == 'q')
- break; // cancel
- }
- }
-
- pad(cur, maxwidth + 3, line);
- }
-
- if (line.length() > 0) {
- printString(line.toString().trim());
- printNewline();
- line.setLength(0);
- }
- }
-
- /**
- * Append <i>toPad</i> to the specified <i>appendTo</i>, as well as (<i>toPad.length () -
- * len</i>) spaces.
- *
- * @param toPad
- * the {@link String} to pad
- * @param len
- * the target length
- * @param appendTo
- * the {@link StringBuffer} to which to append the padded
- * {@link String}.
- */
- private final void pad(final String toPad, final int len,
- final StringBuffer appendTo) {
- appendTo.append(toPad);
-
- for (int i = 0; i < (len - toPad.length()); i++, appendTo.append(' ')) {
- ;
- }
- }
-
- /**
- * Add the specified {@link Completor} to the list of handlers for
- * tab-completion.
- *
- * @param completor
- * the {@link Completor} to add
- * @return true if it was successfully added
- */
- public boolean addCompletor(final Completor completor) {
- return completors.add(completor);
- }
-
- /**
- * Remove the specified {@link Completor} from the list of handlers for
- * tab-completion.
- *
- * @param completor
- * the {@link Completor} to remove
- * @return true if it was successfully removed
- */
- public boolean removeCompletor(final Completor completor) {
- return completors.remove(completor);
- }
-
- /**
- * Returns an unmodifiable list of all the completors.
- */
- public Collection<Completor> getCompletors() {
- return Collections.unmodifiableList(completors);
- }
-
- /**
- * Erase the current line.
- *
- * @return false if we failed (e.g., the buffer was empty)
- */
- final boolean resetLine() throws IOException {
- if (buf.cursor == 0) {
- return false;
- }
-
- backspaceAll();
-
- return true;
- }
-
- /**
- * Move the cursor position to the specified absolute index.
- */
- public final boolean setCursorPosition(final int position)
- throws IOException {
- return moveCursor(position - buf.cursor) != 0;
- }
-
- /**
- * Set the current buffer's content to the specified {@link String}. The
- * visual console will be modified to show the current buffer.
- *
- * @param buffer
- * the new contents of the buffer.
- */
- private final void setBuffer(final String buffer) throws IOException {
- // don't bother modifying it if it is unchanged
- if (buffer.equals(buf.buffer.toString())) {
- return;
- }
-
- // obtain the difference between the current buffer and the new one
- int sameIndex = 0;
-
- for (int i = 0, l1 = buffer.length(), l2 = buf.buffer.length(); (i < l1)
- && (i < l2); i++) {
- if (buffer.charAt(i) == buf.buffer.charAt(i)) {
- sameIndex++;
- } else {
- break;
- }
- }
-
- int diff = buf.buffer.length() - sameIndex;
-
- backspace(diff); // go back for the differences
- killLine(); // clear to the end of the line
- buf.buffer.setLength(sameIndex); // the new length
- putString(buffer.substring(sameIndex)); // append the differences
- }
-
- /**
- * Clear the line and redraw it.
- */
- public final void redrawLine() throws IOException {
- printCharacter(RESET_LINE);
- flushConsole();
- drawLine();
- }
-
- /**
- * Output put the prompt + the current buffer
- */
- public final void drawLine() throws IOException {
- if (prompt != null) {
- printString(prompt);
- }
-
- printString(buf.buffer.toString());
-
- if (buf.length() != buf.cursor) // not at end of line
- back(buf.length() - buf.cursor); // sync
- }
-
- /**
- * Output a platform-dependant newline.
- */
- public final void printNewline() throws IOException {
- printString(CR);
- flushConsole();
- }
-
- /**
- * Clear the buffer and add its contents to the history.
- *
- * @return the former contents of the buffer.
- */
- final String finishBuffer() {
- String str = buf.buffer.toString();
-
- // we only add it to the history if the buffer is not empty
- // and if mask is null, since having a mask typically means
- // the string was a password. We clear the mask after this call
- if (str.length() > 0) {
- if (mask == null && useHistory) {
- history.addToHistory(str);
- } else {
- mask = null;
- }
- }
-
- history.moveToEnd();
-
- buf.buffer.setLength(0);
- buf.cursor = 0;
-
- return str;
- }
-
- /**
- * Write out the specified string to the buffer and the output stream.
- */
- public final void putString(final String str) throws IOException {
- buf.write(str);
- printString(str);
- drawBuffer();
- }
-
- /**
- * Output the specified string to the output stream (but not the buffer).
- */
- public final void printString(final String str) throws IOException {
- printCharacters(str.toCharArray());
- }
-
- /**
- * Output the specified character, both to the buffer and the output stream.
- */
- private final void putChar(final int c, final boolean print)
- throws IOException {
- buf.write((char) c);
-
- if (print) {
- // no masking...
- if (mask == null) {
- printCharacter(c);
- }
- // null mask: don't print anything...
- else if (mask.charValue() == 0) {
- ;
- }
- // otherwise print the mask...
- else {
- printCharacter(mask.charValue());
- }
-
- drawBuffer();
- }
- }
-
- /**
- * Redraw the rest of the buffer from the cursor onwards. This is necessary
- * for inserting text into the buffer.
- *
- * @param clear
- * the number of characters to clear after the end of the buffer
- */
- private final void drawBuffer(final int clear) throws IOException {
- // debug ("drawBuffer: " + clear);
- char[] chars = buf.buffer.substring(buf.cursor).toCharArray();
- if (mask != null)
- Arrays.fill(chars, mask.charValue());
-
- printCharacters(chars);
-
- clearAhead(clear);
- back(chars.length);
- flushConsole();
- }
-
- /**
- * Redraw the rest of the buffer from the cursor onwards. This is necessary
- * for inserting text into the buffer.
- */
- private final void drawBuffer() throws IOException {
- drawBuffer(0);
- }
-
- /**
- * Clear ahead the specified number of characters without moving the cursor.
- */
- private final void clearAhead(final int num) throws IOException {
- if (num == 0) {
- return;
- }
-
- // debug ("clearAhead: " + num);
-
- // print blank extra characters
- printCharacters(' ', num);
-
- // we need to flush here so a "clever" console
- // doesn't just ignore the redundancy of a space followed by
- // a backspace.
- flushConsole();
-
- // reset the visual cursor
- back(num);
-
- flushConsole();
- }
-
- /**
- * Move the visual cursor backwards without modifying the buffer cursor.
- */
- private final void back(final int num) throws IOException {
- printCharacters(BACKSPACE, num);
- flushConsole();
- }
-
- /**
- * Issue an audible keyboard bell, if {@link #getBellEnabled} return true.
- */
- public final void beep() throws IOException {
- if (!(getBellEnabled())) {
- return;
- }
-
- printCharacter(KEYBOARD_BELL);
- // need to flush so the console actually beeps
- flushConsole();
- }
-
- /**
- * Output the specified character to the output stream without manipulating
- * the current buffer.
- */
- private final void printCharacter(final int c) throws IOException {
- if (c == '\t') {
- char cbuf[] = new char[TAB_WIDTH];
- Arrays.fill(cbuf, ' ');
- out.write(cbuf);
- return;
- }
-
- out.write(c);
- }
-
- /**
- * Output the specified characters to the output stream without manipulating
- * the current buffer.
- */
- private final void printCharacters(final char[] c) throws IOException {
- int len = 0;
- for (int i = 0; i < c.length; i++)
- if (c[i] == '\t')
- len += TAB_WIDTH;
- else
- len++;
-
- char cbuf[];
- if (len == c.length)
- cbuf = c;
- else {
- cbuf = new char[len];
- int pos = 0;
- for (int i = 0; i < c.length; i++){
- if (c[i] == '\t') {
- Arrays.fill(cbuf, pos, pos + TAB_WIDTH, ' ');
- pos += TAB_WIDTH;
- } else {
- cbuf[pos] = c[i];
- pos++;
- }
- }
- }
-
- out.write(cbuf);
- }
-
- private final void printCharacters(final char c, final int num)
- throws IOException {
- if (num == 1) {
- printCharacter(c);
- } else {
- char[] chars = new char[num];
- Arrays.fill(chars, c);
- printCharacters(chars);
- }
- }
-
- /**
- * Flush the console output stream. This is important for printout out
- * single characters (like a backspace or keyboard) that we want the console
- * to handle immedately.
- */
- public final void flushConsole() throws IOException {
- out.flush();
- }
-
- private final int backspaceAll() throws IOException {
- return backspace(Integer.MAX_VALUE);
- }
-
- /**
- * Issue <em>num</em> backspaces.
- *
- * @return the number of characters backed up
- */
- private final int backspace(final int num) throws IOException {
- if (buf.cursor == 0) {
- return 0;
- }
-
- int count = 0;
-
- count = moveCursor(-1 * num) * -1;
- // debug ("Deleting from " + buf.cursor + " for " + count);
- buf.buffer.delete(buf.cursor, buf.cursor + count);
- drawBuffer(count);
-
- return count;
- }
-
- /**
- * Issue a backspace.
- *
- * @return true if successful
- */
- public final boolean backspace() throws IOException {
- return backspace(1) == 1;
- }
-
- private final boolean moveToEnd() throws IOException {
- if (moveCursor(1) == 0) {
- return false;
- }
-
- while (moveCursor(1) != 0) {
- ;
- }
-
- return true;
- }
-
- /**
- * Delete the character at the current position and redraw the remainder of
- * the buffer.
- */
- private final boolean deleteCurrentCharacter() throws IOException {
- boolean success = buf.buffer.length() > 0;
- if (!success) {
- return false;
- }
-
- if (buf.cursor == buf.buffer.length()) {
- return false;
- }
-
- buf.buffer.deleteCharAt(buf.cursor);
- drawBuffer(1);
- return true;
- }
-
- private final boolean previousWord() throws IOException {
- while (isDelimiter(buf.current()) && (moveCursor(-1) != 0)) {
- ;
- }
-
- while (!isDelimiter(buf.current()) && (moveCursor(-1) != 0)) {
- ;
- }
-
- return true;
- }
-
- private final boolean nextWord() throws IOException {
- while (isDelimiter(buf.current()) && (moveCursor(1) != 0)) {
- ;
- }
-
- while (!isDelimiter(buf.current()) && (moveCursor(1) != 0)) {
- ;
- }
-
- return true;
- }
-
- private final boolean deletePreviousWord() throws IOException {
- while (isDelimiter(buf.current()) && backspace()) {
- ;
- }
-
- while (!isDelimiter(buf.current()) && backspace()) {
- ;
- }
-
- return true;
- }
-
- /**
- * Move the cursor <i>where</i> characters.
- *
- * @param where
- * if less than 0, move abs(<i>where</i>) to the left,
- * otherwise move <i>where</i> to the right.
- *
- * @return the number of spaces we moved
- */
- public final int moveCursor(final int num) throws IOException {
- int where = num;
-
- if ((buf.cursor == 0) && (where < 0)) {
- return 0;
- }
-
- if ((buf.cursor == buf.buffer.length()) && (where > 0)) {
- return 0;
- }
-
- if ((buf.cursor + where) < 0) {
- where = -buf.cursor;
- } else if ((buf.cursor + where) > buf.buffer.length()) {
- where = buf.buffer.length() - buf.cursor;
- }
-
- moveInternal(where);
-
- return where;
- }
-
- /**
- * debug.
- *
- * @param str
- * the message to issue.
- */
- public static void debug(final String str) {
- if (debugger != null) {
- debugger.println(str);
- debugger.flush();
- }
- }
-
- /**
- * Move the cursor <i>where</i> characters, withough checking the current
- * buffer.
- *
- * @see #where
- *
- * @param where
- * the number of characters to move to the right or left.
- */
- private final void moveInternal(final int where) throws IOException {
- // debug ("move cursor " + where + " ("
- // + buf.cursor + " => " + (buf.cursor + where) + ")");
- buf.cursor += where;
-
- char c;
-
- if (where < 0) {
- int len = 0;
- for (int i = buf.cursor; i < buf.cursor - where; i++){
- if (buf.getBuffer().charAt(i) == '\t')
- len += TAB_WIDTH;
- else
- len++;
- }
-
- char cbuf[] = new char[len];
- Arrays.fill(cbuf, BACKSPACE);
- out.write(cbuf);
-
- return;
- } else if (buf.cursor == 0) {
- return;
- } else if (mask != null) {
- c = mask.charValue();
- } else {
- printCharacters(buf.buffer.substring(buf.cursor - where, buf.cursor).toCharArray());
- return;
- }
-
- // null character mask: don't output anything
- if (NULL_MASK.equals(mask)) {
- return;
- }
-
- printCharacters(c, Math.abs(where));
- }
-
- /**
- * Read a character from the console.
- *
- * @return the character, or -1 if an EOF is received.
- */
- public final int readVirtualKey() throws IOException {
- int c = terminal.readVirtualKey(in);
-
- if (debugger != null) {
- debug("keystroke: " + c + "");
- }
-
- // clear any echo characters
- clearEcho(c);
-
- return c;
- }
-
- public final int readCharacter(final char[] allowed) throws IOException {
- // if we restrict to a limited set and the current character
- // is not in the set, then try again.
- char c;
-
- Arrays.sort(allowed); // always need to sort before binarySearch
-
- while (Arrays.binarySearch(allowed, c = (char) readVirtualKey()) < 0)
- ;
-
- return c;
- }
-
-
- /**
- * Issue <em>num</em> deletes.
- *
- * @return the number of characters backed up
- */
- private final int delete (final int num)
- throws IOException
- {
- /* Commented out beacuse of DWA-2949:
- if (buf.cursor == 0)
- return 0;*/
-
- buf.buffer.delete (buf.cursor, buf.cursor + 1);
- drawBuffer (1);
-
- return 1;
- }
-
- public final boolean replace(int num, String replacement) {
- buf.buffer.replace(buf.cursor - num, buf.cursor, replacement);
- try {
- moveCursor(-num);
- drawBuffer(Math.max(0, num - replacement.length()));
- moveCursor(replacement.length());
- } catch (IOException e) {
- e.printStackTrace();
- return false;
- }
- return true;
- }
-
- /**
- * Issue a delete.
- *
- * @return true if successful
- */
- public final boolean delete ()
- throws IOException
- {
- return delete (1) == 1;
- }
-
-
- public void setHistory(final History history) {
- this.history = history;
- }
-
- public History getHistory() {
- return this.history;
- }
-
- public void setCompletionHandler(final CompletionHandler completionHandler) {
- this.completionHandler = completionHandler;
- }
-
- public CompletionHandler getCompletionHandler() {
- return this.completionHandler;
- }
-
- /**
- * <p>
- * Set the echo character. For example, to have "*" entered when a password
- * is typed:
- * </p>
- *
- * <pre>
- * myConsoleReader.setEchoCharacter(new Character('*'));
- * </pre>
- *
- * <p>
- * Setting the character to
- *
- * <pre>
- * null
- * </pre>
- *
- * will restore normal character echoing. Setting the character to
- *
- * <pre>
- * new Character(0)
- * </pre>
- *
- * will cause nothing to be echoed.
- * </p>
- *
- * @param echoCharacter
- * the character to echo to the console in place of the typed
- * character.
- */
- public void setEchoCharacter(final Character echoCharacter) {
- this.echoCharacter = echoCharacter;
- }
-
- /**
- * Returns the echo character.
- */
- public Character getEchoCharacter() {
- return this.echoCharacter;
- }
-
- /**
- * No-op for exceptions we want to silently consume.
- */
- private void consumeException(final Throwable e) {
- }
-
- /**
- * Checks to see if the specified character is a delimiter. We consider a
- * character a delimiter if it is anything but a letter or digit.
- *
- * @param c
- * the character to test
- * @return true if it is a delimiter
- */
- private boolean isDelimiter(char c) {
- return !Character.isLetterOrDigit(c);
- }
-
- /**
- * Whether or not to add new commands to the history buffer.
- */
- public void setUseHistory(boolean useHistory) {
- this.useHistory = useHistory;
- }
-
- /**
- * Whether or not to add new commands to the history buffer.
- */
- public boolean getUseHistory() {
- return useHistory;
- }
-
- /**
- * Whether to use pagination when the number of rows of candidates exceeds
- * the height of the temrinal.
- */
- public void setUsePagination(boolean usePagination) {
- this.usePagination = usePagination;
- }
-
- /**
- * Whether to use pagination when the number of rows of candidates exceeds
- * the height of the temrinal.
- */
- public boolean getUsePagination() {
- return this.usePagination;
- }
-
-}
diff --git a/src/jline/src/main/java/jline/ConsoleReaderInputStream.java b/src/jline/src/main/java/jline/ConsoleReaderInputStream.java
deleted file mode 100644
index d2a14d8e72..0000000000
--- a/src/jline/src/main/java/jline/ConsoleReaderInputStream.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * 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.*;
-
-/**
- * An {@link InputStream} implementation that wraps a {@link ConsoleReader}.
- * It is useful for setting up the {@link System#in} for a generic
- * console.
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- */
-public class ConsoleReaderInputStream extends SequenceInputStream {
- private static InputStream systemIn = System.in;
-
- public static void setIn() throws IOException {
- setIn(new ConsoleReader());
- }
-
- public static void setIn(final ConsoleReader reader) {
- System.setIn(new ConsoleReaderInputStream(reader));
- }
-
- /**
- * Restore the original {@link System#in} input stream.
- */
- public static void restoreIn() {
- System.setIn(systemIn);
- }
-
- public ConsoleReaderInputStream(final ConsoleReader reader) {
- super(new ConsoleEnumeration(reader));
- }
-
- private static class ConsoleEnumeration implements Enumeration<InputStream> {
- private final ConsoleReader reader;
- private ConsoleLineInputStream next = null;
- private ConsoleLineInputStream prev = null;
-
- public ConsoleEnumeration(final ConsoleReader reader) {
- this.reader = reader;
- }
-
- public InputStream nextElement() {
- if (next != null) {
- InputStream n = next;
- prev = next;
- next = null;
-
- return n;
- }
-
- return new ConsoleLineInputStream(reader);
- }
-
- public boolean hasMoreElements() {
- // the last line was null
- if ((prev != null) && (prev.wasNull == true)) {
- return false;
- }
-
- if (next == null) {
- next = (ConsoleLineInputStream) nextElement();
- }
-
- return next != null;
- }
- }
-
- private static class ConsoleLineInputStream extends InputStream {
- private final ConsoleReader reader;
- private String line = null;
- private int index = 0;
- private boolean eol = false;
- protected boolean wasNull = false;
-
- public ConsoleLineInputStream(final ConsoleReader reader) {
- this.reader = reader;
- }
-
- public int read() throws IOException {
- if (eol) {
- return -1;
- }
-
- if (line == null) {
- line = reader.readLine();
- }
-
- if (line == null) {
- wasNull = true;
- return -1;
- }
-
- if (index >= line.length()) {
- eol = true;
- return '\n'; // lines are ended with a newline
- }
-
- return line.charAt(index++);
- }
- }
-}
diff --git a/src/jline/src/main/java/jline/ConsoleRunner.java b/src/jline/src/main/java/jline/ConsoleRunner.java
deleted file mode 100644
index dac4b7c88a..0000000000
--- a/src/jline/src/main/java/jline/ConsoleRunner.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * 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 property = "jline.history";
-
- public static void main(final String[] args) throws Exception {
- String historyFileName = null;
-
- List<String> argList = new ArrayList<String>(Arrays.asList(args));
-
- if (argList.size() == 0) {
- usage();
-
- return;
- }
-
- historyFileName = System.getProperty(ConsoleRunner.property, 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 completors = System.getProperty
- (ConsoleRunner.class.getName() + ".completors", "");
- List<Completor> completorList = new ArrayList<Completor>();
-
- 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));
- }
-
- 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'] "
- + 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.");
- }
-}
diff --git a/src/jline/src/main/java/jline/FileNameCompletor.java b/src/jline/src/main/java/jline/FileNameCompletor.java
deleted file mode 100644
index d1d63735d1..0000000000
--- a/src/jline/src/main/java/jline/FileNameCompletor.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * 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.*;
-
-/**
- * A file name completor takes the buffer and issues a list of
- * potential completions.
- *
- * <p>
- * This completor tries to behave as similar as possible to
- * <i>bash</i>'s file name completion (using GNU readline)
- * with the following exceptions:
- *
- * <ul>
- * <li>Candidates that are directories will end with "/"</li>
- * <li>Wildcard regular expressions are not evaluated or replaced</li>
- * <li>The "~" character can be used to represent the user's home,
- * but it cannot complete to other users' homes, since java does
- * not provide any way of determining that easily</li>
- * </ul>
- *
- * <p>TODO</p>
- * <ul>
- * <li>Handle files with spaces in them</li>
- * <li>Have an option for file type color highlighting</li>
- * </ul>
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- */
-public class FileNameCompletor implements Completor {
- public int complete(final String buf, final int cursor,
- final List<String> candidates) {
- String buffer = (buf == null) ? "" : buf;
-
- String translated = buffer;
-
- // special character: ~ maps to the user's home directory
- if (translated.startsWith("~" + File.separator)) {
- translated = System.getProperty("user.home")
- + translated.substring(1);
- } else if (translated.startsWith("~")) {
- translated = new File(System.getProperty("user.home")).getParentFile()
- .getAbsolutePath();
- } else if (!(translated.startsWith(File.separator))) {
- translated = new File("").getAbsolutePath() + File.separator
- + translated;
- }
-
- File f = new File(translated);
-
- final File dir;
-
- if (translated.endsWith(File.separator)) {
- dir = f;
- } else {
- dir = f.getParentFile();
- }
-
- final File[] entries = (dir == null) ? new File[0] : dir.listFiles();
-
- try {
- return matchFiles(buffer, translated, entries, candidates);
- } finally {
- // we want to output a sorted list of files
- sortFileNames(candidates);
- }
- }
-
- protected void sortFileNames(final List<String> fileNames) {
- Collections.sort(fileNames);
- }
-
- /**
- * Match the specified <i>buffer</i> to the array of <i>entries</i>
- * and enter the matches into the list of <i>candidates</i>. This method
- * can be overridden in a subclass that wants to do more
- * sophisticated file name completion.
- *
- * @param buffer the untranslated buffer
- * @param translated the buffer with common characters replaced
- * @param entries the list of files to match
- * @param candidates the list of candidates to populate
- *
- * @return the offset of the match
- */
- public int matchFiles(String buffer, String translated, File[] entries,
- List<String> candidates) {
- if (entries == null) {
- return -1;
- }
-
- int matches = 0;
-
- // first pass: just count the matches
- for (int i = 0; i < entries.length; i++) {
- if (entries[i].getAbsolutePath().startsWith(translated)) {
- matches++;
- }
- }
-
- // green - executable
- // blue - directory
- // red - compressed
- // cyan - symlink
- for (int i = 0; i < entries.length; i++) {
- if (entries[i].getAbsolutePath().startsWith(translated)) {
- String name =
- entries[i].getName()
- + (((matches == 1) && entries[i].isDirectory())
- ? File.separator : " ");
-
- /*
- if (entries [i].isDirectory ())
- {
- name = new ANSIBuffer ().blue (name).toString ();
- }
- */
- candidates.add(name);
- }
- }
-
- final int index = buffer.lastIndexOf(File.separator);
-
- return index + File.separator.length();
- }
-}
diff --git a/src/jline/src/main/java/jline/History.java b/src/jline/src/main/java/jline/History.java
deleted file mode 100644
index 9e96f69146..0000000000
--- a/src/jline/src/main/java/jline/History.java
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * 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.*;
-
-/**
- * A command history buffer.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- */
-public class History {
- private List<String> history = new ArrayList<String>();
-
- private PrintWriter output = null;
-
- private int maxSize = 500;
-
- private int currentIndex = 0;
-
- /**
- * Construstor: initialize a blank history.
- */
- public History() {
- }
-
- /**
- * Construstor: initialize History object the the specified {@link File} for
- * storage.
- */
- public History(final File historyFile) throws IOException {
- setHistoryFile(historyFile);
- }
-
- public void setHistoryFile(final File historyFile) throws IOException {
- if (historyFile.isFile()) {
- load(new FileInputStream(historyFile));
- }
-
- setOutput(new PrintWriter(new FileWriter(historyFile), true));
- flushBuffer();
- }
-
- /**
- * Load the history buffer from the specified InputStream.
- */
- public void load(final InputStream in) throws IOException {
- load(new InputStreamReader(in));
- }
-
- /**
- * Load the history buffer from the specified Reader.
- */
- public void load(final Reader reader) throws IOException {
- BufferedReader breader = new BufferedReader(reader);
- List<String> lines = new ArrayList<String>();
- String line;
-
- while ((line = breader.readLine()) != null) {
- lines.add(line);
- }
-
- for (Iterator i = lines.iterator(); i.hasNext();) {
- addToHistory((String) i.next());
- }
- }
-
- public int size() {
- return history.size();
- }
-
- /**
- * Clear the history buffer
- */
- public void clear() {
- history.clear();
- currentIndex = 0;
- }
-
- /**
- * Add the specified buffer to the end of the history. The pointer is set to
- * the end of the history buffer.
- */
- public void addToHistory(final String buffer) {
- // don't append duplicates to the end of the buffer
- if ((history.size() != 0)
- && buffer.equals(history.get(history.size() - 1))) {
- return;
- }
-
- history.add(buffer);
-
- while (history.size() > getMaxSize()) {
- history.remove(0);
- }
-
- currentIndex = history.size();
-
- if (getOutput() != null) {
- getOutput().println(buffer);
- getOutput().flush();
- }
- }
-
- /**
- * Flush the entire history buffer to the output PrintWriter.
- */
- public void flushBuffer() throws IOException {
- if (getOutput() != null) {
- for (Iterator i = history.iterator(); i.hasNext(); getOutput()
- .println((String) i.next())) {
- ;
- }
-
- getOutput().flush();
- }
- }
-
- /**
- * This moves the history to the last entry. This entry is one position
- * before the moveToEnd() position.
- *
- * @return Returns false if there were no history entries or the history
- * index was already at the last entry.
- */
- public boolean moveToLastEntry() {
- int lastEntry = history.size() - 1;
- if (lastEntry >= 0 && lastEntry != currentIndex) {
- currentIndex = history.size() - 1;
- return true;
- }
-
- return false;
- }
-
- /**
- * Move to the end of the history buffer. This will be a blank entry, after
- * all of the other entries.
- */
- public void moveToEnd() {
- currentIndex = history.size();
- }
-
- /**
- * Set the maximum size that the history buffer will store.
- */
- public void setMaxSize(final int maxSize) {
- this.maxSize = maxSize;
- }
-
- /**
- * Get the maximum size that the history buffer will store.
- */
- public int getMaxSize() {
- return this.maxSize;
- }
-
- /**
- * The output to which all history elements will be written (or null of
- * history is not saved to a buffer).
- */
- public void setOutput(final PrintWriter output) {
- this.output = output;
- }
-
- /**
- * Returns the PrintWriter that is used to store history elements.
- */
- public PrintWriter getOutput() {
- return this.output;
- }
-
- /**
- * Returns the current history index.
- */
- public int getCurrentIndex() {
- return this.currentIndex;
- }
-
- /**
- * Return the content of the current buffer.
- */
- public String current() {
- if (currentIndex >= history.size()) {
- return "";
- }
-
- return (String) history.get(currentIndex);
- }
-
- /**
- * Move the pointer to the previous element in the buffer.
- *
- * @return true if we successfully went to the previous element
- */
- public boolean previous() {
- if (currentIndex <= 0) {
- return false;
- }
-
- currentIndex--;
-
- return true;
- }
-
- /**
- * Move the pointer to the next element in the buffer.
- *
- * @return true if we successfully went to the next element
- */
- public boolean next() {
- if (currentIndex >= history.size()) {
- return false;
- }
-
- currentIndex++;
-
- return true;
- }
-
- /**
- * Returns an immutable list of the history buffer.
- */
- public List<String> getHistoryList() {
- return Collections.unmodifiableList(history);
- }
-
- /**
- * Returns the standard {@link AbstractCollection#toString} representation
- * of the history list.
- */
- public String toString() {
- return history.toString();
- }
-
- /**
- * Moves the history index to the first entry.
- *
- * @return Return false if there are no entries in the history or if the
- * history is already at the beginning.
- */
- public boolean moveToFirstEntry() {
- if (history.size() > 0 && currentIndex != 0) {
- currentIndex = 0;
- return true;
- }
-
- return false;
- }
-}
diff --git a/src/jline/src/main/java/jline/MultiCompletor.java b/src/jline/src/main/java/jline/MultiCompletor.java
deleted file mode 100644
index 2d43a204cc..0000000000
--- a/src/jline/src/main/java/jline/MultiCompletor.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * 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.util.*;
-
-/**
- * <p>
- * A completor that contains multiple embedded completors. This differs
- * from the {@link ArgumentCompletor}, in that the nested completors
- * are dispatched individually, rather than delimited by arguments.
- * </p>
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- */
-public class MultiCompletor implements Completor {
- Completor[] completors = new Completor[0];
-
- /**
- * Construct a MultiCompletor with no embedded completors.
- */
- public MultiCompletor() {
- this(new Completor[0]);
- }
-
- /**
- * Construct a MultiCompletor with the specified list of
- * {@link Completor} instances.
- */
- public MultiCompletor(final List<Completor> completors) {
- this((Completor[]) completors.toArray(new Completor[completors.size()]));
- }
-
- /**
- * Construct a MultiCompletor with the specified
- * {@link Completor} instances.
- */
- public MultiCompletor(final Completor[] completors) {
- this.completors = completors;
- }
-
- public int complete(final String buffer, final int pos, final List<String> cand) {
- int[] positions = new int[completors.length];
- List<List<String>> copies = new ArrayList<List<String>>();
- for (int i = 0; i < completors.length; i++) {
- copies.add(null);
- }
-
- for (int i = 0; i < completors.length; i++) {
- // clone and save the candidate list
- copies.set(i, new LinkedList<String>(cand));
- positions[i] = completors[i].complete(buffer, pos, copies.get(i));
- }
-
- int maxposition = -1;
-
- for (int i = 0; i < positions.length; i++) {
- maxposition = Math.max(maxposition, positions[i]);
- }
-
- // now we have the max cursor value: build up all the
- // candidate lists that have the same cursor value
- for (int i = 0; i < copies.size(); i++) {
- if (positions[i] == maxposition) {
- cand.addAll(copies.get(i));
- }
- }
-
- return maxposition;
- }
-
- public void setCompletors(final Completor[] completors) {
- this.completors = completors;
- }
-
- public Completor[] getCompletors() {
- return this.completors;
- }
-}
diff --git a/src/jline/src/main/java/jline/NoInterruptUnixTerminal.java b/src/jline/src/main/java/jline/NoInterruptUnixTerminal.java
new file mode 100644
index 0000000000..b2cd22b5c7
--- /dev/null
+++ b/src/jline/src/main/java/jline/NoInterruptUnixTerminal.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2009 the original author(s).
+ *
+ * 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 jline;
+
+// Based on Apache Karaf impl
+
+/**
+ * Non-interruptable (via CTRL-C) {@link UnixTerminal}.
+ *
+ * @since 2.0
+ */
+public class NoInterruptUnixTerminal
+ extends UnixTerminal
+{
+ public NoInterruptUnixTerminal() throws Exception {
+ super();
+ }
+
+ @Override
+ public void init() throws Exception {
+ super.init();
+ getSettings().set("intr undef");
+ }
+
+ @Override
+ public void restore() throws Exception {
+ getSettings().set("intr ^C");
+ super.restore();
+ }
+}
diff --git a/src/jline/src/main/java/jline/NullCompletor.java b/src/jline/src/main/java/jline/NullCompletor.java
deleted file mode 100644
index aa6cdf744e..0000000000
--- a/src/jline/src/main/java/jline/NullCompletor.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * 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.util.*;
-
-/**
- * <p>
- * A completor that does nothing. Useful as the last item in an
- * {@link ArgumentCompletor}.
- * </p>
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- */
-public class NullCompletor implements Completor {
- /**
- * Returns -1 always, indicating that the the buffer is never
- * handled.
- */
- public int complete(final String buffer, int cursor, List candidates) {
- return -1;
- }
-}
diff --git a/src/jline/src/main/java/jline/SimpleCompletor.java b/src/jline/src/main/java/jline/SimpleCompletor.java
deleted file mode 100644
index 3581277409..0000000000
--- a/src/jline/src/main/java/jline/SimpleCompletor.java
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * 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 simple {@link Completor} implementation that handles a pre-defined
- * list of completion words.
- * </p>
- *
- * <p>
- * Example usage:
- * </p>
- * <pre>
- * myConsoleReader.addCompletor (new SimpleCompletor (new String [] { "now", "yesterday", "tomorrow" }));
- * </pre>
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- */
-public class SimpleCompletor implements Completor, Cloneable {
- /**
- * The list of candidates that will be completed.
- */
- SortedSet<String> candidates;
-
- /**
- * A delimiter to use to qualify completions.
- */
- String delimiter;
- final SimpleCompletorFilter filter;
-
- /**
- * Create a new SimpleCompletor with a single possible completion
- * values.
- */
- public SimpleCompletor(final String candidateString) {
- this(new String[] {
- candidateString
- });
- }
-
- /**
- * Create a new SimpleCompletor with a list of possible completion
- * values.
- */
- public SimpleCompletor(final String[] candidateStrings) {
- this(candidateStrings, null);
- }
-
- public SimpleCompletor(final String[] strings,
- final SimpleCompletorFilter filter) {
- this.filter = filter;
- setCandidateStrings(strings);
- }
-
- /**
- * Complete candidates using the contents of the specified Reader.
- */
- public SimpleCompletor(final Reader reader) throws IOException {
- this(getStrings(reader));
- }
-
- /**
- * Complete candidates using the whitespearated values in
- * read from the specified Reader.
- */
- public SimpleCompletor(final InputStream in) throws IOException {
- this(getStrings(new InputStreamReader(in)));
- }
-
- private static String[] getStrings(final Reader in)
- throws IOException {
- final Reader reader =
- (in instanceof BufferedReader) ? in : new BufferedReader(in);
-
- List<String> words = new LinkedList<String>();
- String line;
-
- while ((line = ((BufferedReader) reader).readLine()) != null) {
- for (StringTokenizer tok = new StringTokenizer(line);
- tok.hasMoreTokens(); words.add(tok.nextToken())) {
- ;
- }
- }
-
- return (String[]) words.toArray(new String[words.size()]);
- }
-
- public int complete(final String buffer, final int cursor, final List<String> clist) {
- String start = (buffer == null) ? "" : buffer;
-
- SortedSet<String> matches = candidates.tailSet(start);
-
- for (Iterator i = matches.iterator(); i.hasNext();) {
- String can = (String) i.next();
-
- if (!(can.startsWith(start))) {
- break;
- }
-
- if (delimiter != null) {
- int index = can.indexOf(delimiter, cursor);
-
- if (index != -1) {
- can = can.substring(0, index + 1);
- }
- }
-
- clist.add(can);
- }
-
- if (clist.size() == 1) {
- clist.set(0, ((String) clist.get(0)) + " ");
- }
-
- // the index of the completion is always from the beginning of
- // the buffer.
- return (clist.size() == 0) ? (-1) : 0;
- }
-
- public void setDelimiter(final String delimiter) {
- this.delimiter = delimiter;
- }
-
- public String getDelimiter() {
- return this.delimiter;
- }
-
- public void setCandidates(final SortedSet<String> candidates) {
- if (filter != null) {
- TreeSet<String> filtered = new TreeSet<String>();
-
- for (Iterator i = candidates.iterator(); i.hasNext();) {
- String element = (String) i.next();
- element = filter.filter(element);
-
- if (element != null) {
- filtered.add(element);
- }
- }
-
- this.candidates = filtered;
- } else {
- this.candidates = candidates;
- }
- }
-
- public SortedSet getCandidates() {
- return Collections.unmodifiableSortedSet(this.candidates);
- }
-
- public void setCandidateStrings(final String[] strings) {
- setCandidates(new TreeSet<String>(Arrays.asList(strings)));
- }
-
- public void addCandidateString(final String candidateString) {
- final String string =
- (filter == null) ? candidateString : filter.filter(candidateString);
-
- if (string != null) {
- candidates.add(string);
- }
- }
-
- public Object clone() throws CloneNotSupportedException {
- return super.clone();
- }
-
- /**
- * Filter for elements in the completor.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- */
- public static interface SimpleCompletorFilter {
- /**
- * Filter the specified String. To not filter it, return the
- * same String as the parameter. To exclude it, return null.
- */
- public String filter(String element);
- }
-
- public static class NoOpFilter implements SimpleCompletorFilter {
- public String filter(final String element) {
- return element;
- }
- }
-}
diff --git a/src/jline/src/main/java/jline/Terminal.java b/src/jline/src/main/java/jline/Terminal.java
index 53a5aff4d4..fb86c07c12 100644
--- a/src/jline/src/main/java/jline/Terminal.java
+++ b/src/jline/src/main/java/jline/Terminal.java
@@ -4,177 +4,53 @@
* 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.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
/**
- * Representation of the input terminal for a platform. Handles
- * any initialization that the platform may need to perform
- * in order to allow the {@link ConsoleReader} to correctly handle
- * input.
+ * Representation of the input terminal for a platform.
*
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.0
*/
-public abstract class Terminal implements ConsoleOperations {
- private static Terminal term;
+public interface Terminal
+{
+ void init() throws Exception;
- /**
- * @see #setupTerminal
- */
- public static Terminal getTerminal() {
- return setupTerminal();
- }
+ void restore() throws Exception;
- /**
- * Reset the current terminal to null.
- */
- public static void resetTerminal() {
- term = null;
- }
+ void reset() throws Exception;
- /**
- * <p>Configure and return the {@link Terminal} instance for the
- * current platform. This will initialize any system settings
- * that are required for the console to be able to handle
- * input correctly, such as setting tabtop, buffered input, and
- * character echo.</p>
- *
- * <p>This class will use the Terminal implementation specified in the
- * <em>jline.terminal</em> system property, or, if it is unset, by
- * detecting the operating system from the <em>os.name</em>
- * system property and instantiating either the
- * {@link WindowsTerminalTest} or {@link UnixTerminal}.
- *
- * @see #initializeTerminal
- */
- public static synchronized Terminal setupTerminal() {
- if (term != null) {
- return term;
- }
-
- final Terminal t;
-
- String os = System.getProperty("os.name").toLowerCase();
- String termProp = System.getProperty("jline.terminal");
-
- if ((termProp != null) && (termProp.length() > 0)) {
- try {
- t = (Terminal) Class.forName(termProp).newInstance();
- } catch (Exception e) {
- throw (IllegalArgumentException) new IllegalArgumentException(e
- .toString()).fillInStackTrace();
- }
- } else if (os.indexOf("windows") != -1) {
- t = new WindowsTerminal();
- } else {
- t = new UnixTerminal();
- }
-
- try {
- t.initializeTerminal();
- } catch (Exception e) {
- e.printStackTrace();
-
- return term = new UnsupportedTerminal();
- }
-
- return term = t;
- }
+ boolean isSupported();
- /**
- * Returns true if the current console supports ANSI
- * codes.
- */
- public boolean isANSISupported() {
- return true;
- }
+ int getWidth();
- /**
- * Read a single character from the input stream. This might
- * enable a terminal implementation to better handle nuances of
- * the console.
- */
- public int readCharacter(final InputStream in) throws IOException {
- return in.read();
- }
+ int getHeight();
- /**
- * Reads a virtual key from the console. Typically, this will
- * just be the raw character that was entered, but in some cases,
- * multiple input keys will need to be translated into a single
- * virtual key.
- *
- * @param in the InputStream to read from
- * @return the virtual key (e.g., {@link ConsoleOperations#VK_UP})
- */
- public int readVirtualKey(InputStream in) throws IOException {
- return readCharacter(in);
- }
+ boolean isAnsiSupported();
/**
- * Initialize any system settings
- * that are required for the console to be able to handle
- * input correctly, such as setting tabtop, buffered input, and
- * character echo.
+ * When ANSI is not natively handled, the output will have to be wrapped.
*/
- public abstract void initializeTerminal() throws Exception;
+ OutputStream wrapOutIfNeeded(OutputStream out);
/**
- * Returns the current width of the terminal (in characters)
+ * For terminals that don't wrap when character is written in last column.
*/
- public abstract int getTerminalWidth();
+ boolean newlineAtWrapNeeded();
- /**
- * Returns the current height of the terminal (in lines)
- */
- public abstract int getTerminalHeight();
+ boolean isEchoEnabled();
- /**
- * Returns true if this terminal is capable of initializing the
- * terminal to use jline.
- */
- public abstract boolean isSupported();
+ void setEchoEnabled(boolean enabled);
- /**
- * Returns true if the terminal will echo all characters type.
- */
- public abstract boolean getEcho();
+ int readCharacter(InputStream in) throws IOException;
- /**
- * Invokes before the console reads a line with the prompt and mask.
- */
- public void beforeReadLine(ConsoleReader reader, String prompt,
- Character mask) {
- }
-
- /**
- * Invokes after the console reads a line with the prompt and mask.
- */
- public void afterReadLine(ConsoleReader reader, String prompt,
- Character mask) {
- }
-
- /**
- * Returns false if character echoing is disabled.
- */
- public abstract boolean isEchoEnabled();
-
-
- /**
- * Enable character echoing. This can be used to re-enable character
- * if the ConsoleReader is no longer being used.
- */
- public abstract void enableEcho();
-
-
- /**
- * Disable character echoing. This can be used to manually re-enable
- * character if the ConsoleReader has been disabled.
- */
- public abstract void disableEcho();
+ int readVirtualKey(InputStream in) throws IOException;
- public InputStream getDefaultBindings() {
- return Terminal.class.getResourceAsStream("keybindings.properties");
- }
+ InputStream getDefaultBindings();
}
diff --git a/src/jline/src/main/java/jline/TerminalFactory.java b/src/jline/src/main/java/jline/TerminalFactory.java
new file mode 100644
index 0000000000..7a45cc9c51
--- /dev/null
+++ b/src/jline/src/main/java/jline/TerminalFactory.java
@@ -0,0 +1,173 @@
+/*
+ * 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 jline.internal.Configuration;
+import jline.internal.Log;
+
+import java.text.MessageFormat;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Creates terminal instances.
+ *
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.0
+ */
+public class TerminalFactory
+{
+ public static final String JLINE_TERMINAL = "jline.terminal";
+
+ public static final String AUTO = "auto";
+
+ public static final String UNIX = "unix";
+
+ public static final String WIN = "win";
+
+ public static final String WINDOWS = "windows";
+
+ public static final String NONE = "none";
+
+ public static final String OFF = "off";
+
+ public static final String FALSE = "false";
+
+ private static final InheritableThreadLocal<Terminal> holder = new InheritableThreadLocal<Terminal>();
+
+ public static synchronized Terminal create() {
+ if (Log.TRACE) {
+ //noinspection ThrowableInstanceNeverThrown
+ Log.trace(new Throwable("CREATE MARKER"));
+ }
+
+ String type = Configuration.getString(JLINE_TERMINAL);
+ if (type == null) {
+ type = AUTO;
+ }
+
+ Log.debug("Creating terminal; type=", type);
+
+ Terminal t;
+ try {
+ String tmp = type.toLowerCase();
+
+ if (tmp.equals(UNIX)) {
+ t = getFlavor(Flavor.UNIX);
+ }
+ else if (tmp.equals(WIN) | tmp.equals(WINDOWS)) {
+ t = getFlavor(Flavor.WINDOWS);
+ }
+ else if (tmp.equals(NONE) || tmp.equals(OFF) || tmp.equals(FALSE)) {
+ t = new UnsupportedTerminal();
+ }
+ else {
+ if (tmp.equals(AUTO)) {
+ String os = Configuration.getOsName();
+ Flavor flavor = Flavor.UNIX;
+ if (os.contains(WINDOWS)) {
+ flavor = Flavor.WINDOWS;
+ }
+ t = getFlavor(flavor);
+ }
+ else {
+ try {
+ t = (Terminal) Thread.currentThread().getContextClassLoader().loadClass(type).newInstance();
+ }
+ catch (Exception e) {
+ throw new IllegalArgumentException(MessageFormat.format("Invalid terminal type: {0}", type), e);
+ }
+ }
+ }
+ }
+ catch (Exception e) {
+ Log.error("Failed to construct terminal; falling back to unsupported", e);
+ t = new UnsupportedTerminal();
+ }
+
+ Log.debug("Created Terminal: ", t);
+
+ try {
+ t.init();
+ }
+ catch (Exception e) {
+ Log.error("Terminal initialization failed; falling back to unsupported", e);
+ return new UnsupportedTerminal();
+ }
+
+ return t;
+ }
+
+ public static synchronized void reset() {
+ holder.remove();
+ }
+
+ public static synchronized void resetIf(final Terminal t) {
+ if (holder.get() == t) {
+ reset();
+ }
+ }
+
+ public static enum Type
+ {
+ AUTO,
+ WINDOWS,
+ UNIX,
+ NONE
+ }
+
+ public static synchronized void configure(final String type) {
+ assert type != null;
+ System.setProperty(JLINE_TERMINAL, type);
+ }
+
+ public static synchronized void configure(final Type type) {
+ assert type != null;
+ configure(type.name().toLowerCase());
+ }
+
+ //
+ // Flavor Support
+ //
+
+ public static enum Flavor
+ {
+ WINDOWS,
+ UNIX
+ }
+
+ private static final Map<Flavor, Class<? extends Terminal>> FLAVORS = new HashMap<Flavor, Class<? extends Terminal>>();
+
+ static {
+ registerFlavor(Flavor.WINDOWS, AnsiWindowsTerminal.class);
+ registerFlavor(Flavor.UNIX, UnixTerminal.class);
+ }
+
+ public static synchronized Terminal get() {
+ Terminal t = holder.get();
+ if (t == null) {
+ t = create();
+ holder.set(t);
+ }
+ return t;
+ }
+
+ public static Terminal getFlavor(final Flavor flavor) throws Exception {
+ Class<? extends Terminal> type = FLAVORS.get(flavor);
+ if (type != null) {
+ return type.newInstance();
+ }
+
+ throw new InternalError();
+ }
+
+ public static void registerFlavor(final Flavor flavor, final Class<? extends Terminal> type) {
+ FLAVORS.put(flavor, type);
+ }
+
+} \ No newline at end of file
diff --git a/src/jline/src/main/java/jline/TerminalSupport.java b/src/jline/src/main/java/jline/TerminalSupport.java
new file mode 100644
index 0000000000..22f51c5e80
--- /dev/null
+++ b/src/jline/src/main/java/jline/TerminalSupport.java
@@ -0,0 +1,163 @@
+/*
+ * 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 jline.internal.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Provides support for {@link Terminal} instances.
+ *
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.0
+ */
+public abstract class TerminalSupport
+ implements Terminal
+{
+ public static String DEFAULT_KEYBINDINGS_PROPERTIES = "keybindings.properties";
+
+ public static final int DEFAULT_WIDTH = 80;
+
+ public static final int DEFAULT_HEIGHT = 24;
+
+ private Thread shutdownHook;
+
+ private boolean supported;
+
+ private boolean echoEnabled;
+
+ private boolean ansiSupported;
+
+ protected TerminalSupport(final boolean supported) {
+ this.supported = supported;
+ }
+
+ public void init() throws Exception {
+ installShutdownHook(new RestoreHook());
+ }
+
+ public void restore() throws Exception {
+ TerminalFactory.resetIf(this);
+ removeShutdownHook();
+ }
+
+ public void reset() throws Exception {
+ restore();
+ init();
+ }
+
+ protected void installShutdownHook(final Thread hook) {
+ assert hook != null;
+
+ if (shutdownHook != null) {
+ throw new IllegalStateException("Shutdown hook already installed");
+ }
+
+ try {
+ Runtime.getRuntime().addShutdownHook(hook);
+ shutdownHook = hook;
+ }
+ catch (AbstractMethodError e) {
+ // JDK 1.3+ only method. Bummer.
+ Log.trace("Failed to register shutdown hook: ", e);
+ }
+ }
+
+ protected void removeShutdownHook() {
+ if (shutdownHook != null) {
+ try {
+ Runtime.getRuntime().removeShutdownHook(shutdownHook);
+ }
+ catch (AbstractMethodError e) {
+ // JDK 1.3+ only method. Bummer.
+ Log.trace("Failed to remove shutdown hook: ", e);
+ }
+ catch (IllegalStateException e) {
+ // The VM is shutting down, not a big deal; ignore
+ }
+ shutdownHook = null;
+ }
+ }
+
+ public final boolean isSupported() {
+ return supported;
+ }
+
+ public synchronized boolean isAnsiSupported() {
+ return ansiSupported;
+ }
+
+ protected synchronized void setAnsiSupported(final boolean supported) {
+ this.ansiSupported = supported;
+ Log.debug("Ansi supported: ", supported);
+ }
+
+ /**
+ * Subclass to change behavior if needed.
+ * @return the passed out
+ */
+ public OutputStream wrapOutIfNeeded(OutputStream out) {
+ return out;
+ }
+
+ /**
+ * Defaults to true which was the behaviour before this method was added.
+ */
+ public boolean newlineAtWrapNeeded() {
+ return true;
+ }
+
+ public int getWidth() {
+ return DEFAULT_WIDTH;
+ }
+
+ public int getHeight() {
+ return DEFAULT_HEIGHT;
+ }
+
+ public synchronized boolean isEchoEnabled() {
+ return echoEnabled;
+ }
+
+ public synchronized void setEchoEnabled(final boolean enabled) {
+ this.echoEnabled = enabled;
+ Log.debug("Echo enabled: ", enabled);
+ }
+
+ public int readCharacter(final InputStream in) throws IOException {
+ return in.read();
+ }
+
+ public int readVirtualKey(final InputStream in) throws IOException {
+ return readCharacter(in);
+ }
+
+ public InputStream getDefaultBindings() {
+ return TerminalSupport.class.getResourceAsStream(DEFAULT_KEYBINDINGS_PROPERTIES);
+ }
+
+ //
+ // RestoreHook
+ //
+
+ protected class RestoreHook
+ extends Thread
+ {
+ public void start() {
+ try {
+ restore();
+ }
+ catch (Exception e) {
+ Log.trace("Failed to restore: ", e);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/jline/src/main/java/jline/UnixTerminal.java b/src/jline/src/main/java/jline/UnixTerminal.java
index a873b40ff1..755d899765 100644
--- a/src/jline/src/main/java/jline/UnixTerminal.java
+++ b/src/jline/src/main/java/jline/UnixTerminal.java
@@ -4,112 +4,72 @@
* 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.*;
+import jline.console.Key;
+import jline.internal.Configuration;
+import jline.internal.Log;
+import jline.internal.ReplayPrefixOneCharInputStream;
+import jline.internal.TerminalLineSettings;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.HashMap;
+import java.util.Map;
+
+import static jline.UnixTerminal.UnixKey.*;
+import static jline.console.Key.*;
/**
- * <p>
- * Terminal that is used for unix platforms. Terminal initialization
- * is handled by issuing the <em>stty</em> command against the
- * <em>/dev/tty</em> file to disable character echoing and enable
- * character input. All known unix systems (including
- * Linux and Macintosh OS X) support the <em>stty</em>), so this
- * implementation should work for an reasonable POSIX system.
- * </p>
+ * Terminal that is used for unix platforms. Terminal initialization
+ * is handled by issuing the <em>stty</em> command against the
+ * <em>/dev/tty</em> file to disable character echoing and enable
+ * character input. All known unix systems (including
+ * Linux and Macintosh OS X) support the <em>stty</em>), so this
+ * implementation should work for an reasonable POSIX system.
*
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- * @author Updates <a href="mailto:dwkemp@gmail.com">Dale Kemp</a> 2005-12-03
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:dwkemp@gmail.com">Dale Kemp</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @author <a href="mailto:jbonofre@apache.org">Jean-Baptiste Onofré</a>
+ * @since 2.0
*/
-public class UnixTerminal extends Terminal {
- public static final short ARROW_START = 27;
- public static final short ARROW_PREFIX = 91;
- public static final short ARROW_LEFT = 68;
- public static final short ARROW_RIGHT = 67;
- public static final short ARROW_UP = 65;
- public static final short ARROW_DOWN = 66;
- public static final short O_PREFIX = 79;
- public static final short HOME_CODE = 72;
- public static final short END_CODE = 70;
-
- public static final short DEL_THIRD = 51;
- public static final short DEL_SECOND = 126;
-
- private boolean echoEnabled;
- private String ttyConfig;
- private boolean backspaceDeleteSwitched = false;
- private static String sttyCommand =
- System.getProperty("jline.sttyCommand", "stty");
-
-
- String encoding = System.getProperty("jline.UnixTerminal.input.encoding", "UTF-8");
- ReplayPrefixOneCharInputStream replayStream = new ReplayPrefixOneCharInputStream(encoding);
- InputStreamReader replayReader;
-
- public UnixTerminal() {
- try {
- replayReader = new InputStreamReader(replayStream, encoding);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
+public class UnixTerminal
+ extends TerminalSupport
+{
+ private final TerminalLineSettings settings = new TerminalLineSettings();
- protected void checkBackspace(){
- String[] ttyConfigSplit = ttyConfig.split(":|=");
- String eof;
-
- if ("gfmt1".equals(ttyConfigSplit[0]) && ttyConfigSplit.length > 20) {
- // BSD style -g
- eof = ttyConfigSplit[20];
- } else if (ttyConfigSplit.length > 6 && ttyConfigSplit[6] != null) {
- eof = ttyConfigSplit[6];
- } else {
- return;
- }
+ private final ReplayPrefixOneCharInputStream replayStream;
- backspaceDeleteSwitched = eof.equals("7f");
+ private final InputStreamReader replayReader;
+
+ public UnixTerminal() throws Exception {
+ super(true);
+
+ this.replayStream = new ReplayPrefixOneCharInputStream(Configuration.getInputEncoding());
+ this.replayReader = new InputStreamReader(replayStream, replayStream.getEncoding());
+ }
+
+ protected TerminalLineSettings getSettings() {
+ return settings;
}
/**
- * Remove line-buffered input by invoking "stty -icanon min 1"
- * against the current terminal.
+ * Remove line-buffered input by invoking "stty -icanon min 1"
+ * against the current terminal.
*/
- public void initializeTerminal() throws IOException, InterruptedException {
- // save the initial tty configuration
- ttyConfig = stty("-g");
-
- // sanity check
- if ((ttyConfig.length() == 0)
- || ((ttyConfig.indexOf("=") == -1)
- && (ttyConfig.indexOf(":") == -1))) {
- throw new IOException("Unrecognized stty code: " + ttyConfig);
- }
+ @Override
+ public void init() throws Exception {
+ super.init();
- checkBackspace();
+ setAnsiSupported(true);
// set the console to be character-buffered instead of line-buffered
- stty("-icanon min 1");
-
- // disable character echoing
- stty("-echo");
- echoEnabled = false;
+ settings.set("-icanon min 1");
- // at exit, restore the original tty configuration (for JDK 1.3+)
- try {
- Runtime.getRuntime().addShutdownHook(new Thread() {
- public void start() {
- try {
- restoreTerminal();
- } catch (Exception e) {
- consumeException(e);
- }
- }
- });
- } catch (AbstractMethodError ame) {
- // JDK 1.3+ only method. Bummer.
- consumeException(ame);
- }
+ setEchoEnabled(false);
}
/**
@@ -117,315 +77,156 @@ public class UnixTerminal extends Terminal {
* shutting down the console reader. The ConsoleReader cannot be
* used after calling this method.
*/
- public void restoreTerminal() throws Exception {
- if (ttyConfig != null) {
- stty(ttyConfig);
- ttyConfig = null;
- }
- resetTerminal();
- }
-
-
-
- public int readVirtualKey(InputStream in) throws IOException {
- int c = readCharacter(in);
-
- if (backspaceDeleteSwitched)
- if (c == DELETE)
- c = '\b';
- else if (c == '\b')
- c = DELETE;
-
- // in Unix terminals, arrow keys are represented by
- // a sequence of 3 characters. E.g., the up arrow
- // key yields 27, 91, 68
- if (c == ARROW_START) {
- //also the escape key is 27
- //thats why we read until we
- //have something different than 27
- //this is a bugfix, because otherwise
- //pressing escape and than an arrow key
- //was an undefined state
- while (c == ARROW_START)
- c = readCharacter(in);
- if (c == ARROW_PREFIX || c == O_PREFIX) {
- c = readCharacter(in);
- if (c == ARROW_UP) {
- return CTRL_P;
- } else if (c == ARROW_DOWN) {
- return CTRL_N;
- } else if (c == ARROW_LEFT) {
- return CTRL_B;
- } else if (c == ARROW_RIGHT) {
- return CTRL_F;
- } else if (c == HOME_CODE) {
- return CTRL_A;
- } else if (c == END_CODE) {
- return CTRL_E;
- } else if (c == DEL_THIRD) {
- c = readCharacter(in); // read 4th
- return DELETE;
- }
- }
- }
- // handle unicode characters, thanks for a patch from amyi@inf.ed.ac.uk
- if (c > 128) {
- // handle unicode characters longer than 2 bytes,
- // thanks to Marc.Herbert@continuent.com
- replayStream.setInput(c, in);
-// replayReader = new InputStreamReader(replayStream, encoding);
- c = replayReader.read();
-
- }
-
- return c;
+ @Override
+ public void restore() throws Exception {
+ settings.restore();
+ super.restore();
+ // print a newline after the terminal exits.
+ // this should probably be a configurable.
+ System.out.println();
}
/**
- * No-op for exceptions we want to silently consume.
+ * Returns the value of <tt>stty columns</tt> param.
*/
- private void consumeException(Throwable e) {
- }
-
- public boolean isSupported() {
- return true;
- }
-
- public boolean getEcho() {
- return false;
+ @Override
+ public int getWidth() {
+ int w = settings.getProperty("columns");
+ return w < 1 ? DEFAULT_WIDTH : w;
}
/**
- * Returns the value of "stty size" width param.
- *
- * <strong>Note</strong>: this method caches the value from the
- * first time it is called in order to increase speed, which means
- * that changing to size of the terminal will not be reflected
- * in the console.
+ * Returns the value of <tt>stty rows>/tt> param.
*/
- public int getTerminalWidth() {
- int val = -1;
-
- try {
- val = getTerminalProperty("columns");
- } catch (Exception e) {
- }
-
- if (val == -1) {
- val = 80;
- }
-
- return val;
+ @Override
+ public int getHeight() {
+ int h = settings.getProperty("rows");
+ return h < 1 ? DEFAULT_HEIGHT : h;
}
- /**
- * Returns the value of "stty size" height param.
- *
- * <strong>Note</strong>: this method caches the value from the
- * first time it is called in order to increase speed, which means
- * that changing to size of the terminal will not be reflected
- * in the console.
- */
- public int getTerminalHeight() {
- int val = -1;
-
+ @Override
+ public synchronized void setEchoEnabled(final boolean enabled) {
try {
- val = getTerminalProperty("rows");
- } catch (Exception e) {
+ if (enabled) {
+ settings.set("echo");
+ }
+ else {
+ settings.set("-echo");
+ }
+ super.setEchoEnabled(enabled);
}
-
- if (val == -1) {
- val = 24;
+ catch (Exception e) {
+ Log.error("Failed to ", (enabled ? "enable" : "disable"), " echo: ", e);
}
-
- return val;
}
- private static int getTerminalProperty(String prop)
- throws IOException, InterruptedException {
- // need to be able handle both output formats:
- // speed 9600 baud; 24 rows; 140 columns;
- // and:
- // speed 38400 baud; rows = 49; columns = 111; ypixels = 0; xpixels = 0;
- String props = stty("-a");
-
- for (StringTokenizer tok = new StringTokenizer(props, ";\n");
- tok.hasMoreTokens();) {
- String str = tok.nextToken().trim();
-
- if (str.startsWith(prop)) {
- int index = str.lastIndexOf(" ");
-
- return Integer.parseInt(str.substring(index).trim());
- } else if (str.endsWith(prop)) {
- int index = str.indexOf(" ");
+ @Override
+ public int readVirtualKey(final InputStream in) throws IOException {
+ int c = readCharacter(in);
- return Integer.parseInt(str.substring(0, index).trim());
- }
+ if (Key.valueOf(c) == DELETE && settings.getProperty("erase") == DELETE.code) {
+ c = BACKSPACE.code;
}
- return -1;
- }
+ UnixKey key = UnixKey.valueOf(c);
- /**
- * Execute the stty command with the specified arguments
- * against the current active terminal.
- */
- private static String stty(final String args)
- throws IOException, InterruptedException {
- return exec("stty " + args + " < /dev/tty").trim();
- }
-
- /**
- * Execute the specified command and return the output
- * (both stdout and stderr).
- */
- private static String exec(final String cmd)
- throws IOException, InterruptedException {
- return exec(new String[] {
- "sh",
- "-c",
- cmd
- });
- }
-
- /**
- * Execute the specified command and return the output
- * (both stdout and stderr).
- */
- private static String exec(final String[] cmd)
- throws IOException, InterruptedException {
- ByteArrayOutputStream bout = new ByteArrayOutputStream();
-
- Process p = Runtime.getRuntime().exec(cmd);
- int c;
- InputStream in;
+ // in Unix terminals, arrow keys are represented by a sequence of 3 characters. E.g., the up arrow key yields 27, 91, 68
+ if (key == ARROW_START) {
+ // also the escape key is 27 thats why we read until we have something different than 27
+ // this is a bugfix, because otherwise pressing escape and than an arrow key was an undefined state
+ while (key == ARROW_START) {
+ c = readCharacter(in);
+ key = UnixKey.valueOf(c);
+ }
- in = p.getInputStream();
+ if (key == ARROW_PREFIX || key == O_PREFIX) {
+ c = readCharacter(in);
+ key = UnixKey.valueOf(c);
- while ((c = in.read()) != -1) {
- bout.write(c);
+ if (key == ARROW_UP) {
+ return CTRL_P.code;
+ }
+ else if (key == ARROW_DOWN) {
+ return CTRL_N.code;
+ }
+ else if (key == ARROW_LEFT) {
+ return CTRL_B.code;
+ }
+ else if (key == ARROW_RIGHT) {
+ return CTRL_F.code;
+ }
+ else if (key == HOME_CODE) {
+ return CTRL_A.code;
+ }
+ else if (key == END_CODE) {
+ return CTRL_E.code;
+ }
+ else if (key == DEL_THIRD) {
+ readCharacter(in); // read 4th & ignore
+ return DELETE.code;
+ }
+ }
}
- in = p.getErrorStream();
-
- while ((c = in.read()) != -1) {
- bout.write(c);
+ // handle unicode characters, thanks for a patch from amyi@inf.ed.ac.uk
+ if (c > 128) {
+ // handle unicode characters longer than 2 bytes,
+ // thanks to Marc.Herbert@continuent.com
+ replayStream.setInput(c, in);
+ // replayReader = new InputStreamReader(replayStream, encoding);
+ c = replayReader.read();
}
- p.waitFor();
-
- String result = new String(bout.toByteArray());
-
- return result;
+ return c;
}
/**
- * The command to use to set the terminal options. Defaults
- * to "stty", or the value of the system property "jline.sttyCommand".
+ * Unix keys.
*/
- public static void setSttyCommand(String cmd) {
- sttyCommand = cmd;
- }
+ public static enum UnixKey
+ {
+ ARROW_START(27),
- /**
- * The command to use to set the terminal options. Defaults
- * to "stty", or the value of the system property "jline.sttyCommand".
- */
- public static String getSttyCommand() {
- return sttyCommand;
- }
+ ARROW_PREFIX(91),
- public synchronized boolean isEchoEnabled() {
- return echoEnabled;
- }
+ ARROW_LEFT(68),
+ ARROW_RIGHT(67),
- public synchronized void enableEcho() {
- try {
- stty("echo");
- echoEnabled = true;
- } catch (Exception e) {
- consumeException(e);
- }
- }
+ ARROW_UP(65),
- public synchronized void disableEcho() {
- try {
- stty("-echo");
- echoEnabled = false;
- } catch (Exception e) {
- consumeException(e);
- }
- }
+ ARROW_DOWN(66),
- /**
- * This is awkward and inefficient, but probably the minimal way to add
- * UTF-8 support to JLine
- *
- * @author <a href="mailto:Marc.Herbert@continuent.com">Marc Herbert</a>
- */
- static class ReplayPrefixOneCharInputStream extends InputStream {
- byte firstByte;
- int byteLength;
- InputStream wrappedStream;
- int byteRead;
+ O_PREFIX(79),
- final String encoding;
+ HOME_CODE(72),
- public ReplayPrefixOneCharInputStream(String encoding) {
- this.encoding = encoding;
- }
+ END_CODE(70),
- public void setInput(int recorded, InputStream wrapped) throws IOException {
- this.byteRead = 0;
- this.firstByte = (byte) recorded;
- this.wrappedStream = wrapped;
-
- byteLength = 1;
- if (encoding.equalsIgnoreCase("UTF-8"))
- setInputUTF8(recorded, wrapped);
- else if (encoding.equalsIgnoreCase("UTF-16"))
- byteLength = 2;
- else if (encoding.equalsIgnoreCase("UTF-32"))
- byteLength = 4;
- }
+ DEL_THIRD(51),
+
+ DEL_SECOND(126),;
+ public final short code;
- public void setInputUTF8(int recorded, InputStream wrapped) throws IOException {
- // 110yyyyy 10zzzzzz
- if ((firstByte & (byte) 0xE0) == (byte) 0xC0)
- this.byteLength = 2;
- // 1110xxxx 10yyyyyy 10zzzzzz
- else if ((firstByte & (byte) 0xF0) == (byte) 0xE0)
- this.byteLength = 3;
- // 11110www 10xxxxxx 10yyyyyy 10zzzzzz
- else if ((firstByte & (byte) 0xF8) == (byte) 0xF0)
- this.byteLength = 4;
- else
- throw new IOException("invalid UTF-8 first byte: " + firstByte);
+ UnixKey(final int code) {
+ this.code = (short) code;
}
- public int read() throws IOException {
- if (available() == 0)
- return -1;
+ private static final Map<Short, UnixKey> codes;
- byteRead++;
+ static {
+ Map<Short, UnixKey> map = new HashMap<Short, UnixKey>();
- if (byteRead == 1)
- return firstByte;
+ for (UnixKey key : UnixKey.values()) {
+ map.put(key.code, key);
+ }
- return wrappedStream.read();
+ codes = map;
}
- /**
- * InputStreamReader is greedy and will try to read bytes in advance. We
- * do NOT want this to happen since we use a temporary/"losing bytes"
- * InputStreamReader above, that's why we hide the real
- * wrappedStream.available() here.
- */
- public int available() {
- return byteLength - byteRead;
+ public static UnixKey valueOf(final int code) {
+ return codes.get((short) code);
}
}
-}
+} \ No newline at end of file
diff --git a/src/jline/src/main/java/jline/UnsupportedTerminal.java b/src/jline/src/main/java/jline/UnsupportedTerminal.java
index 2d87a18f6c..55c399c311 100644
--- a/src/jline/src/main/java/jline/UnsupportedTerminal.java
+++ b/src/jline/src/main/java/jline/UnsupportedTerminal.java
@@ -4,95 +4,22 @@
* 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.IOException;
+package jline;
/**
- * A no-op unsupported terminal.
+ * An unsupported terminal.
*
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.0
*/
-public class UnsupportedTerminal extends Terminal {
- private Thread maskThread = null;
-
- public void initializeTerminal() {
- // nothing we need to do (or can do) for windows.
- }
-
- public boolean getEcho() {
- return true;
- }
-
-
- public boolean isEchoEnabled() {
- return true;
- }
-
-
- public void enableEcho() {
- }
-
-
- public void disableEcho() {
- }
-
-
- /**
- * Always returng 80, since we can't access this info on Windows.
- */
- public int getTerminalWidth() {
- return 80;
- }
-
- /**
- * Always returng 24, since we can't access this info on Windows.
- */
- public int getTerminalHeight() {
- return 80;
- }
-
- public boolean isSupported() {
- return false;
- }
-
- public void beforeReadLine(final ConsoleReader reader, final String prompt,
- final Character mask) {
- if ((mask != null) && (maskThread == null)) {
- final String fullPrompt = "\r" + prompt
- + " "
- + " "
- + " "
- + "\r" + prompt;
-
- maskThread = new Thread("JLine Mask Thread") {
- public void run() {
- while (!interrupted()) {
- try {
- reader.out.write(fullPrompt);
- reader.out.flush();
- sleep(3);
- } catch (IOException ioe) {
- return;
- } catch (InterruptedException ie) {
- return;
- }
- }
- }
- };
-
- maskThread.setPriority(Thread.MAX_PRIORITY);
- maskThread.setDaemon(true);
- maskThread.start();
- }
- }
-
- public void afterReadLine(final ConsoleReader reader, final String prompt,
- final Character mask) {
- if ((maskThread != null) && maskThread.isAlive()) {
- maskThread.interrupt();
- }
-
- maskThread = null;
+public class UnsupportedTerminal
+ extends TerminalSupport
+{
+ public UnsupportedTerminal() {
+ super(false);
+ setAnsiSupported(false);
+ setEchoEnabled(true);
}
}
diff --git a/src/jline/src/main/java/jline/WindowsTerminal.java b/src/jline/src/main/java/jline/WindowsTerminal.java
index 5d603cbcf0..dcaa3a9cde 100644
--- a/src/jline/src/main/java/jline/WindowsTerminal.java
+++ b/src/jline/src/main/java/jline/WindowsTerminal.java
@@ -4,16 +4,30 @@
* 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.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.HashMap;
+import java.util.Map;
+
+import jline.internal.Configuration;
+import org.fusesource.jansi.internal.WindowsSupport;
+
+import jline.internal.Log;
+import jline.internal.ReplayPrefixOneCharInputStream;
-import jline.UnixTerminal.ReplayPrefixOneCharInputStream;
+import static jline.WindowsTerminal.ConsoleMode.*;
+import static jline.WindowsTerminal.WindowsKey.*;
+import static jline.console.Key.*;
/**
- * <p>
* Terminal implementation for Microsoft Windows. Terminal initialization in
- * {@link #initializeTerminal} is accomplished by extracting the
+ * {@link #init} is accomplished by extracting the
* <em>jline_<i>version</i>.dll</em>, saving it to the system temporary
* directoy (determined by the setting of the <em>java.io.tmpdir</em> System
* property), loading the library, and then calling the Win32 APIs <a
@@ -22,8 +36,7 @@ import jline.UnixTerminal.ReplayPrefixOneCharInputStream;
* <a href="http://msdn.microsoft.com/library/default.asp?
* url=/library/en-us/dllproc/base/getconsolemode.asp">GetConsoleMode</a> to
* disable character echoing.
- * </p>
- *
+ * <p/>
* <p>
* By default, the {@link #readCharacter} method will attempt to test to see if
* the specified {@link InputStream} is {@link System#in} or a wrapper around
@@ -31,483 +44,423 @@ import jline.UnixTerminal.ReplayPrefixOneCharInputStream;
* directly invoke the readc() method in the JNI library. This is so the class
* can read special keys (like arrow keys) which are otherwise inaccessible via
* the {@link System#in} stream. Using JNI reading can be bypassed by setting
- * the <code>jline.WindowsTerminal.disableDirectConsole</code> system property
- * to <code>true</code>.
+ * the <code>jline.WindowsTerminal.directConsole</code> system property
+ * to <code>false</code>.
* </p>
*
* @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.0
*/
-public class WindowsTerminal extends Terminal {
- // constants copied from wincon.h
+public class WindowsTerminal
+ extends TerminalSupport
+{
+ public static final String JLINE_WINDOWS_TERMINAL_INPUT_ENCODING = "jline.WindowsTerminal.input.encoding";
- /**
- * The ReadFile or ReadConsole function returns only when a carriage return
- * character is read. If this mode is disable, the functions return when one
- * or more characters are available.
- */
- private static final int ENABLE_LINE_INPUT = 2;
+ public static final String JLINE_WINDOWS_TERMINAL_OUTPUT_ENCODING = "jline.WindowsTerminal.output.encoding";
- /**
- * Characters read by the ReadFile or ReadConsole function are written to
- * the active screen buffer as they are read. This mode can be used only if
- * the ENABLE_LINE_INPUT mode is also enabled.
- */
- private static final int ENABLE_ECHO_INPUT = 4;
+ public static final String JLINE_WINDOWS_TERMINAL_DIRECT_CONSOLE = "jline.WindowsTerminal.directConsole";
- /**
- * CTRL+C is processed by the system and is not placed in the input buffer.
- * If the input buffer is being read by ReadFile or ReadConsole, other
- * control keys are processed by the system and are not returned in the
- * ReadFile or ReadConsole buffer. If the ENABLE_LINE_INPUT mode is also
- * enabled, backspace, carriage return, and linefeed characters are handled
- * by the system.
- */
- private static final int ENABLE_PROCESSED_INPUT = 1;
+ public static final String WINDOWSBINDINGS_PROPERTIES = "windowsbindings.properties";
- /**
- * User interactions that change the size of the console screen buffer are
- * reported in the console's input buffee. Information about these events
- * can be read from the input buffer by applications using
- * theReadConsoleInput function, but not by those using ReadFile
- * orReadConsole.
- */
- private static final int ENABLE_WINDOW_INPUT = 8;
+ public static final String ANSI = WindowsTerminal.class.getName() + ".ansi";
- /**
- * If the mouse pointer is within the borders of the console window and the
- * window has the keyboard focus, mouse events generated by mouse movement
- * and button presses are placed in the input buffer. These events are
- * discarded by ReadFile or ReadConsole, even when this mode is enabled.
- */
- private static final int ENABLE_MOUSE_INPUT = 16;
+ private boolean directConsole;
- /**
- * When enabled, text entered in a console window will be inserted at the
- * current cursor location and all text following that location will not be
- * overwritten. When disabled, all following text will be overwritten. An OR
- * operation must be performed with this flag and the ENABLE_EXTENDED_FLAGS
- * flag to enable this functionality.
- */
- private static final int ENABLE_PROCESSED_OUTPUT = 1;
+ private int originalMode;
- /**
- * This flag enables the user to use the mouse to select and edit text. To
- * enable this option, use the OR to combine this flag with
- * ENABLE_EXTENDED_FLAGS.
- */
- private static final int ENABLE_WRAP_AT_EOL_OUTPUT = 2;
+ private final ReplayPrefixOneCharInputStream replayStream;
- /**
- * On windows terminals, this character indicates that a 'special' key has
- * been pressed. This means that a key such as an arrow key, or delete, or
- * home, etc. will be indicated by the next character.
- */
- public static final int SPECIAL_KEY_INDICATOR = 224;
+ private final InputStreamReader replayReader;
- /**
- * On windows terminals, this character indicates that a special key on the
- * number pad has been pressed.
- */
- public static final int NUMPAD_KEY_INDICATOR = 0;
+ public WindowsTerminal() throws Exception {
+ super(true);
- /**
- * When following the SPECIAL_KEY_INDICATOR or NUMPAD_KEY_INDICATOR,
- * this character indicates an left arrow key press.
- */
- public static final int LEFT_ARROW_KEY = 75;
+ this.replayStream =
+ new ReplayPrefixOneCharInputStream(Configuration.getString(JLINE_WINDOWS_TERMINAL_INPUT_ENCODING, Configuration.getFileEncoding()));
+ this.replayReader = new InputStreamReader(replayStream, replayStream.getEncoding());
+ }
- /**
- * When following the SPECIAL_KEY_INDICATOR or NUMPAD_KEY_INDICATOR
- * this character indicates an
- * right arrow key press.
- */
- public static final int RIGHT_ARROW_KEY = 77;
+ @Override
+ public void init() throws Exception {
+ super.init();
- /**
- * When following the SPECIAL_KEY_INDICATOR or NUMPAD_KEY_INDICATOR
- * this character indicates an up
- * arrow key press.
- */
- public static final int UP_ARROW_KEY = 72;
+ setAnsiSupported(Boolean.getBoolean(ANSI));
- /**
- * When following the SPECIAL_KEY_INDICATOR or NUMPAD_KEY_INDICATOR
- * this character indicates an
- * down arrow key press.
- */
- public static final int DOWN_ARROW_KEY = 80;
+ //
+ // FIXME: Need a way to disable direct console and sysin detection muck
+ //
- /**
- * When following the SPECIAL_KEY_INDICATOR or NUMPAD_KEY_INDICATOR
- * this character indicates that
- * the delete key was pressed.
- */
- public static final int DELETE_KEY = 83;
+ setDirectConsole(Boolean.getBoolean(JLINE_WINDOWS_TERMINAL_DIRECT_CONSOLE));
- /**
- * When following the SPECIAL_KEY_INDICATOR or NUMPAD_KEY_INDICATOR
- * this character indicates that
- * the home key was pressed.
- */
- public static final int HOME_KEY = 71;
+ this.originalMode = getConsoleMode();
+ setConsoleMode(originalMode & ~ENABLE_ECHO_INPUT.code);
+ setEchoEnabled(false);
+ }
/**
- * When following the SPECIAL_KEY_INDICATOR or NUMPAD_KEY_INDICATOR
- * this character indicates that
- * the end key was pressed.
+ * Restore the original terminal configuration, which can be used when
+ * shutting down the console reader. The ConsoleReader cannot be
+ * used after calling this method.
*/
- public static final char END_KEY = 79;
+ @Override
+ public void restore() throws Exception {
+ // restore the old console mode
+ setConsoleMode(originalMode);
+ super.restore();
+ }
- /**
- * When following the SPECIAL_KEY_INDICATOR or NUMPAD_KEY_INDICATOR
- * this character indicates that
- * the page up key was pressed.
- */
- public static final char PAGE_UP_KEY = 73;
+ @Override
+ public int getWidth() {
+ int w = getWindowsTerminalWidth();
+ return w < 1 ? DEFAULT_WIDTH : w;
+ }
- /**
- * When following the SPECIAL_KEY_INDICATOR or NUMPAD_KEY_INDICATOR
- * this character indicates that
- * the page down key was pressed.
- */
- public static final char PAGE_DOWN_KEY = 81;
+ @Override
+ public int getHeight() {
+ int h = getWindowsTerminalHeight();
+ return h < 1 ? DEFAULT_HEIGHT : h;
+ }
+
+ @Override
+ public void setEchoEnabled(final boolean enabled) {
+ // Must set these four modes at the same time to make it work fine.
+ if (enabled) {
+ setConsoleMode(getConsoleMode() |
+ ENABLE_ECHO_INPUT.code |
+ ENABLE_LINE_INPUT.code |
+ ENABLE_PROCESSED_INPUT.code |
+ ENABLE_WINDOW_INPUT.code);
+ }
+ else {
+ setConsoleMode(getConsoleMode() &
+ ~(ENABLE_LINE_INPUT.code |
+ ENABLE_ECHO_INPUT.code |
+ ENABLE_PROCESSED_INPUT.code |
+ ENABLE_WINDOW_INPUT.code));
+ }
+ super.setEchoEnabled(enabled);
+ }
/**
- * When following the SPECIAL_KEY_INDICATOR or NUMPAD_KEY_INDICATOR
- * this character indicates that
- * the insert key was pressed.
+ * Whether or not to allow the use of the JNI console interaction.
*/
- public static final char INSERT_KEY = 82;
+ public void setDirectConsole(final boolean flag) {
+ this.directConsole = flag;
+ Log.debug("Direct console: ", flag);
+ }
/**
- * When following the SPECIAL_KEY_INDICATOR or NUMPAD_KEY_INDICATOR,
- * this character indicates that the escape key was pressed.
+ * Whether or not to allow the use of the JNI console interaction.
*/
- public static final char ESCAPE_KEY = 0;
-
- private Boolean directConsole;
-
- private boolean echoEnabled;
-
- String encoding = System.getProperty("jline.WindowsTerminal.input.encoding", System.getProperty("file.encoding"));
- ReplayPrefixOneCharInputStream replayStream = new ReplayPrefixOneCharInputStream(encoding);
- InputStreamReader replayReader;
-
- public WindowsTerminal() {
- String dir = System.getProperty("jline.WindowsTerminal.directConsole");
-
- if ("true".equals(dir)) {
- directConsole = Boolean.TRUE;
- } else if ("false".equals(dir)) {
- directConsole = Boolean.FALSE;
- }
-
- try {
- replayReader = new InputStreamReader(replayStream, encoding);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
-
+ public Boolean getDirectConsole() {
+ return directConsole;
}
- private native int getConsoleMode();
-
- private native void setConsoleMode(final int mode);
-
- private native int readByte();
-
- private native int getWindowsTerminalWidth();
-
- private native int getWindowsTerminalHeight();
+ @Override
public int readCharacter(final InputStream in) throws IOException {
// if we can detect that we are directly wrapping the system
// input, then bypass the input stream and read directly (which
// allows us to access otherwise unreadable strokes, such as
// the arrow keys)
- if (directConsole == Boolean.FALSE) {
- return super.readCharacter(in);
- } else if ((directConsole == Boolean.TRUE)
- || ((in == System.in) || (in instanceof FileInputStream
- && (((FileInputStream) in).getFD() == FileDescriptor.in)))) {
+
+ if (directConsole || isSystemIn(in)) {
return readByte();
- } else {
+ }
+ else {
return super.readCharacter(in);
}
}
- public void initializeTerminal() throws Exception {
- loadLibrary("jline");
-
- final int originalMode = getConsoleMode();
-
- setConsoleMode(originalMode & ~ENABLE_ECHO_INPUT);
-
- // set the console to raw mode
- int newMode = originalMode
- & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT
- | ENABLE_PROCESSED_INPUT | ENABLE_WINDOW_INPUT);
- echoEnabled = false;
- setConsoleMode(newMode);
-
- // at exit, restore the original tty configuration (for JDK 1.3+)
- try {
- Runtime.getRuntime().addShutdownHook(new Thread() {
- public void start() {
- // restore the old console mode
- setConsoleMode(originalMode);
- }
- });
- } catch (AbstractMethodError ame) {
- // JDK 1.3+ only method. Bummer.
- consumeException(ame);
+ private boolean isSystemIn(final InputStream in) throws IOException {
+ assert in != null;
+
+ if (in == System.in) {
+ return true;
+ }
+ else if (in instanceof FileInputStream && ((FileInputStream) in).getFD() == FileDescriptor.in) {
+ return true;
}
- }
- private void loadLibrary(final String name) throws IOException {
- // store the DLL in the temporary directory for the System
- String version = getClass().getPackage().getImplementationVersion();
+ return false;
+ }
- if (version == null) {
- version = "";
- }
+ @Override
+ public int readVirtualKey(final InputStream in) throws IOException {
+ int indicator = readCharacter(in);
- version = version.replace('.', '_');
+ // in Windows terminals, arrow keys are represented by
+ // a sequence of 2 characters. E.g., the up arrow
+ // key yields 224, 72
+ if (indicator == SPECIAL_KEY_INDICATOR.code || indicator == NUMPAD_KEY_INDICATOR.code) {
+ int c = readCharacter(in);
+ WindowsKey key = WindowsKey.valueOf(c);
- File f = new File(System.getProperty("java.io.tmpdir"), name + "_"
- + version + ".dll");
- boolean exists = f.isFile(); // check if it already exists
+ switch (key) {
+ case UP_ARROW_KEY:
+ return CTRL_P.code; // translate UP -> CTRL-P
- // extract the embedded jline.dll file from the jar and save
- // it to the current directory
- int bits = 32;
+ case LEFT_ARROW_KEY:
+ return CTRL_B.code; // translate LEFT -> CTRL-B
- // check for 64-bit systems and use to appropriate DLL
- if (System.getProperty("os.arch").indexOf("64") != -1)
- bits = 64;
+ case RIGHT_ARROW_KEY:
+ return CTRL_F.code; // translate RIGHT -> CTRL-F
- InputStream in = new BufferedInputStream(getClass()
- .getResourceAsStream(name + bits + ".dll"));
+ case DOWN_ARROW_KEY:
+ return CTRL_N.code; // translate DOWN -> CTRL-N
- try {
- OutputStream fout = new BufferedOutputStream(
- new FileOutputStream(f));
- byte[] bytes = new byte[1024 * 10];
+ case DELETE_KEY:
+ return CTRL_QM.code; // translate DELETE -> CTRL-?
- for (int n = 0; n != -1; n = in.read(bytes)) {
- fout.write(bytes, 0, n);
- }
+ case HOME_KEY:
+ return CTRL_A.code;
- fout.close();
- } catch (IOException ioe) {
- // We might get an IOException trying to overwrite an existing
- // jline.dll file if there is another process using the DLL.
- // If this happens, ignore errors.
- if (!exists) {
- throw ioe;
- }
- }
+ case END_KEY:
+ return CTRL_E.code;
- // try to clean up the DLL after the JVM exits
- f.deleteOnExit();
+ case PAGE_UP_KEY:
+ return CTRL_K.code;
- // now actually load the DLL
- System.load(f.getAbsolutePath());
- }
+ case PAGE_DOWN_KEY:
+ return CTRL_L.code;
- public int readVirtualKey(InputStream in) throws IOException {
- int indicator = readCharacter(in);
+ case ESCAPE_KEY:
+ return CTRL_OB.code; // translate ESCAPE -> CTRL-[
- // in Windows terminals, arrow keys are represented by
- // a sequence of 2 characters. E.g., the up arrow
- // key yields 224, 72
- if (indicator == SPECIAL_KEY_INDICATOR
- || indicator == NUMPAD_KEY_INDICATOR) {
- int key = readCharacter(in);
+ case INSERT_KEY:
+ return CTRL_C.code;
- switch (key) {
- case UP_ARROW_KEY:
- return CTRL_P; // translate UP -> CTRL-P
- case LEFT_ARROW_KEY:
- return CTRL_B; // translate LEFT -> CTRL-B
- case RIGHT_ARROW_KEY:
- return CTRL_F; // translate RIGHT -> CTRL-F
- case DOWN_ARROW_KEY:
- return CTRL_N; // translate DOWN -> CTRL-N
- case DELETE_KEY:
- return CTRL_QM; // translate DELETE -> CTRL-?
- case HOME_KEY:
- return CTRL_A;
- case END_KEY:
- return CTRL_E;
- case PAGE_UP_KEY:
- return CTRL_K;
- case PAGE_DOWN_KEY:
- return CTRL_L;
- case ESCAPE_KEY:
- return CTRL_OB; // translate ESCAPE -> CTRL-[
- case INSERT_KEY:
- return CTRL_C;
- default:
- return 0;
+ default:
+ return 0;
}
- } else if (indicator > 128) {
- // handle unicode characters longer than 2 bytes,
- // thanks to Marc.Herbert@continuent.com
- replayStream.setInput(indicator, in);
- // replayReader = new InputStreamReader(replayStream, encoding);
- indicator = replayReader.read();
+ }
+ else if (indicator > 128) {
+ // handle unicode characters longer than 2 bytes,
+ // thanks to Marc.Herbert@continuent.com
+ replayStream.setInput(indicator, in);
+ // replayReader = new InputStreamReader(replayStream, encoding);
+ indicator = replayReader.read();
}
return indicator;
-
- }
-
- public boolean isSupported() {
- return true;
}
- /**
- * Windows doesn't support ANSI codes by default; disable them.
- */
- public boolean isANSISupported() {
- return false;
+ @Override
+ public InputStream getDefaultBindings() {
+ return WindowsTerminal.class.getResourceAsStream(WINDOWSBINDINGS_PROPERTIES);
}
- public boolean getEcho() {
- return false;
+ //
+ // Native Bits
+ //
+ private int getConsoleMode() {
+ return WindowsSupport.getConsoleMode();
}
- /**
- * Unsupported; return the default.
- *
- * @see Terminal#getTerminalWidth
- */
- public int getTerminalWidth() {
- return getWindowsTerminalWidth();
+ private void setConsoleMode(int mode) {
+ WindowsSupport.setConsoleMode(mode);
}
- /**
- * Unsupported; return the default.
- *
- * @see Terminal#getTerminalHeight
- */
- public int getTerminalHeight() {
- return getWindowsTerminalHeight();
+ private int readByte() {
+ return WindowsSupport.readByte();
}
- /**
- * No-op for exceptions we want to silently consume.
- */
- private void consumeException(final Throwable e) {
+ private int getWindowsTerminalWidth() {
+ return WindowsSupport.getWindowsTerminalWidth();
}
- /**
- * Whether or not to allow the use of the JNI console interaction.
- */
- public void setDirectConsole(Boolean directConsole) {
- this.directConsole = directConsole;
+ private int getWindowsTerminalHeight() {
+ return WindowsSupport.getWindowsTerminalHeight();
}
/**
- * Whether or not to allow the use of the JNI console interaction.
+ * Console mode
+ * <p/>
+ * Constants copied <tt>wincon.h</tt>.
*/
- public Boolean getDirectConsole() {
- return this.directConsole;
- }
+ public static enum ConsoleMode
+ {
+ /**
+ * The ReadFile or ReadConsole function returns only when a carriage return
+ * character is read. If this mode is disable, the functions return when one
+ * or more characters are available.
+ */
+ ENABLE_LINE_INPUT(2),
- public synchronized boolean isEchoEnabled() {
- return echoEnabled;
- }
+ /**
+ * Characters read by the ReadFile or ReadConsole function are written to
+ * the active screen buffer as they are read. This mode can be used only if
+ * the ENABLE_LINE_INPUT mode is also enabled.
+ */
+ ENABLE_ECHO_INPUT(4),
- public synchronized void enableEcho() {
- // Must set these four modes at the same time to make it work fine.
- setConsoleMode(getConsoleMode() | ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT
- | ENABLE_PROCESSED_INPUT | ENABLE_WINDOW_INPUT);
- echoEnabled = true;
- }
+ /**
+ * CTRL+C is processed by the system and is not placed in the input buffer.
+ * If the input buffer is being read by ReadFile or ReadConsole, other
+ * control keys are processed by the system and are not returned in the
+ * ReadFile or ReadConsole buffer. If the ENABLE_LINE_INPUT mode is also
+ * enabled, backspace, carriage return, and linefeed characters are handled
+ * by the system.
+ */
+ ENABLE_PROCESSED_INPUT(1),
- public synchronized void disableEcho() {
- // Must set these four modes at the same time to make it work fine.
- setConsoleMode(getConsoleMode()
- & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT
- | ENABLE_PROCESSED_INPUT | ENABLE_WINDOW_INPUT));
- echoEnabled = true;
- }
+ /**
+ * User interactions that change the size of the console screen buffer are
+ * reported in the console's input buffee. Information about these events
+ * can be read from the input buffer by applications using
+ * theReadConsoleInput function, but not by those using ReadFile
+ * orReadConsole.
+ */
+ ENABLE_WINDOW_INPUT(8),
- public InputStream getDefaultBindings() {
- return getClass().getResourceAsStream("windowsbindings.properties");
+ /**
+ * If the mouse pointer is within the borders of the console window and the
+ * window has the keyboard focus, mouse events generated by mouse movement
+ * and button presses are placed in the input buffer. These events are
+ * discarded by ReadFile or ReadConsole, even when this mode is enabled.
+ */
+ ENABLE_MOUSE_INPUT(16),
+
+ /**
+ * When enabled, text entered in a console window will be inserted at the
+ * current cursor location and all text following that location will not be
+ * overwritten. When disabled, all following text will be overwritten. An OR
+ * operation must be performed with this flag and the ENABLE_EXTENDED_FLAGS
+ * flag to enable this functionality.
+ */
+ ENABLE_PROCESSED_OUTPUT(1),
+
+ /**
+ * This flag enables the user to use the mouse to select and edit text. To
+ * enable this option, use the OR to combine this flag with
+ * ENABLE_EXTENDED_FLAGS.
+ */
+ ENABLE_WRAP_AT_EOL_OUTPUT(2),;
+
+ public final int code;
+
+ ConsoleMode(final int code) {
+ this.code = code;
+ }
}
/**
- * This is awkward and inefficient, but probably the minimal way to add
- * UTF-8 support to JLine
- *
- * @author <a href="mailto:Marc.Herbert@continuent.com">Marc Herbert</a>
+ * Windows keys.
+ * <p/>
+ * Constants copied <tt>wincon.h</tt>.
*/
- static class ReplayPrefixOneCharInputStream extends InputStream {
- byte firstByte;
- int byteLength;
- InputStream wrappedStream;
- int byteRead;
+ public static enum WindowsKey
+ {
+ /**
+ * On windows terminals, this character indicates that a 'special' key has
+ * been pressed. This means that a key such as an arrow key, or delete, or
+ * home, etc. will be indicated by the next character.
+ */
+ SPECIAL_KEY_INDICATOR(224),
- final String encoding;
+ /**
+ * On windows terminals, this character indicates that a special key on the
+ * number pad has been pressed.
+ */
+ NUMPAD_KEY_INDICATOR(0),
- public ReplayPrefixOneCharInputStream(String encoding) {
- this.encoding = encoding;
- }
+ /**
+ * When following the SPECIAL_KEY_INDICATOR or NUMPAD_KEY_INDICATOR,
+ * this character indicates an left arrow key press.
+ */
+ LEFT_ARROW_KEY(75),
- public void setInput(int recorded, InputStream wrapped) throws IOException {
- this.byteRead = 0;
- this.firstByte = (byte) recorded;
- this.wrappedStream = wrapped;
-
- byteLength = 1;
- if (encoding.equalsIgnoreCase("UTF-8"))
- setInputUTF8(recorded, wrapped);
- else if (encoding.equalsIgnoreCase("UTF-16"))
- byteLength = 2;
- else if (encoding.equalsIgnoreCase("UTF-32"))
- byteLength = 4;
- }
+ /**
+ * When following the SPECIAL_KEY_INDICATOR or NUMPAD_KEY_INDICATOR
+ * this character indicates an
+ * right arrow key press.
+ */
+ RIGHT_ARROW_KEY(77),
+
+ /**
+ * When following the SPECIAL_KEY_INDICATOR or NUMPAD_KEY_INDICATOR
+ * this character indicates an up
+ * arrow key press.
+ */
+ UP_ARROW_KEY(72),
+ /**
+ * When following the SPECIAL_KEY_INDICATOR or NUMPAD_KEY_INDICATOR
+ * this character indicates an
+ * down arrow key press.
+ */
+ DOWN_ARROW_KEY(80),
+
+ /**
+ * When following the SPECIAL_KEY_INDICATOR or NUMPAD_KEY_INDICATOR
+ * this character indicates that
+ * the delete key was pressed.
+ */
+ DELETE_KEY(83),
+
+ /**
+ * When following the SPECIAL_KEY_INDICATOR or NUMPAD_KEY_INDICATOR
+ * this character indicates that
+ * the home key was pressed.
+ */
+ HOME_KEY(71),
- public void setInputUTF8(int recorded, InputStream wrapped) throws IOException {
- // 110yyyyy 10zzzzzz
- if ((firstByte & (byte) 0xE0) == (byte) 0xC0)
- this.byteLength = 2;
- // 1110xxxx 10yyyyyy 10zzzzzz
- else if ((firstByte & (byte) 0xF0) == (byte) 0xE0)
- this.byteLength = 3;
- // 11110www 10xxxxxx 10yyyyyy 10zzzzzz
- else if ((firstByte & (byte) 0xF8) == (byte) 0xF0)
- this.byteLength = 4;
- else
- throw new IOException("invalid UTF-8 first byte: " + firstByte);
+ /**
+ * When following the SPECIAL_KEY_INDICATOR or NUMPAD_KEY_INDICATOR
+ * this character indicates that
+ * the end key was pressed.
+ */
+ END_KEY(79),
+
+ /**
+ * When following the SPECIAL_KEY_INDICATOR or NUMPAD_KEY_INDICATOR
+ * this character indicates that
+ * the page up key was pressed.
+ */
+ PAGE_UP_KEY(73),
+
+ /**
+ * When following the SPECIAL_KEY_INDICATOR or NUMPAD_KEY_INDICATOR
+ * this character indicates that
+ * the page down key was pressed.
+ */
+ PAGE_DOWN_KEY(81),
+
+ /**
+ * When following the SPECIAL_KEY_INDICATOR or NUMPAD_KEY_INDICATOR
+ * this character indicates that
+ * the insert key was pressed.
+ */
+ INSERT_KEY(82),
+
+ /**
+ * When following the SPECIAL_KEY_INDICATOR or NUMPAD_KEY_INDICATOR,
+ * this character indicates that the escape key was pressed.
+ */
+ ESCAPE_KEY(0),;
+
+ public final int code;
+
+ WindowsKey(final int code) {
+ this.code = code;
}
- public int read() throws IOException {
- if (available() == 0)
- return -1;
+ private static final Map<Integer, WindowsKey> codes;
- byteRead++;
+ static {
+ Map<Integer, WindowsKey> map = new HashMap<Integer, WindowsKey>();
- if (byteRead == 1)
- return firstByte;
+ for (WindowsKey key : WindowsKey.values()) {
+ map.put(key.code, key);
+ }
- return wrappedStream.read();
+ codes = map;
}
- /**
- * InputStreamReader is greedy and will try to read bytes in advance. We
- * do NOT want this to happen since we use a temporary/"losing bytes"
- * InputStreamReader above, that's why we hide the real
- * wrappedStream.available() here.
- */
- public int available() {
- return byteLength - byteRead;
+ public static WindowsKey valueOf(final int code) {
+ return codes.get(code);
}
}
-
}
diff --git a/src/jline/src/main/java/jline/console/ConsoleReader.java b/src/jline/src/main/java/jline/console/ConsoleReader.java
new file mode 100644
index 0000000000..fe9e85aed9
--- /dev/null
+++ b/src/jline/src/main/java/jline/console/ConsoleReader.java
@@ -0,0 +1,2103 @@
+/*
+ * 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.console;
+
+import jline.Terminal;
+import jline.TerminalFactory;
+import jline.console.completer.CandidateListCompletionHandler;
+import jline.console.completer.Completer;
+import jline.console.completer.CompletionHandler;
+import jline.console.history.History;
+import jline.console.history.MemoryHistory;
+import jline.internal.Configuration;
+import jline.internal.Log;
+import org.fusesource.jansi.AnsiOutputStream;
+
+import java.awt.Toolkit;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.Transferable;
+import java.awt.datatransfer.UnsupportedFlavorException;
+import java.awt.event.ActionListener;
+import java.io.*;
+import java.util.*;
+
+/**
+ * A reader for console applications. It supports custom tab-completion,
+ * saveable command history, and command line editing. On some platforms,
+ * platform-specific commands will need to be issued before the reader will
+ * function properly. See {@link jline.Terminal#init} for convenience
+ * methods for issuing platform-specific setup commands.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ */
+public class ConsoleReader
+{
+ public static final String JLINE_NOBELL = "jline.nobell";
+
+ public static final String JLINE_EXPANDEVENTS = "jline.expandevents";
+
+ public static final char BACKSPACE = '\b';
+
+ public static final char RESET_LINE = '\r';
+
+ public static final char KEYBOARD_BELL = '\07';
+
+ public static final char NULL_MASK = 0;
+
+ public static final int TAB_WIDTH = 4;
+
+ private static final ResourceBundle
+ resources = ResourceBundle.getBundle(CandidateListCompletionHandler.class.getName());
+
+ private final Terminal terminal;
+
+ private InputStream in;
+
+ private final Writer out;
+
+ private final CursorBuffer buf = new CursorBuffer();
+
+ private String prompt;
+
+ private boolean bellEnabled = true;
+
+ private boolean expandEvents = false;
+
+ private Character mask;
+
+ private Character echoCharacter;
+
+ private StringBuffer searchTerm = null;
+
+ private String previousSearchTerm = "";
+
+ private int searchIndex = -1;
+
+ public ConsoleReader(final InputStream in, final OutputStream out, final InputStream bindings, final Terminal term) throws
+ IOException
+ {
+ this.in = in;
+ this.terminal = term != null ? term : TerminalFactory.get();
+ this.out = new PrintWriter(terminal.wrapOutIfNeeded(out));
+ this.keyBindings = loadKeyBindings(bindings);
+
+ setBellEnabled(!Configuration.getBoolean(JLINE_NOBELL, false));
+ setExpandEvents(Configuration.getBoolean(JLINE_EXPANDEVENTS, false));
+ }
+
+ /**
+ * @deprecated use {@link #ConsoleReader(InputStream, OutputStream, InputStream, Terminal)}
+ * to let the terminal wrap the output stream if needed.
+ */
+ public ConsoleReader(final InputStream in, final Writer out, final InputStream bindings, final Terminal term) throws
+ IOException
+ {
+ this.in = in;
+ this.out = out;
+ this.terminal = term != null ? term : TerminalFactory.get();
+ this.keyBindings = loadKeyBindings(bindings);
+
+ setBellEnabled(!Configuration.getBoolean(JLINE_NOBELL, false));
+ }
+
+ /**
+ * @deprecated use {@link #ConsoleReader(InputStream, OutputStream, InputStream, Terminal)}
+ * to let the terminal wrap the output stream if needed.
+ */
+ public ConsoleReader(final InputStream in, final Writer out, final Terminal term) throws IOException {
+ this(in, out, null, term);
+ }
+
+ /**
+ * @deprecated use {@link #ConsoleReader(InputStream, OutputStream, InputStream, Terminal)}
+ * to let the terminal wrap the output stream if needed.
+ */
+ public ConsoleReader(final InputStream in, final Writer out) throws IOException
+ {
+ this(in, out, null, null);
+ }
+
+ /**
+ * Create a new reader using {@link FileDescriptor#in} for input and
+ * {@link System#out} for output.
+ * <p/>
+ * {@link FileDescriptor#in} is used because it has a better chance of not being buffered.
+ */
+ public ConsoleReader() throws IOException {
+ this(new FileInputStream(FileDescriptor.in), System.out, null, null );
+ }
+
+ // FIXME: Only used for tests
+
+ void setInput(final InputStream in) {
+ this.in = in;
+ }
+
+ public InputStream getInput() {
+ return in;
+ }
+
+ public Writer getOutput() {
+ return out;
+ }
+
+ public Terminal getTerminal() {
+ return terminal;
+ }
+
+ public CursorBuffer getCursorBuffer() {
+ return buf;
+ }
+
+ public void setBellEnabled(final boolean enabled) {
+ this.bellEnabled = enabled;
+ }
+
+ public boolean isBellEnabled() {
+ return bellEnabled;
+ }
+
+ public void setExpandEvents(final boolean expand) {
+ this.expandEvents = expand;
+ }
+
+ public boolean getExpandEvents() {
+ return expandEvents;
+ }
+
+ public void setPrompt(final String prompt) {
+ this.prompt = prompt;
+ }
+
+ public String getPrompt() {
+ return prompt;
+ }
+
+ /**
+ * Set the echo character. For example, to have "*" entered when a password is typed:
+ * <p/>
+ * <pre>
+ * myConsoleReader.setEchoCharacter(new Character('*'));
+ * </pre>
+ * <p/>
+ * Setting the character to
+ * <p/>
+ * <pre>
+ * null
+ * </pre>
+ * <p/>
+ * will restore normal character echoing. Setting the character to
+ * <p/>
+ * <pre>
+ * new Character(0)
+ * </pre>
+ * <p/>
+ * will cause nothing to be echoed.
+ *
+ * @param c the character to echo to the console in place of the typed character.
+ */
+ public void setEchoCharacter(final Character c) {
+ this.echoCharacter = c;
+ }
+
+ /**
+ * Returns the echo character.
+ */
+ public Character getEchoCharacter() {
+ return echoCharacter;
+ }
+
+ /**
+ * Erase the current line.
+ *
+ * @return false if we failed (e.g., the buffer was empty)
+ */
+ final boolean resetLine() throws IOException {
+ if (buf.cursor == 0) {
+ return false;
+ }
+
+ backspaceAll();
+
+ return true;
+ }
+
+ int getCursorPosition() {
+ // FIXME: does not handle anything but a line with a prompt absolute position
+ String prompt = getPrompt();
+ return ((prompt == null) ? 0 : stripAnsi(lastLine(prompt)).length()) + buf.cursor;
+ }
+
+ /**
+ * Returns the text after the last '\n'.
+ * prompt is returned if no '\n' characters are present.
+ * null is returned if prompt is null.
+ */
+ private String lastLine(String str) {
+ if (str == null) return "";
+ int last = str.lastIndexOf("\n");
+
+ if (last >= 0) {
+ return str.substring(last + 1, str.length());
+ }
+
+ return str;
+ }
+
+ private String stripAnsi(String str) {
+ if (str == null) return "";
+ try {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ AnsiOutputStream aos = new AnsiOutputStream(baos);
+ aos.write(str.getBytes());
+ aos.flush();
+ return baos.toString();
+ } catch (IOException e) {
+ return str;
+ }
+ }
+
+ /**
+ * Move the cursor position to the specified absolute index.
+ */
+ public final boolean setCursorPosition(final int position) throws IOException {
+ return moveCursor(position - buf.cursor) != 0;
+ }
+
+ /**
+ * Set the current buffer's content to the specified {@link String}. The
+ * visual console will be modified to show the current buffer.
+ *
+ * @param buffer the new contents of the buffer.
+ */
+ private void setBuffer(final String buffer) throws IOException {
+ // don't bother modifying it if it is unchanged
+ if (buffer.equals(buf.buffer.toString())) {
+ return;
+ }
+
+ // obtain the difference between the current buffer and the new one
+ int sameIndex = 0;
+
+ for (int i = 0, l1 = buffer.length(), l2 = buf.buffer.length(); (i < l1)
+ && (i < l2); i++) {
+ if (buffer.charAt(i) == buf.buffer.charAt(i)) {
+ sameIndex++;
+ }
+ else {
+ break;
+ }
+ }
+
+ int diff = buf.cursor - sameIndex;
+ if (diff < 0) { // we can't backspace here so try from the end of the buffer
+ moveToEnd();
+ diff = buf.buffer.length() - sameIndex;
+ }
+
+ backspace(diff); // go back for the differences
+ killLine(); // clear to the end of the line
+ buf.buffer.setLength(sameIndex); // the new length
+ putString(buffer.substring(sameIndex)); // append the differences
+ }
+
+ private void setBuffer(final CharSequence buffer) throws IOException {
+ setBuffer(String.valueOf(buffer));
+ }
+
+ /**
+ * Output put the prompt + the current buffer
+ */
+ public final void drawLine() throws IOException {
+ String prompt = getPrompt();
+ if (prompt != null) {
+ print(prompt);
+ }
+
+ print(buf.buffer.toString());
+
+ if (buf.length() != buf.cursor) { // not at end of line
+ back(buf.length() - buf.cursor - 1);
+ }
+ }
+
+ /**
+ * Clear the line and redraw it.
+ */
+ public final void redrawLine() throws IOException {
+ print(RESET_LINE);
+// flush();
+ drawLine();
+ }
+
+ /**
+ * Clear the buffer and add its contents to the history.
+ *
+ * @return the former contents of the buffer.
+ */
+ final String finishBuffer() throws IOException { // FIXME: Package protected because used by tests
+ String str = buf.buffer.toString();
+
+ if (expandEvents) {
+ str = expandEvents(str);
+ }
+
+ // we only add it to the history if the buffer is not empty
+ // and if mask is null, since having a mask typically means
+ // the string was a password. We clear the mask after this call
+ if (str.length() > 0) {
+ if (mask == null && isHistoryEnabled()) {
+ history.add(str);
+ }
+ else {
+ mask = null;
+ }
+ }
+
+ history.moveToEnd();
+
+ buf.buffer.setLength(0);
+ buf.cursor = 0;
+
+ return str;
+ }
+
+ /**
+ * Expand event designator such as !!, !#, !3, etc...
+ * See http://www.gnu.org/software/bash/manual/html_node/Event-Designators.html
+ *
+ * @param str
+ * @return
+ */
+ final String expandEvents(String str) throws IOException {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < str.length(); i++) {
+ char c = str.charAt(i);
+ switch (c) {
+ case '!':
+ if (i + 1 < str.length()) {
+ c = str.charAt(++i);
+ boolean neg = false;
+ String rep = null;
+ int i1, idx;
+ switch (c) {
+ case '!':
+ if (history.size() == 0) {
+ throw new IllegalArgumentException("!!: event not found");
+ }
+ rep = history.get(history.index() - 1).toString();
+ break;
+ case '#':
+ sb.append(sb.toString());
+ break;
+ case '?':
+ i1 = str.indexOf('?', i + 1);
+ if (i1 < 0) {
+ i1 = str.length();
+ }
+ String sc = str.substring(i + 1, i1);
+ i = i1;
+ idx = searchBackwards(sc);
+ if (idx < 0) {
+ throw new IllegalArgumentException("!?" + sc + ": event not found");
+ } else {
+ rep = history.get(idx).toString();
+ }
+ break;
+ case ' ':
+ case '\t':
+ sb.append('!');
+ sb.append(c);
+ break;
+ case '-':
+ neg = true;
+ i++;
+ // fall through
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ i1 = i;
+ for (; i < str.length(); i++) {
+ c = str.charAt(i);
+ if (c < '0' || c > '9') {
+ break;
+ }
+ }
+ idx = 0;
+ try {
+ idx = Integer.parseInt(str.substring(i1, i));
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException((neg ? "!-" : "!") + str.substring(i1, i) + ": event not found");
+ }
+ if (neg) {
+ if (idx < history.size()) {
+ rep = (history.get(history.index() - idx)).toString();
+ } else {
+ throw new IllegalArgumentException((neg ? "!-" : "!") + str.substring(i1, i) + ": event not found");
+ }
+ } else {
+ if (idx >= history.index() - history.size() && idx < history.index()) {
+ rep = (history.get(idx)).toString();
+ } else {
+ throw new IllegalArgumentException((neg ? "!-" : "!") + str.substring(i1, i) + ": event not found");
+ }
+ }
+ break;
+ default:
+ String ss = str.substring(i);
+ i = str.length();
+ idx = searchBackwards(ss, history.index(), true);
+ if (idx < 0) {
+ throw new IllegalArgumentException("!" + ss + ": event not found");
+ } else {
+ rep = history.get(idx).toString();
+ }
+ break;
+ }
+ if (rep != null) {
+ sb.append(rep);
+ }
+ } else {
+ sb.append(c);
+ }
+ break;
+ case '^':
+ if (i == 0) {
+ int i1 = str.indexOf('^', i + 1);
+ int i2 = str.indexOf('^', i1 + 1);
+ if (i2 < 0) {
+ i2 = str.length();
+ }
+ if (i1 > 0 && i2 > 0) {
+ String s1 = str.substring(i + 1, i1);
+ String s2 = str.substring(i1 + 1, i2);
+ String s = history.get(history.index() - 1).toString().replace(s1, s2);
+ sb.append(s);
+ i = i2 + 1;
+ break;
+ }
+ }
+ sb.append(c);
+ break;
+ default:
+ sb.append(c);
+ break;
+ }
+ }
+ String result = sb.toString();
+ if (!str.equals(result)) {
+ print(result);
+ println();
+ flush();
+ }
+ return result;
+
+ }
+
+ /* Handle case where terminal does not move cursor to the next line
+ * when a character is inserted at the width of the terminal. This also
+ * fixes backspace issue, where it assumes that the terminal is doing this.
+ */
+ private final void newlineAtWrap() throws IOException {
+ if (terminal.newlineAtWrapNeeded()) {
+ int width = getTerminal().getWidth();
+
+ if ((getCursorPosition() % width == 0) && getCurrentPosition() >= width)
+ println();
+ }
+ }
+
+ /**
+ * Write out the specified string to the buffer and the output stream.
+ */
+ public final void putString(final CharSequence str) throws IOException {
+ buf.write(str);
+ print(str);
+ drawBuffer();
+ newlineAtWrap();
+ }
+
+ /**
+ * Output the specified character, both to the buffer and the output stream.
+ */
+ private void putChar(final int c, final boolean print) throws IOException {
+ buf.write((char) c);
+
+ if (print) {
+ if (mask == null) {
+ // no masking
+ print(c);
+ }
+ else if (mask == NULL_MASK) {
+ // Don't print anything
+ }
+ else {
+ print(mask);
+ }
+
+ drawBuffer();
+ newlineAtWrap();
+ }
+ }
+
+ /**
+ * Redraw the rest of the buffer from the cursor onwards. This is necessary
+ * for inserting text into the buffer.
+ *
+ * @param clear the number of characters to clear after the end of the buffer
+ */
+ private void drawBuffer(final int clear) throws IOException {
+ // debug ("drawBuffer: " + clear);
+ if (buf.cursor == buf.length() && clear == 0) {
+ return;
+ }
+ char[] chars = buf.buffer.substring(buf.cursor).toCharArray();
+ if (mask != null) {
+ Arrays.fill(chars, mask);
+ }
+
+ print(chars);
+ clearAhead(clear);
+ if (terminal.isAnsiSupported()) {
+ if (chars.length > 0) {
+ // don't ask, it works
+ //back(Math.max(chars.length - 1, 1), true);
+ back(chars.length, true);
+ }
+ } else {
+ back(chars.length);
+ }
+// flush();
+ }
+
+ /**
+ * Redraw the rest of the buffer from the cursor onwards. This is necessary
+ * for inserting text into the buffer.
+ */
+ private void drawBuffer() throws IOException {
+ drawBuffer(0);
+ }
+
+ /**
+ * Clear ahead the specified number of characters without moving the cursor.
+ */
+ private void clearAhead(final int num) throws IOException {
+ if (num == 0) {
+ return;
+ }
+
+ if (terminal.isAnsiSupported()) {
+ printAnsiSequence("K");
+ // if cursor+num wraps, then we need to clear the line(s) below too
+ int width = terminal.getWidth();
+ int cursor = getCursorPosition();
+ int curCol = cursor % width;
+ int endCol = (cursor + num) % width;
+ int lines = num / width;
+ if (endCol < curCol) lines++;
+ for (int i = 0; i < lines; i++) {
+ printAnsiSequence("B");
+ printAnsiSequence("2K");
+ }
+ for (int i = 0; i < lines; i++) {
+ printAnsiSequence("A");
+ }
+ return;
+ }
+
+ // print blank extra characters
+ print(' ', num);
+
+ // we need to flush here so a "clever" console doesn't just ignore the redundancy
+ // of a space followed by a backspace.
+// flush();
+
+ // reset the visual cursor
+ back(num, true);
+
+// flush();
+ }
+
+ private void back(final int num) throws IOException {
+ back(num, false);
+ }
+
+ /**
+ * Move the visual cursor backwards without modifying the buffer cursor.
+ * @param printed if true some characters were printed and we have to deal
+ * with new line at wrap
+ */
+ private void back(final int num, boolean printed) throws IOException {
+ if (num == 0) return;
+ if (terminal.isAnsiSupported()) {
+ int width = getTerminal().getWidth();
+ int cursor = getCursorPosition();
+ int realCursor = cursor + num;
+ // adjust cursor if it did not wrapped on its own
+ if (printed && terminal.newlineAtWrapNeeded() && realCursor%width == 0) {
+ realCursor--;
+ }
+ int realCol = realCursor % width;
+ int newCol = cursor % width;
+ int moveup = num / width;
+ int delta = realCol - newCol;
+ if (delta < 0) moveup++;
+ if (moveup > 0) {
+ printAnsiSequence(moveup + "A");
+ }
+ printAnsiSequence((1 + newCol) + "G");
+ return;
+ }
+ print(BACKSPACE, num);
+// flush();
+ }
+
+ /**
+ * Flush the console output stream. This is important for printout out single characters (like a backspace or
+ * keyboard) that we want the console to handle immediately.
+ */
+ public void flush() throws IOException {
+ out.flush();
+ }
+
+ private int backspaceAll() throws IOException {
+ return backspace(Integer.MAX_VALUE);
+ }
+
+ /**
+ * Issue <em>num</em> backspaces.
+ *
+ * @return the number of characters backed up
+ */
+ private int backspace(final int num) throws IOException {
+ if (buf.cursor == 0) {
+ return 0;
+ }
+
+ int count = 0;
+
+ int termwidth = getTerminal().getWidth();
+ int lines = getCursorPosition() / termwidth;
+ count = moveCursor(-1 * num) * -1;
+ buf.buffer.delete(buf.cursor, buf.cursor + count);
+ if (getCursorPosition() / termwidth != lines) {
+ if (terminal.isAnsiSupported()) {
+ // debug("doing backspace redraw: " + getCursorPosition() + " on " + termwidth + ": " + lines);
+ printAnsiSequence("K");
+ }
+ }
+ drawBuffer(count);
+
+ return count;
+ }
+
+ /**
+ * Issue a backspace.
+ *
+ * @return true if successful
+ */
+ public boolean backspace() throws IOException {
+ return backspace(1) == 1;
+ }
+
+ private boolean moveToEnd() throws IOException {
+ return moveCursor(buf.length() - buf.cursor) > 0;
+ }
+
+ /**
+ * Delete the character at the current position and redraw the remainder of the buffer.
+ */
+ private boolean deleteCurrentCharacter() throws IOException {
+ if (buf.length() == 0 || buf.cursor == buf.length()) {
+ return false;
+ }
+
+ buf.buffer.deleteCharAt(buf.cursor);
+ drawBuffer(1);
+ return true;
+ }
+
+ private boolean previousWord() throws IOException {
+ while (isDelimiter(buf.current()) && (moveCursor(-1) != 0)) {
+ // nothing
+ }
+
+ while (!isDelimiter(buf.current()) && (moveCursor(-1) != 0)) {
+ // nothing
+ }
+
+ return true;
+ }
+
+ private boolean nextWord() throws IOException {
+ while (isDelimiter(buf.current()) && (moveCursor(1) != 0)) {
+ // nothing
+ }
+
+ while (!isDelimiter(buf.current()) && (moveCursor(1) != 0)) {
+ // nothing
+ }
+
+ return true;
+ }
+
+ private boolean deletePreviousWord() throws IOException {
+ while (isDelimiter(buf.current()) && backspace()) {
+ // nothing
+ }
+
+ while (!isDelimiter(buf.current()) && backspace()) {
+ // nothing
+ }
+
+ return true;
+ }
+
+ /**
+ * Move the cursor <i>where</i> characters.
+ *
+ * @param num If less than 0, move abs(<i>where</i>) to the left, otherwise move <i>where</i> to the right.
+ * @return The number of spaces we moved
+ */
+ public int moveCursor(final int num) throws IOException {
+ int where = num;
+
+ if ((buf.cursor == 0) && (where <= 0)) {
+ return 0;
+ }
+
+ if ((buf.cursor == buf.buffer.length()) && (where >= 0)) {
+ return 0;
+ }
+
+ if ((buf.cursor + where) < 0) {
+ where = -buf.cursor;
+ }
+ else if ((buf.cursor + where) > buf.buffer.length()) {
+ where = buf.buffer.length() - buf.cursor;
+ }
+
+ moveInternal(where);
+
+ return where;
+ }
+
+ /**
+ * Move the cursor <i>where</i> characters, without checking the current buffer.
+ *
+ * @param where the number of characters to move to the right or left.
+ */
+ private void moveInternal(final int where) throws IOException {
+ // debug ("move cursor " + where + " ("
+ // + buf.cursor + " => " + (buf.cursor + where) + ")");
+ buf.cursor += where;
+
+ if (terminal.isAnsiSupported()) {
+ if (where < 0) {
+ back(Math.abs(where));
+ } else {
+ int width = getTerminal().getWidth();
+ int cursor = getCursorPosition();
+ int oldLine = (cursor - where) / width;
+ int newLine = cursor / width;
+ if (newLine > oldLine) {
+ printAnsiSequence((newLine - oldLine) + "B");
+ }
+ printAnsiSequence(1 +(cursor % width) + "G");
+ }
+// flush();
+ return;
+ }
+
+ char c;
+
+ if (where < 0) {
+ int len = 0;
+ for (int i = buf.cursor; i < buf.cursor - where; i++) {
+ if (buf.buffer.charAt(i) == '\t') {
+ len += TAB_WIDTH;
+ }
+ else {
+ len++;
+ }
+ }
+
+ char chars[] = new char[len];
+ Arrays.fill(chars, BACKSPACE);
+ out.write(chars);
+
+ return;
+ }
+ else if (buf.cursor == 0) {
+ return;
+ }
+ else if (mask != null) {
+ c = mask;
+ }
+ else {
+ print(buf.buffer.substring(buf.cursor - where, buf.cursor).toCharArray());
+ return;
+ }
+
+ // null character mask: don't output anything
+ if (mask == NULL_MASK) {
+ return;
+ }
+
+ print(c, Math.abs(where));
+ }
+
+ // FIXME: replace() is not used
+
+ public final boolean replace(final int num, final String replacement) {
+ buf.buffer.replace(buf.cursor - num, buf.cursor, replacement);
+ try {
+ moveCursor(-num);
+ drawBuffer(Math.max(0, num - replacement.length()));
+ moveCursor(replacement.length());
+ }
+ catch (IOException e) {
+ e.printStackTrace();
+ return false;
+ }
+ return true;
+ }
+
+ //
+ // Key reading
+ //
+
+ /**
+ * Read a character from the console.
+ *
+ * @return the character, or -1 if an EOF is received.
+ */
+ public final int readVirtualKey() throws IOException {
+ int c = terminal.readVirtualKey(in);
+
+ Log.trace("Keystroke: ", c);
+
+ // clear any echo characters
+ clearEcho(c);
+
+ return c;
+ }
+
+ /**
+ * Clear the echoed characters for the specified character code.
+ */
+ private int clearEcho(final int c) throws IOException {
+ // if the terminal is not echoing, then ignore
+ if (!terminal.isEchoEnabled()) {
+ return 0;
+ }
+
+ // otherwise, clear
+ int num = countEchoCharacters((char) c);
+ back(num);
+ drawBuffer(num);
+
+ return num;
+ }
+
+ private int countEchoCharacters(final char c) {
+ // tabs as special: we need to determine the number of spaces
+ // to cancel based on what out current cursor position is
+ if (c == 9) {
+ int tabStop = 8; // will this ever be different?
+ int position = getCursorPosition();
+
+ return tabStop - (position % tabStop);
+ }
+
+ return getPrintableCharacters(c).length();
+ }
+
+ /**
+ * Return the number of characters that will be printed when the specified
+ * character is echoed to the screen
+ *
+ * Adapted from cat by Torbjorn Granlund, as repeated in stty by David MacKenzie.
+ */
+ private StringBuilder getPrintableCharacters(final char ch) {
+ StringBuilder sbuff = new StringBuilder();
+
+ if (ch >= 32) {
+ if (ch < 127) {
+ sbuff.append(ch);
+ }
+ else if (ch == 127) {
+ sbuff.append('^');
+ sbuff.append('?');
+ }
+ else {
+ sbuff.append('M');
+ sbuff.append('-');
+
+ if (ch >= (128 + 32)) {
+ if (ch < (128 + 127)) {
+ sbuff.append((char) (ch - 128));
+ }
+ else {
+ sbuff.append('^');
+ sbuff.append('?');
+ }
+ }
+ else {
+ sbuff.append('^');
+ sbuff.append((char) (ch - 128 + 64));
+ }
+ }
+ }
+ else {
+ sbuff.append('^');
+ sbuff.append((char) (ch + 64));
+ }
+
+ return sbuff;
+ }
+
+ public final int readCharacter(final char... allowed) throws IOException {
+ // if we restrict to a limited set and the current character is not in the set, then try again.
+ char c;
+
+ Arrays.sort(allowed); // always need to sort before binarySearch
+
+ while (Arrays.binarySearch(allowed, c = (char) readVirtualKey()) < 0) {
+ // nothing
+ }
+
+ return c;
+ }
+
+ //
+ // Key Bindings
+ //
+
+ public static final String JLINE_COMPLETION_THRESHOLD = "jline.completion.threshold";
+
+ public static final String JLINE_KEYBINDINGS = "jline.keybindings";
+
+ public static final String JLINEBINDINGS_PROPERTIES = ".jlinebindings.properties";
+
+ /**
+ * The map for logical operations.
+ */
+ private final short[] keyBindings;
+
+ private short[] loadKeyBindings(InputStream input) throws IOException {
+ if (input == null) {
+ try {
+ File file = new File(Configuration.getUserHome(), JLINEBINDINGS_PROPERTIES);
+
+ String path = Configuration.getString(JLINE_KEYBINDINGS);
+ if (path != null) {
+ file = new File(path);
+ }
+
+ if (file.isFile()) {
+ Log.debug("Loading user bindings from: ", file);
+ input = new FileInputStream(file);
+ }
+ }
+ catch (Exception e) {
+ Log.error("Failed to load user bindings", e);
+ }
+ }
+
+ if (input == null) {
+ Log.debug("Using default bindings");
+ input = getTerminal().getDefaultBindings();
+ }
+
+ short[] keyBindings = new short[Character.MAX_VALUE * 2];
+
+ Arrays.fill(keyBindings, Operation.UNKNOWN.code);
+
+ // Loads the key bindings. Bindings file is in the format:
+ //
+ // keycode: operation name
+
+ if (input != null) {
+ input = new BufferedInputStream(input);
+ Properties p = new Properties();
+ p.load(input);
+ input.close();
+
+ for (Object key : p.keySet()) {
+ String val = (String) key;
+
+ try {
+ short code = Short.parseShort(val);
+ String name = p.getProperty(val);
+ Operation op = Operation.valueOf(name);
+ keyBindings[code] = op.code;
+ }
+ catch (NumberFormatException e) {
+ Log.error("Failed to convert binding code: ", val, e);
+ }
+ }
+
+ // hardwired arrow key bindings
+ // keybindings[VK_UP] = PREV_HISTORY;
+ // keybindings[VK_DOWN] = NEXT_HISTORY;
+ // keybindings[VK_LEFT] = PREV_CHAR;
+ // keybindings[VK_RIGHT] = NEXT_CHAR;
+ }
+
+ return keyBindings;
+ }
+
+ int getKeyForAction(final short logicalAction) {
+ for (int i = 0; i < keyBindings.length; i++) {
+ if (keyBindings[i] == logicalAction) {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ int getKeyForAction(final Operation op) {
+ assert op != null;
+ return getKeyForAction(op.code);
+ }
+
+ /**
+ * Reads the console input and returns an array of the form [raw, key binding].
+ */
+ private int[] readBinding() throws IOException {
+ int c = readVirtualKey();
+
+ if (c == -1) {
+ return null;
+ }
+
+ // extract the appropriate key binding
+ short code = keyBindings[c];
+
+ Log.trace("Translated: ", c, " -> ", code);
+
+ return new int[]{c, code};
+ }
+
+ //
+ // Line Reading
+ //
+
+ /**
+ * Read the next line and return the contents of the buffer.
+ */
+ public String readLine() throws IOException {
+ return readLine((String) null);
+ }
+
+ /**
+ * Read the next line with the specified character mask. If null, then
+ * characters will be echoed. If 0, then no characters will be echoed.
+ */
+ public String readLine(final Character mask) throws IOException {
+ return readLine(null, mask);
+ }
+
+ public String readLine(final String prompt) throws IOException {
+ return readLine(prompt, null);
+ }
+
+ /**
+ * Read a line from the <i>in</i> {@link InputStream}, and return the line
+ * (without any trailing newlines).
+ *
+ * @param prompt The prompt to issue to the console, may be null.
+ * @return A line that is read from the terminal, or null if there was null input (e.g., <i>CTRL-D</i>
+ * was pressed).
+ */
+ public String readLine(String prompt, final Character mask) throws IOException {
+ // prompt may be null
+ // mask may be null
+
+ // FIXME: This blows, each call to readLine will reset the console's state which doesn't seem very nice.
+ this.mask = mask;
+ if (prompt != null) {
+ setPrompt(prompt);
+ }
+ else {
+ prompt = getPrompt();
+ }
+
+ try {
+ if (!terminal.isSupported()) {
+ beforeReadLine(prompt, mask);
+ }
+
+ if (prompt != null && prompt.length() > 0) {
+ out.write(prompt);
+ out.flush();
+ }
+
+ // if the terminal is unsupported, just use plain-java reading
+ if (!terminal.isSupported()) {
+ return readLine(in);
+ }
+
+ String originalPrompt = this.prompt;
+
+ final int NORMAL = 1;
+ final int SEARCH = 2;
+ int state = NORMAL;
+
+ boolean success = true;
+
+ while (true) {
+ int[] next = readBinding();
+
+ if (next == null) {
+ return null;
+ }
+
+ int c = next[0];
+ // int code = next[1];
+ Operation code = Operation.valueOf(next[1]);
+
+ if (c == -1) {
+ return null;
+ }
+
+ // Search mode.
+ //
+ // Note that we have to do this first, because if there is a command
+ // not linked to a search command, we leave the search mode and fall
+ // through to the normal state.
+ if (state == SEARCH) {
+ int cursorDest = -1;
+
+ switch (code) {
+ // This doesn't work right now, it seems CTRL-G is not passed
+ // down correctly. :(
+ case ABORT:
+ state = NORMAL;
+ break;
+
+ case SEARCH_PREV:
+ if (searchTerm.length() == 0) {
+ searchTerm.append(previousSearchTerm);
+ }
+
+ if (searchIndex == -1) {
+ searchIndex = searchBackwards(searchTerm.toString());
+ } else {
+ searchIndex = searchBackwards(searchTerm.toString(), searchIndex);
+ }
+ break;
+
+ case DELETE_PREV_CHAR:
+ if (searchTerm.length() > 0) {
+ searchTerm.deleteCharAt(searchTerm.length() - 1);
+ searchIndex = searchBackwards(searchTerm.toString());
+ }
+ break;
+
+ case UNKNOWN:
+ searchTerm.appendCodePoint(c);
+ searchIndex = searchBackwards(searchTerm.toString());
+ break;
+
+ default:
+ // Set buffer and cursor position to the found string.
+ if (searchIndex != -1) {
+ history.moveTo(searchIndex);
+ // set cursor position to the found string
+ cursorDest = history.current().toString().indexOf(searchTerm.toString());
+ }
+ state = NORMAL;
+ break;
+ }
+
+ // if we're still in search mode, print the search status
+ if (state == SEARCH) {
+ if (searchTerm.length() == 0) {
+ printSearchStatus("", "");
+ searchIndex = -1;
+ } else {
+ if (searchIndex == -1) {
+ beep();
+ } else {
+ printSearchStatus(searchTerm.toString(), history.get(searchIndex).toString());
+ }
+ }
+ }
+ // otherwise, restore the line
+ else {
+ restoreLine(originalPrompt, cursorDest);
+ }
+ }
+
+ if (state == NORMAL) {
+ switch (code) {
+ case EXIT: // ctrl-d
+ if (buf.buffer.length() == 0) {
+ return null;
+ } else {
+ deleteCurrentCharacter();
+ }
+ break;
+
+ case COMPLETE: // tab
+ success = complete();
+ break;
+
+ case MOVE_TO_BEG:
+ success = setCursorPosition(0);
+ break;
+
+ case KILL_LINE: // CTRL-K
+ success = killLine();
+ break;
+
+ case CLEAR_SCREEN: // CTRL-L
+ success = clearScreen();
+ break;
+
+ case KILL_LINE_PREV: // CTRL-U
+ success = resetLine();
+ break;
+
+ case NEWLINE: // enter
+ moveToEnd();
+ println(); // output newline
+ flush();
+ return finishBuffer();
+
+ case DELETE_PREV_CHAR: // backspace
+ success = backspace();
+ break;
+
+ case DELETE_NEXT_CHAR: // delete
+ success = deleteCurrentCharacter();
+ break;
+
+ case MOVE_TO_END:
+ success = moveToEnd();
+ break;
+
+ case PREV_CHAR:
+ success = moveCursor(-1) != 0;
+ break;
+
+ case NEXT_CHAR:
+ success = moveCursor(1) != 0;
+ break;
+
+ case NEXT_HISTORY:
+ success = moveHistory(true);
+ break;
+
+ case PREV_HISTORY:
+ success = moveHistory(false);
+ break;
+
+ case ABORT:
+ case REDISPLAY:
+ break;
+
+ case PASTE:
+ success = paste();
+ break;
+
+ case DELETE_PREV_WORD:
+ success = deletePreviousWord();
+ break;
+
+ case PREV_WORD:
+ success = previousWord();
+ break;
+
+ case NEXT_WORD:
+ success = nextWord();
+ break;
+
+ case START_OF_HISTORY:
+ success = history.moveToFirst();
+ if (success) {
+ setBuffer(history.current());
+ }
+ break;
+
+ case END_OF_HISTORY:
+ success = history.moveToLast();
+ if (success) {
+ setBuffer(history.current());
+ }
+ break;
+
+ case CLEAR_LINE:
+ moveInternal(-(buf.cursor));
+ killLine();
+ break;
+
+ case INSERT:
+ buf.setOverTyping(!buf.isOverTyping());
+ break;
+
+ case SEARCH_PREV: // CTRL-R
+ if (searchTerm != null) {
+ previousSearchTerm = searchTerm.toString();
+ }
+ searchTerm = new StringBuffer(buf.buffer);
+ state = SEARCH;
+ if (searchTerm.length() > 0) {
+ searchIndex = searchBackwards(searchTerm.toString());
+ if (searchIndex == -1) {
+ beep();
+ }
+ printSearchStatus(searchTerm.toString(),
+ searchIndex > -1 ? history.get(searchIndex).toString() : "");
+ } else {
+ searchIndex = -1;
+ printSearchStatus("", "");
+ }
+ break;
+
+ case UNKNOWN:
+ default:
+ if (c != 0) { // ignore null chars
+ ActionListener action = triggeredActions.get((char) c);
+ if (action != null) {
+ action.actionPerformed(null);
+ }
+ else {
+ putChar(c, true);
+ }
+ }
+ else {
+ success = false;
+ }
+ }
+
+ if (!success) {
+ beep();
+ }
+
+ flush();
+ }
+ }
+ }
+ finally {
+ if (!terminal.isSupported()) {
+ afterReadLine();
+ }
+ }
+ }
+
+ /**
+ * Read a line for unsupported terminals.
+ */
+ private String readLine(final InputStream in) throws IOException {
+ StringBuilder buff = new StringBuilder();
+
+ while (true) {
+ int i = in.read();
+
+ if (i == -1 || i == '\n' || i == '\r') {
+ return buff.toString();
+ }
+
+ buff.append((char) i);
+ }
+
+ // return new BufferedReader (new InputStreamReader (in)).readLine ();
+ }
+
+ //
+ // Completion
+ //
+
+ private final List<Completer> completers = new LinkedList<Completer>();
+
+ private CompletionHandler completionHandler = new CandidateListCompletionHandler();
+
+ /**
+ * Add the specified {@link jline.console.completer.Completer} to the list of handlers for tab-completion.
+ *
+ * @param completer the {@link jline.console.completer.Completer} to add
+ * @return true if it was successfully added
+ */
+ public boolean addCompleter(final Completer completer) {
+ return completers.add(completer);
+ }
+
+ /**
+ * Remove the specified {@link jline.console.completer.Completer} from the list of handlers for tab-completion.
+ *
+ * @param completer The {@link Completer} to remove
+ * @return True if it was successfully removed
+ */
+ public boolean removeCompleter(final Completer completer) {
+ return completers.remove(completer);
+ }
+
+ /**
+ * Returns an unmodifiable list of all the completers.
+ */
+ public Collection<Completer> getCompleters() {
+ return Collections.unmodifiableList(completers);
+ }
+
+ public void setCompletionHandler(final CompletionHandler handler) {
+ assert handler != null;
+ this.completionHandler = handler;
+ }
+
+ public CompletionHandler getCompletionHandler() {
+ return this.completionHandler;
+ }
+
+ /**
+ * Use the completers to modify the buffer with the appropriate completions.
+ *
+ * @return true if successful
+ */
+ private boolean complete() throws IOException {
+ // debug ("tab for (" + buf + ")");
+ if (completers.size() == 0) {
+ return false;
+ }
+
+ List<CharSequence> candidates = new LinkedList<CharSequence>();
+ String bufstr = buf.buffer.toString();
+ int cursor = buf.cursor;
+
+ int position = -1;
+
+ for (Completer comp : completers) {
+ if ((position = comp.complete(bufstr, cursor, candidates)) != -1) {
+ break;
+ }
+ }
+
+ return candidates.size() != 0 && getCompletionHandler().complete(this, candidates, position);
+ }
+
+ /**
+ * The number of tab-completion candidates above which a warning will be
+ * prompted before showing all the candidates.
+ */
+ private int autoprintThreshold = Integer.getInteger(JLINE_COMPLETION_THRESHOLD, 100); // same default as bash
+
+ /**
+ * @param threshold the number of candidates to print without issuing a warning.
+ */
+ public void setAutoprintThreshold(final int threshold) {
+ this.autoprintThreshold = threshold;
+ }
+
+ /**
+ * @return the number of candidates to print without issuing a warning.
+ */
+ public int getAutoprintThreshold() {
+ return autoprintThreshold;
+ }
+
+ private boolean paginationEnabled;
+
+ /**
+ * Whether to use pagination when the number of rows of candidates exceeds the height of the terminal.
+ */
+ public void setPaginationEnabled(final boolean enabled) {
+ this.paginationEnabled = enabled;
+ }
+
+ /**
+ * Whether to use pagination when the number of rows of candidates exceeds the height of the terminal.
+ */
+ public boolean isPaginationEnabled() {
+ return paginationEnabled;
+ }
+
+ //
+ // History
+ //
+
+ private History history = new MemoryHistory();
+
+ public void setHistory(final History history) {
+ this.history = history;
+ }
+
+ public History getHistory() {
+ return history;
+ }
+
+ private boolean historyEnabled = true;
+
+ /**
+ * Whether or not to add new commands to the history buffer.
+ */
+ public void setHistoryEnabled(final boolean enabled) {
+ this.historyEnabled = enabled;
+ }
+
+ /**
+ * Whether or not to add new commands to the history buffer.
+ */
+ public boolean isHistoryEnabled() {
+ return historyEnabled;
+ }
+
+ /**
+ * Move up or down the history tree.
+ */
+ private boolean moveHistory(final boolean next) throws IOException {
+ if (next && !history.next()) {
+ return false;
+ }
+ else if (!next && !history.previous()) {
+ return false;
+ }
+
+ setBuffer(history.current());
+
+ return true;
+ }
+
+ //
+ // Printing
+ //
+
+ public static final String CR = System.getProperty("line.separator");
+
+ /**
+ * Output the specified character to the output stream without manipulating the current buffer.
+ */
+ private void print(final int c) throws IOException {
+ if (c == '\t') {
+ char chars[] = new char[TAB_WIDTH];
+ Arrays.fill(chars, ' ');
+ out.write(chars);
+ return;
+ }
+
+ out.write(c);
+ }
+
+ /**
+ * Output the specified characters to the output stream without manipulating the current buffer.
+ */
+ private void print(final char... buff) throws IOException {
+ int len = 0;
+ for (char c : buff) {
+ if (c == '\t') {
+ len += TAB_WIDTH;
+ }
+ else {
+ len++;
+ }
+ }
+
+ char chars[];
+ if (len == buff.length) {
+ chars = buff;
+ }
+ else {
+ chars = new char[len];
+ int pos = 0;
+ for (char c : buff) {
+ if (c == '\t') {
+ Arrays.fill(chars, pos, pos + TAB_WIDTH, ' ');
+ pos += TAB_WIDTH;
+ }
+ else {
+ chars[pos] = c;
+ pos++;
+ }
+ }
+ }
+
+ out.write(chars);
+ }
+
+ private void print(final char c, final int num) throws IOException {
+ if (num == 1) {
+ print(c);
+ }
+ else {
+ char[] chars = new char[num];
+ Arrays.fill(chars, c);
+ print(chars);
+ }
+ }
+
+ /**
+ * Output the specified string to the output stream (but not the buffer).
+ */
+ public final void print(final CharSequence s) throws IOException {
+ assert s != null;
+ print(s.toString().toCharArray());
+ }
+
+ public final void println(final CharSequence s) throws IOException {
+ assert s != null;
+ print(s.toString().toCharArray());
+ println();
+ }
+
+ /**
+ * Output a platform-dependant newline.
+ */
+ public final void println() throws IOException {
+ print(CR);
+// flush();
+ }
+
+ //
+ // Actions
+ //
+
+ /**
+ * Issue a delete.
+ *
+ * @return true if successful
+ */
+ public final boolean delete() throws IOException {
+ return delete(1) == 1;
+ }
+
+ // FIXME: delete(int) only used by above + the return is always 1 and num is ignored
+
+ /**
+ * Issue <em>num</em> deletes.
+ *
+ * @return the number of characters backed up
+ */
+ private int delete(final int num) throws IOException {
+ // TODO: Try to use jansi for this
+
+ /* Commented out because of DWA-2949:
+ if (buf.cursor == 0) {
+ return 0;
+ }
+ */
+
+ buf.buffer.delete(buf.cursor, buf.cursor + 1);
+ drawBuffer(1);
+
+ return 1;
+ }
+
+ /**
+ * Kill the buffer ahead of the current cursor position.
+ *
+ * @return true if successful
+ */
+ public boolean killLine() throws IOException {
+ int cp = buf.cursor;
+ int len = buf.buffer.length();
+
+ if (cp >= len) {
+ return false;
+ }
+
+ int num = buf.buffer.length() - cp;
+ clearAhead(num);
+
+ for (int i = 0; i < num; i++) {
+ buf.buffer.deleteCharAt(len - i - 1);
+ }
+
+ return true;
+ }
+
+ /**
+ * Clear the screen by issuing the ANSI "clear screen" code.
+ */
+ public boolean clearScreen() throws IOException {
+ if (!terminal.isAnsiSupported()) {
+ return false;
+ }
+
+ // send the ANSI code to clear the screen
+ printAnsiSequence("2J");
+
+ // then send the ANSI code to go to position 1,1
+ printAnsiSequence("1;1H");
+
+ redrawLine();
+
+ return true;
+ }
+
+ /**
+ * Issue an audible keyboard bell, if {@link #isBellEnabled} return true.
+ */
+ public void beep() throws IOException {
+ if (isBellEnabled()) {
+ print(KEYBOARD_BELL);
+ // need to flush so the console actually beeps
+ flush();
+ }
+ }
+
+ /**
+ * Paste the contents of the clipboard into the console buffer
+ *
+ * @return true if clipboard contents pasted
+ */
+ public boolean paste() throws IOException {
+ Clipboard clipboard;
+ try { // May throw ugly exception on system without X
+ clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
+ }
+ catch (Exception e) {
+ return false;
+ }
+
+ if (clipboard == null) {
+ return false;
+ }
+
+ Transferable transferable = clipboard.getContents(null);
+
+ if (transferable == null) {
+ return false;
+ }
+
+ try {
+ Object content = transferable.getTransferData(DataFlavor.plainTextFlavor);
+
+ // This fix was suggested in bug #1060649 at
+ // http://sourceforge.net/tracker/index.php?func=detail&aid=1060649&group_id=64033&atid=506056
+ // to get around the deprecated DataFlavor.plainTextFlavor, but it
+ // raises a UnsupportedFlavorException on Mac OS X
+
+ if (content == null) {
+ try {
+ content = new DataFlavor().getReaderForText(transferable);
+ }
+ catch (Exception e) {
+ // ignore
+ }
+ }
+
+ if (content == null) {
+ return false;
+ }
+
+ String value;
+
+ if (content instanceof Reader) {
+ // TODO: we might want instead connect to the input stream
+ // so we can interpret individual lines
+ value = "";
+ String line;
+
+ BufferedReader read = new BufferedReader((Reader) content);
+ while ((line = read.readLine()) != null) {
+ if (value.length() > 0) {
+ value += "\n";
+ }
+
+ value += line;
+ }
+ }
+ else {
+ value = content.toString();
+ }
+
+ if (value == null) {
+ return true;
+ }
+
+ putString(value);
+
+ return true;
+ }
+ catch (UnsupportedFlavorException e) {
+ Log.error("Paste failed: ", e);
+
+ return false;
+ }
+ }
+
+ //
+ // Triggered Actions
+ //
+
+ private final Map<Character, ActionListener> triggeredActions = new HashMap<Character, ActionListener>();
+
+ /**
+ * Adding a triggered Action allows to give another curse of action if a character passed the pre-processing.
+ * <p/>
+ * Say you want to close the application if the user enter q.
+ * addTriggerAction('q', new ActionListener(){ System.exit(0); }); would do the trick.
+ */
+ public void addTriggeredAction(final char c, final ActionListener listener) {
+ triggeredActions.put(c, listener);
+ }
+
+ //
+ // Formatted Output
+ //
+
+ /**
+ * Output the specified {@link Collection} in proper columns.
+ */
+ public void printColumns(final Collection<? extends CharSequence> items) throws IOException {
+ if (items == null || items.isEmpty()) {
+ return;
+ }
+
+ int width = getTerminal().getWidth();
+ int height = getTerminal().getHeight();
+
+ int maxWidth = 0;
+ for (CharSequence item : items) {
+ maxWidth = Math.max(maxWidth, item.length());
+ }
+ Log.debug("Max width: ", maxWidth);
+
+ int showLines;
+ if (isPaginationEnabled()) {
+ showLines = height - 1; // page limit
+ }
+ else {
+ showLines = Integer.MAX_VALUE;
+ }
+
+ StringBuilder buff = new StringBuilder();
+ for (CharSequence item : items) {
+ if ((buff.length() + maxWidth) > width) {
+ println(buff);
+ buff.setLength(0);
+
+ if (--showLines == 0) {
+ // Overflow
+ print(resources.getString("display-more"));
+ flush();
+ int c = readVirtualKey();
+ if (c == '\r' || c == '\n') {
+ // one step forward
+ showLines = 1;
+ }
+ else if (c != 'q') {
+ // page forward
+ showLines = height - 1;
+ }
+
+ back(resources.getString("display-more").length());
+ if (c == 'q') {
+ // cancel
+ break;
+ }
+ }
+ }
+
+ // NOTE: toString() is important here due to AnsiString being retarded
+ buff.append(item.toString());
+ for (int i = 0; i < (maxWidth + 3 - item.length()); i++) {
+ buff.append(' ');
+ }
+ }
+
+ if (buff.length() > 0) {
+ println(buff);
+ }
+ }
+
+ //
+ // Non-supported Terminal Support
+ //
+
+ private Thread maskThread;
+
+ private void beforeReadLine(final String prompt, final Character mask) {
+ if (mask != null && maskThread == null) {
+ final String fullPrompt = "\r" + prompt
+ + " "
+ + " "
+ + " "
+ + "\r" + prompt;
+
+ maskThread = new Thread()
+ {
+ public void run() {
+ while (!interrupted()) {
+ try {
+ Writer out = getOutput();
+ out.write(fullPrompt);
+ out.flush();
+ sleep(3);
+ }
+ catch (IOException e) {
+ return;
+ }
+ catch (InterruptedException e) {
+ return;
+ }
+ }
+ }
+ };
+
+ maskThread.setPriority(Thread.MAX_PRIORITY);
+ maskThread.setDaemon(true);
+ maskThread.start();
+ }
+ }
+
+ private void afterReadLine() {
+ if (maskThread != null && maskThread.isAlive()) {
+ maskThread.interrupt();
+ }
+
+ maskThread = null;
+ }
+
+ /**
+ * Erases the current line with the existing prompt, then redraws the line
+ * with the provided prompt and buffer
+ * @param prompt
+ * the new prompt
+ * @param buffer
+ * the buffer to be drawn
+ * @param cursorDest
+ * where you want the cursor set when the line has been drawn.
+ * -1 for end of line.
+ * */
+ public void resetPromptLine(String prompt, String buffer, int cursorDest) throws IOException {
+ // move cursor to end of line
+ moveToEnd();
+
+ // backspace all text, including prompt
+ buf.buffer.append(this.prompt);
+ buf.cursor += this.prompt.length();
+ this.prompt = "";
+ backspaceAll();
+
+ this.prompt = prompt;
+ redrawLine();
+ setBuffer(buffer);
+
+ // move cursor to destination (-1 will move to end of line)
+ if (cursorDest < 0) cursorDest = buffer.length();
+ setCursorPosition(cursorDest);
+
+ flush();
+ }
+
+ public void printSearchStatus(String searchTerm, String match) throws IOException {
+ String prompt = "(reverse-i-search)`" + searchTerm + "': ";
+ String buffer = match;
+ int cursorDest = match.indexOf(searchTerm);
+ resetPromptLine(prompt, buffer, cursorDest);
+ }
+
+ public void restoreLine(String originalPrompt, int cursorDest) throws IOException {
+ // TODO move cursor to matched string
+ String prompt = lastLine(originalPrompt);
+ String buffer = buf.buffer.toString();
+ resetPromptLine(prompt, buffer, cursorDest);
+ }
+
+ //
+ // History search
+ //
+ /**
+ * Search backward in history from a given position.
+ *
+ * @param searchTerm substring to search for.
+ * @param startIndex the index from which on to search
+ * @return index where this substring has been found, or -1 else.
+ */
+ public int searchBackwards(String searchTerm, int startIndex) {
+ return searchBackwards(searchTerm, startIndex, false);
+ }
+
+ /**
+ * Search backwards in history from the current position.
+ *
+ * @param searchTerm substring to search for.
+ * @return index where the substring has been found, or -1 else.
+ */
+ public int searchBackwards(String searchTerm) {
+ return searchBackwards(searchTerm, history.index());
+ }
+
+
+ public int searchBackwards(String searchTerm, int startIndex, boolean startsWith) {
+ ListIterator<History.Entry> it = history.entries(startIndex);
+ while (it.hasPrevious()) {
+ History.Entry e = it.previous();
+ if (startsWith) {
+ if (e.value().toString().startsWith(searchTerm)) {
+ return e.index();
+ }
+ } else {
+ if (e.value().toString().contains(searchTerm)) {
+ return e.index();
+ }
+ }
+ }
+ return -1;
+ }
+
+ //
+ // Helpers
+ //
+
+ /**
+ * Checks to see if the specified character is a delimiter. We consider a
+ * character a delimiter if it is anything but a letter or digit.
+ *
+ * @param c The character to test
+ * @return True if it is a delimiter
+ */
+ private boolean isDelimiter(final char c) {
+ return !Character.isLetterOrDigit(c);
+ }
+
+ private void printAnsiSequence(String sequence) throws IOException {
+ print(27);
+ print('[');
+ print(sequence);
+ flush(); // helps with step debugging
+ }
+
+ // return column position, reported by the terminal
+ private int getCurrentPosition() {
+ // check for ByteArrayInputStream to disable for unit tests
+ if (terminal.isAnsiSupported() && !(in instanceof ByteArrayInputStream)) {
+ try {
+ printAnsiSequence("6n");
+ flush();
+ StringBuffer b = new StringBuffer(8);
+ // position is sent as <ESC>[{ROW};{COLUMN}R
+ int r;
+ while((r = in.read()) > -1 && r != 'R') {
+ if (r != 27 && r != '[') {
+ b.append((char) r);
+ }
+ }
+ String[] pos = b.toString().split(";");
+ return Integer.parseInt(pos[1]);
+ } catch (Exception x) {
+ // no luck
+ }
+ }
+
+ return -1; // TODO: throw exception instead?
+ }
+
+}
diff --git a/src/jline/src/main/java/jline/CursorBuffer.java b/src/jline/src/main/java/jline/console/CursorBuffer.java
index 3aec20af51..ef9932f43a 100644
--- a/src/jline/src/main/java/jline/CursorBuffer.java
+++ b/src/jline/src/main/java/jline/console/CursorBuffer.java
@@ -4,20 +4,31 @@
* This software is distributable under the BSD license. See the terms of the
* BSD license in the documentation provided with this software.
*/
-package jline;
+
+package jline.console;
/**
- * A CursorBuffer is a holder for a {@link StringBuffer} that also contains the
- * current cursor position.
+ * A holder for a {@link StringBuilder} that also contains the current cursor position.
*
* @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.0
*/
-public class CursorBuffer {
+public class CursorBuffer
+{
+ private boolean overTyping = false;
+
public int cursor = 0;
- StringBuffer buffer = new StringBuffer();
+ public final StringBuilder buffer = new StringBuilder();
- private boolean overtyping = false;
+ public boolean isOverTyping() {
+ return overTyping;
+ }
+
+ public void setOverTyping(final boolean b) {
+ overTyping = b;
+ }
public int length() {
return buffer.length();
@@ -31,74 +42,52 @@ public class CursorBuffer {
return buffer.charAt(cursor - 1);
}
- public boolean clearBuffer() {
- if (buffer.length() == 0) {
- return false;
- }
-
- buffer.delete(0, buffer.length());
- cursor = 0;
- return true;
- }
-
/**
* Write the specific character into the buffer, setting the cursor position
* ahead one. The text may overwrite or insert based on the current setting
- * of isOvertyping().
+ * of {@link #isOverTyping}.
*
- * @param c
- * the character to insert
+ * @param c the character to insert
*/
public void write(final char c) {
buffer.insert(cursor++, c);
- if (isOvertyping() && cursor < buffer.length()) {
+ if (isOverTyping() && cursor < buffer.length()) {
buffer.deleteCharAt(cursor);
}
}
/**
- * Insert the specified {@link String} into the buffer, setting the cursor
- * to the end of the insertion point.
- *
- * @param str
- * the String to insert. Must not be null.
+ * Insert the specified chars into the buffer, setting the cursor to the end of the insertion point.
*/
- public void write(final String str) {
+ public void write(final CharSequence str) {
+ assert str != null;
+
if (buffer.length() == 0) {
buffer.append(str);
- } else {
+ }
+ else {
buffer.insert(cursor, str);
}
cursor += str.length();
- if (isOvertyping() && cursor < buffer.length()) {
+ if (isOverTyping() && cursor < buffer.length()) {
buffer.delete(cursor, (cursor + str.length()));
}
}
- public String toString() {
- return buffer.toString();
- }
+ public boolean clear() {
+ if (buffer.length() == 0) {
+ return false;
+ }
- public boolean isOvertyping() {
- return overtyping;
+ buffer.delete(0, buffer.length());
+ cursor = 0;
+ return true;
}
- public void setOvertyping(boolean b) {
- overtyping = b;
+ @Override
+ public String toString() {
+ return buffer.toString();
}
-
- public StringBuffer getBuffer() {
- return buffer;
- }
-
- public void setBuffer(StringBuffer buffer) {
- buffer.setLength(0);
- buffer.append(this.buffer.toString());
-
- this.buffer = buffer;
- }
-
-
}
diff --git a/src/jline/src/main/java/jline/console/Key.java b/src/jline/src/main/java/jline/console/Key.java
new file mode 100644
index 0000000000..8997985dcc
--- /dev/null
+++ b/src/jline/src/main/java/jline/console/Key.java
@@ -0,0 +1,74 @@
+/*
+ * 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.console;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Map from key name to key codes.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @see java.awt.event.KeyEvent
+ * @since 2.0
+ */
+public enum Key
+{
+ CTRL_A(1),
+
+ CTRL_B(2),
+
+ CTRL_C(3),
+
+ CTRL_D(4),
+
+ CTRL_E(5),
+
+ CTRL_F(6),
+
+ CTRL_G(7),
+
+ CTRL_K(11),
+
+ CTRL_L(12),
+
+ CTRL_N(14),
+
+ CTRL_P(16),
+
+ CTRL_OB(27),
+
+ CTRL_QM(127),
+
+ BACKSPACE('\b'),
+
+ DELETE(127),;
+
+ public final short code;
+
+ Key(final int code) {
+ this.code = (short) code;
+ }
+
+ private static final Map<Short, Key> codes;
+
+ static {
+ Map<Short, Key> map = new HashMap<Short, Key>();
+
+ for (Key op : Key.values()) {
+ map.put(op.code, op);
+ }
+
+ codes = map;
+ }
+
+ public static Key valueOf(final int code) {
+ return codes.get((short) code);
+ }
+} \ No newline at end of file
diff --git a/src/jline/src/main/java/jline/console/Operation.java b/src/jline/src/main/java/jline/console/Operation.java
new file mode 100644
index 0000000000..e2d9ea564b
--- /dev/null
+++ b/src/jline/src/main/java/jline/console/Operation.java
@@ -0,0 +1,285 @@
+/*
+ * 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.console;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Map for console operation to virtual key bindings.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @see java.awt.event.KeyEvent
+ * @since 2.0
+ */
+public enum Operation
+{
+ /**
+ * Unknown operation.
+ */
+ UNKNOWN(-99),
+
+ /**
+ * Operation that moves to the beginning of the buffer.
+ */
+ MOVE_TO_BEG(-1),
+
+ /**
+ * Operation that moves to the end of the buffer.
+ */
+ MOVE_TO_END(-3),
+
+ /**
+ * Operation that moved to the previous character in the buffer.
+ */
+ PREV_CHAR(-4),
+
+ /**
+ * Operation that issues a newline.
+ */
+ NEWLINE(-6),
+
+ /**
+ * Operation that deletes the buffer from the current character to the end.
+ */
+ KILL_LINE(-7),
+
+ /**
+ * Operation that clears the screen.
+ */
+ CLEAR_SCREEN(-8),
+
+ /**
+ * Operation that sets the buffer to the next history item.
+ */
+ NEXT_HISTORY(-9),
+
+ /**
+ * Operation that sets the buffer to the previous history item.
+ */
+ PREV_HISTORY(-11),
+
+ /**
+ * Operation that redisplays the current buffer.
+ */
+ REDISPLAY(-13),
+
+ /**
+ * Operation that deletes the buffer from the cursor to the beginning.
+ */
+ KILL_LINE_PREV(-15),
+
+ /**
+ * Operation that deletes the previous word in the buffer.
+ */
+ DELETE_PREV_WORD(-16),
+
+ /**
+ * Operation that moves to the next character in the buffer.
+ */
+ NEXT_CHAR(-19),
+
+ /**
+ * Operation that moves to the previous character in the buffer.
+ */
+ REPEAT_PREV_CHAR(-20),
+
+ /**
+ * Operation that searches backwards in the command history.
+ */
+ SEARCH_PREV(-21),
+
+ /**
+ * Operation that repeats the character.
+ */
+ REPEAT_NEXT_CHAR(-24),
+
+ /**
+ * Operation that searches forward in the command history.
+ */
+ SEARCH_NEXT(-25),
+
+ /**
+ * Operation that moved to the previous whitespace.
+ */
+ PREV_SPACE_WORD(-27),
+
+ /**
+ * Operation that moved to the end of the current word.
+ */
+ TO_END_WORD(-29),
+
+ /**
+ * Operation that
+ */
+ REPEAT_SEARCH_PREV(-34),
+
+ /**
+ * Operation that
+ */
+ PASTE_PREV(-36),
+
+ /**
+ * Operation that
+ */
+ REPLACE_MODE(-37),
+
+ /**
+ * Operation that
+ */
+ SUBSTITUTE_LINE(-38),
+
+ /**
+ * Operation that
+ */
+ TO_PREV_CHAR(-39),
+
+ /**
+ * Operation that
+ */
+ NEXT_SPACE_WORD(-40),
+
+ /**
+ * Operation that
+ */
+ DELETE_PREV_CHAR(-41),
+
+ /**
+ * Operation that
+ */
+ ADD(-42),
+
+ /**
+ * Operation that
+ */
+ PREV_WORD(-43),
+
+ /**
+ * Operation that
+ */
+ CHANGE_META(-44),
+
+ /**
+ * Operation that
+ */
+ DELETE_META(-45),
+
+ /**
+ * Operation that
+ */
+ END_WORD(-46),
+
+ /**
+ * Operation that toggles insert/overtype
+ */
+ INSERT(-48),
+
+ /**
+ * Operation that
+ */
+ REPEAT_SEARCH_NEXT(-49),
+
+ /**
+ * Operation that
+ */
+ PASTE_NEXT(-50),
+
+ /**
+ * Operation that
+ */
+ REPLACE_CHAR(-51),
+
+ /**
+ * Operation that
+ */
+ SUBSTITUTE_CHAR(-52),
+
+ /**
+ * Operation that
+ */
+ TO_NEXT_CHAR(-53),
+
+ /**
+ * Operation that undoes the previous operation.
+ */
+ UNDO(-54),
+
+ /**
+ * Operation that moved to the next word.
+ */
+ NEXT_WORD(-55),
+
+ /**
+ * Operation that deletes the previous character.
+ */
+ DELETE_NEXT_CHAR(-56),
+
+ /**
+ * Operation that toggles between uppercase and lowercase.
+ */
+ CHANGE_CASE(-57),
+
+ /**
+ * Operation that performs completion operation on the current word.
+ */
+ COMPLETE(-58),
+
+ /**
+ * Operation that exits the command prompt.
+ */
+ EXIT(-59),
+
+ /**
+ * Operation that pastes the contents of the clipboard into the line
+ */
+ PASTE(-60),
+
+ /**
+ * Operation that moves the current History to the beginning.
+ */
+ START_OF_HISTORY(-61),
+
+ /**
+ * Operation that moves the current History to the end.
+ */
+ END_OF_HISTORY(-62),
+
+ /**
+ * Operation that clears whatever text is on the current line.
+ */
+ CLEAR_LINE(-63),
+
+ /**
+ * Cancel search
+ */
+ ABORT(-64),
+ ;
+
+ public final short code;
+
+ Operation(final int code) {
+ this.code = (short) code;
+ }
+
+ private static final Map<Short, Operation> codes;
+
+ static {
+ Map<Short, Operation> map = new HashMap<Short, Operation>();
+
+ for (Operation op : Operation.values()) {
+ map.put(op.code, op);
+ }
+
+ codes = map;
+ }
+
+ public static Operation valueOf(final int code) {
+ return codes.get((short) code);
+ }
+} \ No newline at end of file
diff --git a/src/jline/src/main/java/jline/console/completer/AggregateCompleter.java b/src/jline/src/main/java/jline/console/completer/AggregateCompleter.java
new file mode 100644
index 0000000000..621ac5f6d8
--- /dev/null
+++ b/src/jline/src/main/java/jline/console/completer/AggregateCompleter.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 jline.console.completer;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Completer which contains multiple completers and aggregates them together.
+ *
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public class AggregateCompleter
+ implements Completer
+{
+ private final List<Completer> completers = new ArrayList<Completer>();
+
+ public AggregateCompleter() {
+ // empty
+ }
+
+ public AggregateCompleter(final Collection<Completer> completers) {
+ assert completers != null;
+ this.completers.addAll(completers);
+ }
+
+ public AggregateCompleter(final Completer... completers) {
+ this(Arrays.asList(completers));
+ }
+
+ public Collection<Completer> getCompleters() {
+ return completers;
+ }
+
+ public int complete(final String buffer, final int cursor, final List<CharSequence> candidates) {
+ // buffer could be null
+ assert candidates != null;
+
+ List<Completion> completions = new ArrayList<Completion>(completers.size());
+
+ // Run each completer, saving its completion results
+ int max = -1;
+ for (Completer completer : completers) {
+ Completion completion = new Completion(candidates);
+ completion.complete(completer, buffer, cursor);
+
+ // Compute the max cursor position
+ max = Math.max(max, completion.cursor);
+
+ completions.add(completion);
+ }
+
+ // Append candidates from completions which have the same cursor position as max
+ for (Completion completion : completions) {
+ if (completion.cursor == max) {
+ candidates.addAll(completion.candidates);
+ }
+ }
+
+ return max;
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "{" +
+ "completers=" + completers +
+ '}';
+ }
+
+ private class Completion
+ {
+ public final List<CharSequence> candidates;
+
+ public int cursor;
+
+ public Completion(final List<CharSequence> candidates) {
+ assert candidates != null;
+ this.candidates = new LinkedList<CharSequence>(candidates);
+ }
+
+ public void complete(final Completer completer, final String buffer, final int cursor) {
+ assert completer != null;
+
+ this.cursor = completer.complete(buffer, cursor, candidates);
+ }
+ }
+}
diff --git a/src/jline/src/main/java/jline/console/completer/ArgumentCompleter.java b/src/jline/src/main/java/jline/console/completer/ArgumentCompleter.java
new file mode 100644
index 0000000000..542d4b4424
--- /dev/null
+++ b/src/jline/src/main/java/jline/console/completer/ArgumentCompleter.java
@@ -0,0 +1,398 @@
+/*
+ * 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.console.completer;
+
+import jline.internal.Log;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * A {@link Completer} implementation that invokes a child completer using the appropriate <i>separator</i> argument.
+ * This can be used instead of the individual completers having to know about argument parsing semantics.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public class ArgumentCompleter
+ implements Completer
+{
+ private final ArgumentDelimiter delimiter;
+
+ private final List<Completer> completers = new ArrayList<Completer>();
+
+ private boolean strict = true;
+
+ /**
+ * Create a new completer with the specified argument delimiter.
+ *
+ * @param delimiter The delimiter for parsing arguments
+ * @param completers The embedded completers
+ */
+ public ArgumentCompleter(final ArgumentDelimiter delimiter, final Collection<Completer> completers) {
+ assert delimiter != null;
+ this.delimiter = delimiter;
+ assert completers != null;
+ this.completers.addAll(completers);
+ }
+
+ /**
+ * Create a new completer with the specified argument delimiter.
+ *
+ * @param delimiter The delimiter for parsing arguments
+ * @param completers The embedded completers
+ */
+ public ArgumentCompleter(final ArgumentDelimiter delimiter, final Completer... completers) {
+ this(delimiter, Arrays.asList(completers));
+ }
+
+ /**
+ * Create a new completer with the default {@link WhitespaceArgumentDelimiter}.
+ *
+ * @param completers The embedded completers
+ */
+ public ArgumentCompleter(final Completer... completers) {
+ this(new WhitespaceArgumentDelimiter(), completers);
+ }
+
+ /**
+ * Create a new completer with the default {@link WhitespaceArgumentDelimiter}.
+ *
+ * @param completers The embedded completers
+ */
+ public ArgumentCompleter(final List<Completer> completers) {
+ this(new WhitespaceArgumentDelimiter(), completers);
+ }
+
+ /**
+ * If true, a completion at argument index N will only succeed
+ * if all the completions from 0-(N-1) also succeed.
+ */
+ public void setStrict(final boolean strict) {
+ this.strict = strict;
+ }
+
+ /**
+ * Returns whether a completion at argument index N will success
+ * if all the completions from arguments 0-(N-1) also succeed.
+ *
+ * @return True if strict.
+ * @since 2.3
+ */
+ public boolean isStrict() {
+ return this.strict;
+ }
+
+ /**
+ * @since 2.3
+ */
+ public ArgumentDelimiter getDelimiter() {
+ return delimiter;
+ }
+
+ /**
+ * @since 2.3
+ */
+ public List<Completer> getCompleters() {
+ return completers;
+ }
+
+ public int complete(final String buffer, final int cursor, final List<CharSequence> candidates) {
+ // buffer can be null
+ assert candidates != null;
+
+ ArgumentDelimiter delim = getDelimiter();
+ ArgumentList list = delim.delimit(buffer, cursor);
+ int argpos = list.getArgumentPosition();
+ int argIndex = list.getCursorArgumentIndex();
+
+ if (argIndex < 0) {
+ return -1;
+ }
+
+ List<Completer> completers = getCompleters();
+ Completer completer;
+
+ // if we are beyond the end of the completers, just use the last one
+ if (argIndex >= completers.size()) {
+ completer = completers.get(completers.size() - 1);
+ }
+ else {
+ completer = completers.get(argIndex);
+ }
+
+ // ensure that all the previous completers are successful before allowing this completer to pass (only if strict).
+ for (int i = 0; isStrict() && (i < argIndex); i++) {
+ Completer sub = completers.get(i >= completers.size() ? (completers.size() - 1) : i);
+ String[] args = list.getArguments();
+ String arg = (args == null || i >= args.length) ? "" : args[i];
+
+ List<CharSequence> subCandidates = new LinkedList<CharSequence>();
+
+ if (sub.complete(arg, arg.length(), subCandidates) == -1) {
+ return -1;
+ }
+
+ if (subCandidates.size() == 0) {
+ return -1;
+ }
+ }
+
+ int ret = completer.complete(list.getCursorArgument(), argpos, candidates);
+
+ if (ret == -1) {
+ return -1;
+ }
+
+ int pos = ret + list.getBufferPosition() - argpos;
+
+ // Special case: when completing in the middle of a line, and the area under the cursor is a delimiter,
+ // then trim any delimiters from the candidates, since we do not need to have an extra delimiter.
+ //
+ // E.g., if we have a completion for "foo", and we enter "f bar" into the buffer, and move to after the "f"
+ // and hit TAB, we want "foo bar" instead of "foo bar".
+
+ if ((cursor != buffer.length()) && delim.isDelimiter(buffer, cursor)) {
+ for (int i = 0; i < candidates.size(); i++) {
+ CharSequence val = candidates.get(i);
+
+ while (val.length() > 0 && delim.isDelimiter(val, val.length() - 1)) {
+ val = val.subSequence(0, val.length() - 1);
+ }
+
+ candidates.set(i, val);
+ }
+ }
+
+ Log.trace("Completing ", buffer, " (pos=", cursor, ") with: ", candidates, ": offset=", pos);
+
+ return pos;
+ }
+
+ /**
+ * The {@link ArgumentCompleter.ArgumentDelimiter} allows custom breaking up of a {@link String} into individual
+ * arguments in order to dispatch the arguments to the nested {@link Completer}.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ */
+ public static interface ArgumentDelimiter
+ {
+ /**
+ * Break the specified buffer into individual tokens that can be completed on their own.
+ *
+ * @param buffer The buffer to split
+ * @param pos The current position of the cursor in the buffer
+ * @return The tokens
+ */
+ ArgumentList delimit(CharSequence buffer, int pos);
+
+ /**
+ * Returns true if the specified character is a whitespace parameter.
+ *
+ * @param buffer The complete command buffer
+ * @param pos The index of the character in the buffer
+ * @return True if the character should be a delimiter
+ */
+ boolean isDelimiter(CharSequence buffer, int pos);
+ }
+
+ /**
+ * Abstract implementation of a delimiter that uses the {@link #isDelimiter} method to determine if a particular
+ * character should be used as a delimiter.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ */
+ public abstract static class AbstractArgumentDelimiter
+ implements ArgumentDelimiter
+ {
+ // TODO: handle argument quoting and escape characters
+
+ private char[] quoteChars = {'\'', '"'};
+
+ private char[] escapeChars = {'\\'};
+
+ public void setQuoteChars(final char[] chars) {
+ this.quoteChars = chars;
+ }
+
+ public char[] getQuoteChars() {
+ return this.quoteChars;
+ }
+
+ public void setEscapeChars(final char[] chars) {
+ this.escapeChars = chars;
+ }
+
+ public char[] getEscapeChars() {
+ return this.escapeChars;
+ }
+
+ public ArgumentList delimit(final CharSequence buffer, final int cursor) {
+ List<String> args = new LinkedList<String>();
+ StringBuilder arg = new StringBuilder();
+ int argpos = -1;
+ int bindex = -1;
+
+ for (int i = 0; (buffer != null) && (i <= buffer.length()); i++) {
+ // once we reach the cursor, set the
+ // position of the selected index
+ if (i == cursor) {
+ bindex = args.size();
+ // the position in the current argument is just the
+ // length of the current argument
+ argpos = arg.length();
+ }
+
+ if ((i == buffer.length()) || isDelimiter(buffer, i)) {
+ if (arg.length() > 0) {
+ args.add(arg.toString());
+ arg.setLength(0); // reset the arg
+ }
+ }
+ else {
+ arg.append(buffer.charAt(i));
+ }
+ }
+
+ return new ArgumentList(args.toArray(new String[args.size()]), bindex, argpos, cursor);
+ }
+
+ /**
+ * Returns true if the specified character is a whitespace parameter. Check to ensure that the character is not
+ * escaped by any of {@link #getQuoteChars}, and is not escaped by ant of the {@link #getEscapeChars}, and
+ * returns true from {@link #isDelimiterChar}.
+ *
+ * @param buffer The complete command buffer
+ * @param pos The index of the character in the buffer
+ * @return True if the character should be a delimiter
+ */
+ public boolean isDelimiter(final CharSequence buffer, final int pos) {
+ return !isQuoted(buffer, pos) && !isEscaped(buffer, pos) && isDelimiterChar(buffer, pos);
+ }
+
+ public boolean isQuoted(final CharSequence buffer, final int pos) {
+ return false;
+ }
+
+ public boolean isEscaped(final CharSequence buffer, final int pos) {
+ if (pos <= 0) {
+ return false;
+ }
+
+ for (int i = 0; (escapeChars != null) && (i < escapeChars.length);
+ i++) {
+ if (buffer.charAt(pos) == escapeChars[i]) {
+ return !isEscaped(buffer, pos - 1); // escape escape
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns true if the character at the specified position if a delimiter. This method will only be called if
+ * the character is not enclosed in any of the {@link #getQuoteChars}, and is not escaped by ant of the
+ * {@link #getEscapeChars}. To perform escaping manually, override {@link #isDelimiter} instead.
+ */
+ public abstract boolean isDelimiterChar(CharSequence buffer, int pos);
+ }
+
+ /**
+ * {@link ArgumentCompleter.ArgumentDelimiter} implementation that counts all whitespace (as reported by
+ * {@link Character#isWhitespace}) as being a delimiter.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ */
+ public static class WhitespaceArgumentDelimiter
+ extends AbstractArgumentDelimiter
+ {
+ /**
+ * The character is a delimiter if it is whitespace, and the
+ * preceding character is not an escape character.
+ */
+ @Override
+ public boolean isDelimiterChar(final CharSequence buffer, final int pos) {
+ return Character.isWhitespace(buffer.charAt(pos));
+ }
+ }
+
+ /**
+ * The result of a delimited buffer.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ */
+ public static class ArgumentList
+ {
+ private String[] arguments;
+
+ private int cursorArgumentIndex;
+
+ private int argumentPosition;
+
+ private int bufferPosition;
+
+ /**
+ * @param arguments The array of tokens
+ * @param cursorArgumentIndex The token index of the cursor
+ * @param argumentPosition The position of the cursor in the current token
+ * @param bufferPosition The position of the cursor in the whole buffer
+ */
+ public ArgumentList(final String[] arguments, final int cursorArgumentIndex, final int argumentPosition, final int bufferPosition) {
+ assert arguments != null;
+
+ this.arguments = arguments;
+ this.cursorArgumentIndex = cursorArgumentIndex;
+ this.argumentPosition = argumentPosition;
+ this.bufferPosition = bufferPosition;
+ }
+
+ public void setCursorArgumentIndex(final int i) {
+ this.cursorArgumentIndex = i;
+ }
+
+ public int getCursorArgumentIndex() {
+ return this.cursorArgumentIndex;
+ }
+
+ public String getCursorArgument() {
+ if ((cursorArgumentIndex < 0) || (cursorArgumentIndex >= arguments.length)) {
+ return null;
+ }
+
+ return arguments[cursorArgumentIndex];
+ }
+
+ public void setArgumentPosition(final int pos) {
+ this.argumentPosition = pos;
+ }
+
+ public int getArgumentPosition() {
+ return this.argumentPosition;
+ }
+
+ public void setArguments(final String[] arguments) {
+ this.arguments = arguments;
+ }
+
+ public String[] getArguments() {
+ return this.arguments;
+ }
+
+ public void setBufferPosition(final int pos) {
+ this.bufferPosition = pos;
+ }
+
+ public int getBufferPosition() {
+ return this.bufferPosition;
+ }
+ }
+}
diff --git a/src/jline/src/main/java/jline/console/completer/CandidateListCompletionHandler.java b/src/jline/src/main/java/jline/console/completer/CandidateListCompletionHandler.java
new file mode 100644
index 0000000000..3f6ede6fc4
--- /dev/null
+++ b/src/jline/src/main/java/jline/console/completer/CandidateListCompletionHandler.java
@@ -0,0 +1,192 @@
+/*
+ * 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.console.completer;
+
+import jline.console.ConsoleReader;
+import jline.console.CursorBuffer;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.util.Set;
+
+/**
+ * A {@link CompletionHandler} that deals with multiple distinct completions
+ * by outputting the complete list of possibilities to the console. This
+ * mimics the behavior of the
+ * <a href="http://www.gnu.org/directory/readline.html">readline</a> library.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public class CandidateListCompletionHandler
+ implements CompletionHandler
+{
+ // TODO: handle quotes and escaped quotes && enable automatic escaping of whitespace
+
+ public boolean complete(final ConsoleReader reader, final List<CharSequence> candidates, final int pos) throws
+ IOException
+ {
+ CursorBuffer buf = reader.getCursorBuffer();
+
+ // if there is only one completion, then fill in the buffer
+ if (candidates.size() == 1) {
+ CharSequence value = candidates.get(0);
+
+ // fail if the only candidate is the same as the current buffer
+ if (value.equals(buf.toString())) {
+ return false;
+ }
+
+ setBuffer(reader, value, pos);
+
+ return true;
+ }
+ else if (candidates.size() > 1) {
+ String value = getUnambiguousCompletions(candidates);
+ setBuffer(reader, value, pos);
+ }
+
+ printCandidates(reader, candidates);
+
+ // redraw the current console buffer
+ reader.drawLine();
+
+ return true;
+ }
+
+ public static void setBuffer(final ConsoleReader reader, final CharSequence value, final int offset) throws
+ IOException
+ {
+ while ((reader.getCursorBuffer().cursor > offset) && reader.backspace()) {
+ // empty
+ }
+
+ reader.putString(value);
+ reader.setCursorPosition(offset + value.length());
+ }
+
+ /**
+ * Print out the candidates. If the size of the candidates is greater than the
+ * {@link ConsoleReader#getAutoprintThreshold}, they prompt with a warning.
+ *
+ * @param candidates the list of candidates to print
+ */
+ public static void printCandidates(final ConsoleReader reader, Collection<CharSequence> candidates) throws
+ IOException
+ {
+ Set<CharSequence> distinct = new HashSet<CharSequence>(candidates);
+
+ if (distinct.size() > reader.getAutoprintThreshold()) {
+ //noinspection StringConcatenation
+ reader.print(Messages.DISPLAY_CANDIDATES.format(candidates.size()));
+ reader.flush();
+
+ int c;
+
+ String noOpt = Messages.DISPLAY_CANDIDATES_NO.format();
+ String yesOpt = Messages.DISPLAY_CANDIDATES_YES.format();
+ char[] allowed = {yesOpt.charAt(0), noOpt.charAt(0)};
+
+ while ((c = reader.readCharacter(allowed)) != -1) {
+ String tmp = new String(new char[]{(char) c});
+
+ if (noOpt.startsWith(tmp)) {
+ reader.println();
+ return;
+ }
+ else if (yesOpt.startsWith(tmp)) {
+ break;
+ }
+ else {
+ reader.beep();
+ }
+ }
+ }
+
+ // copy the values and make them distinct, without otherwise affecting the ordering. Only do it if the sizes differ.
+ if (distinct.size() != candidates.size()) {
+ Collection<CharSequence> copy = new ArrayList<CharSequence>();
+
+ for (CharSequence next : candidates) {
+ if (!copy.contains(next)) {
+ copy.add(next);
+ }
+ }
+
+ candidates = copy;
+ }
+
+ reader.println();
+ reader.printColumns(candidates);
+ }
+
+ /**
+ * Returns a root that matches all the {@link String} elements of the specified {@link List},
+ * or null if there are no commonalities. For example, if the list contains
+ * <i>foobar</i>, <i>foobaz</i>, <i>foobuz</i>, the method will return <i>foob</i>.
+ */
+ private String getUnambiguousCompletions(final List<CharSequence> candidates) {
+ if (candidates == null || candidates.isEmpty()) {
+ return null;
+ }
+
+ // convert to an array for speed
+ String[] strings = candidates.toArray(new String[candidates.size()]);
+
+ String first = strings[0];
+ StringBuilder candidate = new StringBuilder();
+
+ for (int i = 0; i < first.length(); i++) {
+ if (startsWith(first.substring(0, i + 1), strings)) {
+ candidate.append(first.charAt(i));
+ }
+ else {
+ break;
+ }
+ }
+
+ return candidate.toString();
+ }
+
+ /**
+ * @return true is all the elements of <i>candidates</i> start with <i>starts</i>
+ */
+ private boolean startsWith(final String starts, final String[] candidates) {
+ for (String candidate : candidates) {
+ if (!candidate.startsWith(starts)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private static enum Messages
+ {
+ DISPLAY_CANDIDATES,
+ DISPLAY_CANDIDATES_YES,
+ DISPLAY_CANDIDATES_NO,;
+
+ private static final
+ ResourceBundle
+ bundle =
+ ResourceBundle.getBundle(CandidateListCompletionHandler.class.getName(),
+ Locale.getDefault(),
+ CandidateListCompletionHandler.class.getClassLoader());
+
+ public String format(final Object... args) {
+ return String.format(bundle.getString(name()), args);
+ }
+ }
+}
diff --git a/src/jline/src/main/java/jline/console/completer/Completer.java b/src/jline/src/main/java/jline/console/completer/Completer.java
new file mode 100644
index 0000000000..ff5d22b108
--- /dev/null
+++ b/src/jline/src/main/java/jline/console/completer/Completer.java
@@ -0,0 +1,37 @@
+/*
+ * 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.console.completer;
+
+import java.util.List;
+
+/**
+ * A completer is the mechanism by which tab-completion candidates will be resolved.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public interface Completer
+{
+ //
+ // FIXME: Check if we can use CharSequece for buffer?
+ //
+
+ /**
+ * Populates <i>candidates</i> with a list of possible completions for the <i>buffer</i>.
+ *
+ * The <i>candidates</i> list will not be sorted before being displayed to the user: thus, the
+ * complete method should sort the {@link List} before returning.
+ *
+ * @param buffer The buffer
+ * @param cursor The current position of the cursor in the <i>buffer</i>
+ * @param candidates The {@link List} of candidates to populate
+ * @return The index of the <i>buffer</i> for which the completion will be relative
+ */
+ int complete(String buffer, int cursor, List<CharSequence> candidates);
+}
diff --git a/src/jline/src/main/java/jline/console/completer/CompletionHandler.java b/src/jline/src/main/java/jline/console/completer/CompletionHandler.java
new file mode 100644
index 0000000000..8f32f2c7f6
--- /dev/null
+++ b/src/jline/src/main/java/jline/console/completer/CompletionHandler.java
@@ -0,0 +1,25 @@
+/*
+ * 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.console.completer;
+
+import jline.console.ConsoleReader;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * Handler for dealing with candidates for tab-completion.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public interface CompletionHandler
+{
+ boolean complete(ConsoleReader reader, List<CharSequence> candidates, int position) throws IOException;
+}
diff --git a/src/jline/src/main/java/jline/console/completer/EnumCompleter.java b/src/jline/src/main/java/jline/console/completer/EnumCompleter.java
new file mode 100644
index 0000000000..738689e8a6
--- /dev/null
+++ b/src/jline/src/main/java/jline/console/completer/EnumCompleter.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2009 the original author(s).
+ *
+ * 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 jline.console.completer;
+
+/**
+ * {@link Completer} for {@link Enum} names.
+ *
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public class EnumCompleter
+ extends StringsCompleter
+{
+ public EnumCompleter(Class<? extends Enum> source) {
+ assert source != null;
+
+ for (Enum<?> n : source.getEnumConstants()) {
+ this.getStrings().add(n.name().toLowerCase());
+ }
+ }
+} \ No newline at end of file
diff --git a/src/jline/src/main/java/jline/console/completer/FileNameCompleter.java b/src/jline/src/main/java/jline/console/completer/FileNameCompleter.java
new file mode 100644
index 0000000000..69667aa9bf
--- /dev/null
+++ b/src/jline/src/main/java/jline/console/completer/FileNameCompleter.java
@@ -0,0 +1,133 @@
+/*
+ * 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.console.completer;
+
+import jline.internal.Configuration;
+
+import java.io.File;
+import java.util.List;
+
+/**
+ * A file name completer takes the buffer and issues a list of
+ * potential completions.
+ * <p/>
+ * This completer tries to behave as similar as possible to
+ * <i>bash</i>'s file name completion (using GNU readline)
+ * with the following exceptions:
+ * <p/>
+ * <ul>
+ * <li>Candidates that are directories will end with "/"</li>
+ * <li>Wildcard regular expressions are not evaluated or replaced</li>
+ * <li>The "~" character can be used to represent the user's home,
+ * but it cannot complete to other users' homes, since java does
+ * not provide any way of determining that easily</li>
+ * </ul>
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public class FileNameCompleter
+ implements Completer
+{
+ // TODO: Handle files with spaces in them
+
+ private static final boolean OS_IS_WINDOWS;
+
+ static {
+ String os = Configuration.getOsName();
+ OS_IS_WINDOWS = os.contains("windows");
+ }
+
+ public int complete(String buffer, final int cursor, final List<CharSequence> candidates) {
+ // buffer can be null
+ assert candidates != null;
+
+ if (buffer == null) {
+ buffer = "";
+ }
+
+ if (OS_IS_WINDOWS) {
+ buffer = buffer.replace('/', '\\');
+ }
+
+ String translated = buffer;
+
+ File homeDir = getUserHome();
+
+ // Special character: ~ maps to the user's home directory
+ if (translated.startsWith("~" + separator())) {
+ translated = homeDir.getPath() + translated.substring(1);
+ }
+ else if (translated.startsWith("~")) {
+ translated = homeDir.getParentFile().getAbsolutePath();
+ }
+ else if (!(translated.startsWith(separator()))) {
+ String cwd = getUserDir().getAbsolutePath();
+ translated = cwd + separator() + translated;
+ }
+
+ File file = new File(translated);
+ final File dir;
+
+ if (translated.endsWith(separator())) {
+ dir = file;
+ }
+ else {
+ dir = file.getParentFile();
+ }
+
+ File[] entries = dir == null ? new File[0] : dir.listFiles();
+
+ return matchFiles(buffer, translated, entries, candidates);
+ }
+
+ protected String separator() {
+ return File.separator;
+ }
+
+ protected File getUserHome() {
+ return Configuration.getUserHome();
+ }
+
+ protected File getUserDir() {
+ return new File(".");
+ }
+
+ protected int matchFiles(final String buffer, final String translated, final File[] files, final List<CharSequence> candidates) {
+ if (files == null) {
+ return -1;
+ }
+
+ int matches = 0;
+
+ // first pass: just count the matches
+ for (File file : files) {
+ if (file.getAbsolutePath().startsWith(translated)) {
+ matches++;
+ }
+ }
+ for (File file : files) {
+ if (file.getAbsolutePath().startsWith(translated)) {
+ CharSequence name = file.getName() + (matches == 1 && file.isDirectory() ? separator() : " ");
+ candidates.add(render(file, name).toString());
+ }
+ }
+
+ final int index = buffer.lastIndexOf(separator());
+
+ return index + separator().length();
+ }
+
+ protected CharSequence render(final File file, final CharSequence name) {
+ assert file != null;
+ assert name != null;
+
+ return name;
+ }
+}
diff --git a/src/jline/src/main/java/jline/console/completer/NullCompleter.java b/src/jline/src/main/java/jline/console/completer/NullCompleter.java
new file mode 100644
index 0000000000..872aee7c84
--- /dev/null
+++ b/src/jline/src/main/java/jline/console/completer/NullCompleter.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 jline.console.completer;
+
+import java.util.List;
+
+/**
+ * Null completer.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public final class NullCompleter
+ implements Completer
+{
+ public static final NullCompleter INSTANCE = new NullCompleter();
+
+ public int complete(final String buffer, final int cursor, final List<CharSequence> candidates) {
+ return -1;
+ }
+} \ No newline at end of file
diff --git a/src/jline/src/main/java/jline/console/completer/StringsCompleter.java b/src/jline/src/main/java/jline/console/completer/StringsCompleter.java
new file mode 100644
index 0000000000..afd2abbcd1
--- /dev/null
+++ b/src/jline/src/main/java/jline/console/completer/StringsCompleter.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 jline.console.completer;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+/**
+ * Completer for a set of strings.
+ *
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public class StringsCompleter
+ implements Completer
+{
+ private final SortedSet<String> strings = new TreeSet<String>();
+
+ public StringsCompleter() {
+ // empty
+ }
+
+ public StringsCompleter(final Collection<String> strings) {
+ assert strings != null;
+ getStrings().addAll(strings);
+ }
+
+ public StringsCompleter(final String... strings) {
+ this(Arrays.asList(strings));
+ }
+
+ public Collection<String> getStrings() {
+ return strings;
+ }
+
+ public int complete(final String buffer, final int cursor, final List<CharSequence> candidates) {
+ // buffer could be null
+ assert candidates != null;
+
+ if (buffer == null) {
+ candidates.addAll(strings);
+ }
+ else {
+ for (String match : strings.tailSet(buffer)) {
+ if (!match.startsWith(buffer)) {
+ break;
+ }
+
+ candidates.add(match);
+ }
+ }
+
+ if (candidates.size() == 1) {
+ candidates.set(0, candidates.get(0) + " ");
+ }
+
+ return candidates.isEmpty() ? -1 : 0;
+ }
+} \ No newline at end of file
diff --git a/src/jline/src/main/java/jline/console/completer/package-info.java b/src/jline/src/main/java/jline/console/completer/package-info.java
new file mode 100644
index 0000000000..4f8fc08a76
--- /dev/null
+++ b/src/jline/src/main/java/jline/console/completer/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+/**
+ * Console completer support.
+ *
+ * @since 2.3
+ */
+package jline.console.completer; \ No newline at end of file
diff --git a/src/jline/src/main/java/jline/console/history/FileHistory.java b/src/jline/src/main/java/jline/console/history/FileHistory.java
new file mode 100644
index 0000000000..a32e05ab75
--- /dev/null
+++ b/src/jline/src/main/java/jline/console/history/FileHistory.java
@@ -0,0 +1,106 @@
+/*
+ * 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.console.history;
+
+import jline.internal.Log;
+
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.Flushable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+import java.io.Reader;
+import java.util.ListIterator;
+
+/**
+ * {@link History} using a file for persistent backing.
+ * <p/>
+ * Implementers should install shutdown hook to call {@link FileHistory#flush}
+ * to save history to disk.
+ *
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.0
+ */
+public class FileHistory
+ extends MemoryHistory
+ implements PersistentHistory, Flushable
+{
+ private final File file;
+
+ public FileHistory(final File file) throws IOException {
+ assert file != null;
+ this.file = file;
+ load(file);
+ }
+
+ public File getFile() {
+ return file;
+ }
+
+ public void load(final File file) throws IOException {
+ assert file != null;
+ if (file.exists()) {
+ Log.trace("Loading history from: ", file);
+ load(new FileReader(file));
+ }
+ }
+
+ public void load(final InputStream input) throws IOException {
+ assert input != null;
+ load(new InputStreamReader(input));
+ }
+
+ public void load(final Reader reader) throws IOException {
+ assert reader != null;
+ BufferedReader input = new BufferedReader(reader);
+
+ String item;
+ while ((item = input.readLine()) != null) {
+ add(item);
+ }
+ }
+
+ public void flush() throws IOException {
+ Log.trace("Flushing history");
+
+ if (!file.exists()) {
+ File dir = file.getParentFile();
+ if (!dir.exists() && !dir.mkdirs()) {
+ Log.warn("Failed to create directory: ", dir);
+ }
+ if (!file.createNewFile()) {
+ Log.warn("Failed to create file: ", file);
+ }
+ }
+
+ PrintStream out = new PrintStream(new BufferedOutputStream(new FileOutputStream(file)));
+ try {
+ for (Entry entry : this) {
+ out.println(entry.value());
+ }
+ }
+ finally {
+ out.close();
+ }
+ }
+
+ public void purge() throws IOException {
+ Log.trace("Purging history");
+
+ clear();
+
+ if (!file.delete()) {
+ Log.warn("Failed to delete history file: ", file);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/jline/src/main/java/jline/console/history/History.java b/src/jline/src/main/java/jline/console/history/History.java
new file mode 100644
index 0000000000..9e098c9985
--- /dev/null
+++ b/src/jline/src/main/java/jline/console/history/History.java
@@ -0,0 +1,71 @@
+/*
+ * 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.console.history;
+
+import java.util.Iterator;
+import java.util.ListIterator;
+
+/**
+ * Console history.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public interface History
+ extends Iterable<History.Entry>
+{
+ int size();
+
+ boolean isEmpty();
+
+ int index();
+
+ void clear();
+
+ CharSequence get(int index);
+
+ void add(CharSequence line);
+
+ void replace(CharSequence item);
+
+ //
+ // Entries
+ //
+
+ interface Entry
+ {
+ int index();
+
+ CharSequence value();
+ }
+
+ ListIterator<Entry> entries(int index);
+
+ ListIterator<Entry> entries();
+
+ Iterator<Entry> iterator();
+
+ //
+ // Navigation
+ //
+
+ CharSequence current();
+
+ boolean previous();
+
+ boolean next();
+
+ boolean moveToFirst();
+
+ boolean moveToLast();
+
+ boolean moveTo(int index);
+
+ void moveToEnd();
+}
diff --git a/src/jline/src/main/java/jline/console/history/MemoryHistory.java b/src/jline/src/main/java/jline/console/history/MemoryHistory.java
new file mode 100644
index 0000000000..5b67d8801b
--- /dev/null
+++ b/src/jline/src/main/java/jline/console/history/MemoryHistory.java
@@ -0,0 +1,318 @@
+/*
+ * 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.console.history;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.ListIterator;
+import java.util.NoSuchElementException;
+
+/**
+ * Non-persistent {@link History}.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public class MemoryHistory
+ implements History
+{
+ public static final int DEFAULT_MAX_SIZE = 500;
+
+ private final LinkedList<CharSequence> items = new LinkedList<CharSequence>();
+
+ private int maxSize = DEFAULT_MAX_SIZE;
+
+ private boolean ignoreDuplicates = true;
+
+ private boolean autoTrim = false;
+
+ // NOTE: These are all ideas from looking at the Bash man page:
+
+ // TODO: Add ignore space? (lines starting with a space are ignored)
+
+ // TODO: Add ignore patterns?
+
+ // TODO: Add history timestamp?
+
+ // TODO: Add erase dups?
+
+ private int offset = 0;
+
+ private int index = 0;
+
+ public void setMaxSize(final int maxSize) {
+ this.maxSize = maxSize;
+ maybeResize();
+ }
+
+ public int getMaxSize() {
+ return maxSize;
+ }
+
+ public boolean isIgnoreDuplicates() {
+ return ignoreDuplicates;
+ }
+
+ public void setIgnoreDuplicates(final boolean flag) {
+ this.ignoreDuplicates = flag;
+ }
+
+ public boolean isAutoTrim() {
+ return autoTrim;
+ }
+
+ public void setAutoTrim(final boolean flag) {
+ this.autoTrim = flag;
+ }
+
+ public int size() {
+ return items.size();
+ }
+
+ public boolean isEmpty() {
+ return items.isEmpty();
+ }
+
+ public int index() {
+ return offset + index;
+ }
+
+ public void clear() {
+ items.clear();
+ offset = 0;
+ index = 0;
+ }
+
+ public CharSequence get(final int index) {
+ return items.get(index - offset);
+ }
+
+ public void add(CharSequence item) {
+ assert item != null;
+
+ if (isAutoTrim()) {
+ item = String.valueOf(item).trim();
+ }
+
+ if (isIgnoreDuplicates()) {
+ if (!items.isEmpty() && item.equals(items.getLast())) {
+ return;
+ }
+ }
+
+ items.add(item);
+
+ maybeResize();
+ }
+
+ public void replace(final CharSequence item) {
+ items.removeLast();
+ add(item);
+ }
+
+ private void maybeResize() {
+ while (size() > getMaxSize()) {
+ items.removeFirst();
+ offset++;
+ }
+
+ index = size();
+ }
+
+ public ListIterator<Entry> entries(final int index) {
+ return new EntriesIterator(index - offset);
+ }
+
+ public ListIterator<Entry> entries() {
+ return entries(offset);
+ }
+
+ public Iterator<Entry> iterator() {
+ return entries();
+ }
+
+ private static class EntryImpl
+ implements Entry
+ {
+ private final int index;
+
+ private final CharSequence value;
+
+ public EntryImpl(int index, CharSequence value) {
+ this.index = index;
+ this.value = value;
+ }
+
+ public int index() {
+ return index;
+ }
+
+ public CharSequence value() {
+ return value;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%d: %s", index, value);
+ }
+ }
+
+ private class EntriesIterator
+ implements ListIterator<Entry>
+ {
+ private final ListIterator<CharSequence> source;
+
+ private EntriesIterator(final int index) {
+ source = items.listIterator(index);
+ }
+
+ public Entry next() {
+ if (!source.hasNext()) {
+ throw new NoSuchElementException();
+ }
+ return new EntryImpl(offset + source.nextIndex(), source.next());
+ }
+
+ public Entry previous() {
+ if (!source.hasPrevious()) {
+ throw new NoSuchElementException();
+ }
+ return new EntryImpl(offset + source.previousIndex(), source.previous());
+ }
+
+ public int nextIndex() {
+ return offset + source.nextIndex();
+ }
+
+ public int previousIndex() {
+ return offset + source.previousIndex();
+ }
+
+ public boolean hasNext() {
+ return source.hasNext();
+ }
+
+ public boolean hasPrevious() {
+ return source.hasPrevious();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ public void set(final Entry entry) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void add(final Entry entry) {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ //
+ // Navigation
+ //
+
+ /**
+ * This moves the history to the last entry. This entry is one position
+ * before the moveToEnd() position.
+ *
+ * @return Returns false if there were no history entries or the history
+ * index was already at the last entry.
+ */
+ public boolean moveToLast() {
+ int lastEntry = size() - 1;
+ if (lastEntry >= 0 && lastEntry != index) {
+ index = size() - 1;
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Move to the specified index in the history
+ * @param index
+ * @return
+ */
+ public boolean moveTo(int index) {
+ index -= offset;
+ if (index >= 0 && index < size() ) {
+ this.index = index;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Moves the history index to the first entry.
+ *
+ * @return Return false if there are no entries in the history or if the
+ * history is already at the beginning.
+ */
+ public boolean moveToFirst() {
+ if (size() > 0 && index != 0) {
+ index = 0;
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Move to the end of the history buffer. This will be a blank entry, after
+ * all of the other entries.
+ */
+ public void moveToEnd() {
+ index = size();
+ }
+
+ /**
+ * Return the content of the current buffer.
+ */
+ public CharSequence current() {
+ if (index >= size()) {
+ return "";
+ }
+
+ return items.get(index);
+ }
+
+ /**
+ * Move the pointer to the previous element in the buffer.
+ *
+ * @return true if we successfully went to the previous element
+ */
+ public boolean previous() {
+ if (index <= 0) {
+ return false;
+ }
+
+ index--;
+
+ return true;
+ }
+
+ /**
+ * Move the pointer to the next element in the buffer.
+ *
+ * @return true if we successfully went to the next element
+ */
+ public boolean next() {
+ if (index >= size()) {
+ return false;
+ }
+
+ index++;
+
+ return true;
+ }
+
+
+} \ No newline at end of file
diff --git a/src/jline/src/main/java/jline/console/history/PersistentHistory.java b/src/jline/src/main/java/jline/console/history/PersistentHistory.java
new file mode 100644
index 0000000000..b4cff792e3
--- /dev/null
+++ b/src/jline/src/main/java/jline/console/history/PersistentHistory.java
@@ -0,0 +1,34 @@
+/*
+ * 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.console.history;
+
+import java.io.IOException;
+
+/**
+ * Persistent {@link History}.
+ *
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public interface PersistentHistory
+ extends History
+{
+ /**
+ * Flush all items to persistent storage.
+ *
+ * @throws IOException Flush failed
+ */
+ void flush() throws IOException;
+
+ /**
+ * Purge persistent storage and {@link #clear}.
+ *
+ * @throws IOException Purge failed
+ */
+ void purge() throws IOException;
+} \ No newline at end of file
diff --git a/src/jline/src/main/java/jline/console/history/package-info.java b/src/jline/src/main/java/jline/console/history/package-info.java
new file mode 100644
index 0000000000..d001133efb
--- /dev/null
+++ b/src/jline/src/main/java/jline/console/history/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2009 the original author(s).
+ *
+ * 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.
+ */
+
+/**
+ * Console history support.
+ *
+ * @since 2.0
+ */
+package jline.console.history; \ No newline at end of file
diff --git a/src/jline/src/main/java/jline/console/package-info.java b/src/jline/src/main/java/jline/console/package-info.java
new file mode 100644
index 0000000000..ea2c05651d
--- /dev/null
+++ b/src/jline/src/main/java/jline/console/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2009 the original author(s).
+ *
+ * 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.
+ */
+
+/**
+ * Console support.
+ *
+ * @since 2.0
+ */
+package jline.console; \ No newline at end of file
diff --git a/src/jline/src/main/java/jline/internal/Configuration.java b/src/jline/src/main/java/jline/internal/Configuration.java
new file mode 100644
index 0000000000..6c6e0eb843
--- /dev/null
+++ b/src/jline/src/main/java/jline/internal/Configuration.java
@@ -0,0 +1,127 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 jline.internal;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+/**
+ * Provides access to configuration values.
+ *
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.4
+ */
+public final class Configuration
+{
+ public static final String JLINE_RC = ".jline.rc";
+
+ private static final Properties userprops;
+
+ static {
+ Properties props = new Properties();
+
+ File file = new File(getUserHome(), JLINE_RC);
+ if (file.exists() && file.canRead()) {
+ try {
+ InputStream input = new BufferedInputStream(new FileInputStream(file));
+ try {
+ props.load(input);
+ Log.debug("Loaded user configuration: ", file);
+ }
+ finally {
+ input.close();
+ }
+ }
+ catch (IOException e) {
+ Log.warn("Unable to read user configuration: ", file, e);
+ }
+ }
+ else {
+ Log.trace("User configuration file missing or unreadable: ", file);
+ }
+
+ userprops = props;
+ }
+
+ private static boolean isEmpty(final String value) {
+ return value == null || value.trim().length() == 0;
+ }
+
+ public static String getString(final String name, final String defaultValue) {
+ assert name != null;
+
+ String value;
+
+ // Check sysprops first, it always wins
+ value = System.getProperty(name);
+
+ if (isEmpty(value)) {
+ // Next try userprops
+ value = userprops.getProperty(name);
+
+ if (isEmpty(value)) {
+ // else use the default
+ value = defaultValue;
+ }
+ }
+
+ return value;
+ }
+
+ public static String getString(final String name) {
+ return getString(name, null);
+ }
+
+ public static Boolean getBoolean(final String name, final Boolean defaultValue) {
+ String value = getString(name);
+ if (isEmpty(value)) {
+ return defaultValue;
+ }
+ return Boolean.valueOf(value);
+ }
+
+ public static Boolean getBoolean(final String name) {
+ return getBoolean(name, null);
+ }
+
+ //
+ // System property helpers
+ //
+
+ public static File getUserHome() {
+ return new File(System.getProperty("user.home"));
+ }
+
+ public static String getOsName() {
+ return System.getProperty("os.name").toLowerCase();
+ }
+
+ public static String getFileEncoding() {
+ return System.getProperty("file.encoding");
+ }
+
+ public static String getInputEncoding() {
+ return System.getProperty("input.encoding", "UTF-8");
+ }
+} \ No newline at end of file
diff --git a/src/jline/src/main/java/jline/internal/Log.java b/src/jline/src/main/java/jline/internal/Log.java
new file mode 100644
index 0000000000..deb34c89ae
--- /dev/null
+++ b/src/jline/src/main/java/jline/internal/Log.java
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 jline.internal;
+
+import java.io.PrintStream;
+
+/**
+ * Internal logger.
+ *
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.0
+ */
+public final class Log
+{
+ ///CLOVER:OFF
+
+ public static enum Level
+ {
+ TRACE,
+ DEBUG,
+ INFO,
+ WARN,
+ ERROR
+ }
+
+ @SuppressWarnings({"StringConcatenation"})
+ public static final boolean DEBUG = Boolean.getBoolean(Log.class.getName() + ".debug");
+
+ @SuppressWarnings({"StringConcatenation"})
+ public static final boolean TRACE = Boolean.getBoolean(Log.class.getName() + ".trace");
+
+ private static PrintStream output = System.err;
+
+ public static PrintStream getOutput() {
+ return output;
+ }
+
+ public static void setOutput(final PrintStream out) {
+ assert out != null;
+ output = out;
+ }
+
+ private static void print(final Object message) {
+ if (message instanceof Throwable) {
+ ((Throwable) message).printStackTrace();
+ }
+ else if (message.getClass().isArray()) {
+ Object[] array = (Object[]) message;
+
+ for (int i = 0; i < array.length; i++) {
+ output.print(array[i]);
+ if (i + 1 < array.length) {
+ output.print(",");
+ }
+ }
+ }
+ else {
+ output.print(message);
+ }
+ }
+
+ private static void log(final Level level, final Object[] messages) {
+ //noinspection SynchronizeOnNonFinalField
+ synchronized (output) {
+ output.format("[%s] ", level);
+
+ for (Object message : messages) {
+ print(message);
+ }
+
+ output.println();
+ output.flush();
+ }
+ }
+
+ public static void trace(final Object... messages) {
+ if (TRACE) {
+ log(Level.TRACE, messages);
+ }
+ }
+
+ public static void debug(final Object... messages) {
+ if (TRACE || DEBUG) {
+ log(Level.DEBUG, messages);
+ }
+ }
+
+ public static void warn(final Object... messages) {
+ log(Level.WARN, messages);
+ }
+
+ public static void error(final Object... messages) {
+ log(Level.ERROR, messages);
+ }
+} \ No newline at end of file
diff --git a/src/jline/src/main/java/jline/internal/ReplayPrefixOneCharInputStream.java b/src/jline/src/main/java/jline/internal/ReplayPrefixOneCharInputStream.java
new file mode 100644
index 0000000000..ae54fbb329
--- /dev/null
+++ b/src/jline/src/main/java/jline/internal/ReplayPrefixOneCharInputStream.java
@@ -0,0 +1,95 @@
+package jline.internal;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.MessageFormat;
+
+/**
+ * This is awkward and inefficient, but probably the minimal way to add UTF-8 support to JLine
+ *
+ * @author <a href="mailto:Marc.Herbert@continuent.com">Marc Herbert</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.0
+ */
+public final class ReplayPrefixOneCharInputStream
+ extends InputStream
+{
+ private byte firstByte;
+
+ private int byteLength;
+
+ private InputStream wrappedStream;
+
+ private int byteRead;
+
+ private final String encoding;
+
+ public ReplayPrefixOneCharInputStream(final String encoding) {
+ assert encoding != null;
+ this.encoding = encoding;
+ }
+
+ public String getEncoding() {
+ return encoding;
+ }
+
+ public void setInput(final int recorded, final InputStream wrapped) throws IOException {
+ this.byteRead = 0;
+ this.firstByte = (byte) recorded;
+ this.wrappedStream = wrapped;
+
+ byteLength = 1;
+ if (encoding.equalsIgnoreCase("UTF-8")) {
+ setInputUTF8(recorded, wrapped);
+ }
+ else if (encoding.equalsIgnoreCase("UTF-16")) {
+ byteLength = 2;
+ }
+ else if (encoding.equalsIgnoreCase("UTF-32")) {
+ byteLength = 4;
+ }
+ }
+
+
+ public void setInputUTF8(final int recorded, final InputStream wrapped) throws IOException {
+ // 110yyyyy 10zzzzzz
+ if ((firstByte & (byte) 0xE0) == (byte) 0xC0) {
+ this.byteLength = 2;
+ }
+ // 1110xxxx 10yyyyyy 10zzzzzz
+ else if ((firstByte & (byte) 0xF0) == (byte) 0xE0) {
+ this.byteLength = 3;
+ }
+ // 11110www 10xxxxxx 10yyyyyy 10zzzzzz
+ else if ((firstByte & (byte) 0xF8) == (byte) 0xF0) {
+ this.byteLength = 4;
+ }
+ else {
+ throw new IOException(MessageFormat.format("Invalid UTF-8 first byte: {0}", firstByte));
+ }
+ }
+
+ public int read() throws IOException {
+ if (available() == 0) {
+ return -1;
+ }
+
+ byteRead++;
+
+ if (byteRead == 1) {
+ return firstByte;
+ }
+
+ return wrappedStream.read();
+ }
+
+ /**
+ * InputStreamReader is greedy and will try to read bytes in advance. We
+ * do NOT want this to happen since we use a temporary/"losing bytes"
+ * InputStreamReader above, that's why we hide the real
+ * wrappedStream.available() here.
+ */
+ public int available() {
+ return byteLength - byteRead;
+ }
+} \ No newline at end of file
diff --git a/src/jline/src/main/java/jline/internal/TerminalLineSettings.java b/src/jline/src/main/java/jline/internal/TerminalLineSettings.java
new file mode 100644
index 0000000000..4b4b957649
--- /dev/null
+++ b/src/jline/src/main/java/jline/internal/TerminalLineSettings.java
@@ -0,0 +1,217 @@
+/*
+ * 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.internal;
+
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.text.MessageFormat;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Provides access to terminal line settings via <tt>stty</tt>.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:dwkemp@gmail.com">Dale Kemp</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @author <a href="mailto:jbonofre@apache.org">Jean-Baptiste Onofré</a>
+ * @since 2.0
+ */
+public final class TerminalLineSettings
+{
+ public static final String JLINE_STTY = "jline.stty";
+
+ public static final String DEFAULT_STTY = "stty";
+
+ public static final String JLINE_SH = "jline.sh";
+
+ public static final String DEFAULT_SH = "sh";
+
+ private static String sttyCommand = Configuration.getString(JLINE_STTY, DEFAULT_STTY);
+
+ private static String shCommand = Configuration.getString(JLINE_SH, DEFAULT_SH);
+
+ private String config;
+
+ private long configLastFetched;
+
+ public TerminalLineSettings() throws IOException, InterruptedException {
+ config = get("-a");
+ configLastFetched = System.currentTimeMillis();
+
+ Log.debug("Config: ", config);
+
+ // sanity check
+ if (config.length() == 0) {
+ throw new IOException(MessageFormat.format("Unrecognized stty code: {0}", config));
+ }
+ }
+
+ public String getConfig() {
+ return config;
+ }
+
+ public void restore() throws IOException, InterruptedException {
+ set("sane");
+ }
+
+ public String get(final String args) throws IOException, InterruptedException {
+ return stty(args);
+ }
+
+ public void set(final String args) throws IOException, InterruptedException {
+ stty(args);
+ }
+
+ /**
+ * <p>
+ * Get the value of a stty property, including the management of a cache.
+ * </p>
+ *
+ * @param name the stty property.
+ * @return the stty property value.
+ */
+ public int getProperty(String name) {
+ assert name != null;
+ try {
+ // tty properties are cached so we don't have to worry too much about getting term widht/height
+ if (config == null || System.currentTimeMillis() - configLastFetched > 1000 ) {
+ config = get("-a");
+ configLastFetched = System.currentTimeMillis();
+ }
+ return this.getProperty(name, config);
+ } catch (Exception e) {
+ Log.warn("Failed to query stty ", name, e);
+ return -1;
+ }
+ }
+
+ /**
+ * <p>
+ * Parses a stty output (provided by stty -a) and return the value of a given property.
+ * </p>
+ *
+ * @param name property name.
+ * @param stty string resulting of stty -a execution.
+ * @return value of the given property.
+ */
+ protected int getProperty(String name, String stty) {
+ // try the first kind of regex
+ Pattern pattern = Pattern.compile(name + "\\s+=\\s+([^;]*)[;\\n\\r]");
+ Matcher matcher = pattern.matcher(stty);
+ if (!matcher.find()) {
+ // try a second kind of regex
+ pattern = Pattern.compile(name + "\\s+([^;]*)[;\\n\\r]");
+ matcher = pattern.matcher(stty);
+ if (!matcher.find()) {
+ // try a second try of regex
+ pattern = Pattern.compile("(\\S*)\\s+" + name);
+ matcher = pattern.matcher(stty);
+ if (!matcher.find()) {
+ return -1;
+ }
+ }
+ }
+ return parseControlChar(matcher.group(1));
+ }
+
+ private int parseControlChar(String str) {
+ // under
+ if ("<undef>".equals(str)) {
+ return -1;
+ }
+ // octal
+ if (str.charAt(0) == '0') {
+ return Integer.parseInt(str, 8);
+ }
+ // decimal
+ if (str.charAt(0) >= '1' && str.charAt(0) <= '9') {
+ return Integer.parseInt(str, 10);
+ }
+ // control char
+ if (str.charAt(0) == '^') {
+ if (str.charAt(1) == '?') {
+ return 127;
+ } else {
+ return str.charAt(1) - 64;
+ }
+ } else if (str.charAt(0) == 'M' && str.charAt(1) == '-') {
+ if (str.charAt(2) == '^') {
+ if (str.charAt(3) == '?') {
+ return 127 + 128;
+ } else {
+ return str.charAt(3) - 64 + 128;
+ }
+ } else {
+ return str.charAt(2) + 128;
+ }
+ } else {
+ return str.charAt(0);
+ }
+ }
+
+ private static String stty(final String args) throws IOException, InterruptedException {
+ assert args != null;
+ return exec(String.format("%s %s < /dev/tty", sttyCommand, args));
+ }
+
+ private static String exec(final String cmd) throws IOException, InterruptedException {
+ assert cmd != null;
+ return exec(shCommand, "-c", cmd);
+ }
+
+ private static String exec(final String... cmd) throws IOException, InterruptedException {
+ assert cmd != null;
+
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+
+ Log.trace("Running: ", cmd);
+
+ Process p = Runtime.getRuntime().exec(cmd);
+
+ InputStream in = null;
+ InputStream err = null;
+ OutputStream out = null;
+ try {
+ int c;
+ in = p.getInputStream();
+ while ((c = in.read()) != -1) {
+ bout.write(c);
+ }
+ err = p.getErrorStream();
+ while ((c = err.read()) != -1) {
+ bout.write(c);
+ }
+ out = p.getOutputStream();
+ p.waitFor();
+ }
+ finally {
+ close(in, out, err);
+ }
+
+ String result = bout.toString();
+
+ Log.trace("Result: ", result);
+
+ return result;
+ }
+
+ private static void close(final Closeable... closeables) {
+ for (Closeable c : closeables) {
+ try {
+ c.close();
+ }
+ catch (Exception e) {
+ // Ignore
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/jline/src/main/java/jline/internal/package-info.java b/src/jline/src/main/java/jline/internal/package-info.java
new file mode 100644
index 0000000000..e15ddfb25c
--- /dev/null
+++ b/src/jline/src/main/java/jline/internal/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2009 the original author(s).
+ *
+ * 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.
+ */
+
+/**
+ * Internal support.
+ *
+ * @since 2.0
+ */
+package jline.internal; \ No newline at end of file
diff --git a/src/jline/src/main/java/jline/package-info.java b/src/jline/src/main/java/jline/package-info.java
new file mode 100644
index 0000000000..78924e262a
--- /dev/null
+++ b/src/jline/src/main/java/jline/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+/**
+ * JLine 2.
+ *
+ * @since 2.0
+ */
+package jline; \ No newline at end of file
diff --git a/src/jline/src/main/java/jline/package.html b/src/jline/src/main/java/jline/package.html
deleted file mode 100644
index c80743165a..0000000000
--- a/src/jline/src/main/java/jline/package.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<body>
-<p>
-The core JLine API. The central class is
-<a href="ConsoleReader">jline.ConsoleReader</a>}, which
-is a reader for obtaining input from an arbitrary
-InputStream (usually <em>System.in</em>).
-</p>
-</body>
-
diff --git a/src/jline/src/main/native/Makefile b/src/jline/src/main/native/Makefile
deleted file mode 100644
index c620814825..0000000000
--- a/src/jline/src/main/native/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-#export PATH=${PATH}:/usr/lib/gcc-lib/i686-pc-cygwin/3.3.3
-JDK='/C/Program Files/Java/jdk1.5.0/'
-
-native:
- #gcc -I'C:/Program Files/Java/'*'/include/' -I'C:/Program Files/Java/'*'/include//win32/' -mno-cygwin -Wl,--add-stdcall-alias -shared -o jline.dll jline_WindowsTerminal.c
- gcc -L /usr/lib/mingw/ -I${JDK}/include -I${JDK}/include/win32 -mwindows -mno-cygwin -Wl,--add-stdcall-alias -shared -o jline.dll jline_WindowsTerminal.c
diff --git a/src/jline/src/main/native/jline_WindowsTerminal.c b/src/jline/src/main/native/jline_WindowsTerminal.c
deleted file mode 100644
index f020cae52b..0000000000
--- a/src/jline/src/main/native/jline_WindowsTerminal.c
+++ /dev/null
@@ -1,57 +0,0 @@
-#include "jline_WindowsTerminal.h"
-#include <windows.h>
-
-JNIEXPORT jint JNICALL Java_jline_WindowsTerminal_getConsoleMode
- (JNIEnv *env, jobject ob)
-{
- DWORD mode;
- HANDLE hConsole = GetStdHandle (STD_INPUT_HANDLE);
-
- if (hConsole == INVALID_HANDLE_VALUE)
- return -1;
-
- if (!GetConsoleMode (hConsole, &mode))
- return -1;
-
- // CloseHandle (hConsole);
-
- // printf ("JNI get mode=%d\n", mode);
- return mode;
-}
-
-JNIEXPORT void JNICALL Java_jline_WindowsTerminal_setConsoleMode
- (JNIEnv *env, jobject ob, jint mode)
-{
- DWORD m = (DWORD)mode;
- HANDLE hConsole = GetStdHandle (STD_INPUT_HANDLE);
-
- if (hConsole == INVALID_HANDLE_VALUE)
- return;
-
- // printf ("JNI set mode=%d\n", m);
- SetConsoleMode (hConsole, m);
- // CloseHandle (hConsole);
-}
-
-JNIEXPORT jint JNICALL Java_jline_WindowsTerminal_readByte (JNIEnv * env, jclass class)
-{
- return getch ();
-}
-
-JNIEXPORT jint JNICALL Java_jline_WindowsTerminal_getWindowsTerminalWidth (JNIEnv * env, jclass class)
-{
- HANDLE inputHandle = GetStdHandle (STD_INPUT_HANDLE);
- HANDLE outputHandle = GetStdHandle (STD_OUTPUT_HANDLE);
- PCONSOLE_SCREEN_BUFFER_INFO info = malloc (sizeof (CONSOLE_SCREEN_BUFFER_INFO));
- GetConsoleScreenBufferInfo (outputHandle, info);
- return info->srWindow.Right - info->srWindow.Left+1;
-}
-
-JNIEXPORT jint JNICALL Java_jline_WindowsTerminal_getWindowsTerminalHeight (JNIEnv * env, jclass class)
-{
- HANDLE inputHandle = GetStdHandle (STD_INPUT_HANDLE);
- HANDLE outputHandle = GetStdHandle (STD_OUTPUT_HANDLE);
- PCONSOLE_SCREEN_BUFFER_INFO info = malloc (sizeof (CONSOLE_SCREEN_BUFFER_INFO));
- GetConsoleScreenBufferInfo (outputHandle, info);
- return info->srWindow.Bottom - info->srWindow.Top+1;
-}
diff --git a/src/jline/src/main/native/jline_WindowsTerminal.h b/src/jline/src/main/native/jline_WindowsTerminal.h
deleted file mode 100644
index 5078b939cb..0000000000
--- a/src/jline/src/main/native/jline_WindowsTerminal.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/* DO NOT EDIT THIS FILE - it is machine generated */
-#include <jni.h>
-/* Header for class jline_WindowsTerminal */
-
-#ifndef _Included_jline_WindowsTerminal
-#define _Included_jline_WindowsTerminal
-#ifdef __cplusplus
-extern "C" {
-#endif
-/* Inaccessible static: term */
-#undef jline_WindowsTerminal_ENABLE_LINE_INPUT
-#define jline_WindowsTerminal_ENABLE_LINE_INPUT 2L
-#undef jline_WindowsTerminal_ENABLE_ECHO_INPUT
-#define jline_WindowsTerminal_ENABLE_ECHO_INPUT 4L
-#undef jline_WindowsTerminal_ENABLE_PROCESSED_INPUT
-#define jline_WindowsTerminal_ENABLE_PROCESSED_INPUT 1L
-#undef jline_WindowsTerminal_ENABLE_WINDOW_INPUT
-#define jline_WindowsTerminal_ENABLE_WINDOW_INPUT 8L
-#undef jline_WindowsTerminal_ENABLE_MOUSE_INPUT
-#define jline_WindowsTerminal_ENABLE_MOUSE_INPUT 16L
-#undef jline_WindowsTerminal_ENABLE_PROCESSED_OUTPUT
-#define jline_WindowsTerminal_ENABLE_PROCESSED_OUTPUT 1L
-#undef jline_WindowsTerminal_ENABLE_WRAP_AT_EOL_OUTPUT
-#define jline_WindowsTerminal_ENABLE_WRAP_AT_EOL_OUTPUT 2L
-/*
- * Class: jline_WindowsTerminal
- * Method: getConsoleMode
- * Signature: ()I
- */
-JNIEXPORT jint JNICALL Java_jline_WindowsTerminal_getConsoleMode
- (JNIEnv *, jobject);
-
-/*
- * Class: jline_WindowsTerminal
- * Method: setConsoleMode
- * Signature: (I)V
- */
-JNIEXPORT void JNICALL Java_jline_WindowsTerminal_setConsoleMode
- (JNIEnv *, jobject, jint);
-
-/*
- * Class: jline_WindowsTerminal
- * Method: readByte
- * Signature: ()I
- */
-JNIEXPORT jint JNICALL Java_jline_WindowsTerminal_readByte
- (JNIEnv *, jobject);
-
-/*
- * Class: jline_WindowsTerminal
- * Method: getWindowsTerminalWidth
- * Signature: ()I
- */
-JNIEXPORT jint JNICALL Java_jline_WindowsTerminal_getWindowsTerminalWidth
- (JNIEnv *, jobject);
-
-/*
- * Class: jline_WindowsTerminal
- * Method: getWindowsTerminalHeight
- * Signature: ()I
- */
-JNIEXPORT jint JNICALL Java_jline_WindowsTerminal_getWindowsTerminalHeight
- (JNIEnv *, jobject);
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/src/jline/src/main/resources/jline/CandidateListCompletionHandler.properties b/src/jline/src/main/resources/jline/CandidateListCompletionHandler.properties
deleted file mode 100644
index 18ee221cc9..0000000000
--- a/src/jline/src/main/resources/jline/CandidateListCompletionHandler.properties
+++ /dev/null
@@ -1,5 +0,0 @@
-display-candidates: Display all {0} possibilities? (y or n)
-display-candidates-yes: y
-display-candidates-no: n
-display-more: --More--
-
diff --git a/src/jline/src/main/resources/jline/console/completer/CandidateListCompletionHandler.properties b/src/jline/src/main/resources/jline/console/completer/CandidateListCompletionHandler.properties
new file mode 100644
index 0000000000..fd097efb8a
--- /dev/null
+++ b/src/jline/src/main/resources/jline/console/completer/CandidateListCompletionHandler.properties
@@ -0,0 +1,4 @@
+DISPLAY_CANDIDATES=Display all %d possibilities? (y or n)
+DISPLAY_CANDIDATES_YES=y
+DISPLAY_CANDIDATES_NO=n
+DISPLAY_MORE=--More--
diff --git a/src/jline/src/main/resources/jline/jline32.dll b/src/jline/src/main/resources/jline/jline32.dll
deleted file mode 100644
index a0d3b117ce..0000000000
--- a/src/jline/src/main/resources/jline/jline32.dll
+++ /dev/null
Binary files differ
diff --git a/src/jline/src/main/resources/jline/jline64.dll b/src/jline/src/main/resources/jline/jline64.dll
deleted file mode 100644
index 922d6b01c5..0000000000
--- a/src/jline/src/main/resources/jline/jline64.dll
+++ /dev/null
Binary files differ
diff --git a/src/jline/src/main/resources/jline/keybindings.properties b/src/jline/src/main/resources/jline/keybindings.properties
index 6f13615d84..610a1626aa 100644
--- a/src/jline/src/main/resources/jline/keybindings.properties
+++ b/src/jline/src/main/resources/jline/keybindings.properties
@@ -1,62 +1,65 @@
# Keybinding mapping for JLine. The format is:
-# [key code]: [logical operation]
-
-# CTRL-B: move to the previous character
-2: PREV_CHAR
-
-# CTRL-G: move to the previous word
-7: PREV_WORD
-
-# CTRL-F: move to the next character
-6: NEXT_CHAR
+# [key code]=[logical operation]
# CTRL-A: move to the beginning of the line
-1: MOVE_TO_BEG
+1=MOVE_TO_BEG
+
+# CTRL-B: move to the previous character
+2=PREV_CHAR
# CTRL-D: close out the input stream
-4: EXIT
+4=EXIT
# CTRL-E: move the cursor to the end of the line
-5: MOVE_TO_END
+5=MOVE_TO_END
+
+# CTRL-F: move to the next character
+6=NEXT_CHAR
+
+# CTRL-G: abort
+7=ABORT
# BACKSPACE, CTRL-H: delete the previous character
# 8 is the ASCII code for backspace and therefor
# deleting the previous character
-8: DELETE_PREV_CHAR
+8=DELETE_PREV_CHAR
# TAB, CTRL-I: signal that console completion should be attempted
-9: COMPLETE
+9=COMPLETE
# CTRL-J, CTRL-M: newline
-10: NEWLINE
+10=NEWLINE
# CTRL-K: erase the current line
-11: KILL_LINE
-
-# ENTER: newline
-13: NEWLINE
+11=KILL_LINE
# CTRL-L: clear screen
-12: CLEAR_SCREEN
+12=CLEAR_SCREEN
+
+# ENTER: newline
+13=NEWLINE
# CTRL-N: scroll to the next element in the history buffer
-14: NEXT_HISTORY
+14=NEXT_HISTORY
+
+# CTRL-O: move to the previous word
+15=PREV_WORD
# CTRL-P: scroll to the previous element in the history buffer
-16: PREV_HISTORY
+16=PREV_HISTORY
# CTRL-R: redraw the current line
-18: REDISPLAY
+18=SEARCH_PREV
# CTRL-U: delete all the characters before the cursor position
-21: KILL_LINE_PREV
+21=KILL_LINE_PREV
# CTRL-V: paste the contents of the clipboard (useful for Windows terminal)
-22: PASTE
+22=PASTE
# CTRL-W: delete the word directly before the cursor
-23: DELETE_PREV_WORD
+23=DELETE_PREV_WORD
-# DELETE, CTRL-?: delete the previous character
+# DELETE, CTRL-?: delete the next character
# 127 is the ASCII code for delete
-127: DELETE_PREV_CHAR
+127=DELETE_NEXT_CHAR
diff --git a/src/jline/src/main/resources/jline/windowsbindings.properties b/src/jline/src/main/resources/jline/windowsbindings.properties
index 51ba4919c9..340b5aa5b9 100644
--- a/src/jline/src/main/resources/jline/windowsbindings.properties
+++ b/src/jline/src/main/resources/jline/windowsbindings.properties
@@ -1,65 +1,71 @@
# Keybinding mapping for JLine. The format is:
-# [key code]: [logical operation]
+# [key code]=[logical operation]
+
+# CTRL-A: move to the beginning of the line
+1=MOVE_TO_BEG
# CTRL-B: move to the previous character
-2: PREV_CHAR
+2=PREV_CHAR
# CTRL-C: toggle overtype mode (frankly, I wasn't sure where to bind this)
-3: INSERT
-
-# CTRL-G: move to the previous word
-7: PREV_WORD
-
-# CTRL-F: move to the next character
-6: NEXT_CHAR
-
-# CTRL-A: move to the beginning of the line
-1: MOVE_TO_BEG
+3=INSERT
# CTRL-D: close out the input stream
-4: EXIT
+4=EXIT
# CTRL-E: move the cursor to the end of the line
-5: MOVE_TO_END
+5=MOVE_TO_END
+
+# CTRL-F: move to the next character
+6=NEXT_CHAR
+
+# CTRL-G: move to the previous word
+7=ABORT
# CTRL-H: delete the previous character
-8: DELETE_PREV_CHAR
+8=DELETE_PREV_CHAR
# TAB, CTRL-I: signal that console completion should be attempted
-9: COMPLETE
+9=COMPLETE
# CTRL-J, CTRL-M: newline
-10: NEWLINE
+10=NEWLINE
-# CTRL-K: Vertical tab - on windows we'll move to the start of the history
-11: START_OF_HISTORY
+# CTRL-K: erase the current line
+11=KILL_LINE
-# ENTER: newline
-13: NEWLINE
+# CTRL-L: clear screen
+12=CLEAR_SCREEN
-# CTRL-L: Form feed - on windows, we'll move to the end of the history
-12: END_OF_HISTORY
+# ENTER: newline
+13=NEWLINE
# CTRL-N: scroll to the next element in the history buffer
-14: NEXT_HISTORY
+14=NEXT_HISTORY
+
+# CTRL-O: move to the previous word
+15=PREV_WORD
# CTRL-P: scroll to the previous element in the history buffer
-16: PREV_HISTORY
+16=PREV_HISTORY
+
+# CTRL-R: search backwards in history
+18=SEARCH_PREV
-# CTRL-R: redraw the current line
-18: REDISPLAY
+# CTRL-S: Move to the end of the history
+19=END_OF_HISTORY
# CTRL-U: delete all the characters before the cursor position
-21: KILL_LINE_PREV
+21=KILL_LINE_PREV
# CTRL-V: paste the contents of the clipboard (useful for Windows terminal)
-22: PASTE
+22=PASTE
# CTRL-W: delete the word directly before the cursor
-23: DELETE_PREV_WORD
+23=DELETE_PREV_WORD
# CTRL-[: escape - clear the current line.
-27: CLEAR_LINE
+27=CLEAR_LINE
# CTRL-?: delete the previous character
-127: DELETE_NEXT_CHAR
+127=DELETE_NEXT_CHAR
diff --git a/src/jline/src/site/apt/building.apt b/src/jline/src/site/apt/building.apt
deleted file mode 100644
index a09137873a..0000000000
--- a/src/jline/src/site/apt/building.apt
+++ /dev/null
@@ -1,39 +0,0 @@
- ------
- jline
- ------
-
-Building JLine
-
- Building JLine requires an installation of {{{http://maven.apache.org/}Maven 2}}.
-
- Source code is included in the JLine distribution, or can be checked out from CVS as described {{{source-repository.html}here}}.
-
-Maven Repository
-
- If you are using Maven 2, you can add JLine as an automatic dependency by adding the following to your project's pom.xml file:
-
-+--------------------------------+
-
- <repositories>
- ...
- <repository>
- <id>jline</id>
- <name>JLine Project Repository</name>
- <url>http://jline.sourceforge.net/m2repo</url>
- </repository>
- </repositories>
- <dependencies>
- ...
- <dependency>
- <groupId>jline</groupId>
- <artifactId>jline</artifactId>
- <version>0.9.9</version>
- </dependency>
- </dependencies>
-
-+--------------------------------+
-
-
-
-
-
diff --git a/src/jline/src/site/apt/downloads.apt b/src/jline/src/site/apt/downloads.apt
deleted file mode 100644
index de90db9595..0000000000
--- a/src/jline/src/site/apt/downloads.apt
+++ /dev/null
@@ -1,39 +0,0 @@
- ------
- jline
- ------
-
-Download JLine
-
- JLine packages can be downloaded from:
-
- {{{http://sourceforge.net/project/showfiles.php?group_id=64033}http://sourceforge.net/project/showfiles.php?group_id=64033}}
-
-
-Maven Repository
-
- If you are using Maven 2, you can add JLine as an automatic dependency by adding the following to your project's pom.xml file:
-
-+--------------------------------+
-
- <repositories>
- ...
- <repository>
- <id>jline</id>
- <name>JLine Project Repository</name>
- <url>http://jline.sourceforge.net/m2repo</url>
- </repository>
- </repositories>
- <dependencies>
- ...
- <dependency>
- <groupId>jline</groupId>
- <artifactId>jline</artifactId>
- <version>0.9.9</version>
- </dependency>
- </dependencies>
-
-+--------------------------------+
-
-
-
-
diff --git a/src/jline/src/site/docbook/index.xml b/src/jline/src/site/docbook/index.xml
deleted file mode 100644
index c68b42f1e9..0000000000
--- a/src/jline/src/site/docbook/index.xml
+++ /dev/null
@@ -1,492 +0,0 @@
-<!DOCTYPE book
- PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
- "http://www.docbook.org/xml/4.1.2/docbookx.dtd">
-
-<book>
- <bookinfo>
- <title>
- JLine
- </title>
- <copyright>
- <year>2002, 2003, 2004, 2005, 2006, 2007</year>
- <holder>Marc Prud'hommeaux</holder>
- </copyright>
- </bookinfo>
- <part id="manual">
- <title>JLine Manual</title>
-
- <chapter id="introduction">
- <title>Introduction</title>
- <para>
- JLine is a Java library for handling console input.
- It is similar in functionality to BSD editline and GNU
- readline. People familiar with the readline/editline
- capabilities for modern shells (such as bash and tcsh) will
- find most of the command editing features of JLine to
- be familiar.
- </para>
- </chapter>
-
- <chapter id="license">
- <title>License and Terms of Use</title>
- <para>
- JLine is distributed under the BSD license, meaning that
- you are completely free to redistribute, modify, or sell it
- with almost no restrictins.
- For more information on the BSD license, see
- <ulink url="http://www.opensource.org/licenses/bsd-license.php"
- >http://www.opensource.org/licenses/bsd-license.php</ulink>.
- </para>
- <para>
- For information on obtaining the software under another
- license, contact the copyright holder:
- <ulink url="mailto:mwp1@cornell.edu">mwp1@cornell.edu</ulink>.
- </para>
- </chapter>
-
- <chapter id="obtaining">
- <title>Obtaining JLine</title>
- <para>
- JLine is hosted on SourceForge, and is located at
- <ulink url="http://jline.sf.net">http://jline.sf.net</ulink>.
- The latest release can be downloaded from
- <ulink url=
- "http://sourceforge.net/project/showfiles.php?group_id=64033">http://sourceforge.net/project/showfiles.php?group_id=64033</ulink>.
- API documentation can be found in the
- <ulink url="apidocs">apidocs/</ulink> directory.
- </para>
- </chapter>
-
- <chapter id="installation">
- <title>Installation</title>
- <para>
- JLine has no library dependencies, aside from a JVM
- of version 1.2 or higher. To install JLine, download the
- <filename>jline.jar</filename> file, and either place it in
- the system-wide java extensions directory, or
- manually add it to your
- <computeroutput>CLASSPATH</computeroutput>.
- The extensions directory is dependent on your operating
- system. Some few examples are:
- <itemizedlist>
- <listitem><para>
- Macintosh OS X:
- <filename>/Library/Java/Extensions</filename> or
- <filename>/System/Library/Java/Extensions</filename>
- </para></listitem>
- <listitem><para>
- Microsoft Windows:
- <filename>JAVAHOME\jre\lib\ext</filename>
- (example:
- <filename>C:\j2sdk1.4.1_03\jre\lib\ext</filename>)
- </para></listitem>
- <listitem><para>
- UNIX Systems:
- <filename>JAVAHOME/jre/lib/ext</filename>
- (example:
- <filename>/usr/local/java/jre/lib/ext</filename>)
- </para></listitem>
- </itemizedlist>
- </para>
- <para>
- JLine is not 100% pure Java. On Windows, it relies on a
- <filename>.dll</filename> file to initialize the terminal
- to be able to accept unbuffered input. However,
- no installation is necessary for this: when initialized,
- JLine will dynamically extract the DLL to a temporary
- directory and load it. For more details, see the
- documentation for the <classname>jline.WindowsTerminal</classname> class.
- </para>
- <para>
- On UNIX systems (including Macintosh OS X), JLine will
- execute the <filename>stty</filename> command to initialize
- the terminal to allow unbuffered input. For more details,
- see the documentation for the <classname>jline.UnixTerminal</classname> class.
- </para>
- <para>
- For both Windows and UNIX systems, JLine will fail to
- initialize if it is run inside a strict security manager
- that does not allow the loading of libraries, writing
- to the file system, or executing external programs. However,
- for most console applications, this is usually not the case.
- </para>
- </chapter>
- <chapter id="supported_platforms">
- <title>Supported Platforms</title>
- <para>
- JLine should work on any Windows system, or any
- minimally compliant POSIX system (includling Linux and
- Macintosh OS X).
- </para>
- <para>
- The platforms on which JLine has been confirmed to work are:
- <itemizedlist>
- <listitem><para>
- Microsoft Windows XP
- </para></listitem>
- <listitem><para>
- RedHat Linux 9.0
- </para></listitem>
- <listitem><para>
- Debian Linux 3.0
- </para></listitem>
- <listitem><para>
- Macintosh OS X 10.3
- </para></listitem>
- </itemizedlist>
- </para>
- <para>
- Please report successes or failures to the author:
- <ulink url="mailto:mwp1@cornell.edu">mwp1@cornell.edu</ulink>.
- </para>
- </chapter>
- <chapter id="features">
- <title>Features</title>
- <section id="features_history">
- <title>Command History</title>
- <para>
- </para>
- </section>
- <section id="features_completion">
- <title>Tab completion</title>
- <para>
- </para>
- </section>
- <section id="features_line_editing">
- <title>Line editing</title>
- <para>
- </para>
- </section>
- <section id="features_keybindings">
- <title>Custom Keybindings</title>
- <para>
- You can create your own keybindings by creating a
- <filename>HOME/.jlinebindings.properties"</filename>
- file. You can override the location of this file with
- the "<computeroutput>jline.keybindings</computeroutput>"
- system property.
- </para>
- <!--
- <para>
- The default keybindings are as follows:
- <programlisting>
- </programlisting>
- </para>
- -->
- </section>
- <section id="features_masking">
- <title>Character masking</title>
- <para>
- </para>
- </section>
- </chapter>
- <chapter id="api">
- <title>API</title>
- <para>
- This section discusses some common usages of the JLine API.
- For in-depth usage of the JLine API, see the
- <ulink url="apidocs">apidocs</ulink>.
- </para>
- <section id="reading_password">
- <title>Reading a password from the console</title>
- <para>
- A common task that console applications need to do is
- read in a password. While it is standard for software
- to not echo password strings as they are typed,
- the Java core APIs surprisingly do not provide any
- means to do this.
- </para>
- <para>
- JLine can read a password with the following code:
- <programlisting>
-String password = new <classname>jline.ConsoleReader</classname>().readLine(new Character('*'));
- </programlisting>
- This will replace every character types on the console
- with a star character.
- </para>
- <para>
- Alternately, you can have it not echo password
- character at all:
- <programlisting>
-String password = new <classname>jline.ConsoleReader</classname>().readLine(new Character(0));
- </programlisting>
- </para>
- <para>
- The <filename>jline-demo.jar</filename> file contains
- a sample application that reads the password. To run
- the sample, execute:
- <programlisting>
-java -cp jline-demo.jar jline.example.PasswordReader "*"
- </programlisting>
- </para>
- </section>
- </chapter>
- <chapter id="faq">
- <title>Frequently Asked Questions</title>
- <section id="faq_unsupported_platform"><title>
- Can I disable JLine if it isn't working on my platform?
- </title>
- <para>
- You can disable JLine by setting the System property
- "<computeroutput>jline.terminal</computeroutput>"
- to
- "<classname>jline.UnsupportedTerminal</classname>". For example:
- <programlisting>
-java -Djline.terminal=jline.UnsupportedTerminal jline.example.Example simple
- </programlisting>
- </para>
- </section>
- <section id="faq_custom_keybindings"><title>
- How do I customize the key bindings?
- </title>
- <para>
- You can create your own keybindings by creating a
- <filename>HOME/.jlinebindings.properties"</filename>
- file. You can override the location of this file with
- the "<computeroutput>jline.keybindings</computeroutput>"
- system property. To examine the format to use, see the
- <filename>src/jline/keybindings.properties</filename>
- file in the source distribution.
- </para>
- </section>
- <section id="faq_jline_as_default"><title>
- Can I use JLine as the default console input stream for
- all applications?
- </title>
- <para>
- No, but you can use the <classname>jline.ConsoleRunner</classname> application
- to set up the system input stream and continue on
- the launch another program. For example, to use JLine
- as the input handler for the popular
- <ulink url="http://www.beanshell.org">BeanShell</ulink>
- console application, you can run:
- <programlisting>
-java <classname>jline.ConsoleRunner</classname> <ulink url="http://www.beanshell.org/manual/standalonemode.html">bsh.Interpreter</ulink>
- </programlisting>
- </para>
- </section>
- <section id="faq_jline_beanshell"><title>
- Can I use JLine as the input handler for <ulink url="http://www.beanshell.org">BeanShell</ulink>?
- </title>
- <para>
- Yes. Try running:
- <programlisting>
-java <classname>jline.ConsoleRunner</classname> <ulink url="http://www.beanshell.org/manual/standalonemode.html">bsh.Interpreter</ulink>
- </programlisting>
- </para>
- </section>
- <section id="faq_jline_jdb"><title>
- Can I use JLine as the input handler for <ulink url="http://java.sun.com/j2se/1.3/docs/tooldocs/solaris/jdb.html">jdb</ulink> (the java debugger)?
- </title>
- <para>
- Yes. Try running:
- <programlisting>
-java <classname>jline.ConsoleRunner</classname> com.sun.tools.example.debug.tty.TTY <emphasis>args</emphasis>
- </programlisting>
- </para>
- </section>
- <section id="faq_pure_java"><title>
- Is JLine <trademark>100% pure Java</trademark>?
- </title>
- <para>
- No: JLine uses a couple small native methods in the Windows
- platform. On Unix, it is technically pure java, but relies
- on the execution of external (non-java) programs. See the
- <link linkend="installation">installation section</link>
- for more details.
- </para>
- </section>
- <section id="faq_password"><title>
- How do I make it so password characters are no echoed
- to the screen?
- </title>
- <para>
- See <link linkend="reading_password"/>.
- </para>
- </section>
- <section id="faq_cursrs"><title>
- Is JLine a full-featured curses implementation?
- </title>
- <para>
- No: JLine has no ability to position the cursor on the
- console. It might someday evolve into a plausible
- Java curses implementation.
- </para>
- </section>
- </chapter>
- </part>
-
- <appendix id="known_bugs">
- <title>Known Bugs</title>
- <itemizedlist>
- <listitem><para>
- Clearing the screen (CTRL-L) doesn't currently work on Windows.
- </para></listitem>
- </itemizedlist>
- </appendix>
-
- <appendix id="contributors">
- <title>Contributors</title>
- <para>
- The following people have contributed to improving JLine over the
- years:
- </para>
- <itemizedlist>
- <listitem><para>
- Marc Prud'hommeaux
- </para></listitem>
- <listitem><para>
- Damian Steer
- </para></listitem>
- <listitem><para>
- Dale Kemp
- </para></listitem>
- <listitem><para>
- Jun Liu
- </para></listitem>
- <listitem><para>
- malcolm@epcc.ed.ac.uk
- </para></listitem>
- <listitem><para>
- Simon Patarin
- </para></listitem>
- <listitem><para>
- Amy Isard
- </para></listitem>
- <listitem><para>
- Ryan Bell
- </para></listitem>
- <listitem><para>
- Marc Herbert
- </para></listitem>
- <listitem><para>
- Christian Salm
- </para></listitem>
- </itemizedlist>
- </appendix>
-
- <appendix id="todo">
- <title>Future enhancements</title>
- <itemizedlist>
- <listitem><para>
- Add localization for all strings.
- </para></listitem>
- <listitem><para>
- Create a BNFCompletor that can handle any BNF.
- </para></listitem>
- </itemizedlist>
- </appendix>
-
- <appendix id="changelog">
- <title>Change Log</title>
- <itemizedlist>
- <title>0.9.93 2007-11-13</title>
- <listitem><para>
- Fixed backspace handling on Unix/OS X.
- </para></listitem>
- </itemizedlist>
- <itemizedlist>
- <title>0.9.92 2007-10-30</title>
- <listitem><para>
- JLine now works with 64-bit Windows systems.
- </para></listitem>
- </itemizedlist>
- <itemizedlist>
- <title>0.9.91 2007-03-11</title>
- <listitem><para>
- Added ConsoleReader.setUsePagination() method which allows
- configuration of pagination when the number of rows of
- candidates exceeds the height of the detected terminal, thanks
- to a patch by Damian Steer.
- </para></listitem>
- <listitem><para>
- Better support for UTF-8 inputs (issue #1623521).
- </para></listitem>
- <listitem><para>
- Improved list of supported keys on Windows (issue #1649790).
- </para></listitem>
- </itemizedlist>
- <itemizedlist>
- <title>0.9.5 2006-03-08</title>
- <listitem><para>
- Fixed problem with "stty" on Solaris, which doesn't
- understand "stty size" to query the terminal size. It now
- uses "stty -a", which supposedly outputs a POSIX standard
- format.
- </para></listitem>
- <listitem><para>
- Support HOME and END keys, thanks to a patch by
- Dale Kemp.
- </para></listitem>
- </itemizedlist>
- <itemizedlist>
- <title>0.9.1 2005-01-29</title>
- <listitem><para>
- Fixed problem with the 0.9.0 distribution that
- failed to include the Windows jline.dll in the jline.jar,
- rendering it inoperable on Windows.
- </para></listitem>
- <listitem><para>
- Implemented proper interception or arrow keys on Windows,
- meaning that history can now be navigated with the UP
- and DOWN keys, and line editing can take place with
- the LEFT and RIGHT arrow keys.
- </para></listitem>
- </itemizedlist>
- <itemizedlist>
- <title>0.9.0 2005-01-23</title>
- <listitem><para>
- Changed license from GPL to BSD.
- </para></listitem>
- <listitem><para>
- Made "CTRL-L" map to clearing the screen.
- </para></listitem>
- </itemizedlist>
- <itemizedlist>
- <title>0.8.1 2003-11-18</title>
- <listitem><para>
- Fixed accidental dependency on JVM 1.4.
- </para></listitem>
- </itemizedlist>
- <itemizedlist>
- <title>0.8.0 2003-11-17</title>
- <listitem><para>
- Windows support using a native .dll
- </para></listitem>
- <listitem><para>
- A new ClassNameCompletor
- </para></listitem>
- <listitem><para>
- Many doc improvements
- </para></listitem>
- </itemizedlist>
- <itemizedlist>
- <title>0.6.0 2003-07-08</title>
- <listitem><para>
- Many bugfixes
- </para></listitem>
- <listitem><para>
- Better release system
- </para></listitem>
- <listitem><para>
- Automatically set terminal property by
- issuing stty on UNIX systems
- </para></listitem>
- <listitem><para>
- Additional tab-completion handlers
- </para></listitem>
- <listitem><para>
- Tested on Debian Linux and Mac OS 10.2
- </para></listitem>
- <listitem><para>
- Example includes dictionary, filename, and simple completion
- </para></listitem>
- </itemizedlist>
- <itemizedlist>
- <title>0.3.0 2002-10-05</title>
- <listitem><para>
- Initial release
- </para></listitem>
- </itemizedlist>
- </appendix>
-</book>
diff --git a/src/jline/src/site/fml/faq.fml b/src/jline/src/site/fml/faq.fml
deleted file mode 100644
index b9902b0fa7..0000000000
--- a/src/jline/src/site/fml/faq.fml
+++ /dev/null
@@ -1,26 +0,0 @@
- <?xml version="1.0"?>
-<faqs title="JLine FAQ">
- <part id="general">
- <faq>
- <question>How does JLine work?</question>
- <answer>
- <p>
- On Windows, JLine uses a native .dll (which it automatically
- extracts from the jline jar and loads at runtime) to access
- native console features. On UNIX systems, JLine will perform
- the necessary terminal setup by launching the "stty" command.
- </p>
- </answer>
- </faq>
- <faq>
- <question>What platforms has JLine been tested on?</question>
- <answer>
- <p>
- Various flavors of Windows (95, 98, NT, XP, 2000), Mac OS X,
- and multiple UNIX systems (Linux, Solaris, HPUX).
- </p>
- </answer>
- </faq>
-
- </part>
-</faqs>
diff --git a/src/jline/src/site/resources/css/site.css b/src/jline/src/site/resources/css/site.css
deleted file mode 100755
index 5d71608c15..0000000000
--- a/src/jline/src/site/resources/css/site.css
+++ /dev/null
@@ -1,311 +0,0 @@
-
-body {
- min-width: 600px;
- width: 600px;
- width: auto !important;
- background-color: #fff;
- font-family: Verdana, sans;
-}
-
-body,div,span,td,p,h2,h3,h4,h5,h6,a,ul,li {
- font-family: Verdana, sans;
- font-size: 11px;
- color: #5A5A5A;
- font-style: normal;
-}
-
-a,a:hover,a:visited,a:active {
- color: #5A5A5A;
- /* text-decoration: underline; */
-}
-
-/* main layout */
-#banner {
- color: #FFA500;
- border: none;
- margin: 0 0 0 0;
- background-color: #fff;
- background-image: url(../images/header.jpg);
- background-position: right;
- background-repeat: no-repeat;
- height: 100px;
-}
-
-#bannerLeft img{
- margin: 10px 0 0 10px;
-}
-
-#leftColumn {
- background-color: transparent;
- position: absolute;
- top: 140px;
- left: 20px;
- width: 180px;
- margin: 0px;
- padding: 0px;
- border: none;
-}
-
-#bodyColumn {
- margin: 0 0 20px 220px;
- background-color: #fff;
- padding: 30px;
- position: relative;
- background-image: url(../images/dotted.png);
- background-repeat: repeat-y;
-}
-
-#footer div.xright {
- color: #fff;
- margin-right: 10px;
-}
-
-/* end main layout */
-.deprecated {
- text-decoration: line-through;
-}
-
-.comment {
- color: green;
-}
-
-.source pre {
- font-family: "Andale Mono", monospace;
- font-size: 11px;
- background-color: #ddd;
- width: 100%;
- color: #5A5A5A;
- border-width: 0px;
- padding-top: 6px;
- padding-left: 3px;
-}
-
-#breadcrumbs {
- background-color: #FE1100;
- border: none;
- height: 15px;
-}
-
-/*
- workaround for bug in the Doxia docbook renderer that opens
- anchors (e.g. <a name="index">), but doesn't ever close them
-*/
-#section a,a:hover,a:visited,a:active {
- text-decoration: none;
-}
-
-
-#breadcrumbs a {
- color: #fff;
- margin-left: 20px;
- text-decoration: none;
-}
-
-h1 {
- border: none;
- padding-left: 0;
- font-weight: bold;
- text-transform: capitalize;
- background-color: #7FAABB !important;
- color: #FFFFFF !important;
- font-size: 19px !important;
-}
-
-h2 {
- border: none;
- padding-left: 0;
- font-size: 13px;
- font-weight: bold;
- text-transform: capitalize;
- background-color: #7FAABB !important;
- color: #FFFFFF !important;
- font-size: 17px !important;
-}
-
-h3 {
- border: none;
- font-weight: bolder;
- padding-left: 0;
- background-color: #8BBBD1 !important;
- color: #FFFFFF !important;
-}
-
-#navcolumn {
- padding: 0;
- overflow: hidden;
-}
-
-#navcolumn ul {
- margin: 0px 0 3px 0;
- background-repeat: repeat-x;
-}
-
-#navcolumn h5 {
- border: none;
- background-image: url(../images/dotted.png);
- background-repeat: repeat-x;
- padding: 4px 0 3px 20px;
- font-size: 11px !important;
- margin-top: -1px;
-}
-
-#navcolumn ul {
- margin-bottom: 8px;
-}
-
-#navcolumn li {
- margin: 0px 0 0px 3px;
- padding: 2px;
- list-style-position: outside;
- font-size: 7.5pt !important;
- padding-left: 16px;
- padding-left /**/: 2px !important;
- /* warning, don't reformat, there should be no comment between padding-left and comment, to fix IE5 issues */
-}
-
-#menuDownloadable_docs li {
- background-image: url(../images/ico_file_pdf.png);
- padding-top: 3px;
- padding-bottom: 1px;
-}
-
-#navcolumn strong {
- color: #000000;
- font-weight: bold;
-}
-
-#navcolumn strong a {
- color: #000000;
- font-weight: bold;
-}
-
-#navcolumn a {
- padding-left: 14px;
- text-decoration: underline;
- padding-bottom: 2px;
- color: #5a5a5a;
-}
-
-#navcolumn a img {
- margin-top: 0;
-}
-
-#navcolumn a#poweredBy img {
- margin: 0 0 15px 20px;
- width: 90px;
- height: 30px;
-}
-
-#navcolumn #lastPublished {
- color: #999;
- margin: 0 0 0 20px;
-}
-
-#navcolumn a:hover {
- color: Olive;
- padding-left: 14px;
- text-decoration: underline;
- padding-bottom: 2px;
-}
-
-#breadcrumbs div.xright,#breadcrumbs div.xleft {
- color: #fff;
- display: inline;
- font-size: 7pt !important;
-}
-
-#banner a#projectLogo img {
- float: left;
- background-color: #fff !important;
- margin: 20px 0 0 20px !important;
-}
-
-#navcolumn li {
- color: #000000;
-}
-
-#navcolumn strong {
- color: #000000;
- font-weight: bold;
- margin-left: 15px;
-}
-
-div.source {
- background-color: #ddd;
-}
-
-div.source pre,code,td.code {
- font-size: 8pt !important;
- font-family: monospace;
- margin: 0;
-}
-
-td.code {
- font-size: 10pt !important;
- font-family: monospace;
-}
-
-div#legend {
- display: none;
-}
-
-table td.source {
- border: none !important;
-}
-
-table td,table th {
- font-size: 8pt !important;
- font-family: verdana;
-}
-
-table th {
- font-weight: bold;
-}
-
-.collapsed {
- background-image: url(../images/collapsed.png) !important;
-}
-
-li.expanded {
- background-image: url(../images/expanded.png) !important;
-}
-
-/*
-li.expanded ul {
- margin-top: 5px !important;
-}
-*/
-
-a.externalLink,a.newWindow {
- padding-right: 9px !important;
- background-image: none !important; /*ie5*/
-}
-
-a.externalLink /* */ {
- background-image: url(../images/external.png) !important;
-}
-
-a.newWindow /* */ {
- background-image: url(../images/newwindow.png) !important;
-}
-
-table {
- width: 68%; /* fix for ie 5.x */
-}
-
-i {
- content: "\"/*"
-}
-
-table {
- width: 100%;
-}
-/* remove banner: comment the following lines for the full layout */ /*
-#banner, #breadcrumbs {
- display: none !important;
-}
-#leftColumn {
- position: relative;
- top: 0;
-}
-*/
diff --git a/src/jline/src/site/resources/images/collapsed.png b/src/jline/src/site/resources/images/collapsed.png
deleted file mode 100755
index a02c1e67c9..0000000000
--- a/src/jline/src/site/resources/images/collapsed.png
+++ /dev/null
Binary files differ
diff --git a/src/jline/src/site/resources/images/dotted.png b/src/jline/src/site/resources/images/dotted.png
deleted file mode 100755
index 8a4d443a4a..0000000000
--- a/src/jline/src/site/resources/images/dotted.png
+++ /dev/null
Binary files differ
diff --git a/src/jline/src/site/resources/images/expanded.png b/src/jline/src/site/resources/images/expanded.png
deleted file mode 100755
index 8a19dbf103..0000000000
--- a/src/jline/src/site/resources/images/expanded.png
+++ /dev/null
Binary files differ
diff --git a/src/jline/src/site/resources/images/external.png b/src/jline/src/site/resources/images/external.png
deleted file mode 100755
index 19f28955ca..0000000000
--- a/src/jline/src/site/resources/images/external.png
+++ /dev/null
Binary files differ
diff --git a/src/jline/src/site/resources/images/ico_file_pdf.png b/src/jline/src/site/resources/images/ico_file_pdf.png
deleted file mode 100644
index 9ceb00f2dd..0000000000
--- a/src/jline/src/site/resources/images/ico_file_pdf.png
+++ /dev/null
Binary files differ
diff --git a/src/jline/src/site/resources/images/logo.jpg b/src/jline/src/site/resources/images/logo.jpg
deleted file mode 100644
index 1f1da5c8f2..0000000000
--- a/src/jline/src/site/resources/images/logo.jpg
+++ /dev/null
Binary files differ
diff --git a/src/jline/src/site/resources/images/newwindow.png b/src/jline/src/site/resources/images/newwindow.png
deleted file mode 100755
index 1374c228af..0000000000
--- a/src/jline/src/site/resources/images/newwindow.png
+++ /dev/null
Binary files differ
diff --git a/src/jline/src/site/site.xml b/src/jline/src/site/site.xml
deleted file mode 100644
index 274ec83ee4..0000000000
--- a/src/jline/src/site/site.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>
-<project name="JLine">
- <bannerLeft>
- <name>JLine</name>
- <src>images/logo.jpg</src>
- <href>http://jline.sourceforge.net/</href>
- </bannerLeft>
- <bannerRight>
- <name>SourceForge</name>
- <src>http://sourceforge.net/sflogo.php?group_id=64033</src>
- <href>http://sourceforge.net/</href>
- </bannerRight>
- <body>
- <menu name="JLine">
- <item name="Manual" href="index.html"/>
- <item name="FAQs" href="faq.html"/>
- <item name="Download" href="downloads.html"/>
- <item name="Building" href="building.html"/>
- </menu>
-
- <menu name="Community">
- <item name="Forums"
- href="http://sourceforge.net/forum/?group_id=64033"/>
- <item name="Issue Tracker"
- href="http://sourceforge.net/tracker/?group_id=64033"/>
- <item name="News"
- href="http://sourceforge.net/news/?group_id=64033"/>
- </menu>
-
- <menu name="Project">
- <item name="Javadocs"
- href="apidocs/index.html"/>
- <item name="Browse Source Code"
- href="http://jline.cvs.sourceforge.net/jline/"/>
- </menu>
-
- ${reports}
-
- </body>
-</project>
diff --git a/src/jline/src/test/java/jline/ConsoleReaderTest.java b/src/jline/src/test/java/jline/ConsoleReaderTest.java
deleted file mode 100644
index 4a25783c58..0000000000
--- a/src/jline/src/test/java/jline/ConsoleReaderTest.java
+++ /dev/null
@@ -1,162 +0,0 @@
-package jline;
-
-import java.io.ByteArrayInputStream;
-import java.io.InputStream;
-import java.io.StringWriter;
-import java.io.Writer;
-
-import junit.framework.TestCase;
-
-public class ConsoleReaderTest extends TestCase {
-
- public ConsoleReaderTest(String name) {
- super(name);
- }
-
- protected void setUp() throws Exception {
- System.setProperty("jline.WindowsTerminal.directConsole", "false");
- }
-
- public void testDeleteAndBackspaceKeymappings() throws Exception {
- // test only works on Windows
- if (!(Terminal.getTerminal() instanceof WindowsTerminal))
- return;
-
- ConsoleReader consoleReader = new ConsoleReader();
- assertNotNull(consoleReader);
- assertEquals(127, consoleReader
- .getKeyForAction(ConsoleReader.DELETE_NEXT_CHAR));
- assertEquals(8, consoleReader
- .getKeyForAction(ConsoleReader.DELETE_PREV_CHAR));
- }
-
- public void testReadline() throws Exception {
- ConsoleReader consoleReader = createConsole("Sample String\r\n"
- .getBytes());
- assertNotNull(consoleReader);
- String line = consoleReader.readLine();
- assertEquals("Sample String", line);
-
- }
-
- public void testDeleteOnWindowsTerminal() throws Exception {
- // test only works on Windows
- if (!(Terminal.getTerminal() instanceof WindowsTerminal))
- return;
-
- char[] characters = new char[] { 'S', 's',
- WindowsTerminal.SPECIAL_KEY_INDICATOR,
- WindowsTerminal.LEFT_ARROW_KEY,
- WindowsTerminal.SPECIAL_KEY_INDICATOR,
- WindowsTerminal.DELETE_KEY, '\r', 'n' };
- assertWindowsKeyBehavior("S", characters);
- }
-
- public void testNumpadDeleteOnWindowsTerminal() throws Exception {
- // test only works on Windows
- if (!(Terminal.getTerminal() instanceof WindowsTerminal))
- return;
-
- char[] characters = new char[] { 'S', 's',
- WindowsTerminal.NUMPAD_KEY_INDICATOR,
- WindowsTerminal.LEFT_ARROW_KEY,
- WindowsTerminal.NUMPAD_KEY_INDICATOR,
- WindowsTerminal.DELETE_KEY, '\r', 'n' };
- assertWindowsKeyBehavior("S", characters);
- }
-
- public void testHomeKeyOnWindowsTerminal() throws Exception {
- // test only works on Windows
- if (!(Terminal.getTerminal() instanceof WindowsTerminal))
- return;
-
- char[] characters = new char[] { 'S', 's',
- WindowsTerminal.SPECIAL_KEY_INDICATOR,
- WindowsTerminal.HOME_KEY, 'x', '\r', '\n' };
- assertWindowsKeyBehavior("xSs", characters);
-
- }
-
- public void testEndKeyOnWindowsTerminal() throws Exception {
- // test only works on Windows
- if (!(Terminal.getTerminal() instanceof WindowsTerminal))
- return;
-
- char[] characters = new char[] { 'S', 's',
- WindowsTerminal.SPECIAL_KEY_INDICATOR,
- WindowsTerminal.HOME_KEY, 'x',
- WindowsTerminal.SPECIAL_KEY_INDICATOR, WindowsTerminal.END_KEY,
- 'j', '\r', '\n' };
- assertWindowsKeyBehavior("xSsj", characters);
- }
-
- public void testPageUpOnWindowsTerminal() throws Exception {
- // test only works on Windows
- if (!(Terminal.getTerminal() instanceof WindowsTerminal))
- return;
-
- char[] characters = new char[] { WindowsTerminal.SPECIAL_KEY_INDICATOR,
- WindowsTerminal.PAGE_UP_KEY, '\r', '\n' };
- assertWindowsKeyBehavior("dir", characters);
- }
-
- public void testPageDownOnWindowsTerminal() throws Exception {
- // test only works on Windows
- if (!(Terminal.getTerminal() instanceof WindowsTerminal))
- return;
-
- char[] characters = new char[] { WindowsTerminal.SPECIAL_KEY_INDICATOR,
- WindowsTerminal.PAGE_DOWN_KEY, '\r', '\n' };
- assertWindowsKeyBehavior("mkdir monkey", characters);
- }
-
- public void testEscapeOnWindowsTerminal() throws Exception {
- // test only works on Windows
- if (!(Terminal.getTerminal() instanceof WindowsTerminal))
- return;
-
- char[] characters = new char[] { 's', 's', 's',
- WindowsTerminal.SPECIAL_KEY_INDICATOR,
- WindowsTerminal.ESCAPE_KEY, '\r', '\n' };
- assertWindowsKeyBehavior("", characters);
- }
-
- public void testInsertOnWindowsTerminal() throws Exception {
- // test only works on Windows
- if (!(Terminal.getTerminal() instanceof WindowsTerminal))
- return;
-
- char[] characters = new char[] { 'o', 'p', 's',
- WindowsTerminal.SPECIAL_KEY_INDICATOR,
- WindowsTerminal.HOME_KEY,
- WindowsTerminal.SPECIAL_KEY_INDICATOR,
- WindowsTerminal.INSERT_KEY, 'o', 'o', 'p', 's', '\r', '\n' };
- assertWindowsKeyBehavior("oops", characters);
- }
-
- private void assertWindowsKeyBehavior(String expected, char[] input)
- throws Exception {
- StringBuffer buffer = new StringBuffer();
- buffer.append(input);
- ConsoleReader reader = createConsole(buffer.toString().getBytes());
- assertNotNull(reader);
- String line = reader.readLine();
- assertEquals(expected, line);
- }
-
- private ConsoleReader createConsole(byte[] bytes) throws Exception {
- InputStream in = new ByteArrayInputStream(bytes);
- Writer writer = new StringWriter();
- ConsoleReader reader = new ConsoleReader(in, writer);
- reader.setHistory(createSeededHistory());
- return reader;
- }
-
- private History createSeededHistory() {
- History history = new History();
- history.addToHistory("dir");
- history.addToHistory("cd c:\\");
- history.addToHistory("mkdir monkey");
- return history;
- }
-}
diff --git a/src/jline/src/test/java/jline/JLineTestCase.java b/src/jline/src/test/java/jline/JLineTestCase.java
deleted file mode 100644
index 92e09d485d..0000000000
--- a/src/jline/src/test/java/jline/JLineTestCase.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * 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 junit.framework.*;
-
-import java.io.*;
-
-public abstract class JLineTestCase extends TestCase {
- ConsoleReader console;
-
- public JLineTestCase(String test) {
- super(test);
- }
-
- public void setUp() throws Exception {
- super.setUp();
- console = new ConsoleReader(null, new PrintWriter(
- new OutputStreamWriter(new ByteArrayOutputStream())), null,
- new UnixTerminal());
- }
-
- public void assertBuffer(String expected, Buffer buffer) throws IOException {
- assertBuffer(expected, buffer, true);
- }
-
- public void assertBuffer(String expected, Buffer buffer, boolean clear)
- throws IOException {
- // clear current buffer, if any
- if (clear) {
- console.finishBuffer();
- console.getHistory().clear();
- }
-
- console.setInput(new ByteArrayInputStream(buffer.getBytes()));
-
- // run it through the reader
- while (console.readLine((String) null) != null) {
- ;
- }
-
- assertEquals(expected, console.getCursorBuffer().toString());
- }
-
- private int getKeyForAction(short logicalAction) {
- int action = console.getKeyForAction(logicalAction);
-
- if (action == -1) {
- fail("Keystroke for logical action " + logicalAction
- + " was not bound in the console");
- }
-
- return action;
- }
-
- /**
- * TODO: Fix this so tests don't break on windows machines.
- *
- * @author Ryan
- *
- */
- class Buffer {
- private final ByteArrayOutputStream bout = new ByteArrayOutputStream();
-
- public Buffer() {
- }
-
- public Buffer(String str) {
- append(str);
- }
-
- public byte[] getBytes() {
- return bout.toByteArray();
- }
-
- public Buffer op(short operation) {
- return append(getKeyForAction(operation));
- }
-
- public Buffer ctrlA() {
- return append(getKeyForAction(ConsoleReader.MOVE_TO_BEG));
- }
-
- public Buffer ctrlU() {
- return append(getKeyForAction(ConsoleReader.KILL_LINE_PREV));
- }
-
- public Buffer tab() {
- return append(getKeyForAction(ConsoleReader.COMPLETE));
- }
-
- public Buffer back() {
- return append(getKeyForAction(ConsoleReader.DELETE_PREV_CHAR));
- }
-
- public Buffer left() {
- return append(UnixTerminal.ARROW_START).append(
- UnixTerminal.ARROW_PREFIX).append(UnixTerminal.ARROW_LEFT);
- }
-
- public Buffer right() {
- return append(UnixTerminal.ARROW_START).append(
- UnixTerminal.ARROW_PREFIX).append(UnixTerminal.ARROW_RIGHT);
- }
-
- public Buffer up() {
- return append(UnixTerminal.ARROW_START).append(
- UnixTerminal.ARROW_PREFIX).append(UnixTerminal.ARROW_UP);
- }
-
- public Buffer down() {
- return append(UnixTerminal.ARROW_START).append(
- UnixTerminal.ARROW_PREFIX).append(UnixTerminal.ARROW_DOWN);
- }
-
- public Buffer append(String str) {
- byte[] bytes = str.getBytes();
-
- for (int i = 0; i < bytes.length; i++) {
- append(bytes[i]);
- }
-
- return this;
- }
-
- public Buffer append(int i) {
- return append((byte) i);
- }
-
- public Buffer append(byte b) {
- bout.write(b);
-
- return this;
- }
- }
-}
diff --git a/src/jline/src/test/java/jline/TerminalFactoryTest.java b/src/jline/src/test/java/jline/TerminalFactoryTest.java
new file mode 100644
index 0000000000..3b38fbec95
--- /dev/null
+++ b/src/jline/src/test/java/jline/TerminalFactoryTest.java
@@ -0,0 +1,34 @@
+package jline;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * Tests for the {@link TerminalFactory}.
+ */
+public class TerminalFactoryTest
+{
+ @Before
+ public void setUp() throws Exception {
+ TerminalFactory.reset();
+ }
+
+ @Test
+ public void testConfigureNone() {
+ TerminalFactory.configure(TerminalFactory.NONE);
+ Terminal t = TerminalFactory.get();
+ assertNotNull(t);
+ assertEquals(UnsupportedTerminal.class.getName(), t.getClass().getName());
+ }
+
+ @Test
+ public void testConfigureUnsupportedTerminal() {
+ TerminalFactory.configure(UnsupportedTerminal.class.getName());
+ Terminal t = TerminalFactory.get();
+ assertNotNull(t);
+ assertEquals(UnsupportedTerminal.class.getName(), t.getClass().getName());
+ }
+} \ No newline at end of file
diff --git a/src/jline/src/test/java/jline/TestCompletion.java b/src/jline/src/test/java/jline/TestCompletion.java
deleted file mode 100644
index a481e2625b..0000000000
--- a/src/jline/src/test/java/jline/TestCompletion.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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.util.*;
-
-/**
- * Tests command history.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- */
-public class TestCompletion extends JLineTestCase {
- public TestCompletion(String test) {
- super(test);
- }
-
- public void testSimpleCompletor() throws Exception {
- // clear any current completors
- for (Iterator i = console.getCompletors().iterator(); i.hasNext();
- console.removeCompletor((Completor) i.next())) {
- ;
- }
-
- console.addCompletor
- (new SimpleCompletor(new String[] { "foo", "bar", "baz" }));
-
- assertBuffer("foo ", new Buffer("f").op(ConsoleReader.COMPLETE));
- // single tab completes to unabbiguous "ba"
- assertBuffer("ba", new Buffer("b").op(ConsoleReader.COMPLETE));
- assertBuffer("ba", new Buffer("ba").op(ConsoleReader.COMPLETE));
- assertBuffer("baz ", new Buffer("baz").op(ConsoleReader.COMPLETE));
- }
-
- public void testArgumentCompletor() throws Exception {
- // clear any current completors
- for (Iterator i = console.getCompletors().iterator(); i.hasNext();
- console.removeCompletor((Completor) i.next())) {
- ;
- }
-
- console.addCompletor(new ArgumentCompletor
- (new SimpleCompletor(new String[] { "foo", "bar", "baz" })));
-
- assertBuffer("foo foo ", new Buffer("foo f").
- op(ConsoleReader.COMPLETE));
- assertBuffer("foo ba", new Buffer("foo b").
- op(ConsoleReader.COMPLETE));
- assertBuffer("foo ba", new Buffer("foo ba").
- op(ConsoleReader.COMPLETE));
- assertBuffer("foo baz ", new Buffer("foo baz").
- op(ConsoleReader.COMPLETE));
-
- // test completion in the mid range
- assertBuffer("foo baz",
- new Buffer("f baz").left().left().left().left().
- op(ConsoleReader.COMPLETE));
- assertBuffer("ba foo",
- new Buffer("b foo").left().left().left().left().
- op(ConsoleReader.COMPLETE));
- assertBuffer("foo ba baz",
- new Buffer("foo b baz").left().left().left().left().
- op(ConsoleReader.COMPLETE));
- assertBuffer("foo foo baz",
- new Buffer("foo f baz").left().left().left().left().
- op(ConsoleReader.COMPLETE));
- }
-}
diff --git a/src/jline/src/test/java/jline/TestEditLine.java b/src/jline/src/test/java/jline/TestEditLine.java
deleted file mode 100644
index 88b45240ed..0000000000
--- a/src/jline/src/test/java/jline/TestEditLine.java
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * 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;
-
-
-/**
- * Tests various features of editing lines.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- */
-public class TestEditLine extends JLineTestCase {
- public TestEditLine(String test) {
- super(test);
- }
-
- public void testDeletePreviousWord() throws Exception {
- Buffer b = new Buffer("This is a test");
-
- assertBuffer("This is a ", b = b.op(ConsoleReader.DELETE_PREV_WORD));
- assertBuffer("This is ", b = b.op(ConsoleReader.DELETE_PREV_WORD));
- assertBuffer("This ", b = b.op(ConsoleReader.DELETE_PREV_WORD));
- assertBuffer("", b = b.op(ConsoleReader.DELETE_PREV_WORD));
- assertBuffer("", b = b.op(ConsoleReader.DELETE_PREV_WORD));
- assertBuffer("", b = b.op(ConsoleReader.DELETE_PREV_WORD));
- }
-
- public void testMoveToEnd() throws Exception {
- Buffer b = new Buffer("This is a test");
-
- assertBuffer("This is a XtestX",
- new Buffer("This is a test").op(ConsoleReader.PREV_WORD)
- .append('X')
- .op(ConsoleReader.MOVE_TO_END)
- .append('X'));
-
- assertBuffer("This is Xa testX",
- new Buffer("This is a test").op(ConsoleReader.PREV_WORD)
- .op(ConsoleReader.PREV_WORD)
- .append('X')
- .op(ConsoleReader.MOVE_TO_END)
- .append('X'));
-
- assertBuffer("This Xis a testX",
- new Buffer("This is a test").op(ConsoleReader.PREV_WORD)
- .op(ConsoleReader.PREV_WORD)
- .op(ConsoleReader.PREV_WORD)
- .append('X')
- .op(ConsoleReader.MOVE_TO_END)
- .append('X'));
- }
-
- public void testPreviousWord() throws Exception {
- assertBuffer("This is a Xtest",
- new Buffer("This is a test").op(ConsoleReader.PREV_WORD)
- .append('X'));
- assertBuffer("This is Xa test",
- new Buffer("This is a test").op(ConsoleReader.PREV_WORD)
- .op(ConsoleReader.PREV_WORD)
- .append('X'));
- assertBuffer("This Xis a test",
- new Buffer("This is a test").op(ConsoleReader.PREV_WORD)
- .op(ConsoleReader.PREV_WORD)
- .op(ConsoleReader.PREV_WORD)
- .append('X'));
- assertBuffer("XThis is a test",
- new Buffer("This is a test").op(ConsoleReader.PREV_WORD)
- .op(ConsoleReader.PREV_WORD)
- .op(ConsoleReader.PREV_WORD)
- .op(ConsoleReader.PREV_WORD)
- .append('X'));
- assertBuffer("XThis is a test",
- new Buffer("This is a test").op(ConsoleReader.PREV_WORD)
- .op(ConsoleReader.PREV_WORD)
- .op(ConsoleReader.PREV_WORD)
- .op(ConsoleReader.PREV_WORD)
- .op(ConsoleReader.PREV_WORD)
- .append('X'));
- assertBuffer("XThis is a test",
- new Buffer("This is a test").op(ConsoleReader.PREV_WORD)
- .op(ConsoleReader.PREV_WORD)
- .op(ConsoleReader.PREV_WORD)
- .op(ConsoleReader.PREV_WORD)
- .op(ConsoleReader.PREV_WORD)
- .op(ConsoleReader.PREV_WORD)
- .append('X'));
- }
-
- public void testLineStart() throws Exception {
- assertBuffer("XThis is a test",
- new Buffer("This is a test").ctrlA().append('X'));
- assertBuffer("TXhis is a test",
- new Buffer("This is a test").ctrlA().right().append('X'));
- }
-
- public void testClearLine() throws Exception {
- assertBuffer("", new Buffer("This is a test").ctrlU());
- assertBuffer("t", new Buffer("This is a test").left().ctrlU());
- assertBuffer("st", new Buffer("This is a test").left().left().ctrlU());
- }
-
- public void testRight() throws Exception {
- Buffer b = new Buffer("This is a test");
- b = b.left().right().back();
- assertBuffer("This is a tes", b);
- b = b.left().left().left().right().left().back();
- assertBuffer("This is ates", b);
- b.append('X');
- assertBuffer("This is aXtes", b);
- }
-
- public void testLeft() throws Exception {
- Buffer b = new Buffer("This is a test");
- b = b.left().left().left();
- assertBuffer("This is a est", b = b.back());
- assertBuffer("This is aest", b = b.back());
- assertBuffer("This is est", b = b.back());
- assertBuffer("This isest", b = b.back());
- assertBuffer("This iest", b = b.back());
- assertBuffer("This est", b = b.back());
- assertBuffer("Thisest", b = b.back());
- assertBuffer("Thiest", b = b.back());
- assertBuffer("Thest", b = b.back());
- assertBuffer("Test", b = b.back());
- assertBuffer("est", b = b.back());
- assertBuffer("est", b = b.back());
- assertBuffer("est", b = b.back());
- assertBuffer("est", b = b.back());
- assertBuffer("est", b = b.back());
- }
-
- public void testBackspace() throws Exception {
- Buffer b = new Buffer("This is a test");
- assertBuffer("This is a tes", b = b.back());
- assertBuffer("This is a te", b = b.back());
- assertBuffer("This is a t", b = b.back());
- assertBuffer("This is a ", b = b.back());
- assertBuffer("This is a", b = b.back());
- assertBuffer("This is ", b = b.back());
- assertBuffer("This is", b = b.back());
- assertBuffer("This i", b = b.back());
- assertBuffer("This ", b = b.back());
- assertBuffer("This", b = b.back());
- assertBuffer("Thi", b = b.back());
- assertBuffer("Th", b = b.back());
- assertBuffer("T", b = b.back());
- assertBuffer("", b = b.back());
- assertBuffer("", b = b.back());
- assertBuffer("", b = b.back());
- assertBuffer("", b = b.back());
- assertBuffer("", b = b.back());
- }
-
- public void testBuffer() throws Exception {
- assertBuffer("This is a test", new Buffer("This is a test"));
- }
-}
diff --git a/src/jline/src/test/java/jline/TestHistory.java b/src/jline/src/test/java/jline/TestHistory.java
deleted file mode 100644
index a39afa5c19..0000000000
--- a/src/jline/src/test/java/jline/TestHistory.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * 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;
-
-
-/**
- * Tests command history.
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- */
-public class TestHistory extends JLineTestCase {
- public TestHistory(String test) {
- super(test);
- }
-
- public void testSingleHistory() throws Exception {
- Buffer b = new Buffer().
- append("test line 1").op(ConsoleReader.NEWLINE).
- append("test line 2").op(ConsoleReader.NEWLINE).
- append("test line 3").op(ConsoleReader.NEWLINE).
- append("test line 4").op(ConsoleReader.NEWLINE).
- append("test line 5").op(ConsoleReader.NEWLINE).
- append("");
-
- assertBuffer("", b);
-
- assertBuffer("test line 5", b = b.op(ConsoleReader.PREV_HISTORY));
- assertBuffer("test line 4", b = b.op(ConsoleReader.PREV_HISTORY));
- assertBuffer("test line 5", b = b.op(ConsoleReader.NEXT_HISTORY));
- assertBuffer("test line 4", b = b.op(ConsoleReader.PREV_HISTORY));
- assertBuffer("test line 3", b = b.op(ConsoleReader.PREV_HISTORY));
- assertBuffer("test line 2", b = b.op(ConsoleReader.PREV_HISTORY));
- assertBuffer("test line 1", b = b.op(ConsoleReader.PREV_HISTORY));
-
- // beginning of history
- assertBuffer("test line 1", b = b.op(ConsoleReader.PREV_HISTORY));
- assertBuffer("test line 1", b = b.op(ConsoleReader.PREV_HISTORY));
- assertBuffer("test line 1", b = b.op(ConsoleReader.PREV_HISTORY));
- assertBuffer("test line 1", b = b.op(ConsoleReader.PREV_HISTORY));
-
- assertBuffer("test line 2", b = b.op(ConsoleReader.NEXT_HISTORY));
- assertBuffer("test line 3", b = b.op(ConsoleReader.NEXT_HISTORY));
- assertBuffer("test line 4", b = b.op(ConsoleReader.NEXT_HISTORY));
- assertBuffer("test line 5", b = b.op(ConsoleReader.NEXT_HISTORY));
-
- // end of history
- assertBuffer("", b = b.op(ConsoleReader.NEXT_HISTORY));
- assertBuffer("", b = b.op(ConsoleReader.NEXT_HISTORY));
- assertBuffer("", b = b.op(ConsoleReader.NEXT_HISTORY));
-
- assertBuffer("test line 5", b = b.op(ConsoleReader.PREV_HISTORY));
- assertBuffer("test line 4", b = b.op(ConsoleReader.PREV_HISTORY));
- b = b.op(ConsoleReader.MOVE_TO_BEG).append("XXX")
- .op(ConsoleReader.NEWLINE);
- assertBuffer("XXXtest line 4", b = b.op(ConsoleReader.PREV_HISTORY));
- assertBuffer("test line 5", b = b.op(ConsoleReader.PREV_HISTORY));
- assertBuffer("test line 4", b = b.op(ConsoleReader.PREV_HISTORY));
- assertBuffer("test line 5", b = b.op(ConsoleReader.NEXT_HISTORY));
- assertBuffer("XXXtest line 4", b = b.op(ConsoleReader.NEXT_HISTORY));
- assertBuffer("", b = b.op(ConsoleReader.NEXT_HISTORY));
-
- assertBuffer("XXXtest line 4", b = b.op(ConsoleReader.PREV_HISTORY));
- assertBuffer("XXXtest line 4", b = b.op(ConsoleReader.NEWLINE).
- op(ConsoleReader.PREV_HISTORY));
- assertBuffer("XXXtest line 4", b = b.op(ConsoleReader.NEWLINE).
- op(ConsoleReader.PREV_HISTORY));
- assertBuffer("XXXtest line 4", b = b.op(ConsoleReader.NEWLINE).
- op(ConsoleReader.PREV_HISTORY));
- assertBuffer("XXXtest line 4", b = b.op(ConsoleReader.NEWLINE).
- op(ConsoleReader.PREV_HISTORY));
- }
-}
diff --git a/src/jline/src/test/java/jline/console/ConsoleReaderTest.java b/src/jline/src/test/java/jline/console/ConsoleReaderTest.java
new file mode 100644
index 0000000000..45ba4775e1
--- /dev/null
+++ b/src/jline/src/test/java/jline/console/ConsoleReaderTest.java
@@ -0,0 +1,261 @@
+package jline.console;
+
+import jline.TerminalFactory;
+import jline.WindowsTerminal;
+import jline.console.history.History;
+import jline.console.history.MemoryHistory;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.StringWriter;
+import java.io.Writer;
+
+import static jline.WindowsTerminal.WindowsKey.DELETE_KEY;
+import static jline.WindowsTerminal.WindowsKey.END_KEY;
+import static jline.WindowsTerminal.WindowsKey.ESCAPE_KEY;
+import static jline.WindowsTerminal.WindowsKey.HOME_KEY;
+import static jline.WindowsTerminal.WindowsKey.INSERT_KEY;
+import static jline.WindowsTerminal.WindowsKey.LEFT_ARROW_KEY;
+import static jline.WindowsTerminal.WindowsKey.NUMPAD_KEY_INDICATOR;
+import static jline.WindowsTerminal.WindowsKey.PAGE_DOWN_KEY;
+import static jline.WindowsTerminal.WindowsKey.PAGE_UP_KEY;
+import static jline.WindowsTerminal.WindowsKey.SPECIAL_KEY_INDICATOR;
+import static jline.console.Operation.DELETE_NEXT_CHAR;
+import static jline.console.Operation.DELETE_PREV_CHAR;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * Tests for the {@link ConsoleReader}.
+ */
+public class ConsoleReaderTest
+{
+ @Before
+ public void setUp() throws Exception {
+ System.setProperty(WindowsTerminal.JLINE_WINDOWS_TERMINAL_DIRECT_CONSOLE, "false");
+ }
+
+ private void assertWindowsKeyBehavior(String expected, char[] input) throws Exception {
+ StringBuilder buffer = new StringBuilder();
+ buffer.append(input);
+ ConsoleReader reader = createConsole(buffer.toString().getBytes());
+ assertNotNull(reader);
+ String line = reader.readLine();
+ assertEquals(expected, line);
+ }
+
+ private ConsoleReader createConsole(byte[] bytes) throws Exception {
+ InputStream in = new ByteArrayInputStream(bytes);
+ Writer writer = new StringWriter();
+ ConsoleReader reader = new ConsoleReader(in, writer);
+ reader.setHistory(createSeededHistory());
+ return reader;
+ }
+
+ private History createSeededHistory() {
+ History history = new MemoryHistory();
+ history.add("dir");
+ history.add("cd c:\\");
+ history.add("mkdir monkey");
+ return history;
+ }
+
+ @Test
+ public void testDeleteAndBackspaceKeymappings() throws Exception {
+ // test only works on Windows
+ if (!(TerminalFactory.get() instanceof WindowsTerminal)) {
+ return;
+ }
+
+ ConsoleReader consoleReader = new ConsoleReader();
+ assertNotNull(consoleReader);
+ assertEquals(127, consoleReader.getKeyForAction(DELETE_NEXT_CHAR));
+ assertEquals(8, consoleReader.getKeyForAction(DELETE_PREV_CHAR));
+ }
+
+ @Test
+ public void testReadline() throws Exception {
+ ConsoleReader consoleReader = createConsole("Sample String\r\n".getBytes());
+ assertNotNull(consoleReader);
+ String line = consoleReader.readLine();
+ assertEquals("Sample String", line);
+ }
+
+ @Test
+ public void testDeleteOnWindowsTerminal() throws Exception {
+ // test only works on Windows
+ if (!(TerminalFactory.get() instanceof WindowsTerminal)) {
+ return;
+ }
+
+ char[] characters = new char[]{
+ 'S', 's',
+ (char) SPECIAL_KEY_INDICATOR.code,
+ (char) LEFT_ARROW_KEY.code,
+ (char) SPECIAL_KEY_INDICATOR.code,
+ (char) DELETE_KEY.code, '\r', 'n'
+ };
+ assertWindowsKeyBehavior("S", characters);
+ }
+
+ @Test
+ public void testNumpadDeleteOnWindowsTerminal() throws Exception {
+ // test only works on Windows
+ if (!(TerminalFactory.get() instanceof WindowsTerminal)) {
+ return;
+ }
+
+ char[] characters = new char[]{
+ 'S', 's',
+ (char) NUMPAD_KEY_INDICATOR.code,
+ (char) LEFT_ARROW_KEY.code,
+ (char) NUMPAD_KEY_INDICATOR.code,
+ (char) DELETE_KEY.code, '\r', 'n'
+ };
+ assertWindowsKeyBehavior("S", characters);
+ }
+
+ @Test
+ public void testHomeKeyOnWindowsTerminal() throws Exception {
+ // test only works on Windows
+ if (!(TerminalFactory.get() instanceof WindowsTerminal)) {
+ return;
+ }
+
+ char[] characters = new char[]{
+ 'S', 's',
+ (char) SPECIAL_KEY_INDICATOR.code,
+ (char) HOME_KEY.code, 'x', '\r', '\n'
+ };
+ assertWindowsKeyBehavior("xSs", characters);
+
+ }
+
+ @Test
+ public void testEndKeyOnWindowsTerminal() throws Exception {
+ // test only works on Windows
+ if (!(TerminalFactory.get() instanceof WindowsTerminal)) {
+ return;
+ }
+
+ char[] characters = new char[]{
+ 'S', 's',
+ (char) SPECIAL_KEY_INDICATOR.code,
+ (char) HOME_KEY.code, 'x',
+ (char) SPECIAL_KEY_INDICATOR.code, (char) END_KEY.code,
+ 'j', '\r', '\n'
+ };
+ assertWindowsKeyBehavior("xSsj", characters);
+ }
+
+ @Test
+ public void testPageUpOnWindowsTerminal() throws Exception {
+ // test only works on Windows
+ if (!(TerminalFactory.get() instanceof WindowsTerminal)) {
+ return;
+ }
+
+ char[] characters = new char[]{
+ (char) SPECIAL_KEY_INDICATOR.code,
+ (char) PAGE_UP_KEY.code, '\r', '\n'
+ };
+ assertWindowsKeyBehavior("dir", characters);
+ }
+
+ @Test
+ public void testPageDownOnWindowsTerminal() throws Exception {
+ // test only works on Windows
+ if (!(TerminalFactory.get() instanceof WindowsTerminal)) {
+ return;
+ }
+
+ char[] characters = new char[]{
+ (char) SPECIAL_KEY_INDICATOR.code,
+ (char) PAGE_DOWN_KEY.code, '\r', '\n'
+ };
+ assertWindowsKeyBehavior("mkdir monkey", characters);
+ }
+
+ @Test
+ public void testEscapeOnWindowsTerminal() throws Exception {
+ // test only works on Windows
+ if (!(TerminalFactory.get() instanceof WindowsTerminal)) {
+ return;
+ }
+
+ char[] characters = new char[]{
+ 's', 's', 's',
+ (char) SPECIAL_KEY_INDICATOR.code,
+ (char) ESCAPE_KEY.code, '\r', '\n'
+ };
+ assertWindowsKeyBehavior("", characters);
+ }
+
+ @Test
+ public void testInsertOnWindowsTerminal() throws Exception {
+ // test only works on Windows
+ if (!(TerminalFactory.get() instanceof WindowsTerminal)) {
+ return;
+ }
+
+ char[] characters = new char[]{
+ 'o', 'p', 's',
+ (char) SPECIAL_KEY_INDICATOR.code,
+ (char) HOME_KEY.code,
+ (char) SPECIAL_KEY_INDICATOR.code,
+ (char) INSERT_KEY.code, 'o', 'o', 'p', 's', '\r', '\n'
+ };
+ assertWindowsKeyBehavior("oops", characters);
+ }
+
+ @Test
+ public void testExpansion() throws Exception {
+ ConsoleReader reader = new ConsoleReader();
+ MemoryHistory history = new MemoryHistory();
+ history.setMaxSize(3);
+ history.add("foo");
+ history.add("dir");
+ history.add("cd c:\\");
+ history.add("mkdir monkey");
+ reader.setHistory(history);
+
+ assertEquals("echo a!", reader.expandEvents("echo a!"));
+ assertEquals("mkdir monkey ; echo a!", reader.expandEvents("!! ; echo a!"));
+ assertEquals("echo ! a", reader.expandEvents("echo ! a"));
+ assertEquals("echo !\ta", reader.expandEvents("echo !\ta"));
+
+ assertEquals("mkdir barey", reader.expandEvents("^monk^bar^"));
+ assertEquals("mkdir barey", reader.expandEvents("^monk^bar"));
+ assertEquals("a^monk^bar", reader.expandEvents("a^monk^bar"));
+
+ assertEquals("mkdir monkey", reader.expandEvents("!!"));
+ assertEquals("echo echo a", reader.expandEvents("echo !#a"));
+
+ assertEquals("mkdir monkey", reader.expandEvents("!mk"));
+ try {
+ reader.expandEvents("!mz");
+ } catch (IllegalArgumentException e) {
+ assertEquals("!mz: event not found", e.getMessage());
+ }
+
+ assertEquals("mkdir monkey", reader.expandEvents("!?mo"));
+ assertEquals("mkdir monkey", reader.expandEvents("!?mo?"));
+
+ assertEquals("mkdir monkey", reader.expandEvents("!-1"));
+ assertEquals("cd c:\\", reader.expandEvents("!-2"));
+ assertEquals("cd c:\\", reader.expandEvents("!2"));
+ assertEquals("mkdir monkey", reader.expandEvents("!3"));
+ try {
+ reader.expandEvents("!20");
+ } catch (IllegalArgumentException e) {
+ assertEquals("!20: event not found", e.getMessage());
+ }
+ try {
+ reader.expandEvents("!-20");
+ } catch (IllegalArgumentException e) {
+ assertEquals("!-20: event not found", e.getMessage());
+ }
+ }
+}
diff --git a/src/jline/src/test/java/jline/console/ConsoleReaderTestSupport.java b/src/jline/src/test/java/jline/console/ConsoleReaderTestSupport.java
new file mode 100644
index 0000000000..7bb65fe3ca
--- /dev/null
+++ b/src/jline/src/test/java/jline/console/ConsoleReaderTestSupport.java
@@ -0,0 +1,142 @@
+/*
+ * 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.console;
+
+import jline.UnixTerminal;
+import org.junit.Before;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+
+import static jline.UnixTerminal.UnixKey.ARROW_DOWN;
+import static jline.UnixTerminal.UnixKey.ARROW_LEFT;
+import static jline.UnixTerminal.UnixKey.ARROW_PREFIX;
+import static jline.UnixTerminal.UnixKey.ARROW_RIGHT;
+import static jline.UnixTerminal.UnixKey.ARROW_START;
+import static jline.UnixTerminal.UnixKey.ARROW_UP;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+/**
+ * Provides support for console reader tests.
+ */
+public abstract class ConsoleReaderTestSupport
+{
+ protected ConsoleReader console;
+
+ @Before
+ public void setUp() throws Exception {
+ console = new ConsoleReader(null, new PrintWriter(new OutputStreamWriter(new ByteArrayOutputStream())), new UnixTerminal());
+ }
+
+ protected void assertBuffer(final String expected, final Buffer buffer) throws IOException {
+ assertBuffer(expected, buffer, true);
+ }
+
+ protected void assertBuffer(final String expected, final Buffer buffer, final boolean clear) throws IOException {
+ // clear current buffer, if any
+ if (clear) {
+ console.finishBuffer();
+ console.getHistory().clear();
+ }
+
+ console.setInput(new ByteArrayInputStream(buffer.getBytes()));
+
+ // run it through the reader
+ while (console.readLine((String) null) != null) {
+ // ignore
+ }
+
+ assertEquals(expected, console.getCursorBuffer().toString());
+ }
+
+ private int getKeyForAction(final Operation key) {
+ return getKeyForAction(key.code);
+ }
+
+ private int getKeyForAction(final short logicalAction) {
+ int action = console.getKeyForAction(logicalAction);
+
+ if (action == -1) {
+ fail("Keystroke for logical action " + logicalAction + " was not bound in the console");
+ }
+
+ return action;
+ }
+
+ protected class Buffer
+ {
+ private final ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+ public Buffer() {
+ // nothing
+ }
+
+ public Buffer(final String str) {
+ append(str);
+ }
+
+ public byte[] getBytes() {
+ return out.toByteArray();
+ }
+
+ public Buffer op(final short operation) {
+ return append(getKeyForAction(operation));
+ }
+
+ public Buffer op(final Operation op) {
+ return op(op.code);
+ }
+
+ public Buffer ctrlA() {
+ return append(getKeyForAction(Operation.MOVE_TO_BEG));
+ }
+
+ public Buffer ctrlU() {
+ return append(getKeyForAction(Operation.KILL_LINE_PREV));
+ }
+
+ public Buffer tab() {
+ return append(getKeyForAction(Operation.COMPLETE));
+ }
+
+ public Buffer back() {
+ return append(getKeyForAction(Operation.DELETE_PREV_CHAR));
+ }
+
+ public Buffer left() {
+ return append(ARROW_START.code).append(ARROW_PREFIX.code).append(ARROW_LEFT.code);
+ }
+
+ public Buffer right() {
+ return append(ARROW_START.code).append(ARROW_PREFIX.code).append(ARROW_RIGHT.code);
+ }
+
+ public Buffer up() {
+ return append(ARROW_START.code).append(ARROW_PREFIX.code).append(ARROW_UP.code);
+ }
+
+ public Buffer down() {
+ return append(ARROW_START.code).append(ARROW_PREFIX.code).append(ARROW_DOWN.code);
+ }
+
+ public Buffer append(final String str) {
+ for (byte b : str.getBytes()) {
+ append(b);
+ }
+ return this;
+ }
+
+ public Buffer append(final int i) {
+ out.write((byte) i);
+ return this;
+ }
+ }
+}
diff --git a/src/jline/src/test/java/jline/console/EditLineTest.java b/src/jline/src/test/java/jline/console/EditLineTest.java
new file mode 100644
index 0000000000..3471ab4276
--- /dev/null
+++ b/src/jline/src/test/java/jline/console/EditLineTest.java
@@ -0,0 +1,172 @@
+/*
+ * 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.console;
+
+import org.junit.Test;
+
+import static jline.console.Operation.DELETE_PREV_WORD;
+import static jline.console.Operation.MOVE_TO_END;
+import static jline.console.Operation.PREV_WORD;
+
+/**
+ * Tests various features of editing lines.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ */
+public class EditLineTest
+ extends ConsoleReaderTestSupport
+{
+ @Test
+ public void testDeletePreviousWord() throws Exception {
+ Buffer b = new Buffer("This is a test");
+
+ assertBuffer("This is a ", b = b.op(DELETE_PREV_WORD));
+ assertBuffer("This is ", b = b.op(DELETE_PREV_WORD));
+ assertBuffer("This ", b = b.op(DELETE_PREV_WORD));
+ assertBuffer("", b = b.op(DELETE_PREV_WORD));
+ assertBuffer("", b = b.op(DELETE_PREV_WORD));
+ assertBuffer("", b = b.op(DELETE_PREV_WORD));
+ }
+
+ @Test
+ public void testMoveToEnd() throws Exception {
+ Buffer b = new Buffer("This is a test");
+
+ assertBuffer("This is a XtestX",
+ new Buffer("This is a test").op(PREV_WORD)
+ .append('X')
+ .op(MOVE_TO_END)
+ .append('X'));
+
+ assertBuffer("This is Xa testX",
+ new Buffer("This is a test").op(PREV_WORD)
+ .op(PREV_WORD)
+ .append('X')
+ .op(MOVE_TO_END)
+ .append('X'));
+
+ assertBuffer("This Xis a testX",
+ new Buffer("This is a test").op(PREV_WORD)
+ .op(PREV_WORD)
+ .op(PREV_WORD)
+ .append('X')
+ .op(MOVE_TO_END)
+ .append('X'));
+ }
+
+ @Test
+ public void testPreviousWord() throws Exception {
+ assertBuffer("This is a Xtest",
+ new Buffer("This is a test").op(PREV_WORD)
+ .append('X'));
+ assertBuffer("This is Xa test",
+ new Buffer("This is a test").op(PREV_WORD)
+ .op(PREV_WORD)
+ .append('X'));
+ assertBuffer("This Xis a test",
+ new Buffer("This is a test").op(PREV_WORD)
+ .op(PREV_WORD)
+ .op(PREV_WORD)
+ .append('X'));
+ assertBuffer("XThis is a test",
+ new Buffer("This is a test").op(PREV_WORD)
+ .op(PREV_WORD)
+ .op(PREV_WORD)
+ .op(PREV_WORD)
+ .append('X'));
+ assertBuffer("XThis is a test",
+ new Buffer("This is a test").op(PREV_WORD)
+ .op(PREV_WORD)
+ .op(PREV_WORD)
+ .op(PREV_WORD)
+ .op(PREV_WORD)
+ .append('X'));
+ assertBuffer("XThis is a test",
+ new Buffer("This is a test").op(PREV_WORD)
+ .op(PREV_WORD)
+ .op(PREV_WORD)
+ .op(PREV_WORD)
+ .op(PREV_WORD)
+ .op(PREV_WORD)
+ .append('X'));
+ }
+
+ @Test
+ public void testLineStart() throws Exception {
+ assertBuffer("XThis is a test",
+ new Buffer("This is a test").ctrlA().append('X'));
+ assertBuffer("TXhis is a test",
+ new Buffer("This is a test").ctrlA().right().append('X'));
+ }
+
+ @Test
+ public void testClearLine() throws Exception {
+ assertBuffer("", new Buffer("This is a test").ctrlU());
+ assertBuffer("t", new Buffer("This is a test").left().ctrlU());
+ assertBuffer("st", new Buffer("This is a test").left().left().ctrlU());
+ }
+
+ @Test
+ public void testRight() throws Exception {
+ Buffer b = new Buffer("This is a test");
+ b = b.left().right().back();
+ assertBuffer("This is a tes", b);
+ b = b.left().left().left().right().left().back();
+ assertBuffer("This is ates", b);
+ b.append('X');
+ assertBuffer("This is aXtes", b);
+ }
+
+ @Test
+ public void testLeft() throws Exception {
+ Buffer b = new Buffer("This is a test");
+ b = b.left().left().left();
+ assertBuffer("This is a est", b = b.back());
+ assertBuffer("This is aest", b = b.back());
+ assertBuffer("This is est", b = b.back());
+ assertBuffer("This isest", b = b.back());
+ assertBuffer("This iest", b = b.back());
+ assertBuffer("This est", b = b.back());
+ assertBuffer("Thisest", b = b.back());
+ assertBuffer("Thiest", b = b.back());
+ assertBuffer("Thest", b = b.back());
+ assertBuffer("Test", b = b.back());
+ assertBuffer("est", b = b.back());
+ assertBuffer("est", b = b.back());
+ assertBuffer("est", b = b.back());
+ assertBuffer("est", b = b.back());
+ assertBuffer("est", b = b.back());
+ }
+
+ @Test
+ public void testBackspace() throws Exception {
+ Buffer b = new Buffer("This is a test");
+ assertBuffer("This is a tes", b = b.back());
+ assertBuffer("This is a te", b = b.back());
+ assertBuffer("This is a t", b = b.back());
+ assertBuffer("This is a ", b = b.back());
+ assertBuffer("This is a", b = b.back());
+ assertBuffer("This is ", b = b.back());
+ assertBuffer("This is", b = b.back());
+ assertBuffer("This i", b = b.back());
+ assertBuffer("This ", b = b.back());
+ assertBuffer("This", b = b.back());
+ assertBuffer("Thi", b = b.back());
+ assertBuffer("Th", b = b.back());
+ assertBuffer("T", b = b.back());
+ assertBuffer("", b = b.back());
+ assertBuffer("", b = b.back());
+ assertBuffer("", b = b.back());
+ assertBuffer("", b = b.back());
+ assertBuffer("", b = b.back());
+ }
+
+ @Test
+ public void testBuffer() throws Exception {
+ assertBuffer("This is a test", new Buffer("This is a test"));
+ }
+}
diff --git a/src/jline/src/test/java/jline/console/completer/ArgumentCompleterTest.java b/src/jline/src/test/java/jline/console/completer/ArgumentCompleterTest.java
new file mode 100644
index 0000000000..a74acf4adb
--- /dev/null
+++ b/src/jline/src/test/java/jline/console/completer/ArgumentCompleterTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2010 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 jline.console.completer;
+
+import jline.console.ConsoleReaderTestSupport;
+import jline.console.completer.ArgumentCompleter;
+import jline.console.completer.StringsCompleter;
+import org.junit.Test;
+
+/**
+ * Tests for {@link jline.console.completer.ArgumentCompleter}.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ */
+public class ArgumentCompleterTest
+ extends ConsoleReaderTestSupport
+{
+ @Test
+ public void test1() throws Exception {
+ console.addCompleter(new ArgumentCompleter(new StringsCompleter("foo", "bar", "baz")));
+
+ assertBuffer("foo foo ", new Buffer("foo f").tab());
+ assertBuffer("foo ba", new Buffer("foo b").tab());
+ assertBuffer("foo ba", new Buffer("foo ba").tab());
+ assertBuffer("foo baz ", new Buffer("foo baz").tab());
+
+ // test completion in the mid range
+ assertBuffer("foo baz", new Buffer("f baz").left().left().left().left().tab());
+ assertBuffer("ba foo", new Buffer("b foo").left().left().left().left().tab());
+ assertBuffer("foo ba baz", new Buffer("foo b baz").left().left().left().left().tab());
+ assertBuffer("foo foo baz", new Buffer("foo f baz").left().left().left().left().tab());
+ }
+} \ No newline at end of file
diff --git a/src/jline/src/test/java/jline/console/completer/NullCompleterTest.java b/src/jline/src/test/java/jline/console/completer/NullCompleterTest.java
new file mode 100644
index 0000000000..accdd801ac
--- /dev/null
+++ b/src/jline/src/test/java/jline/console/completer/NullCompleterTest.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2010 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 jline.console.completer;
+
+import jline.console.ConsoleReaderTestSupport;
+import jline.console.completer.NullCompleter;
+import org.junit.Test;
+
+/**
+ * Tests for {@link NullCompleter}.
+ *
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ */
+public class NullCompleterTest
+ extends ConsoleReaderTestSupport
+{
+ @Test
+ public void test1() throws Exception {
+ console.addCompleter(NullCompleter.INSTANCE);
+
+ assertBuffer("f", new Buffer("f").tab());
+ assertBuffer("ba", new Buffer("ba").tab());
+ assertBuffer("baz", new Buffer("baz").tab());
+ }
+} \ No newline at end of file
diff --git a/src/jline/src/test/java/jline/console/completer/StringsCompleterTest.java b/src/jline/src/test/java/jline/console/completer/StringsCompleterTest.java
new file mode 100644
index 0000000000..6c7c982a25
--- /dev/null
+++ b/src/jline/src/test/java/jline/console/completer/StringsCompleterTest.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2010 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 jline.console.completer;
+
+import jline.console.ConsoleReaderTestSupport;
+import jline.console.completer.StringsCompleter;
+import org.junit.Test;
+
+/**
+ * Tests for {@link jline.console.completer.StringsCompleter}.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ */
+public class StringsCompleterTest
+ extends ConsoleReaderTestSupport
+{
+ @Test
+ public void test1() throws Exception {
+ console.addCompleter(new StringsCompleter("foo", "bar", "baz"));
+
+ assertBuffer("foo ", new Buffer("f").tab());
+ // single tab completes to unambiguous "ba"
+ assertBuffer("ba", new Buffer("b").tab());
+ assertBuffer("ba", new Buffer("ba").tab());
+ assertBuffer("baz ", new Buffer("baz").tab());
+ }
+} \ No newline at end of file
diff --git a/src/jline/src/test/java/jline/console/history/HistoryTest.java b/src/jline/src/test/java/jline/console/history/HistoryTest.java
new file mode 100644
index 0000000000..c53107d984
--- /dev/null
+++ b/src/jline/src/test/java/jline/console/history/HistoryTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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.console.history;
+
+import jline.console.ConsoleReaderTestSupport;
+import org.junit.Test;
+
+import static jline.console.Operation.MOVE_TO_BEG;
+import static jline.console.Operation.NEWLINE;
+import static jline.console.Operation.NEXT_HISTORY;
+import static jline.console.Operation.PREV_HISTORY;
+import static jline.console.Operation.PREV_CHAR;
+
+/**
+ * Tests command history.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ */
+public class HistoryTest
+ extends ConsoleReaderTestSupport
+{
+ @Test
+ public void testSingleHistory() throws Exception {
+ Buffer b = new Buffer().
+ append("test line 1").op(NEWLINE).
+ append("test line 2").op(NEWLINE).
+ append("test line 3").op(NEWLINE).
+ append("test line 4").op(NEWLINE).
+ append("test line 5").op(NEWLINE).
+ append("");
+
+ assertBuffer("", b);
+
+ assertBuffer("test line 5", b = b.op(PREV_HISTORY));
+ assertBuffer("test line 5", b = b.op(PREV_CHAR));
+ assertBuffer("test line 4", b = b.op(PREV_HISTORY));
+ assertBuffer("test line 5", b = b.op(NEXT_HISTORY));
+ assertBuffer("test line 4", b = b.op(PREV_HISTORY));
+ assertBuffer("test line 3", b = b.op(PREV_HISTORY));
+ assertBuffer("test line 2", b = b.op(PREV_HISTORY));
+ assertBuffer("test line 1", b = b.op(PREV_HISTORY));
+
+ // beginning of history
+ assertBuffer("test line 1", b = b.op(PREV_HISTORY));
+ assertBuffer("test line 1", b = b.op(PREV_HISTORY));
+ assertBuffer("test line 1", b = b.op(PREV_HISTORY));
+ assertBuffer("test line 1", b = b.op(PREV_HISTORY));
+
+ assertBuffer("test line 2", b = b.op(NEXT_HISTORY));
+ assertBuffer("test line 3", b = b.op(NEXT_HISTORY));
+ assertBuffer("test line 4", b = b.op(NEXT_HISTORY));
+ assertBuffer("test line 5", b = b.op(NEXT_HISTORY));
+
+ // end of history
+ assertBuffer("", b = b.op(NEXT_HISTORY));
+ assertBuffer("", b = b.op(NEXT_HISTORY));
+ assertBuffer("", b = b.op(NEXT_HISTORY));
+
+ assertBuffer("test line 5", b = b.op(PREV_HISTORY));
+ assertBuffer("test line 4", b = b.op(PREV_HISTORY));
+ b = b.op(MOVE_TO_BEG).append("XXX").op(NEWLINE);
+ assertBuffer("XXXtest line 4", b = b.op(PREV_HISTORY));
+ assertBuffer("test line 5", b = b.op(PREV_HISTORY));
+ assertBuffer("test line 4", b = b.op(PREV_HISTORY));
+ assertBuffer("test line 5", b = b.op(NEXT_HISTORY));
+ assertBuffer("XXXtest line 4", b = b.op(NEXT_HISTORY));
+ assertBuffer("", b = b.op(NEXT_HISTORY));
+
+ assertBuffer("XXXtest line 4", b = b.op(PREV_HISTORY));
+ assertBuffer("XXXtest line 4", b = b.op(NEWLINE).op(PREV_HISTORY));
+ assertBuffer("XXXtest line 4", b = b.op(NEWLINE).op(PREV_HISTORY));
+ assertBuffer("XXXtest line 4", b = b.op(NEWLINE).op(PREV_HISTORY));
+ assertBuffer("XXXtest line 4", b = b.op(NEWLINE).op(PREV_HISTORY));
+ }
+}
diff --git a/src/jline/src/test/java/jline/console/history/MemoryHistoryTest.java b/src/jline/src/test/java/jline/console/history/MemoryHistoryTest.java
new file mode 100644
index 0000000000..6e5c731a80
--- /dev/null
+++ b/src/jline/src/test/java/jline/console/history/MemoryHistoryTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2010 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 jline.console.history;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static junit.framework.Assert.*;
+
+/**
+ * Tests for {@link MemoryHistory}.
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ */
+public class MemoryHistoryTest
+{
+ private MemoryHistory history;
+
+ @Before
+ public void setUp() {
+ history = new MemoryHistory();
+ }
+
+ @After
+ public void tearDown() {
+ history = null;
+ }
+
+ @Test
+ public void testAdd() {
+ assertEquals(0, history.size());
+
+ history.add("test");
+
+ assertEquals(1, history.size());
+ assertEquals("test", history.get(0));
+ assertEquals(1, history.index());
+ }
+
+ private void assertHistoryContains(final int offset, final String... items) {
+ assertEquals(items.length, history.size());
+ int i=0;
+ for (History.Entry entry : history) {
+ assertEquals(offset + i, entry.index());
+ assertEquals(items[i++], entry.value());
+ }
+ }
+
+ @Test
+ public void testOffset() {
+ history.setMaxSize(5);
+
+ assertEquals(0, history.size());
+ assertEquals(0, history.index());
+
+ history.add("a");
+ history.add("b");
+ history.add("c");
+ history.add("d");
+ history.add("e");
+
+ assertEquals(5, history.size());
+ assertEquals(5, history.index());
+ assertHistoryContains(0, "a", "b", "c", "d", "e");
+
+ history.add("f");
+
+ assertEquals(5, history.size());
+ assertEquals(6, history.index());
+
+ assertHistoryContains(1, "b", "c", "d", "e", "f");
+ assertEquals("f", history.get(5));
+ }
+
+ @Test
+ public void testReplace() {
+ assertEquals(0, history.size());
+
+ history.add("a");
+ history.add("b");
+ history.replace("c");
+
+ assertHistoryContains(0, "a", "c");
+ }
+} \ No newline at end of file
diff --git a/src/jline/src/test/java/jline/example/Example.java b/src/jline/src/test/java/jline/example/Example.java
index 80a8d99e33..0da3799cd3 100644
--- a/src/jline/src/test/java/jline/example/Example.java
+++ b/src/jline/src/test/java/jline/example/Example.java
@@ -6,33 +6,34 @@
*/
package jline.example;
-import jline.*;
+import jline.console.completer.*;
+import jline.console.ConsoleReader;
import java.io.*;
import java.util.*;
-import java.util.zip.*;
-public class Example {
+public class Example
+{
public static void usage() {
System.out.println("Usage: java " + Example.class.getName()
- + " [none/simple/files/dictionary [trigger mask]]");
+ + " [none/simple/files/dictionary [trigger mask]]");
System.out.println(" none - no completors");
System.out.println(" simple - a simple completor that comples "
- + "\"foo\", \"bar\", and \"baz\"");
+ + "\"foo\", \"bar\", and \"baz\"");
System.out
- .println(" files - a completor that comples " + "file names");
+ .println(" files - a completor that comples " + "file names");
System.out.println(" dictionary - a completor that comples "
- + "english dictionary words");
+ + "english dictionary words");
System.out.println(" classes - a completor that comples "
- + "java class names");
+ + "java class names");
System.out
- .println(" trigger - a special word which causes it to assume "
- + "the next line is a password");
+ .println(" trigger - a special word which causes it to assume "
+ + "the next line is a password");
System.out.println(" mask - is the character to print in place of "
- + "the actual password character");
+ + "the actual password character");
System.out.println("\n E.g - java Example simple su '*'\n"
- + "will use the simple compleator with 'su' triggering\n"
- + "the use of '*' as a password mask.");
+ + "will use the simple compleator with 'su' triggering\n"
+ + "the use of '*' as a password mask.");
}
public static void main(String[] args) throws IOException {
@@ -40,8 +41,8 @@ public class Example {
String trigger = null;
ConsoleReader reader = new ConsoleReader();
+
reader.setBellEnabled(false);
- reader.setDebug(new PrintWriter(new FileWriter("writer.debug", true)));
if ((args == null) || (args.length == 0)) {
usage();
@@ -49,21 +50,18 @@ public class Example {
return;
}
- List<Completor> completors = new LinkedList<Completor>();
+ List<Completer> completors = new LinkedList<Completer>();
if (args.length > 0) {
if (args[0].equals("none")) {
- } else if (args[0].equals("files")) {
- completors.add(new FileNameCompletor());
- } else if (args[0].equals("classes")) {
- completors.add(new ClassNameCompletor());
- } else if (args[0].equals("dictionary")) {
- completors.add(new SimpleCompletor(new GZIPInputStream(
- Example.class.getResourceAsStream("english.gz"))));
- } else if (args[0].equals("simple")) {
- completors.add(new SimpleCompletor(new String[] { "foo", "bar",
- "baz" }));
- } else {
+ }
+ else if (args[0].equals("files")) {
+ completors.add(new FileNameCompleter());
+ }
+ else if (args[0].equals("simple")) {
+ completors.add(new StringsCompleter("foo", "bar", "baz"));
+ }
+ else {
usage();
return;
@@ -71,11 +69,13 @@ public class Example {
}
if (args.length == 3) {
- mask = new Character(args[2].charAt(0));
+ mask = args[2].charAt(0);
trigger = args[1];
}
- reader.addCompletor(new ArgumentCompletor(completors));
+ for (Completer c : completors) {
+ reader.addCompleter(c);
+ }
String line;
PrintWriter out = new PrintWriter(System.out);
diff --git a/src/jline/src/test/java/jline/example/PasswordReader.java b/src/jline/src/test/java/jline/example/PasswordReader.java
deleted file mode 100644
index 133185540a..0000000000
--- a/src/jline/src/test/java/jline/example/PasswordReader.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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.example;
-
-import jline.*;
-
-import java.io.*;
-
-public class PasswordReader {
- public static void usage() {
- System.out.println("Usage: java "
- + PasswordReader.class.getName() + " [mask]");
- }
-
- public static void main(String[] args) throws IOException {
- ConsoleReader reader = new ConsoleReader();
-
- Character mask = (args.length == 0)
- ? new Character((char) 0)
- : new Character(args[0].charAt(0));
-
- String line = null;
- do {
- line = reader.readLine("enter password> ", mask);
- System.out.println("Got password: " + line);
- } while(line != null && line.length() > 0);
- }
-}
diff --git a/src/jline/src/test/java/jline/internal/TerminalLineSettingsTest.java b/src/jline/src/test/java/jline/internal/TerminalLineSettingsTest.java
new file mode 100644
index 0000000000..80b7f0be0b
--- /dev/null
+++ b/src/jline/src/test/java/jline/internal/TerminalLineSettingsTest.java
@@ -0,0 +1,146 @@
+package jline.internal;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests for the {@link TerminalLineSettings}.
+ *
+ * @author <a href="mailto:jbonofre@apache.org">Jean-Baptiste Onofré</a>
+ */
+public class TerminalLineSettingsTest
+{
+ private TerminalLineSettings settings;
+
+ private final String linuxSttySample = "speed 38400 baud; rows 85; columns 244; line = 0;\n" +
+ "intr = ^C; quit = ^\\; erase = ^?; kill = ^U; eof = ^D; eol = M-^?; eol2 = M-^?; swtch = M-^?; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0;\n" +
+ "-parenb -parodd cs8 hupcl -cstopb cread -clocal -crtscts\n" +
+ "-ignbrk brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc ixany imaxbel iutf8\n" +
+ "opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0\n" +
+ "isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke";
+
+ private final String solarisSttySample = "speed 38400 baud; \n" +
+ "rows = 85; columns = 244; ypixels = 0; xpixels = 0;\n" +
+ "csdata ?\n" +
+ "eucw 1:0:0:0, scrw 1:0:0:0\n" +
+ "intr = ^c; quit = ^\\; erase = ^?; kill = ^u;\n" +
+ "eof = ^d; eol = -^?; eol2 = -^?; swtch = <undef>;\n" +
+ "start = ^q; stop = ^s; susp = ^z; dsusp = ^y;\n" +
+ "rprnt = ^r; flush = ^o; werase = ^w; lnext = ^v;\n" +
+ "-parenb -parodd cs8 -cstopb -hupcl cread -clocal -loblk -crtscts -crtsxoff -parext \n" +
+ "-ignbrk brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl -iuclc \n" +
+ "ixon ixany -ixoff imaxbel \n" +
+ "isig icanon -xcase echo echoe echok -echonl -noflsh \n" +
+ "-tostop echoctl -echoprt echoke -defecho -flusho -pendin iexten \n" +
+ "opost -olcuc onlcr -ocrnl -onocr -onlret -ofill -ofdel tab3";
+
+ private final String aixSttySample = "speed 38400 baud; 85 rows; 244 columns;\n" +
+ "eucw 1:1:0:0, scrw 1:1:0:0:\n" +
+ "intr = ^C; quit = ^\\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>\n" +
+ "eol2 = <undef>; start = ^Q; stop = ^S; susp = ^Z; dsusp = ^Y; reprint = ^R\n" +
+ "discard = ^O; werase = ^W; lnext = ^V\n" +
+ "-parenb -parodd cs8 -cstopb -hupcl cread -clocal -parext \n" +
+ "-ignbrk brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl -iuclc \n" +
+ "ixon ixany -ixoff imaxbel \n" +
+ "isig icanon -xcase echo echoe echok -echonl -noflsh \n" +
+ "-tostop echoctl -echoprt echoke -flusho -pending iexten \n" +
+ "opost -olcuc onlcr -ocrnl -onocr -onlret -ofill -ofdel tab3";
+
+ private final String macOsSttySample = "speed 9600 baud; 47 rows; 155 columns;\n" +
+ "lflags: icanon isig iexten echo echoe -echok echoke -echonl echoctl\n" +
+ "-echoprt -altwerase -noflsh -tostop -flusho pendin -nokerninfo\n" +
+ "-extproc\n" +
+ "iflags: -istrip icrnl -inlcr -igncr ixon -ixoff ixany imaxbel iutf8\n" +
+ "-ignbrk brkint -inpck -ignpar -parmrk\n" +
+ "oflags: opost onlcr -oxtabs -onocr -onlret\n" +
+ "cflags: cread cs8 -parenb -parodd hupcl -clocal -cstopb -crtscts -dsrflow\n" +
+ "-dtrflow -mdmbuf\n" +
+ "cchars: discard = ^O; dsusp = ^Y; eof = ^D; eol = <undef>;\n" +
+ "eol2 = <undef>; erase = ^?; intr = ^C; kill = ^U; lnext = ^V;\n" +
+ "min = 1; quit = ^\\; reprint = ^R; start = ^Q; status = ^T;\n" +
+ "stop = ^S; susp = ^Z; time = 0; werase = ^W;";
+
+ private final String netBsdSttySample = "speed 38400 baud; 85 rows; 244 columns;\n" +
+ "lflags: icanon isig iexten echo echoe echok echoke -echonl echoctl\n" +
+ " -echoprt -altwerase -noflsh -tostop -flusho pendin -nokerninfo\n" +
+ " -extproc\n" +
+ "iflags: -istrip icrnl -inlcr -igncr ixon -ixoff ixany imaxbel -ignbrk\n" +
+ " brkint -inpck -ignpar -parmrk\n" +
+ "oflags: opost onlcr -ocrnl oxtabs onocr onlret\n" +
+ "cflags: cread cs8 -parenb -parodd hupcl -clocal -cstopb -crtscts -mdmbuf\n" +
+ " -cdtrcts\n" +
+ "cchars: discard = ^O; dsusp = ^Y; eof = ^D; eol = <undef>;\n" +
+ " eol2 = <undef>; erase = ^?; intr = ^C; kill = ^U; lnext = ^V;\n" +
+ " min = 1; quit = ^\\; reprint = ^R; start = ^Q; status = ^T;\n" +
+ " stop = ^S; susp = ^Z; time = 0; werase = ^W;";
+
+ private final String freeBsdSttySample = "speed 9600 baud; 32 rows; 199 columns;\n" +
+ "lflags: icanon isig iexten echo echoe echok echoke -echonl echoctl\n" +
+ " -echoprt -altwerase -noflsh -tostop -flusho -pendin -nokerninfo\n" +
+ " -extproc\n" +
+ "iflags: -istrip icrnl -inlcr -igncr ixon -ixoff ixany imaxbel -ignbrk\n" +
+ " brkint -inpck -ignpar -parmrk\n" +
+ "oflags: opost onlcr -ocrnl tab0 -onocr -onlret\n" +
+ "cflags: cread cs8 -parenb -parodd hupcl -clocal -cstopb -crtscts -dsrflow\n" +
+ " -dtrflow -mdmbuf\n" +
+ "cchars: discard = ^O; dsusp = ^Y; eof = ^D; eol = <undef>;\n" +
+ " eol2 = <undef>; erase = ^?; erase2 = ^H; intr = ^C; kill = ^U;\n" +
+ " lnext = ^V; min = 1; quit = ^\\; reprint = ^R; start = ^Q;\n" +
+ " status = ^T; stop = ^S; susp = ^Z; time = 0; werase = ^W;";
+
+ @Before
+ public void setUp() throws Exception {
+ settings = new TerminalLineSettings();
+ }
+
+ @Test
+ public void testGetConfig() {
+ String config = settings.getConfig();
+ System.out.println(config);
+ }
+
+ @Test
+ public void testLinuxSttyParsing() {
+ assertEquals(0x7f, settings.getProperty("erase", linuxSttySample));
+ assertEquals(244, settings.getProperty("columns", linuxSttySample));
+ assertEquals(85, settings.getProperty("rows", linuxSttySample));
+ }
+
+ @Test
+ public void testSolarisSttyParsing() {
+ assertEquals(0x7f, settings.getProperty("erase", solarisSttySample));
+ assertEquals(244, settings.getProperty("columns", solarisSttySample));
+ assertEquals(85, settings.getProperty("rows", solarisSttySample));
+ }
+
+ @Test
+ public void testAixSttyParsing() {
+ assertEquals(0x7f, settings.getProperty("erase", aixSttySample));
+ assertEquals(244, settings.getProperty("columns", aixSttySample));
+ assertEquals(85, settings.getProperty("rows", aixSttySample));
+ }
+
+ @Test
+ public void testMacOsSttyParsing() {
+ assertEquals(0x7f, settings.getProperty("erase", macOsSttySample));
+ assertEquals(155, settings.getProperty("columns", macOsSttySample));
+ assertEquals(47, settings.getProperty("rows", macOsSttySample));
+ }
+
+ @Test
+ public void testNetBsdSttyParsing() {
+ assertEquals(0x7f, settings.getProperty("erase", netBsdSttySample));
+ assertEquals(244, settings.getProperty("columns", netBsdSttySample));
+ assertEquals(85, settings.getProperty("rows", netBsdSttySample));
+ }
+
+ @Test
+ public void testFreeBsdSttyParsing() {
+ assertEquals(0x7f, settings.getProperty("erase", freeBsdSttySample));
+ assertEquals(199, settings.getProperty("columns", freeBsdSttySample));
+ assertEquals(32, settings.getProperty("rows", freeBsdSttySample));
+ }
+
+} \ No newline at end of file
diff --git a/src/jline/src/test/resources/jline/example/english.gz b/src/jline/src/test/resources/jline/example/english.gz
deleted file mode 100644
index f0a85c08d9..0000000000
--- a/src/jline/src/test/resources/jline/example/english.gz
+++ /dev/null
Binary files differ