| M | README.md | 8 | ++++++-- |
| M | site/ | 3 | ++- |
| M | site/ | 14 | ++++++++------ |
| M | test/ | 9 | +++++++++ |
@@ -540,7 +540,9 @@ are cut to 240 characters and wiki pages to 2000, to keep the index small.
540540 541541 Every section reads a query the same way (`site/assets/query.ts`): terms542542 split on whitespace, in any order, and a quoted phrase (`"fix the search"`)543-is one term, spaces and all, that must appear as written. Every term must543+is one term, spaces and all, that must appear as written, except that a run544+of whitespace in it counts as one space, as in the indexes, which collapse545+whitespace (`"fix the"` is `"fix the"`). Every term must544546 match, ignoring case, and results mark each match, a phrase as a whole. A545547 quote opens a phrase only at the start of a term (in `it's"` it is just a546548 character), an unclosed quote runs to the end of the query as a phrase, so a@@ -567,7 +569,9 @@ goes to a worker, and a Code section lists each line that has every word,
567569 ignoring case, as `path:line`, linked to that line of the file's page (the568570 source page for markdown). Its words are the terms the other sections read,569571 so a quoted phrase (`"import fs from"`) is one literal string, spaces and570-all; a word inside another goes, since a line with the longer one has it.572+all, a run of whitespace as one space as everywhere (so it won't find code573+aligned with several spaces); a word inside another goes, since a line with574+the longer one has it.571575 Words of 3 characters or more are looked up572576 in the index; shorter ones only filter the lines it finds. It loads nothing573577 until then: the first code query starts the worker, which loads@@ -427,7 +427,8 @@ export function match(q: string): string {
427427 428428 // A query's words, lower case, its terms as query.ts reads them: split on429429 // whitespace, except that a quoted phrase ("like this") is one literal430-// string, spaces and all (an unclosed quote runs to the end).430+// string, spaces and all, a run of them as one (an unclosed quote runs to431+// the end).431432 // A word that is part of another goes, since every line with the longer one432433 // has it, and so do NULs, which an FTS5 string can't hold.433434 export const words = (q: string): string[] => narrow(terms(q.replaceAll('\0', '')));@@ -2,15 +2,17 @@
22 // commits, reviews, wiki pages, file paths and repos, and codesearch.ts for33 // the lines of files. A query is terms split on whitespace, except that a44 // quoted phrase ("like this") is one term, spaces and all, which must appear5-// as written. A quote opens a phrase only at the start of a term (in6-// `it's"` or `a"b` it is just a character), an unclosed one runs to the end7-// of the query, and empty quotes are no term. Every term must match, ignoring8-// case. Nothing here touches the page, so test/search-phrases.ts checks it9-// in Node as the browser runs it.5+// as written, except that a run of whitespace in it is one space, as in the6+// indexes (lib/search.ts flattens bodies and wiki text). A quote opens a7+// phrase only at the start of a term (in `it's"` or `a"b` it is just a8+// character), an unclosed one runs to the end of the query, and empty quotes9+// are no term. Every term must match, ignoring case. Nothing here touches10+// the page, so test/search-phrases.ts checks it in Node as the browser runs11+// it.1012 1113 // A query's terms, lower case, each once.1214 export function terms(q: string): string[] {13- const all = [...q.toLowerCase().matchAll(/"([^"]*)"?|(\S+)/g)].map((m) => m[1] ?? m[2]).filter((t) => t.trim());15+ const all = [...q.toLowerCase().matchAll(/"([^"]*)"?|(\S+)/g)].map((m) => m[2] ?? m[1].replace(/\s+/g, ' ')).filter((t) => t.trim());1416 return [...new Set(all)];1517 }1618 @@ -34,6 +34,11 @@ ok terms '"Fix the Search"'
3434 eq "$(output)" '"Fix the Search" => [fix the search] | code [fix the search]'3535 ok terms '"the search'3636 eq "$(output)" '"the search => [the search] | code [the search]'37+# A run of whitespace in a phrase is one space, as in the indexes; spaces38+# at its ends stay (one each).39+ok terms '"fix the search"' '" fix "'40+eq "$(output)" '"fix the search" => [fix the search] | code [fix the search]41+" fix " => [ fix ] | code [ fix ]'3742 ok terms '""' '" "' '"'3843 eq "$(output)" '"" => - | code -3944 " " => - | code -@@ -58,6 +63,10 @@ ok match "$ix" '"fix the search"'
5863 eq "$(output | grep '^Commits: ' | sed 's/ | .*//')" 'Commits: [Fix the search] box5964 Commits: Tidy the box'6065 has "$T_LOG" '^Commits: Tidy the box \| This is to \[fix the search\] for good\.$'66+# Spaced out, it is the same phrase.67+ok match "$ix" '"fix the search"'68+eq "$(output | grep '^Commits: ' | sed 's/ | .*//')" 'Commits: [Fix the search] box69+Commits: Tidy the box'6170 # Unclosed, it is the same phrase.6271 ok match "$ix" '"FIX THE SEARCH'6372 eq "$(output | grep '^Commits: ' | sed 's/ | .*//')" 'Commits: [Fix the search] box