2021-08-30 18:28:50 +02:00
|
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
|
// Copyright © 2021 System76
|
|
|
|
|
|
2021-08-23 20:04:10 +02:00
|
|
|
use futures_lite::prelude::*;
|
2021-08-24 21:56:42 +02:00
|
|
|
use gtk::prelude::*;
|
2021-08-23 20:04:10 +02:00
|
|
|
use pop_launcher::*;
|
2021-08-24 21:56:42 +02:00
|
|
|
use slab::Slab;
|
2021-08-23 20:04:10 +02:00
|
|
|
use smol::Unblock;
|
2021-08-24 21:56:42 +02:00
|
|
|
use std::{borrow::Cow, io};
|
2021-08-23 20:04:10 +02:00
|
|
|
|
|
|
|
|
pub struct App {
|
2021-08-24 21:56:42 +02:00
|
|
|
manager: gtk::RecentManager,
|
2021-08-23 20:04:10 +02:00
|
|
|
out: Unblock<io::Stdout>,
|
2021-08-24 21:56:42 +02:00
|
|
|
uris: Slab<String>,
|
2021-08-23 20:04:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Default for App {
|
|
|
|
|
fn default() -> Self {
|
|
|
|
|
Self {
|
2021-08-24 21:56:42 +02:00
|
|
|
manager: gtk::RecentManager::new(),
|
2021-08-23 20:04:10 +02:00
|
|
|
out: async_stdout(),
|
2021-08-24 21:56:42 +02:00
|
|
|
uris: Slab::new(),
|
2021-08-23 20:04:10 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub async fn main() {
|
2021-08-24 21:56:42 +02:00
|
|
|
if gtk::init().is_err() {
|
|
|
|
|
tracing::error!("failed to initialize GTK");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-23 20:04:10 +02:00
|
|
|
let mut requests = json_input_stream(async_stdin());
|
|
|
|
|
|
|
|
|
|
let mut app = App::default();
|
|
|
|
|
|
|
|
|
|
while let Some(result) = requests.next().await {
|
|
|
|
|
match result {
|
|
|
|
|
Ok(request) => match request {
|
|
|
|
|
Request::Activate(id) => app.activate(id).await,
|
|
|
|
|
Request::Search(query) => app.search(query).await,
|
|
|
|
|
Request::Exit => break,
|
|
|
|
|
_ => (),
|
|
|
|
|
},
|
|
|
|
|
Err(why) => {
|
|
|
|
|
tracing::error!("malformed JSON input: {}", why);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl App {
|
2021-08-24 21:56:42 +02:00
|
|
|
async fn activate(&mut self, id: u32) {
|
|
|
|
|
if let Some(uri) = self.uris.get(id as usize) {
|
|
|
|
|
crate::xdg_open(uri);
|
|
|
|
|
crate::send(&mut self.out, PluginResponse::Close).await;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-08-23 20:04:10 +02:00
|
|
|
|
|
|
|
|
async fn search(&mut self, query: String) {
|
2021-08-24 21:56:42 +02:00
|
|
|
self.uris.clear();
|
|
|
|
|
if let Some(query) = normalized(&query) {
|
|
|
|
|
for item in self.manager.items() {
|
|
|
|
|
if let Some(name) = item.display_name() {
|
|
|
|
|
if name.to_ascii_lowercase().contains(&query) {
|
|
|
|
|
if let Some((mime, uri)) = item.mime_type().zip(item.uri()) {
|
|
|
|
|
let id = self.uris.insert(uri.to_string());
|
|
|
|
|
crate::send(
|
|
|
|
|
&mut self.out,
|
|
|
|
|
PluginResponse::Append(PluginSearchResult {
|
|
|
|
|
id: id as u32,
|
|
|
|
|
name: name.to_string(),
|
|
|
|
|
description: item
|
|
|
|
|
.uri_display()
|
|
|
|
|
.map(String::from)
|
|
|
|
|
.unwrap_or_default(),
|
|
|
|
|
icon: Some(IconSource::Mime(Cow::Owned(mime.to_string()))),
|
|
|
|
|
..Default::default()
|
|
|
|
|
}),
|
|
|
|
|
)
|
|
|
|
|
.await;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-08-23 20:04:10 +02:00
|
|
|
|
2021-08-24 21:56:42 +02:00
|
|
|
crate::send(&mut self.out, PluginResponse::Finished).await;
|
2021-08-23 20:04:10 +02:00
|
|
|
}
|
|
|
|
|
}
|
2021-08-24 21:56:42 +02:00
|
|
|
|
|
|
|
|
fn normalized(input: &str) -> Option<String> {
|
|
|
|
|
input
|
|
|
|
|
.find(' ')
|
|
|
|
|
.map(|pos| input[pos + 1..].trim().to_ascii_lowercase())
|
|
|
|
|
}
|