Go言語で「複数ファイルの内容をクリップボードへコピー」するCLIを作りました

# TL;DR

こんにちは。今回は、Go言語で作成したシンプルなCLIツールをご紹介します。

このツールを使えば、ファイルを選択してその内容を丸ごとクリップボードにコピーすることができます。
生成AIに質問する際など、複数のファイル内容を一度にコピーしたいときに便利になるかと思います。

## 1. CLIでできること

該当リポジトリはこちらです：[makinzm/partial-tree-copy](https://github.com/makinzm/partial-tree-copy)

このCLIツールの主な機能は**複数ファイルのコピー**です。
複数のファイルを選択して、一度にその内容をコピーすることが可能です。

### 1.1. デモ

（手順１）コンソール上で、コピーをしたい内容があるディレクトリに移動をします。
（手順２）次に今回作成したコマンドを実行します。
```shell
❯ partial-tree-copy
```
すると次のような画面になります。
```shell
❯ partial-tree-copy
> 📁 /<CurrentDirectory>

How to use
Press 'w'/Ctrl+'c' to quit, 'Enter' to select a file or expand/collapse a dir, up('k')/down('j') to move

```
画面の下の`How to use`に従って`Enter`を押して、いくつかファイルを選択します。

```
❯ partial-tree-copy
> 📁 /<CurrentDirectory>
    📁 .git
    [ ].gitignore
    [ ]LICENSE
    [ ]README.md
    [ ]go.mod
    [ ]go.sum
    [ ]partial-tree-copy
    📂 src
      [レ] commands.go
      [レ] main.go
      [ ]models.go
    > [レ] update.go

How to use
Press 'w'/Ctrl+'c' to quit, 'Enter' to select a file or expand/collapse a dir, up('k')/down('j') to move
```

最後に`w`を押して終了をします。

その内容はクリップボードにコピーされているため、すぐ貼り付けを行うことができます。

実際にコピーできる内容は以下の通りで 「★★」で区切られている形をしています。
- [demo/realText.md](https://github.com/makinzm/partial-tree-copy/blob/ec2ffff03defae98f8450c189001ffe99a998f28/demo/realText.md)　　 

## 2. コードのポイントの抜粋

このツールのコードには、Go言語の基本的な文法で構成されています。
いくつかポイントを抜粋して解説します。

### 2.1 構造体の定義と再帰的なデータ構造

```go
type fileNode struct {
    name     string       // ファイル名またはディレクトリ名
    path     string       // フルパス
    isDir    bool         // ディレクトリかどうか
    expanded bool         // 展開されているかどうか
    children []*fileNode  // 子ノードのスライス
    selected bool         // 選択されているかどうか
    parent   *fileNode    // 親ノードへのポインタ
}
```
[該当箇所](https://github.com/makinzm/partial-tree-copy/blob/1b724048036aee68e7edd3fbd49b7a4093595cf6/src/models.go#L8-L19)

- **ポイント**：構造体内で自身の型のポインタをフィールドとして持つことで、再帰的なデータ構造（ツリー構造）を表現しています。

### 2.2 マップの活用

```go
selection map[string]*fileNode
```
[該当箇所](https://github.com/makinzm/partial-tree-copy/blob/1b724048036aee68e7edd3fbd49b7a4093595cf6/src/models.go#L26)

- **ポイント**：選択されたファイルを管理するためにマップを使用し、選択状態を保持しています。

### 2.3. キーボード入力の処理

```go
case tea.KeyMsg:
    switch msg.String() {
    case "ctrl+c", "w":
        m.copySelection()
        return m, tea.Quit
    // 他のキー入力の処理
    }
```
[該当箇所](https://github.com/makinzm/partial-tree-copy/blob/1b724048036aee68e7edd3fbd49b7a4093595cf6/src/update.go#L16-L21)

- **ポイント**：ユーザーからのキー入力を検知して、それぞれの操作に応じた関数を呼び出しています。
    - [charmbracelet/bubbletea: A powerful little TUI framework 🏗](https://github.com/charmbracelet/bubbletea?tab=readme-ov-file#the-update-method)

## 3. まだ改善できていないところ

このツールには、まだいくつか改善の余地があります。

### 3.1 検索機能の未実装

- **課題**：現在はファイルツリーを手動で展開して目的のファイルを探す必要があります。
- **改善案**：ファイル名やディレクトリ名で検索できる機能を追加すると、目的のファイルに素早くアクセスできます。

### 3.2 カーソルの表示範囲の問題

- **課題**：ファイルツリーが膨大な場合、カーソルが表示範囲外に移動してしまう場合があります。
- **改善案**：カーソルの位置を適切に制御し、表示範囲内に収めるロジックを追加する必要があります。

### 3.3. お願い

上記の内容以外にも、興味のある方はぜひぜひPRを送っていただけると嬉しいです🙇
- [makinzm/partial-tree-copy](https://github.com/makinzm/partial-tree-copy)

## 4. 最後に

今回、Goで初めてCLIツールを作成しました。
ChatGPTの力を借りつつではありますが、比較的簡素に行いたいことを実現できたので、Go言語のパワフルな標準ライブラリとサードパーティライブラリに感心しました。

最後までお読みいただき、ありがとうございました！