commit
fb8d5f50eb
17 changed files with 843 additions and 472 deletions
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
|
|
@ -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
1023
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
16
Cargo.toml
16
Cargo.toml
|
|
@ -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"]
|
||||||
|
|
|
||||||
|
|
@ -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
9
debian/changelog
vendored
|
|
@ -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
|
||||||
|
|
|
||||||
3
justfile
3
justfile
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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"]
|
||||||
|
|
|
||||||
|
|
@ -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"]
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,9 +74,11 @@ 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| {
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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,12 +32,13 @@ 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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for Priority {
|
impl PartialEq for Priority {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.plugin_priority == other.plugin_priority
|
self.plugin_priority == other.plugin_priority
|
||||||
&& self.compute_value(other) == other.match_score
|
&& self.compute_value(other) == other.match_score
|
||||||
&& self.execlen == other.execlen
|
&& self.execlen == other.execlen
|
||||||
|
|
@ -45,10 +48,13 @@ impl PartialEq for Priority {
|
||||||
impl Eq for Priority {}
|
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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -56,4 +62,4 @@ impl Ord for Priority {
|
||||||
fn cmp(&self, other: &Self) -> Ordering {
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
self.partial_cmp(other).unwrap()
|
self.partial_cmp(other).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,12 +77,12 @@ 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,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,16 +10,16 @@ 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"
|
||||||
path = "examples/man-pages-plugin.rs"
|
path = "examples/man-pages-plugin.rs"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue