From cd30f9b9c9b01059c359727381283e91b48135d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Mart=C3=ADnez=20Portela?= Date: Sun, 23 Feb 2025 22:50:34 +0100 Subject: [PATCH] Add support for retrieval of snippet matches. --- scripts/search-server.sh | 2 +- scripts/search-server/server.go | 23 +++++++++++++++++++++-- static/search-box.js | 27 +++++++++++++++++++++++++-- static/style.css | 22 ++++++++++++++++++++++ 4 files changed, 69 insertions(+), 5 deletions(-) diff --git a/scripts/search-server.sh b/scripts/search-server.sh index 49f0250..90ff02c 100644 --- a/scripts/search-server.sh +++ b/scripts/search-server.sh @@ -12,4 +12,4 @@ cd ../../_gen/notes/ set -x -exec docker run -it --rm -p $PORT:80 -e PORT=80 -e DB_PATH=/db.sqlite3 -v `pwd`/db.sqlite3:/db.sqlite3:ro search-server +exec docker run -it --rm -p $PORT:80 -e SNIPPET_SIZE=128 -e PORT=80 -e DB_PATH=/db.sqlite3 -v `pwd`/db.sqlite3:/db.sqlite3:ro search-server diff --git a/scripts/search-server/server.go b/scripts/search-server/server.go index 8914956..a2275d4 100644 --- a/scripts/search-server/server.go +++ b/scripts/search-server/server.go @@ -33,6 +33,22 @@ func main() { port = port_num } + snippet_size := 128 + snippet_size_str, ok := os.LookupEnv("SNIPPET_SIZE") + if ok { + snippet_size_num, err := strconv.Atoi(snippet_size_str) + + if err != nil { + log.Fatal(err) + os.Exit(1) + } + if (snippet_size_num < 64) { + log.Fatal("Environment variale $SNIPPET_SIZE must be >= 64.") + os.Exit(1) + } + snippet_size = snippet_size_num + } + db, err := sql.Open("sqlite3", database_path) if err != nil { log.Fatal(err) @@ -64,7 +80,7 @@ func main() { query := c.Query("q") - stm, err := db.Prepare("SELECT note_id, title, top_level_title, is_done, is_todo FROM note_search(?)") + stm, err := db.Prepare("SELECT note_id, highlight(note_search, 1, '', ''), top_level_title, is_done, is_todo, snippet(note_search, 2, '', '', '', ?) FROM note_search(?)") if err != nil { log.Fatal(err) @@ -77,7 +93,7 @@ func main() { results := make([]map[string]string, 0) - rows, err := stm.Query(query) + rows, err := stm.Query(snippet_size, query) if err != nil { log.Fatal(err) c.JSON(500, gin.H{ @@ -93,6 +109,7 @@ func main() { var note_top_level_title string var note_is_done string var note_is_todo string + var note_highlight string err = rows.Scan( ¬e_id, @@ -100,6 +117,7 @@ func main() { ¬e_top_level_title, ¬e_is_done, ¬e_is_todo, + ¬e_highlight, ) if err != nil { log.Fatal(err) @@ -116,6 +134,7 @@ func main() { item["top_level_title"] = note_top_level_title item["is_done"] = note_is_done item["is_todo"] = note_is_todo + item["highlight"] = note_highlight results = append(results, item) } diff --git a/static/search-box.js b/static/search-box.js index 5e412a5..6fa89da 100644 --- a/static/search-box.js +++ b/static/search-box.js @@ -1,4 +1,9 @@ function _codigoparallevar_enable_search_box(selector, options) { + const unescape = (str, tag) => { + const prev = tag.replaceAll('<', '<').replaceAll('>', '>'); + return str.replaceAll(prev, tag); + } + const element = document.querySelector(selector); if ('placeholder' in options) { element.setAttribute('placeholder', options.placeholder); @@ -94,14 +99,32 @@ function _codigoparallevar_enable_search_box(selector, options) { const resultTitle = document.createElement('h2'); resultTitle.innerText = `${note.title} (${note.top_level_title})`; + resultTitle.innerHTML = unescape(unescape( + resultTitle.innerHTML, + ''), '' + ); if (note.is_todo === "1") { - resultTitle.setAttribute('class', 'is-todo'); + resultCard.setAttribute('class', 'is-todo'); } else if (note.is_done === "1") { - resultTitle.setAttribute('class', 'is-done'); + resultCard.setAttribute('class', 'is-done'); } resultContents.appendChild(resultTitle); + + if (note.highlight) { + const resultBody = document.createElement('p'); + resultBody.innerText = note.highlight; + resultBody.innerHTML = unescape( + unescape( + unescape( + resultBody.innerHTML, + ''), + ''), + ''); + resultContents.appendChild(resultBody); + } + resultCard.appendChild(resultContents); resultsList.appendChild(resultCard); } diff --git a/static/style.css b/static/style.css index e362552..cdc453b 100644 --- a/static/style.css +++ b/static/style.css @@ -126,13 +126,30 @@ body nav input { box-shadow: 0px 1px 2px 0px rgba(0, 0, 0, 0.25); } +.results-box ul li a { + text-decoration: none; +} .results-box ul li h2 { font-size: 110%; padding: 1.25ex; display: block; margin: 0; + text-decoration: underline; } +.results-box ul li p { + padding: 1.25ex; + color: black; +} + +.results-box ul li span.match { + text-decoration: underline red; +} + +.results-box ul li .search-result-break::before { + content: '…'; + color: #777; +} .results-box li h2.is-todo::before { content: 'TODO'; display: inline-block; @@ -659,6 +676,11 @@ tr.__table-separator { .results-box ul li h2 { color: white; } + .results-box ul li p { + padding: 1.25ex; + color: white; + } + .results-box-container .results-box input:focus { border-bottom: 1px solid #fff; }