mirror of
https://github.com/fluxerapp/fluxer.git
synced 2026-09-02 21:04:06 +03:00
fix(markdown): only open code fences at line start (#2081)
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
use crate::ast::{AlertType, ListItem, Node, ParserFlags, TableAlignment};
|
||||
use crate::constants::{MAX_AST_NODES, MAX_LINE_LENGTH};
|
||||
use crate::links::{has_open_inline_code, has_valid_code_fence_language};
|
||||
use crate::links::has_valid_code_fence_language;
|
||||
use crate::normalize::{normalize_nodes, replace_trailing_whitespace_with_newline};
|
||||
use crate::parser::{MarkdownParser, ParseError, RuntimeState};
|
||||
use crate::text::{
|
||||
@@ -175,31 +175,6 @@ pub(crate) fn parse_block(state: &mut RuntimeState<'_>) -> Result<BlockParseResu
|
||||
}
|
||||
return Ok(no_block(current, state.parser.node_count));
|
||||
}
|
||||
let prefix = &line[..fence_pos];
|
||||
if has_open_inline_code(prefix) {
|
||||
return Ok(no_block(current, state.parser.node_count));
|
||||
}
|
||||
let inline_nodes = crate::inline::parse_inline(state.parser, prefix, line_offset)?;
|
||||
let code_lines = slice_lines_from_fence(&state.lines, current, fence_pos);
|
||||
if let Some(code_result) = parse_code_block(state.parser, &code_lines, 0)? {
|
||||
let new_line_index = current + code_result.new_line_index;
|
||||
let mut extra_nodes = Vec::new();
|
||||
if inline_nodes.len() > 1 {
|
||||
extra_nodes.extend(inline_nodes[1..].iter().cloned());
|
||||
}
|
||||
extra_nodes.push(code_result.node.clone());
|
||||
if let Some(extra) = &code_result.extra_content {
|
||||
state.lines[new_line_index].text = extra.content.clone();
|
||||
state.lines[new_line_index].offset = extra.offset;
|
||||
}
|
||||
let first_node = inline_nodes.first().cloned().unwrap_or(code_result.node);
|
||||
return Ok(BlockParseResult {
|
||||
node: Some(first_node),
|
||||
extra_nodes: Some(extra_nodes),
|
||||
new_line_index,
|
||||
new_node_count: state.parser.node_count + inline_nodes.len() + 1,
|
||||
});
|
||||
}
|
||||
}
|
||||
} else if starts_with(trimmed, "```") {
|
||||
let mut content = line;
|
||||
@@ -1251,16 +1226,6 @@ fn alert_type(label: &str) -> Option<AlertType> {
|
||||
}
|
||||
}
|
||||
|
||||
fn slice_lines_from_fence(lines: &[Line], current: usize, fence_pos: usize) -> Vec<Line> {
|
||||
let mut out = Vec::with_capacity(lines.len() - current);
|
||||
out.push(Line {
|
||||
text: lines[current].text[fence_pos..].to_owned(),
|
||||
offset: lines[current].offset + fence_pos,
|
||||
});
|
||||
out.extend(lines[current + 1..].iter().cloned());
|
||||
out
|
||||
}
|
||||
|
||||
fn normalise_ordinal(items: &[ListItem], ordinal: Option<usize>, ordered: bool) -> Option<usize> {
|
||||
if !ordered {
|
||||
return None;
|
||||
|
||||
@@ -1078,31 +1078,6 @@ fn has_terminal_tld(text: &str) -> bool {
|
||||
letter_count >= 2 && i > 0 && byte_at(text, i - 1) == b'.'
|
||||
}
|
||||
|
||||
pub fn has_open_inline_code(text: &str) -> bool {
|
||||
if !text.contains('`') {
|
||||
return false;
|
||||
}
|
||||
let mut open_len: Option<usize> = None;
|
||||
let mut index = 0;
|
||||
while index < text.len() {
|
||||
if byte_at(text, index) != b'`' {
|
||||
index += 1;
|
||||
continue;
|
||||
}
|
||||
let mut run = 0usize;
|
||||
while index + run < text.len() && byte_at(text, index + run) == b'`' {
|
||||
run += 1;
|
||||
}
|
||||
if open_len.is_none() {
|
||||
open_len = Some(run);
|
||||
} else if open_len == Some(run) {
|
||||
open_len = None;
|
||||
}
|
||||
index += run;
|
||||
}
|
||||
open_len.is_some()
|
||||
}
|
||||
|
||||
pub fn has_valid_code_fence_language(language: &str) -> bool {
|
||||
if is_whitespace(byte_at(language, 0)) {
|
||||
return false;
|
||||
|
||||
@@ -172,3 +172,27 @@ fn single_line_fence_without_space_is_content() {
|
||||
json!([{"type":"CodeBlock","content":"hello"}])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mid_line_fence_is_literal_text() {
|
||||
assert_eq!(
|
||||
parse("note text```rust\nfn main() {}\n```"),
|
||||
json!([{"type":"Text","content":"note text```rust\nfn main() {}\n```"}])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mid_line_fence_spanning_multiple_lines_stays_text() {
|
||||
assert_eq!(
|
||||
parse("intro line ```js\nbody one\nbody two\n```"),
|
||||
json!([{"type":"Text","content":"intro line ```js\nbody one\nbody two\n```"}])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn line_start_fence_still_opens_code_block() {
|
||||
assert_eq!(
|
||||
parse("```rust\nfn main() {}\n```"),
|
||||
json!([{"type":"CodeBlock","language":"rust","content":"fn main() {}\n"}])
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user