Ubuntuで VSCodeの Quick Fixが使えなかった問題の調査と修正

VScodeには Quick Fixという機能があって, Rustとか Goの traitとか interfaceを実装する際の雛形の生成に使えるのですが, そのショートカットである Ctrl + .Ubuntuで効かなかったのでその原因の調査と修正を行った.

バインドされているキーを探す

gsettings list-recursively を使ってショートカット一覧を出力し, Ctrlがバインドされているキーを探す.

% gsettings list-recursively | grep "<Control>" 
org.freedesktop.ibus.panel.emoji hotkey ['<Control>period', '<Control>semicolon']
org.freedesktop.ibus.panel.emoji unicode-hotkey ['<Control><Shift>u']
org.gnome.Terminal.Legacy.Keybindings close-tab '<Control><Shift>w'
org.gnome.Terminal.Legacy.Keybindings close-window '<Control><Shift>q'
org.gnome.Terminal.Legacy.Keybindings copy '<Control><Shift>c'
org.gnome.Terminal.Legacy.Keybindings find '<Control><Shift>F'
org.gnome.Terminal.Legacy.Keybindings find-clear '<Control><Shift>J'
org.gnome.Terminal.Legacy.Keybindings find-next '<Control><Shift>G'
org.gnome.Terminal.Legacy.Keybindings find-previous '<Control><Shift>H'
org.gnome.Terminal.Legacy.Keybindings move-tab-left '<Control><Shift>Page_Up'
org.gnome.Terminal.Legacy.Keybindings move-tab-right '<Control><Shift>Page_Down'
org.gnome.Terminal.Legacy.Keybindings new-tab '<Control><Shift>t'
org.gnome.Terminal.Legacy.Keybindings new-window '<Control><Shift>n'
org.gnome.Terminal.Legacy.Keybindings next-tab '<Control>Page_Down'
org.gnome.Terminal.Legacy.Keybindings paste '<Control><Shift>v'
org.gnome.Terminal.Legacy.Keybindings prev-tab '<Control>Page_Up'
org.gnome.Terminal.Legacy.Keybindings zoom-in '<Control>plus'
org.gnome.Terminal.Legacy.Keybindings zoom-normal '<Control>0'
org.gnome.Terminal.Legacy.Keybindings zoom-out '<Control>minus'
org.gnome.desktop.wm.keybindings cycle-panels ['<Control><Alt>Escape']
org.gnome.desktop.wm.keybindings cycle-panels-backward ['<Shift><Control><Alt>Escape']
org.gnome.desktop.wm.keybindings switch-panels ['<Control><Alt>Tab']
org.gnome.desktop.wm.keybindings switch-panels-backward ['<Shift><Control><Alt>Tab']
org.gnome.shell.extensions.screenshot-window-sizer cycle-screenshot-sizes ['<Alt><Control>s']
org.gnome.shell.extensions.screenshot-window-sizer cycle-screenshot-sizes-backward ['<Shift><Alt><Control>s']

org.freedesktop.ibus.panel.emoji'<Control>period'アサインされており, こちらにキーが取られ VScodeの方が効いていないと予想される

ibusのショートカットを変更する

ibus-setupibusの設定画面を起動, emoji タブが下記のようになっていることを確認する

絵文字を直接使うことはまずないし, 使ったこともないのですべて削除した.

最後に

これで VScodeCtrl+. でショートカットが効くようになりました.

merge sort in F#

b.hatena.ne.jp

merge sortを何も見ずに書けるかが気になって書いてみたが特に問題なく書けた. この手の問題は筋トレと同じでいかに普段手を動かして解いている感があるので, leetcodeなどは継続していた方がいいのかなと思った.

open System

let generateNumbers (n: int) : int list =
    let rec generateNumbers' n (r: Random) acc =
        if n = 0 then
            acc
        else
            generateNumbers' (n - 1) r (r.Next(0, 100) :: acc)

    generateNumbers' n (new Random()) []

let merge a b =
    let rec merge' a b acc =
        match a, b with
        | [], [] -> acc |> List.rev
        | h :: t, [] -> merge' t b (h :: acc)
        | [], h :: t -> merge' a t (h :: acc)
        | h1 :: t1, h2 :: t2 ->
            if h1 < h2 then
                merge' t1 b (h1 :: acc)
            else
                merge' a t2 (h2 :: acc)

    merge' a b []

let rec mergeSort (nums: int list) =
    let len = nums.Length

    if len <= 1 then
        nums
    else
        let half = len / 2
        let a = nums |> List.take half |> mergeSort
        let b = nums |> List.skip half |> mergeSort

        merge a b

let nums = generateNumbers 100
let got = mergeSort nums
let expected = List.sort nums

// true
got |> List.zip expected |> List.forall (fun (a, b) -> a = b)

zero length array, flexible array

github.com

たまたま目に入ったこのコードを見ていて, zero length arrayって末尾のメンバ以外でも使えたんだって思って気になるところを調べてみた.

Flexible array

en.wikipedia.org

C99から入った機能. 配列の長さを宣言しないことで利用できる. sizeofはできない. 構造体などの末尾フィールドに置くことができる. 典型的な使い方は以下のような感じ.

struct Data {
   // some fields
   SomeData s[];
};

struct Data *d = malloc(sizeof(Data) + some_arbitrary_size);

ポインタを使ってしまうと構造体とこの末尾のデータがある場所は別の領域になってしまうわけだが, このようにすることで連続するメモリにすべて割り当てることができる.

構造体の末尾以外に置くことはできない

struct Data {
  int a[];
  int b;
};

このようなコードはエラーとなる

a.c:2:7: error: flexible array member not at end of struct
    2 |   int a[];
      |      

Zero length array

gcc.gnu.org

GCC拡張. C90時代から使えたもので, 宣言時に配列サイズを 0とする. Flexible arrayと違い構造体に何個でも宣言でき, GCCでは sizeofを行った場合 0が返るものと規定している.

struct Data {
    int a;
    unsigned char b[0];
    int c[0];
};

このように宣言した場合, bc は同じ先頭アドレスを持ち実質的に union のようになる.

#include <stdio.h>
#include <stdlib.h>

struct Data {
    int a;
    unsigned char b[0];
    int c[0];
};

int main() {
    struct Data *d = malloc(sizeof(int) * 2);
    printf("&d.a=%p\n", &d->a);
    printf("&d.b=%p\n", &d->b);
    printf("&d.c=%p\n", &d->c);

    d->b[0] = 0;
    d->c[0] = 0xdeadbeef;

    printf("d.b[0]=%x\n", d->b[0]);
    printf("d.c[0]=%x\n", d->c[0]);
    return 0;
}

結果は以下の通りで

&d.a=0x559613d242a0
&d.b=0x559613d242a4
&d.c=0x559613d242a4 // cは bと同じアドレス
d.b[0]=ef // cを書き換えると bも変わってしまう
d.c[0]=deadbeef

Flexible array, zero length arrayを使わない場合

今時そんな環境はないと思うが, C99以前かつ GCC拡張が使えない場合は長さ 1の char配列などを置いて代用していたように記憶している.

その他

github.com

上記の変更が含まれる PRにあった non temporalって何ぞやと思ってググると下記の解説があった.

lwn.net

Non-temporal in this context means the data will not be reused soon, so there is no reason to cache it.

とのこと. streamな dataで, 非常に計算速度が重要なものになるとそこまで意識する必要があるんですね. 計算する際キャッシュにうまく載せることは考えたことあったけど不要なものはそもそも載せないという発想がなかった.

いろいろ学びがあった.

markdown-fontify-whole-heading-line

github.com

markdown-modemarkdown-fontify-whole-heading-line flagを実装した. 機能としては org-fontify-whole-heading-line と同じで, non-nilの場合 header lineを丸々一行色付けできるようになる. 特に emacs 27で追加された faceの extend 属性を non-nilにして, 背景色を設定すればその行をすべて色付けできる. (補足 extend 属性が nil だと文字がある部分までしか色付けされない)

設定は以下のようになる

(setq markdown-fontify-whole-heading-line t)
(set-face-attribute 'markdown-header-face-1 nil :extend t :background "green" :foreground "black")
(set-face-attribute 'markdown-header-face-2 nil :extend t :background "pink" :foreground "black")

Visual Studio Code 1.67(2022 April)で入った Toggle Inlay Hintsが良い

code.visualstudio.com

詳細は公式サイトを見てください。

Visual Studio Codeでは上記のように型を書いていなくても型を表示してくれるわけですが, 正直うざいと思うことが多い。特にあまり型を明示的に書かない F#や Rustの場合. 見た目もそうなのだが, 文字を挿入したり削除するときどこにカーソルを合わせるのが適切なのかがわかりづらかったりする問題もあってあまり好きではなかった。ただしどうしても型を知りたいこともあり有効にするか悩ましかったのだが, 先のフラストレーションの方が大きかったので一部機能を無効化していた(F#では細かく設定できたため, 変数と関数呼び出しの型表示を無効化していた).

1.67で入った Toggle Inlay Hintsがこの問題を解消してくれた. editor.inlayHints.enabledon, off しかできなかったのだが, ここに onUnlessPressed, offUnlessPressed という値が設定できるようになり, それぞれデフォルトで Ctrl-Alt を押している間だけ型ヒントを表示, 非常時にできるようになった. offUnlessPressed に設定すれば普段は非常時, 型が見たいときだけ Ctrl-Alt を押せばよくなり, 個人的に非常に使い勝手の良いものになった.

補足: F#の関数の型とパイプラインオペレータを使ったときの行末の型は常に表示するようにしています. 各変数や引数の型が Ctrl-Altにより表示を切り替えられるようになっている.

設定方法

GUIの場合は inlay 等で検索して項目を設定する

settings.json の場合は以下の通り

{
    "editor.inlayHints.enabled": "offUnlessPressed"
}

scoop cleanup

Windowsでのパッケージ管理には scoopを使っているが, scoop cleanup を知らなかった.

> scoop cleanup '*'
Removing 7zip: 19.00 21.06
Removing bat: 0.18.2 0.18.3 0.19.0
Removing cmake: 3.21.3 3.21.4 3.22.0 3.22.1 3.22.2 3.22.3
Removing deno: 1.16.4 1.17.0 1.17.1 1.17.2 1.17.3 1.18.0 1.18.1 1.18.2 1.19.0 1.19.2 1.19.3 1.20.1 1.20.3 1.20.5 1.20.6 1.21.0 1.21.1
Removing fzf: 0.27.2 0.27.3 0.28.0 0.29.0
Removing gh: 1.10.3 1.11.0 1.12.1 1.13.1 1.14.0 1.9.1 1.9.2 2.0.0 2.1.0 2.2.0 2.3.0 2.4.0 2.5.0 2.5.1 2.5.2 2.6.0 2.7.0 2.8.0
Removing go: 1.16.3 1.16.4 1.16.5 1.16.6 1.16.7 1.17 1.17.1 1.17.2 1.17.3 1.17.4 1.17.5 1.17.6 1.17.7 1.17.8 1.18
Removing gradle: 7.0 7.0.2 7.1 7.1.1 7.2 7.3 7.3.1 7.3.2 7.3.3 7.4 7.4.1
Removing lessmsi: 1.8.1 1.8.2 1.9.0
Removing llvm: 11.1.0 12.0.0 12.0.1 13.0.0 13.0.1 14.0.0 14.0.1
Removing python: 3.10.0 3.10.1 3.10.2 3.10.3 3.9.4 3.9.5 3.9.6 3.9.7
Removing ripgrep: 12.1.1
Removing rustup: 1.23.1 1.24.0 1.24.1 1.24.2
Removing sqlite: 3.37.2 3.38.0 3.38.1 3.38.2 3.38.3
Removing zoxide: 0.7.3 0.7.4 0.7.5 0.7.7 0.7.8 0.7.9 0.8.0
Everything is shiny now!

だいぶ古いものが溜まっていた.

HTTP::Tinyで httpsアクセスで 599が返るようになった問題の修正

某モジュールのメンテンスでテストに必要なモジュールを入れようとしたらそもそもエラーが出るということで, エラー原因を調べてみたところ下記のようなエラーが出ていた。HTTP::Tinyを使った httpsへの GETが軒並み失敗していることが原因であった。

$VAR1 = {
          'headers' => {
                         'content-type' => 'text/plain',
                         'content-length' => 110
                       },
          'success' => '',
          'url' => 'https://fastapi.metacpan.org/author/XSAWYERX',
          'status' => 599,
          'content' => 'IO::Socket::SSL 1.42 must be installed for https support
Net::SSLeay 1.49 must be installed for https support
',
          'reason' => 'Internal Exception'
        };

IO::Socket::SSLNet::SSLeay も最新バージョンが入っているのになんでだろと思って以下のコードを実行したところ, 次のようなエラーが出てすぐに問題が特定できた. Ubuntuをアップデートしたところ OpenSSLのバージョンが更新されメジャーバージョンも変わってしまったために再コンパイルが必要になっていただけであった.

use IO::Socket::SSL;
Can't load '/home/syohei/.plenv/versions/5.34.1/lib/perl5/site_perl/5.34.1/x86_64-linux-thread-multi/auto/Net/SSLeay/SSLeay.so' for module Net::SSLeay: libssl.so.1.1: cannot open shared object file: No such file or directory at /home/syohei/.plenv/versions/5.34.1/lib/perl5/5.34.1/x86_64-linux-thread-multi/DynaLoader.pm line 193.
 at /home/syohei/.plenv/versions/5.34.1/lib/perl5/site_perl/5.34.1/IO/Socket/SSL.pm line 19.
Compilation failed in require at /home/syohei/.plenv/versions/5.34.1/lib/perl5/site_perl/5.34.1/IO/Socket/SSL.pm line 19.
BEGIN failed--compilation aborted at /home/syohei/.plenv/versions/5.34.1/lib/perl5/site_perl/5.34.1/IO/Socket/SSL.pm line 19.
Compilation failed in require at a.pl line 2.
BEGIN failed--compilation aborted at a.pl line 2.

再インストールしたら問題が解消した

cpanm --reinstall Net::SSLeay