improv: Separate components & merge plugins binary with launcher service

This commit is contained in:
Michael Aaron Murphy 2021-08-14 14:19:42 +02:00
parent 43a4229ba7
commit 88acf0a74e
41 changed files with 219 additions and 152 deletions

46
Cargo.lock generated
View file

@ -761,23 +761,21 @@ dependencies = [
name = "pop-launcher" name = "pop-launcher"
version = "1.0.0" version = "1.0.0"
dependencies = [ dependencies = [
"anyhow", "blocking",
"async-io",
"async-oneshot",
"async-trait",
"flume",
"futures-lite", "futures-lite",
"futures_codec", "futures_codec",
"gen-z",
"regex",
"ron",
"serde", "serde",
"serde_json", "serde_json",
"serde_with", "serde_with",
"slab", ]
[[package]]
name = "pop-launcher-bin"
version = "1.0.0"
dependencies = [
"pop-launcher-plugins",
"pop-launcher-service",
"smol", "smol",
"strsim",
"toml",
"tracing", "tracing",
"tracing-subscriber", "tracing-subscriber",
] ]
@ -803,6 +801,32 @@ dependencies = [
"zvariant", "zvariant",
] ]
[[package]]
name = "pop-launcher-service"
version = "1.0.0"
dependencies = [
"anyhow",
"async-io",
"async-oneshot",
"async-trait",
"flume",
"futures-lite",
"futures_codec",
"gen-z",
"pop-launcher",
"regex",
"ron",
"serde",
"serde_json",
"serde_with",
"slab",
"smol",
"strsim",
"toml",
"tracing",
"tracing-subscriber",
]
[[package]] [[package]]
name = "proc-macro-crate" name = "proc-macro-crate"
version = "0.1.5" version = "0.1.5"

View file

@ -2,29 +2,18 @@
name = "pop-launcher" name = "pop-launcher"
version = "1.0.0" version = "1.0.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"
repository = "https://github.com/pop-os/launcher"
edition = "2018" edition = "2018"
resolver = "2" resolver = "2"
[workspace] [workspace]
members = ["plugins"] members = ["bin", "plugins", "service"]
[dependencies] [dependencies]
anyhow = "1"
async-io = "1"
async-oneshot = "0.5"
async-trait = "0.1"
flume = "=0.10.7" # Restrict version to build with 1.47.0
futures_codec = "0.4"
futures-lite = "1"
regex = "1.5"
ron = "0.6"
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
serde_json = "1" serde_json = "1"
serde_with = "1" serde_with = "1"
slab = "0.4" futures-lite = "1"
smol = "1" futures_codec = "0.4"
strsim = "0.10" blocking = "1"
toml = "0.5"
tracing = "0.1"
tracing-subscriber = { version = "0.2", features = ["fmt"] }
gen-z = "0.1"

View file

@ -12,8 +12,8 @@ endif
LAUNCHER_DIR = $(LIB_PATH)/pop-launcher LAUNCHER_DIR = $(LIB_PATH)/pop-launcher
SCRIPTS_DIR = $(LAUNCHER_DIR)/scripts SCRIPTS_DIR = $(LAUNCHER_DIR)/scripts
PLUGIN_DIR = $(LAUNCHER_DIR)/plugins PLUGIN_DIR = $(LAUNCHER_DIR)/plugins
DEFAULT_PLUGINS_BIN = $(PLUGIN_DIR)/pop-launcher-plugins
BIN_DIR = $(BASE_PATH)/bin BIN_DIR = $(BASE_PATH)/bin
BIN = $(BIN_DIR)/pop-launcher
PLUGINS=calc desktop_entries files find pop_shell pulse recent scripts terminal web PLUGINS=calc desktop_entries files find pop_shell pulse recent scripts terminal web
@ -31,8 +31,7 @@ ifneq ($(VENDOR),0)
endif endif
all: extract-vendor all: extract-vendor
cargo build -p pop-launcher-plugins $(ARGS) cargo build -p pop-launcher-bin $(ARGS)
cargo build $(ARGS)
clean: clean:
cargo clean cargo clean
@ -56,42 +55,41 @@ install:
for plugin in $(PLUGINS); do \ for plugin in $(PLUGINS); do \
dest=$(PLUGIN_DIR)/$${plugin}; \ dest=$(PLUGIN_DIR)/$${plugin}; \
mkdir -p $${dest}; \ mkdir -p $${dest}; \
install -Dm0644 plugins/src/plugins/$${plugin}/plugin.ron $${dest}/plugin.ron; \ install -Dm0644 plugins/src/$${plugin}/plugin.ron $${dest}/plugin.ron; \
done done
install -Dm0755 target/$(TARGET)/pop-launcher $(BIN_DIR)/pop-launcher install -Dm0755 target/$(TARGET)/pop-launcher-bin $(BIN)
install -Dm0755 target/$(TARGET)/pop-launcher-plugins $(DEFAULT_PLUGINS_BIN)
# Pop Shell Windows plugin # Pop Shell Windows plugin
ln -sf $(DEFAULT_PLUGINS_BIN) $(PLUGIN_DIR)/pop_shell/pop-shell ln -sf $(BIN) $(PLUGIN_DIR)/pop_shell/pop-shell
# Desktop Entries plugin # Desktop Entries plugin
ln -sf $(DEFAULT_PLUGINS_BIN) $(PLUGIN_DIR)/desktop_entries/desktop-entries ln -sf $(BIN) $(PLUGIN_DIR)/desktop_entries/desktop-entries
# Find plugin # Find plugin
ln -sf $(DEFAULT_PLUGINS_BIN) $(PLUGIN_DIR)/find/find ln -sf $(BIN) $(PLUGIN_DIR)/find/find
# Scripts plugin # Scripts plugin
ln -sf $(DEFAULT_PLUGINS_BIN) $(PLUGIN_DIR)/scripts/scripts ln -sf $(BIN) $(PLUGIN_DIR)/scripts/scripts
# Calculator plugin # Calculator plugin
install -Dm0755 plugins/src/plugins/calc/calc.js $(PLUGIN_DIR)/calc install -Dm0755 plugins/src/calc/calc.js $(PLUGIN_DIR)/calc
install -Dm0644 plugins/src/plugins/calc/math.js $(PLUGIN_DIR)/calc install -Dm0644 plugins/src/calc/math.js $(PLUGIN_DIR)/calc
# Files plugin # Files plugin
install -Dm0755 plugins/src/plugins/files/files.js $(PLUGIN_DIR)/files install -Dm0755 plugins/src/files/files.js $(PLUGIN_DIR)/files
# Recent plugin # Recent plugin
install -Dm0755 plugins/src/plugins/recent/recent.js $(PLUGIN_DIR)/recent install -Dm0755 plugins/src/recent/recent.js $(PLUGIN_DIR)/recent
# Pulse plugin # Pulse plugin
install -Dm0755 plugins/src/plugins/pulse/pulse.js $(PLUGIN_DIR)/pulse install -Dm0755 plugins/src/pulse/pulse.js $(PLUGIN_DIR)/pulse
# Terminal plugin # Terminal plugin
install -Dm0755 plugins/src/plugins/terminal/terminal.js $(PLUGIN_DIR)/terminal install -Dm0755 plugins/src/terminal/terminal.js $(PLUGIN_DIR)/terminal
# Web plugin # Web plugin
install -Dm0755 plugins/src/plugins/web/web.js $(PLUGIN_DIR)/web install -Dm0755 plugins/src/web/web.js $(PLUGIN_DIR)/web
# Scripts # Scripts
mkdir -p $(SCRIPTS_DIR) mkdir -p $(SCRIPTS_DIR)

View file

@ -12,7 +12,7 @@ Using IPC enables each plugin to isolate their data from other plugin processes
## Script Directories ## Script Directories
- User-local plugins: `~/.local/share/pop-shell/scripts` - User-local scripts: `~/.local/share/pop-shell/scripts`
- System-wide install for system administrators: `/etc/pop-shell/scripts` - System-wide install for system administrators: `/etc/pop-shell/scripts`
- Distribution packaging: `/usr/lib/pop-shell/scripts` - Distribution packaging: `/usr/lib/pop-shell/scripts`
@ -65,7 +65,7 @@ If you are writing a plugin, you should send these events to your stdout.
```rust ```rust
pub enum PluginResponse { pub enum PluginResponse {
/// Append a new search item to the launcher /// Append a new search item to the launcher
Append(SearchMeta), Append(PluginSearchResult),
/// Clear all results in the launcher list /// Clear all results in the launcher list
Clear, Clear,
/// Close the launcher /// Close the launcher
@ -81,14 +81,14 @@ pub enum PluginResponse {
#### JSON Equivalent #### JSON Equivalent
- `{ "Append": SearchMeta }`, - `{ "Append": PluginSearchResult }`,
- `"Clear"`, - `"Clear"`,
- `"Close"`, - `"Close"`,
- `{ "DesktopEntry": string }` - `{ "DesktopEntry": string }`
- `{ "Fill": string }` - `{ "Fill": string }`
- `"Finished"` - `"Finished"`
Where `SearchMeta` is: Where `PluginSearchResult` is:
```ts ```ts
{ {

14
bin/Cargo.toml Normal file
View file

@ -0,0 +1,14 @@
[package]
name = "pop-launcher-bin"
version = "1.0.0"
edition = "2018"
publish = false
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
pop-launcher-plugins = { path = "../plugins" }
pop-launcher-service = { path = "../service" }
smol = "1"
tracing = "0.1"
tracing-subscriber = "0.2"

View file

@ -1,5 +1,5 @@
mod plugins; use pop_launcher_plugins as plugins;
use pop_launcher_service::Service;
use smol::block_on; use smol::block_on;
use std::io; use std::io;
@ -13,7 +13,12 @@ fn main() {
if let Some(plugin) = std::env::args().next() { if let Some(plugin) = std::env::args().next() {
let start = plugin.rfind('/').map(|v| v + 1).unwrap_or(0); let start = plugin.rfind('/').map(|v| v + 1).unwrap_or(0);
match &plugin.as_str()[start..] { let cmd = &plugin.as_str()[start..];
match cmd {
"pop-launcher" => {
let stdout = io::stdout();
block_on(Service::new(stdout.lock()).exec())
},
"desktop-entries" => block_on(plugins::desktop_entries::main()), "desktop-entries" => block_on(plugins::desktop_entries::main()),
"pop-shell" => block_on(plugins::pop_shell::main()), "pop-shell" => block_on(plugins::pop_shell::main()),
"find" => block_on(plugins::find::main()), "find" => block_on(plugins::find::main()),

View file

@ -1,4 +1,4 @@
/usr/lib/pop-launcher/plugins/pop-launcher-plugins /usr/lib/pop-launcher/plugins/desktop_entries/desktop-entries /usr/bin/pop-launcher /usr/lib/pop-launcher/plugins/desktop_entries/desktop-entries
/usr/lib/pop-launcher/plugins/pop-launcher-plugins /usr/lib/pop-launcher/plugins/find/find /usr/bin/pop-launcher /usr/lib/pop-launcher/plugins/find/find
/usr/lib/pop-launcher/plugins/pop-launcher-plugins /usr/lib/pop-launcher/plugins/pop_shell/pop-shell /usr/bin/pop-launcher /usr/lib/pop-launcher/plugins/pop_shell/pop-shell
/usr/lib/pop-launcher/plugins/pop-launcher-plugins /usr/lib/pop-launcher/plugins/scripts/scripts /usr/bin/pop-launcher /usr/lib/pop-launcher/plugins/scripts/scripts

View file

@ -3,6 +3,7 @@ name = "pop-launcher-plugins"
version = "1.0.0" version = "1.0.0"
authors = ["Michael Aaron Murphy <mmstick@pm.me>"] authors = ["Michael Aaron Murphy <mmstick@pm.me>"]
edition = "2018" edition = "2018"
publish = false
[dependencies] [dependencies]
flume = "0.10" flume = "0.10"

View file

@ -1,7 +1,7 @@
use freedesktop_desktop_entry::{default_paths, DesktopEntry, Iter as DesktopIter, PathSource}; use freedesktop_desktop_entry::{default_paths, DesktopEntry, Iter as DesktopIter, PathSource};
use futures_lite::{AsyncWrite, StreamExt}; use futures_lite::{AsyncWrite, StreamExt};
use pop_launcher::*; use pop_launcher::*;
use pop_launcher_plugins::*; use crate::*;
use std::borrow::Cow; use std::borrow::Cow;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::path::PathBuf; use std::path::PathBuf;
@ -172,7 +172,7 @@ impl<W: AsyncWrite + Unpin> DesktopEntryPlugin<W> {
|| strsim::damerau_levenshtein(&*query, &*search_interest) < 3; || strsim::damerau_levenshtein(&*query, &*search_interest) < 3;
if append { if append {
let response = PluginResponse::Append(SearchMeta { let response = PluginResponse::Append(PluginSearchResult {
id: id as u32, id: id as u32,
name: entry.name.clone(), name: entry.name.clone(),
description: format!("{} - {}", path_string(&entry.src), entry.description), description: format!("{} - {}", path_string(&entry.src), entry.description),

View file

@ -1,6 +1,6 @@
use futures_lite::*; use futures_lite::*;
use pop_launcher::*; use pop_launcher::*;
use pop_launcher_plugins::send; use crate::send;
use smol::process::{ChildStdout, Command, Stdio}; use smol::process::{ChildStdout, Command, Stdio};
use std::borrow::Cow; use std::borrow::Cow;
use std::cell::Cell; use std::cell::Cell;
@ -121,7 +121,7 @@ impl SearchContext {
let path = PathBuf::from(line); let path = PathBuf::from(line);
let response = PluginResponse::Append(SearchMeta { let response = PluginResponse::Append(PluginSearchResult {
id, id,
description, description,
name, name,

View file

@ -1,3 +1,8 @@
pub mod desktop_entries;
pub mod find;
pub mod pop_shell;
pub mod scripts;
use futures_lite::{AsyncWrite, AsyncWriteExt}; use futures_lite::{AsyncWrite, AsyncWriteExt};
use pop_launcher::PluginResponse; use pop_launcher::PluginResponse;

View file

@ -1,4 +0,0 @@
pub mod desktop_entries;
pub mod find;
pub mod pop_shell;
pub mod scripts;

View file

@ -1,6 +1,6 @@
use futures_lite::{AsyncWrite, AsyncWriteExt, StreamExt}; use futures_lite::{AsyncWrite, AsyncWriteExt, StreamExt};
use pop_launcher::*; use pop_launcher::*;
use pop_launcher_plugins::*; use crate::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::convert::TryFrom; use std::convert::TryFrom;
use zbus::Connection; use zbus::Connection;
@ -106,7 +106,7 @@ impl<W: AsyncWrite + Unpin> App<W> {
send( send(
&mut self.tx, &mut self.tx,
PluginResponse::Append(SearchMeta { PluginResponse::Append(PluginSearchResult {
id: id as u32, id: id as u32,
name: item.name.clone(), name: item.name.clone(),
description: item.description.clone(), description: item.description.clone(),

View file

@ -1,5 +1,5 @@
use pop_launcher::*; use pop_launcher::*;
use pop_launcher_plugins::*; use crate::*;
use flume::Sender; use flume::Sender;
use futures_lite::{AsyncBufReadExt, StreamExt}; use futures_lite::{AsyncBufReadExt, StreamExt};
@ -114,7 +114,7 @@ impl App {
if should_include { if should_include {
send( send(
out, out,
PluginResponse::Append(SearchMeta { PluginResponse::Append(PluginSearchResult {
id: id as u32, id: id as u32,
name: script.name.clone(), name: script.name.clone(),
description: script.description.clone(), description: script.description.clone(),

27
service/Cargo.toml Normal file
View file

@ -0,0 +1,27 @@
[package]
name = "pop-launcher-service"
version = "1.0.0"
edition = "2018"
publish = false
[dependencies]
anyhow = "1"
async-io = "1"
async-oneshot = "0.5"
async-trait = "0.1"
flume = "=0.10.7" # Restrict version to build with 1.47.0
futures_codec = "0.4"
futures-lite = "1"
regex = "1.5"
ron = "0.6"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
serde_with = "1"
slab = "0.4"
smol = "1"
strsim = "0.10"
toml = "0.5"
tracing = "0.1"
tracing-subscriber = { version = "0.2", features = ["fmt"] }
gen-z = "0.1"
pop-launcher = { path = "../" }

View file

@ -1,12 +1,30 @@
use crate::*; mod plugins;
use pop_launcher::*;
use crate::plugins::*;
use flume::{unbounded, Receiver, Sender}; use flume::{unbounded, Receiver, Sender};
use futures_lite::{future, StreamExt}; use futures_lite::{future, StreamExt};
use regex::Regex; use regex::Regex;
use slab::Slab; use slab::Slab;
use std::io::Write; use std::io::Write;
pub type PluginKey = usize;
pub enum Event {
Request(Request),
Response((PluginKey, PluginResponse)),
PluginExit(PluginKey),
Help(async_oneshot::Sender<Slab<PluginHelp>>),
}
pub struct PluginHelp {
pub name: String,
pub description: String,
pub help: Option<String>,
}
pub struct Service<O> { pub struct Service<O> {
active_search: Vec<(PluginKey, SearchMeta)>, active_search: Vec<(PluginKey, PluginSearchResult)>,
awaiting_results: usize, awaiting_results: usize,
last_query: String, last_query: String,
output: O, output: O,
@ -172,7 +190,7 @@ impl<O: Write> Service<O> {
} }
} }
fn append(&mut self, plugin: PluginKey, append: SearchMeta) { fn append(&mut self, plugin: PluginKey, append: PluginSearchResult) {
self.active_search.push((plugin, append)); self.active_search.push((plugin, append));
} }
@ -303,7 +321,7 @@ impl<O: Write> Service<O> {
} }
/// From a given position ID, fetch the search result and its associated plugin /// From a given position ID, fetch the search result and its associated plugin
fn search_result(&mut self, id: usize) -> Option<(&mut PluginConnector, &mut SearchMeta)> { fn search_result(&mut self, id: usize) -> Option<(&mut PluginConnector, &mut PluginSearchResult)> {
let &mut Self { let &mut Self {
ref mut active_search, ref mut active_search,
ref mut plugins, ref mut plugins,
@ -334,7 +352,7 @@ impl<O: Write> Service<O> {
*no_sort = false; *no_sort = false;
} else { } else {
active_search.sort_by(|a, b| { active_search.sort_by(|a, b| {
fn calculate_weight(meta: &SearchMeta, query: &str) -> usize { fn calculate_weight(meta: &PluginSearchResult, query: &str) -> usize {
let mut weight = 0; let mut weight = 0;
let name = meta.name.to_ascii_lowercase(); let name = meta.name.to_ascii_lowercase();

View file

@ -1,5 +1,5 @@
use crate::{Event, IconSource, Plugin, PluginConfig, PluginQuery, PluginResponse, SearchMeta}; use crate::*;
use pop_launcher::*;
use flume::Sender; use flume::Sender;
use slab::Slab; use slab::Slab;
use std::borrow::Cow; use std::borrow::Cow;
@ -19,13 +19,6 @@ pub const CONFIG: PluginConfig = PluginConfig {
}, },
icon: Some(IconSource::Name(Cow::Borrowed("system-help-symbolic"))), icon: Some(IconSource::Name(Cow::Borrowed("system-help-symbolic"))),
}; };
pub struct PluginHelp {
pub name: String,
pub description: String,
pub help: Option<String>,
}
pub struct HelpPlugin { pub struct HelpPlugin {
pub details: Slab<PluginHelp>, pub details: Slab<PluginHelp>,
pub internal: Sender<Event>, pub internal: Sender<Event>,
@ -78,7 +71,7 @@ impl Plugin for HelpPlugin {
if detail.help.is_some() { if detail.help.is_some() {
let _ = self let _ = self
.tx .tx
.send_async(PluginResponse::Append(SearchMeta { .send_async(PluginResponse::Append(PluginSearchResult {
id: id as u32, id: id as u32,
name: detail.name.clone(), name: detail.name.clone(),
description: detail.description.clone(), description: detail.description.clone(),

View file

@ -4,9 +4,9 @@ pub mod help;
pub use self::config::{PluginBinary, PluginConfig, PluginQuery}; pub use self::config::{PluginBinary, PluginConfig, PluginQuery};
pub use self::external::ExternalPlugin; pub use self::external::ExternalPlugin;
pub use self::help::{HelpPlugin, PluginHelp}; pub use self::help::HelpPlugin;
use crate::Request; use crate::{PluginHelp, Request};
use async_trait::async_trait; use async_trait::async_trait;
use flume::{Receiver, Sender}; use flume::{Receiver, Sender};
use regex::Regex; use regex::Regex;

View file

@ -1,7 +1,7 @@
use futures_codec::{FramedRead, LinesCodec}; use futures_codec::{FramedRead, LinesCodec};
use futures_lite::{AsyncRead, Stream, StreamExt}; use futures_lite::{AsyncRead, Stream, StreamExt};
use serde::Deserialize; use serde::Deserialize;
use smol::Unblock; use blocking::Unblock;
use std::io; use std::io;
/// stdin with AsyncRead support /// stdin with AsyncRead support

View file

@ -1,115 +1,124 @@
mod codec; mod codec;
mod plugins;
mod service;
pub use self::codec::*; pub use self::codec::*;
pub use self::plugins::*;
pub use self::service::Service;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use slab::Slab;
use std::{borrow::Cow, path::PathBuf}; use std::{borrow::Cow, path::PathBuf};
pub type PluginKey = usize; /// u32 value defining the generation of an indice.
pub type Generation = u32; pub type Generation = u32;
pub type Indice = u32;
pub enum Event { /// u32 value defining the indice of a slot.
Request(Request), pub type Indice = u32;
Response((PluginKey, PluginResponse)),
PluginExit(PluginKey),
Help(async_oneshot::Sender<Slab<PluginHelp>>),
}
#[derive(Debug, Clone, Deserialize, Serialize)] #[derive(Debug, Clone, Deserialize, Serialize)]
pub enum IconSource { pub enum IconSource {
// Locate by name or path // Locate by name or path.
Name(Cow<'static, str>), Name(Cow<'static, str>),
// Icon is a mime type // Icon is a mime type.
Mime(Cow<'static, str>), Mime(Cow<'static, str>),
// Window Entity ID // Window Entity ID.
Window((Generation, Indice)), Window((Generation, Indice)),
} }
// Launcher frontends shall send these requests to the launcher service. /// Sent from a plugin to the launcher service.
#[derive(Debug, Deserialize, Serialize)]
pub enum PluginResponse {
/// Append a new search item to the launcher.
Append(PluginSearchResult),
/// Clear all results in the launcher list.
Clear,
/// Close the launcher.
Close,
// Notifies that a .desktop entry should be launched by the frontend.
DesktopEntry(PathBuf),
/// Update the text in the launcher.
Fill(String),
/// Indicoates that a plugin is finished with its queries.
Finished,
}
/// Search information from a plugin to be sorted and filtered by the launcher service.
#[derive(Debug, Default, Deserialize, Serialize)]
pub struct PluginSearchResult {
/// Numeric identifier tracked by the plugin.
pub id: Indice,
/// The name / title.
pub name: String,
/// The description / subtitle.
pub description: String,
/// Extra words to match when sorting and filtering.
pub keywords: Option<Vec<String>>,
/// Icon to display in the frontend.
pub icon: Option<IconSource>,
/// Command that is executed by this result, used for sorting and filtering.
pub exec: Option<String>,
/// Designates that this search item refers to a window.
pub window: Option<(Generation, Indice)>,
}
// Sent to the input pipe of the launcher service, and disseminated to its plugins.
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
pub enum Request { pub enum Request {
/// Activate on the selected item /// Activate on the selected item.
Activate(Indice), Activate(Indice),
/// Perform a tab completion from the selected item /// Perform a tab completion from the selected item.
Complete(Indice), Complete(Indice),
/// Request to end the service /// Request to end the service.
Exit, Exit,
/// Requests to cancel any active searches /// Requests to cancel any active searches.
Interrupt, Interrupt,
/// Request to close the selected item /// Request to close the selected item.
Quit(Indice), Quit(Indice),
/// Perform a search in our database /// Perform a search in our database.
Search(String), Search(String),
} }
/// Launcher frontends shall react to these responses from the launcher service. /// Sent from the launcher service to a frontend.
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
pub enum Response { pub enum Response {
// An operation was performed and the frontend may choose to exit its process. // An operation was performed and the frontend may choose to exit its process.
Close, Close,
// Notifies that a .desktop entry should be launched by the frontend // Notifies that a .desktop entry should be launched by the frontend.
DesktopEntry(PathBuf), DesktopEntry(PathBuf),
// The frontend should clear its search results and display a new list // The frontend should clear its search results and display a new list.
Update(Vec<SearchResult>), Update(Vec<SearchResult>),
// An item was selected that resulted in a need to autofill the launcher // An item was selected that resulted in a need to autofill the launcher.
Fill(String), Fill(String),
} }
#[derive(Debug, Deserialize, Serialize)]
pub enum PluginResponse {
/// Append a new search item to the launcher
Append(SearchMeta),
/// Clear all results in the launcher list
Clear,
/// Close the launcher
Close,
// Notifies that a .desktop entry should be launched by the frontend
DesktopEntry(PathBuf),
/// Update the text in the launcher
Fill(String),
/// Indicoates that a plugin is finished with its queries
Finished,
}
#[derive(Debug, Default, Deserialize, Serialize)]
pub struct SearchMeta {
pub id: Indice,
pub name: String,
pub description: String,
pub keywords: Option<Vec<String>>,
pub icon: Option<IconSource>,
pub exec: Option<String>,
pub window: Option<(Generation, Indice)>,
}
/// Serialized response to launcher frontend about a search result. /// Serialized response to launcher frontend about a search result.
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct SearchResult { pub struct SearchResult {
/// Numeric identifier tracked by the plugin.
pub id: Indice, pub id: Indice,
/// The name / title.
pub name: String, pub name: String,
/// The description / subtitle.
pub description: String, pub description: String,
#[serde( #[serde(
default, default,
skip_serializing_if = "Option::is_none", skip_serializing_if = "Option::is_none",
with = "::serde_with::rust::unwrap_or_skip" with = "::serde_with::rust::unwrap_or_skip"
)] )]
/// Icon to display in the frontend for this item
pub icon: Option<IconSource>, pub icon: Option<IconSource>,
#[serde( #[serde(
default, default,
skip_serializing_if = "Option::is_none", skip_serializing_if = "Option::is_none",
with = "::serde_with::rust::unwrap_or_skip" with = "::serde_with::rust::unwrap_or_skip"
)] )]
/// Icon to display in the frontend for this plugin
pub category_icon: Option<IconSource>, pub category_icon: Option<IconSource>,
#[serde( #[serde(
default, default,
skip_serializing_if = "Option::is_none", skip_serializing_if = "Option::is_none",
with = "::serde_with::rust::unwrap_or_skip" with = "::serde_with::rust::unwrap_or_skip"
)] )]
/// Designates that this search item refers to a window.
pub window: Option<(Generation, Indice)>, pub window: Option<(Generation, Indice)>,
} }

View file

@ -1,12 +0,0 @@
use pop_launcher::Service;
use std::io;
fn main() {
tracing_subscriber::fmt()
.with_writer(io::stderr)
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
.init();
let stdout = io::stdout();
smol::block_on(Service::new(stdout.lock()).exec());
}