diff --git a/docs/pylib/build_search_index.py b/docs/pylib/build_search_index.py new file mode 100644 index 0000000000..4c9497cf08 --- /dev/null +++ b/docs/pylib/build_search_index.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Builds a lunr static search index for optimized search + +""" +import os +import json +import glob +from argparse import ArgumentParser +from os.path import sep, abspath, dirname, join as joinpath +from lunr import lunr + +_DOCS_PATH = dirname(dirname(abspath(__file__))) + +_DEFAULT_BUILD_DIR = joinpath(_DOCS_PATH, "build", "html") +_DEFAULT_URL_BASE = f"file://{_DEFAULT_BUILD_DIR}" +_INDEX_PATH = joinpath("_static", "js", "lunr", "search_index.json") + +DEFAULT_SOURCE_DIR = joinpath(_DOCS_PATH, "source") +DEFAULT_OUTFILE = joinpath(DEFAULT_SOURCE_DIR, _INDEX_PATH) + +URL_BASE = os.environ.get("SEARCH_URL_BASE", _DEFAULT_URL_BASE) + + +def create_search_index(sourcedir, outfile): + """ + Create the index. + + Args: + sourcedir (str): Path to the source directory. This will be searched + for both .md and .rst files. + outfile (str): Path to the index file to create. + + """ + markdown_files = glob.glob(f"{sourcedir}{sep}*.md") + markdown_files.extend(glob.glob(f"{sourcedir}{sep}*{sep}*.md")) + rest_files = glob.glob(f"{sourcedir}{sep}*.rst") + rest_files.extend(glob.glob(f"{sourcedir}{sep}*{sep}*.rst")) + filepaths = markdown_files + rest_files + + outlist = [] + + print(f"Building Search index from {len(filepaths)} files ... ", end="") + + for filepath in filepaths: + with open(filepath, 'r') as fil: + filename = filepath.rsplit(sep, 1)[1].split(".", 1)[0] + url = f"{URL_BASE}{sep}{filename}.html".strip() + title = filename.replace("-", " ").strip() + body = fil.read() + + data = { + "url": url, + "title": title, + "text": body, + } + outlist.append(data) + + idx = lunr( + ref="url", + documents=outlist, + fields=[ + { + "field_name": "title", + "boost": 10 + }, + { + "field_name": "text", + "boost": 1 + } + ], + ) + + with open(outfile, "w") as fil: + fil.write(json.dumps(idx.serialize())) + + print(f"wrote to source{sep}{_INDEX_PATH}.") + + +if __name__ == "__main__": + + parser = ArgumentParser(description="Build a static search index.") + + parser.add_argument("-i", dest="sourcedir", default=DEFAULT_SOURCE_DIR, + help="Absolute path to the documentation source dir") + parser.add_argument("-o", dest="outfile", default=DEFAULT_OUTFILE, + help="Absolute path to the index file to output.") + + args = parser.parse_args() + + create_search_index(args.sourcedir, args.outfile) diff --git a/docs/requirements.txt b/docs/requirements.txt index c3748022a7..db3bc09e4c 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -2,8 +2,7 @@ sphinx==2.4.4 sphinx-multiversion==0.1.1 +lunr==0.5.6 # recommonmark custom branch with evennia-specific fixes git+https://github.com/evennia/recommonmark.git@evennia-mods#egg=recommonmark - -# theme diff --git a/docs/source/_static/js/lunr/search.js b/docs/source/_static/js/lunr/search.js new file mode 100644 index 0000000000..124809e12b --- /dev/null +++ b/docs/source/_static/js/lunr/search.js @@ -0,0 +1,95 @@ +// +// Using the pre-generated index file, set up a dynamic +// search mechanims that returns quick suggestions of the +// best matches you start to enter. +// + +var lunrIndex, + $results, + documents; + +function initLunr() { + // retrieve the index file + $.getJSON("_static/js/lunr/search_index.json") + .done(function(index) { + + lunrIndex = lunr.Index.load(index) + + // documents = index; + + // lunrIndex = lunr(function(){ + // this.ref('url') + // this.field('body') + + // this.field("title", { + // boost: 10 + // }); + + // documents.forEach(function(doc) { + // try { + // this.add(doc) + // } catch (e) {} + // }, this) + // }) + }) + .fail(function(jqxhr, textStatus, error) { + var err = textStatus + ", " + error; + console.error("Error getting Lunr index file:", err); + }); +} + +function search(query) { + return lunrIndex.search(query).map(function(result) { + return documents.filter(function(page) { + try { + console.log(page) + return page.href === result.ref; + } catch (e) { + console.log('Error in search. ' + e) + } + })[0]; + }); +} + +function renderResults(results) { + if (!results.length) { + return; + } + + // show first ten results + results.slice(0, 10).forEach(function(result) { + var $result = $("
  • "); + + $result.append($("", { + href: result.url, + text: "ยป " + result.title + })); + + $results.append($result); + }); +} + +function initUI() { + $results = $("#lunrsearchresults"); + + $("#lunrsearch").keyup(function(){ + // empty previous results + $results.empty(); + + // trigger search when at least two chars provided. + var query = $(this).val(); + if (query.length < 2) { + return; + } + + var results = search(query); + + renderResults(results); + }); +} + +initLunr(); + +$(document).ready(function(){ + initUI(); +}); diff --git a/docs/source/_templates/searchbox.html b/docs/source/_templates/searchbox.html new file mode 100644 index 0000000000..5dd5fab1a0 --- /dev/null +++ b/docs/source/_templates/searchbox.html @@ -0,0 +1,31 @@ +{# + basic/searchbox.html + ~~~~~~~~~~~~~~~~~~~~ + + Variant for lunrJS search + +#} +{%- if pagename != "search" and builder != "singlehtml" %} + + +{%- endif %} + +{# + + Lunr indexed quick search + +#} +

    + + + + +