diff --git a/README.md b/README.md index 603383f..e08fc13 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ See LICENSE.txt for licensing information. *** -Txtmark is yet another markdown processor for the JVM. +### Txtmark is yet another markdown processor for the JVM. * It is easy to use: @@ -16,12 +16,14 @@ Txtmark is yet another markdown processor for the JVM. * It does not depend on other libraries, so classpathing `txtmark.jar` is sufficient to use Txtmark in your project. -For an in-depth explanation of the markdown syntax have a look at [daringfireball.net](http://daringfireball.net/projects/markdown/syntax). +For an in-depth explanation of markdown have a look at the original [Markdown Syntax]. + +*** ### Build instructions -1. Clone the repo or download the sources as [tar] or [zip] -2. Install [Apache Ant(TM)](http://ant.apache.org/) +1. Clone the [repo] or download the sources as [tar] or [zip] +2. Install [Apache Ant(TM)] 3. Do ant release @@ -29,10 +31,148 @@ For an in-depth explanation of the markdown syntax have a look at [daringfirebal and you will find everything you need inside the `release` folder. -### Where Txtmark is not like Markdown +*** + +### Txtmark extensions + +To enable Txtmark's extended markdown parsing you can use the $PROFILE$ mechanism: + + [$PROFILE$]: extended + +This seemed to me as the easiest and safest way to enable different behaviours. +Just put this line into your Txtmark file like you would use reference links. + +#### Behavior changes when using `[$PROFILE$]: extended` + +* ##### Lists and code blocks end a paragraph + + In normal markdown the following: + + This is a paragraph + * and this is not a list + + Will produce: + +
This is a paragraph + * and this is not a list
+ + When using Txtmark extensions this changes to: + +This is a paragraph
+Links: Foo
+ + The ID _must_ be the last thing on the first line. + + All spaces before `{#` get removed, so you can't + use an ID and a manual line break in the same line. + +* ##### Auto HTML entities + + * `(C)` becomes `©` - © + * `(R)` becomes `®` - ® + * `(TM)` becomes `™` - ™ + * `--` becomes `–` - – + * `---` becomes `—` - — + * `...` becomes `…` - … + * `<<` becomes `«` - « + * `>>` becomes `»` - » + * `"Hello"` becomes `“Hello”` - “Hello” + +* ##### Underscores (Emphasis) + + Underscores in the middle of a word don't result in emphasis. + + Con_cat_this + + normally produces this: + + Concatthis + +* ##### Superscript + + You can use `^` to mark a span as superscript. + + 2^2^ = 4 + + turns into + + 22 = 4 + +* ##### Abbreviations + + Abbreviations are defined like reference links, but using a `*` + instead of a link and must be single-line only. + + [Git]: * "Fast distributed revision control system" + + and used like this + + This is [Git]! + + which will produce + + This is Git! + +*** + +### Markdown conformity + +Txtmark passes all tests inside [MarkdownTest\_1.0\_2007-05-09](http://daringfireball.net/projects/downloads/MarkdownTest_1.0_2007-05-09.tgz) +except of two: + +1. **Images.text** + + Fails because Txtmark doesn't produce empty 'title' image attributes. + (IMHO: Images ... OK) + +2. **Literal quotes in titles.text** + + What the frell ... this test will continue to FAIL. + Sorry, but using unescaped `"` in a title which should be surrounded + by `"` is unacceptable for me ;) + + Change: + + Foo [bar](/url/ "Title with "quotes" inside"). + [bar]: /url/ "Title with "quotes" inside" + + to: + + Foo [bar](/url/ "Title with \"quotes\" inside"). + [bar]: /url/ "Title with \"quotes\" inside" + + and Txtmark will produce the correct result. + (IMHO: Literal quotes in titles ... OK) *** +### Where Txtmark is not like Markdown + * Txtmark does not produce empty `title` attributes in link and image tags. * Unescaped `"` in link titles starting with `"` are not recognized and result @@ -77,86 +217,17 @@ For an in-depth explanation of the markdown syntax have a look at [daringfirebal -### Txtmark extensions +* List of escapeable characters: + + \ [ ] ( ) { } # + " ' . < > + - _ + ! ` ^ + *** -To enable Txtmark's extended markdown parsing you can use the $PROFILE$ mechanism: - - [$PROFILE$]: extended - -This seemed to me as the easiest and safest way to enable different behaviours. -(All other markdown processors will ignore this line.) - -#### Behavior changes when using `[$PROFILE$]: extended` - -* Lists and code blocks end a paragraph (inspired by [Actuarius]) - - In normal markdown the following: - - This is a paragraph - * and this is not a list - - will produce: - -This is a paragraph - * and this is not a list
- - When using Txtmark extensions this changes to: - -This is a paragraph
-Note: Don't close the HTML tag!
*Default implementation is:
* out.append("<h");
- * out.append(level);
- * out.append('>');
+ * out.append(level);
*
* @param out The StringBuilder to write to.
*/
@@ -155,6 +155,26 @@ public interface Decorator
*/
public void closeEmphasis(final StringBuilder out);
+ /**
+ * Called when a superscript span is opened.
+ *
+ * Default implementation is:
+ *out.append("<sup>");
+ *
+ * @param out The StringBuilder to write to.
+ */
+ public void openSuper(final StringBuilder out);
+
+ /**
+ * Called when a superscript span is closed.
+ *
+ * Default implementation is:
+ *out.append("</sup>");
+ *
+ * @param out The StringBuilder to write to.
+ */
+ public void closeSuper(final StringBuilder out);
+
/**
* Called when an ordered list is opened.
*
@@ -198,8 +218,9 @@ public interface Decorator
/**
* Called when a list item is opened.
*
+ * Note: Don't close the HTML tag!
*Default implementation is:
- *out.append("<li>");
+ * out.append("<li");
*
* @param out The StringBuilder to write to.
*/
@@ -228,6 +249,7 @@ public interface Decorator
/**
* Called when a link is opened.
*
+ * Note: Don't close the HTML tag!
*Default implementation is:
*out.append("<a");
*
@@ -238,6 +260,7 @@ public interface Decorator
/**
* Called when an image is opened.
*
+ * Note: Don't close the HTML tag!
*Default implementation is:
*out.append("<img");
*
diff --git a/src/java/txtmark/DefaultDecorator.java b/src/java/txtmark/DefaultDecorator.java
index cd8c60f..4415ba1 100644
--- a/src/java/txtmark/DefaultDecorator.java
+++ b/src/java/txtmark/DefaultDecorator.java
@@ -90,7 +90,6 @@ public class DefaultDecorator implements Decorator
{
out.append("null if no valid ID exists.
+ */
+ // FIXME ... hack
+ public String stripIP()
+ {
+ if(this.isEmpty || this.value.charAt(this.value.length() - this.trailing - 1) != '}')
+ return null;
+ int p = this.leading;
+ boolean found = false;
+ while(p < this.value.length() && !found)
+ {
+ switch(this.value.charAt(p))
+ {
+ case '\\':
+ if(p + 1 < this.value.length())
+ {
+ switch(this.value.charAt(p + 1))
+ {
+ case '{':
+ p++;
+ break;
+ }
+ }
+ p++;
+ break;
+ case '{':
+ found = true;
+ break;
+ default:
+ p++;
+ break;
+ }
+ }
+
+ if(found)
+ {
+ if(p + 1 < this.value.length() && this.value.charAt(p + 1) == '#')
+ {
+ final int start = p + 2;
+ p = start;
+ found = false;
+ while(p < this.value.length() && !found)
+ {
+ switch(this.value.charAt(p))
+ {
+ case '\\':
+ if(p + 1 < this.value.length())
+ {
+ switch(this.value.charAt(p + 1))
+ {
+ case '}':
+ p++;
+ break;
+ }
+ }
+ p++;
+ break;
+ case '}':
+ found = true;
+ break;
+ default:
+ p++;
+ break;
+ }
+ }
+ if(found)
+ {
+ final String id = this.value.substring(start, p).trim();
+ if(this.leading != 0)
+ {
+ this.value = this.value.substring(0, this.leading) + this.value.substring(this.leading, start - 2).trim();
+ }
+ else
+ {
+ this.value = this.value.substring(this.leading, start - 2).trim();
+ }
+ this.trailing = 0;
+ return id.length() > 0 ? id : null;
+ }
+ }
+ }
+ return null;
+ }
/**
* Checks for a valid HTML block. Sets xmlEndLine.
diff --git a/src/java/txtmark/LinkRef.java b/src/java/txtmark/LinkRef.java
index 22f5863..35be03a 100644
--- a/src/java/txtmark/LinkRef.java
+++ b/src/java/txtmark/LinkRef.java
@@ -15,6 +15,8 @@ class LinkRef
public final String link;
/** The optional comment/title. */
public String title;
+ /** Flag indicating that this is an abbreviation. */
+ public final boolean isAbbrev;
/**
* Constructor.
@@ -22,10 +24,11 @@ class LinkRef
* @param link The link.
* @param title The title (may be null).
*/
- public LinkRef(final String link, final String title)
+ public LinkRef(final String link, final String title, final boolean isAbbrev)
{
this.link = link;
this.title = title;
+ this.isAbbrev = isAbbrev;
}
/** @see java.lang.Object#toString() */
diff --git a/src/java/txtmark/MarkToken.java b/src/java/txtmark/MarkToken.java
index 8004110..eb87488 100644
--- a/src/java/txtmark/MarkToken.java
+++ b/src/java/txtmark/MarkToken.java
@@ -35,24 +35,26 @@ enum MarkToken
ENTITY, // &
/** \ */
ESCAPE, // \x
- /** Extended: © */
+ /** Extended: ^ */
+ SUPER, // ^
+ /** Extended: (C) */
X_COPY, // (C)
- /** Extended: ® */
+ /** Extended: (R) */
X_REG, // (R)
- /** Extended: ™ */
+ /** Extended: (TM) */
X_TRADE, // (TM)
- /** Extended: « */
+ /** Extended: << */
X_LAQUO, // <<
- /** Extended: » */
+ /** Extended: >> */
X_RAQUO, // >>
- /** Extended: — */
+ /** Extended: -- */
X_NDASH, // --
- /** Extended: – */
+ /** Extended: --- */
X_MDASH, // ---
- /** Extended: … */
+ /** Extended: ... */
X_HELLIP, // ...
- /** Extended: ” */
+ /** Extended: "x */
X_RDQUO, // "
- /** Extended: “ */
+ /** Extended: x" */
X_LDQUO // "
}
diff --git a/src/java/txtmark/Processor.java b/src/java/txtmark/Processor.java
index 5752b7d..76568f0 100644
--- a/src/java/txtmark/Processor.java
+++ b/src/java/txtmark/Processor.java
@@ -336,7 +336,7 @@ public class Processor
else
{
// Store linkRef and skip line
- final LinkRef lr = new LinkRef(link, comment);
+ final LinkRef lr = new LinkRef(link, comment, comment != null && (link.length() == 1 && link.charAt(0) == '*'));
this.emitter.addLinkRef(id, lr);
if(comment == null)
lastLinkRef = lr;
@@ -402,18 +402,24 @@ public class Processor
* @param root The Block to process.
* @param listMode Flag indicating that we're in a list item block.
*/
- // TODO ... paragraphs and lists seems to be not working correctly
private void recurse(final Block root, boolean listMode)
{
Block block, list;
Line line = root.lines;
+
+ if(listMode)
+ {
+ root.removeListIndent();
+ if(this.useExtensions && root.lines != null && root.lines.getLineType() != LineType.CODE)
+ {
+ root.id = root.lines.stripIP();
+ }
+ }
+
while(line != null && line.isEmpty) line = line.next;
if(line == null)
return;
- if(listMode)
- root.removeListIndent();
-
while(line != null)
{
final LineType type = line.getLineType();
@@ -509,6 +515,8 @@ public class Processor
block.type = BlockType.HEADLINE;
if(type != LineType.HEADLINE)
block.hlDepth = type == LineType.HEADLINE1 ? 1 : 2;
+ if(this.useExtensions)
+ block.id = block.lines.stripIP();
block.transfromHeadline();
root.removeLeadingEmptyLines();
line = root.lines;
diff --git a/src/java/txtmark/Run.java b/src/java/txtmark/Run.java
index 333fdcb..bf15a96 100644
--- a/src/java/txtmark/Run.java
+++ b/src/java/txtmark/Run.java
@@ -32,7 +32,7 @@ import java.io.InputStreamReader;
*<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
*</head>
*<body>
- *<!-- the following file separates header from footer -->
+ *<!-- the following line separates header from footer -->
*<!-- ### -->
*</body>
*</html>
diff --git a/src/java/txtmark/Utils.java b/src/java/txtmark/Utils.java
index 36dc212..8fff33c 100644
--- a/src/java/txtmark/Utils.java
+++ b/src/java/txtmark/Utils.java
@@ -63,12 +63,14 @@ class Utils
case '\'':
case '.':
case '>':
+ case '<':
case '*':
case '+':
case '-':
case '_':
case '!':
case '`':
+ case '^':
out.append(ch);
return pos + 1;
default: