간단한 CUI 힌트를 만들어 보도록 하겠습니다.

36183 단어 Goprogrammingtech
본가의 블로그에도 글을 썼지만 새해 벽두부터
https://zenn.dev/zetamatta/articles/d7b76ff6535d7d
이 보도를 본 후, 나는 수중자체 제작 도구가 업데이트되었습니다.에서 이번에 보살핌을 받은 zetamatta/go-readline-ny 포장에 대해 진일보한 발굴과 소개를 진행하였다.
go-readline-ny에는 다음과 같은 특징이 있습니다.
  • Windows용 확장 셸NYAGOS을 위한 패키지
  • Emacs 스타일의 키 바인딩C-w 또는 C-y 등을 사용할 수 있음
  • 기능은 기능 키 등에 분배된다(비슷한?)
  • Ctrl+C와 Ctrl+D 오류readline를 정확하게 줍습니다.CtrlC 및 io.EOF의 보답으로 (상부에서 SIGNAL 조작 필요 없음)

  • mattn/go-colorable와 함께 사용
  • 추가 간이 기록 기능

  • context 표준 패키지 지원
  • 다중 플랫폼 지원(가능).최소 Windows 및 Ubuntu는 문제 없이 작동 중
  • 불쌍하다(웃음)
    간이 힌트bufio로 표준 포장bufio을 사용했다.Scanner는 유명합니다.입력 흐름을 선택하지 않는 것이 장점이지만 단행 편집, 입력에 대해서는 기본적인 기능, 예를 들어 배공간 등만 제공한다.
    또 위"지령선 조개?? 누구나 할 수 있어요."에서 소개mattn/go-tty했는데, 이걸 사용하면 RAW 모드에서 상당히 원시적인 조작이 가능할 것 같은데'간편한 CUI 힌트를 간단하게 조립하고 싶다'는 상황에서 조금 이상하다는 생각이 들었다.go-readline-ny라면
    text, err := (&readline.Editor{}).ReadLine(context.Background())
    
    도 정상적으로 작동할 수 있다.너무 좋아요!
    따라서 go-readline-ny를 사용하여 간단한 CUI 프롬프트를 설정합니다.
    우선 다음과 같은 함수를 고려한다.
    func Reverse(r []rune) []rune {
        if len(r) > 1 {
            for i, j := 0, len(r)-1; i < j; i, j = i+1, j-1 {
                r[i], r[j] = r[j], r[i]
            }
        }
        return r
    }
    
    이것은 간단한 작업으로 런을 반대로 배열하기만 하면 된다.단순 CUI 프롬프트에 입력한 문자열을 함수로 반전[1]합니다.이런 느낌의 코드는 어때요?
    sample1.go
    func main() {
        //input
        text, err := (&readline.Editor{
            Prompt: func() (int, error) { return fmt.Print("> ") },
        }).ReadLine(context.Background())
        if err != nil {
            fmt.Fprintln(os.Stderr, errPrint(err))
            return
        }
        //output
        fmt.Println(string(Reverse([]rune(text))))
    }
    
    참고로 errprint () 함수는
    func errPrint(err error) string {
        if err == nil {
            return ""
        }
        switch {
        case errors.Is(err, readline.CtrlC):
            return "処理を中断します"
        case errors.Is(err, io.EOF):
            return "処理を終了します"
        default:
            return err.Error()
        }
    }
    
    는 검사Ctrl+CCtrl+D의 함수다.
    이걸 수행하면...
    결과
    $ go run sample1.go 
    > あいうえお
    おえういあ
    
    .응, 응.잘 반전하고 있어.
    다음에 이 알림을 반복해서 실행하기 위해 코드를 변경해 보십시오.더욱 효과적인 간이 역사 기능.
    sample2.go
    func main() {
        history := simplehistory.New()
        editor := readline.Editor{
            Prompt:  func() (int, error) { return fmt.Print("> ") },
            History: history,
        }
        fmt.Println("Input Ctrl+D to stop.")
        for {
            //input
            text, err := editor.ReadLine(context.Background())
            if err != nil {
                fmt.Fprintln(os.Stderr, errPrint(err))
                return
            }
            //output
            fmt.Println(string(Reverse([]rune(text))))
            //add history
            history.Add(text)
        }
        return
    }
    
    또한 역사 제어용 대상은 zetamatta/go-readline-ny/simplehistory 포장을 사용합니다.이걸 수행하면...
    $ go run sample2.go 
    Input Ctrl+D to stop.
    > あいうえお
    おえういあ
    > しんぶんし
    しんぶんし
    > 
    処理を終了します
    
    이런 느낌(마지막으로Ctrl+D으로 끝난다).참고로 위아래 커서는 역사를 표시할 수 있다.버건디!
    사실readline.Editor 유형은
    history.go
    type Editor struct {
        KeyMap
        History       IHistory
        Writer        io.Writer
        Out           *bufio.Writer
        Prompt        func() (int, error)
        Default       string
        Cursor        int
        LineFeed      func(Result)
        OpenKeyGetter func() (KeyGetter, error)
    }
    
    의 IHistory형
    history.go
    type IHistory interface {
        Len() int
        At(int) string
    }
    
    인터페이스형이랑.그러니까 이거readline.IHistory형 구성이 충족되면 자체 제작된 역사형도 사용할 수 있다.
    저기 있다
    sample3.go
    const (
        max     = 50
        logfile = "history.log"
    )
    
    type History struct {
        buffer []string
    }
    
    var _ readline.IHistory = (*History)(nil) //compiler hint
    
    func New() (*History, error) {
        history := &History{buffer: []string{}}
        file, err := os.Open(logfile)
        if err != nil {
            return history, err
        }
        defer file.Close()
        scanner := bufio.NewScanner(file)
        for scanner.Scan() {
            history.Add(scanner.Text())
        }
        return history, scanner.Err()
    }
    
    func (h *History) Len() int {
        if h == nil {
            return 0
        }
        return len(h.buffer)
    }
    
    func (h *History) At(n int) string {
        if h == nil || h.Len() <= n {
            return ""
        }
        return h.buffer[n]
    }
    
    func (h *History) Add(s string) {
        if h == nil || len(s) == 0 {
            return
        }
        if n := h.Len(); n < 1 {
            h.buffer = append(h.buffer, s)
    
        } else if h.buffer[n-1] != s {
            h.buffer = append(h.buffer, s)
        }
        if n := h.Len(); n > max {
            h.buffer = h.buffer[n-max:]
        }
    }
    
    func (h *History) Save() error {
        if h == nil {
            return nil
        }
        file, err := os.Create(logfile)
        if err != nil {
            return err
        }
        defer file.Close()
        for _, s := range h.buffer {
            fmt.Fprintln(file, s)
        }
        return nil
    }
    
    유형과 방법[2].이것 괜찮아요?
    sample3.go
    func main() {
        history, err := New()
        if err != nil {
            fmt.Fprintln(os.Stderr, err)
            //continue
        }
        editor := readline.Editor{
            Prompt:  func() (int, error) { return fmt.Print("> ") },
            History: history,
        }
        fmt.Println("Input Ctrl+D to stop.")
        for {
            //input
            text, err := editor.ReadLine(context.Background())
            if err != nil {
                fmt.Fprintln(os.Stderr, errPrint(err))
                break
            }
            //output
            fmt.Println(string(Reverse([]rune(text))))
            //add history
            history.Add(text)
        }
        if err := history.Save(); err != nil {
            fmt.Fprintln(os.Stderr, err)
        }
        return
    }
    
    이 경우 최대 50개의 히스토리가 history.log에 저장됩니다.전sample2.go의 코드와 비교하기를 바랍니다.
    이렇게 go-readline-ny의 기본 기능이 제어되겠지.좀 더 놀자.

    참고서


    https://www.amazon.co.jp/dp/4621300253
    각주
    엄밀히 말하면, 정렬은 '텍스트' 단위가 아니라 rune (Unicde 코드 점) 단위이다.이체자와 그림문자 등이 여러 코드를 합성할 때가 있는데 이번 코드로 반전시키면 귀찮을 것 같다(웃음)↩︎
    사실 권투대 같은 걸 써야 하는데 이번에 게으름을 피웠어요.미안합니다, 컴퓨터.↩︎

    좋은 웹페이지 즐겨찾기