use of com.vladsch.flexmark.util.sequence.BasedSequence in project flexmark-java by vsch.
the class AttributeImpl method indexOfValue.
@SuppressWarnings("WeakerAccess")
public static int indexOfValue(final CharSequence value, final CharSequence valueName, final char valueListDelimiter, final char valueNameDelimiter) {
if (valueName.length() == 0 || value.length() == 0)
return -1;
if (valueListDelimiter == NUL) {
return value.equals(valueName) ? 0 : -1;
} else {
int lastPos = 0;
final BasedSequence subSeq = SubSequence.of(value);
while (lastPos < value.length()) {
int pos = subSeq.indexOf(valueName, lastPos);
if (pos == -1)
break;
// see if it is 0 or preceded by a space, or at the end or followed by a space
int endPos = pos + valueName.length();
if (pos == 0 || value.charAt(pos - 1) == valueListDelimiter || valueNameDelimiter != NUL && value.charAt(pos - 1) == valueNameDelimiter) {
if (endPos >= value.length() || value.charAt(endPos) == valueListDelimiter || valueNameDelimiter != NUL && value.charAt(endPos) == valueNameDelimiter) {
return pos;
}
}
lastPos = endPos + 1;
}
}
return -1;
}
use of com.vladsch.flexmark.util.sequence.BasedSequence in project flexmark-java by vsch.
the class IndentedCodeBlockParser method closeBlock.
@Override
public void closeBlock(ParserState state) {
// trim trailing blank lines out of the block
if (trimTrailingBlankLines) {
int trailingBlankLines = 0;
List<BasedSequence> lines = content.getLines();
for (BasedSequence line : new Reverse<BasedSequence>(lines)) {
if (!line.isBlank())
break;
trailingBlankLines++;
}
if (trailingBlankLines > 0)
block.setContent(lines.subList(0, lines.size() - trailingBlankLines));
else
block.setContent(content);
} else {
block.setContent(content);
}
if (codeContentBlock) {
CodeBlock codeBlock = new CodeBlock(block.getChars(), block.getContentLines());
block.appendChild(codeBlock);
}
content = null;
}
use of com.vladsch.flexmark.util.sequence.BasedSequence in project flexmark-java by vsch.
the class InlineParserImpl method matchLinkRef.
private ReferenceProcessorMatch matchLinkRef(Bracket opener, int startIndex, int lookAhead, int nesting) {
if (linkRefProcessorsData.nestingIndex.length == 0)
return null;
ReferenceProcessorMatch match = null;
BasedSequence textNoBang = null;
BasedSequence textWithBang = null;
boolean wantBang;
int iMax = linkRefProcessorsData.processors.size();
int startProc = linkRefProcessorsData.nestingIndex[lookAhead + nesting];
for (int i = startProc; i < iMax; i++) {
LinkRefProcessor linkProcessor = linkRefProcessors.get(i);
BasedSequence nodeChars;
if (lookAhead + nesting < linkProcessor.getBracketNestingLevel())
break;
wantBang = linkProcessor.getWantExclamationPrefix();
// preview the link ref
if (opener.image && wantBang) {
// this one has index off by one for the leading !
if (textWithBang == null)
textWithBang = input.subSequence(opener.index - 1 - lookAhead, startIndex + lookAhead);
nodeChars = textWithBang;
} else {
if (wantBang && opener.index >= lookAhead + 1 && input.charAt(opener.index - 1 - lookAhead) == '!') {
if (textWithBang == null)
textWithBang = input.subSequence(opener.index - 1 - lookAhead, startIndex + lookAhead);
nodeChars = textWithBang;
} else {
if (textNoBang == null)
textNoBang = input.subSequence(opener.index - lookAhead, startIndex + lookAhead);
nodeChars = textNoBang;
}
}
if (linkProcessor.isMatch(nodeChars)) {
match = new ReferenceProcessorMatch(linkProcessor, wantBang, nodeChars);
break;
}
}
return match;
}
use of com.vladsch.flexmark.util.sequence.BasedSequence in project flexmark-java by vsch.
the class InlineParserImpl method parseAutolink.
/**
* Attempt to parse an autolink (URL or email in pointy brackets).
*
* @return true if processed characters false otherwise
*/
@Override
public boolean parseAutolink() {
BasedSequence m;
if ((m = match(myParsing.EMAIL_AUTOLINK)) != null) {
MailLink node = new MailLink(m.subSequence(0, 1), m.subSequence(1, m.length() - 1), m.subSequence(m.length() - 1, m.length()));
appendNode(node);
return true;
} else if ((m = match(myParsing.AUTOLINK)) != null) {
AutoLink node = new AutoLink(m.subSequence(0, 1), m.subSequence(1, m.length() - 1), m.subSequence(m.length() - 1, m.length()));
appendNode(node);
return true;
} else {
return false;
}
}
use of com.vladsch.flexmark.util.sequence.BasedSequence in project flexmark-java by vsch.
the class InlineParserImpl method parseCloseBracket.
/**
* Try to match close bracket against an opening in the delimiter stack. Add either a link or image, or a
* plain [ character, to block's children. If there is a matching delimiter, removeIndex it from the delimiter stack.
* <p>
* Also handles custom link ref processing
*
* @return true
*/
protected boolean parseCloseBracket() {
index++;
int startIndex = index;
int nestedBrackets;
boolean hadBang = false;
// look through stack of delimiters for a [ or ![
Bracket opener = this.lastBracket;
if (opener == null) {
// No matching opener, just return a literal.
appendText(input.subSequence(index - 1, index));
return true;
}
if (!opener.allowed) {
// Matching opener but it's not allowed, just return a literal.
appendText(input.subSequence(index - 1, index));
removeLastBracket();
return true;
}
nestedBrackets = 0;
// Check to see if we have a link/image
BasedSequence dest = null;
BasedSequence title = null;
BasedSequence ref = null;
boolean isLinkOrImage = false;
boolean refIsBare = false;
ReferenceProcessorMatch linkRefProcessorMatch = null;
boolean refIsDefined = false;
BasedSequence linkOpener = BasedSequence.NULL;
BasedSequence linkCloser = BasedSequence.NULL;
BasedSequence bareRef = BasedSequence.NULL;
BasedSequence imageUrlContent = null;
// Inline link?
int preSpaceIndex = index;
// May need to skip spaces
if (options.spaceInLinkElements && peek() == ' ') {
sp();
}
if (peek() == '(') {
int savedIndex = index;
linkOpener = input.subSequence(index, index + 1);
index++;
spnl();
if ((dest = parseLinkDestination()) != null) {
if (options.parseMultiLineImageUrls && opener.image && !dest.startsWith("<") && dest.endsWith("?") && spnlUrl()) {
// possible multi-line image url
int contentStart = index;
int contentEnd = contentStart;
BasedSequence multiLineTitle;
while (true) {
sp();
multiLineTitle = parseLinkTitle();
if (multiLineTitle != null)
sp();
if (peek() == ')') {
linkCloser = input.subSequence(index, index + 1);
index++;
imageUrlContent = input.subSequence(contentStart, contentEnd);
title = multiLineTitle;
isLinkOrImage = true;
break;
}
BasedSequence restOfLine = toEOL();
if (restOfLine == null)
break;
contentEnd = index;
}
} else {
spnl();
// title needs a whitespace before
if (myParsing.WHITESPACE.matcher(input.subSequence(index - 1, index)).matches()) {
title = parseLinkTitle();
spnl();
}
// test for spaces in url making it invalid, otherwise anything else goes
if (peek() == ')') {
linkCloser = input.subSequence(index, index + 1);
index++;
isLinkOrImage = true;
} else {
// back out, no match
index = savedIndex;
}
}
} else {
index = savedIndex;
}
} else {
index = preSpaceIndex;
}
if (!isLinkOrImage) {
// as something else, like a wiki link
if (!options.matchLookaheadFirst) {
linkRefProcessorMatch = matchLinkRef(opener, startIndex, 0, nestedBrackets);
}
if (linkRefProcessorMatch != null) {
// have a match, then no look ahead for next matches
} else {
// need to figure out max nesting we should test based on what is max processor desire and max available
// nested inner ones are always only []
int maxWanted = linkRefProcessorsData.maxNesting;
int maxAvail = 0;
if (maxWanted > nestedBrackets) {
// need to see what is available
Bracket nested = opener;
while (nested.previous != null && nested.index == nested.previous.index + 1 && peek(maxAvail) == ']') {
nested = nested.previous;
maxAvail++;
if (maxAvail + nestedBrackets == maxWanted || nested.image)
break;
}
}
for (int nesting = maxAvail + 1; nesting-- > 0; ) {
linkRefProcessorMatch = matchLinkRef(opener, startIndex, nesting, nestedBrackets);
if (linkRefProcessorMatch != null) {
if (nesting > 0) {
while (nesting-- > 0) {
index++;
lastBracket.node.unlink();
removeLastBracket();
}
opener = lastBracket;
}
break;
}
}
}
if (linkRefProcessorMatch == null) {
// See if there's a link label
int beforeLabel = index;
int labelLength = parseLinkLabel();
if (labelLength > 2) {
ref = input.subSequence(beforeLabel, beforeLabel + labelLength);
} else if (!opener.bracketAfter) {
// Empty or missing second label can only be a reference if there's no unescaped bracket in it.
bareRef = input.subSequence(beforeLabel, beforeLabel + labelLength);
if (opener.image) {
// this one has index off by one for the leading !
ref = input.subSequence(opener.index - 1, startIndex);
} else {
ref = input.subSequence(opener.index, startIndex);
}
refIsBare = true;
}
if (ref != null) {
String normalizedLabel = Escaping.normalizeReferenceChars(ref, true);
if (referenceRepository.containsKey(normalizedLabel)) {
BasedSequence sequence = input.subSequence(opener.index, startIndex);
boolean containsLinks = containsLinkRefs(refIsBare ? ref : sequence, opener.node.getNext(), true);
isLinkOrImage = !containsLinks;
refIsDefined = true;
} else {
// need to test if we are cutting in the middle of some other delimiters matching, if we are not then we will make this into a tentative
if (!opener.isStraddling(ref)) {
if (!refIsBare && peek() == '[') {
int beforeNext = index;
int nextLength = parseLinkLabel();
if (nextLength > 0) {
// not bare and not defined and followed by another [], roll back to before the label and make it just text
index = beforeLabel;
} else {
// undefined ref, create a tentative one but only if does not contain any other link refs
boolean containsLinks = containsLinkRefs(ref, opener.node.getNext(), null);
if (!containsLinks) {
refIsBare = true;
isLinkOrImage = true;
}
}
} else {
// undefined ref, bare or followed by empty [], create a tentative link ref but only if does not contain any other link refs
boolean containsLinks = containsLinkRefs(ref, opener.node.getNext(), null);
if (!containsLinks) {
isLinkOrImage = true;
}
}
}
}
}
}
}
if (isLinkOrImage || linkRefProcessorMatch != null) {
// If we got here, open is a potential opener
// Flush text now. We don't need to worry about combining it with adjacent text nodes, as we'll wrap it in a
// link or image node.
flushTextNode();
Node insertNode;
boolean isImage = opener.image;
if (linkRefProcessorMatch != null) {
if (!linkRefProcessorMatch.wantExclamation && isImage) {
appendText(input.subSequence(opener.index - 1, opener.index));
opener.node.setChars(opener.node.getChars().subSequence(1));
// opener.image = false;
isImage = false;
}
insertNode = linkRefProcessorMatch.processor.createNode(linkRefProcessorMatch.nodeChars);
} else {
insertNode = ref != null ? isImage ? new ImageRef() : new LinkRef() : isImage ? new Image() : new Link();
}
{
Node node = opener.node.getNext();
while (node != null) {
Node next = node.getNext();
insertNode.appendChild(node);
node = next;
}
}
if (linkRefProcessorMatch != null) {
// may need to adjust children's text because some characters were part of the processor's opener/closer
if (insertNode.hasChildren()) {
final BasedSequence original = insertNode.getChildChars();
final BasedSequence text = linkRefProcessorMatch.processor.adjustInlineText(document, insertNode);
// may need to remove some delimiters if they span across original and changed text boundary or if now they are outside text boundary
Delimiter delimiter = lastDelimiter;
while (delimiter != null) {
Delimiter prevDelimiter = delimiter.previous;
final BasedSequence delimiterChars = delimiter.getInput().subSequence(delimiter.getStartIndex(), delimiter.getEndIndex());
if (original.containsAllOf(delimiterChars)) {
if (!text.containsAllOf(delimiterChars) || !linkRefProcessorMatch.processor.allowDelimiters(delimiterChars, document, insertNode)) {
// remove it
removeDelimiterKeepNode(delimiter);
}
}
delimiter = prevDelimiter;
}
if (!text.containsAllOf(original)) {
// now need to truncate child text
for (Node node : insertNode.getChildren()) {
final BasedSequence nodeChars = node.getChars();
if (text.containsSomeOf(nodeChars)) {
if (!text.containsAllOf(nodeChars)) {
// truncate the contents to intersection of node's chars and adjusted chars
BasedSequence chars = text.intersect(nodeChars);
node.setChars(chars);
}
} else {
// remove the node
node.unlink();
}
}
}
}
}
appendNode(insertNode);
if (insertNode instanceof RefNode) {
// set up the parts
RefNode refNode = (RefNode) insertNode;
refNode.setReferenceChars(ref);
if (refIsDefined)
refNode.setDefined(true);
if (!refIsBare) {
refNode.setTextChars(input.subSequence(opener.index, startIndex));
} else if (!bareRef.isEmpty()) {
refNode.setTextOpeningMarker(bareRef.subSequence(0, 1));
refNode.setTextClosingMarker(bareRef.endSequence(1));
}
insertNode.setCharsFromContent();
} else if (insertNode instanceof InlineLinkNode) {
// set dest and title
InlineLinkNode inlineLinkNode = (InlineLinkNode) insertNode;
inlineLinkNode.setUrlChars(dest);
inlineLinkNode.setTitleChars(title);
inlineLinkNode.setLinkOpeningMarker(linkOpener);
inlineLinkNode.setLinkClosingMarker(linkCloser);
inlineLinkNode.setTextChars(isImage ? input.subSequence(opener.index - 1, startIndex) : input.subSequence(opener.index, startIndex));
if (imageUrlContent != null) {
((Image) insertNode).setUrlContent(imageUrlContent);
}
insertNode.setCharsFromContent();
}
// Process delimiters such as emphasis inside link/image
processDelimiters(opener.previousDelimiter);
Node toRemove = opener.node;
removeLastBracket();
if (linkRefProcessorMatch != null) {
linkRefProcessorMatch.processor.updateNodeElements(document, insertNode);
}
// Links within links are not allowed. We found this link, so there can be no other link around it.
if (insertNode instanceof Link) {
Bracket bracket = this.lastBracket;
while (bracket != null) {
if (!bracket.image) {
// Disallow link opener. It will still get matched, but will not result in a link.
bracket.allowed = false;
}
bracket = bracket.previous;
}
// collapse any link refs contained in this link, they are duds, link takes precedence
// TODO: add a test to see if all link refs should be collapsed or just undefined ones
collapseLinkRefChildren(insertNode, null);
} else if (insertNode instanceof RefNode) {
// have a link ref, collapse to text any tentative ones contained in it, they are duds
collapseLinkRefChildren(insertNode, true);
}
toRemove.unlink();
return true;
} else {
// no link or image
index = startIndex;
appendText(input.subSequence(index - 1, index));
removeLastBracket();
return true;
}
}
Aggregations