Add `ChangedFilesystemContents` event

finchie
Jan 2, 2026, 12:11 PM
XRFRJHZM4TEIQCSEEESJG3SCPFRLJRHOWHVCGW5744YBKF6ONW2AC

Dependencies

  • [2] WFWTKCJN Create initial Visual Studio Code extension
  • [3] 72K45XKD Refactor inline credit to improve hover messages
  • [4] VKCHFDMC Create simple `FileSystemWatcher`
  • [5] T4NQUSRP Emit events on file decoration change
  • [6] 57DXWD6G Handle file rename/move events in VS Code extension
  • [7] 3YGYMEXV Create `event_loop` module
  • [8] NB2MF3MY Add `OpenWorkspaceFolder` event
  • [9] OUADGWKR Create fully-initialized `SourceControl` object in `event_loop`
  • [10] 2ZAM5V35 Move event handling into modules
  • [11] QY4Z5ZXZ Refactor `event_loop/threadsafe_function` file into `event_loop::js_function` module
  • [12] IBVCQSSG Use `External` to wrap `initialize_source_control` arguments
  • [13] IDY5SNLO Update source control resource states in event loop
  • [14] 3RNQI5RX Refactor `provide_file_decoration` to return a `Promise` resolved by `event_loop`
  • [15] M5RW5PN4 Add `OpenTextEditor` event
  • [16] QY4DF3NM Add `ChangeEditorContents` event
  • [17] 3TWMKU4M Add `RequestInlineCredit` event
  • [18] MGJ23FHF Assign repository URI to source control in `OpenWorkspaceFolder` events
  • [19] XDFSAPI7 Create a tokio runtime directly instead of `#[tokio::main]`

Change contents

  • edit in editors/vscode/src/lib.rs at line 38
    [2.109730][5.2067:2144]()
    decoration_change_event_emitter: vscode_sys::reference::EventEmitterRef,
  • replacement in editors/vscode/src/lib.rs at line 251
    [4.653][4.653:813](),[4.813][5.2145:2270]()
    pub fn handle_fs_watcher_event(env: &napi::Env, uri: vscode_sys::Uri) -> Result<(), napi::Error> {
    let mut extension_state = crate::ExtensionState::get()?;
    let decoration_change_event_emitter = extension_state
    .decoration_change_event_emitter
    .get_inner(env)?;
    [4.653]
    [4.813]
    pub fn handle_fs_watcher_event(
    _env: &napi::Env,
    vscode_uri: vscode_sys::Uri,
    ) -> Result<(), napi::Error> {
    let uri = uri::from_vscode(&vscode_uri)?;
    event_loop::send(Event::ChangedFilesystemContents { uri });
  • edit in editors/vscode/src/lib.rs at line 258
    [4.814][4.814:1367](),[4.1367][2.117875:117876](),[2.117875][2.117875:117876](),[2.117876][4.1368:1607](),[4.1607][5.2271:2329](),[5.2329][4.1607:1679](),[4.1607][4.1607:1679](),[4.1679][6.574:580](),[6.580][6.580:581]()
    if let Some((repository_path, open_repository)) = extension_state
    .repositories
    .get_open_repository_mut(env, &uri)?
    {
    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}"
    ))
    })?
    .to_path_buf();
    open_repository
    .repository
    .update_path_state(relative_file_path)
    .map_err(|error| {
    napi::Error::from_reason(format!("Failed to update path state: {error:?}"))
    })?;
    decoration_change_event_emitter.fire(uri.inner)?;
    open_repository.update_resource_states(env, &repository_path)?;
    }
  • edit in editors/vscode/src/lib.rs at line 267
    [6.800][6.800:925]()
    let decoration_change_event_emitter = extension_state
    .decoration_change_event_emitter
    .get_inner(env)?;
  • edit in editors/vscode/src/lib.rs at line 305
    [6.2525][6.2525:2591]()
    decoration_change_event_emitter.fire(new_uri.inner)?;
  • edit in editors/vscode/src/lib.rs at line 337
    [2.118516]
    [2.118516]
    let decoration_change_event_emitter = vscode_sys::EventEmitter::new(env)?;
    let decoration_change_event = decoration_change_event_emitter.get_event()?;
  • replacement in editors/vscode/src/lib.rs at line 341
    [2.118517][9.0:45]()
    event_loop::start(env, &vscode_object)?;
    [2.118517]
    [7.114]
    event_loop::start(env, &vscode_object, decoration_change_event_emitter)?;
  • replacement in editors/vscode/src/lib.rs at line 357
    [5.2331][5.2331:2490](),[3.947][2.118947:118948](),[5.2490][2.118947:118948](),[2.118947][2.118947:118948](),[2.118948][2.118948:118991](),[2.119047][5.2491:2579](),[5.2579][2.119047:119076](),[2.119047][2.119047:119076]()
    let decoration_change_event_emitter = vscode_sys::EventEmitter::new(env)?;
    let decoration_change_event = decoration_change_event_emitter.get_event()?;
    let extension_state = ExtensionState {
    decoration_change_event_emitter: decoration_change_event_emitter.create_ref()?,
    repositories,
    };
    [2.118878]
    [2.119076]
    let extension_state = ExtensionState { repositories };
  • edit in editors/vscode/src/event_loop/mod.rs at line 30
    [14.605]
    [17.1243]
    decoration_change_event_emitter: Rc<vscode_sys::reference::EventEmitterRef>,
  • edit in editors/vscode/src/event_loop/mod.rs at line 89
    [13.201]
    [17.1372]
    decoration_change_event_emitter: vscode_sys::reference::EventEmitterRef,
  • edit in editors/vscode/src/event_loop/mod.rs at line 98
    [14.1221]
    [17.1446]
    decoration_change_event_emitter: Rc::new(decoration_change_event_emitter),
  • edit in editors/vscode/src/event_loop/mod.rs at line 140
    [16.1232]
    [17.1635]
    }
    Event::ChangedFilesystemContents { uri } => {
    event::changed_filesystem_contents::handle(
    uri,
    &mut extension_state,
    &js_functions,
    )
    .await
  • edit in editors/vscode/src/event_loop/mod.rs at line 185
    [9.5456]
    [9.5456]
    decoration_change_event_emitter: vscode_sys::EventEmitter,
  • edit in editors/vscode/src/event_loop/mod.rs at line 187
    [9.5487]
    [11.251]
    let decoration_change_event_emitter_ref = decoration_change_event_emitter.create_ref()?;
    let decoration_type = crate::inline_credit::create_decoration_type(env)?.create_ref()?;
  • edit in editors/vscode/src/event_loop/mod.rs at line 190
    [11.324][17.1811:1903]()
    let decoration_type = crate::inline_credit::create_decoration_type(env)?.create_ref()?;
  • replacement in editors/vscode/src/event_loop/mod.rs at line 202
    [17.1937][17.1937:2023]()
    runtime.block_on(event_loop(decoration_type, js_functions, sender, receiver))
    [17.1937]
    [17.2023]
    runtime.block_on(event_loop(
    decoration_change_event_emitter_ref,
    decoration_type,
    js_functions,
    sender,
    receiver,
    ))
  • edit in editors/vscode/src/event_loop/js_function/mod.rs at line 4
    [13.3343]
    [12.0]
    use iri_string::types::UriAbsoluteString;
  • edit in editors/vscode/src/event_loop/js_function/mod.rs at line 10
    [8.833]
    [15.2177]
    pub mod fire_decoration_change_event;
  • edit in editors/vscode/src/event_loop/js_function/mod.rs at line 19
    [11.510]
    [15.2212]
    fire_decoration_change_event: fire_decoration_change_event::Prototype,
  • edit in editors/vscode/src/event_loop/js_function/mod.rs at line 32
    [8.1076]
    [15.2280]
    fire_decoration_change_event: fire_decoration_change_event::build(env)?,
  • edit in editors/vscode/src/event_loop/js_function/mod.rs at line 43
    [15.2365]
    [15.2365]
    pub async fn fire_decoration_change_event(
    &self,
    uri: UriAbsoluteString,
    event_emitter_reference: &Rc<vscode_sys::reference::EventEmitterRef>,
    ) -> Result<(), napi::Error> {
    let arguments = fire_decoration_change_event::Arguments {
    uri,
    event_emitter_reference: Rc::clone(event_emitter_reference),
    };
    self.fire_decoration_change_event
    .call_async(External::new(arguments))
    .await
    }
  • file addition: fire_decoration_change_event.rs (----------)
    [11.435]
    use std::rc::Rc;
    use iri_string::types::UriAbsoluteString;
    use napi::bindgen_prelude::{External, FunctionCallContext};
    use napi::threadsafe_function::ThreadsafeFunction;
    use crate::vscode_sys;
    pub struct Arguments {
    pub uri: UriAbsoluteString,
    pub event_emitter_reference: Rc<vscode_sys::reference::EventEmitterRef>,
    }
    pub type Prototype =
    ThreadsafeFunction<External<Arguments>, (), External<Arguments>, napi::Status, false, false, 0>;
    pub fn build(env: &napi::Env) -> Result<Prototype, napi::Error> {
    env.create_function_from_closure("fire_event", callback)?
    .build_threadsafe_function()
    .build()
    }
    fn callback(function_call_context: FunctionCallContext) -> Result<(), napi::Error> {
    let (external,): (&External<Arguments>,) = function_call_context.args()?;
    let Arguments {
    uri,
    event_emitter_reference,
    } = &**external;
    let event_emitter = event_emitter_reference.get_inner(function_call_context.env)?;
    let vscode_uri = crate::uri::to_vscode(function_call_context.env, uri)?;
    event_emitter.fire(vscode_uri.inner)
    }
  • edit in editors/vscode/src/event_loop/event/mod.rs at line 7
    [16.1265]
    [15.5913]
    pub mod changed_filesystem_contents;
  • edit in editors/vscode/src/event_loop/event/mod.rs at line 33
    [16.1530]
    [17.13133]
    },
    ChangedFilesystemContents {
    uri: UriAbsoluteString,
  • file addition: changed_filesystem_contents.rs (----------)
    [10.332]
    use iri_string::types::UriAbsoluteString;
    use crate::event_loop::ExtensionState;
    use crate::event_loop::js_function::Functions;
    #[tracing::instrument(skip(extension_state, js_functions))]
    pub async fn handle(
    uri: UriAbsoluteString,
    extension_state: &mut ExtensionState,
    js_functions: &Functions,
    ) {
    let Some((_repository_path, relative_path, repository)) =
    extension_state.get_repository_mut(&uri)
    else {
    tracing::info!(message = "Ignoring filesystem changes");
    return;
    };
    match repository
    .repository
    .update_path_state(relative_path.to_path_buf())
    {
    Ok(()) => tracing::debug!(message = "Updated path state"),
    Err(error) => {
    tracing::error!(
    message = "Failed to update path states",
    ?relative_path,
    ?error
    );
    return;
    }
    }
    match js_functions
    .fire_decoration_change_event(uri, &extension_state.decoration_change_event_emitter)
    .await
    {
    Ok(()) => {
    tracing::debug!(message = "Fired onDidChangeFileDecorations");
    }
    Err(error) => {
    tracing::warn!(
    message = "Failed to fire onDidChangeFileDecorations",
    ?error
    );
    }
    }
    }