私が歌川です

@utgwkk が書いている

oEmbedの規格におけるpadding, marginとは何なのか

2.3.4.4. The rich type

(中略)

html (required)

The HTML required to display the resource. The HTML should have no padding or margins. Consumers may wish to load the HTML in an off-domain iframe to avoid XSS vulnerabilities. The markup should be valid XHTML 1.0 Basic.

https://oembed.com/

"The HTML should have no padding or margins." という文の解釈がうまくできずに立ち止まってしまった。 ここでいうpaddingやmarginとは何なのか、規格をさっとgrepしてみても、どうやらここでは定義されてないように見える。 CSSのmarginやpadding? だとしたらここで言及されることなのだろうか、と思う。 余分な空白を入れるべきではありませんよ、ということ? HTMLがmarginやpaddingを持つべきではない、と書いてあるのでこの解釈でいいのだろうか。誰か教えてください。

メーリングリストがあるのを見つけたけど最終投稿が6年前だった。

groups.google.com

VSCodeでPerlのコードのRename Symbol機能を提供する拡張機能を書いた

VSCodeには Rename Symbol っていって、変数やメソッドの名前を一括変更する機能があるのだけれど、これをPerlでも使えるようにしたい。ということで、できたものがこちらになります。

marketplace.visualstudio.com

App::PRTApp::EditorToolsを手元にインストールしてからご利用ください。

メソッド名を変える

App::PRTid:hitode909 さんが作ったPerlリファクタリングツールで、メソッドのリネームなどを安全に行うことができる。 App::PRTを使えばコマンドを叩くだけでリファクタリング成功するのでなんかうまく使えないか、ということで休日を潰して実装した。

提供されているAPIのインタフェースを見るに、ほんとうは、どのトークンを書き換えたらよいかを列挙してreplaceする、ということが求められているのだと思うけれど、コマンド1つで書き換えてくれるので、APIのインタフェースを無視して、無の変更を適用したのち、おもむろにファイルが書き変わる、という形式になっている。

const args = [prtPath, 'replace_token', oldName, newName, ...targetFiles];
cp.execSync(args.join(' '));
resolve(new vscode.WorkspaceEdit());

使用例

gyazo.com

Plack::Responseの header メソッドを一括で atama メソッドにリネームしている。 ちょっと待つとどかっとsource controlに変更点が出てきておもしろい。

変数名を変える

App::EditorToolsというツールを使えば、変数のスコープを考慮した変数のリネームができる、と聞いたので、こちらも使ってみることにした。 こちらは、標準入力からソースコードを流し、コマンドライン引数で変えたい変数について教えて、標準出力から取る、という仕組みになっている。

const args = [editorToolsPath, 'renamevariable', '-c', position.character, '-l', position.line + 1, '-r', newName];
const source = document.getText(); // ファイル全体を取得
const output = cp.execSync(args.join(' '), { input: source, encoding: 'utf-8' });
const edit = new vscode.WorkspaceEdit();
// ファイル全体を書き換える
edit.replace(
    document.uri,
    new vscode.Range(document.lineAt(0).range.start, document.lineAt(document.lineCount - 1).range.end),
    output.toString()
);
resolve(edit);

相変わらずコマンド1つで動けばよかろうの精神で、出力をまるごと今開いてるファイルに適用することでリファクタリングを実現している。

使用例

gyazo.com

Plack::Responseの headers メソッド内の $self を一括で $watashi にリネームしている。 あとから気軽に変数名を変えられるのはたいへん安心できる。

ご活用・ごフイードバックください

とにかく動けばいい、の精神で実装したので、うまくインストールできない、このケースでうまく動かない、などありましたらお知らせいただけるとありがたいです。

github.com

Windows Terminalを試す

Windows Terminalは、Microsoftが開発しているオープンソースの新しいターミナルソフトウェアです。

github.com

ちょっと調べて様子を眺めると、コマンドプロンプト時代からは信じられないほどにカスタマイズ可能になっているようです。 WindowsからはWSLでコードを書いたりSSHしたりするぐらいしかやってないので、このさいwsl-terminalを捨ててみよう、と考えて、Windows Terminalを試してみることにしました。

インストールする

プレビュー版だけどMicrosoft Storeからボタン1つでインストールできます。 GitHubのreleaseから落としてくる、みたいなことをしなくても気軽にお試しできて便利ですね。

www.microsoft.com

Chocolateyでもインストールできるようです。

設定をカスタマイズする

標準状態では、以下のシェルを起動できるプロファイル設定が行われています。

Settingsを押すと設定を編集できますが、突然メモ帳でJSONファイルが開かれるので何が何だか、となってしまいます。 VSCodeで開くと、JSON schemaによる補完やバリデーションが効いて便利です。 %LocalAppData%\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState\profiles.json に設定ファイルがあるので開きます。

このファイルにどんどん所望の設定を突っ込めばカスタマイズ完了です。とりあえず以下のようにしてみました。

// なんとコメントが書ける!!!
{
    "$schema": "https://aka.ms/terminal-profiles-schema",

    // デフォルトでWSLを起動する
    "defaultProfile": "{58ad8b0c-3ef8-5f4d-bc6f-13e4c00f2530}",

    "copyOnSelect": true, // 選択するだけでコピーする
    "snapToGridOnResize": true, // 文字のbounding boxの大きさ単位でウィンドウサイズを変える

    // Azure Cloud Shellを追加されないようにする
    "disabledProfileSources": ["Windows.Terminal.Azure"],

    "profiles":
    {
        "defaults":
        {
            "backgroundImage": "(snip)",
            "backgroundImageOpacity": 0.2,
            "closeOnExit": "always", // exit code関係なくexitしたらタブを閉じる
            "colorScheme": "Campbell",
            "cursorShape": "filledBox", // カーソルの形を █ にする
            "fontFace": "Ricty Diminished",
            "fontSize": 16,
            "padding": "4" // 画面のpadding
        },
        "list":
        [
            {
                "guid": "{58ad8b0c-3ef8-5f4d-bc6f-13e4c00f2530}",
                "hidden": false,
                "name": "WSL",
                "source": "Windows.Terminal.Wsl",
                "commandline": "wsl.exe ~" // %USERPROFILE% じゃなくてWSLの $HOME を起動時のディレクトリとする
            },
            {
                "guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
                "name": "Windows PowerShell",
                "commandline": "powershell.exe",
                "hidden": false
            },
            {
                "guid": "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}",
                "name": "cmd",
                "commandline": "cmd.exe",
                "hidden": true
            },
            {
                // こんな感じでプロファイルを追加できる
                // guidは適当に生成してかぶらなければよさそう?
                "guid": "{084fbb3a-e4f1-445e-92e7-d65eef40e6fa}",
                "name": "SSH (yuuko)",
                "commandline": "ssh.exe yuuko",
                "hidden": false
            }
        ]
    },

    "schemes": [],


    "keybindings": [
        {
            // フォントサイズを大きくする
            "command": "increaseFontSize",
            "keys": ["ctrl+="]
        },
        {
            // フォントサイズを小さくする
            "command": "decreaseFontSize",
            "keys": ["ctrl+-"]
        },
        {
            // フォントサイズをリセットする
            "command": "resetFontSize",
            "keys": ["ctrl+0"]
        },
        // ペイン分割のショートカットキーを封じる
        // - 分割したくなったらtmux使うから
        // - 誤爆したら紛らわしいことになるから
        {
            "command": {
                "action": "unbound",
                "split": "horizontal"
            },
            "keys": [ "alt+shift+-" ]
        },
        {
            "command": {
                "action": "unbound",
                "split": "vertical"
            },
            "keys": [ "alt+shift+plus" ]
        }
    ]
}

完成したターミナルがこちらになります。かわいらしい感じに仕上がってよかったですね。

gyazo.com *1

他にも、以下のページを参考にすれば、いろいろな設定を変えることができます。

デフォルトの設定は、Altを押しながらSettingsを押すと(メモ帳で!)確認することができます。

使い心地どうなの

色をいい感じに変えられる、背景画像を設定できる、ということで、wsl-terminalを使っていたときに欲していた機能や設定は満たしています*2。 日本語も絵文字も難なく入出力できます。

設定を変えよう、となったときにメモ帳が開くのは驚き最大ですが、JSONで設定できるしJSON schemaもあるので安心して設定できるし、再起動しなくても即座に設定が反映され、エラーがあるとエラーだよって教えてくれるのがおもてなしポイント高いです。

がんばってminttyを入れる、みたいなことをせずに快適なターミナルを得ることができてよかったですね。

見つけた不具合

profiles.jsonJSON schemaにない値がある

keybindingsのcommandに unbound (キーとコマンドの関連付けを解除する) があるけどJSON schemaには含まれておらず、警告が出ます。 実際unbindはできているのでJSON schemaの定義に漏れがあるのだと思います。 ざっと検索してみたところissueはなさそうだったので立ててみました。

github.com

JSON schemaを書き直すだけだったらさっとPRを出せるけど、Contribution License Agreementへの同意が必要、ということでいったん立ち止まっているところです。

エスケープシーケンスによって意図せず文字が小さくなることがある

gyazo.com

man zshbuiltins を、wsl-terminal(左)とWindows Terminal(右)で見比べています。 赤い文字列の後に来る文字列がいきなり小さくなることがあります。

gyazo.com

エスケープシーケンスのなにかがおかしそう、という予感がしますが再現条件がまだ特定できていません。 サークルの友だちは、vimで日本語文章を表示すると漢字がときどき小さくなることがあるようでした。

*1:背景画像: #バーチャルYouTuber この子にしましたー - 坦々めお/雲呑めおのイラスト - pixiv

*2:もともとそこまで凝った設定をしてなかったと思う、背景画像が設定できるのはマストだった

Perlの定数とfat comma

たぶん世界中のみなさまがハマったことあると思いますが、私も本日ハマりました。

use strict;
use warnings;
use Data::Dumper;
use constant HOGE_KEY => 'hoge';

print Dumper { HOGE_KEY => 'fuga' };

HashRefのキーを定数に切り出してtypoを防ぐ、という意図でこのように書くと何が起こるか? {hoge => 'fuga'} ではなく {HOGE_KEY => 'fuga'} というHashRefが得られます。

=> 演算子(時々「ファットコンマ」と発音されます)はコンマ演算子の 同義語ですが、もし左側の単語が文字か下線で始まっていて、かつ文字、数字、 下線でのみ構成されている場合、これを文字列として扱うという効果もあります。 これには他の場所では演算子、定数、v-文字列、関数呼び出しとして扱われる オペランドを含みます。 この振る舞いについて迷うことがあるなら、左オペランドを明示的に クォートすることも出来ます。 *1

=> の左辺がidentifierっぽければ文字列として扱われるのが優先され、定数は展開されません。=> の左辺に定数を使いたいときはこうする必要があります。

use strict;
use warnings;
use Data::Dumper;
use constant HOGE_KEY => 'hoge';

print Dumper { HOGE_KEY() => 'fuga' };

これに限らず常に HOGE_KEY() のように書くことを習慣付ける(あるいはlinterで検出する)のがいいのではないかと思ってきました。 そしてここまで書いて perldoc constant にまさにこのケースについて言及されているのを発見しました。

自動的に裸の単語をクォートするコンテキストで定数を使うと (サブルーチン呼び出しの場合と同様)問題が起こります。 例えば、$hash{CONSTANT} とはできません; CONSTANT は文字列として 解釈されるからです。 裸の単語をクォートする機構を防ぐために $hash{CONSTANT()} や $hash{+CONSTANT} を使ってください。 同様に、the => 演算子は左側の裸の単語をクォートするので、 CONSTANT => 'value' ではなく CONSTANT() => 'value' とする (または単に大矢印の代わりにカンマを使う)必要があります。 *2

perldocにはなんでも書いてあります。