This should be the last big change of the event loop refactor, and while lots of code has been shuffled around the logic is almost exactly the same, just driven by the event loop instead of the event handlers themselves.
3TWMKU4MTPZAYZ7X3QQBUV3HFMLKQWHCFAP26POW4HTWDND53QHAC WFWTKCJNC4VSURSQWE5FXJGTEJJOCDMQ6LN2O6EW2DNOVT2ZUMRQC 72K45XKDA7R3R4I7ZOMZAA2433VR4SD7C7I5K6PCE6RTYL545GGQC M2NAH3DCKREU74FXJSQDDRA35LP55VVCD6Z2UH5UCAL7TOTFNNQQC DUZBRB3U7ERDXRM6A7NFI4IGUB6IR4V2L7JJSLCQBSJYJDUZQR6AC 6AUGQLIKK6WY3ZB3ZQ4PCN6NXRLP65CLF2YMOTDDAP6QQAIGGELQC T4NQUSRPQAIACUZLVDPXMNISBHKMD73A22H5SGQWIDQZD675VAZAC NB2MF3MYAJ25KNZP3GMHX42LUSBYOX6FTNLIBK3CQ7CMANFZFEGQC XDFSAPI75FQXHD3ZMYBEGROQ35VQC3WQFQ5EJQAWUXTCKR2N62LAC OUADGWKR6A7G3UHCLSC7AWLJIMS45Y56NPVTQ7FENJPYNTAMXXMAC 2ZAM5V35CAQD5MOFPZEGU4ERQ2FM5CL5MB2DOJDW2ZQ74IQFBISQC TWEUQ64DU5ZXAEG67GQSS7GDEZ2O2JR5352WRVIIUK5J7ZOMO5QAC QY4Z5ZXZ7G6DZFCTRPX7D6TIDZ5DHSDTLOWFDANIPUHOEKQRAIXAC IBVCQSSGPKLQTD4T4TAJZRC4LY3G6FP4QWFEBHN5KEFI44ZGGAXQC IDY5SNLOFZ663OCJ2L5NZMFNJXZSGL5O22QQXR5BIV3SJ2VUQIMQC 3RNQI5RXZMXF5N2WKYS3O3G2GTD4TTWDNQ3EBVGUVVKNNOTKQTJAC M5RW5PN4VFYZOKHUFMVWR2XAUAXHUYROVZFTS3RIE7AAUGTVHAEQC QY4DF3NMDBZQ4IJQJIYRWKQ66FWMFQUSASMEBNG5ROXDHTWI2J4QC QJ6EZNXEJE4N5NPDFPXNVDUSR5QZSSIMC3FLQ4XFMDOF2J7M62CAC 3YGYMEXVHOHRQVPC53MVPSLI2ZJM77MBPWNPDDCL56DNCPUC6XTAC // Re-render the inline credit annotationlet text_editor = open_repository.get_text_editor(env, relative_document_path)?.ok_or_else(|| {napi::Error::from_reason(format!("no open text editor for {absolute_document_path}"))})?;
// // Re-render the inline credit annotation// let text_editor = open_repository// .get_text_editor(env, relative_document_path)?// .ok_or_else(|| {// napi::Error::from_reason(format!(// "no open text editor for {absolute_document_path}"// ))// })?;
let program_state = ExtensionState::get()?;inline_credit::render(env, &program_state, &editor)
let uri = uri::from_vscode(&vscode_uri)?;event_loop::send(Event::RequestInlineCredit { uri });Ok(())
}// TODO: different rendering modes? e.g. render only at boundaries between lines, render only on cursors, etcpub fn render(env: &napi::Env,program_state: &ExtensionState,editor: &vscode_sys::TextEditor,) -> Result<(), napi::Error> {let editor_document = editor.get_document()?;let document_uri = editor_document.get_uri()?;let Some((repository_path, open_repository)) = program_state.repositories.get_open_repository(env, &document_uri)?else {tracing::warn!(message = "No repository for URI",uri = document_uri.to_string()?);return Ok(());};let absolute_file_path = Utf8PathBuf::from(document_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 open_file = open_repository.repository.get_open_file(relative_file_path).ok_or_else(|| {napi::Error::from_reason(format!("unable to get open file for {relative_file_path}"))})?;// TODO: don't initialize herelet localization_context = l10n_embed::Context::new(locale!("en-US"), false);let mut decoration_options_list = Vec::new();for editor_selection in editor.get_selections()? {let start_line = editor_selection.get_start()?.get_line()?;let end_line: u32 = editor_selection.get_end()?.get_line()?;let selected_range = (start_line as usize)..=(end_line as usize);let credits = open_file.credit(selected_range);for credit_span in credits {for line in credit_span.lines {let annotation_range = line_annotation::range(env, open_file, line)?;let line_annotation_text = line_annotation::render(&localization_context,&open_repository.repository,&editor_document,open_file,&credit_span.value,)?;let hover_message = hover::render(env,&localization_context,&open_repository.repository,open_file,credit_span.value,)?;let after = vscode_sys::ThemableDecorationAttachmentRenderOptions::new(env)?.content_text(&line_annotation_text)?;let render_options =vscode_sys::DecorationInstanceRenderOptions::new(env)?.after(after)?;let decoration_options =vscode_sys::DecorationOptions::new(env, &annotation_range)?.hover_message(&hover_message)?.render_options(render_options)?;decoration_options_list.push(decoration_options);}}}let decoration_type = program_state.decoration_type.get_inner(env)?;editor.set_decorations(decoration_type, decoration_options_list)?;Ok(())
}pub fn range<'env>(env: &'env napi::Env,open_file: &OpenFile,line: usize,) -> Result<vscode_sys::Range<'env>, napi::Error> {let current_line_contents = open_file.contents.text.get_line(line, ropey::LineType::LF_CR).ok_or_else(|| napi::Error::from_reason(format!("no contents for line {line}")))?;let final_character_offset = current_line_contents.len() as u32;let start = vscode_sys::Position::new(env, line as u32, final_character_offset)?;let end = vscode_sys::Position::new(env, line as u32, final_character_offset)?;vscode_sys::Range::new(env, &start, &end)
use std::rc::Rc;use napi::bindgen_prelude::{External, FunctionCallContext};use napi::threadsafe_function::ThreadsafeFunction;use crate::vscode_sys;pub struct Arguments {pub line_decorations: Vec<crate::inline_credit::LineDecoration>,pub text_editor_reference: Rc<vscode_sys::reference::TextEditorRef>,pub decoration_type_reference: Rc<vscode_sys::reference::TextEditorDecorationTypeRef>,}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("set_text_editor_decorations", callback)?.build_threadsafe_function().build()}fn callback(function_call_context: FunctionCallContext) -> Result<(), napi::Error> {let (external,): (&External<Arguments>,) = function_call_context.args()?;let Arguments {line_decorations,text_editor_reference,decoration_type_reference,} = &**external;let mut decoration_options_list = Vec::with_capacity(line_decorations.len());for crate::inline_credit::LineDecoration {line_number,line_annotation_text,hover_message_text,} in line_decorations{let annotation_line =vscode_sys::Position::new(function_call_context.env, *line_number as u32, u32::MAX)?;let annotation_range = vscode_sys::Range::new(function_call_context.env,&annotation_line,&annotation_line,)?;let mut hover_message =vscode_sys::MarkdownString::new(function_call_context.env, hover_message_text, false)?;hover_message.set_support_html(true)?;let after =vscode_sys::ThemableDecorationAttachmentRenderOptions::new(function_call_context.env)?.content_text(line_annotation_text)?;let render_options =vscode_sys::DecorationInstanceRenderOptions::new(function_call_context.env)?.after(after)?;let decoration_options =vscode_sys::DecorationOptions::new(function_call_context.env, &annotation_range)?.hover_message(&hover_message)?.render_options(render_options)?;decoration_options_list.push(decoration_options);}let text_editor = text_editor_reference.get_inner(function_call_context.env)?;let decoration_type = decoration_type_reference.get_inner(function_call_context.env)?;text_editor.set_decorations(decoration_type, decoration_options_list)?;Ok(())}
.call_async(External::new(arguments)).await}pub async fn get_text_editor_is_dirty(&self,text_editor_reference: &Rc<vscode_sys::reference::TextEditorRef>,) -> Result<bool, napi::Error> {let arguments = get_text_editor_is_dirty::Arguments {text_editor_reference: Rc::clone(text_editor_reference),};self.get_text_editor_is_dirty.call_async(External::new(arguments)).await}pub async fn get_text_editor_selections(&self,text_editor_reference: &Rc<vscode_sys::reference::TextEditorRef>,) -> Result<Vec<(u32, u32)>, napi::Error> {let arguments = get_text_editor_selections::Arguments {text_editor_reference: Rc::clone(text_editor_reference),};self.get_text_editor_selections
.call_async(External::new(arguments)).await}pub async fn set_text_editor_decorations(&self,line_decorations: Vec<crate::inline_credit::LineDecoration>,text_editor_reference: &Rc<vscode_sys::reference::TextEditorRef>,decoration_type_reference: &Rc<vscode_sys::reference::TextEditorDecorationTypeRef>,) -> Result<(), napi::Error> {let arguments = set_text_editor_decorations::Arguments {line_decorations,text_editor_reference: Rc::clone(text_editor_reference),decoration_type_reference: Rc::clone(decoration_type_reference),};self.set_text_editor_decorations
use std::rc::Rc;use napi::bindgen_prelude::{External, FunctionCallContext};use napi::threadsafe_function::ThreadsafeFunction;use crate::vscode_sys;pub struct Arguments {pub text_editor_reference: Rc<vscode_sys::reference::TextEditorRef>,}pub type Prototype = ThreadsafeFunction<External<Arguments>,Vec<(u32, u32)>,External<Arguments>,napi::Status,false,false,0,>;pub fn build(env: &napi::Env) -> Result<Prototype, napi::Error> {env.create_function_from_closure("get_text_editor_selections", callback)?.build_threadsafe_function().build()}fn callback(function_call_context: FunctionCallContext) -> Result<Vec<(u32, u32)>, napi::Error> {let (external,): (&External<Arguments>,) = function_call_context.args()?;let Arguments {text_editor_reference,} = &**external;let text_editor = text_editor_reference.get_inner(function_call_context.env)?;let editor_selections = text_editor.get_selections()?;let mut selections = Vec::with_capacity(editor_selections.len());for editor_selection in text_editor.get_selections()? {let start_line = editor_selection.get_start()?.get_line()?;let end_line = editor_selection.get_end()?.get_line()?;selections.push((start_line, end_line));}Ok(selections)}
use std::rc::Rc;use napi::bindgen_prelude::{External, FunctionCallContext};use napi::threadsafe_function::ThreadsafeFunction;use crate::vscode_sys;pub struct Arguments {pub text_editor_reference: Rc<vscode_sys::reference::TextEditorRef>,}pub type Prototype = ThreadsafeFunction<External<Arguments>,bool,External<Arguments>,napi::Status,false,false,0,>;pub fn build(env: &napi::Env) -> Result<Prototype, napi::Error> {env.create_function_from_closure("get_text_editor_is_dirty", callback)?.build_threadsafe_function().build()}fn callback(function_call_context: FunctionCallContext) -> Result<bool, napi::Error> {let (external,): (&External<Arguments>,) = function_call_context.args()?;let Arguments {text_editor_reference,} = &**external;let text_editor = text_editor_reference.get_inner(function_call_context.env)?;let document = text_editor.get_document()?;document.get_is_dirty()}
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: &ExtensionState,js_functions: &Functions,) {let Some((repository_path, relative_path, repository)) = extension_state.get_repository(&uri)else {tracing::info!(message = "No matching repository for path", ?uri);return;};let Some(open_file) = repository.repository.get_open_file(relative_path) else {tracing::info!(message = "No open file found in repository",?repository_path,?relative_path);return;};let Some(text_editor_reference) = repository.open_editors.get(relative_path) else {tracing::error!(message = "No matching TextEditor found for path",?repository_path,?relative_path);return;};let editor_selections = match js_functions.get_text_editor_selections(text_editor_reference).await{Ok(editor_selections) => editor_selections,Err(error) => {tracing::error!(message = "Failed to get text editor selections", ?error);return;}};let text_document_is_dirty = match js_functions.get_text_editor_is_dirty(text_editor_reference).await{Ok(is_dirty) => is_dirty,Err(error) => {tracing::warn!(message = "Failed to get isDirty for text editor", ?error);false}};let mut line_decorations = Vec::new();for (start_line, end_line) in editor_selections {let selected_range = (start_line as usize)..=(end_line as usize);let credit_spans = open_file.credit(selected_range);for credit_span in credit_spans {for line in credit_span.lines {let line_annotation_text = match crate::inline_credit::line_annotation::render(&credit_span.value,open_file,text_document_is_dirty,&repository.repository,&extension_state.localization_context,) {Ok(line_annotation_text) => line_annotation_text,Err(error) => {tracing::error!(message = "Failed to render line annotation", ?error);return;}};let hover_message_text = match crate::inline_credit::hover::render(credit_span.value,open_file,&repository.repository,&extension_state.localization_context,) {Ok(hover_message_text) => hover_message_text,Err(error) => {tracing::error!(message = "Failed to render hover message", ?error);return;}};line_decorations.push(crate::inline_credit::LineDecoration {line_number: line,line_annotation_text,hover_message_text,})}}}if let Err(error) = js_functions.set_text_editor_decorations(line_decorations,text_editor_reference,&extension_state.decoration_type,).await{tracing::error!(message = "Failed to set text editor decorations", ?error);return;}}