Skip to content

Commit

Permalink
show recent versions on no or empty query
Browse files Browse the repository at this point in the history
  • Loading branch information
robjtede committed Mar 19, 2021
1 parent 3658e80 commit f5c2f67
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 15 deletions.
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "alfred-caniuse-rs"
version = "0.1.2"
version = "0.2.0"
authors = ["Rob Ede <[email protected]>"]
edition = "2018"
license = "MIT"
Expand All @@ -17,5 +17,5 @@ ureq = { version = "2", features = ["json"] }
zstd = "0.6"

[profile.release]
# lto = true
# opt-level = "z"
lto = true
opt-level = "z"
6 changes: 3 additions & 3 deletions src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,9 @@ fn cache_put_inner(db: &Db) -> eyre::Result<()> {
// ensure containing direction of cache file exists
fs::create_dir_all(cache_dir())?;

// we need to reset the created datetime
// since the caching strategy relies on it
let _ = fs::remove_file(cache_path())?;
// we need to reset the created datetime since the caching strategy relies on it
// error is ignored to allow cache creation in first instant
let _ = fs::remove_file(cache_path());

// if create is successful, any existing file is truncated
let mut file = fs::File::create(cache_path())?;
Expand Down
7 changes: 7 additions & 0 deletions src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,13 @@ impl Db {
Ok(db)
}

/// Returns an iterator of the most recent Rust versions in reverse chronological order.
pub fn versions_preview(&self) -> impl Iterator<Item = VersionData> {
let mut versions = self.versions.values().cloned().collect::<Vec<_>>();
versions.sort_by(|a, b| a.partial_cmp(&b).unwrap().reverse());
versions.into_iter().take(8)
}

/// Finds a feature given a query string and returns the feature and stabilization version data.
pub fn lookup<'a>(&'a self, query: &str) -> Option<(&'a FeatureData, Option<&'a VersionData>)> {
let feature = self.features.get(query)?;
Expand Down
26 changes: 19 additions & 7 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,6 @@ fn try_main() -> eyre::Result<Vec<alfred::Item<'static>>> {
// skip self binary arg
args.next();

// TODO: allow empty query to show recent versions

let query = args
.next()
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "no query"))?;

let db = match cache_fetch() {
Some(db) => db,
None => {
Expand All @@ -39,6 +33,24 @@ fn try_main() -> eyre::Result<Vec<alfred::Item<'static>>> {
}
};

match args.next() {
None => show_recent_versions(&db, &mut items),
Some(query) if query.is_empty() => show_recent_versions(&db, &mut items),

Some(query) => match_query(&db, &query, &mut items),
}?;

Ok(items)
}

fn show_recent_versions(db: &Db, items: &mut Vec<alfred::Item<'static>>) -> eyre::Result<()> {
let versions = db.versions_preview().map(|v| v.to_alfred_item());
items.extend(versions);

Ok(())
}

fn match_query(db: &Db, query: &str, items: &mut Vec<alfred::Item<'static>>) -> eyre::Result<()> {
// TODO: fuzzy matching

let (feature, _) = db
Expand All @@ -48,5 +60,5 @@ fn try_main() -> eyre::Result<Vec<alfred::Item<'static>>> {
let item = feature.to_alfred_item(CANIUSE_URL);
items.push(item);

Ok(items)
Ok(())
}
91 changes: 89 additions & 2 deletions src/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,17 @@
//!
//! Definitions derived from https://github.com/jplatte/caniuse.rs/blob/e9c940047437cccfaf8ff65bcf68f70538877662/build.rs.
use std::{
cmp::{self, Ordering},
fmt,
};

use serde::{Deserialize, Serialize};

const RUST_BLOG_ROOT: &str = "https://blog.rust-lang.org/";

/// Versions that have been cut are either stable, beta or nightly.
#[derive(Copy, Clone, Debug, Deserialize, Serialize)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum Channel {
Stable,
Expand All @@ -19,8 +26,38 @@ impl Default for Channel {
}
}

impl PartialOrd for Channel {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
Some(self.cmp(&other))
}
}

impl Ord for Channel {
fn cmp(&self, other: &Self) -> cmp::Ordering {
let numeric = |&chan| -> u8 {
match chan {
Channel::Stable => 0,
Channel::Beta => 1,
Channel::Nightly => 2,
}
};

numeric(self).cmp(&numeric(other))
}
}

impl fmt::Display for Channel {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Channel::Stable => f.write_str("stable"),
Channel::Beta => f.write_str("beta"),
Channel::Nightly => f.write_str("nightly"),
}
}
}

/// Rust compiler version info.
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
#[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize, Serialize)]
pub struct VersionData {
/// Rust version number, e.g. "1.0.0"
pub number: String,
Expand All @@ -42,6 +79,56 @@ pub struct VersionData {
pub gh_milestone_id: Option<u64>,
}

impl VersionData {
/// Creates an Alfred item from version data.
pub fn to_alfred_item(&self) -> alfred::Item<'static> {
let mut builder = ItemBuilder::new(format!("v{} ({})", &self.number, &self.channel));

if let Some(release_date) = self.release_date() {
builder.set_subtitle(format!(
"Released: {} | Press enter to view release post.",
release_date.format("%F")
))
}

if let Some(blog_post) = self.blog_post_path.as_deref() {
builder.set_arg(format!("{}{}", RUST_BLOG_ROOT, blog_post.to_owned()));
builder.set_quicklook_url(format!("{}{}", RUST_BLOG_ROOT, blog_post.to_owned()));
};

builder.into_item()
}
}

impl VersionData {
fn release_date(&self) -> Option<time::Date> {
self.release_date
.as_deref()
.and_then(|date| time::Date::parse(date, "%F").ok())
}
}

impl PartialOrd<VersionData> for VersionData {
fn partial_cmp(&self, other: &VersionData) -> Option<cmp::Ordering> {
self.channel
.cmp(&other.channel)
.then_with(|| {
let self_rel = match self.release_date() {
Some(rel) => rel,
None => return Ordering::Equal,
};

let other_rel = match other.release_date() {
Some(rel) => rel,
None => return Ordering::Equal,
};

self_rel.cmp(&other_rel)
})
.into()
}
}

/// Rust "feature" info for some arbitrary definition of feature.
///
/// Not strictly tied to compiler features.
Expand Down

0 comments on commit f5c2f67

Please sign in to comment.