blocks = new ArrayList<>();
StringBuilder current = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
if (line.isEmpty()) {
if (!current.isEmpty()) {
blocks.add(current.toString());
current.setLength(0);
}
} else {
if (!current.isEmpty()) {
current.append('\n');
}
current.append(line);
}
}
if (!current.isEmpty()) {
blocks.add(current.toString());
}
return blocks;
}
private static String convertBlock(String block) {
int level = countHeaderLevel(block);
if (level > 0) {
String content = block.substring(level + 1);
return "" + parseInline(content) + "";
} else {
return "" + parseInline(block) + "
";
}
}
private static int countHeaderLevel(String block) {
int i = 0;
while (i < block.length() && block.charAt(i) == '#') {
i++;
}
if (i > 0 && i <= 6 && i < block.length() && block.charAt(i) == ' ') {
return i;
}
return 0;
}
private static String parseInline(String text) {
StringBuilder result = new StringBuilder();
Deque stack = new ArrayDeque<>();
Map tags = Map.of(
"*", "em",
"_", "em",
"**", "strong",
"__", "strong",
"--", "s",
"`", "code"
);
for (int i = 0; i < text.length(); ) {
// escape
if (text.charAt(i) == '\\' && i + 1 < text.length()) {
result.append(escapeHtml(text.charAt(i + 1)));
i += 2;
continue;
}
// check double markers first
if (i + 1 < text.length()) {
String two = text.substring(i, i + 2);
if (tags.containsKey(two)) {
if (!stack.isEmpty() && stack.peek().equals(two)) {
result.append("").append(tags.get(two)).append(">");
stack.pop();
} else {
result.append("<").append(tags.get(two)).append(">");
stack.push(two);
}
i += 2;
continue;
}
}
// single markers
String one = String.valueOf(text.charAt(i));
if (tags.containsKey(one)) {
if (!stack.isEmpty() && stack.peek().equals(one)) {
result.append("").append(tags.get(one)).append(">");
stack.pop();
} else {
result.append("<").append(tags.get(one)).append(">");
stack.push(one);
}
i++;
continue;
}
// normal char
result.append(escapeHtml(text.charAt(i)));
i++;
}
return result.toString();
}
private static String escapeHtml(char c) {
return switch (c) {
case '<' -> "<";
case '>' -> ">";
case '&' -> "&";
default -> String.valueOf(c);
};
}
}