• R/O
  • SSH
  • HTTPS

catalpa: Commit


Commit MetaInfo

Revisão106 (tree)
Hora2022-09-08 13:52:26
Autorhirukawa_ryo

Mensagem de Log

* catalpa 0.9
青空文庫のルビ記法に対応しました。
タスクリストの li に <checkbox> を出力しないようにしました。代わりにタスクリストの ul に checked または unchecked のクラス属性が付加するように変更しました。

Mudança Sumário

Diff

--- catalpa/trunk/src/main/java/net/osdn/catalpa/flexmark/ext/BasicNodeRenderer.java (revision 105)
+++ catalpa/trunk/src/main/java/net/osdn/catalpa/flexmark/ext/BasicNodeRenderer.java (revision 106)
@@ -72,8 +72,15 @@
7272
7373 protected void render(Heading node, NodeRendererContext context, HtmlWriter html) {
7474 if(2 <= node.getLevel() && node.getLevel() <= 5) {
75+ // id と name に含まれているタグとルビ記法は取り除きます。
7576 String id = node.getAnchorRefId();
77+ id = id.replaceAll("<.+?>", "");
78+ id = id.replaceAll("|", "");
79+ id = id.replaceAll("《.+?》", "");
7680 String name = node.getAnchorRefText().toString().trim().replace(' ', '+');
81+ name = name.replaceAll("<.+?>", "");
82+ name = name.replaceAll("|", "");
83+ name = name.replaceAll("《.+?》", "");
7784 html.raw("<a class=\"h" + node.getLevel() + " anchor\" id=\"" + id + "\" name=\"" + name + "\"></a>");
7885 }
7986 context.delegateRender();
--- catalpa/trunk/src/main/java/net/osdn/catalpa/freemarker/MarkdownDirective.java (revision 105)
+++ catalpa/trunk/src/main/java/net/osdn/catalpa/freemarker/MarkdownDirective.java (revision 106)
@@ -29,6 +29,7 @@
2929
3030 private static final String PARAM_RELATIVE_URL_PREFIX = "relative_url_prefix";
3131 private static final String PARAM_REPLACE_BACKSLASH_TO_YENSIGN = "replace_backslash_to_yensign";
32+ private static final String PARAM_USE_RUBY = "use_ruby";
3233 private static final String PARAM_USE_CATALPA_FONT = "use_catalpa_font";
3334
3435 private static final DataValueFactory<Object> NULL_VALUE_FACTORY = new DataValueFactory<Object>() {
@@ -52,6 +53,7 @@
5253 // Processing the parameters
5354 String relativeUrlPrefix = null;
5455 boolean isReplaceBackslashToYensign = false;
56+ boolean useRuby = false;
5557 boolean useCatalpaFont = false;
5658
5759 @SuppressWarnings("unchecked")
@@ -64,10 +66,15 @@
6466 }
6567 relativeUrlPrefix = ((TemplateScalarModel)param.getValue()).getAsString();
6668 } else if(param.getKey().equals(PARAM_REPLACE_BACKSLASH_TO_YENSIGN)) {
67- if(!(param.getValue() instanceof TemplateBooleanModel)) {
69+ if (!(param.getValue() instanceof TemplateBooleanModel)) {
6870 throw new TemplateModelException("The \"" + PARAM_REPLACE_BACKSLASH_TO_YENSIGN + "\" parameter must be a boolean.");
6971 }
70- isReplaceBackslashToYensign = ((TemplateBooleanModel)param.getValue()).getAsBoolean();
72+ isReplaceBackslashToYensign = ((TemplateBooleanModel) param.getValue()).getAsBoolean();
73+ } else if(param.getKey().equals(PARAM_USE_RUBY)) {
74+ if(!((param.getValue()) instanceof TemplateBooleanModel)) {
75+ throw new TemplateModelException("The \"" + PARAM_USE_RUBY + "\" parameter must be a boolean.");
76+ }
77+ useRuby = ((TemplateBooleanModel)param.getValue()).getAsBoolean();
7178 } else if(param.getKey().equals(PARAM_USE_CATALPA_FONT)) {
7279 if(!((param.getValue()) instanceof TemplateBooleanModel)) {
7380 throw new TemplateModelException("The \"" + PARAM_USE_CATALPA_FONT + "\" parameter must be a boolean.");
@@ -109,7 +116,7 @@
109116 renderer = HtmlRenderer.builder(options).build();
110117 }
111118 String output = renderer.render(document);
112- String japaneseTextLayouted = JapaneseTextLayouter.layout(output, isReplaceBackslashToYensign, useCatalpaFont);
119+ String japaneseTextLayouted = JapaneseTextLayouter.layout(output, isReplaceBackslashToYensign, useRuby, useCatalpaFont);
113120 env.getOut().write(japaneseTextLayouted);
114121 }
115122
--- catalpa/trunk/src/main/java/net/osdn/catalpa/html/JapaneseTextLayouter.java (revision 105)
+++ catalpa/trunk/src/main/java/net/osdn/catalpa/html/JapaneseTextLayouter.java (revision 106)
@@ -1,10 +1,12 @@
11 package net.osdn.catalpa.html;
22
33 import java.util.Arrays;
4+import java.util.HashMap;
45 import java.util.HashSet;
56 import java.util.Iterator;
67 import java.util.LinkedList;
78 import java.util.List;
9+import java.util.Map;
810 import java.util.Set;
911 import java.util.regex.Matcher;
1012 import java.util.regex.Pattern;
@@ -17,6 +19,9 @@
1719
1820 //private static final Pattern HTML_TAG_PATTERN = Pattern.compile("<(\"[^\"]*\"|'[^']*'|[^'\">])*>");
1921 private static final Pattern HTML_TAG_PATTERN = Pattern.compile("<(/?\\w+|!--|!DOCTYPE)(\"[^\"]*\"|'[^']*'|[^'\">])*>", Pattern.CASE_INSENSITIVE);
22+ private static final Pattern RUBY_PATTERN_1 = Pattern.compile("|(.+?)《(.+?)》");
23+ private static final Pattern RUBY_PATTERN_2 = Pattern.compile("([\\u4E00-\\u9FFF\\u3005-\\u3007\\u30F6]+)《(.+?)》");
24+
2025 private static final Set<String> HTML_TAGS = new HashSet<String>(Arrays.asList(
2126 "!--", "!DOCTYPE",
2227 "A", "ABBR", "ACRONYM", "ADDRESS", "APPLET", "AREA", "ARTICLE", "ASIDE", "AUDIO",
@@ -42,7 +47,7 @@
4247 "WBR"));
4348
4449 private static final Set<String> ELEMENTS_TO_SKIP = new HashSet<String>(Arrays.asList(
45- "CODE", "KBD", "PRE", "SAMP", "SCRIPT", "STYLE", "TT"));
50+ "CODE", "KBD", "PRE", "SAMP", "SCRIPT", "STYLE", "TT", "RUBY"));
4651
4752 private static final Set<String> ELEMENTS_WITH_BOUNDARY = new HashSet<String>(Arrays.asList(
4853 "CODE", "KBD", "SAMP", "TT"));
@@ -50,7 +55,12 @@
5055 private static final Set<String> INLINE_TEXT_TAGS = new HashSet<String>(Arrays.asList(
5156 "A", "BIG", "EM", "I", "SMALL", "SPAN", "STRONG"));
5257
53- public static String layout(CharSequence input, boolean isReplaceBackslashToYensign, boolean useCatalpaFont) {
58+ public static String layout(CharSequence input, boolean isReplaceBackslashToYensign, boolean useRuby, boolean useCatalpaFont) {
59+ // 青空文庫のルビ記法を ruby タグに置き換えます。
60+ if(useRuby) {
61+ input = applyRuby(input);
62+ }
63+
5464 //プログラミング言語のキャメルケースやファイルパス記述でも折り返しできるように、ゼロ幅スペースとして<wbr>を挿入します。
5565 //&#8203;ではなく<wbr>を挿入するのは、&#8203;を含むテキストをクリップボードにコピーするとゼロ幅スペースが含まれ、
5666 //ソースコードとしてビルドできなくなるなどの問題を引き起こすためです。<wbr>はクリップボードへのコピー時に取り除かれます。
@@ -387,6 +397,101 @@
387397 }
388398 }
389399
400+ /** 指定した文字列に含まれる青空文庫のルビ記法を <ruby> タグに置き換えて返します。
401+ *
402+ * @param s 文字列
403+ * @return 青空文庫のルビ記法を <ruby> タグに置き換えた文字列
404+ */
405+ private static String applyRuby(CharSequence s) {
406+ /* [\u4E00-\u9FFF\u3005-\u3007\u30F6]+ は漢字にマッチするパターンです。(ひらがな・カタカナにはマッチしません)
407+ *
408+ * 漢字 \u4E00 ~ \u9FFF
409+ * 以下の文字も漢字として扱います。
410+ * \u3005 々
411+ * \u3006 〆
412+ * \u3007 〇
413+ * \u30F6 ヶ
414+ * \u4EDD 仝
415+ */
416+
417+ Set<String> rubies = new HashSet<>();
418+ Map<String, String> map = new HashMap<>();
419+
420+ StringBuilder sb = new StringBuilder();
421+ Matcher m;
422+ int start;
423+
424+ m = RUBY_PATTERN_1.matcher(s);
425+ start = 0;
426+ while(m.find(start)) {
427+ sb.append(s.subSequence(start, m.start()));
428+
429+ if(m.group(1).isBlank()) {
430+ sb.append(m.group(0));
431+ } else {
432+ String rb = m.group(1);
433+ String rt = m.group(2);
434+ String element = "<ruby data-rt=\"" + rt + "\"><rb>" + rb + "</rb><rt>" + rt + "</rt></ruby>";
435+ rubies.add(rb);
436+ map.put(rb, element);
437+ sb.append(element);
438+ }
439+ start = m.end();
440+ }
441+ sb.append(s.subSequence(start, s.length()));
442+
443+ s = sb.toString();
444+ sb = new StringBuilder();
445+ m = RUBY_PATTERN_2.matcher(s);
446+ start = 0;
447+ while(m.find(start)) {
448+ sb.append(s.subSequence(start, m.start()));
449+
450+ if(m.group(1).isBlank()) {
451+ sb.append(m.group(0));
452+ } else {
453+ String rb = m.group(1);
454+ String rt = m.group(2);
455+ String element = "<ruby data-rt=\"" + rt + "\"><rb>" + rb + "</rb><rt>" + rt + "</rt></ruby>";
456+ rubies.add(rb);
457+ map.put(rb, element);
458+ sb.append(element);
459+ }
460+ start = m.end();
461+ }
462+ sb.append(s.subSequence(start, s.length()));
463+
464+ /*
465+ // ルビが指定されていない箇所にもルビを自動適用します。
466+ List<String> list = new ArrayList<>(rubies);
467+ list.sort(Comparator.comparingInt(String::length).reversed());
468+ for(String rb : list) {
469+ String element = map.get(rb);
470+ int fromIndex = 0;
471+ int index;
472+ while((index = sb.indexOf(rb, fromIndex)) >= 0) {
473+ boolean skip = false;
474+ for(int i = index; i > fromIndex; i--) {
475+ if(sb.charAt(i - 1) == '>') {
476+ if (i >= 4 && "<rb>".equals(sb.subSequence(i - 4, i))) {
477+ skip = true;
478+ }
479+ break;
480+ }
481+ }
482+ if(skip) {
483+ fromIndex = index + rb.length();
484+ } else {
485+ sb.replace(index, index + rb.length(), element);
486+ fromIndex = index + element.length();
487+ }
488+ }
489+ }
490+ */
491+
492+ return sb.toString();
493+ }
494+
390495 private static void addLetterSpacing(Char firstChar) {
391496 Char currentChar = firstChar;
392497 while(currentChar != null) {
--- catalpa/trunk/src/main/java/net/osdn/catalpa/Catalpa.java (revision 105)
+++ catalpa/trunk/src/main/java/net/osdn/catalpa/Catalpa.java (revision 106)
@@ -149,6 +149,10 @@
149149 MutableDataSet options = new MutableDataSet();
150150 options.set(HtmlRenderer.FENCED_CODE_NO_LANGUAGE_CLASS, "nohighlight");
151151 options.set(HighlightExtension.REPLACE_YEN_SIGN, true);
152+ options.set(TaskListExtension.ITEM_DONE_CLASS, "checked"); // タスクリストの完了アイテム <li> に "checked" クラスを追加します。
153+ options.set(TaskListExtension.ITEM_NOT_DONE_CLASS, "unchecked"); // タスクリストの未完了アイテム <li> に "unchecked" クラスを追加します。
154+ options.set(TaskListExtension.ITEM_DONE_MARKER, ""); // タスクリストの完了アイテム <li> に既定の子要素 <checkbox> を追加しません。
155+ options.set(TaskListExtension.ITEM_NOT_DONE_MARKER, ""); // タスクリストの未完了アイテム <li> に既定の子要素 <checkbox> を追加しません。
152156 options.set(Parser.EXTENSIONS, Arrays.asList(new Extension[] {
153157 AttributesExtension.create(),
154158 DefinitionExtension.create(),
Show on old repository browser