Minimal prototype using regex

This commit is contained in:
Amethyst Reese
2026-01-12 18:20:12 -08:00
parent 06440dc5ba
commit f0fa410a02
2 changed files with 62 additions and 2 deletions

View File

@@ -31,6 +31,7 @@ ruff_options_metadata = { workspace = true, features = ["serde"] }
ruff_python_ast = { workspace = true }
ruff_python_formatter = { workspace = true }
ruff_python_parser = { workspace = true }
ruff_python_trivia = { workspace = true }
ruff_server = { workspace = true }
ruff_source_file = { workspace = true }
ruff_text_size = { workspace = true }

View File

@@ -11,6 +11,7 @@ use itertools::Itertools;
use log::{error, warn};
use rayon::iter::Either::{Left, Right};
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
use regex::{Captures, Regex};
use ruff_db::diagnostic::{
Annotation, Diagnostic, DiagnosticId, DisplayDiagnosticConfig, Severity, Span,
};
@@ -18,6 +19,7 @@ use ruff_linter::message::{EmitterContext, create_panic_diagnostic, render_diagn
use ruff_linter::settings::types::OutputFormat;
use ruff_notebook::NotebookIndex;
use ruff_python_parser::ParseError;
use ruff_python_trivia::textwrap::{dedent, indent};
use rustc_hash::{FxHashMap, FxHashSet};
use thiserror::Error;
use tracing::debug;
@@ -489,8 +491,65 @@ pub(crate) fn format_source(
formatted,
)))
}
SourceKind::Markdown(source) => {
unimplemented!()
SourceKind::Markdown(unformatted_document) => {
// adapted from blacken-docs
// https://github.com/adamchainz/blacken-docs/blob/fb107c1dce25f9206e29297aaa1ed7afc2980a5a/src/blacken_docs/__init__.py#L17
let code_block_regex = Regex::new(
r"(?imsx)
(?<before>
^(?<indent>\ *)```[^\S\r\n]*
(?:python|py|python3|py3)
(?:\ .*?)?\n
)
(?<code>.*?)
(?<after>
^\ *```[^\S\r\n]*$
)
",
)
.unwrap();
let mut changed = false;
let formatted_document =
code_block_regex.replace_all(unformatted_document, |capture: &Captures| {
let (original, [before, code_indent, unformatted_code, after]) =
capture.extract();
let unformatted_code = dedent(unformatted_code);
let options = settings.to_format_options(source_type, &unformatted_code, path);
let formatted_code = if let Some(_range) = range {
unimplemented!()
} else {
// Using `Printed::into_code` requires adding `ruff_formatter` as a direct dependency, and I suspect that Rust can optimize the closure away regardless.
#[expect(clippy::redundant_closure_for_method_calls)]
format_module_source(&unformatted_code, options)
.map(|formatted| formatted.into_code())
};
// TODO: figure out how to properly raise errors from inside closure
if let Ok(formatted_code) = formatted_code {
if formatted_code.len() == unformatted_code.len()
&& formatted_code == *unformatted_code
{
original.to_string()
} else {
changed = true;
let formatted_code = indent(formatted_code.as_str(), code_indent);
format!("{before}{formatted_code}{after}")
}
} else {
original.to_string()
}
});
if changed {
Ok(FormattedSource::Formatted(SourceKind::Markdown(
formatted_document.to_string(),
)))
} else {
Ok(FormattedSource::Unchanged)
}
}
}
}