Skip to content
This repository has been archived by the owner on Mar 31, 2024. It is now read-only.

Commit

Permalink
Merge pull request #55 from swsnr/always-refresh
Browse files Browse the repository at this point in the history
Always refresh recent projects when searching
  • Loading branch information
swsnr authored Feb 12, 2024
2 parents caa500e + ea9c17f commit a82533e
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 115 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ and this project doesn't really care for versioning.

## [Unreleased]

### Changed
- Refresh recent projects (see [GH-55]).

### Removed
- Reload interface and `systemctl reload` support (see [GH-55]).

[GH-55]: https://github.com/swsnr/gnome-search-providers-jetbrains/pull/55

## [1.16.0] – 2023-09-30

### Added
Expand Down
6 changes: 1 addition & 5 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,11 @@ use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::Registry;

use providers::*;
use reload::*;
use searchprovider::*;

mod config;
mod launch;
mod providers;
mod reload;
mod searchprovider;
mod systemd;

Expand Down Expand Up @@ -106,11 +104,10 @@ fn main() -> Result<()> {
.filter_map(|provider| {
gio::DesktopAppInfo::new(provider.desktop_id).map(|gio_app| {
event!(Level::INFO, "Found app {}", provider.desktop_id);
let mut search_provider = JetbrainsProductSearchProvider::new(
let search_provider = JetbrainsProductSearchProvider::new(
App::from(gio_app),
&provider.config,
);
let _ = search_provider.reload_recent_projects();
(provider.objpath(), search_provider)
})
})
Expand All @@ -129,7 +126,6 @@ fn main() -> Result<()> {
builder.serve_at(path, provider)
},
)?
.serve_at("/", ReloadAll)?
.serve_log_control(LogControl1::new(control))?
.name(BUSNAME)?
.build()
Expand Down
65 changes: 0 additions & 65 deletions src/reload.rs

This file was deleted.

101 changes: 57 additions & 44 deletions src/searchprovider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,33 @@ async fn launch_app_in_new_scope(
})
}

/// Calculate how well `recent_projects` matches all of the given `terms`.
///
/// If all terms match the name of the `recent_projects`, the project receives a base score of 10.
/// If all terms match the directory of the `recent_projects`, the project gets scored for each
/// term according to how far right the term appears in the directory, under the assumption that
/// the right most part of a directory path is the most specific.
///
/// All matches are done on the lowercase text, i.e. case insensitve.
fn score_recent_project(recent_project: &JetbrainsRecentProject, terms: &[&str]) -> f64 {
let name = recent_project.name.to_lowercase();
let directory = recent_project.directory.to_lowercase();
terms
.iter()
.try_fold(0.0, |score, term| {
directory
.rfind(&term.to_lowercase())
// We add 1 to avoid returning zero if the term matches right at the beginning.
.map(|index| score + ((index + 1) as f64 / recent_project.directory.len() as f64))
})
.unwrap_or(0.0)
+ if terms.iter().all(|term| name.contains(&term.to_lowercase())) {
10.0
} else {
0.0
}
}

/// A search provider for recent Jetbrains products.
#[derive(Debug)]
pub struct JetbrainsProductSearchProvider {
Expand Down Expand Up @@ -295,11 +322,31 @@ impl JetbrainsProductSearchProvider {
}

/// Reload all recent projects provided by this search provider.
pub fn reload_recent_projects(&mut self) -> Result<()> {
fn reload_recent_projects(&mut self) -> Result<()> {
self.recent_projects = read_recent_projects(self.config, self.app.id())?;
Ok(())
}

/// Find all projects matching the given `terms`.
///
/// Return a list of IDs of matching projects.
fn find_project_ids_by_terms(&self, terms: &[&str]) -> Vec<&str> {
let mut scored_ids = self
.recent_projects
.iter()
.filter_map(|(id, item)| {
let score = score_recent_project(item, terms);
if 0.0 < score {
Some((id.as_ref(), score))
} else {
None
}
})
.collect::<Vec<_>>();
scored_ids.sort_by_key(|(_, score)| -((score * 1000.0) as i64));
scored_ids.into_iter().map(|(id, _)| id).collect()
}

#[instrument(skip(self, connection), fields(app_id = %self.app.id()))]
async fn launch_app_on_default_main_context(
&self,
Expand All @@ -324,33 +371,6 @@ impl JetbrainsProductSearchProvider {
}
}

/// Calculate how well `recent_projects` matches all of the given `terms`.
///
/// If all terms match the name of the `recent_projects`, the project receives a base score of 10.
/// If all terms match the directory of the `recent_projects`, the project gets scored for each
/// term according to how far right the term appears in the directory, under the assumption that
/// the right most part of a directory path is the most specific.
///
/// All matches are done on the lowercase text, i.e. case insensitve.
fn score_recent_project(recent_project: &JetbrainsRecentProject, terms: &[&str]) -> f64 {
let name = recent_project.name.to_lowercase();
let directory = recent_project.directory.to_lowercase();
terms
.iter()
.try_fold(0.0, |score, term| {
directory
.rfind(&term.to_lowercase())
// We add 1 to avoid returning zero if the term matches right at the beginning.
.map(|index| score + ((index + 1) as f64 / recent_project.directory.len() as f64))
})
.unwrap_or(0.0)
+ if terms.iter().all(|term| name.contains(&term.to_lowercase())) {
10.0
} else {
0.0
}
}

/// The DBus interface of the search provider.
///
/// See <https://developer.gnome.org/SearchProvider/> for information.
Expand All @@ -362,22 +382,15 @@ impl JetbrainsProductSearchProvider {
/// and should return an array of result IDs. gnome-shell will call GetResultMetas for (some) of these result
/// IDs to get details about the result that can be be displayed in the result list.
#[instrument(skip(self), fields(app_id = %self.app.id()))]
fn get_initial_result_set(&self, terms: Vec<&str>) -> Vec<&str> {
fn get_initial_result_set(&mut self, terms: Vec<&str>) -> Vec<&str> {
event!(Level::DEBUG, "Reloading recent projects");
if let Err(error) = self.reload_recent_projects() {
// Ignore errors while reloading recent projects, and just resume
// search with what we've got.
event!(Level::ERROR, "Failed to reload recent projects: {}", error);
}
event!(Level::DEBUG, "Searching for {:?}", terms);
let mut scored_ids = self
.recent_projects
.iter()
.filter_map(|(id, item)| {
let score = score_recent_project(item, &terms);
if 0.0 < score {
Some((id.as_ref(), score))
} else {
None
}
})
.collect::<Vec<_>>();
scored_ids.sort_by_key(|(_, score)| -((score * 1000.0) as i64));
let ids = scored_ids.into_iter().map(|(id, _)| id).collect();
let ids = self.find_project_ids_by_terms(&terms);
event!(Level::DEBUG, "Found ids {:?}", ids);
ids
}
Expand All @@ -397,7 +410,7 @@ impl JetbrainsProductSearchProvider {
);
// For simplicity just run the overall search again, and filter out everything not already matched.
let ids = self
.get_initial_result_set(terms)
.find_project_ids_by_terms(&terms)
.into_iter()
.filter(|id| previous_results.contains(id))
.collect();
Expand Down
1 change: 0 additions & 1 deletion systemd/gnome-search-providers-jetbrains.service
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,3 @@ Description=Jetbrains projects search provider for Gnome shell
Type=dbus
BusName=de.swsnr.searchprovider.Jetbrains
ExecStart=gnome-search-providers-jetbrains
ExecReload=busctl --user call de.swsnr.searchprovider.Jetbrains / de.swsnr.searchprovider.ReloadAll ReloadAll

0 comments on commit a82533e

Please sign in to comment.