🦊

C++でfzfみたいなUIを提供するライブラリを書いた

2024/04/15に公開
2

土日を使ってこんなライブラリを書きました。
C++をまともに触ったのはこれが初めてですが、それにしては良いものが作れたと思っています。

https://github.com/comamoca/libffui

C++でfzfのようなあいまい検索を使えるライブラリです。
(まだ完全にバグが取れていなくて、長めのvectorを突っ込んだりすると表示がバグります)4/17追記: このバグは修正できました。

動作風景はこんな感じになります。

https://youtu.be/Sbb8hyaiNpk

具体的な使い方はREADMEを見てもらうとして、ここでは以下のことについて書いていきます。
試行錯誤している内容が多いです。

  • なぜこのライブラリを作ったのか
  • 実装の話
  • 作ってみた所感

なぜこのライブラリを作ったのか

このようなあいまい検索を実装したソフトウェアの代表格といえば真っ先にfzfの名前が挙げられると思います。

https://github.com/junegunn/fzf

このツールはstdinから入力されたデータをあいまい検索し、選択されたデータをstdoutに出力するというシンプルなツールです。
それ故に様々なユースケースに応えられる非常にパワフルなツールとなっています。

自分がfzfと出会った時はかなりの衝撃を受けていて、今ではCLIにおける検索の考え方を大きく変えたものだと考えています。
そう考えているので当然自作CLIツールに組込みたくなったりもします。

GoやRustには以下のようなライブラリがあります。

  • Go

https://github.com/ktr0731/go-fuzzyfinder

https://github.com/koki-develop/go-fzf

  • Rust

https://github.com/lotabout/skim

GoやRustはどちらもCLIツールの開発に使われやすく、あいまい検索を提供するライブラリも揃っています。
ですがC++などの言語にはアルゴリズムの実装はあれど、UIがセットになっていてライブラリとして使用が想定された実装は見かけませんでした。

そのようなケースにも対応できるよう、C++で実装したものがlibffuiになります。

始めは他言語からの呼び出しを考えていた

実装する手間を省けるので始めはGo製のgo-fuzzyfinder、Rust製のskimをCなどから呼び出すことを考えてました。

Go

Goはlibcに依存せず、libc非依存な作りになっていることでクロスコンパイルが容易になっています。
また独自のランタイムで動作することで、並列処理が扱いやすくなっています。
ですがそれ故にCなどとの連携で大変になることが多いです。

具体的にはcgoというツールを使うのですが、これはGoの良さを潰してしまうため使用は避けたいものです。

https://zenn.dev/mopeneko/articles/dc294e1e95d11e

Rust

Rustは言語リンケージ(extern "C")を用いることでCに関数を公開できます。
始めはこれも良いと思っていましたが、手順が思っていたよりも複雑だったのと、
CのビルトシステムにCargoが混在してくるためプロジェクトが複雑になると考え断念しました。

実装

そんなこともあり結局一から自作することにしました。
始めはCでの実装を考えていましたが、文字列の扱いずらさに耐えられなくなりC++へ移行しました。
本格的にC++に触るのは今回が初めてでしたが、Rustを触ったことがあったため同じノリで行けると考え突貫で作りはじめました。
この考えは的中して、メモリまわりで困ったことがあれど構文で困ったことはあまりありませんでした。

使用したライブラリは以下の2つです。実装にはC++11を使用しています。(C++23でのビルド確認済み)

  • ncurses
  • rapidfuzz

実装はかなりシンプルです。クラス等も使っていません。

  • Ctrl-n/pでカーソルの座標を上下させる
  • 英数文字が入力されたら内部のvectorに格納し、ソートする
  • Ctrl-h/Backspaceが入力されたら後ろから削除する
  • Ctrl-uが入力されたら全削除する

作ってみた所感

まず始めに、モダンC++が思ってた以上にRustチックだったことが挙げられます。
C++11からRustで有名な所有権(ムーブセマンティクス)が使えるようになっていて、変数のライフタイムが終わるとメモリが自動的に開放されるようになっています。(libffuiでは使用していませんが...)

また、命名は違えどvectorstringなども使うことができるようになっています。

C++で挙げられる不便な点として、CMakeを使ったビルドが挙げられます。
確かに大変ではありましたが、Makefileを手書きするよりかは遥かに楽だと思っています。[1]

今後は既知のバグを潰したり、DlangやHaxeなどのwrapperなどを書いていきたいです。

脚注
  1. Makefile手書きからCMakeに移行した時の感動は忘れられません。 ↩︎

GitHubで編集を提案

Discussion

rikusen0335rikusen0335

全然記事に関係ないんですが、SSのデスクトップ環境がすごい良くて気になりました、どういうの使ってるのでしょうか?

こまもか🦊こまもか🦊

コメントありがとうございます!

自分のラップトップはManjaro LinuxとHyprlandというウィンドウマネージャを使って構築しています。画面上部はWaybarというステータスバーを使っています。

設定等はこちらで公開しているので気になったらぜひ見てみてください!

https://github.com/Comamoca/dotfiles/tree/main/config