S-JIS[2022-09-02/2022-09-05] 変更履歴

JLine3 LineReader

JLine3のLineReaderのメモ。


概要

LineReaderは、JLine3でユーザーからの入力を扱うクラス。


import java.io.IOException;

import org.jline.reader.LineReader;
import org.jline.reader.LineReaderBuilder;
import org.jline.terminal.Terminal;
import org.jline.terminal.TerminalBuilder;
public class JLineExample {

    public static void main(String[] args) throws IOException {
        try (Terminal terminal = TerminalBuilder.terminal()) {
            LineReader lineReader = LineReaderBuilder.builder() //
                .terminal(terminal) //
                .build();

            for (;;) {
                String line = lineReader.readLine("jline> "); // 文字列引数はプロンプト

                terminal.writer().println(line);
            }
        }
    }
}

readLine()を呼ぶと、プロンプトが表示されて、ユーザーからの入力待ちになる。

ユーザーのキー操作に伴う特殊な処理(カーソルの上下やCtrl+Rを押したときの履歴の表示等)はLineReader(具象クラスはLineReaderImpl)が行う。

ユーザーが入力した文字列の解析はParserが行う。(→DefaultParser
Parser.parse()がEOFErrorを返すと、LineReaderは次の行の入力を待ち、元の文字列と結合して再びParser.parse()を呼び出す。(→複数行の入力

エスケープ文字が設定されている場合、エスケープ処理された文字列がreadLine()から返ってくる。(デフォルトでは「\」がエスケープ文字として設定されている)
また、その文字列を履歴に登録するのもLineReaderが行っている。


エスケープ処理を抑止する例

デフォルトでは、ユーザーがエスケープ文字を入力すると、エスケープ処理された文字列がreadLine()から返される。[2022-09-05]
(例えば「\exit」という文字列を入力すると「exit」が返される)

\」から始まる文字列をコマンドとして扱いたいような場合は、エスケープ処理を抑止するのが良いだろう。

エスケープ処理の実施の有無はDISABLE_EVENT_EXPANSIONオプションで制御できる。

    LineReader lineReader = LineReaderBuilder.builder() //
        .terminal(terminal) //
        .option(Option.DISABLE_EVENT_EXPANSION, true) // エスケープ処理を無効にする
        .build();
    lineReader.setOpt(Option.DISABLE_EVENT_EXPANSION);   // エスケープ処理を無効にする
    lineReader.unsetOpt(Option.DISABLE_EVENT_EXPANSION); // エスケープ処理を有効にする(デフォルト)
    lineReader.option(Option.DISABLE_EVENT_EXPANSION, true); // エスケープ処理を無効にする

※エスケープ処理を無効にすると、行継続も出来なくなる

エスケープ文字を指定する方法


閉じ括弧のblinkを抑止する例

デフォルトでは、閉じ括弧「)]}」を入力すると、対応する開き括弧の位置にカーソルが一時的に移動する(blinkする)。

LineReaderのBLINK_MATCHING_PARENでblinkの時間を指定できる。(デフォルト値は500[ミリ秒])
0以下を指定するとblinkしなくなる。

    LineReader lineReader = LineReaderBuilder.builder() //
        .terminal(terminal) //
        .variable(LineReader.BLINK_MATCHING_PAREN, 0) // blinkを抑止
        .build();
    LineReader lineReader = LineReaderBuilder.builder() //
        .terminal(terminal) //
        .build();
    if (terminal.getType().equals(Terminal.TYPE_DUMB)) {
        // DumbTerminalだけblinkを抑止
        lineReader.setVariable(LineReader.BLINK_MATCHING_PAREN, 0);
    }

参考: JLine3のdemoのRepl.java


ただし、DumbTerminalではblinkがきちんと動作しない。 (jline 3.21.0)

閉じ括弧を含む入力データ自体が画面上にそのまま表示される。
そのため、自分でも入力データを表示していると、二重に表示されているように見えてしまう。

DumbTerminalでの使用時に、二重に表示されてしまう例
jline> (a)
(a)(a)
jline> }
}}

BLINK_MATCHING_PARENに0以下を指定するとblinkしなくなるので、DumbTerminalで余計な表示がされなくなる。


JLine3へ戻る / JLineへ戻る / Javaへ戻る / 技術メモへ戻る
メールの送信先:ひしだま