Panda Noir

JavaScript の限界を究めるブログでした。最近はいろんな分野を幅広めに書いてます。

善は急げ 悪は延べよ

「善は急げ」はよく知られています。しかし、実は続きがあるそうです。それが「悪は延べよ」です。

悪は延べよの意味は、「悪いと思う事は、一事延期せよ、そうすれば事情がやがて変化して、行なわないで済むようになることもある。」とのことです。

プログラミングでもメチャクチャ出てくる概念ですよね。いわゆる「早すぎる最適化」はまさに悪を延べていればなぁという後悔の話ですし。

決定はなるべく遅延させるべきだし、課題は一旦引いて考えてみると良い案が出てくる、仕事を終えてシャワーを浴びてる時にふと妙案が出てくる。これらもそうですよね。…いや後半のは悪は延べよとはちょっと違うかもですが。

ともかく、事を急いてしまって後々の負債になってしまうくらいなら慌てずに対応しよう。そもそも実装を遅らせて対応できるかもしれない。そういう話でした

pubsub パターンの現時点でのベストプラクティス

以前pubsub パターンのベタープラクティスを考えたんですが、よく考えたらイベント名を設定する必要なかったです。

これでよさそう↓

class PubSub<Payload extends unknown[]> {
  private listeners: ((...payload: Payload) => void)[] = [];
  subscribe(callback: (...payload: Payload) => void) {
    this.listeners.push(callback);
  }
  unsubscribe(callback: (...payload: Payload) => void) {
    this.listeners = this.listeners.filter((item) => item !== callback);
  }
  publish(...payload: Payload) {
    for (const listener of this.listeners) {
      listener(...payload);
    }
  }
}

export const buttonPubsub = new PubSub<[]>();
export const messagePubsub = new PubSub<[string]>();

イベント名を指定したかったらオーバーロードを使えば実装可能

const subscribe: {
  (eventName: 'click', callback: () => void): void;
  (eventName: 'message', callback: (message: string) => void): void;
} = (eventName: string, callback: (...event: any[]) => void) => {
  switch (eventName) {
    case 'click':
      buttonPubsub.subscribe(callback);
      break;
    case 'message':
      messagePubsub.subscribe(callback);
      break;
  }
};
subscribe('message', (mes: string) => console.log(mes)); // OK
subscribe('click', (mes: string) => console.log(mes)); // 型エラー

vue の SFC 内でうまくコメントアウトプラグインを動かしたい vim + mini.comment 編

(vim + mini.comment 編と書いたが、別に他パターンを書く予定はない)

割と手間取ったのでメモとして残しておきます。他の人の参考にもなりそうなので

結構無理やりな方法を取ったので、もっとスマートなやり方がありそうですが…

ポイント: hooks.pre で filetype を切り替える + vue の commentstring を設定する

こんな感じの基本方針のもと実装しました。

  1. コメントアウト処理の直前に filetype をカーソル行のものに変更
  2. コメントアウト処理が走る
  3. 処理が終わったらもとに戻す

以下がコードです (パッケージマネージャーは packer.nvim)

  use 'Shougo/context_filetype.vim'
  use {
    'echasnovski/mini.comment',
    config = function()
      require 'mini.comment'.setup {
        hooks = {
          pre = function()
            -- context_filetype プラグインを使って、カーソル行の filetype を取得している。
            vim.cmd('noa setfiletype ' .. vim.fn['context_filetype#get_filetypes']()[1])
          end,
          post = function()
            -- コメントアウト処理が終わったので元に戻す
            vim.cmd 'filetype detect'
          end
        }
      }
    end
  }

ポイントは noa setfiletype です。noa なしで setfiletype としてしまうと、LSP が起動してしまいます。LSP が動くと余計なシンタックスエラーが表示されてウザったいので noa をつけて不要な autocmd が動かないようにしてます。

ただ、これでは不十分です。実は mini.comment はそのままだと vue テンプレートのコメントアウトができません(多分。あまりよく調べてない)。そこで、自力で commentstring を設定する必要があります

  vim.api.nvim_create_autocmd({ 'BufRead', 'BufNewFile' }, {
    pattern = '*.vue',
    command = 'setlocal commentstring=<!--%s-->'
  })

これでコメントアウトできるようになります

はてなブログで tsx コードをシンタックスハイライトする方法

追記: 公式が対応しました!

staff.hatenablog.com

tsx 対応がついに入りました。そのため以下のコードは不要になりました。

実際にシンタックスハイライトされてるところ

const Component = () => {
  const [count, setCount] = useState(0);
  return (
    <button onClick={() => setCount(n => n+1)}>{count} times clicked!</button>
  );
};

↑ こんな感じで、tsx がハイライトされます!!!!

やり方: 以下のコードを貼り付ける

デザイン設定 → ヘッダー → ブログタイトル下 に以下のコードを貼り付ければ OK です

↓貼り付ける位置

↓貼り付けるコード

<style type="text/css">
.entry-content pre,.entry-content code{
    font-family: "Source Code Pro", sans-serif;
    line-height: 1.2;
  }
.entry-content pre:not(.code){
    background: transparent;
}
</style>

<!-- 以下は tsx のシンタックスハイライト用のコード -->
<code class="language-tsx" style="display: none"></code>
<script src="https://unpkg.com/prismjs@1.29.0/components/prism-core.min.js"></script>
<script src="https://unpkg.com/prismjs@1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
<script>
  let count = 0;
  const run = () => {
    if (!(Prism && Prism.languages && 'tsx' in Prism.languages)) {
      ++count;
      if (count < 1e5) {
        setTimeout(run, 5);
      }
      return
    }
    for (const $el of document.querySelectorAll('pre.code.tsx'))
      $el.innerHTML = Prism.highlight($el.innerText, Prism.languages.tsx, 'tsx')
  }
  run();
</script>
<link href="https://unpkg.com/prismjs@1.29.0/themes/prism-tomorrow.css" rel="stylesheet" />
<style>.token.keyword{ color: #cc99cd!important; }</style>

あとは下みたいに↓普通に tsx コードブロックを書けばシンタックスハイライトされます。

これで OK ↓

```tsx
render(<App />)
```

つまり、 Markdown 側に変な小細工をする必要が一切ありません。 zenn など他のサービスで書いた記事を転載しても tsx がハイライトされてくれます。うれしいですね…!!!

解説

上のコードが何をしてるかというと、

  1. prism というシンタックスハイライトのライブラリを読み込む
  2. prism が <code class="language-tsx" style="display: none"></code> をハイライトしようとする
  3. prism が tsx をシンタックスハイライトするために必要なものを動的にダウンロードし始める
  4. ダウンロードが完了するまで待つ (setTimeout(run, 5); あたりのコード)
  5. tsx をシンタックスハイライトする準備ができたら Prism.highlight を使って tsx のコードブロックをハイライトする

という感じです。難しいことはしてません。

テーマを変えたい場合

prism はいくつかテーマを提供しています。

https://unpkg.com/browse/prismjs@1.29.0/themes/

ここから選んで <link href="https://unpkg.com/prismjs@1.29.0/themes/prism-tomorrow.css" rel="stylesheet" /> の部分を差し替えてください。また、<style>.token.keyword{ color: #cc99cd!important; }</style> の部分もテーマに合わせて変えてください。

終わりに

こんなハックをユーザーに強いないで、早く tsx シンタックスハイライトに対応してください はてなさん!!!!!!

MGS (マジで業務で使うシェルスクリプト)

MGS(マジ業務使いのシェルスクリプト)がまあまああるのでまとめる。いま思いついたものだけ書いてるが、思い出したら追記するかも。

説明 コマンド
スペース埋め出力から特定列を抜き出す | awk '{print $1}'
先頭から特定の文字までのみ表示 | cut -f 1 -d :
先頭の x 文字だけ抜き出す | awk '{print substr($0, 0, 30)}'
x文字ごとに改行する | fold -40
特定文字を改行に変える | tr ':' '\n'

以下各コマンドの使用例とコマンド

スペース埋め出力から特定列を抜き出す | awk '{ print $3 }

5       6       npmrc
14      8       tmux.conf
7       2       zsh/alias.zsh

↑こんな感じになってるとき、3列目だけ抜き出すには | awk '{ print $3 } でいけます

git diff --numstat | awk '{print $3}'

先頭から特定の文字までのみ表示 | cut -f 1 -d :

article を含むラインから article_id を含むラインを除いて、ファイル一覧に変換する

rg article | rg -v 'article_id' | cut -f 1 -d : | sort | uniq

先頭の x 文字だけ抜き出す | awk '{print substr($0, 0, 30)}'

minify されたファイルのように1行が膨大なものがマッチしたときに先頭30文字だけ見るときとかに使う(たまにこういうシーンがある)

rg x | awk '{print substr($0, 0, 30)}'

x文字ごとに改行する | fold -40

minify されたファイル同士を diff 取るとき、折り返しておくとうまく diff を取れることがある(取れないこともある)

diff $(cat dist/main.js | fold -40) $(cat dist2/main.js | fold -40)

特定文字を改行に変える | tr ':' '\n'

$PATH が見やすくなる

echo $PATH | tr : \\n