Refactor `provide_file_decoration` to return a `Promise` resolved by `event_loop`
Dependencies
- [2]
WFWTKCJNCreate initial Visual Studio Code extension - [3]
LQJG2LGQRefactor `PathState` handling to be updated incrementally - [4]
3YGYMEXVCreate `event_loop` module - [5]
LSZTPUQTUpgrade `napi` to latest version - [6]
NB2MF3MYAdd `OpenWorkspaceFolder` event - [7]
MGJ23FHFAssign repository URI to source control in `OpenWorkspaceFolder` events - [8]
OUADGWKRCreate fully-initialized `SourceControl` object in `event_loop` - [9]
2ZAM5V35Move event handling into modules - [10]
SLTXBK5GRecursively discover repositories when handling `OpenWorkspaceFolder` event - [11]
QY4Z5ZXZRefactor `event_loop/threadsafe_function` file into `event_loop::js_function` module - [12]
IDY5SNLOUpdate source control resource states in event loop - [13]
T4NQUSRPEmit events on file decoration change - [14]
72K45XKDRefactor inline credit to improve hover messages - [15]
TWPZLEGDReturn correct file contents for quick diff
Change contents
- edit in editors/vscode/src/lib.rs at line 19
use iri_string::types::UriAbsoluteString; - edit in editors/vscode/src/lib.rs at line 22
use pijul_extension::path_state::{PathState, TrackedState}; - edit in editors/vscode/src/lib.rs at line 53
#[tracing::instrument(skip_all)] - replacement in editors/vscode/src/lib.rs at line 58
) -> Result<Option<vscode_sys::FileDecoration<'env>>, napi::Error> {let program_state = ExtensionState::get()?;let Some((repository_path, open_repository)) =program_state.repositories.get_open_repository(env, &uri)?else {return Ok(None);};let absolute_file_path = Utf8PathBuf::from(uri.get_fs_path()?);let relative_file_path =absolute_file_path.strip_prefix(&repository_path).map_err(|error| {napi::Error::from_reason(format!("Failed to strip prefix {repository_path} from {absolute_file_path}: {error}"))})?;let Some(path_state) = open_repository.repository.get_path_state(relative_file_path)else {return Ok(None);};// TODO: l10n_embedlet (badge, tooltip, color_id) = match path_state {PathState::Untracked => ("U", "Untracked", "pijul.decorations.path.untracked"),PathState::Tracked(modified_state) => match modified_state {TrackedState::Added => ("A", "Added", "pijul.decorations.path.added"),TrackedState::Removed => ("RM", "Removed", "pijul.decorations.path.removed"),TrackedState::Modified => ("M", "Modified", "pijul.decorations.path.modified"),TrackedState::Moved => ("MV", "Moved", "pijul.decorations.path.moved"),TrackedState::ModifiedAndMoved => ("M,MV","Modified, Moved","pijul.decorations.path.modifiedAndMoved",),},};let color = vscode_sys::ThemeColor::new(env, color_id)?;) -> Result<bindgen_prelude::Object<'env>, napi::Error> {let (deferred_promise, promise_object) = env.create_deferred()?;let parsed_uri = UriAbsoluteString::try_from(uri.to_string()?).map_err(|error| napi::Error::from_reason(format!("Failed to parse URI: {error}")))?;event_loop::send(Event::RequestFileDecoration {uri: parsed_uri,deferred_promise,}); - replacement in editors/vscode/src/lib.rs at line 67
let path_decoration = vscode_sys::FileDecoration::new(env, badge, tooltip, &color)?;Ok(Some(path_decoration))Ok(promise_object) - replacement in editors/vscode/src/event_loop/mod.rs at line 5
use camino::Utf8PathBuf;use camino::{Utf8Path, Utf8PathBuf};use iri_string::types::UriAbsoluteStr; - edit in editors/vscode/src/event_loop/mod.rs at line 27
}struct ExtensionState {repositories: HashMap<Utf8PathBuf, Repository>,}impl ExtensionState {#[tracing::instrument(skip(self))]fn find_repository<'uri>(&'uri self,uri: &'uri UriAbsoluteStr,) -> Option<(&'uri Utf8Path, &'uri Repository)> {if uri.scheme_str() != "file" {return None;}for ancestor in Utf8Path::new(uri.path_str()).ancestors() {if let Some(repository) = self.repositories.get(ancestor) {return Some((ancestor, repository));}}None} - replacement in editors/vscode/src/event_loop/mod.rs at line 61
let mut repositories: HashMap<Utf8PathBuf, Repository> = HashMap::new();let mut extension_state = ExtensionState {repositories: HashMap::new(),}; - replacement in editors/vscode/src/event_loop/mod.rs at line 81
&mut repositories,&mut extension_state, - edit in editors/vscode/src/event_loop/mod.rs at line 87
Event::RequestFileDecoration {uri,deferred_promise,} => {event::request_file_decoration::handle(uri, deferred_promise, &extension_state).await} - replacement in editors/vscode/src/event_loop/mod.rs at line 97
&repositories,&extension_state, - edit in editors/vscode/src/event_loop/mod.rs at line 105
tracing::debug!(?event_buffer); - edit in editors/vscode/src/event_loop/event/update_resource_states.rs at line 1
use std::collections::HashMap; - replacement in editors/vscode/src/event_loop/event/update_resource_states.rs at line 3
use crate::event_loop::Repository;use crate::event_loop::ExtensionState; - replacement in editors/vscode/src/event_loop/event/update_resource_states.rs at line 6
#[tracing::instrument(skip(repositories, js_functions))]#[tracing::instrument(skip(extension_state, js_functions))] - replacement in editors/vscode/src/event_loop/event/update_resource_states.rs at line 9
repositories: &HashMap<Utf8PathBuf, Repository>,extension_state: &ExtensionState, - replacement in editors/vscode/src/event_loop/event/update_resource_states.rs at line 12
let Some(repository) = repositories.get(&repository_path) else {let Some(repository) = extension_state.repositories.get(&repository_path) else { - file addition: request_file_decoration.rs[9.332]
use camino::Utf8Path;use iri_string::types::{UriAbsoluteStr, UriAbsoluteString};use pijul_extension::path_state::{PathState, TrackedState};use crate::event_loop::ExtensionState;use crate::vscode_sys;pub type DeferredPromise = napi::JsDeferred<Option<vscode_sys::reference::FileDecorationRef>,Box<dyn FnOnce(napi::Env,)-> Result<Option<vscode_sys::reference::FileDecorationRef>, napi::Error>,>,>;#[tracing::instrument(skip(deferred_promise, extension_state))]pub async fn handle(uri: UriAbsoluteString,deferred_promise: DeferredPromise,extension_state: &ExtensionState,) {let optional_path_state = get_decoration(&uri, extension_state);deferred_promise.resolve(Box::new(move |env| {let Some(path_state) = optional_path_state else {return Ok(None);};// TODO: l10n_embedlet (badge, tooltip, color_id) = match path_state {PathState::Untracked => ("U", "Untracked", "pijul.decorations.path.untracked"),PathState::Tracked(modified_state) => match modified_state {TrackedState::Added => ("A", "Added", "pijul.decorations.path.added"),TrackedState::Removed => ("RM", "Removed", "pijul.decorations.path.removed"),TrackedState::Modified => ("M", "Modified", "pijul.decorations.path.modified"),TrackedState::Moved => ("MV", "Moved", "pijul.decorations.path.moved"),TrackedState::ModifiedAndMoved => ("M,MV","Modified, Moved","pijul.decorations.path.modifiedAndMoved",),},};let color = vscode_sys::ThemeColor::new(&env, color_id)?;let path_decoration = vscode_sys::FileDecoration::new(&env, badge, tooltip, &color)?;Ok(Some(path_decoration.create_ref()?))}));}fn get_decoration(uri: &UriAbsoluteStr, extension_state: &ExtensionState) -> Option<PathState> {if uri.scheme_str() != "file" {return None;}let Some((repository_path, repository)) = extension_state.find_repository(uri) else {tracing::info!(message = "No matching repository for path", ?uri);return None;};let decoration_path = match Utf8Path::new(uri.path_str()).strip_prefix(repository_path) {Ok(decoration_path) => decoration_path,Err(error) => {tracing::error!(message = "Failed to strip repository prefix from path",?repository_path,?uri,?error);return None;}};repository.repository.get_path_state(decoration_path)} - replacement in editors/vscode/src/event_loop/event/open_workspace_folder.rs at line 9
use crate::event_loop::{Event, Repository};use crate::event_loop::{Event, ExtensionState, Repository}; - replacement in editors/vscode/src/event_loop/event/open_workspace_folder.rs at line 11
#[tracing::instrument(skip(repositories, js_functions))]#[tracing::instrument(skip(extension_state, js_functions, sender))] - replacement in editors/vscode/src/event_loop/event/open_workspace_folder.rs at line 14
repositories: &mut HashMap<Utf8PathBuf, Repository>,extension_state: &mut ExtensionState, - replacement in editors/vscode/src/event_loop/event/open_workspace_folder.rs at line 82
repositories.entry(repository_path.clone())extension_state.repositories.entry(repository_path.clone()) - edit in editors/vscode/src/event_loop/event/mod.rs at line 2
use iri_string::types::UriAbsoluteString; - edit in editors/vscode/src/event_loop/event/mod.rs at line 5
pub mod request_file_decoration; - edit in editors/vscode/src/event_loop/event/mod.rs at line 8
#[derive(Debug)] - replacement in editors/vscode/src/event_loop/event/mod.rs at line 9
OpenWorkspaceFolder { uri: String },UpdateResourceStates { repository_path: Utf8PathBuf },OpenWorkspaceFolder {uri: String,},RequestFileDecoration {uri: UriAbsoluteString,deferred_promise: request_file_decoration::DeferredPromise,},UpdateResourceStates {repository_path: Utf8PathBuf,}, - replacement in Cargo.toml at line 42
napi = { version = "3.7", features = ["napi5"] }napi = { version = "3.7", features = ["napi5", "deferred_trace"] }