|
| 1 | +--- |
| 2 | +title: Instruction Search |
| 3 | +permalink: search/index.html |
| 4 | +--- |
| 5 | +<h1>Instruction Search</h1> |
| 6 | + |
| 7 | +<p>Search by mnemonic or long name. Hit Enter on an exact mnemonic match to jump straight to the instruction details.</p> |
| 8 | + |
| 9 | +<input id="search" placeholder="Search mnemonic, e.g. addi" style="padding:8px; width: 100%; max-width: 480px;" /> |
| 10 | + |
| 11 | +{# Creates box divide between checkboxes and rest of page #} |
| 12 | +<fieldset id="extension-filters-fieldset" class="filters"> |
| 13 | + <legend>Filter by extension</legend> |
| 14 | + <div id="extension-filters" class="filter-options"></div> |
| 15 | +</fieldset> |
| 16 | + |
| 17 | +<ul id="instruction_list"> |
| 18 | +{% for inst in instructions %} |
| 19 | + <li |
| 20 | + data-search="{{ (inst.name ~ ' ' ~ inst.longName) | lower }}" |
| 21 | + data-mnemonic="{{ inst.name | lower }}" |
| 22 | + data-extension="{{ inst.extension }}" |
| 23 | + data-extension-slug="{{ inst.extensionSlug }}" |
| 24 | + > |
| 25 | + <a href="/instructions/{{ inst.name }}/">{{ inst.name }}</a> |
| 26 | + <span class="ext-name" data-extension-slug="{{ inst.extensionSlug }}" title="Extension"> |
| 27 | + - {{ inst.extension }} |
| 28 | + </span> |
| 29 | + </li> |
| 30 | +{% endfor %} |
| 31 | +</ul> |
| 32 | + |
| 33 | +<script> |
| 34 | +const input = document.getElementById('search'); |
| 35 | +const instruction_list = document.getElementById('instruction_list'); |
| 36 | +const filtersFieldset = document.getElementById('extension-filters-fieldset'); |
| 37 | +{# the blank area where we’ll insert checkboxes #} |
| 38 | +const filtersContainer = document.getElementById('extension-filters'); |
| 39 | +const items = Array.from(instruction_list.querySelectorAll('li')); |
| 40 | +const activeExtensions = new Set(); |
| 41 | +
|
| 42 | +// Gather unique extension names from the rendered instruction <li> items. |
| 43 | +const extensionSet = new Set(); |
| 44 | +for (const li of items) { |
| 45 | + const extension = li.dataset.extension; |
| 46 | + extensionSet.add(extension); |
| 47 | + } |
| 48 | +
|
| 49 | +const extensions = Array.from(extensionSet).sort(); |
| 50 | + for (const extension of extensions) { |
| 51 | + const id = `ext-${extension}`; |
| 52 | + const label = document.createElement('label'); |
| 53 | + label.className = 'filter-option'; |
| 54 | +
|
| 55 | + const checkbox = document.createElement('input'); |
| 56 | + checkbox.type = 'checkbox'; |
| 57 | + checkbox.value = extension; |
| 58 | + checkbox.id = id; |
| 59 | + checkbox.addEventListener('change', () => { |
| 60 | + if (checkbox.checked) { |
| 61 | + activeExtensions.add(extension); |
| 62 | + } else { |
| 63 | + activeExtensions.delete(extension); |
| 64 | + } |
| 65 | + applyFilters(); |
| 66 | + }); |
| 67 | +
|
| 68 | + const text = document.createElement('span'); |
| 69 | + text.textContent = extension; |
| 70 | +
|
| 71 | + label.appendChild(checkbox); |
| 72 | + label.appendChild(text); |
| 73 | + filtersContainer.appendChild(label); |
| 74 | + } |
| 75 | +
|
| 76 | +
|
| 77 | +function applyFilters() { |
| 78 | + const q = input.value.trim().toLowerCase(); |
| 79 | + const filtersActive = activeExtensions.size > 0; |
| 80 | + for (const li of items) { |
| 81 | +
|
| 82 | + {# Check if the item matches the text search |
| 83 | + - If the search box is empty, match everything |
| 84 | + - Otherwise, match if the search string includes the query #} |
| 85 | + const matchesQuery = !q || (li.dataset.search || '').includes(q); |
| 86 | +
|
| 87 | + {# Check if the item matches an active extension filter |
| 88 | + - If no filters are active, match everything |
| 89 | + - Otherwise, show only if its extension is selected #} |
| 90 | + const matchesExtension = !filtersActive || activeExtensions.has(li.dataset.extension); |
| 91 | +
|
| 92 | + {# Show or hide this <li> depending on whether both match conditions are true #} |
| 93 | + li.style.display = (matchesQuery && matchesExtension) ? '' : 'none'; |
| 94 | + } |
| 95 | +} |
| 96 | +
|
| 97 | +input.addEventListener('input', applyFilters); |
| 98 | +
|
| 99 | +input.addEventListener('keydown', (e) => { |
| 100 | + {# Only act if Enter is pressed #} |
| 101 | + if (e.key !== 'Enter') return; |
| 102 | +
|
| 103 | + const q = input.value.trim().toLowerCase(); |
| 104 | +
|
| 105 | + {# Do nothing if the box is empty #} |
| 106 | + if (!q) return; |
| 107 | +
|
| 108 | + const filtersActive = activeExtensions.size > 0; |
| 109 | +
|
| 110 | + {# Look for an exact mnemonic match among all instructions |
| 111 | + - If filters are active, also ensure it belongs to one of the selected extensions #} |
| 112 | + const exact = items.find(li => { |
| 113 | + if (li.dataset.mnemonic !== q) return false; |
| 114 | + if (!filtersActive) return true; |
| 115 | + return activeExtensions.has(li.dataset.extension); |
| 116 | + }); |
| 117 | +
|
| 118 | + {# If an exact match is found, redirect to that instruction's detail page #} |
| 119 | + if (exact) { |
| 120 | + const link = exact.querySelector('a').getAttribute('href'); |
| 121 | + location.href = link; |
| 122 | + } |
| 123 | +}); |
| 124 | +
|
| 125 | +applyFilters(); |
| 126 | +</script> |
| 127 | +
|
| 128 | +<style> |
| 129 | +body { font-family: system-ui, sans-serif; line-height: 1.5; margin: 2rem auto; max-width: 900px; padding: 0 1rem; } |
| 130 | +ul { instruction_list-style: none; padding: 0; } |
| 131 | +li { margin: 6px 0; } |
| 132 | +a { text-decoration: none; color: #0366d6; } |
| 133 | +a:hover { text-decoration: underline; } |
| 134 | +#extension-filters-fieldset { margin: 1rem 0; padding: 0.75rem 1rem; border: 1px solid #d0d7de; border-radius: 6px; } |
| 135 | +#extension-filters-fieldset legend { font-weight: 600; font-size: 0.95rem; padding: 0 6px; } |
| 136 | +.filter-options { display: flex; flex-wrap: wrap; gap: 0.5rem 1rem; margin-top: 0.5rem; align-items: center; } |
| 137 | +.filter-option { display: inline-flex; align-items: center; gap: 0.4rem; font-size: 0.95rem; white-space: nowrap; } |
| 138 | +.filter-option input { width: 16px; height: 16px; } |
| 139 | +</style> |
0 commit comments