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
38 changes: 29 additions & 9 deletions src-tauri/src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,10 @@ pub fn note_preview(html: &str) -> String {
let s = html.trim_start();
let inner = match s.strip_prefix('<') {
Some(rest) => {
let name: String = rest.chars().take_while(|c| c.is_ascii_alphanumeric()).collect();
let name: String = rest
.chars()
.take_while(|c| c.is_ascii_alphanumeric())
.collect();
match (name.is_empty(), s.find('>')) {
(false, Some(gt)) => {
let body = &s[gt + 1..];
Expand Down Expand Up @@ -238,7 +241,9 @@ impl Store {

/// The full HTML content of one note, or `None` if it doesn't exist.
pub fn load_note_content(&self, id: &str) -> rusqlite::Result<Option<String>> {
let mut stmt = self.conn.prepare("SELECT content FROM notes WHERE id = ?1")?;
let mut stmt = self
.conn
.prepare("SELECT content FROM notes WHERE id = ?1")?;
let mut rows = stmt.query_map([id], |r| r.get::<_, String>(0))?;
match rows.next() {
Some(r) => Ok(Some(r?)),
Expand Down Expand Up @@ -272,7 +277,10 @@ impl Store {
continue;
}
let snippet = snippet_around(&plain, &q);
let hit = SearchHit { note: meta, snippet };
let hit = SearchHit {
note: meta,
snippet,
};
if in_title {
title_hits.push(hit);
} else {
Expand Down Expand Up @@ -530,7 +538,10 @@ mod tests {
assert_eq!(note_preview("<p>Hello <b>world</b></p>"), "Hello world");
assert_eq!(note_preview(""), "");
assert_eq!(note_preview("<p></p>"), "");
assert_eq!(note_preview(&format!("<p>{}</p>", "x".repeat(100))).len(), 60);
assert_eq!(
note_preview(&format!("<p>{}</p>", "x".repeat(100))).len(),
60
);
}

#[test]
Expand All @@ -543,8 +554,12 @@ mod tests {
#[test]
fn load_notes_meta_has_preview_and_counts_no_content() {
let s = store();
s.save_note(&note("a", r#"<p>Title</p><li data-checked="true">x</li>"#, 1000))
.unwrap();
s.save_note(&note(
"a",
r#"<p>Title</p><li data-checked="true">x</li>"#,
1000,
))
.unwrap();
let meta = s.load_notes_meta().unwrap();
assert_eq!(meta.len(), 1);
assert_eq!(meta[0].id, "a");
Expand All @@ -556,17 +571,22 @@ mod tests {
fn load_note_content_returns_html_or_none() {
let s = store();
s.save_note(&note("a", "<p>body</p>", 1000)).unwrap();
assert_eq!(s.load_note_content("a").unwrap().as_deref(), Some("<p>body</p>"));
assert_eq!(
s.load_note_content("a").unwrap().as_deref(),
Some("<p>body</p>")
);
assert_eq!(s.load_note_content("missing").unwrap(), None);
}

#[test]
fn search_notes_ranks_title_first_and_snippets() {
let s = store();
// body-only match
s.save_note(&note("body", "<p>Zeta</p><p>the apple is red</p>", 10)).unwrap();
s.save_note(&note("body", "<p>Zeta</p><p>the apple is red</p>", 10))
.unwrap();
// title match (higher rank)
s.save_note(&note("title", "<p>apple crumble</p>", 20)).unwrap();
s.save_note(&note("title", "<p>apple crumble</p>", 20))
.unwrap();
let hits = s.search_notes("apple", 50).unwrap();
assert_eq!(hits.len(), 2);
assert_eq!(hits[0].note.id, "title"); // title/preview hit ranks first
Expand Down
35 changes: 28 additions & 7 deletions src-tauri/src/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,18 @@ pub struct UpdateInfo {
/// (missing/garbage components count as 0).
pub fn is_newer(current: &str, latest: &str) -> bool {
fn parts(s: &str) -> Vec<u64> {
s.trim().trim_start_matches('v').split('.')
.map(|p| p.trim().parse::<u64>().unwrap_or(0)).collect()
s.trim()
.trim_start_matches('v')
.split('.')
.map(|p| p.trim().parse::<u64>().unwrap_or(0))
.collect()
}
let (c, l) = (parts(current), parts(latest));
for i in 0..c.len().max(l.len()) {
let (cv, lv) = (c.get(i).copied().unwrap_or(0), l.get(i).copied().unwrap_or(0));
let (cv, lv) = (
c.get(i).copied().unwrap_or(0),
l.get(i).copied().unwrap_or(0),
);
if lv != cv {
return lv > cv;
}
Expand All @@ -45,7 +51,9 @@ pub async fn check_for_update() -> Result<UpdateInfo, String> {
.map_err(|e| e.to_string())?;

let resp = client
.get(format!("https://api.github.com/repos/{REPO}/releases/latest"))
.get(format!(
"https://api.github.com/repos/{REPO}/releases/latest"
))
.header("Accept", "application/vnd.github+json")
.send()
.await
Expand All @@ -56,13 +64,26 @@ pub async fn check_for_update() -> Result<UpdateInfo, String> {
}

let body: serde_json::Value = resp.json().await.map_err(|e| e.to_string())?;
let latest = body.get("tag_name").and_then(|v| v.as_str()).unwrap_or("").to_string();
let latest = body
.get("tag_name")
.and_then(|v| v.as_str())
.unwrap_or("")
.to_string();
if latest.is_empty() {
return Err("no release tag found".into());
}
let url = body.get("html_url").and_then(|v| v.as_str()).unwrap_or(RELEASES_URL).to_string();
let url = body
.get("html_url")
.and_then(|v| v.as_str())
.unwrap_or(RELEASES_URL)
.to_string();

Ok(UpdateInfo { update_available: is_newer(&current, &latest), current, latest, url })
Ok(UpdateInfo {
update_available: is_newer(&current, &latest),
current,
latest,
url,
})
}

#[cfg(test)]
Expand Down
Loading