Monthly Archives: 7月 2021

2021-07-22 ,

Feedly Open All Unread Button Jul.2021

久しぶりにFeedlyを使ってみているのですが、未読のページ(全文)を一括で開く機能が無いととても使う気になれないので以前作っていたスクリプトを修正しました。

ChromeのTampermonkeyで確認。

// ==UserScript==
// @name         Feedly Open All Unread
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  try to take over the world!
// @author       You
// @match        https://feedly.com/i/*
// @icon         https://www.google.com/s2/favicons?domain=feedly.com
// @grant        GM_openInTab
// ==/UserScript==

(function() {
    'use strict';

    function openUnreadEntries(limit){
        const unreads = document.querySelectorAll(".entry--unread");
        const count = Math.min(unreads.length, limit || 5);
        console.log("count="+count);
        for(let i = 0; i < count; ++i){
            const entry = unreads[i];
            const url = entry && entry.dataset.alternateLink;
            //window.open(url, "_blank");
            //browser.tabs.create({url, active: false});
            GM_openInTab(url, {active:false});
            console.log("open " + url);

            // mark as read and hide
            const readAndHideButton = entry && (
                entry.querySelector(".EntryHideButton") || //Title Only
                    entry.querySelector(".EntryMarkAsReadButton") //Magazine, Card
            );
            if(readAndHideButton){
                readAndHideButton.click();
            }
        };
    }
    function createButton(){
        const div = document.createElement("div");
        div.style.display = "inline-block";
        div.style.verticalAlign = "top";
        div.className = "button-dropdown OpenUnreadButton";

        const button = document.createElement("button");
        div.appendChild(button);
        button.type = "button";
        button.innerText = "Open Unread";
        button.style = "padding-right:0px; margin-right:0px;";
        button.addEventListener("click", function(e){
            openUnreadEntries(parseInt(inputCount.value, 10));
        }, false);

        const inputCount = document.createElement("input");
        div.appendChild(inputCount);
        inputCount.type = "number";
        inputCount.value = "5";
        inputCount.style = "width:4em; padding:12px 5px 10px 5px; border:1px solid transparent; appearance: normal;";

        return div;
    }
    function updatePageUI(){
        for(const bar of document.getElementsByClassName("actions-container")){
            if(!bar.querySelector(".OpenUnreadButton")){
                bar.insertBefore(createButton(), bar.firstChild);
            }
        }
    }
    setInterval(updatePageUI, 1000);

})();

Inoreaderというのも使ってみたのですが、どっちみち全文を一気に読むには拡張機能が必要なことに変わりないのでとりあえずFeedlyでいいやと思いました。

2021-07-18 , ,

FontForgeでMeiryoKe_ConsoleとInconsolataをくっつける

これまでEmacsのフォント設定でASCIIはInconsolata、それ以外はMeiryoKe_Consoleを使うように設定していたのだけど、細かい調整が出来ないのでそれならばとFontForgeで一つのフォントに合成してしまうことにした。そうすれば細かい調整はFontForgeの方である程度行えるからだ。また、フォントサイズ(奇数サイズ)によって全角の幅が半角の幅のちょうど二倍にならない場合があるのもフォントを一つにしてしまえば解決すると思われた。ちなみにInconsolataは0に斜線が入っていて細身で綺麗なので長年使っている。MeiryoKe_Consoleを使っているのはぼやけたフォントが嫌いなのでヒンティングがしっかりしているメイリオでかつ等幅にしたものが欲しいからだ(ヒンティングには賛否両論あるとは思うが私はどちらかと言えば下手にアンチエイリアスしてぼやけたものよりもシャープな文字の方が好きだ。低解像度環境で細いフォントならば)。

ダウンロード先:

  • Inconsolata : Boldもダウンロードしておくと良い。さらにFontForge等で斜体版を作っておくとなお良い。
  • MeiryoKe : こちらもFontForgeで斜体版を作っておくと良い。
  • FontForge : 最新版にしたら常時カナロックがかかってしまう現象が発生した。IMEで半角変換して入力すればなんとか使える。最新の開発版では問題なかった。

合成する手順:

  1. Inconsolata側:
    1. FontForgeでフォントを開く。
    2. EMサイズを2048にする。「エレメント」→「フォント情報」→「一般情報」→「EMの大きさ」を「2048」にしてOKを押す。すると(「輪郭を拡大/縮小」にチェックが入っていれば)自動的にグリフが拡大縮小される。InconsolataのEMサイズは1000、MeiryoKe_Consoleは2048なので合成する前に合わせなければならない。
    3. ヒント情報・ヒント命令を削除する。「編集」→「選択」→「出力に値するグリフ」, 「ヒント」→「ヒントを削除」, 「ヒント→ヒント命令を削除」。MeiryoKe側に移したときにヒント命令は単純には引き継げないので削除する。
    4. ASCII文字(等MeiryoKe側へコピーしたい文字)のグリフを選択して右クリックし「参照を解除」。iとjがuni0307を参照していたりするのでこれを解除する。しないとコピーしたときにiやjの上の点がメイリオのものになってしまう。
    5. ASCII文字(等MeiryoKe側へコピーしたい文字)のグリフを選択して右クリックし「コピー」する。
  2. MeiryoKe_Console側:
    1. FontForgeでフォントを開く。
    2. フォント情報を書き替える。
      • PS Names
        • フォント名は「MeiryoKe_Inconsolata_スタイル名」等とする。
        • ファミリー名は「MeiryoKe_Inconsolata」とする。
      • 一般情報
        • (斜体なら)イタリックの傾きを傾けた角度にする。
      • OS/2
        • その他/Style MapをRegular, Bold, Italic, Bold Italicのいずれかに。
        • メトリック/WinDescentを360へ増やす(jの下が切れてしまうので。値はjやyの一番下の座標を見て決める)。
        • (斜体なら)Panose/文字の形状を「斜体/箱入」に。
        • TTF名のファミリー名、スタイル名、フルネーム等を適切に変更。
    3. ASCII文字(等Inconsolataから持ってきたい範囲)のグリフをカットして削除する。
    4. Inconsolata側でコピーしたグリフを貼り付ける(または、「エレメント」→「フォントの統合」で持ってきた方がトラブルが少ないかもしれない。少なくともアンカー情報はコピーだと引き継がれない模様。どちらを使うにせよすでにあるグリフには上書きされないので統合・コピーする前に取りこみたい箇所を消しておくこと)。
    5. フォントを出力する。「ファイル」→「フォントを出力」。 オプションはほとんどデフォルトだが、一応私が出力したときのを書いておく:
      • ヒント
        • Flexヒント
      • TrueType ヒント
      • PostScriptグリフ名
      • TrueType
      • オプション
        • OpenTypeの仕様
        • 旧来のkernテーブル(不要かも?)
        • Windows Compatible kern(不要かも?)
        • Prefer native kerning(不要かも?)
  3. 出力したフォントの平均文字幅情報を書き替える。平均文字幅(xAveCharWidth)はFontForgeが勝手に計算してしまうので設定で変更できない。半角文字の幅である1024にしたいのでバイナリエディタで書き替える。
    1. バイナリエディタで開いて先頭付近のOS/2という文字列を見つける。
    2. OS/2の後の4バイトはチェックサムなので無視し、次の4バイトが示すオフセットを読み取り(ビックエンディアン)、ファイル先頭からそのオフセットの場所に飛ぶ。
    3. 最初の2バイトはバージョン番号なので無視し、次の2バイトを1024(04 00)に書き替える。

メモ:

  • ○や■の記号などInconsolataから持ってきたくないものもあるのでASCIIのグリフだけInconsolataからMeiryoKe_Consolasにコピーした。
  • 変形は極力しない方が良い(特にMeiryoKe側は)。ヒント情報がどうなるか分からないので。
  • Inconsolataのiやjは他のグリフを参照しているので、「参照を解除」してから移すこと。でないとiやjの上ポチがずれた位置に出てしまう。参照先であるuni0307もコピーする手もあるかもしれない。
  • WinDescentを少し増やさないとjの下が切れてしまう。座標を見て 360 400にした。一般情報の「深さ」は変えなくて大丈夫。
  • 「エレメント」→「フォント情報」→「OS/2」→「Panose」→「幅の比率」が「等幅」だと全角文字の後に空白が空いてしまう。FontForgeのバグだそう(FontForgeで生成した日本語TrueTypeフォント文字幅広すぎ対策 - itouhiroはてなブログ)なので「等幅」のまま出力してxAvgCharWidthを別途書き替える。「任意」にすると一見問題が解決するように見えるが、フォントサイズが奇数のときに全角の幅が半角のぴったり二倍にならなくなる。例えば全角の幅が19pxにときに半角の幅が10pxになってしまう。「等幅」で出力して後でxAvgCharWidthを書き替えるとこの問題は起きない(フォントサイズ19pxのとき全角の幅が20pxになる)。
  • Emacsで使うとフレームの横幅が異様に大きくなってしまうことがある。(default-font-width)が大きな値を返してくる。これもxAvgCharWidthの問題。OS/2テーブルのxAvgCharWidthを書き替える必要がある。FontForgeは勝手に計算して出力するので設定で変更できない。
  • xAvgCharWidthの書き替え方:

    1. TTFファイルの中でOS/2テーブルの位置は、ファイル先頭付近の「OS/2」と書いてある所の直後を見れば分かる。「OS/2」の直後には32ビット整数(ビックエンディアン)でチェックサム、オフセット、サイズと続く。手元のファイルでは、オフセットは1D8hや1C8h等であった。このオフセットはファイル先頭からOS/2テーブル先頭までのバイト数。
    2. OS/2テーブル先頭からバージョン(uint16)、xAvgCharWidth(int16)と続く。手元のファイルでは xAveCharWidthは1959(7a7h)だった。これを1024(400h)に書き替える。

    (参考: OpenTypeフォント: vanillaの日記, OpenTypeフォントの続き(5)・・・OS/2テーブル: vanillaの日記, OS/2 - OS/2 and Windows metrics table (OpenType 1.8.4) - Typography | Microsoft Docs)

  • ヒント命令はコピーでもフォントの統合でも引き継げないのでInconsolataの分は諦める。大人しく消してしまった方が良い。各グリフのヒント命令(glyfテーブル)はフォント全体(fpgmテーブル)で定義している関数を呼び出したりしているので単純にグリフをコピーしても正しく動作しない。頑張って解析すれば統合できるかもしれないが大変。FDEF命令で定義する関数の番号をずらせれば統合できるかもしれない。CALLの前が必ずしも番号のPUSHとは限らないみたいなので慎重に追っていく必要がありそう。関連する他のテーブルにも注意を払う必要がありそう。(参考: OpenTypeフォントの続き(9)・・・インストラクション: vanillaの日記, TrueType Instruction Set (OpenType 1.8.4) - Typography | Microsoft Docs)
  • ハイフンマイナス(U+002D)がなぜか太く表示されてしまうようなので 縦110%拡大したら小さなフォントサイズでチルダの波形が波に見えない場合があったので、そのグリフだけはヒント情報とヒント命令を生成した。他の文字はヒント情報をFontForgeで自動生成すると文字の形や幅がおかしくなることがあった。
  • ベースラインが揃っていないのが気になる。元々メイリオ自体漢字や仮名は少しベースラインより下にはみ出してる。調整したいがメイリオ側を変形するのはヒンティングが大丈夫が不安。Inconsolataをベースラインより下げてしまうのも手かも?
  • なぜかInconsolata部分の高さが微妙に低い(ヒントがないせい?)ので縦方向に少し(110%ほど)拡大した。
2021-07-17 ,

指定した任意のorgファイルへエントリー(サブツリー)を移動する方法

org-refile (C-c C-w) でorg-modeのエントリー(サブツリー)を他の場所へ移動できるのだけど、デフォルトだとカレントバッファ内の第1レベルのエントリ内へしか移動できない。

移動先の候補は org-refile-targets 変数で変更できるのだけど、その場で好きなファイルを指定してその中へ移動というのは出来ないように見える。これまで org-refile-targets には (org-agenda-files :maxlevel . 2) を指定していたのでアジェンダ処理対象ファイルへは移動できるのだけど、特定のプロジェクト専用のorgファイル(あちこちのディレクトリにある)へ移動したい場合には困る。

やりたいことはシンプルに、C-c C-wの後にファイルを指定して、次に移動先のエントリーを指定したいだけなのだけど。

変数 org-refile-use-outline-path や org-outline-path-complete-in-steps を使うと最初にファイルを指定できるようにもなるけれど、やっぱり org-refile-targets の制限を受けてしまう。

これまではエントリーをカット&ペーストしていたのだけど、やはり C-c C-w で出来た方が便利だ。ちなみにペーストは任意のエントリーの子としてペーストする機能が見当たらずペーストしてからレベルを調整する必要があって手間がかかる。C-c C-x C-y (org-paste-special) は現在の場所と同一レベルにペーストするので M-right で一段下げなければならない。

どうにもならないのかと諦めかけたところ、次の記事を見た。

目にとまったのはこの部分。

org-refile-targets lets you control which files to consider, e.g.:

nil  ;; only the current file
'((org-agenda-files :maxlevel . 2)) ;; all agenda files, 1st/2nd level
'((org-files-list :maxlevel . 4)) ;; all agenda and all open files
'((my-org-files-list :maxlevel . 4)) ;; all files returned by `my-org-files-list'

org-refile-targets には任意の関数を指定できるのであった。その関数は移動候補となるファイル名のリストを返すことになっている。

(org-files-list) 関数はアジェンダファイルと現在開いているorgファイルを返すので、それを指定すればアジェンダファイルの他に現在開いているorgファイルへも移動できるようになる。

完全に任意のファイルとはいかないが、先にファイルを開いておけばいいだけなので当分これで我慢しておこうと思う。