use crate::types::{CursorShaderMetadata, ShaderMetadata};
use std::path::Path;
pub(super) const METADATA_MARKER: &str = "/*! par-term shader metadata";
pub(super) fn extract_yaml_block(source: &str) -> Option<&str> {
let start_marker = source.find(METADATA_MARKER)?;
let yaml_start = source[start_marker + METADATA_MARKER.len()..]
.find('\n')
.map(|i| start_marker + METADATA_MARKER.len() + i + 1)?;
let yaml_end = source[yaml_start..].find("*/")?;
let yaml_content = &source[yaml_start..yaml_start + yaml_end];
Some(yaml_content.trim())
}
pub fn parse_shader_metadata(source: &str) -> Option<ShaderMetadata> {
let yaml_trimmed = extract_yaml_block(source)?;
match serde_yaml_ng::from_str(yaml_trimmed) {
Ok(metadata) => {
log::debug!("Parsed shader metadata: {:?}", metadata);
Some(metadata)
}
Err(e) => {
log::warn!("Failed to parse shader metadata YAML: {}", e);
log::debug!("YAML content was:\n{}", yaml_trimmed);
None
}
}
}
pub fn parse_shader_metadata_from_file(path: &Path) -> Option<ShaderMetadata> {
match std::fs::read_to_string(path) {
Ok(source) => parse_shader_metadata(&source),
Err(e) => {
log::warn!("Failed to read shader file '{}': {}", path.display(), e);
None
}
}
}
pub fn serialize_metadata_to_yaml(metadata: &ShaderMetadata) -> Result<String, String> {
serde_yaml_ng::to_string(metadata).map_err(|e| format!("Failed to serialize metadata: {}", e))
}
pub fn format_metadata_block(metadata: &ShaderMetadata) -> Result<String, String> {
let yaml = serialize_metadata_to_yaml(metadata)?;
Ok(format!("{}\n{}\n*/", METADATA_MARKER, yaml.trim_end()))
}
pub fn update_shader_metadata(source: &str, metadata: &ShaderMetadata) -> Result<String, String> {
let new_block = format_metadata_block(metadata)?;
if let Some(start_pos) = source.find(METADATA_MARKER)
&& let Some(end_offset) = source[start_pos..].find("*/")
{
let end_pos = start_pos + end_offset + 2; let mut result = String::with_capacity(source.len());
result.push_str(&source[..start_pos]);
result.push_str(&new_block);
result.push_str(&source[end_pos..]);
return Ok(result);
}
Ok(format!("{}\n\n{}", new_block, source))
}
pub fn update_shader_metadata_file(path: &Path, metadata: &ShaderMetadata) -> Result<(), String> {
let source = std::fs::read_to_string(path)
.map_err(|e| format!("Failed to read shader file '{}': {}", path.display(), e))?;
let updated_source = update_shader_metadata(&source, metadata)?;
std::fs::write(path, updated_source)
.map_err(|e| format!("Failed to write shader file '{}': {}", path.display(), e))?;
log::info!("Updated metadata in shader file: {}", path.display());
Ok(())
}
pub fn parse_cursor_shader_metadata(source: &str) -> Option<CursorShaderMetadata> {
let yaml_trimmed = extract_yaml_block(source)?;
match serde_yaml_ng::from_str(yaml_trimmed) {
Ok(metadata) => {
log::debug!("Parsed cursor shader metadata: {:?}", metadata);
Some(metadata)
}
Err(e) => {
log::warn!("Failed to parse cursor shader metadata YAML: {}", e);
log::debug!("YAML content was:\n{}", yaml_trimmed);
None
}
}
}
pub fn parse_cursor_shader_metadata_from_file(path: &Path) -> Option<CursorShaderMetadata> {
match std::fs::read_to_string(path) {
Ok(source) => parse_cursor_shader_metadata(&source),
Err(e) => {
log::warn!(
"Failed to read cursor shader file '{}': {}",
path.display(),
e
);
None
}
}
}
pub fn serialize_cursor_metadata_to_yaml(
metadata: &CursorShaderMetadata,
) -> Result<String, String> {
serde_yaml_ng::to_string(metadata).map_err(|e| format!("Failed to serialize metadata: {}", e))
}
pub fn format_cursor_metadata_block(metadata: &CursorShaderMetadata) -> Result<String, String> {
let yaml = serialize_cursor_metadata_to_yaml(metadata)?;
Ok(format!("{}\n{}\n*/", METADATA_MARKER, yaml.trim_end()))
}
pub fn update_cursor_shader_metadata(
source: &str,
metadata: &CursorShaderMetadata,
) -> Result<String, String> {
let new_block = format_cursor_metadata_block(metadata)?;
if let Some(start_pos) = source.find(METADATA_MARKER)
&& let Some(end_offset) = source[start_pos..].find("*/")
{
let end_pos = start_pos + end_offset + 2; let mut result = String::with_capacity(source.len());
result.push_str(&source[..start_pos]);
result.push_str(&new_block);
result.push_str(&source[end_pos..]);
return Ok(result);
}
Ok(format!("{}\n\n{}", new_block, source))
}
pub fn update_cursor_shader_metadata_file(
path: &Path,
metadata: &CursorShaderMetadata,
) -> Result<(), String> {
let source = std::fs::read_to_string(path)
.map_err(|e| format!("Failed to read shader file '{}': {}", path.display(), e))?;
let updated_source = update_cursor_shader_metadata(&source, metadata)?;
std::fs::write(path, updated_source)
.map_err(|e| format!("Failed to write shader file '{}': {}", path.display(), e))?;
log::info!("Updated cursor shader metadata in file: {}", path.display());
Ok(())
}