package main import ( "encoding/json" "flag" "fmt" "io" "net/http" "os" "strings" ) const searxEnvVar = "SEARX_ENDPOINT" const defaultWrap = 72 const defaultMaxResults = 10 type Result struct { Title string `json:"title"` Content string `json:"content"` URL string `json:"url"` } type Response struct { Results []Result `json:"results"` } func main() { // Define command-line flags //pagePtr := flag.Int("p", 1, "Search page number") enginesPtr := flag.String("e", "", "Comma-separated list of engines to query") wrapPtr := flag.Int("c", defaultWrap, "Wrap column for description") noDescPtr := flag.Bool("nd", false, "Do not display descriptions") maxResultsPtr := flag.Int("n", defaultMaxResults, "Limit number of displayed results") flag.Usage = func() { fmt.Fprintf(flag.CommandLine.Output(), "Usage: searx [options] query ...\nOptions:\n") flag.PrintDefaults() } flag.Parse() // Validate SEARX_ENDPOINT searxEndpoint := os.Getenv(searxEnvVar) if searxEndpoint == "" { fmt.Printf("Environmental variable %s must be defined:\n\n", searxEnvVar) fmt.Printf(" export %s=https://example.com/search\n\n", searxEnvVar) os.Exit(1) } // Prepare the query query := strings.Join(flag.Args(), " ") if query == "" { fmt.Println("The query is empty\n") flag.Usage() os.Exit(1) } // Build query parameters queryParams := fmt.Sprintf("q=%s&format=json", query) if *enginesPtr != "" { queryParams += "&engines=" + *enginesPtr } url := searxEndpoint + "?" + queryParams fmt.Printf("Querying %s\n", url) // Make HTTP request resp, err := http.Get(url) if err != nil { fmt.Println("Error making request:", err) os.Exit(1) } defer resp.Body.Close() // Read and parse response body, err := io.ReadAll(resp.Body) if err != nil { fmt.Println("Error reading response:", err) os.Exit(1) } fmt.Printf("body: %v\n\n", string(body)) var reply Response if err := json.Unmarshal(body, &reply); err != nil { fmt.Println("Error parsing response:", err) os.Exit(1) } // Display results for i, result := range reply.Results { fmt.Printf("\033[1m%d: %s\033[0m\n", i+1, result.Title) if !*noDescPtr && result.Content != "" { fmt.Println(wordWrap(result.Content, *wrapPtr)) } fmt.Printf("\033[4m%s\033[0m\n\n", result.URL) if i+1 >= *maxResultsPtr { break } } } func wordWrap(text string, limit int) string { if len(text) > limit { words := strings.Fields(text) var result, line string for _, word := range words { if len(line)+len(word)+1 > limit { result += line + "\n" line = "" } line += word + " " } result += line return result } return text }