LoginSignup
8
8

More than 5 years have passed since last update.

peco/pecoではじめるコード・リーディング

Last updated at Posted at 2014-08-16

はじめに

pecoのソースコード読みが少し進んだので、そのことについて少し書きたいと思います。

どんなふうに進んだのかといいますと、pecoパッケージにBufferReaderという構造体があるのですが、この構造体を使わずに標準入力を内部状態に保存してみました。そして、pecoと同じような動作になるようにがんばってみました。

少し期待しない結果になっていますが、一応、同じような動作になっています。

実装

昨日のjessevdk/go-flagsを使ってみるに引き続き、サンプルとして少し実装しました。

ソースコードのほとんどの部分はpeco.goのソースコードです。

変更しているところはいくつかあります。

まず、オプションの機能がありません。main関数をみていただければ納得していただけると思います。

次に、ファイル操作がありません。ターゲットは標準入力だけです。しかも、元のエラー処理をほとんど壊してしまっている可能性が高いです。

そして、私がコードを追加したところは、コメントで「ここから」「ここまで」となっているところと、peco/ctx.goです。peco/ctx.goにAppendLine関数を追加しました。

sample.go
package main

import (
    "bufio"
    "fmt"
    "os"
    "runtime"

    "github.com/jessevdk/go-flags"
    "github.com/nsf/termbox-go"
    "github.com/peco/peco"
)

type cmdOptions struct {
    OptHelp           bool   `short:"h" long:"help"`
    OptTTY            string `long:"tty"`
    OptQuery          string `long:"query"`
    OptRcfile         string `long:"rcfile"`
    OptNoIgnoreCase   bool   `long:"no-ignore-case"`
    OptVersion        bool   `long:"version"`
    OptBufferSize     int    `long:"buffer-size" short:"b"`
    OptEnableNullSep  bool   `long:"null"`
    OptInitialIndex   int    `long:"initial-index"`
    OptInitialMatcher string `long:"initial-matcher"`
    OptPrompt         string `long:"prompt"`
}

// BufferSize returns the specified buffer size. Fulfills peco.CtxOptions
func (o cmdOptions) BufferSize() int {
    return o.OptBufferSize
}

// EnableNullSep returns tru if --null was specified. Fulfills peco.CtxOptions
func (o cmdOptions) EnableNullSep() bool {
    return o.OptEnableNullSep
}

func (o cmdOptions) InitialIndex() int {
    if o.OptInitialIndex >= 0 {
        return o.OptInitialIndex + 1
    }
    return 1
}

func main() {
    opts := &cmdOptions{}
    p := flags.NewParser(opts, flags.PrintErrors)
    p.Parse()

    ctx := peco.NewCtx(opts)
    defer func() {
        if err := recover(); err != nil {
            fmt.Fprintf(os.Stderr, "Error:\n%s", err)
        }

        if result := ctx.Result(); result != nil {
            for _, match := range result {
                line := match.Output()
                if line[len(line)-1] != '\n' {
                    line = line + "\n"
                }
                fmt.Fprint(os.Stdout, line)
            }
        }
    }()

    // ここから
    in := os.Stdin
    scanner := bufio.NewScanner(in)
    for scanner.Scan() {
        // fmt.Println(scanner.Text())
        // ctx.lines = append(ctx.lines, NewNoMatch(scanner.Text(), ctx.enableSep))
        ctx.AppendLine(scanner.Text())
    }
    // ここまで

    var err error
    err = peco.TtyReady()
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        return
    }
    defer peco.TtyTerm()

    err = termbox.Init()
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        return
    }
    defer termbox.Close()

    // Windows handle Esc/Alt self
    if runtime.GOOS == "windows" {
        termbox.SetInputMode(termbox.InputEsc | termbox.InputAlt)
    }

    view := ctx.NewView()
    filter := ctx.NewFilter()
    input := ctx.NewInput()
    sig := ctx.NewSignalHandler()

    loopers := []interface {
        Loop()
    }{
        view,
        filter,
        input,
        sig,
    }
    for _, looper := range loopers {
        ctx.AddWaitGroup(1)
        go looper.Loop()
    }

    ctx.WaitDone()
}
peco/ctx.go
func (c *Ctx) AppendLine(line string) {
    c.lines = append(c.lines, NewNoMatch(line, c.enableSep))
}

だめだろうと思いながらpeco/ctx.goに関数を追加しました。関数を追加して、次のようにコマンドラインを実行しました。

$ go get github.com/peco/peco
$ go build sample.go
$ ls | ./sample

真っ暗な画面になりました。やっぱりだめだったかと思いながら、キーボードをタイプすると、pecoと同じような画面に!!

まとめ

カーネルハッカー・小崎資広の「コードを読む技術」を読んで、目からウロコでした。

kernel.png

この記事を読んでコンプレックスみたいなものが少し解消されました。

記事の内容と少し違うかもしれませんが、今回みたいな感じでコード・リーディングを続けたいと思います。

8
8
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
8