Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 34 additions & 6 deletions src/commands/search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,29 @@ fn endpoint(path: &str, authenticated: bool) -> String {
}
}

/// Older servers still return `description`; fold it into `snippet` when no
/// snippet exists and drop the field — the CLI never outputs `description`.
fn fold_description_into_snippet(data: &mut Value) {
let Some(results) = data["results"].as_array_mut() else {
return;
};
for result in results {
let Some(obj) = result.as_object_mut() else {
continue;
};
let Some(desc) = obj.remove("description") else {
continue;
};
let has_snippet = obj
.get("snippet")
.and_then(Value::as_str)
.is_some_and(|s| !s.is_empty());
if !has_snippet && desc.as_str().is_some_and(|d| !d.is_empty()) {
obj.insert("snippet".into(), desc);
}
}
}

fn print_yaml(data: &Value) {
match serde_yaml::to_string(data) {
Ok(yaml) => print!("{}", yaml),
Expand Down Expand Up @@ -308,7 +331,8 @@ pub async fn search(
let api_key = key_override(api_key);
let api_key = api_key.as_deref();
match execute(&req, api_key).await {
Ok(data) => {
Ok(mut data) => {
fold_description_into_snippet(&mut data);
if human {
ui::header(&format!("keenable search \"{}\"", query));
if let Some(results) = data["results"].as_array() {
Expand All @@ -320,16 +344,17 @@ pub async fn search(
for (i, result) in results.iter().enumerate() {
let title = result["title"].as_str().unwrap_or("Untitled");
let url = result["url"].as_str().unwrap_or("");
let description = result["description"].as_str().unwrap_or("");
let desc_truncated: String = description.chars().take(200).collect();
let snippet = result["snippet"].as_str().unwrap_or("");
let snippet_flat = snippet.split_whitespace().collect::<Vec<_>>().join(" ");
let snippet_truncated: String = snippet_flat.chars().take(200).collect();
let published = result["published_at"].as_str().unwrap_or("");
let acquired = result["acquired_at"].as_str().unwrap_or("");

let num = format!("{:>2}.", i + 1).dimmed();
eprintln!(" {} {}", num, title.bold());
eprintln!(" {}", url.cyan());
if !desc_truncated.is_empty() {
eprintln!(" {}", desc_truncated.dimmed());
if !snippet_truncated.is_empty() {
eprintln!(" {}", snippet_truncated.dimmed());
}
if !published.is_empty() || !acquired.is_empty() {
let mut dates = Vec::new();
Expand Down Expand Up @@ -365,7 +390,10 @@ pub async fn fetch(url: &str, human: bool, api_key: Option<&str>) {
let api_key = key_override(api_key);
let api_key = api_key.as_deref();
match execute(&req, api_key).await {
Ok(data) => {
Ok(mut data) => {
if let Some(obj) = data.as_object_mut() {
obj.remove("description");
}
if human {
ui::header("keenable fetch");
let title = data["title"].as_str().unwrap_or("Untitled");
Expand Down
1 change: 1 addition & 0 deletions tests/e2e/test_fetch.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ def test_fetch_single_url(kn):
assert data["title"] == "Example Domain"
assert data["url"].startswith("https://example.com")
assert "# Example Domain" in data["content"]
assert "description" not in data


def test_pretty_fetch(kn):
Expand Down
3 changes: 2 additions & 1 deletion tests/e2e/test_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from conftest import SEARCH_QUERY, host_of, host_under, parse_ts, results_of, search_results, utc

# published_at is omitted (not nulled) for pages with no known publish date
RESULT_FIELDS = ("url", "title", "description", "snippet", "acquired_at")
RESULT_FIELDS = ("url", "title", "snippet", "acquired_at")
Comment thread
qodo-code-review[bot] marked this conversation as resolved.


# --- 2.1 core ---
Expand All @@ -20,6 +20,7 @@ def test_basic_search(basic_search):
for r in results:
for field in RESULT_FIELDS:
assert field in r, f"result missing {field}: {list(r)}"
assert "description" not in r


def test_pretty_output(kn):
Expand Down
2 changes: 1 addition & 1 deletion tests/e2e/test_semantic.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@


def blob(result) -> str:
return " ".join(str(result.get(f) or "") for f in ("title", "description", "snippet"))
return " ".join(str(result.get(f) or "") for f in ("title", "snippet"))


def test_gold_fact_mozart(kn):
Expand Down
Loading