summaryrefslogtreecommitdiff
path: root/src/jline
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2010-12-12 19:13:10 +0000
committerPaul Phillips <paulp@improving.org>2010-12-12 19:13:10 +0000
commit5d6b870ea8b7b62670d616b055b85b03f061ba2b (patch)
treee419b0033657dfa3a49ce3513458a04f32c59816 /src/jline
parent9c238c6accf43f2bfe9bcfcdc7aa2384e71dc165 (diff)
downloadscala-5d6b870ea8b7b62670d616b055b85b03f061ba2b.tar.gz
scala-5d6b870ea8b7b62670d616b055b85b03f061ba2b.tar.bz2
scala-5d6b870ea8b7b62670d616b055b85b03f061ba2b.zip
New jline: BSD licensed, based on [ https://git...
New jline: BSD licensed, based on [ https://github.com/jdillon/jline2 ] with additional code thanks to [ https://github.com/huynhjl/jline2 ]. Replaces lib/jline.jar with build of these sources, and modifies trunk code to work with the new jar. Hopeful improvements including baseline functionality on cygwin and 64bit windows, as well as more accurate line wrapping / cursor positioning on all platforms and ctrl-R history search. For the time being the canonical source repository is this: https://github.com/paulp/jline2 The enclosed sources are a mirror of that repository, and should be treated as read-only in the scala svn repository. No review, codewise, but people are very strongly encouraged to try it out and report any regressions.
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