use camino::Utf8PathBuf;
use icu_locale::locale;
use crate::{ExtensionState, vscode_sys};
pub mod hover;
pub mod line_annotation;
pub fn create_decoration_type<'env>(
env: &'env napi::Env,
) -> Result<vscode_sys::TextEditorDecorationType<'env>, napi::Error> {
let theme_color =
vscode_sys::ThemeColor::new(env, "pijul.decorations.inlineCredit.foreground")?;
let after = vscode_sys::ThemableDecorationAttachmentRenderOptions::new(env)?
.margin("0 0 0 10ch")?
.color(&theme_color)?;
let render_options = vscode_sys::DecorationRenderOptions::new(env)?.after(after)?;
let decoration_type =
vscode_sys::window::create_text_editor_decoration_type(env, render_options)?;
Ok(decoration_type)
}
pub 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}"))
})?;
let 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(())
}