diff --git a/scripts/generate.py b/scripts/generate.py index 80b3900..e883e7f 100644 --- a/scripts/generate.py +++ b/scripts/generate.py @@ -530,6 +530,12 @@ def render_results_block(element, acc, headline, graph): if len(content.strip()) > 0: render_block(content, acc, _class='results lang-text', is_code=False) +def render_generic_drawer_block(element, acc, headline, graph): + items = [e.get_raw() for e in element.children] + content = '\n'.join(items) + if len(content.strip()) > 0: + render_block(content, acc, _class='generic-drawer {}-drawer lang-text'.format(element.drawer_name), is_code=False) + def render_org_text(element, acc, headline, graph): as_dom = org_rw.text_to_dom(element.contents, element) render_text_tokens(as_dom, acc, headline, graph) @@ -662,6 +668,7 @@ def render_tag(element, acc, headline, graph): dom.CodeBlock: render_code_block, dom.Text: render_text, dom.ResultsDrawerNode: render_results_block, + dom.GenericDrawerNode: render_generic_drawer_block, org_rw.Text: render_org_text, }[type(element)](element, acc, headline, graph) diff --git a/scripts/search-server.sh b/scripts/search-server.sh index 49f0250..62abda0 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=256 -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..be6ab0d 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) @@ -63,8 +79,23 @@ func main() { c.Writer.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS") query := c.Query("q") + body_type := c.Query("body") + + if ((body_type != "all") && (body_type != "none") && (body_type != "snippet")) { + body_type = "none" + } + + var stm *sql.Stmt + var err error + + if (body_type == "snippet") { + 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(?)") + } else if (body_type == "all") { + stm, err = db.Prepare("SELECT note_id, highlight(note_search, 1, '', ''), top_level_title, is_done, is_todo, highlight(note_search, 2, '', '') FROM note_search(?)") + } else if (body_type == "none") { + stm, err = db.Prepare("SELECT note_id, highlight(note_search, 1, '', ''), top_level_title, is_done, is_todo FROM note_search(?)") + } - stm, err := db.Prepare("SELECT note_id, title, top_level_title, is_done, is_todo FROM note_search(?)") if err != nil { log.Fatal(err) @@ -76,8 +107,13 @@ func main() { } results := make([]map[string]string, 0) + var rows *sql.Rows - rows, err := stm.Query(query) + if (body_type == "snippet") { + rows, err = stm.Query(snippet_size, query) + } else { + rows, err = stm.Query(query) + } if err != nil { log.Fatal(err) c.JSON(500, gin.H{ @@ -94,13 +130,31 @@ func main() { var note_is_done string var note_is_todo string - err = rows.Scan( - ¬e_id, - ¬e_title, - ¬e_top_level_title, - ¬e_is_done, - ¬e_is_todo, - ) + item := make(map[string]string) + + if (body_type != "none") { + var note_highlight string + + err = rows.Scan( + ¬e_id, + ¬e_title, + ¬e_top_level_title, + ¬e_is_done, + ¬e_is_todo, + ¬e_highlight, + ) + if (body_type != "none") { + item["highlight"] = note_highlight + } + } else { + err = rows.Scan( + ¬e_id, + ¬e_title, + ¬e_top_level_title, + ¬e_is_done, + ¬e_is_todo, + ) + } if err != nil { log.Fatal(err) c.JSON(500, gin.H{ @@ -110,7 +164,6 @@ func main() { return } - item := make(map[string]string) item["id"] = note_id item["title"] = note_title item["top_level_title"] = note_top_level_title diff --git a/static/search-box.js b/static/search-box.js index 5e412a5..08b81f0 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); @@ -69,7 +74,7 @@ function _codigoparallevar_enable_search_box(selector, options) { lastVal = val; resultsBox.classList.add('loading'); - const uri = SEARCH_ENDPOINT + '?q=' + encodeURIComponent(val); + const uri = SEARCH_ENDPOINT + '?q=' + encodeURIComponent(val) + '&body=snippet'; let query = fetch(uri); currentQuery = query; query @@ -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..493a929 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 { + background: yellow; +} + +.results-box ul li .search-result-break::before { + content: '…'; + color: #777; +} .results-box li h2.is-todo::before { content: 'TODO'; display: inline-block; @@ -659,10 +676,19 @@ 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; } + .results-box ul li span.match { + background: #886600; + } + /* Code blocks */ .highlight pre { padding: 1ex;