LoginSignup
0
1

More than 3 years have passed since last update.

Julia のREPL上でカラフルな出力をする(お遊び)

Posted at

本日は

  • TerminalMenus の実装を調べてたらこういうことできそうだなという物で作ったネタです.TerminalMenus 自体はJuilaのREPL上で対話操作を可能にしその結果に応じて処理を分岐させることができるツールとしてJuliaの標準に組み込まれています.今回は実装を眺めててえられた知見から得られたコードを紹介します.

できたこと

下記のGIFをごらんください

out.gif

ターミナル上に出力される文字(の背後)に色をつけたものを逐次プリントしているものになります.

実装

下記のコードをそのまま実行します.

$ julia --color=yes partypeople.jl

--color オプションを有効にしておかないと背景に色が修飾されないので寂しいアウトプットになります.

partypeople.jl
#=
julia --color=yes partypeople.jl
=#

using Crayons
using Crayons.Box
using ColorTypes


const SPACE = " " # one white space
BG_COLORS=[
    #BLACK_BG         ,
    RED_BG           ,
    GREEN_BG         ,
    YELLOW_BG        ,
    BLUE_BG          ,
    MAGENTA_BG       ,
    CYAN_BG          ,
    LIGHT_GRAY_BG    ,
    DEFAULT_BG       ,
    DARK_GRAY_BG     ,
    LIGHT_RED_BG     ,
    LIGHT_GREEN_BG   ,
    LIGHT_YELLOW_BG  ,
    LIGHT_BLUE_BG    ,
    LIGHT_MAGENTA_BG ,
    LIGHT_CYAN_BG    ,
    WHITE_BG         ,
]

function draw(c,H,W; init::Bool=false)
    H,W = 5,10
    buf = IOBuffer()
    if !init
        print(buf, "\x1b[999D\x1b[$(H)A") #rollback H-times
    end
    for i in 1:H
        msg = repeat("$(rand(1:9))",W)
        println(buf, c, msg, Crayon(reset=true))
    end
    print(buf |> take! |> String)
end

function clean(H)
    buf = IOBuffer()
    for i in 1:H+1
        print(buf, "\x1b[2K") # clear line
        print(buf, "\x1b[999D\x1b[$(1)A") # rollback
    end
    print(buf |> take! |> String)
end

function partypeople()
    H,W=5,10
    draw(BLACK_BG,H,W,init=true)
    for c in BG_COLORS
        draw(c,H,W)
        sleep(0.1)
    end
    clean(H)
end

partypeople()

やっていること

Crayon で色付け

draw 関数で色付きの文字を出力します.for ループの中を見ると msg に格納した文字列を println している様子がわかります.
色を付けるために Crayons.jl で定義されているCrayon構造体を msg の前後に挟んでいます.実体はプリントの制御をする \e[31m (赤色)や \e[0m (元に戻す)のような命令を挟んでいるだけです.

例えば下図のように出力に使う色を制御させることができます.

image.png

繰り返しプリントするために

プリントしたら元に戻す

print(buf, "\x1b[999D\x1b[$(H)A") をするとプリントをする場所をH行分戻してくれます.これをすることで出力がダーーーーっと流れるのを防いでいます.

普通 println("Hello") とするとプリントした結果の次の行にカーソルが出ますね.続けて println("World") とすると

Hello
World

のように前の出力である Hello が残っています.カーソルを1行戻して World を書くと Hello が消えて World ”だけ”が残るという仕組みです.

Step 1      |     Step 2      | Step 3
Hello       |   > Hello       | World
World>      | (上に持っていく)  |

実際に動かしてもらった方が理解が進むと思います.

後片付け

clean 関数で draw をした結果を消していきます.print(buf, "\x1b[2K") をして行を消してカーソルを1行上に持っていくという操作をプリントした行数繰り返すということをしています.

まとめ

  • 以上の動作を高速にすることで色付きの文字がパッパと入れ替わるように見せることができました.
  • TerminnalMenu の実装から面白いところを取ってきてJuliaのお遊びコードを書きました.TerminalMenus の中では waitKey という関数が中で動いており,ユーザーのキーの入力に合わせてアクションをしその中で IOBuffer を制御 させてターミナルでの対話操作を可能にしています.頑張ったらJuliaだけで簡単なエディタ作れそうですね.お暇な方是非どうぞ.

おまけ

おつきさんがグルグル回転します.

function moonbar()
    try
        print("\x1b[?25l") # hide cursor
        while true
            for 🌝  '🌑':'🌘'
                sleep(0.1)
                print(🌝)
                print('\r')
            end
        end
    finally
        print("\x1b[?25h") # unhide cursor
    end
end

moonbar()

これも同様で出力する場所をコントロールしています.Nowloading...って感じのシチュエーションで使ってみてください.

0
1
0

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
0
1