Skip to content

Commit bc4493d

Browse files
committed
vimhelp: Add offline tag search ability using tags.json
Add back the search box when using static page generation. This works by querying tags.json and then performing a local search instead of relying on the server code in tagsearch.py. The matching logic is ported over to be the same though. Because we only have ~10k tags, linear search is fast enough that we don't need to implement a binary search (since JS doesn't come with a native binary search algorithm). Otherwise, for performance, a indexed array using the initial character of the tag may work better than implementing a binary search.
1 parent 24abbb0 commit bc4493d

File tree

2 files changed

+82
-5
lines changed

2 files changed

+82
-5
lines changed

vimhelp/static/vimhelp-v5.js

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
// "Go to keyword" entry
44

5-
/*
65
new TomSelect("#vh-select-tag", {
76
maxItems: 1,
87
loadThrottle: 250,
@@ -15,17 +14,97 @@ new TomSelect("#vh-select-tag", {
1514
},
1615
shouldLoad: (query) => query.length >= 1,
1716
load: async (query, callback) => {
17+
/*
18+
* Online dynamic server route. Not used.
19+
*
1820
const url = "/api/tagsearch?q=" + encodeURIComponent(query);
1921
const resp = await fetch(url);
2022
callback((await resp.json()).results);
23+
*/
24+
25+
// Offline mode
26+
if (!window.vimtags) {
27+
// Only download this file on demand as it's not tiny.
28+
const tags_url = "tags.json";
29+
const tags_resp = await fetch(tags_url);
30+
window.vimtags = await tags_resp.json();
31+
window.sortedVimtags = Object.keys(window.vimtags).sort();
32+
}
33+
// Use logic from tagsearch.py
34+
const MAX_RESULT = 30;
35+
36+
let results = [];
37+
let results_set = {};
38+
function addResult(tag) {
39+
if (tag in results_set)
40+
return false;
41+
const link = window.vimtags[tag];
42+
results.push({href: link, id: tag, text: tag});
43+
results_set[tag] = null;
44+
return results.length >= MAX_RESULT;
45+
}
46+
47+
// Find all tags beginning with query.
48+
for (let found = false, i = 0; i < sortedVimtags.length; i++) {
49+
let tag = sortedVimtags[i];
50+
if (tag.startsWith(query)) {
51+
found = true;
52+
if (addResult(tag)) {
53+
callback(results);
54+
return;
55+
}
56+
}
57+
else if (found) {
58+
break;
59+
}
60+
}
61+
// If we didn't find enough, and the query is all-lowercase, add all
62+
// case-insensitive matches.
63+
const queryLower = query.toLowerCase();
64+
if (queryLower == query) {
65+
for (let i = 0; i < sortedVimtags.length; i++) {
66+
let tag = sortedVimtags[i];
67+
if (tag.toLowerCase().startsWith(queryLower)) {
68+
if (addResult(tag)) {
69+
callback(results);
70+
return;
71+
}
72+
}
73+
}
74+
}
75+
// If we still didn't find enough, additionally find all tags that contain query as a
76+
// substring.
77+
for (let i = 0; i < sortedVimtags.length; i++) {
78+
let tag = sortedVimtags[i];
79+
if (tag.includes(query)) {
80+
if (addResult(tag)) {
81+
callback(results);
82+
return;
83+
}
84+
}
85+
}
86+
87+
// If we still didn't find enough, and the query is all-lowercase, additionally find
88+
// all tags that contain query as a substring case-insensitively.
89+
if (queryLower == query) {
90+
for (let i = 0; i < sortedVimtags.length; i++) {
91+
let tag = sortedVimtags[i];
92+
if (tag.toLowerCase().includes(queryLower)) {
93+
if (addResult(tag)) {
94+
callback(results);
95+
return;
96+
}
97+
}
98+
}
99+
}
100+
callback(results);
21101
},
22102
onChange: (value) => {
23103
if (value) {
24104
window.location = value;
25105
}
26106
}
27107
});
28-
*/
29108

30109
// Theme switcher
31110

vimhelp/templates/page.html

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,10 @@
1919
<!-- {{project.favicon_notice}} -->
2020

2121
{% if mode != "offline" %}
22-
{% if project.name != 'MacVim' %}
2322
{# MacVim does not host this on a server and cannot do dynamic queries #}
2423
<link rel="stylesheet" href="{{static_dir}}tom-select-2.2.2.min.css">
2524
<script defer src="{{static_dir}}tom-select-2.2.2.base.min.js"></script>
2625
{% endif %}
27-
{% endif %}
2826

2927
<link rel="stylesheet" href="{{static_dir}}vimhelp-v5.css" type="text/css">
3028
<noscript><link rel="stylesheet" href="{{static_dir}}noscript.css" type="text/css"></noscript>
@@ -92,10 +90,10 @@ <h1>{{project.name}} help files</h1>
9290
{% if mode != "offline" %}
9391
<div class="bar">
9492
<div class="ql">{{sitenavi}}</div>
95-
{% if project.name != "MacVim" %}
9693
<div class="srch" id="go-to-tag">
9794
<select id="vh-select-tag"></select>
9895
</div>
96+
{% if project.name != "MacVim" %}
9997
<form class="srch" action="https://duckduckgo.com" method="get" target="_blank" rel="noopener noreferrer">
10098
<input type="hidden" name="sites" value="{{project.vimdoc_site}}">
10199
<input type="search" name="q" id="vh-srch-input" placeholder="Site search">

0 commit comments

Comments
 (0)