Fix some markdown bugs.

This commit is contained in:
hns 2009-09-28 12:21:16 +00:00
parent 0dc5aed374
commit 7483b7a8ad

View file

@ -60,27 +60,30 @@ public class MarkdownProcessor {
public MarkdownProcessor() {}
public MarkdownProcessor(String text) {
length = text.length();
chars = new char[length + 2];
text.getChars(0, length, chars, 0);
chars[length] = chars[length + 1] = '\n';
init(text);
}
public MarkdownProcessor(File file) throws IOException {
length = (int) file.length();
chars = new char[length + 2];
FileReader reader = new FileReader(file);
if (reader.read(chars) != length) {
throw new IOException("Couldn't read file");
int read = 0;
try {
while (read < length) {
int r = reader.read(chars, read, length - read);
if (r == -1)
break;
read += r;
}
} finally {
reader.close();
}
length = read;
chars[length] = chars[length + 1] = '\n';
}
public synchronized String process(String text) {
length = text.length();
chars = new char[length + 2];
text.getChars(0, length, chars, 0);
chars[length] = chars[length + 1] = '\n';
init(text);
return process();
}
@ -95,6 +98,18 @@ public class MarkdownProcessor {
return result;
}
public synchronized String processLinkText(String text) {
init(text);
return processLinkText();
}
private void init(String text) {
length = text.length();
chars = new char[length + 2];
text.getChars(0, length, chars, 0);
chars[length] = chars[length + 1] = '\n';
}
/**
* Retrieve a link defined in the source text. If the link is not found, we call
* lookupLink(String) to retrieve it from an external source.
@ -232,7 +247,7 @@ public class MarkdownProcessor {
// no valid link title - escape
state = NONE;
}
} else {
} else if (!isSpace(c) || buffer.length() > 0) {
buffer.append(c);
}
}
@ -436,7 +451,7 @@ public class MarkdownProcessor {
char lastChar = 0;
int count = 0;
boolean escape = false;
for (int k = j; k < length; k++) {
for (int k = j; k <= length; k++) {
if (chars[k] == '\n' && lastChar == '\n') {
break;
}
@ -449,6 +464,8 @@ public class MarkdownProcessor {
escape = true;
} else if (chars[k] == '`') {
k = skipCodeSpan(k);
} else if (chars[k] == '[') {
k = skipLink(k);
} else if (chars[k] == c) {
count += 1;
} else {
@ -575,6 +592,83 @@ public class MarkdownProcessor {
return j;
}
private int skipLink(int start) {
boolean escape = false;
int nesting = 0;
int j = start + 1;
char c;
while (j < length && (escape || chars[j] != ']' || nesting != 0)) {
c = chars[j];
if (c == '\n' && chars[j - 1] == '\n') {
return start;
}
if (escape) {
escape = false;
} else {
escape = c == '\\';
if (!escape) {
if (c == '[') {
nesting += 1;
} else if (c == ']') {
nesting -= 1;
}
}
}
j += 1;
}
int k = j;
j += 1;
boolean extraSpace = false;
if (j < length && Character.isWhitespace(chars[j])) {
j += 1;
extraSpace = true;
}
c = chars[j++];
if (c == '[') {
while (j < length && chars[j] != ']') {
if (chars[j] == '\n') {
return start;
}
j += 1;
}
} else if (c == '(' && !extraSpace) {
while (j < length && chars[j] != ')' && !isSpace(chars[j])) {
if (chars[j] == '\n') {
return start;
}
j += 1;
}
if (j < length && chars[j] != ')') {
while (j < length && chars[j] != ')' && Character.isWhitespace(chars[j])) {
j += 1;
}
if (chars[j] == '"') {
int quoteStart = j = j + 1;
int len = -1;
while (j < length && chars[j] != '\n') {
if (chars[j] == '"') {
len = j - quoteStart;
} else if (len > -1) {
if (chars[j] == ')') {
break;
} else if (!isSpace(chars[j])) {
len = -1;
}
}
j += 1;
}
}
if (chars[j] != ')') {
return start;
}
}
} else {
j = k;
}
return j;
}
private boolean checkLink(char c) {
return checkLinkInternal(c, i + 1, false);
}
@ -609,7 +703,7 @@ public class MarkdownProcessor {
} else if (c == ']') {
nesting -= 1;
}
if (c == '*' || c == '_' || c == '`') {
if (c == '*' || c == '_' || c == '`' || c == '[') {
needsEncoding = true;
}
boolean s = Character.isWhitespace(chars[j]);
@ -627,10 +721,10 @@ public class MarkdownProcessor {
String linkId;
int k = j;
j += 1;
// this is weird, bug we follow the official markup implementation here:
// this is weird, but we follow the official markup implementation here:
// only accept space between link text and link target for [][], not for []()
boolean extraSpace = false;
if (j < length && isSpace(chars[j])) {
if (j < length && Character.isWhitespace(chars[j])) {
j += 1;
extraSpace = true;
}
@ -715,19 +809,13 @@ public class MarkdownProcessor {
}
buffer.append(">");
if (needsEncoding) {
b.append(escapeHtml(text)).append("</a>");
MarkdownProcessor wrapped = new MarkdownProcessor();
buffer.append(wrapped.processLinkText(text)).append("</a>");
} else {
buffer.append(escapeHtml(text)).append("</a>");
}
}
if (b.length() > 0) {
System.arraycopy(chars, j + 1, chars, i + b.length(), length - j - 1);
b.getChars(0, b.length(), chars, i);
length = i + (length - j - 1) + b.length();
} else {
System.arraycopy(chars, j + 1, chars, i, length - j - 1);
length -= 1 + j - i;
}
i = j + 1;
return true;
}
@ -1021,6 +1109,51 @@ public class MarkdownProcessor {
return b.toString();
}
private synchronized String processLinkText() {
buffer = new StringBuilder((int) (length * 1.2));
line = 1;
boolean escape = false;
for (i = 0; i < length; ) {
char c = chars[i];
if (escape) {
buffer.append(c);
escape = false;
i += 1;
continue;
} else if (c == '\\') {
escape = true;
i += 1;
continue;
}
switch (c) {
case '*':
case '_':
if (checkEmphasis(c)) {
continue;
}
break;
case '`':
if (checkCodeSpan(c)) {
continue;
}
break;
case '!':
if (checkImage()) {
continue;
}
break;
}
buffer.append(c);
i += 1;
}
return buffer.toString().trim();
}
boolean isLinkQuote(char c) {
return c == '"' || c == '\'' || c == '(';
}