Microのプラグイン開発の例として、現在開いているファイルのパスをクリップボードに保存するという処理を書いてみます。
Microでのプラグイン開発はinit.luaに処理を記述するか?配布できる形にするか?の2つの形式がありますが、内容を簡略化する為にinit.luaに記述する方式を取ります。
環境
Micro:2.0.11
今回追加したい機能はコマンドモードで
> cp path
を実行した時は、現在開いているファイルのパスをクリップボードに保存し、
> cp dir
を実行した時は、現在開いているファイルが配置されているディレクトリをクリップボードに保存します。
クリップボードに関しては、コマンドライン上でのクリップボードの利用方法をご覧ください。
※今回の内容を読み進める前に、上記のリンク先の記事を参考にして、wl-copyとosc52のコマンドを使用できるようにしておきましょう。
先に今回作成したコードを載せておきます。
~/.config/micro/init.lua
local micro = import("micro") local config = import("micro/config") local shell = import("micro/shell") function init() config.MakeCommand("cp", cp, config.NoComplete) end -- コマンド実行時に引数を取得する function extractCpMode(args) local mode = ""; for i = 1, #args do mode = args[i] end return mode end -- 使用しているディスプレイサーバを取得する (wayland|x11|tty) function getDisplayServerType() local srv, err = shell.RunCommand("sh -c 'echo $XDG_SESSION_TYPE'") if err == nil and srv:len() > 0 then local strings = import("strings") srv = strings.TrimRight(srv, "\n") if srv:len() > 0 then return srv end end return "tty" end function cp(bp, args) local mode = extractCpMode(args) local path = bp.Buf.AbsPath if mode == "dir" then local fp = import("filepath") path = fp.Dir(path) end local srv = getDisplayServerType() if srv == "wayland" then cmd = "sh -c 'echo -n \""..path.."\" | wl-copy'" elseif srv == "tty" then cmd = "sh -c 'echo -n \""..path.."\" | osc52'" else cmd = "sh -c 'echo -n \""..path.."\" | xclip -selection clipboard'" end local output, err = shell.RunInteractiveShell(cmd, false, false) if err == nil then micro.InfoBar():Message("copied filepath.") else micro.InfoBar():Error(err) end end
コードの解説になります。
extractCpMode関数に関しては省略します。
function getDisplayServerType() local srv, err = shell.RunCommand("sh -c 'echo $XDG_SESSION_TYPE'") if err == nil and srv:len() > 0 then local strings = import("strings") srv = strings.TrimRight(srv, "\n") if srv:len() > 0 then return srv end end return "tty" end
ですが、シェルモードで
sh -c 'echo $XDG_SESSION_TYPE
を実行し、その値を返します。
何も値が返ってこなかった場合は tty を返すようにしています。
この関数で注意すべき内容は、シェルモードを
RunCommand(input string) (string, error)
を介してコマンドを実行しているのですが、実行結果には必ず改行コードが付いてしまいますので、Go言語の strings パッケージにあるTrimRightメソッドで改行コードを削除しています。
micro/runtime/help/plugins.md at master · zyedidia/micro
Luaのコード内でGo言語のパッケージを使用できるようにしているのは、GopherLuaとgopher-luarによって実現しています。
yuin/gopher-lua: GopherLua: VM and compiler for Lua in Go
layeh/gopher-luar: simplifies data passing to and from gopher-lua
使い方は
local strings = import("strings") srv = strings.TrimRight(srv, "\n")
import関数でGo言語のパッケージを読み込み、Go言語の仕様と同様にドット区切りでメソッドを呼び出します。
strings package - strings#TrimRight - Go Packages
使用可能なメソッドはmicro/internal/lua/lua.go at master · zyedidia/microをご確認ください。
続いて見るべきコードは cp 関数内にあります
local path = bp.Buf.AbsPath
になります。
BufのAbsPathはbuffer package - github.com/zyedidia/micro/v2/internal/buffer#SharedBuffer - Go Packagesを参考にしました。
cp 関数内の下記の処理にも触れておきます。
local srv = getDisplayServerType() if srv == "wayland" then cmd = "sh -c 'echo -n \""..path.."\" | wl-copy'" elseif srv == "tty" then cmd = "sh -c 'echo -n \""..path.."\" | osc52'" else cmd = "sh -c 'echo -n \""..path.."\" | xclip -selection clipboard'" end local output, err = shell.RunInteractiveShell(cmd, false, false)
になります。
ディスプレイサーバに合わせて、クリップボードに文字列を保存するコマンドを生成してシェルモードで実行なのですが、今回は
RunInteractiveShell(input string, wait bool, getOutput bool) (string, error)
を利用しています。
何故、ディスプレイサーバの確認時と異なるメソッドを使用する必要があるのか?
これは、RunInteractiveShellの引数にあります wait と getOutput を使用したいからになります。
micro/runtime/help/plugins.md at master · zyedidia/micro
Microのシェルモードで wl-copy を実行すると、実行結果がない状態でエンターキーの入力待ちになります。
※ シェルモードで echo を実行すると待機にはなりますが、実行結果がある為、RunCommandでも問題ないようです。
入力待ち状態を回避するために、wait と getOutput のパラメータを false にしておく必要があります。
追記
tmuxを起動した状態で、Microを開いた時、
> cp path
をしても意図通りに動作しないことがあります。
tmuxの設定を変更する - ターミナルの内容を参考にして、tmux上でクリップボードを使用できるようにしておきましょう。
~/.tmux.conf
set -g set-clipboard on