67 lines
1.4 KiB
Go
67 lines
1.4 KiB
Go
package wiki
|
|
|
|
import (
|
|
"net/url"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
// SearchResult represents a single search hit from the wiki.
|
|
type SearchResult struct {
|
|
Title string `json:"title"`
|
|
Snippet string `json:"snippet"`
|
|
PageID int `json:"pageid"`
|
|
Size int `json:"size"`
|
|
}
|
|
|
|
// searchResponse is the raw API response shape for action=query&list=search.
|
|
type searchResponse struct {
|
|
Query struct {
|
|
Search []SearchResult `json:"search"`
|
|
} `json:"query"`
|
|
}
|
|
|
|
// Search performs a full-text search across wiki pages.
|
|
func (c *Client) Search(query string, limit int) ([]SearchResult, error) {
|
|
if limit <= 0 {
|
|
limit = 10
|
|
}
|
|
|
|
params := url.Values{
|
|
"action": {"query"},
|
|
"list": {"search"},
|
|
"srsearch": {query},
|
|
"srlimit": {strconv.Itoa(limit)},
|
|
"srprop": {"snippet|size"},
|
|
}
|
|
|
|
var resp searchResponse
|
|
if err := c.get(params, &resp); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Strip HTML tags from snippets (the API returns <span class="searchmatch">...</span>)
|
|
for i := range resp.Query.Search {
|
|
resp.Query.Search[i].Snippet = stripHTML(resp.Query.Search[i].Snippet)
|
|
}
|
|
|
|
return resp.Query.Search, nil
|
|
}
|
|
|
|
// stripHTML removes HTML tags from a string. Lightweight, no external dep.
|
|
func stripHTML(s string) string {
|
|
var b strings.Builder
|
|
inTag := false
|
|
for _, r := range s {
|
|
switch {
|
|
case r == '<':
|
|
inTag = true
|
|
case r == '>':
|
|
inTag = false
|
|
case !inTag:
|
|
b.WriteRune(r)
|
|
}
|
|
}
|
|
return b.String()
|
|
}
|