# 画面設計書 4-シェルモード（shell>）

## 概要

OSシェルコマンドを実行するREPLモードの設計書。cdコマンドはJuliaプロセスの作業ディレクトリを変更する特別な処理を持つ。

### 本画面の処理概要

本画面は、Julia REPLのシェルモードであり、ユーザーがOSのシェルコマンドをJulia REPL内から直接実行できるインタフェースを提供する。

**業務上の目的・背景**：Juliaプログラミング中にファイル操作、環境確認、外部ツール実行等のOS操作をREPLを離れることなく行えるようにするためのモードである。特に `cd` コマンドはJuliaプロセス自体の作業ディレクトリを変更する特別な処理を持ち、ファイルの読み書きやパッケージ操作で重要な役割を果たす。`sticky=true` が設定されているため、一度シェルモードに入ると実行後も自動的にシェルモードが維持され、連続してコマンドを実行できる。

**画面へのアクセス方法**：Juliaプロンプト画面で `;` キーを行頭で入力すると本モードに遷移する。プロンプトが `shell>` に変わり、シェルコマンドの入力が可能になる。

**主要な操作・処理内容**：
1. ユーザーがシェルモードのプロンプト（`shell>`）にOSコマンドを入力する
2. 入力文字列が `Base.shell_parse()` でシェルの引用規則に従いパースされる
3. `cd` コマンドの場合は `Base.repl_cmd()` 内で特別処理され、`cd()` / `expanduser()` / `pwd()` を使用してJuliaプロセスの作業ディレクトリを変更する
4. その他のコマンドは `run(ignorestatus(cmd))` でOSのシェルを介して実行される
5. 非Windowsでは `JULIA_SHELL` 環境変数、次に `SHELL` 環境変数のシェルが使用される（デフォルト: `/bin/sh`）
6. コマンド実行失敗時はエラーメッセージが表示されるが、REPLは継続する

**画面遷移**：
- 遷移元：Juliaプロンプト（`;` キー入力、行頭）
- 遷移先：Juliaプロンプト（`Backspace` 行頭、`Ctrl+C`）
- sticky=trueにより、コマンド実行後もシェルモードが維持される

**権限による表示制御**：権限による表示制御は存在しない。OSレベルの権限によりコマンドの実行可否が決まる。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 70 | コマンド実行 | 主機能 | run/Cmdによるシェルコマンド実行。Base.repl_cmd()でコマンドをパース・実行する |
| 71 | プロセス制御 | 補助機能 | ignorestatus()でプロセス終了コードを無視した実行 |
| 72 | パイプライン | 補助機能 | pipelineによるシェルコマンドのパイプライン接続 |
| 41 | パス操作 | 補助機能 | cdコマンド実行時のexpanduser/pwd/cd関数によるディレクトリ操作 |
| 102 | REPL | 補助機能 | REPLモジュール内のシェルモードプロンプトとして実装 |
| 64 | エラー表示 | 補助機能 | コマンド実行失敗時のdisplay_errorによるエラーメッセージ表示 |

## 画面種別

コマンド実行（シェルモード）

## URL/ルーティング

該当なし（ターミナルベースのCLIアプリケーション）

## 入出力項目

| 項目名 | 入出力 | 型 | 説明 |
|--------|--------|-----|------|
| シェルコマンド | 入力 | String | ユーザーが入力するOSシェルコマンド文字列 |
| コマンド出力 | 出力 | String | コマンドの標準出力・標準エラー出力 |
| エラー情報 | 出力 | String | コマンド実行失敗時のエラーメッセージ |
| 変更後ディレクトリ | 出力 | String | cdコマンド実行後のpwd()結果 |

## 表示項目

| 項目名 | 表示内容 | 条件 |
|--------|----------|------|
| プロンプト | `shell> ` | シェルモード時 |
| コマンド出力 | OSコマンドの標準出力 | コマンド実行成功時 |
| ディレクトリパス | cd後のカレントディレクトリ | cdコマンド実行時 |
| エラーメッセージ | display_errorによるエラー表示 | コマンド実行失敗時 |

## イベント仕様

### 1-コマンド実行（Enter）

ユーザーがコマンドを入力してEnterを押下すると、`on_done` コールバックが `Base.repl_cmd()` を呼び出す。入力文字列は `Base.shell_parse()` でパースされ、`Base.cmd_gen()` でCmdオブジェクトに変換される。

### 2-cdコマンド

`cd` コマンドは `Base.repl_cmd()` 内で特別扱いされる：
- 引数なし：`homedir()` に移動
- 引数1つ：指定ディレクトリに移動（`expanduser()` で `~` を展開）
- `cd -`：`ENV["OLDPWD"]` に移動
- 引数2つ以上：ArgumentError

移動前のディレクトリは `ENV["OLDPWD"]` に保存される。

### 3-モード離脱（Backspace / Ctrl+C）

行頭で `Backspace` を押下するか、`Ctrl+C` を押下するとJuliaプロンプトに戻る。

## データベース更新仕様

### 操作別データベース影響一覧

該当なし（データベースを使用しない）

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|-------------|------|---------------|----------|
| - | エラー | コマンド実行失敗エラー | コマンドが見つからない・実行権限がない等の場合 |
| - | エラー | `cd: OLDPWD not set` | `cd -` で OLDPWD未設定の場合 |
| - | エラー | `cd method only takes one argument` | cdに2つ以上の引数を渡した場合 |

## 例外処理

| 例外 | 発生条件 | 対応 |
|------|----------|------|
| ArgumentError | cd引数不正（引数なし、引数2つ以上） | エラーメッセージを表示してREPLを継続 |
| コマンド未検出 | 指定コマンドがPATHに存在しない | display_errorでエラー表示してREPLを継続 |
| IOError | 現在のディレクトリが削除されている場合のpwd()エラー | OLDPWDを削除して処理を継続 |

## 備考

- シェルモードは `sticky=true` で設定されているため、コマンド実行後もシェルモードが維持される
- 非WindowsではJULIA_SHELL → SHELL → /bin/sh の優先順位でシェルが選択される
- `expanduser()` により `~` がホームディレクトリに展開される
- `ignorestatus()` によりコマンドの非ゼロ終了コードでもJulia側でエラーにならない
- `ShellCompletionProvider` によりファイルパス補完が提供される

---

## コードリーディングガイド

本画面を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

シェルモードの中核はCmd型とシェルのパース処理である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | cmd.jl | `base/cmd.jl` | Cmd構造体の定義。exec, ignorestatus等のフィールドを確認 |
| 1-2 | shell.jl | `base/shell.jl` | shell_parse(), shell_escape_posixly() のシェル引用規則処理 |

**読解のコツ**: Juliaのコマンドリテラル（バッククォート構文 `` `cmd` ``）はCmd型を生成する。shell_parse()はPOSIX シェルの引用規則に従い文字列をパースする。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | REPL.jl | `stdlib/REPL/src/REPL.jl` | shell_modeのPrompt設定（1316-1330行）: on_doneでBase.repl_cmd()を呼び出す設定 |
| 2-2 | client.jl | `base/client.jl` | repl_cmd()関数（34-79行）: シェルコマンド実行のメインロジック |

**主要処理フロー**:
1. **1325-1329行**: on_doneでshell_parse()→cmd_gen()→Base.repl_cmd()の呼び出しチェーンを構築
2. **36行**: cmd.exec に expanduser() を適用して引数を展開
3. **40-62行**: cdコマンドの特別処理（引数解析、OLDPWD管理、ディレクトリ変更）
4. **64-78行**: その他のコマンドの実行（シェル経由、ignorestatus付き）

#### Step 3: コマンド実行の詳細を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | process.jl | `base/process.jl` | run(), ignorestatus() の実装 |
| 3-2 | client.jl | `base/client.jl` | repl_cmd()内のエラーハンドリング（70-77行） |

### プログラム呼び出し階層図

```
setup_interface() で shell_mode の on_done を設定 [1316行]
    |
    +-- on_done コールバック
            |
            +-- Base.shell_parse(line)
            +-- Base.cmd_gen()
            +-- Base.repl_cmd(cmd, out)  [34行]
                    |
                    +-- expanduser() で引数展開  [36行]
                    |
                    +-- if cmd == "cd"  [40行]
                    |       +-- cd(dir) / homedir()
                    |       +-- ENV["OLDPWD"] = pwd()
                    |       +-- println(out, pwd())
                    |
                    +-- else  [63行]
                            +-- shell_split(ENV["JULIA_SHELL"])
                            +-- run(ignorestatus(cmd))
                            +-- display_error() (失敗時)
```

### データフロー図

```
[入力]                  [処理]                         [出力]

ユーザー入力     -----> shell_parse()             -----> Cmd オブジェクト
(コマンド文字列)        |
                  cmd_gen() で Cmd 生成
                        |
                  repl_cmd(cmd, out)
                        |
                  +-- cd コマンド?
                  |   Yes: cd(dir)             -----> pwd() 結果を表示
                  |   No:  run(ignorestatus(cmd))
                  |                            -----> コマンドのstdout/stderr
                  +-- エラー時
                      display_error()          -----> エラーメッセージ
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| REPL.jl | `stdlib/REPL/src/REPL.jl` | ソース | シェルモードのPrompt設定（1316-1330行） |
| client.jl | `base/client.jl` | ソース | repl_cmd()関数（34-79行）。コマンド実行とcd特別処理 |
| shell.jl | `base/shell.jl` | ソース | shell_parse(), shell_escape_posixly() |
| cmd.jl | `base/cmd.jl` | ソース | Cmd構造体とコマンドリテラル |
| process.jl | `base/process.jl` | ソース | run(), ignorestatus() |
| LineEdit.jl | `stdlib/REPL/src/LineEdit.jl` | ソース | モード遷移とキーマップ |
