Merge pull request #148 from pop-os/launcher

Dependency updates
This commit is contained in:
leviport 2022-11-14 14:20:31 -07:00 committed by GitHub
commit fb8d5f50eb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 843 additions and 472 deletions

View file

@ -1,4 +1,5 @@
{ {
"remote.containers.dockerPath": "podman", "remote.containers.dockerPath": "podman",
"rust-analyzer.checkOnSave.command": "clippy" "rust-analyzer.checkOnSave.command": "clippy",
"rust-analyzer.checkOnSave.extraArgs": ["--", "-W", "clippy::pedantic"]
} }

1023
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
[package] [package]
name = "pop-launcher" name = "pop-launcher"
version = "1.2.1" version = "1.2.2"
license = "MPL-2.0" license = "MPL-2.0"
authors = ["Michael Aaron Murphy <mmstick@pm.me>"] authors = ["Michael Aaron Murphy <mmstick@pm.me>"]
description = "Library for writing plugins and frontends for pop-launcher" description = "Library for writing plugins and frontends for pop-launcher"
@ -11,12 +11,12 @@ edition = "2018"
members = ["bin", "plugins", "service", "toolkit"] members = ["bin", "plugins", "service", "toolkit"]
[dependencies] [dependencies]
const_format = "0.2.22" const_format = "0.2.30"
dirs = "4.0.0" dirs = "4.0.0"
futures = "0.3.21" futures = "0.3.25"
serde = { version = "1.0.136", features = ["derive"] } serde = { version = "1.0.147", features = ["derive"] }
serde_json = "1.0.79" serde_json = "1.0.87"
serde_with = "1.12.0" serde_with = "2.0.1"
[profile.release] [profile.release]
lto = true lto = true
@ -24,9 +24,9 @@ panic = "abort"
strip = true strip = true
[dependencies.tokio] [dependencies.tokio]
version = "1.17.0" version = "1.21.2"
features = ["io-std", "io-util"] features = ["io-std", "io-util"]
[dependencies.tokio-stream] [dependencies.tokio-stream]
version = "0.1.8" version = "0.1.11"
features = ["io-util"] features = ["io-util"]

View file

@ -9,11 +9,11 @@ publish = false
[dependencies] [dependencies]
pop-launcher-toolkit = { path = "../toolkit" } pop-launcher-toolkit = { path = "../toolkit" }
tracing = "0.1.32" tracing = "0.1.37"
tracing-subscriber = { version = "0.3.9", default-features = false, features = ["std", "fmt", "env-filter"] } tracing-subscriber = { version = "0.3.16", default-features = false, features = ["std", "fmt", "env-filter"] }
dirs = "4.0.0" dirs = "4.0.0"
mimalloc = "0.1.28" mimalloc = "0.1.30"
[dependencies.tokio] [dependencies.tokio]
version = "1.17.0" version = "1.21.2"
features = ["rt"] features = ["rt"]

9
debian/changelog vendored
View file

@ -1,3 +1,12 @@
pop-launcher (1.2.2) jammy; urgency=medium
* Various bug fixes and improvements
* Many dependency updates
* Recent application search enhancements
* New web plugin shortcuts
-- Michael Murphy <mmstick@pm.me> Sat, 05 Nov 2022 00:39:40 +0100
pop-launcher (1.2.1) impish; urgency=medium pop-launcher (1.2.1) impish; urgency=medium
* Use mimalloc as global allocator because it is 2x faster than glib * Use mimalloc as global allocator because it is 2x faster than glib

View file

@ -37,6 +37,9 @@ version := '0.0.0'
all: _extract_vendor all: _extract_vendor
cargo build -p pop-launcher-bin {{cargo_args}} cargo build -p pop-launcher-bin {{cargo_args}}
check:
cargo check -p pop-launcher-bin {{cargo_args}}
# Remove Cargo build artifacts # Remove Cargo build artifacts
clean: clean:
cargo clean cargo clean

View file

@ -1,6 +1,6 @@
[package] [package]
name = "pop-launcher-plugins" name = "pop-launcher-plugins"
version = "1.2.1" version = "1.2.2"
license = "GPL-3.0-only" license = "GPL-3.0-only"
authors = ["Michael Aaron Murphy <mmstick@pm.me>"] authors = ["Michael Aaron Murphy <mmstick@pm.me>"]
edition = "2018" edition = "2018"
@ -8,37 +8,37 @@ publish = false
[dependencies] [dependencies]
async-pidfd = "0.1.4" async-pidfd = "0.1.4"
fork = "0.1.19" fork = "0.1.20"
freedesktop-desktop-entry = "0.5.0" freedesktop-desktop-entry = "0.5.0"
human_format = "1.0.3" human_format = "1.0.3"
human-sort = "0.2.2" human-sort = "0.2.2"
new_mime_guess = "4.0.1" new_mime_guess = "4.0.1"
pop-launcher = { path = "../" } pop-launcher = { path = "../" }
regex = "1.5.5" regex = "1.6.0"
ron = "0.7.0" ron = "0.8.0"
serde = "1.0.136" serde = "1.0.147"
serde_json = "1.0.79" serde_json = "1.0.87"
slab = "0.4.5" slab = "0.4.7"
strsim = "0.10.0" strsim = "0.10.0"
tracing = "0.1.32" tracing = "0.1.37"
urlencoding = "2.1.0" urlencoding = "2.1.2"
zbus = "2.1.1" zbus = "3.4.0"
zvariant = "3.1.2" zvariant = "3.7.1"
ward = "2.1.0" ward = "2.1.0"
url = "2.2.2" url = "2.3.1"
sysfs-class = "0.1.3" sysfs-class = "0.1.3"
anyhow = "1.0.56" anyhow = "1.0.66"
flume = "0.10.12" flume = "0.10.14"
dirs = "4.0.0" dirs = "4.0.0"
futures = "0.3.21" futures = "0.3.25"
bytes = "1.1.0" bytes = "1.2.1"
recently-used-xbel = "1.0.0" recently-used-xbel = "1.0.0"
[dependencies.reqwest] [dependencies.reqwest]
version = "0.11.10" version = "0.11.12"
default-features = false default-features = false
features = ["rustls-tls"] features = ["rustls-tls"]
[dependencies.tokio] [dependencies.tokio]
version = "1.17.0" version = "1.21.2"
features = ["fs", "io-std", "macros", "process", "rt"] features = ["fs", "io-std", "macros", "process", "rt"]

View file

@ -1,35 +1,35 @@
[package] [package]
name = "pop-launcher-service" name = "pop-launcher-service"
version= "1.2.1" version= "1.2.2"
license = "MPL-2.0" license = "MPL-2.0"
edition = "2018" edition = "2018"
[dependencies] [dependencies]
anyhow = "1.0.56" anyhow = "1.0.66"
async-oneshot = "0.5.0" async-oneshot = "0.5.0"
async-trait = "0.1.53" async-trait = "0.1.58"
dirs = "4.0.0" dirs = "4.0.0"
futures = "0.3.21" futures = "0.3.25"
futures_codec = "0.4.1" futures_codec = "0.4.1"
gen-z = "0.1.0" gen-z = "0.1.0"
num_cpus = "1.13.1" num_cpus = "1.14.0"
pop-launcher = { path = "../" } pop-launcher = { path = "../" }
regex = "1.5.5" regex = "1.6.0"
ron = "0.7.0" ron = "0.8.0"
serde = { version = "1.0.136", features = ["derive"] } serde = { version = "1.0.147", features = ["derive"] }
serde_json = "1.0.79" serde_json = "1.0.87"
serde_with = "1.12.0" serde_with = "2.0.1"
slab = "0.4.5" slab = "0.4.7"
strsim = "0.10.0" strsim = "0.10.0"
toml = "0.5.8" toml = "0.5.9"
tracing = "0.1.32" tracing = "0.1.37"
tracing-subscriber = { version = "0.3.9", default-features = false, features = ["std", "fmt", "env-filter"] } tracing-subscriber = { version = "0.3.16", default-features = false, features = ["std", "fmt", "env-filter"] }
flume = "0.10.12" flume = "0.10.14"
[dependencies.tokio] [dependencies.tokio]
version= "1.17.0" version= "1.21.2"
features = ["io-std", "process", "rt"] features = ["io-std", "process", "rt"]
[dependencies.tokio-stream] [dependencies.tokio-stream]
version= "0.1.8" version= "0.1.11"
features = ["io-util"] features = ["io-util"]

View file

@ -32,13 +32,11 @@ impl IpcClient {
let responses = LinesStream::new(tokio::io::BufReader::new(stdout).lines()).filter_map( let responses = LinesStream::new(tokio::io::BufReader::new(stdout).lines()).filter_map(
|result| async move { |result| async move {
if let Ok(line) = result { let Ok(line) = result else {
if let Ok(event) = serde_json::from_str::<Response>(&line) { return None;
return Some(event); };
}
}
None serde_json::from_str::<Response>(&line).ok()
}, },
); );
@ -57,7 +55,7 @@ impl IpcClient {
} }
pub async fn exit(mut self) { pub async fn exit(mut self) {
let _ = self.send(Request::Exit).await; let _res = self.send(Request::Exit).await;
let _ = self.child.wait().await; let _res = self.child.wait().await;
} }
} }

View file

@ -3,24 +3,31 @@
mod client; mod client;
mod plugins; mod plugins;
mod recent;
mod priority; mod priority;
mod recent;
pub use client::*; pub use client::*;
pub use plugins::config; pub use plugins::config;
pub use plugins::external::load; pub use plugins::external::load;
use crate::plugins::*; use crate::plugins::{
use crate::recent::RecentUseStorage; ExternalPlugin, HelpPlugin, Plugin, PluginConfig, PluginConnector, PluginPriority, PluginQuery,
};
use crate::priority::Priority; use crate::priority::Priority;
use crate::recent::RecentUseStorage;
use flume::{Receiver, Sender}; use flume::{Receiver, Sender};
use futures::{future, SinkExt, Stream, StreamExt}; use futures::{future, SinkExt, Stream, StreamExt};
use pop_launcher::*; use pop_launcher::{
json_input_stream, plugin_paths, ContextOption, IconSource, Indice, PluginResponse,
PluginSearchResult, Request, Response, SearchResult,
};
use regex::Regex; use regex::Regex;
use slab::Slab; use slab::Slab;
use std::{ use std::{
cmp::Ordering,
collections::{HashMap, HashSet}, collections::{HashMap, HashSet},
io::{self, Write}, path::PathBuf, io::{self, Write},
path::PathBuf,
}; };
pub type PluginKey = usize; pub type PluginKey = usize;
@ -38,9 +45,10 @@ pub struct PluginHelp {
pub help: Option<String>, pub help: Option<String>,
} }
pub fn ensure_cache_path() -> Result<PathBuf, Box<dyn std::error::Error>> { pub fn ensure_cache_path() -> Result<PathBuf, Box<dyn std::error::Error>> {
let cachepath = dirs::home_dir().ok_or("failed to find home dir")?.join(".cache/pop-launcher"); let cachepath = dirs::home_dir()
.ok_or("failed to find home dir")?
.join(".cache/pop-launcher");
std::fs::create_dir_all(&cachepath)?; std::fs::create_dir_all(&cachepath)?;
Ok(cachepath.join("recent")) Ok(cachepath.join("recent"))
} }
@ -50,10 +58,10 @@ pub fn store_cache(storage: &RecentUseStorage) {
let cachepath = ensure_cache_path()?; let cachepath = ensure_cache_path()?;
Ok(serde_json::to_writer( Ok(serde_json::to_writer(
std::fs::File::create(cachepath)?, std::fs::File::create(cachepath)?,
storage storage,
)?) )?)
}; };
if let Err(e)= write_recent() { if let Err(e) = write_recent() {
eprintln!("could not write to cache file\n{}", e); eprintln!("could not write to cache file\n{}", e);
} }
} }
@ -66,10 +74,12 @@ pub async fn main() {
}; };
let recent = match read_recent() { let recent = match read_recent() {
Ok(r) => r, Ok(r) => r,
Err(e) => {eprintln!("could not read cache file\n{}", e); RecentUseStorage::default()} Err(e) => {
eprintln!("could not read cache file\n{}", e);
RecentUseStorage::default()
}
}; };
// Listens for a stream of requests from stdin. // Listens for a stream of requests from stdin.
let input_stream = json_input_stream(tokio::io::stdin()).filter_map(|result| { let input_stream = json_input_stream(tokio::io::stdin()).filter_map(|result| {
future::ready(match result { future::ready(match result {
@ -163,7 +173,7 @@ impl<O: futures::Sink<Response> + Unpin> Service<O> {
futures::pin_mut!(f1); futures::pin_mut!(f1);
futures::pin_mut!(f2); futures::pin_mut!(f2);
let _ = futures::future::select(f1, f2).await.factor_first().0; futures::future::select(f1, f2).await.factor_first();
} }
async fn response_handler(&mut self, service_rx: Receiver<Event>) { async fn response_handler(&mut self, service_rx: Receiver<Event>) {
@ -175,7 +185,7 @@ impl<O: futures::Sink<Response> + Unpin> Service<O> {
Request::Interrupt => self.interrupt().await, Request::Interrupt => self.interrupt().await,
Request::Activate(id) => self.activate(id).await, Request::Activate(id) => self.activate(id).await,
Request::ActivateContext { id, context } => { Request::ActivateContext { id, context } => {
self.activate_context(id, context).await self.activate_context(id, context).await;
} }
Request::Complete(id) => self.complete(id).await, Request::Complete(id) => self.complete(id).await,
Request::Context(id) => self.context(id).await, Request::Context(id) => self.context(id).await,
@ -186,7 +196,7 @@ impl<O: futures::Sink<Response> + Unpin> Service<O> {
Request::Exit => { Request::Exit => {
for (_key, plugin) in self.plugins.iter_mut() { for (_key, plugin) in self.plugins.iter_mut() {
let tx = plugin.sender_exec(); let tx = plugin.sender_exec();
let _ = tx.send_async(Request::Exit).await; let _res = tx.send_async(Request::Exit).await;
} }
break; break;
@ -199,7 +209,7 @@ impl<O: futures::Sink<Response> + Unpin> Service<O> {
PluginResponse::Clear => self.clear(), PluginResponse::Clear => self.clear(),
PluginResponse::Close => self.close().await, PluginResponse::Close => self.close().await,
PluginResponse::Context { id, options } => { PluginResponse::Context { id, options } => {
self.context_response(id, options).await self.context_response(id, options).await;
} }
PluginResponse::Fill(text) => self.fill(text).await, PluginResponse::Fill(text) => self.fill(text).await,
PluginResponse::Finished => self.finished(plugin).await, PluginResponse::Finished => self.finished(plugin).await,
@ -217,7 +227,7 @@ impl<O: futures::Sink<Response> + Unpin> Service<O> {
// Report the plugin as finished and remove it from future polling // Report the plugin as finished and remove it from future polling
PluginResponse::Deactivate => { PluginResponse::Deactivate => {
self.finished(plugin).await; self.finished(plugin).await;
let _ = self.plugins.remove(plugin); let _res = self.plugins.remove(plugin);
} }
}, },
@ -257,7 +267,7 @@ impl<O: futures::Sink<Response> + Unpin> Service<O> {
.query .query
.isolate_with .isolate_with
.as_ref() .as_ref()
.and_then(|expr| Regex::new(&*expr).ok()); .and_then(|expr| Regex::new(expr).ok());
entry.insert(PluginConnector::new( entry.insert(PluginConnector::new(
config, config,
@ -281,7 +291,7 @@ impl<O: futures::Sink<Response> + Unpin> Service<O> {
let mut ex = None; let mut ex = None;
if let Some((plugin, meta)) = self.search_result(id as usize) { if let Some((plugin, meta)) = self.search_result(id as usize) {
ex = meta.cache_identifier(); ex = meta.cache_identifier();
let _ = plugin let _res = plugin
.sender_exec() .sender_exec()
.send_async(Request::Activate(meta.id)) .send_async(Request::Activate(meta.id))
.await; .await;
@ -296,7 +306,7 @@ impl<O: futures::Sink<Response> + Unpin> Service<O> {
let mut ex = None; let mut ex = None;
if let Some((plugin, meta)) = self.search_result(id as usize) { if let Some((plugin, meta)) = self.search_result(id as usize) {
ex = meta.cache_identifier(); ex = meta.cache_identifier();
let _ = plugin let _res = plugin
.sender_exec() .sender_exec()
.send_async(Request::ActivateContext { .send_async(Request::ActivateContext {
id: meta.id, id: meta.id,
@ -331,7 +341,7 @@ impl<O: futures::Sink<Response> + Unpin> Service<O> {
async fn complete(&mut self, id: Indice) { async fn complete(&mut self, id: Indice) {
if let Some((plugin, meta)) = self.search_result(id as usize) { if let Some((plugin, meta)) = self.search_result(id as usize) {
let _ = plugin let _res = plugin
.sender_exec() .sender_exec()
.send_async(Request::Complete(meta.id)) .send_async(Request::Complete(meta.id))
.await; .await;
@ -340,7 +350,7 @@ impl<O: futures::Sink<Response> + Unpin> Service<O> {
async fn context(&mut self, id: Indice) { async fn context(&mut self, id: Indice) {
if let Some((plugin, meta)) = self.search_result(id as usize) { if let Some((plugin, meta)) = self.search_result(id as usize) {
let _ = plugin let _res = plugin
.sender_exec() .sender_exec()
.send_async(Request::Context(meta.id)) .send_async(Request::Context(meta.id))
.await; .await;
@ -370,14 +380,14 @@ impl<O: futures::Sink<Response> + Unpin> Service<O> {
async fn interrupt(&mut self) { async fn interrupt(&mut self) {
for (_, plugin) in self.plugins.iter_mut() { for (_, plugin) in self.plugins.iter_mut() {
if let Some(sender) = plugin.sender.as_mut() { if let Some(sender) = plugin.sender.as_mut() {
let _ = sender.send_async(Request::Interrupt).await; let _res = sender.send_async(Request::Interrupt).await;
} }
} }
} }
async fn quit(&mut self, id: Indice) { async fn quit(&mut self, id: Indice) {
if let Some((plugin, meta)) = self.search_result(id as usize) { if let Some((plugin, meta)) = self.search_result(id as usize) {
let _ = plugin let _res = plugin
.sender_exec() .sender_exec()
.send_async(Request::Quit(meta.id)) .send_async(Request::Quit(meta.id))
.await; .await;
@ -385,7 +395,7 @@ impl<O: futures::Sink<Response> + Unpin> Service<O> {
} }
async fn respond(&mut self, event: Response) { async fn respond(&mut self, event: Response) {
let _ = self.output.send(event).await; let _res = self.output.send(event).await;
} }
async fn search(&mut self, query: String) { async fn search(&mut self, query: String) {
@ -487,6 +497,7 @@ impl<O: futures::Sink<Response> + Unpin> Service<O> {
}) })
} }
#[allow(clippy::too_many_lines)]
fn sort(&mut self) -> Vec<SearchResult> { fn sort(&mut self) -> Vec<SearchResult> {
let &mut Self { let &mut Self {
ref mut active_search, ref mut active_search,
@ -500,8 +511,6 @@ impl<O: futures::Sink<Response> + Unpin> Service<O> {
let query = &last_query.to_ascii_lowercase(); let query = &last_query.to_ascii_lowercase();
use std::cmp::Ordering;
if *no_sort { if *no_sort {
*no_sort = false; *no_sort = false;
} else { } else {
@ -527,9 +536,9 @@ impl<O: futures::Sink<Response> + Unpin> Service<O> {
if exec.contains(query) { if exec.contains(query) {
if exec.starts_with(query) { if exec.starts_with(query) {
return 1.0; return 1.0;
} else {
weight = strsim::jaro_winkler(query, &exec) - 0.1;
} }
weight = strsim::jaro_winkler(query, &exec) - 0.1;
} }
weight weight
@ -564,12 +573,12 @@ impl<O: futures::Sink<Response> + Unpin> Service<O> {
match_score: calculate_weight(sr, query), match_score: calculate_weight(sr, query),
recent_use_index: ex.as_ref().map(|s| recent.get_recent(s)).unwrap_or(0), recent_use_index: ex.as_ref().map(|s| recent.get_recent(s)).unwrap_or(0),
use_freq: ex.as_ref().map(|s| recent.get_freq(s)).unwrap_or(0), use_freq: ex.as_ref().map(|s| recent.get_freq(s)).unwrap_or(0),
execlen: sr.name.len() execlen: sr.name.len(),
} }
}; };
get_prio(&b.1, plug2).cmp(&get_prio(&a.1, plug1)) get_prio(&b.1, plug2).cmp(&get_prio(&a.1, plug1))
}) });
} }
let take = if last_query.starts_with('/') | last_query.starts_with('~') { let take = if last_query.starts_with('/') | last_query.starts_with('~') {
@ -605,7 +614,7 @@ impl<O: futures::Sink<Response> + Unpin> Service<O> {
if result.window.is_some() { if result.window.is_some() {
windows.push(result); windows.push(result);
} else { } else {
non_windows.push(result) non_windows.push(result);
} }
} }
@ -622,23 +631,23 @@ async fn request_handler(input: impl Stream<Item = Request>, tx: Sender<Event>)
while let Some(request) = input.next().await { while let Some(request) = input.next().await {
if let Request::Exit = request { if let Request::Exit = request {
requested_to_exit = true requested_to_exit = true;
} }
let _ = tx.send_async(Event::Request(request)).await; let _res = tx.send_async(Event::Request(request)).await;
if requested_to_exit { if requested_to_exit {
break; break;
} }
} }
tracing::debug!("no longer listening for requests") tracing::debug!("no longer listening for requests");
} }
/// Serializes the launcher's response to stdout /// Serializes the launcher's response to stdout
fn serialize_out<E: serde::Serialize>(output: &mut io::StdoutLock, event: &E) { fn serialize_out<E: serde::Serialize>(output: &mut io::StdoutLock, event: &E) {
if let Ok(mut vec) = serde_json::to_vec(event) { if let Ok(mut vec) = serde_json::to_vec(event) {
vec.push(b'\n'); vec.push(b'\n');
let _ = output.write_all(&vec); let _res = output.write_all(&vec);
} }
} }

View file

@ -23,7 +23,7 @@ pub const CONFIG: PluginConfig = PluginConfig {
regex: None, regex: None,
}, },
icon: Some(IconSource::Name(Cow::Borrowed("system-help-symbolic"))), icon: Some(IconSource::Name(Cow::Borrowed("system-help-symbolic"))),
history: false history: false,
}; };
pub struct HelpPlugin { pub struct HelpPlugin {
pub id: usize, pub id: usize,

View file

@ -1,8 +1,8 @@
// Copyright 2021 System76 <info@system76.com> // Copyright 2021 System76 <info@system76.com>
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
pub(crate) mod external;
pub mod config; pub mod config;
pub(crate) mod external;
pub mod help; pub mod help;
pub use external::load; pub use external::load;

View file

@ -2,7 +2,6 @@ use std::cmp::Ordering;
use crate::PluginPriority; use crate::PluginPriority;
// holds all values used for ordering search results // holds all values used for ordering search results
pub struct Priority { pub struct Priority {
pub plugin_priority: PluginPriority, pub plugin_priority: PluginPriority,
@ -12,15 +11,18 @@ pub struct Priority {
pub execlen: usize, pub execlen: usize,
} }
fn signum(val: i32) -> f64 { fn signum(val: i32) -> f64 {
if val > 0 { return 1.0; } if val > 0 {
if val < 0 { return -1.0; } return 1.0;
}
if val < 0 {
return -1.0;
}
0.0 0.0
} }
impl Priority { impl Priority {
fn compute_value(&self, other: &Self) -> f64{ fn compute_value(&self, other: &Self) -> f64 {
// increases compared jw-score if this search result // increases compared jw-score if this search result
// was activated more frequent or recent by constant values // was activated more frequent or recent by constant values
let score = self.match_score let score = self.match_score
@ -30,7 +32,8 @@ impl Priority {
if self.match_score < 1.0 { if self.match_score < 1.0 {
return score.min(0.99); return score.min(0.99);
} }
return score;
score
} }
} }
@ -46,9 +49,12 @@ impl Eq for Priority {}
impl PartialOrd for Priority { impl PartialOrd for Priority {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
(other.plugin_priority, self.compute_value(other), self.execlen).partial_cmp( (
&(self.plugin_priority, other.match_score, other.execlen) other.plugin_priority,
self.compute_value(other),
self.execlen,
) )
.partial_cmp(&(self.plugin_priority, other.match_score, other.execlen))
} }
} }

View file

@ -1,6 +1,6 @@
use std::collections::{HashMap, hash_map::DefaultHasher}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::hash::{Hasher, Hash}; use std::collections::{hash_map::DefaultHasher, HashMap};
use serde::{Deserialize, Serialize, Serializer, Deserializer}; use std::hash::{Hash, Hasher};
const SHORTTERM_CAP: usize = 20; const SHORTTERM_CAP: usize = 20;
const LONGTERM_CAP: usize = 100; const LONGTERM_CAP: usize = 100;
@ -13,25 +13,23 @@ const LONGTERM_CAP: usize = 100;
// command string. // command string.
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct RecentUseStorage { pub struct RecentUseStorage {
long_term: HashMap<usize, usize>, long_term: HashMap<u64, usize>,
short_term: HashMap<usize, usize>, short_term: HashMap<u64, usize>,
} }
fn hash_key<K: Hash>(key: K) -> u64 {
fn hash_key<K: Hash>(key: K) -> usize {
let mut hasher = DefaultHasher::new(); let mut hasher = DefaultHasher::new();
key.hash(&mut hasher); key.hash(&mut hasher);
hasher.finish() as usize hasher.finish()
} }
impl RecentUseStorage { impl RecentUseStorage {
pub fn add<K: Hash>(&mut self, exec: &K) { pub fn add<K: Hash>(&mut self, exec: &K) {
let key = hash_key(exec); let key = hash_key(exec);
*self.long_term.entry(key).or_insert(0) += 1; *self.long_term.entry(key).or_insert(0) += 1;
let short_term_idx = self.short_term.values().max().unwrap_or( &0)+1; let short_term_idx = self.short_term.values().max().unwrap_or(&0) + 1;
self.short_term.insert(key, short_term_idx); self.short_term.insert(key, short_term_idx);
self.trim() self.trim();
} }
fn trim(&mut self) { fn trim(&mut self) {
@ -42,7 +40,7 @@ impl RecentUseStorage {
while self.long_term.values().sum::<usize>() > LONGTERM_CAP { while self.long_term.values().sum::<usize>() > LONGTERM_CAP {
let mut delete_keys = Vec::new(); let mut delete_keys = Vec::new();
for (k, v) in self.long_term.iter_mut() { for (k, v) in &mut self.long_term {
*v /= 2; *v /= 2;
if *v == 0 { if *v == 0 {
delete_keys.push(*k); delete_keys.push(*k);
@ -79,9 +77,9 @@ impl<'de> Deserialize<'de> for RecentUseStorage {
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
type SerType = (HashMap<usize, usize>, Vec<usize>); type SerType = (HashMap<u64, usize>, Vec<u64>);
let (long_term, stv) = SerType::deserialize(deserializer)?; let (long_term, stv) = SerType::deserialize(deserializer)?;
let short_term: HashMap<_, _> = stv.into_iter().enumerate().map(|(v,k)| (k,v)).collect(); let short_term: HashMap<_, _> = stv.into_iter().enumerate().map(|(v, k)| (k, v)).collect();
Ok(RecentUseStorage { Ok(RecentUseStorage {
long_term, long_term,
short_term, short_term,

View file

@ -5,12 +5,16 @@ use futures::{Stream, StreamExt};
use serde::Deserialize; use serde::Deserialize;
use tokio::io::{AsyncBufReadExt, AsyncRead}; use tokio::io::{AsyncBufReadExt, AsyncRead};
/// stdin with AsyncRead support /// stdin with [`AsyncWrite`] support
#[must_use]
#[inline]
pub fn async_stdin() -> tokio::io::Stdin { pub fn async_stdin() -> tokio::io::Stdin {
tokio::io::stdin() tokio::io::stdin()
} }
/// stdout with AsyncWrite support /// stdout with [`AsyncWrite`] support
#[must_use]
#[inline]
pub fn async_stdout() -> tokio::io::Stdout { pub fn async_stdout() -> tokio::io::Stdout {
tokio::io::stdout() tokio::io::stdout()
} }

View file

@ -111,11 +111,13 @@ pub struct PluginSearchResult {
} }
impl PluginSearchResult { impl PluginSearchResult {
#[must_use]
#[inline]
pub fn cache_identifier(&self) -> Option<String> { pub fn cache_identifier(&self) -> Option<String> {
// the exec field may clash in multiple search results as the arguments // the exec field may clash in multiple search results as the arguments
// are cut from the string // are cut from the string
// self.exec.to_owned().unwrap_or_else(|| self.name.to_owned()) // self.exec.to_owned().unwrap_or_else(|| self.name.to_owned())
self.exec.as_ref().map(|_| self.name.to_owned()) self.exec.as_ref().map(|_| self.name.clone())
} }
} }

View file

@ -10,15 +10,15 @@ description = "A wrapper around pop-launcher, pop-launcher-service and pop-launc
pop-launcher-plugins = { path = "../plugins"} pop-launcher-plugins = { path = "../plugins"}
pop-launcher-service = { path = "../service"} pop-launcher-service = { path = "../service"}
pop-launcher = { path = "../" } pop-launcher = { path = "../" }
async-trait = "0.1.53" async-trait = "0.1.58"
tracing = "0.1.32" tracing = "0.1.37"
tracing-subscriber = { version = "0.3.9", default-features = false, features = ["std", "fmt", "env-filter"] } tracing-subscriber = { version = "0.3.16", default-features = false, features = ["std", "fmt", "env-filter"] }
dirs = "4.0.0" dirs = "4.0.0"
futures = "0.3.21" futures = "0.3.25"
[dev-dependencies] [dev-dependencies]
tokio = { version = "1", features = [ "rt" ] } tokio = { version = "1", features = [ "rt" ] }
fork = "0.1.19" fork = "0.1.20"
[[example]] [[example]]
name = "man-pages-plugin" name = "man-pages-plugin"