Fix some markdown bugs.
This commit is contained in:
parent
0dc5aed374
commit
7483b7a8ad
1 changed files with 157 additions and 24 deletions
|
@ -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 == '(';
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue