電子冒険:エピソード38:コマンドパレット強調表示


前のエピソードでは、ファイルマネージャに非常に簡単なコマンドパレットを追加しました.これと次のいくつかのエピソード以上で我々はそれに改善されます.最初の機能を追加する-強調表示マッチします.

なぜ我々はハイライトを必要とする
それは審美的な問題のように種を蒔くかもしれませんがgo , マッチは以下の通りです:
  • ファーストファイル
  • 最後のファイルへ
  • 次のファイルに移動します
  • 前のファイルに移動
  • ページダウン
  • それがなぜ最後のものがそこにあるかについて非常に邪魔になるかもしれません.特に何らかの理由で予期しないマッチが予想マッチを優先します.このような混乱はユーザーをフロー状態から中断させることができます.
    src/CommandPalette.svelte CommandPalette コマンドのフィルタリングの責任を停止しますmatcher.js
      import matcher from "./matcher.js"
      $: matchingCommands = matcher(commands, pattern)
    
    src/matcher.jsこれはかなり簡単な実装ですRegExp 策略
  • まず、すべての小文字にパターンを回し、文字や数字でないものをすべて取り除きます
  • パターン内のすべての文字は、正規表現には、例えばx なる/(.*?)(x)(.*)/i - これは、最初の括弧は“X”の残りのすべてに一致し、2番目の“X”(大文字小文字を区別しない)、3番目のすべての“X”の右に一致します-複数の“X”の場合は、我々は最初の1つに一致します.それは質問のマークは、できるだけ早く、デフォルトの正規表現では、できるだけ早く行くことを停止するためです.
  • それから、私たちはすべてのコマンドcheckMatch - それが一致する場合、我々はマッチと一緒に結果に追加し、それ以外の場合我々は結果に追加しないでください
  • function matcher(commands, pattern) {
      let rxs = pattern
        .toLowerCase()
        .replace(/[^a-z0-9]/, "")
        .split("")
        .map(l => new RegExp(`(.*?)(${l})(.*)`, "i"))
      let result = []
      for (let command of commands) {
        let match = checkMatch(rxs, command.name)
        if (match) {
          result.push({...command, match: match})
        }
      }
      return result
    }
    
    export default matcher
    
    インcheckMatch , 私たちは一度に名前を一つの手紙に切ります.例えば"Go "に対して"page down "とマッチした場合、最初の反復は次のようになります.
  • "Page Down" なる["Pa", "g", "e Down"]
  • ["Pa", false] が結果に追加されるので、強調表示されません
  • ["g", true] が結果に追加されるので、強調表示されます
  • のみ"e Down" 次の繰り返しに行きます
  • 次に、2番目の反復処理を行います.
  • "e Down" なる["e D", "o", "wn"]
  • ["e D", false] が結果に追加されるので、強調表示されません
  • ["o", true] が結果に追加されるので、強調表示されます
  • のみ"wn" ループの後に残り、左のものは何も残っていません["wn", false]
  • 以下はコードです.
    function checkMatch(rxs, name) {
      if (!name) {
        return
      }
      let result = []
      for (let rx of rxs) {
        let m = rx.exec(name)
        if (m) {
          result.push([m[1], false])
          result.push([m[2], true])
          name = m[3]
        } else {
          return null
        }
      }
      result.push([name, false])
      return result
    }
    
    これはRubyやPerlのようなより強力な正規表現を持つ言語ではもう少しコンシェデになるでしょう.
    src/CommandPaletteEntry.svelteそして最後に、強調表示された結果を表示するためのサポートを追加する必要がありますCommandPaletteEntry .
    <script>
      import { getContext } from "svelte"
      let { eventBus } = getContext("app")
    
      export let name
      export let match = undefined
      export let key
      export let action
    
      function handleClick() {
        eventBus.emit("app", "closePalette")
        eventBus.emit(...action)
      }
      function keyName(key) {
        if (key === " ") {
          return "Space"
        } else {
          return key
        }
      }
    </script>
    
    <li on:click={handleClick}>
      <span class="name">
        {#if match}
          {#each match as [part, highlight]}
            {#if highlight}
              <em>{part}</em>
            {:else}
              {part}
            {/if}
          {/each}
        {:else}
          {name}
        {/if}
      </span>
      {#if key}
        <span class="key">{keyName(key)}</span>
      {/if}
    </li>
    
    <style>
      li {
        display: flex;
        padding: 0px 8px;
      }
      li:first-child {
        background-color: #66b;
      }
      .name {
        flex: 1;
      }
      .key {
        display: inline-block;
        background-color: hsl(180,100%,30%);
        padding: 2px;
        border: 1px solid  hsl(180,100%,20%);
        border-radius: 20%;
      }
      .name em {
        color: #ff2;
        font-weight: bold;
        font-style: normal;
      }
    </style>
    
    つの余分なオプションのプロパティがありますmatch . そこにあるならば、我々はそれを配列のように扱う[part, highlight] . 強調表示された部品は<em> 次に、選択されたファイルと同じスタイルで強調表示されるように下にフォーマットされます.
    このハイライトは、私が期待していたほど目に見えないので、いくつかの時点でスタイリングを調整する必要があります.

    結果
    結果を以下に示します.

    これは良い小さな機能だった.次のエピソードでは、コントロール、コマンド、シフトなどの修飾キーに対処する方法を我々のアプリを教えてくれますので、キーボードショートカットを1つ以上のキーをすることができます.
    いつものように.all the code for the episode is here .