LoginSignup
11
8

More than 5 years have passed since last update.

Vimみたいに画面分割とかできるターミナルアプリってどうやって作るの?

Last updated at Posted at 2017-03-03

という疑問を持ったので、少し調べてみた。

やってみた

ターミナルを分割して、ターミナルの任意の位置にカーソルの移動を行うサンプルアプリを作って見た。

動きとしてはこんな感じ

ansi2.gif

実装

こんな感じで実装してます。

ansi.rb
# frozen_string_literal: true

# ターミナル幅、高さの取得
width, height = `tput cols`.to_i, `tput lines`.to_i
# 画面を改行で埋めて、カーソルの移動ができるようにする
height.times { puts "\n" }

sleep 2

# ターミナルの中央位置を取得
center = height / 2
# ターミナルの中央部を"="で埋めて擬似的に画面分割をさせる
print "\033[#{center};1H"
puts '=' * width

# ターミナルの先頭行へ移動
print "\033[1;1H"

sleep 2

# 先頭行に文字列を出力
puts 'HELLO WORLD'
sleep 2

# 擬似分割画面下部の先頭行へカーソルを移動する
print "\033[#{center + 1};1H"

# 擬似分割画面下部先頭行へ文字列を出力
print '1234567890'
sleep 2

# 擬似分割画面上部の先頭行へカーソルを移動する
print "\033[1;1H"

# カーソルを左から7番目の位置に移動させる
print "\033[7G"
sleep 2
# カーソルの右側にある文字列を削除する
print "\033[K"
sleep 2
# 文字色を指定して文字列を出力する
puts "\e[31mworld\e[0m"

# 終了後に画面をクリアさせるために、カーソルを画面外に移動
print "\033[1;1H"
print "\033[1A"

sleep 5

解説

結論から言うと、ANSIエスケープシーケンスを使ってカーソル位置の操作を行い、擬似的に画面分割をさせてる感じ。

どんなことやってるかはコメントで全部書いてあるけど、せっかくだしざっくりと説明を。

1. 画面のクリア

  • ターミナルの高さいっぱい改行を挿入して、画面をクリア。

2. 擬似画面分割

  • = をターミナルの横幅いっぱいに出力し、擬似画面分割の境界を示す。

3. 上画面の先頭行に文字列を出力

  • ANSIエスケープコード ESC[n;mH を使用してカーソルを上画面の先頭行に移動
  • HELLO WORLD の文字列を出力

4. 下画面の先頭行に文字列を出力

  • ANSIエスケープコード ESC[n;mH を使用してカーソルを下画面の先頭行に移動
  • 1234567890 の文字列を出力

5. 文字列の変更

  • ANSIエスケープコード ESC[n;mH を使用してカーソルを上画面の先頭行に移動
  • ANSIエスケープコード ESC[nG を使用してカーソルを左から7番目の位置(WORLDW の位置)に移動
  • ANSIエスケープコード ESC[nK を使用して、カーソルより右の文字列を削除
  • ANSIエスケープコード ESC[nm を使用して、カラーコードを指定して world を出力

という感じ。

まとめ

もっとちゃんと画面分割を表現したい場合は、プログラム内で擬似画面の管理を行う必要があるため、結構苦労しそう。

とはいえ、これができるとターミナルアプリの表現力がぐっと広がるので(あと個人的にとても楽しい)もう少し色々と試してみたい。

参考

蒼色工房 -blue studio-

11
8
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
11
8