WSL2でmikutter

[2020-07-13追記] 解説として書いたわけではないので、そういったものをお求めの場合は↓の記事がおすすめです。

osak.hatenablog.jp [追記ここまで]

作業ログを前後関係調整したもの。この順で実行したわけではない。

必要なコンポーネントを有効にする

前バージョンから大幅に性能向上した新Linux環境「WSL 2」の実力を探る:Windows 10 The Latest - @ITによれば

 まず、必要なWindows 10の機能をインストールする。それには、[コントロールパネル]-[プログラムと機能]を開き、左ペインで[Windowsの機能の有効化または無効化]を選択し、[Windowsの機能]で表示されるリストから「LinuxWindowsサブシステム」を有効にする。

 WSL 2を使うなら、このリストの一番下にある「仮想マシンプラットフォーム」も有効にする(Windows 10 Homeでもサポートされている)。

とのことだったがうちの環境では既にチェックが入っていた。前者はWSL1のときに有効にしたものと思われるが、後者は何故有効になっていたのかよくわからない。利用しているのはHomeなので、Hyper-V関連の機能が有効になったのは今回からではないのかと思うけど……

WSL1に適当なディストロをインストールする

せっかくなのでUbuntu20.04を選択。ストア経由でインストールし、(Cドライブは嫌だったので)別ドライブにコピーしてから、同梱されていた ubuntu2004.exe を実行。そのディレクトリで install.tar.gz から rootfs が展開され、必要なレジストリ登録などが実行された。 ユーザー名とパスワードを聞かれるので、設定する。それが終わるとWSLのシェルが開くので、ひとまずパッケージを更新しておく。

$ for i in update full-upgrade autoremove autoclean; do sudo apt $i -y; done

管理者権限のコマンドプロンプトを開いて

wsl -l -v

を実行すると、今まで使っていたUbuntu(WSL1)とともに、新しいものが表示される。

C:\WINDOWS\system32>wsl -l -v
  NAME            STATE           VERSION
* Ubuntu          Stopped         1
  Ubuntu-20.04    Stopped         1

WSL2に変換

次にUbuntu-20.04をWSL2に変換する。

C:\WINDOWS\system32>wsl --set-version Ubuntu-20.04 2
変換中です。この処理には数分かかることがあります...
WSL 2 を実行するには、カーネル コンポーネントの更新が必要です。詳細については https://aka.ms/wsl2kernel を参照してください

とのことで、さっそく指定のURLを開くと説明があり、 wsl_update_x64.msi をダウンロードして実行するように促される。 実行するとウィザード形式のインストーラが開くが、次へ次へと普通に進めれば良い。 その後、改めてWSL2への変換コマンドを再実行する。

C:\WINDOWS\system32>wsl --set-version Ubuntu-20.04 2
変換中です。この処理には数分かかることがあります...
WSL 2 との主な違いについては、https://aka.ms/wsl2 を参照してください
仮想ディスク システムの制限により、要求された操作を完了できませんでした。仮想ハード ディスク ファイルの圧縮と暗号化が解除されている必要があります。また、仮想ハード ディスク ファイルをスパースに設定することはできません。

アッハイ。 Ubuntu20.04が入っているフォルダのプロパティを開いて「内容を圧縮してディスク領域を節約する」のチェックを外し、以下すべてのファイル・フォルダに適用するようにしておく。メッセージから受ける印象とは反してディスク全体の設定を変える必要はない。 仮想ハードディスクを一体どのように作っているのだろう。てっきり空の仮想ディスクファイルを用意して、そこにコピーしていくのかと思ったが、NTFSからダイレクトに変換をかけているのかな。 圧縮設定の変更が完了したあと、三度目の変換を試みる。

C:\WINDOWS\system32>wsl --set-version Ubuntu-20.04 2
変換中です。この処理には数分かかることがあります...
WSL 2 との主な違いについては、https://aka.ms/wsl2 を参照してください
変換が完了しました。

C:\WINDOWS\system32>wsl -l -v
  NAME            STATE           VERSION
* Ubuntu          Stopped         1
  Ubuntu-20.04    Stopped         2

今度はうまく行った模様。

別のターミナルを開いて、 ubuntu2004.exe を実行してみる。通常通りbashが立ち上がる。 その状態でまた wsl -l -v を実行してみる。

C:\WINDOWS\system32>wsl -l -v
  NAME            STATE           VERSION
* Ubuntu          Stopped         1
  Ubuntu-20.04    Running         2

Runningに変化した。

ターミナルを選ぶ

cmd.exeではさすがにやってられないのでターミナルを選ぶ。 WSL1ではwslttyを使っていたが、せっかくなのでWindowsTerminalを試してみる。 ストアからインストールして起動して設定を見る。JSONをテキスト編集させるストロングスタイル。この辺はVSCodeと同じか。デフォルト設定を開くにはAltキーを押しながら開く、というのは妙な感じだがJSONファイル内に説明があるので問題ない。 フォントをCicaに変更し、デフォルトプロファイルを今インストールしたUbuntu20.04に変更。選択時にコピーするオプションを有効、コピーとペーストのショートカットキーを削除、カーソル形状を filledBox に変更。貼り付けはマウス右クリックでできる模様。

必要なソフトのインストール

vimとgitは入っていた。とりあえずzshを入れる。

sudo apt install zsh
chsh -s /usr/bin/zsh

これだけで新しいタブではzshで開いた。wslttyより便利だ。 しかし .zshrc が無いのでいつもの面倒なプロンプトが出る。自分用のdotfilesを持ってきてシェルはこれでOK。

build-essentialを入れなければ何も始まらないので入れる。

sudo apt install build-essential

続いてrbenvを入れる。

git clone https://github.com/rbenv/rbenv/ ~/.rbenv
mkdir .rbenv/plugins && git clone https://github.com/rbenv/ruby-build ~/.rbenv/plugins/ruby-build
export PATH=$HOME/.rbenv/bin:$PATH
eval "$(rbenv init -)"
rbenv install -l

rbenvがいつのまにか各マイナーバージョン系列の最新バージョンしか表示しなくなっていて非常に便利だ。 続いてrubyをインストール

apt-get install -y libssl-dev libreadline-dev zlib1g-dev
rbenv install 2.6.6
rbenv install 2.7.1
rbenv global 2.7.1

2.6.6は必要ないっちゃ必要ないんだけど……一応ね。

mikutterを入れる

mkdir ~/repos
cd repos
git clone git://mikutter.hachune.net/mikutter.git
cd mikutter
git switch develop
bundle install --path vendor/bundle
[DEPRECATED] The `--path` flag is deprecated because it relies on being remembered across bundler invocations, which bundler will no longer do in future versions. Instead please use `bundle config set path 'vendor/bundle'`, and stop using this flag

そうだったのか。まぁそれはそれとして今はまだ動く。

fcitx-mozcをインストール

sudo apt install fcitx-mozc
0 upgraded, 427 newly installed, 0 to remove and 0 not upgraded.

わお。

日本語ロケールのインストール

sudo apt install language-pack-ja

フォントのインストール

sudo apt install fonts-noto fonts-noto-cjk fonts-noto-mono ttf-ancient-fonts

環境変数の設定

export LANG=ja_JP.UTF-8
export EDITOR=vim
export DISPLAY=:0.0
export LIBGL_ALWAYS_INDIRECT=1
export GTK_IM_MODULE=fcitx
export QT_IM_MODULE=fcitx
export XMODIFIERS=@im=fcitx
export DefaultIMModule=fcitx

こんなもんかな。

mikutterの起動

ruby mikutter.rb
/home/cobodo/repos/mikutter/vendor/bundle/ruby/2.7.0/gems/gtk2-3.4.1/lib/gtk2.rb:13:in `init': Cannot open display: :0.0 (Gtk::InitError)

雑にググったら↓が出てきたのでそのようにします。

https://qiita.com/ryoi084/items/0dff11134592d0bb895c

XLaunchで -ac オプション付きの config.xlaunch を作って、それ経由でVcXsrvを起動。

DISPLAY 変数の設定方法を以下のように変更

export DISPLAY=$(cat /etc/resolv.conf | grep nameserver | awk '{print $2}'):0

おわり

fcitx-autostart
ruby ./mikutter.rb

転職した話

ずいぶん間が空いてしまいましたが、その間何をやっていたかというと、生活を変えていたのです。

  • 1~3月頃:転職活動をして内定をもらう
  • 4~5月頃:退職の手続きだの引っ越しのあれやこれや
  • 6月:新しい会社で働き始める

といった具合です。

今までは愛知県に住んで名古屋の会社に通勤していたわけですが、心機一転、東京に引っ越して東京の会社で働くことにしました。

これが初めての転職ということもありますが、前職は受託仕事だったのに対して、現職は自社サービス主体の会社なので、何もかも新鮮です。

1ヶ月経って新しい生活にも少しずつ慣れてきましたが、改善すべき点は多々あるので、がんばっていきたいと思います。

SATySFiを使ってみた話

PDFで文書を書く必要性に直面したので、最近話題のSATySFiを使ってみました。

前提として、The SATySFibookは持っていません。

電子書籍で売って欲しいのですが、電子版は無償公開するという話なのでひとまず待っています。

OCamlは全く触ったことがないので、実装はよくわかりません。 印象としては、TeXレベルの実装は完了していてLaTeXレベルのマクロライブラリやドキュメントクラスのほうがまだまだなのかなといった感じでした。

LaTeXの方は、もう6年くらい触っていないので最近の動向がよくわかりませんが、当時のLaTeXと現在のSATySFiを比べると、以下のような感じかなと思います。

  • 当然UTF-8LaTeXもupLaTeXとかあるらしいですね)
  • 型の不一致によるエラー検出が明確でわかりやすい。
  • section等が構造化されていて、文書構造をネストで表現できる(HTMLの感覚に近い)。
  • 使いたい機能の不足。
    • そして機能が追加しやすい。

基本的には良いことだらけという印象ですが、機能の不足はやはり否めません。「機能」と、雑に書いていますが、実際のところ基本機能として絶対的に足りていないものがあるわけではなく、マクロレベルのショートハンドが足りない、といった印象です。 実際に使う際には、付属の stdjareport.satyh をコピーして改造し、 myjareport.satyh というものを作って、必要な機能を足しながらやっていくということになりました。

そんなに複雑な文書を作成したわけではないので、追加した機能は4つだけです。

+pnの移植

字下げの無い段落を作るやつです。 stdjabook.satyh にはあるのに、 stdjareport.satyh には無かったので、必要そうな部分をコピペしました。それだけです。

即時改行

これが無いというのは驚きました。とはいえ、基本的には無いなら無いで+pnを使えばよいという話なのですが、論理構造が崩れるのが嫌だったので導入しました。

なぜ即時改行が必要になったかというと、禁則処理の問題です。CamelCaseのような単語が和文中に出現すると、右側の余白にはみ出してしまう場合があり、私の意図としては次の行に送ってほしかったために、その前に即時改行を入れるようにした、ということです。 本来的には禁則処理をそのように動かすように改造する(はみ出す語を次の行へ送る+元の行を均等割付)のが筋ですが、難易度が高そうに思えたので、手抜きをしました。

実装としては以下のようにしました。

let-inline ctx \br = inline-fil ++ embed-block-breakable ctx (block-skip (get-natural-width (read-inline ctx {m})))

使うときは \br; です。

block-skipの引数はlength型なのですが、length型のリテラルが見当たらず、適当に型合わせをしました。適当に型を合わせればなんとなく動くというのは静的型付け関数型言語一般の強みだと思います。お世辞にもきれいとは言えませんが、動けばいいのです。((get-font-size ctx) *' 0.7)でもわりとそれっぽくはなりました。

ページ番号を表示しないオプションを追加

今回の要件ではページ番号は必要なかったため、このようなものを追加しました。documentにわたす無名レコード型にwith-pageno : bool;という行を足して、letwith-pagenoという名前を束縛し、

{—  #it-pageno; — }

と書かれている部分を

(if with-pageno then {—  #it-pageno; — } else {})

に置き換えただけです。documentwith-pageno = false;を渡してやれば、ページ番号が表示されなくなります。

+subsubsectionの追加

stdjabook.satyh の場合、セクション構造として以下の3つが用意されています。

  • section
  • subsection
  • subsubsection

一方 stdjareport.satyh はこうです。

  • chapter
  • section
  • subsection

これは確かLaTeXのjarticle系でもこのような感じだったと思いますし、不備というわけではありません。

そもそも文書構造が悪いという話なんですが、書いている途中、どうしても4段目のセクション構造が欲しくなってしまったので、軽率に足しました。つまり、以下の4段階構造となります。

  • chapter
  • section
  • subsection
  • subsubsection

やったことといえば、+subsubsection用のカウンタとフォントサイズ指定を足し、上位のセクションヘッダ出力時にカウンタをリセットするようにし、セクション出力コードは上位のものをコピペして適当に書き換えるだけ、という単純なものです。

わからなかった点

.satyhファイルを触る上で、わからなかった点を挙げます。上記とも重複します。

  • 禁則処理のカスタマイズ方法
  • length型の値を生成するうまいやり方
  • documentに与えるレコード型のデフォルト値の設定方法
  • +section等にラベルを与える方法

最終的にはわかったんですが、Stringリテラルが最初は見つけられず、\codeに渡したい引数をどう書けばいいのか悩んでいた時期もありました。

こう↓書けば動くようでした。

+p{
  \code(`answer`);メソッドの定義。
}
+code(`
  def answer
    42
  end
`);

以下の資料が参考になりました。

The SATySFibookも読みたいものですが、可能な限り物理書籍の所持数を減らしたいので、電子版待ちです。

参考までに、改造した myjareport.satyh を貼っておきます。

% -*- coding: utf-8 -*-
@require: pervasives
@require: gr
@require: list
@require: math
@require: color
@require: footnote-scheme


module MyJaReport : sig

  val document : 'a -> block-text -> document
    constraint 'a :: (|
      title : inline-text;
      author : inline-text;
      with-pageno : bool;
    |)

  val font-latin-roman  : string * float * float
  val font-latin-italic : string * float * float
  val font-latin-sans   : string * float * float
  val font-latin-mono   : string * float * float
  val font-cjk-mincho   : string * float * float
  val font-cjk-gothic   : string * float * float
  val set-latin-font : (string * float * float) -> context -> context
  val set-cjk-font   : (string * float * float) -> context -> context
  direct \ref : [string] inline-cmd
  direct \ref-page : [string] inline-cmd
  direct \figure : [string?; inline-text; block-text] inline-cmd
  direct +p : [inline-text] block-cmd
  direct +pn : [inline-text] block-cmd
  direct +chapter : [string?; inline-text; block-text] block-cmd
  direct +section : [string?; inline-text; block-text] block-cmd
  direct +subsection : [string?; inline-text; block-text] block-cmd
  direct +subsubsection : [string?; inline-text; block-text] block-cmd
  direct \emph : [inline-text] inline-cmd
  direct \dfn : [inline-text] inline-cmd
  direct \footnote : [inline-text] inline-cmd

end = struct

%  type toc-element =
%    | TOCElementChapter    of string * inline-text
%    | TOCElementSection    of string * inline-text
%    | TOCElementSubsection of string * inline-text


  let generate-fresh-label =
    let-mutable count <- 0 in
      (fun () -> (
        let () = count <- !count + 1 in
          `generated:` ^ (arabic (!count))
      ))


  let-inline ctx \ref key =
    let opt = get-cross-reference (key ^ `:num`) in
    let it =
      match opt with
      | None    -> {?}
      | Some(s) -> embed-string s
    in
      read-inline ctx it


  let-inline ctx \ref-page key =
    let opt = get-cross-reference (key ^ `:page`) in
    let it =
      match opt with
      | None    -> {?}
      | Some(s) -> embed-string s
    in
      read-inline ctx it


  let font-size-normal  = 12pt
  let font-size-title   = 18pt
  let font-size-author  = 16pt
  let font-size-chapter = 22pt
  let font-size-section = 18pt
  let font-size-subsection = 16pt
  let font-size-subsubsection = 14pt

  let section-top-margin = 20pt
  let section-bottom-margin = 12pt

  let chapter-top-margin = 30pt
  let chapter-bottom-margin = 18pt

  let font-ratio-latin = 1.
  let font-ratio-cjk = 0.88

  let font-latin-roman  = (`Junicode`   , font-ratio-latin, 0.)
  let font-latin-italic = (`Junicode-it`, font-ratio-latin, 0.)
  let font-latin-sans   = (`lmsans`    , font-ratio-latin, 0.)
  let font-latin-mono   = (`lmmono`    , font-ratio-latin, 0.)
  let font-cjk-mincho   = (`ipaexm`    , font-ratio-cjk  , 0.)
  let font-cjk-gothic   = (`ipaexg`    , font-ratio-cjk  , 0.)


  let set-latin-font font ctx =
    ctx |> set-font Latin font


  let set-cjk-font font ctx =
    ctx |> set-font HanIdeographic font
        |> set-font Kana           font


  let get-standard-context wid =
    get-initial-context wid (command \math)
      |> set-dominant-wide-script Kana
      |> set-language Kana Japanese
      |> set-language HanIdeographic Japanese
      |> set-dominant-narrow-script Latin
      |> set-language Latin English
      |> set-font Kana           font-cjk-mincho
      |> set-font HanIdeographic font-cjk-mincho
      |> set-font Latin          font-latin-roman
      |> set-math-font `lmodern`
      |> set-hyphen-penalty 100


  let-mutable ref-float-boxes <- []


  let height-of-float-boxes pageno =
%    let () = display-message `get height` in
    (!ref-float-boxes) |> List.fold-left (fun h (pn, bb) -> (
      if pn < pageno then h +' (get-natural-length bb) else h
    )) 0pt


  let-mutable ref-figure <- 0


  let-inline ctx \figure ?:labelopt caption inner =
    let () = ref-figure <- !ref-figure + 1 in
    let s-num = arabic (!ref-figure) in
    let () =
      match labelopt with
      | Some(label) -> register-cross-reference (label ^ `:num`) s-num
      | None        -> ()
    in
    let it-num = embed-string s-num in
    let bb-inner =
      let d (_, _) _ _ _ = [] in
      block-frame-breakable ctx (2pt, 2pt, 2pt, 2pt) (d, d, d, d) (fun ctx -> (
        read-block ctx inner
          +++ line-break true true ctx (inline-fil ++ read-inline ctx {図#it-num; #caption;} ++ inline-fil)
      ))
    in
      hook-page-break (fun pbinfo _ -> (
%        let () = display-message (`register` ^ (arabic pbinfo#page-number)) in
        ref-float-boxes <- (pbinfo#page-number, bb-inner) :: !ref-float-boxes
      ))


  let make-chapter-title ctx =
    ctx |> set-font-size font-size-chapter
        |> set-font Latin font-latin-sans
        |> set-cjk-font font-cjk-gothic


  let make-section-title ctx =
    ctx |> set-font-size font-size-section
        |> set-font Latin font-latin-sans
        |> set-cjk-font font-cjk-gothic


  let make-subsection-title ctx =
    ctx |> set-font-size font-size-subsection
        |> set-font Latin font-latin-sans
        |> set-cjk-font font-cjk-gothic

  let make-subsubsection-title ctx =
    ctx |> set-font-size font-size-subsubsection
        |> set-font Latin font-latin-sans
        |> set-cjk-font font-cjk-gothic


%  let-mutable toc-acc-ref <- []


  let get-cross-reference-number label =
    match get-cross-reference (label ^ `:num`) with
    | None    -> `?`
    | Some(s) -> s


  let get-cross-reference-page label =
    match get-cross-reference (label ^ `:page`) with
    | None    -> `?`
    | Some(s) -> s


  let chapter-heading ctx ib-heading =
    line-break true false
      (ctx |> set-paragraph-margin chapter-top-margin chapter-bottom-margin)
        ib-heading


  let section-heading ctx ib-heading =
    line-break true false
      (ctx |> set-paragraph-margin section-top-margin section-bottom-margin)
        ib-heading


  let-inline ctx \dummy it =
    let ib = read-inline (ctx |> set-text-color Color.white) it in
    let w = get-natural-width ib in
      ib ++ inline-skip (0pt -' w)


  let document record inner =
    % -- constants --
    let title = record#title in
    let author = record#author in
    let with-pageno = record#with-pageno in
    let page = A4Paper in
    let txtorg = (80pt, 100pt) in
    let txtwid = 440pt in
    let txthgt = 630pt in
    let hdrorg = (40pt, 30pt) in
    let ftrorg = (40pt, 780pt) in
    let hdrwid = 520pt in
    let ftrwid = 520pt in

    let () =
      register-cross-reference `changed` `F`
    in

    let ctx-doc = get-standard-context txtwid in

    % -- title --
    let bb-title =
      let bb-title-main =
        let ctx =
          ctx-doc |> set-font-size font-size-title
        in
          line-break false false ctx
            (inline-fil ++ read-inline ctx title ++ inline-fil)
      in
      let bb-author =
        let ctx =
          ctx-doc |> set-font-size font-size-author
        in
          line-break false false ctx
            (inline-fil ++ read-inline ctx author ++ inline-fil)
      in
        bb-title-main +++ bb-author
    in

    % -- main --
    let bb-main = read-block ctx-doc inner in

    % -- page settings --
    let pagecontf pbinfo =
      let () = FootnoteScheme.start-page () in
      let hgtfb = height-of-float-boxes pbinfo#page-number in
      let (txtorgx, txtorgy) = txtorg in
      (|
        text-origin = (txtorgx, txtorgy +' hgtfb);
        text-height = txthgt -' hgtfb;
      |)
    in
    let pagepartsf pbinfo =
      let pageno = pbinfo#page-number in
      let header =
        let ctx =
          get-standard-context hdrwid
            |> set-paragraph-margin 0pt 0pt
        in
        let ib-text =
         if pageno mod 2 == 0 then
           (inline-fil ++ read-inline ctx title)
         else
           (read-inline ctx title ++ inline-fil)
        in
%        let () = display-message `insert` in
        let (bb-float-boxes, acc) =
          (!ref-float-boxes) |> List.fold-left (fun (bbacc, acc) elem -> (
            let (pn, bb) = elem in
              if pn < pageno then
                let bbs =
                  line-break true true (ctx |> set-paragraph-margin 0pt 12pt)
                    (inline-fil ++ embed-block-top ctx txtwid (fun _ -> bb) ++ inline-fil)
                      % 'ctx' is a dummy context
                in
                  (bbacc +++ bbs, acc)
              else
                (bbacc, elem :: acc)
          )) (block-nil, [])
        in
        let () = ref-float-boxes <- acc in
          bb-float-boxes
      in
      let footer =
        let ctx = get-standard-context ftrwid in
        let it-pageno = embed-string (arabic pbinfo#page-number) in
          line-break true true ctx
            (inline-fil ++ (read-inline ctx (if with-pageno then {— #it-pageno; —} else {})) ++ inline-fil)
      in
        (|
          header-origin  = hdrorg;
          header-content = header;
          footer-origin  = ftrorg;
          footer-content = footer;
        |)
    in
      page-break page pagecontf pagepartsf (bb-title +++ bb-main)

  let-mutable num-chapter <- 0
  let-mutable num-section <- 0
  let-mutable num-subsection <- 0
  let-mutable num-subsubsection <- 0


  let quad-indent ctx =
    inline-skip (get-font-size ctx *' font-ratio-cjk)


  let-block ctx +p inner =
    let ib-inner = read-inline ctx inner in
    let br-parag = (quad-indent ctx) ++ ib-inner ++ inline-fil
    in
      form-paragraph ctx br-parag

  let-block ctx +pn inner =
    let ib-inner = read-inline ctx inner in
      form-paragraph ctx (ib-inner ++ inline-fil)

  let chapter-scheme ctx label title inner =
    let ctx-title = make-chapter-title ctx in
    let () = increment num-chapter in
    let () = num-section <- 0 in
    let () = num-subsection <- 0 in
    let () = num-subsubsection <- 0 in
    let s-num = arabic (!num-chapter) in
    let () = register-cross-reference (`chapter:` ^ label ^ `:num`) s-num in
%    let () = toc-acc-ref <- (TOCElementChapter(label, title)) :: !toc-acc-ref in
    let ib-num =
      read-inline ctx-title (embed-string (s-num ^ `.`))
        ++ hook-page-break (fun pbinfo _ -> (
             let pageno = pbinfo#page-number in
               register-cross-reference (`chapter:` ^ label ^ `:page`) (arabic pageno)))
    in
    let ib-title = read-inline ctx-title title in
    let bb-title = chapter-heading ctx (ib-num ++ (inline-skip 10pt) ++ ib-title ++ (inline-fil)) in
    let bb-inner = read-block ctx inner in
      bb-title +++ bb-inner


  let section-scheme ctx label title inner =
    let ctx-title = make-section-title ctx in
    let () = increment num-section in
    let () = num-subsection <- 0 in
    let () = num-subsubsection <- 0 in
    let s-num = arabic (!num-chapter) ^ `.` ^ arabic (!num-section) in
    let () = register-cross-reference (`section:` ^ label ^ `:num`) s-num in
%    let () = toc-acc-ref <- (TOCElementSection(label, title)) :: !toc-acc-ref in
    let ib-num =
      read-inline ctx-title (embed-string (s-num ^ `.`))
        ++ hook-page-break (fun pbinfo _ -> (
             let pageno = pbinfo#page-number in
               register-cross-reference (`section:` ^ label ^ `:page`) (arabic pageno)))
    in
    let ib-title = read-inline ctx-title title in
    let bb-title = section-heading ctx (ib-num ++ (inline-skip 10pt) ++ ib-title ++ (inline-fil)) in
    let bb-inner = read-block ctx inner in
      bb-title +++ bb-inner


  let subsection-scheme ctx label title inner =
    let () = num-subsubsection <- 0 in
    let () = increment num-subsection in
    let s-num = arabic (!num-chapter) ^ `.` ^ arabic (!num-section) ^ `.` ^ arabic (!num-subsection) in
    let () = register-cross-reference (label ^ `:num`) s-num in
%    let () = toc-acc-ref <- (TOCElementSubsection(label, title)) :: !toc-acc-ref in
    let ctx-title = make-subsection-title ctx in
    let ib-num =
      read-inline ctx-title (embed-string (s-num ^ `.`))
        ++ hook-page-break (fun pbinfo _ -> register-cross-reference (label ^ `:page`) (arabic pbinfo#page-number))
    in
    let ib-title = read-inline ctx-title title in
    let bb-title =
      line-break true false (ctx |> set-paragraph-margin section-top-margin section-bottom-margin)
        (ib-num ++ (inline-skip 10pt) ++ ib-title ++ (inline-fil))
    in
    let bb-inner = read-block ctx inner in
      bb-title +++ bb-inner

  let subsubsection-scheme ctx label title inner =
    let () = increment num-subsubsection in
    let s-num = arabic (!num-chapter) ^ `.` ^ arabic (!num-section) ^ `.` ^ arabic (!num-subsection) ^ `.` ^ arabic (!num-subsubsection) in
    let () = register-cross-reference (label ^ `:num`) s-num in
%    let () = toc-acc-ref <- (TOCElementSubsection(label, title)) :: !toc-acc-ref in
    let ctx-title = make-subsubsection-title ctx in
    let ib-num =
      read-inline ctx-title (embed-string (s-num ^ `.`))
        ++ hook-page-break (fun pbinfo _ -> register-cross-reference (label ^ `:page`) (arabic pbinfo#page-number))
    in
    let ib-title = read-inline ctx-title title in
    let bb-title =
      line-break true false (ctx |> set-paragraph-margin section-top-margin section-bottom-margin)
        (ib-num ++ (inline-skip 10pt) ++ ib-title ++ (inline-fil))
    in
    let bb-inner = read-block ctx inner in
      bb-title +++ bb-inner


  let-block ctx +chapter ?:labelopt title inner =
    let label =
      match labelopt with
      | None        -> generate-fresh-label ()
      | Some(label) -> label
      in
        chapter-scheme ctx label title inner


  let-block ctx +section ?:labelopt title inner =
    let label =
      match labelopt with
      | None        -> generate-fresh-label ()
      | Some(label) -> label
    in
      section-scheme ctx label title inner


  let-block ctx +subsection ?:labelopt title inner =
    let label =
      match labelopt with
      | None        -> generate-fresh-label ()
      | Some(label) -> label
    in
      subsection-scheme ctx label title inner


  let-block ctx +subsubsection ?:labelopt title inner =
    let label =
      match labelopt with
      | None        -> generate-fresh-label ()
      | Some(label) -> label
    in
      subsubsection-scheme ctx label title inner


  let-inline ctx \emph inner =
    let ctx =
      ctx |> set-font Latin font-latin-sans
          |> set-cjk-font font-cjk-gothic
    in
      read-inline ctx inner


  let-inline \dfn inner = {\emph{#inner;}}


  let-inline ctx \footnote it =
    let size = get-font-size ctx in
    let ibf num =
      let it-num = embed-string (arabic num) in
      let ctx =
        ctx |> set-font-size (size *' 0.75)
            |> set-manual-rising (size *' 0.25)
      in
        read-inline ctx {\*#it-num;}
    in
    let bbf num =
      let it-num = embed-string (arabic num) in
      let ctx =
        ctx |> set-font-size (size *' 0.9)
            |> set-leading (size *' 1.2)
            |> set-paragraph-margin (size *' 0.5) (size *' 0.5)
          %temporary
      in
        line-break false false ctx (read-inline ctx {#it-num; #it;} ++ inline-fil)
    in
      FootnoteScheme.main ctx ibf bbf

  end

  let-inline ctx \br = inline-fil ++ embed-block-breakable ctx (block-skip (get-natural-width (read-inline ctx {m})))

let document = MyJaReport.document
  % ad-hoc

Worldon: MITライセンスに変更

今までは3条項BSDライセンスでしたが、mikutter本体や多くのプラグインと同じ、MITライセンスに変更しました。

また、今までは独自ライセンスのものを利用していた、公開範囲設定に使用するアイコンの方も、同じくMITライセンスであるLibreICONSに変更しました。

open_your_urlプラグイン

GitHub - osak/show_tweet: URLを指定してツイートを開くためのmikutterプラグインというプラグインがあって、これを以下のように変えたものです。

  • 任意のモデルを開けるように修正
  • 入力ダイアログをdialog DSLで開くようにすることで安定性を向上
  • メッセージを開くときに自前でタブを管理するのではなくsmartthreadを使用するようにする
    • これにより返信ツリーも見られるように

ほとんど元のコードが残らなくなってしまったため、pull-reqを送ったらforkしてくれと言われてしまいました

そんなわけで、(一応名前やアイコンを変えて)forkした別物ということにしてあります。

もっとも、:show_tweetイベントのような、元のAPIは維持しているので、完全な別物というわけでもありません。

Worldon: セキュリティアップデート

Worldonを更新しました。 利用されている方はアップデートを推奨します。また、以下の操作を推奨します。

  • mikutter上でWorldonを使用して登録されたアカウントをすべて削除
  • Mastodonの設定→認証済みアプリからWorldonのものをすべて削除
  • mikutter上で改めてアカウント認証

特に、Worldonを入れた状態でmikutterがクラッシュし、次の起動時に表示されるログを送信したり、mastodonredmine等に貼り付けたことがある人は、上記の操作を行っておいたほうがよいです。

危険性

アカウントとトークンの組み合わせがわかると、以下のことができます。

  • 勝手にトゥートする
  • 既存フォロー先の非公開トゥートを読める
  • あなた宛のダイレクトトゥートを読める
  • 勝手にフォローする

トークンは漏れないように注意しましょう。

問題点

worlduriaccess_tokenが含まれていたため、バグ報告などのためにログを取ったりして公開すると、意図せずトークンが漏れる可能性がありました。

このため、uriaccess_tokenを含まないようにする改修を行いました。

この問題は @rinsuki@mstdn.maud.ioさんに指摘していただきました。ありがとうございます。