用Go構建命令行應用程序:彩虹貓
喜歡命令行應用程序嗎?也不要錯過 cowsay 教程!
我正在尋找一些終端應用程序來尋找靈感,結果我偶然發現了 lolcat。
原始碼在 https://github.com/busyloop/lolcat,並且已經有了一些Go的實現:
看起來是一個完全沒有用的東西,所以讓我們來實現它!
首先,讓我們在屏幕上打印一些值,然後我們將為它們上色,然後我們將研究如何接受用戶輸入以作為管道工作。
我使用 https://github.com/enodata/faker 生成假的輸出。
1
| go get -u github.com/enodata/faker
|
該程序輸出了一些短語:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| package main
import ( "fmt" "strings"
"github.com/enodata/faker" )
func main() { var phrases []string
for i := 1; i < 3; i++ { phrases = append(phrases, faker.Hacker().Phrases()...) }
fmt.Println(strings.Join(phrases[:], "; ")) }
|
不幸的是,這都是無聊的黑白。讓我們添加一些顏色。我們可以通過在 fmt.Printf
中插入一個逸出字符序列來實現這一點。這樣就可以以金色 #FFD700(RGB顏色碼:255,215,0)打印所有字符串:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| package main
import ( "fmt" "strings"
"github.com/enodata/faker" )
func main() { var phrases []string
for i := 1; i < 3; i++ { phrases = append(phrases, faker.Hacker().Phrases()...) }
output := strings.Join(phrases[:], "; ") r, g, b := 255, 215, 0
for j := 0; j < len(output); j++ { fmt.Printf("\033[38;2;%d;%d;%dm%c\033[0m", r, g, b, output[j]) } }
|
現在我們有了一個字符串,以及讓每個字符以不同的方式上色的基礎,現在是時候加入彩虹了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| package main
import ( "fmt" "math" "strings"
"github.com/enodata/faker" )
func rgb(i int) (int, int, int) { var f = 0.1 return int(math.Sin(f*float64(i)+0)*127+128), int(math.Sin(f*float64(i)+2*math.Pi/3)*127+128), int(math.Sin(f*float64(i)+4*math.Pi/3)*127+128) }
func main() { var phrases []string
for i := 1; i < 3; i++ { phrases = append(phrases, faker.Hacker().Phrases()...) }
output := strings.Join(phrases[:], "; ")
for j := 0; j < len(output); j++ { r, g, b := rgb(j) fmt.Printf("\033[38;2;%d;%d;%dm%c\033[0m", r, g, b, output[j]) } fmt.Println() }
|
這就是我們想要的效果!
彩虹顏色是使用 rgb()
函數生成的,原始的Ruby代碼在 https://github.com/busyloop/lolcat/blob/master/lib/lolcat/lol.rb 中實現了這個功能。
現在讓我們編輯程序,不再提供自己的輸出,改為讓它作為管道的一部分工作。它將從 os.Stdin
讀取內容並加上彩虹顏色。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| package main
import ( "bufio" "fmt" "io" "math" "os" )
func rgb(i int) (int, int, int) { var f = 0.1 return int(math.Sin(f*float64(i)+0)*127+128), int(math.Sin(f*float64(i)+2*math.Pi/3)*127+128), int(math.Sin(f*float64(i)+4*math.Pi/3)*127+128) }
func print(output []rune) { for j := 0; j < len(output); j++ { r, g, b := rgb(j) fmt.Printf("\033[38;2;%d;%d;%dm%c\033[0m", r, g, b, output[j]) } fmt.Println() }
func main() { info, \_ := os.Stdin.Stat() var output []rune
if info.Mode()&os.ModeCharDevice != 0 { fmt.Println("該命令旨在與管道一起使用。") fmt.Println("用法:fortune | gorainbow") }
reader := bufio.NewReader(os.Stdin) for { input, \_, err := reader.ReadRune() if err != nil && err == io.EOF { break } output = append(output, input) }
print(output) }
|
它從 os.Stdin
逐個字符地讀取並將它們添加到 output
這個字符切片中。
將輸出的渲染操作提取到 print() 函數中,但我們也可以在掃描每個字符時即時地將其添加到管道:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| package main
import ( "bufio" "fmt" "io" "math" "os" )
func rgb(i int) (int, int, int) { var f = 0.1 return int(math.Sin(f*float64(i)+0)*127+128), int(math.Sin(f*float64(i)+2*math.Pi/3)*127+128), int(math.Sin(f*float64(i)+4*math.Pi/3)*127+128) }
func main() { info, \_ := os.Stdin.Stat()
if info.Mode()&os.ModeCharDevice != 0 { fmt.Println("該命令旨在與管道一起使用。") fmt.Println("用法:fortune | gorainbow") }
reader := bufio.NewReader(os.Stdin) j := 0 for { input, \_, err := reader.ReadRune() if err != nil && err == io.EOF { break } r, g, b := rgb(j) fmt.Printf("\033[38;2;%d;%d;%dm%c\033[0m", r, g, b, input) j++ } }
|
這與之前的版本相同。
現在,我們可以用 fortune 和 cowsay 玩耍了。
讓我們通過運行 go build
和 go install
將其變成全局命令。命令將被稱為 gololcat
,因為我們使用這個文件夾名稱。
tags: [“Go”, “命令行”, “彩虹貓”]