Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 13 additions & 6 deletions crates/pico-quarto-render/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,10 @@ fn main() -> Result<()> {
}

// Create output directory if it doesn't exist
fs::create_dir_all(&args.output_dir)
.context(format!("Failed to create output directory: {:?}", args.output_dir))?;
fs::create_dir_all(&args.output_dir).context(format!(
"Failed to create output directory: {:?}",
args.output_dir
))?;

// Find all .qmd files
let qmd_files: Vec<PathBuf> = WalkDir::new(&args.input_dir)
Expand Down Expand Up @@ -87,8 +89,12 @@ fn main() -> Result<()> {
}
}

eprintln!("\nProcessed {} files: {} succeeded, {} failed",
success_count + error_count, success_count, error_count);
eprintln!(
"\nProcessed {} files: {} succeeded, {} failed",
success_count + error_count,
success_count,
error_count
);

if error_count > 0 {
std::process::exit(1);
Expand All @@ -104,8 +110,8 @@ fn process_qmd_file(
verbose: u8,
) -> Result<PathBuf> {
// Read the input file
let input_content = fs::read(qmd_path)
.context(format!("Failed to read file: {:?}", qmd_path))?;
let input_content =
fs::read(qmd_path).context(format!("Failed to read file: {:?}", qmd_path))?;

// Parse QMD to AST
// Enable parser verbose mode at level 2+
Expand All @@ -120,6 +126,7 @@ fn process_qmd_file(
false, // loose mode
qmd_path.to_str().unwrap_or("<unknown>"),
&mut output_stream,
true,
)
.map_err(|diagnostics| {
// Format error messages using DiagnosticMessage API
Expand Down
59 changes: 36 additions & 23 deletions crates/qmd-syntax-helper/src/conversions/attribute_ordering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,16 @@ pub struct AttributeOrderingConverter {

#[derive(Debug, Clone)]
struct AttributeOrderingViolation {
start_offset: usize, // Offset of '{'
end_offset: usize, // Offset of '}' + 1
original: String, // Original attrs including braces
start_offset: usize, // Offset of '{'
end_offset: usize, // Offset of '}' + 1
original: String, // Original attrs including braces
error_location: Option<SourceLocation>, // For reporting
}

impl AttributeOrderingConverter {
pub fn new() -> Result<Self> {
let pandoc_output_regex = Regex::new(r"^\[\]\{(.+)\}\s*$")
.context("Failed to compile pandoc output regex")?;
let pandoc_output_regex =
Regex::new(r"^\[\]\{(.+)\}\s*$").context("Failed to compile pandoc output regex")?;

Ok(Self {
pandoc_output_regex,
Expand All @@ -48,6 +48,7 @@ impl AttributeOrderingConverter {
false, // not loose mode
&filename,
&mut sink,
true,
);

let diagnostics = match result {
Expand Down Expand Up @@ -101,7 +102,11 @@ impl AttributeOrderingConverter {
let bytes = content.as_bytes();

if error_offset >= bytes.len() {
return Err(anyhow!("Error offset {} is beyond content length {}", error_offset, bytes.len()));
return Err(anyhow!(
"Error offset {} is beyond content length {}",
error_offset,
bytes.len()
));
}

// Search backward for '{'
Expand All @@ -110,7 +115,10 @@ impl AttributeOrderingConverter {
start -= 1;
}
if bytes[start] != b'{' {
return Err(anyhow!("Could not find opening brace before offset {}", error_offset));
return Err(anyhow!(
"Could not find opening brace before offset {}",
error_offset
));
}

// Search forward for '}'
Expand All @@ -119,7 +127,10 @@ impl AttributeOrderingConverter {
end += 1;
}
if end >= bytes.len() || bytes[end] != b'}' {
return Err(anyhow!("Could not find closing brace after offset {}", error_offset));
return Err(anyhow!(
"Could not find closing brace after offset {}",
error_offset
));
}

Ok((start, end + 1)) // +1 to include the '}'
Expand All @@ -142,20 +153,22 @@ impl AttributeOrderingConverter {
.context("Failed to spawn pandoc. Is pandoc installed?")?;

if let Some(mut stdin) = child.stdin.take() {
stdin.write_all(input.as_bytes())
stdin
.write_all(input.as_bytes())
.context("Failed to write to pandoc stdin")?;
}

let output = child.wait_with_output()
let output = child
.wait_with_output()
.context("Failed to wait for pandoc")?;

if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
return Err(anyhow!("Pandoc failed: {}", stderr));
}

let stdout = String::from_utf8(output.stdout)
.context("Pandoc output is not valid UTF-8")?;
let stdout =
String::from_utf8(output.stdout).context("Pandoc output is not valid UTF-8")?;

// Extract normalized attrs from "[]{...}"
if let Some(caps) = self.pandoc_output_regex.captures(stdout.trim()) {
Expand All @@ -181,14 +194,14 @@ impl AttributeOrderingConverter {
let mut result = content.to_string();

for violation in violations {
let normalized = self.normalize_with_pandoc(&violation.original)
.with_context(|| format!("Failed to normalize attributes: {}", violation.original))?;
let normalized = self
.normalize_with_pandoc(&violation.original)
.with_context(|| {
format!("Failed to normalize attributes: {}", violation.original)
})?;

// Replace original with normalized
result.replace_range(
violation.start_offset..violation.end_offset,
&normalized
);
result.replace_range(violation.start_offset..violation.end_offset, &normalized);
}

Ok(result)
Expand All @@ -201,7 +214,10 @@ impl AttributeOrderingConverter {

/// Convert byte offset to column number (0-indexed)
fn offset_to_column(&self, content: &str, offset: usize) -> usize {
let line_start = content[..offset].rfind('\n').map(|pos| pos + 1).unwrap_or(0);
let line_start = content[..offset]
.rfind('\n')
.map(|pos| pos + 1)
.unwrap_or(0);
offset - line_start
}
}
Expand All @@ -225,10 +241,7 @@ impl Rule for AttributeOrderingConverter {
file_path: file_path.to_string_lossy().to_string(),
has_issue: true,
issue_count: 1,
message: Some(format!(
"Attribute ordering violation: {}",
v.original
)),
message: Some(format!("Attribute ordering violation: {}", v.original)),
location: v.error_location,
error_code: None,
error_codes: None,
Expand Down
Loading