kotlinc よりも多機能な REPL: kotlin-interactive-shell の使い方

Kotlin のコンパイラである kotlnc には REPL 機能が組み込まれていますが、他言語と比べるとやや物足りない感じです。
そんな中、kotlin-interactive-shell（ki）という機能面で充実したツールが別途リリースされていた（もう数年前の話だけど）ので、試してみました。kotlinc の REPL 機能は近く廃止される予定なので、ki がその移行先となっているようです。

（そもそも REPL がそんなに需要ない説はある）

https://github.com/Kotlin/kotlin-interactive-shell

# ki のインストール

```bash
# macOS（Homebrew）ユーザ
brew install ki

# Linux（SDKMAN!） ユーザ
sdk install ki

# Windows（Scoop） ユーザ
scoop install extras/kotlin-interactive-shell
```

その他の方法については README.md をご参照ください。

# 使い方

基本的に kotlinc の上位互換になっているので、 kotlinc でも使える機能と ki にしかない機能について分けて説明していきます。[^1]

[^1]: class 情報を bytecode で terminal に dump する機能は kotlinc にしかないですが、あまり使いたいシチュエーションが思い浮かばないので、この記事では割愛します。

## kotlinc でも使える機能

以下の特徴については kotlinc と同じでした。

1. 式の実行結果は１実行ごとに自動的に res1, res2, ... のような定数に格納される
1. 最初の実行だけ数秒ほど時間がかかる
1. 基本的な使用方法については特にドキュメントはなく、 `:help` で確認する
1. `:quit` で REPL を終了する
1. `:load` で外部ファイルを REPL にロードする
1. 方向キーの上下で過去に実行した式を選択できる

以降、詳細な使い方を解説していきます。

## help / h コマンド

利用可能なコマンドのヘルプを表示できます。

```text:使用例
[0] :help
:quit or q                           quit the shell
:load or l <path>                    load file and evaluate
:type or t <expr>                    display the type of an expression without evaluating it
:list or ls                          list defined symbols
:help or h [command]                 print this summary or command-specific help
:paste or p                          enter paste mode
:syntax {on | off}                   syntax highlighting
:prompt [pattern]                    customize prompt
:set                                 set configuration parameter
:conf                                list configuration parameters
:dependsOn <artifact coordinates>    Load dependency from the current set of repositories
:repository <repository coordinates> Add repository for the artifacts lookup
:classpath or cp                     Show current script compilation classpath
```

`:help` にコマンド名を引数についてすると、そのコマンドの詳細なヘルプが表示できますが、詳細なヘルプが用意されているのが syntax, prompt, conf しかなかったです。

## quit / q コマンド

REPL を終了します。

## load / l コマンド

外部の Kotlin ファイルを REPL にロードして実行します。

```kotlin:sample.kts
fun greet(name: String) = "Hello, $name!"
```

`sample.kts` が配置されているディレクトリで `ki` を実行すればロードできます。

```text:使用例
[0] :load sample.kts
[1] greet("World")
res1: String = Hello, World!
```

# ki にしかない機能

ここからは kotlinc にはなかった ki 独自の機能の紹介です。

## type / t コマンド

式を評価せずに、その式の型情報を表示します。

```text:使用例
[0] :type "Hello"
String

[1] :type listOf(1, 2, 3)
List<Int>
```

## list / ls コマンド

現在定義されているシンボル（変数、関数など）の一覧を表示します。

```text:使用例
[0] val x = 1
[1] fun double(n: Int) = n * 2
[2] :list
val x: Int
fun double(n: Int): Int
```

ちなみに、式を実行した後は自動的に res0, res1, ... などの定数が作成されますが、それらはこの `:list` では表示されません。

## paste / p コマンド

複数行のコードをペーストするためのモードに入ります。
通常の入力モードでは Enter キーを押すとその行が即座に実行されますが、ペーストモードではコードブロック全体を一度に入力できます。

```text:使用例
[0] :paste
// Entering paste mode (ctrl-D to finish)
fun factorial(n: Int): Int {
    return if (n <= 1) 1
    else n * factorial(n - 1)
}
// Exiting paste mode, now interpreting.
[1] factorial(5)
res1: Int = 120
```

## syntax コマンド

シンタックスハイライトの有効/無効を切り替えます。

```text:使用例
[0] :syntax on
[1] :syntax off
```

## conf コマンド

REPL の設定パラメータを一覧表示します。

```text:使用例
[0] :conf
plugins
org.jetbrains.kotlinx.ki.shell.Shell.Settings.overrideSignals
org.jetbrains.kotlinx.ki.shell.plugins.SyntaxPlugin.Syntax.on
org.jetbrains.kotlinx.ki.shell.plugins.PromptPlugin.Prompt.pattern
org.jetbrains.kotlinx.ki.shell.plugins.PromptPlugin.Prompt.incomplete
history-file
org.jetbrains.kotlinx.ki.shell.Shell.Settings.sayHello
org.jetbrains.kotlinx.ki.shell.plugins.LoadFilePlugin.Load.short
org.jetbrains.kotlinx.ki.shell.plugins.LoadFilePlugin.Load.name
```

```text::help conf の実行結果
Usage: conf [-h] [-g] [-v] GLOB

  -h, --help                Prints help
  -g                        Groups by class
  -v                        Prints with values
  GLOB                      Glob pattern to match parameter (i.e. *.name)
```

ここは詳細不明なので、紹介まで。

## set コマンド

REPL の設定パラメータを変更します。設定可能なパラメータは `:conf` コマンドで確認できます。
ただ、手元で試しましたが、設定失敗するのでよくわからないです。

## dependsOn コマンド

外部ライブラリの依存関係を追加します。Gradle の座標形式で指定します。
ただ、使おうとしましたが、どうやら推移的な依存関係を持つ Maven のライブラリはそもそも `:dependsOn` では使用できないようです。残念。

https://github.com/Kotlin/kotlin-interactive-shell/issues/109

```text:使用例（失敗）
[0] :dependsOn com.fleeksoft.ksoup:ksoup:0.2.1
[1] "<html><head><title>One</title></head><body>Two</body></html>"
res1: String = <html><head><title>One</title></head><body>Two</body></html>
[2] com.fleeksoft.ksoup.Ksoup.parse(html = res1)
ERROR Unresolved reference: Ksoup (Line_5.kts:1:5)
```

## repository コマンド

依存関係を解決する際に使用するリポジトリを切り替えます。
注意が必要なのは、これはリポジトリの追加ではなく切り替えなので、実行した後は Maven Central からは取得できなくなります。

```text:使用例
[0] :repository https://example.com/not_maven/repository
```

## classpath / cp コマンド

現在の Kotlin 実行時のクラスパスを表示します。

```text:使用例
[0] :classpath
C:\Users\nimzo6689\scoop\apps\kotlin-interactive-shell\current\lib\ki-shell.jar
```