ぶていのログでぶログ

思い出したが吉日

Alacrittyからkittyに移行している

普段使うターミナルはAlacrittyを使っていた。 速度や機能など特に不満はなかったが、面白そうなのでkittyに移行している。

sw.kovidgoyal.net

kittyとは

Alacrittyと同じGPUベースのターミナルで、独自の機能としてターミナルプロトコルの拡張がされていたり、kittenと呼ばれるPythonスクリプトにより機能が拡張できることが挙げられる。 具体的な例として、ターミナルの中で画像が表示できたりする。

f:id:buty4649:20220118103956p:plain

画像を表示するためにターミナルに制御文字を送るためのコマンド、↑の例でいうところの kitty +kitten icat がkittenである。 そして、このkittenから送られる制御文字を解釈できるのがターミナルプロトコルの拡張である。

これらがめちゃくちゃ便利かどうかは使用者によるとおもうが、私は面白い!っと思ったのでkittyを使い始めたのであった。

ハマりどころ

kittyはよくできていて前述した機能拡張や独自機能だけにとどまらずかなり細かくカスタマイズが可能である。 しかしながら、私が利用するうえでうーん🤔となった部分があるのでそれをメモ代わりに書いておく。

使用できるフォントがかなり限られる

最初に驚くというかハマるのは使用できるフォントがかなり限られていることだと思う。 非対応フォントを使うこともできるのだが、ものすごく間延びした感じに表示されてしまう。 font_sizeを12にしても↓のようになる。

f:id:buty4649:20220121165603p:plain

対応したフォントを使うと↓のようにきれいに表示できる。

f:id:buty4649:20220121165707p:plain

これはどうもkittyが等幅フォントのみを扱うように設計している*1からのようだ。 ただ、どうも等幅であって日本語のフォントではうまくいかないことが多いようだ…。 例えば私が使っていたCicaフォントは使用できなかった。 また、TakaoやIPA、M+なんかも kitty + list-fonts --psname で使えるとでてくるのだが正しく表示できなかった。 色々試してみたが正しく表示できるのはUbuntu MonoとNoto MonoとFira Codeの3つだった。 この中でイタリックもボールドも使えるのはUbuntu Monoだけだったので今は結局Ubuntu Monoを使っている。 Ubuntu Monoで私は特に気になっていないが、見慣れたフォントを使いたいという人に取ってはつらいかもしれない。

TERM=xterm-kittyが強制される

kittyには独自拡張があるため独自のterminfoを持っている。 これがxterm-kittyとして宣言されている。 ローカルで使う場合はkitty起動時に環境変数で$TERMINFOが設定されkittyに内蔵されているterminfoを使うので問題は起きないのだが、sshするときに困る。 リモート先にはもちろんxterm-kittyが定義されたterminfoが存在しないので意図しない動作をする。 具体的にはBackspaceが効かないなどなど…。

これを解決するために kitty +kitten ssh というコマンドが用意されている。 このコマンドはxterm-kitty用のterminfoファイルをssh先にコピーしてから通常のsshにフォールバックするという挙動になっている。 terminfoのコピー先は、sshユーザのHOME配下になるのでシステムは汚さないのだが…変にファイルを送ったりするのはどうも好きになれず、一旦 alias ssh="TERM=xterm /usr/bin/ssh" してしまった…。

マウスクリックでWindowのフォーカスが変わってしまう

kittyではWindowと呼ばれる単位で画面を分割できる(tmuxのWindowと同じ)。 その状態で例えば、ブラウザからkittyにマウスクリックで切り替えたとする。 その時にマウスクリックされたときのWindowがフォーカスされてしまうという仕様がある。 もともと下のWindowで作業していたのに、マウスクリックしたら別のWindowになってしまうので私にとって不便である…。 どうにかしてフォーカスが切り替わらないようにしたいが…どうもそういう設定することができないので悩んでいる…。

tmuxを使うのをやめた

今までタブの機能やスクロールバッファの管理をすべてtmuxで行っていた。 ここらへんをtmuxに集約することでターミナルや環境が変わっても、tmuxがあれば同じ操作感で作業できるというメリットがあると考えていた。 実際そういう機会も少しあったが、tmuxを使うことでkittyの機能の恩恵が受けられなくなるため、この際tmuxをやめよう!っとなった。

kittyの標準的な機能でほとんど十分だったのだが、tmuxのコピーモードに相当する機能がなくここだけ自作した。 具体的にはkitty-pagerというコマンドを作り、Ctrl+Shift+hでこのコマンドを呼び出し、スクロールバッファを編集できるようにした。 ↓みたいな感じ。

f:id:buty4649:20220121185907g:plain

kitty-pagerのvimのラッパーになっている。 kittyから標準入力経由でスクロールバッファが流れてくるので、端末を操作できるようにfd:63にコピーしてゴニョゴニョしている。 また、$KITTY_PIPE_DATAで今のカーソルやスクロール位置を取得できるのでvim上のカーソル位置をよしなにしている。

❯ cat ~/.local/bin/kitty-pager 
#!/bin/bash

if [ -n "$KITTY_PIPE_DATA" ]; then
    set - $(echo "$KITTY_PIPE_DATA" | tr ':,' ' ')
    kitty_scrolled_by=$1
    cursor_x=$2
    cursor_y=$3
    lines=$4
    columns=$5
    delta_x=$(expr $cursor_x - 1)
    delta_y=$(expr $lines - $cursor_y - 1)
    CURSOR_COMMAND=":normal G"
    if [ $kitty_scrolled_by -eq 0 ]; then
        [ $delta_y -gt 0 ] && CURSOR_COMMAND="${CURSOR_COMMAND}${delta_y}k"
        [ $delta_x -gt 0 ] && CURSOR_COMMAND="${CURSOR_COMMAND}${delta_x}l"
    else
        CURSOR_COMMAND=":exe \"${CURSOR_COMMAND}${kitty_scrolled_by}\\<C-y>M\""
    fi
fi

exec vim 63<&0 0</dev/null \
  -N \
  -u ~/.config/kitty/pager.conf \
  -c ':set termguicolors clipboard=unnamedplus' \
  -c ':nmap <silent> <Space> v' \
  -c ':nmap <silent> q :qa!<CR>' \
  -c ':nmap <silent> ZZ :qa!<CR>' \
  -c ':vmap <silent> q <ESC>' \
  -c ':vmap <silent> <Space> qv' \
  -c ':vmap <silent> v yq' \
  -c ':r!cat 0<&63' \
  -c "$CURSOR_COMMAND" \
  -

kitty.confの設定はこんな感じ。 scrollback_pagerで指定する方法もあるのだが、こちらではエスケープシーケンスがそのまま流れてきてしまい、vimではうまく解釈できないのでそのまま編集することになる。 さすがにそれはつらいので、launchアクションで呼び出している。

map kitty_mod+h launch --type=overlay --stdin-source=@screen_scrollback kitty-pager @input-line-number @cursor-x

日付を挿入するkitten

kittenも作ってみたく日付を挿入するという単純なものを作ってみた。 地味に便利で作業ディレクトリを作るときなどに今日の日付をYYYYMMDD形式で挿入してくれるというもの。 ポイントとしては @result_handler(no_ui=True)属性をつけ、画面がちらつかないようにしている。

❯ cat ~/.config/kitty/datetime.py 
from datetime import datetime
from kittens.tui.handler import result_handler
from kitty.boss import Boss

def main(args):
    pass

@result_handler(no_ui=True)
def handle_result(args, answer, target_window_id, boss):
    w = boss.window_id_map.get(target_window_id)
    if w is not None:
        w.paste(datetime.now().strftime("%Y%m%d"))

kitty.conf

最後にkitty.confを貼っておく。 まだ、手探り状態で今後変わるかもしれない。

❯ cat ~/.config/kitty/kitty.conf 
# vim:fileencoding=utf-8
allow_remote_control yes

font_family      Ubuntu mono
bold_font        auto
italic_font      auto
bold_italic_font auto
font_size 12

hide_window_decorations yes
#inactive_text_alpha 0.5
confirm_os_window_close 2

tab_bar_edge top
tab_bar_style powerline
tab_bar_min_tabs 1

foreground #ffffff
background #2C001E
#background_opacity 0.8
dynamic_background_opacity yes

selection_foreground #000000
selection_background #ffffff

shell /usr/bin/fish
shell_integration enabled

clipboard_control write-clipboard write-primary read-clipboard-ask read-primary-ask

map shift+insert paste_from_clipboard
map kitty_mod+alt+space move_window_to_top
map kitty_mod+n next_window
map kitty_mod+m previous_window

scrollback_lines 100000
map kitty_mod+u scroll_page_up
map kitty_mod+d scroll_page_down
map kitty_mod+h launch --type=overlay --stdin-source=@screen_scrollback kitty-pager @input-line-number @cursor-x
map kitty_mod+p scroll_to_prompt -1

enabled_layouts fat,vertical,stack
map kitty_mod+l>kitty_mod+l toggle_layout fat
map kitty_mod+l>kitty_mod+v toggle_layout vertical
map kitty_mod+space toggle_layout stack

mouse_map left click ungrabbed mouse_handle_click selection prompt

map kitty_mod+o kitten hints --alphabet=asdfghjkl --ascending
map kitty_mod+alt+d kitten datetime.py