Skip to content

Commit

Permalink
#178 add initial implementation for task lists
Browse files Browse the repository at this point in the history
  • Loading branch information
Thorsten Marx committed Mar 6, 2024
1 parent 7990d4b commit 36d4e69
Show file tree
Hide file tree
Showing 5 changed files with 285 additions and 14 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package com.github.thmarx.cms.markdown.rules.block;

/*-
* #%L
* cms-markdown
* %%
* Copyright (C) 2023 - 2024 Marx-Software
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/
import com.github.thmarx.cms.markdown.Block;
import com.github.thmarx.cms.markdown.BlockElementRule;
import com.github.thmarx.cms.markdown.InlineRenderer;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
*
* @author t.marx
*/
public class TaskListBlockRule implements BlockElementRule {

private static final Pattern PATTERN = Pattern.compile(
"(^- \\[([ x]?)\\] (.+?)\n)+(^\\n|\\Z)",
Pattern.MULTILINE);

private static final Pattern CHECKED_PATTERN = Pattern.compile(
"- \\[(?<checked>[ x]?)\\] (?<content>.+?)");

@Override
public Block next(String md) {
Matcher matcher = PATTERN.matcher(md);
if (matcher.find()) {
var content = matcher.group(0).trim();

return new TaskListBlock(matcher.start(), matcher.end(),
createTaskList(content)
);
}
return null;
}

private TaskList createTaskList(String content) {
var rows = content.split("\n");
List<Item> definitionLists = new ArrayList<>();
for (var row : rows) {
if ("".equals(row.trim())) {
continue;
}
var matcher = CHECKED_PATTERN.matcher(row);

if (matcher.matches()) {
definitionLists.add(
new Item(
matcher.group("content").trim(),
"x".equalsIgnoreCase(matcher.group("checked"))
)
);
}
}

return new TaskList(definitionLists);
}

static record TaskList(List<Item> items) {

}

static record Item(String title, boolean checked) {

}

public static record TaskListBlock(int start, int end, TaskList taskList) implements Block {

@Override
public String render(InlineRenderer inlineRenderer) {
StringBuilder sb = new StringBuilder();
sb.append("<ul>");

taskList.items().forEach(item -> {
sb.append("<li>");

sb.append("<input disabled=\"\" type=\"checkbox\" ");
if (item.checked()) {
sb.append("checked=\"\"");
}
sb.append("/> ");

sb.append(item.title());
sb.append("</li>");
});

sb.append("</ul>");

return sb.toString();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/

import com.github.thmarx.cms.markdown.rules.block.BlockquoteBlockRule;
import com.github.thmarx.cms.markdown.rules.block.CodeBlockRule;
import com.github.thmarx.cms.markdown.rules.block.DefinitionListBlockRule;
import com.github.thmarx.cms.markdown.rules.block.HeadingBlockRule;
import com.github.thmarx.cms.markdown.rules.block.HorizontalRuleBlockRule;
import com.github.thmarx.cms.markdown.rules.block.ListBlockRule;
import com.github.thmarx.cms.markdown.rules.block.TableBlockRule;
import com.github.thmarx.cms.markdown.rules.block.TaskListBlockRule;
import com.github.thmarx.cms.markdown.rules.inline.HighlightInlineRule;
import com.github.thmarx.cms.markdown.rules.inline.ItalicInlineRule;
import com.github.thmarx.cms.markdown.rules.inline.ImageInlineRule;
Expand All @@ -48,11 +48,11 @@
* @author t.marx
*/
public class FeaturesTest extends MarkdownTest {

static CMSMarkdown SUT;

@BeforeAll
public static void setup () {
public static void setup() {
Options options = new Options();
options.addInlineRule(new StrongInlineRule());
options.addInlineRule(new ItalicInlineRule());
Expand All @@ -63,48 +63,61 @@ public static void setup () {
options.addInlineRule(new HighlightInlineRule());
options.addInlineRule(new SubscriptInlineRule());
options.addInlineRule(new SuperscriptInlineRule());

options.addBlockRule(new CodeBlockRule());
options.addBlockRule(new HeadingBlockRule());
options.addBlockRule(new TaskListBlockRule());
options.addBlockRule(new ListBlockRule());
options.addBlockRule(new HorizontalRuleBlockRule());
options.addBlockRule(new BlockquoteBlockRule());
options.addBlockRule(new TableBlockRule());
options.addBlockRule(new DefinitionListBlockRule());
SUT = new CMSMarkdown(options);
}

@RepeatedTest(1)
public void test_features() throws IOException {

var md = load("features.md").trim();
var expected = load("features.html");
expected = removeComments(expected);

var result = SUT.render(md);
result = "<div>" + result + "</div>";
Assertions.assertThat(result).isEqualToIgnoringWhitespace(expected);
}

@RepeatedTest(1)
public void test_tables() throws IOException {

var md = load("features.tables.md").trim();
var expected = load("features.tables.html");
expected = removeComments(expected);

var result = SUT.render(md);
result = "<div>" + result + "</div>";
Assertions.assertThat(result).isEqualToIgnoringWhitespace(expected);
}

@RepeatedTest(1)
public void test_definition_lists() throws IOException {

var md = load("features.dl.md").trim();
var expected = load("features.dl.html");
expected = removeComments(expected);


var result = SUT.render(md);
result = "<div>" + result + "</div>";
Assertions.assertThat(result).isEqualToIgnoringWhitespace(expected);
}

@RepeatedTest(1)
public void test_tasklist() throws IOException {

var md = load("features.tasklist.md").trim();
var expected = load("features.tasklist.html");
expected = removeComments(expected);

var result = SUT.render(md);
result = "<div>" + result + "</div>";
Assertions.assertThat(result).isEqualToIgnoringWhitespace(expected);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package com.github.thmarx.cms.markdown.rules.block;

/*-
* #%L
* cms-markdown
* %%
* Copyright (C) 2023 - 2024 Marx-Software
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/
import java.util.List;
import java.util.Optional;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;

/**
*
* @author t.marx
*/
public class TaskListBlockRuleTest {

TaskListBlockRule sut = new TaskListBlockRule();

@Test
public void basic_test() {

String input = """
- [ ] foo
- [x] bar
""";

String expected = """
<ul>
<li><input disabled="" type="checkbox" /> foo</li>
<li><input disabled="" type="checkbox" checked="" /> bar</li>
</ul>
""";

var next = sut.next(input);

Assertions.assertThat(next)
.isNotNull()
.isInstanceOf(TaskListBlockRule.TaskListBlock.class);

Assertions.assertThat(((TaskListBlockRule.TaskListBlock) next))
.hasFieldOrPropertyWithValue("taskList",
new TaskListBlockRule.TaskList(List.of(
new TaskListBlockRule.Item("foo", false),
new TaskListBlockRule.Item("bar", true)
))
);

var rendered = next.render((md) -> md);
Assertions.assertThat(rendered).isEqualToIgnoringWhitespace(expected);
}

@Test
public void mulitple_test() {

String input = """
some paragrahp before
- [ ] foo
- [x] bar
some paragrahp after
""";

String expected = """
<ul>
<li><input disabled="" type="checkbox" /> foo</li>
<li><input disabled="" type="checkbox" checked="" /> bar</li>
</ul>
""";

var next = sut.next(input);

Assertions.assertThat(next)
.isNotNull()
.isInstanceOf(TaskListBlockRule.TaskListBlock.class);

Assertions.assertThat(((TaskListBlockRule.TaskListBlock) next))
.hasFieldOrPropertyWithValue("taskList",
new TaskListBlockRule.TaskList(List.of(
new TaskListBlockRule.Item("foo", false),
new TaskListBlockRule.Item("bar", true)
))
);

var rendered = next.render((md) -> md);
Assertions.assertThat(rendered).isEqualToIgnoringWhitespace(expected);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<!--
#%L
cms-markdown
%%
Copyright (C) 2023 - 2024 Marx-Software
%%
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public
License along with this program. If not, see
<http://www.gnu.org/licenses/gpl-3.0.html>.
#L%
-->
<div>
<h1>task list test</h1>
<p></p>
<ul>
<li><input disabled="" type="checkbox" /> foo</li>
<li><input disabled="" type="checkbox" checked="" /> bar</li>
</ul>

<p>a paragraph</p>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# task list test

- [ ] foo
- [x] bar

a paragraph

0 comments on commit 36d4e69

Please sign in to comment.