あさた研メモ

主に私が気づいたこととか困った時のメモとか書き留めとく用。

tmux から zellij に切り替えて、結局 tmux に戻ってきた

長らく tmux を使っていたのを、簡単に導入できそうだったので zellij を半年くらい使っていた。

zellij は簡単で便利だが、Claude Code Agent Teams が tmux のオフィシャル対応をしていたので、この際だし tmux に戻す決断をした。

といっても、tmux の設定を書くのは大変だな〜と思っていたので、せっかくだし Claude Code に書かせることにした。

zellij -> tmux の移行

プロンプト

Opus 4.6 を使いつつ、plan mode で雑に投げる。

現在 zellij を使っているのですが、Claude Code Agent Teams も出たことですし、それに対応している tmux に切り替えようと思っています。
そこで、~/.config/tmux/ 配下に tmux の設定を作りたいです。
タブが追加・移動できること、垂直方向・水平方向にペイン分割ができることが最低要件で、各セッションで保持する行数はめちゃくちゃ多くしたいです(ログの閲覧などを行うため)。

なお、今使っている zellij の設定は ~/.config/zellij/config.kdl にあります。

作成されたプランがこれ

tmux 設定作成プラン (zellij からの移行)

Context

zellij から tmux への移行に伴い、~/.config/tmux/.tmux.conf を新規作成する。 zellij のキーバインド体系を可能な限り tmux に引き継ぎつつ、tmux の prefix キー方式に適応させる。

  • 環境: tmux 3.6a / alacritty / macOS / zsh
  • エイリアス: .zshrc:15alias tmux="tmux -f ~/.config/tmux/.tmux.conf" 定義済み

対象ファイル

  • 新規作成: ~/.config/tmux/.tmux.conf
  • 参照のみ: ~/.config/zellij/config.kdl (移行元キーバインド確認)

設定の全体構成

1. 基本設定

設定 理由
prefix Ctrl+g zellij のモード切替キーと同一
default-terminal tmux-256color alacritty + true color 対応
terminal-overrides alacritty:Tc,alacritty:RGB true color 有効化
escape-time 0 vim 操作の応答性確保
history-limit 500000 大量ログ閲覧要件
mouse on zellij と同様
base-index 1 zellij の Tab 1-9 と一致
pane-base-index 1 同上
renumber-windows on ウィンドウ閉じた後の番号飛び防止
mode-keys vi コピーモードで vim キーバインド
repeat-time 600 リサイズ連打用に延長
focus-events on エディタ連携用

2. キーバインド: prefix + キー

ペイン操作 (zellij p モード相当)

tmux 操作 zellij 対応
prefix d 下に分割 p → d
prefix r 右に分割 p → r
prefix h/j/k/l ペイン移動 p → h/j/k/l
prefix x ペイン閉じる p → x
prefix f ズームトグル p → f
prefix b ウィンドウに昇格 t → b
prefix B 他ウィンドウから取込 -
prefix H/J/K/L リサイズ (繰返し可) r → h/j/k/l

ウィンドウ(タブ)操作 (zellij t モード相当)

tmux 操作 zellij 対応
prefix c 新規ウィンドウ t → n
prefix , リネーム t → r
prefix n 次のウィンドウ t → l
prefix p 前のウィンドウ t → h
prefix 1-9 番号ジャンプ t → 1-9
prefix Tab 最後のウィンドウと切替 t → tab
prefix < / > ウィンドウ位置スワップ Alt+i/o
prefix X ウィンドウ閉じる (確認付) t → x
prefix w ウィンドウ一覧 -

スクロール/コピー (zellij s モード相当)

tmux 操作 zellij 対応
prefix s or prefix [ コピーモード開始 s (scroll mode)
prefix / 検索開始 s → f
prefix e スクロールバックを vim で開く s → e

セッション操作 (zellij o モード相当)

tmux 操作 zellij 対応
prefix D デタッチ o → d
prefix S セッション一覧/切替 o → w
prefix N 新規セッション -

その他

tmux 操作
prefix R 設定リロード

3. キーバインド: Alt + キー (prefix 不要、常時有効)

zellij の shared_among "normal" "locked" に対応。

tmux 操作 zellij 対応
Alt+h/j/k/l ペイン移動 Alt+h/j/k/l
Alt+H/L ウィンドウ前/次 Alt+h/l (MoveFocusOrTab)
Alt+n 新規ペイン(下方向) Alt+n
Alt+f ポップアップ Alt+f
Alt+=/− リサイズ増/減 Alt++/-
Alt+i/o ウィンドウ位置スワップ Alt+i/o

4. コピーモード内 (vi キーバインド)

キー 操作
v 選択開始
y / Enter コピー (pbcopy 連携)
r 矩形選択トグル
/ 検索、n/N で次/前
Escape コピーモード終了

5. ステータスバー

  • 位置: 上部 (zellij の tab-bar に合わせる)
  • 左: セッション名
  • 中央: ウィンドウリスト (アクティブウィンドウはハイライト、ズーム状態表示)
  • 右: 日時
  • カラー: Catppuccin Mocha 系 (alacritty との相性が良い)
  • ペインボーダー: アクティブ/非アクティブで色分け

6. macOS 固有

  • set-clipboard on でクリップボード連携
  • コピー時は pbcopy にパイプ

zellij との主な差異

  1. モードモデル: zellij は明示的サブモードに入って操作 → tmux は prefix + 1キーで即実行
  2. フローティングペイン: tmux では popup コマンドで代替 (一時的なもの)
  3. リサイズ: -r フラグ + repeat-time 600ms で繰返しリサイズ対応
  4. メモリ: 500,000行/ペインは 50-150MB 程度消費。多数ペイン時は注意

検証方法

  1. tmux 起動 → ステータスバーが上部に表示されることを確認
  2. prefix d / prefix r → ペイン分割を確認
  3. prefix c → 新規ウィンドウ作成を確認
  4. prefix 1 / prefix 2 → ウィンドウ切替を確認
  5. Alt+h/j/k/l → prefix なしでペイン移動を確認
  6. prefix s → コピーモードに入り、スクロールを確認
  7. prefix R → 設定リロードが動作することを確認

このあと、対話の中で

  • キーバインドがわからなくなりそうなので、なにか操作を行うと日本語でキーバインド体系(さっきあなたが書いてくれた表)を出せるようにしたい
    • prefix ? で出せるようにする
  • prefix を入力したときに次に繋がるコマンドの一覧を小さく出すことって出来たりします?
    • →そういう機能はないので、 tmux-which-key で代用する

のような感じのやりとりをした。

実際のコンフィグ

# =============================================================================
# tmux.conf — zellij からの移行設定
# tmux 3.6a / alacritty / macOS / zsh
# =============================================================================

# -----------------------------------------------------------------------------
# 1. 基本設定
# -----------------------------------------------------------------------------

# prefix: Ctrl+g (zellij のモード切替キーと同一)
unbind C-b
set -g prefix C-g
bind C-g send-prefix

# ターミナル・カラー
set -g default-terminal "tmux-256color"
set -ag terminal-overrides ",alacritty:Tc,alacritty:RGB"

# 応答性
set -sg escape-time 0
set -g repeat-time 600

# スクロールバック
set -g history-limit 500000

# マウス
set -g mouse on

# インデックス (zellij Tab 1-9 と一致)
set -g base-index 1
setw -g pane-base-index 1
set -g renumber-windows on

# vi モード
setw -g mode-keys vi

# フォーカスイベント (エディタ連携)
set -g focus-events on

# クリップボード (macOS)
set -g set-clipboard on

# -----------------------------------------------------------------------------
# 2. キーバインド: prefix + キー
# -----------------------------------------------------------------------------

# --- ペイン操作 (zellij `p` モード相当) ---

# 分割
bind d split-window -v -c "#{pane_current_path}"
bind r split-window -h -c "#{pane_current_path}"

# ペイン移動
bind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R

# ペインを閉じる
bind x confirm-before -p "kill-pane #P? (y/n)" kill-pane

# ズームトグル
bind f resize-pane -Z

# ペインをウィンドウに昇格
bind b break-pane

# 他ウィンドウからペインを取り込み
bind B choose-window 'join-pane -s "%%"'

# リサイズ (repeat 可)
bind -r H resize-pane -L 5
bind -r J resize-pane -D 5
bind -r K resize-pane -U 5
bind -r L resize-pane -R 5

# --- ウィンドウ(タブ)操作 (zellij `t` モード相当) ---

# 新規ウィンドウ
bind c new-window -c "#{pane_current_path}"

# リネーム (デフォルト prefix , と同じ)
bind , command-prompt -I "#W" "rename-window -- '%%'"

# 前/次のウィンドウ
bind n next-window
bind p previous-window

# 番号ジャンプ (1-9 はデフォルトで動作)

# 最後のウィンドウと切替
bind Tab last-window

# ウィンドウ位置スワップ
bind < swap-window -t -1\; select-window -t -1
bind > swap-window -t +1\; select-window -t +1

# ウィンドウを閉じる (確認付き)
bind X confirm-before -p "kill-window #W? (y/n)" kill-window

# ウィンドウ一覧
bind w choose-tree -Zw

# --- スクロール/コピー (zellij `s` モード相当) ---

# コピーモード開始
bind s copy-mode
bind [ copy-mode

# 検索 (コピーモードに入ってから検索開始)
bind / copy-mode \; send-keys /

# スクロールバックを vim で開く
bind e run-shell 'tmux capture-pane -pS -#{history_limit} > /tmp/tmux-scrollback-$$.txt && ${EDITOR:-vim} /tmp/tmux-scrollback-$$.txt && rm -f /tmp/tmux-scrollback-$$.txt'

# --- セッション操作 (zellij `o` モード相当) ---

# デタッチ
bind D detach-client

# セッション一覧/切替
bind S choose-tree -Zs

# 新規セッション
bind N command-prompt -p "new session:" "new-session -s '%%'"

# --- その他 ---

# 設定リロード
bind R source-file ~/.config/tmux/.tmux.conf \; display-message "Config reloaded"

# キーバインド一覧 (日本語チートシート)
bind ? display-popup -E -w 56 -h 48 "less -R ~/.config/tmux/keybindings.txt"

# クイックメニュー (prefix Space)
bind Space display-menu -T "#[align=centre]tmux メニュー" -x C -y C \
  "" \
  "-#[nodim]── ペイン ──────────"                "" "" \
  "#{?window_zoomed_flag, 解除, 下に分割}  (d)"  d "split-window -v -c '#{pane_current_path}'" \
  "右に分割          (r)"                        r "split-window -h -c '#{pane_current_path}'" \
  "ペイン閉じる      (x)"                        x "confirm-before -p 'kill-pane? (y/n)' kill-pane" \
  "ズームトグル      (f)"                        f "resize-pane -Z" \
  "ウィンドウに昇格  (b)"                        b "break-pane" \
  "他から取込        (B)"                        B "choose-window 'join-pane -s \"%%\"'" \
  "" \
  "-#[nodim]── ウィンドウ ────"                   "" "" \
  "新規ウィンドウ    (c)"                        c "new-window -c '#{pane_current_path}'" \
  "リネーム          (,)"                        , "command-prompt -I '#W' 'rename-window -- \"%%\"'" \
  "次のウィンドウ    (n)"                        n "next-window" \
  "前のウィンドウ    (p)"                        p "previous-window" \
  "一覧              (w)"                        w "choose-tree -Zw" \
  "閉じる            (X)"                        X "confirm-before -p 'kill-window? (y/n)' kill-window" \
  "" \
  "-#[nodim]── スクロール/コピー"                 "" "" \
  "コピーモード      (s)"                        s "copy-mode" \
  "検索              (/)"                        / "copy-mode ; send-keys /" \
  "vim で開く        (e)"                        e "run-shell 'tmux capture-pane -pS -500000 > /tmp/tmux-scrollback.txt && vim /tmp/tmux-scrollback.txt && rm -f /tmp/tmux-scrollback.txt'" \
  "" \
  "-#[nodim]── セッション ────"                   "" "" \
  "デタッチ          (D)"                        D "detach-client" \
  "セッション一覧    (S)"                        S "choose-tree -Zs" \
  "新規セッション    (N)"                        N "command-prompt -p 'new session:' 'new-session -s \"%%\"'" \
  "" \
  "-#[nodim]── その他 ────────"                   "" "" \
  "設定リロード      (R)"                        R "source-file ~/.config/tmux/.tmux.conf ; display-message 'Config reloaded'" \
  "キーバインド一覧  (?)"                        ? "display-popup -E -w 56 -h 48 'less -R ~/.config/tmux/keybindings.txt'"

# -----------------------------------------------------------------------------
# 3. キーバインド: Alt + キー (prefix 不要)
# -----------------------------------------------------------------------------

# ペイン移動 (zellij shared_among "normal" "locked" 相当)
bind -n M-h select-pane -L
bind -n M-j select-pane -D
bind -n M-k select-pane -U
bind -n M-l select-pane -R

# ウィンドウ前/次 (zellij MoveFocusOrTab 相当)
bind -n M-H previous-window
bind -n M-L next-window

# 新規ペイン (下方向)
bind -n M-n split-window -v -c "#{pane_current_path}"

# ポップアップ (zellij ToggleFloatingPanes 相当)
bind -n M-f display-popup -E -w 80% -h 80% -d "#{pane_current_path}"

# リサイズ増/減
bind -n M-= resize-pane -U 2
bind -n M-- resize-pane -D 2

# ウィンドウ位置スワップ
bind -n M-i swap-window -t -1\; select-window -t -1
bind -n M-o swap-window -t +1\; select-window -t +1

# -----------------------------------------------------------------------------
# 4. コピーモード (vi キーバインド)
# -----------------------------------------------------------------------------

# 選択開始
bind -T copy-mode-vi v send-keys -X begin-selection

# コピー (pbcopy 連携)
bind -T copy-mode-vi y send-keys -X copy-pipe-and-cancel "pbcopy"
bind -T copy-mode-vi Enter send-keys -X copy-pipe-and-cancel "pbcopy"

# 矩形選択トグル
bind -T copy-mode-vi r send-keys -X rectangle-toggle

# 検索 (/ はデフォルトで動作、n/N も同様)

# コピーモード終了
bind -T copy-mode-vi Escape send-keys -X cancel

# -----------------------------------------------------------------------------
# 5. ステータスバー
# -----------------------------------------------------------------------------

# 位置: 上部 (zellij tab-bar に合わせる)
set -g status-position top

# 更新間隔
set -g status-interval 5

# --- Catppuccin Mocha カラー ---
# Base:    #1e1e2e
# Surface: #313244
# Text:    #cdd6f4
# Mauve:   #cba6f7
# Blue:    #89b4fa
# Subtext: #a6adc8

# ステータスバー全体
set -g status-style "bg=#1e1e2e,fg=#cdd6f4"

# 左: セッション名
set -g status-left-length 30
set -g status-left "#[bg=#cba6f7,fg=#1e1e2e,bold] #S #[bg=#1e1e2e] "

# 中央: ウィンドウリスト
set -g status-justify centre
setw -g window-status-format "#[fg=#a6adc8] #I:#W "
setw -g window-status-current-format "#[bg=#313244,fg=#89b4fa,bold] #I:#W#{?window_zoomed_flag, Z,} "

# 右: 日時
set -g status-right-length 40
set -g status-right "#[fg=#a6adc8] %Y-%m-%d #[fg=#cdd6f4,bold]%H:%M "

# --- ペインボーダー ---
set -g pane-border-style "fg=#585b70"
set -g pane-active-border-style "fg=#cba6f7,bold"

# --- メッセージ ---
set -g message-style "bg=#313244,fg=#cdd6f4"
set -g message-command-style "bg=#313244,fg=#cdd6f4"

# --- モード (コピーモード選択など) ---
setw -g mode-style "bg=#313244,fg=#cdd6f4"

ちなみに ~/.config/tmux/keybindings.txt はこんな感じ。

  tmux キーバインド一覧  (prefix = Ctrl+g)
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

  ── ペイン操作 ──────────────────────────
  prefix d        下に分割
  prefix r        右に分割
  prefix h/j/k/l  ペイン移動
  prefix x        ペイン閉じる (確認)
  prefix f        ズームトグル
  prefix b        ウィンドウに昇格
  prefix B        他ウィンドウから取込
  prefix H/J/K/L  リサイズ (繰返し可)

  ── ウィンドウ(タブ)操作 ────────────────
  prefix c        新規ウィンドウ
  prefix ,        リネーム
  prefix n        次のウィンドウ
  prefix p        前のウィンドウ
  prefix 1-9      番号ジャンプ
  prefix Tab      直前のウィンドウ
  prefix < / >    位置スワップ
  prefix X        ウィンドウ閉じる (確認)
  prefix w        ウィンドウ一覧

  ── スクロール/コピー ───────────────────
  prefix s  or [  コピーモード開始
  prefix /        検索開始
  prefix e        スクロールバックを vim で開く

  ── コピーモード内 (vi) ─────────────────
  v               選択開始
  y / Enter       コピー (pbcopy)
  r               矩形選択トグル
  /               検索  n/N 次/前
  Escape          終了

  ── セッション操作 ──────────────────────
  prefix D        デタッチ
  prefix S        セッション一覧/切替
  prefix N        新規セッション

  ── Alt + キー (prefix 不要) ────────────
  Alt+h/j/k/l     ペイン移動
  Alt+H/L         ウィンドウ前/次
  Alt+n           新規ペイン (下方向)
  Alt+f           ポップアップ
  Alt+=/−         リサイズ増/減
  Alt+i/o         ウィンドウ位置スワップ

  ── その他 ──────────────────────────────
  prefix R        設定リロード
  prefix ?        このヘルプを表示

  q で閉じる

これで、こんな感じのヘルプが出るようになった。

操作も問題ない。

prefix ? の結果

雑感

ほぼ手直しなしで、ちゃんと動くものを作ってくれて良かった。

自分で調べながらこういうのをやるのも好きだが、今回はとりあえず動くものがほしかったので AI に書かせて満足している。

基本的に自分のコーディング AI 利用のスタンスは

  • 業務ロジック部分のコーディングは自分でやって、単調な繰り返し作業などは補助的にAIにまかせる
  • 設計に悩んでいる場合は相談込みで作業プランを立てさせてみて、よさそうだったらコーディングも任せたうえで、結果をレビューする

という使い方なのだが、業務関係ないターミナル設定とかは AI に希望を言って書いてもらうのが楽だった。

今後も自分で書きたいところは自力で楽しみつつ、多少妥協して良いところはバンバン AI に書かせていこうと思う。

Emacs を自分でビルドしよう (MacOS)

この記事は Emacs Advent Calendar 2023 の 7 日目の記事です。

qiita.com

はじめに

みなさんは自分の好きなエディタはありますか?

私はなんだかんだいってEmacsを愛用しています。

自分で使うツールは自分でビルドしたいですよね?

ということで、Emacsをパッケージマネージャなどを使わずに自分でビルドして入れる方法を紹介します。

私の環境

必要なものを揃える

XCode の Command line tools と、Homebrew は用意しておきましょう (大体の人は入れてると思いますが)。

libgccjit が必要になるので入れます。

$ brew install libgccjit

ビルドの仕方

まずは git プロジェクトの clone

$ git clone git://git.sv.gnu.org/emacs.git

次に、自分が使いそうなオプションを追加して configure します。
git switch などで特定のリリースをビルドしましょう。

私は master ブランチのままビルドしています。

configure するときにいくつか引数を渡すことで、特定のビルドオプションを ON / OFF できます。 詳しくはここに書いています。

github.com

絶対に入れておくべきなのは、--with-native-compilation です。 Emacs 28 以降、Native Compile にすることで高速に使うことができます。

$ cd ./emacs
$ git pull
$ ./autogen.sh
$ ./configure --with-native-compilation \
            --without-x \
            --with-ns \
            --with-imagemagick \
            --with-json

ここまできたら、あとは build のみです。

$ make bootstrap
$ make install

configure や bootstrap 中にエラー終了することがありますが、気づきにくいのでよくログを見ておきましょう。

たいていはなにかのパッケージが足りてないので、都度エラーの内容から入れるべきパッケージを入れましょう。

make install が終わると、 nextstep/ 配下に Emacs.app ができているので、これを /Application 内に移動して完了です。

注意点

結構ビルドが失敗する要因として、libgccjitopenssl のバージョンです。

Emacs のバージョンによって最低要件のバージョンなどがあるので、コケたらよく調べておきましょう。

さいごに

「ビルドがコケたら」の話は人それぞれなのと、Emacs を自分でビルドして使いたい人はビルド環境などを調べるのも好きな人が多いと思うので、
解決方法を根気よく探しましょう。

Emacsオープンソースでビルドが簡単なので、ぜひ思い思いのオプションをつけてビルドしてみましょう!

お世話になった記事

はじめてビルドするとき、大変お世話になりました。

blog.tomoya.dev

SendGrid の Dynamic Template では equals~else equals 構文も使える

SendGrid の Dynamic Template では、簡易的に if 文などの構文が使える。

docs.sendgrid.com

このドキュメントにおいて、if ~ else if の構文が使えることが紹介されている。

実はドキュメントに書いてないが、 equals や notEquals でも同様の構文が使える。

{{#equals var "hoge"}}
  ホゲだよ
{{else equals var "fuga"}}
  フガでござる
{{else}}
  知らんがな
{{/equals}}

上記の例では、

  • {"var": "hoge"} のとき => ホゲだよ
  • {"var": "fuga"} のとき => フガでござる
  • {"var": "piyo"} のとき => 知らんがな

という置換がされる。

なお注意として、これもifの項でしかドキュメントに書いてないのだが equals スコープ内で変数置換する場合、その参照の仕方に注意しないといけない。

# 渡すjson
{"weather": "rain", "date": "2021-12-31"}

# テンプレート
{{#equals weather "rain"}}
  雨量が少なければ様子を見て開催
{{else equals weather "snow"}}
  中止
{{else}}
  開催 ({{@root.date}})
{{/equals}}

lsp-mode の設定を晒す (2021-02-06 時点)

自分の設定を晒す。

(lsp-document-sync-method . 'lsp--sync-incremental)コメントアウトされているが、他の記事に書いてあったこの設定を入れていたらlspがちゃんと動かなかったので、指定を外した。

こういう設定系は誰かが最新の環境で動くものを晒さないと構成のためにならないと思うので、自分も書いておく。

(leaf lsp-mode
  :doc "LSP mode"
  :req "emacs-26.1" "dash-2.14.1" "dash-functional-2.14.1" "f-0.20.0" "ht-2.0" "spinner-1.7.3" "markdown-mode-2.3" "lv-0"
  :tag "languages" "emacs>=26.1"
  :added "2020-08-27"
  :url "https://github.com/emacs-lsp/lsp-mode"
  :emacs>= 26.1
  :ensure t
  :after spinner markdown-mode lv
  :custom
  `((lsp-keymap-prefix                  . "C-c l")
    (lsp-inhibit-message                . t)
    (lsp-message-project-root-warning   . t)
    (create-lockfiles                   . nil)
    (lsp-signature-auto-activate        . t)
    (lsp-signature-doc-lines            . 1)
    (lsp-print-performance              . t)
    (lsp-log-io                         . t)
    (lsp-eldoc-render-all               . t)
    (lsp-enable-completion-at-point     . t)
    (lsp-enable-xref                    . t)
    (lsp-keep-workspace-alive           . nil)
    (lsp-enable-snippet                 . t)
    (lsp-server-trace                   . nil)
    (lsp-auto-guess-root                . nil)
    ;; (lsp-document-sync-method           . 'lsp--sync-incremental)
    (lsp-document-sync-method           . 2)
    (lsp-diagnostics-provider           . :flycheck)
    (lsp-response-timeout               . 5)
    (lsp-idle-delay                     . 0.500)
    (lsp-enable-file-watchers           . nil)
    (lsp-completion-provider            . :capf)
    (lsp-headerline-breadcrumb-segments . '(symbols)))
  :commands
  (lsp lsp-deferred)
  :hook
  (prog-major-mode . lsp-prog-major-mode-enable)
  (lsp-mode-hook . lsp-ui-mode)
  (lsp-mode-hook . lsp-headerline-breadcrumb-mode)
  
  :init
  (leaf lsp-ui
    :doc "UI modules for lsp-mode"
    :req "emacs-26.1" "dash-2.14" "dash-functional-1.2.0" "lsp-mode-6.0" "markdown-mode-2.3"
    :tag "tools" "languages" "emacs>=26.1"
    :added "2020-08-27"
    :url "https://github.com/emacs-lsp/lsp-ui"
    :emacs>= 26.1
    :ensure t
    :after lsp-mode markdown-mode
    :custom
    ((lsp-ui-doc-enable            . t)
     (lsp-ui-doc-deley             . 0.5)
     (lsp-ui-doc-header            . t)
     (lsp-ui-doc-include-signature . t)
     (lsp-ui-doc-position          . 'at-point)
     (lsp-ui-doc-max-width         . 150)
     (lsp-ui-doc-max-height        . 30)
     (lsp-ui-doc-use-childframe    . nil)
     (lsp-ui-doc-use-webkit        . nil)
     (lsp-ui-flycheck-enable       . t)
     (lsp-ui-peek-enable           . t)
     (lsp-ui-peek-peek-height      . 20)
     (lsp-ui-peek-list-width       . 50)
     (lsp-ui-peek-fontify          . 'on-demand) ;; never, on-demand, or always
     )
    :hook ((lsp-mode-hook . lsp-ui-mode))
    )
  (leaf lsp-treemacs
    :doc "LSP treemacs"
    :req "emacs-26.1" "dash-2.14.1" "dash-functional-2.14.1" "f-0.20.0" "ht-2.0" "treemacs-2.5" "lsp-mode-6.0"
    :tag "languages" "emacs>=26.1"
    :added "2020-10-22"
    :url "https://github.com/emacs-lsp/lsp-treemacs"
    :emacs>= 26.1
    :ensure t
    :after treemacs lsp-mode)
  )

なお動作環境は Emacs 28.0.50。

起動時に Warning (comp): el-get-status.el:22:1: Warning: Package cl is deprecated みたいなのが出まくるんだけど。
init.el に

(setq byte-compile-warnings '(not cl-functions obsolete))

を書いているのに直らない。

Emacs-27 では出なかったんだけど、既知の問題なんだろうか?
鬱陶しいだけなのだが、鬱陶しいのでなんとかしたい…。
だれか教えてください。

quick search を Go で書く

タイトル通り。
参考記事を元に書いたけど、正しく実装できてるのか自信ない。
愚直な実装も一緒に書いておいて、結果の比較をできるようにしてある。

package main

import (
    "bufio"
    "fmt"
    "os"
    "strings"
)

const SIGMA = 256

func native(ts, ps []string) {
    n := len(ts)
    m := len(ps)

    if n == 0 || m == 0 {
        return
    }

    for i := 0; i <= n-m; i++ {
        j := 0
        for j = 0; j < m && ps[j] == ts[i+j]; {
            j++
        }
        if j == m {
            fmt.Println(i)
        }
    }
}

func quickSearch(ts, ps []string) {
    n := len(ts)
    m := len(ps)

    if n == 0 || m == 0 {
        return
    }

    // 要素数+1を参照するため
    ts = append(ts, "")

    // 移動表
    shift := make(map[string]int)
    for i := 0; i < m; i++ {
        shift[ps[i]] = m - i
    }

    for i := 0; i <= n-m; {
        j := 0
        for j = 0; j < m && ps[j] == ts[i+j]; j++ {
        }

        if j == m {
            fmt.Println(i)
        }

        if shift[ts[i+m]] != 0 {
            i += shift[ts[i+m]]
        } else {
            i += m
        }
    }
}

func main() {
    var t, p string
    var sc = bufio.NewScanner(os.Stdin)
    if sc.Scan() {
        t = sc.Text()
    }
    if sc.Scan() {
        p = sc.Text()
    }

    ts := strings.Split(t, "")
    ps := strings.Split(p, "")

    fmt.Println("===== NATIVE =====")
    native(ts, ps)

    fmt.Println("===== QS =====")
    quickSearch(ts, ps)
}

Gist に残した: quick search · GitHub

参考記事

www.m3tech.blog

www.nct9.ne.jp