org.eclipse.mylyn.internal.wikitext.commonmark.inlines.PotentialEmphasisSpan.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.mylyn.internal.wikitext.commonmark.inlines.PotentialEmphasisSpan.java

Source

/*******************************************************************************
 * Copyright (c) 2015 David Green.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     David Green - initial API and implementation
 *******************************************************************************/

package org.eclipse.mylyn.internal.wikitext.commonmark.inlines;

import com.google.common.base.CharMatcher;
import com.google.common.base.Optional;

public class PotentialEmphasisSpan extends SourceSpan {

    @Override
    public Optional<? extends Inline> createInline(Cursor cursor) {
        char c = cursor.getChar();
        if ((c == '_' || c == '*') && !currentPositionIsEscaped(cursor)) {
            int length = lengthMatching(cursor, c);

            boolean leftFlanking = isLeftFlanking(cursor, length);
            boolean rightFlanking = isRightFlanking(cursor, length);

            boolean canOpen = leftFlanking;
            boolean canClose = rightFlanking;
            if (c == '_') {
                canOpen = leftFlanking && (!rightFlanking || isPunctuation(charBefore(cursor)));
                canClose = rightFlanking && (!leftFlanking || isPunctuation(charAfter(cursor, length)));
            }
            return Optional.of(new PotentialEmphasisDelimiter(cursor.getLineAtOffset(), cursor.getOffset(), length,
                    cursor.getTextAtOffset(length), canOpen, canClose));
        }
        return Optional.absent();
    }

    boolean isLeftFlanking(Cursor cursor, int length) {
        char charBefore = charBefore(cursor);
        char charAfter = charAfter(cursor, length);
        return !isWhitespace(charAfter)
                && !(isPunctuation(charAfter) && !isWhitespace(charBefore) && !isPunctuation(charBefore));
    }

    private char charAfter(Cursor cursor, int length) {
        return cursor.hasNext(length) ? cursor.getNext(length) : '\n';
    }

    private char charBefore(Cursor cursor) {
        return cursor.hasPrevious() ? cursor.getPrevious() : '\n';
    }

    boolean isRightFlanking(Cursor cursor, int length) {
        char charBefore = charBefore(cursor);
        char charAfter = charAfter(cursor, length);
        return !isWhitespace(charBefore)
                && !(isPunctuation(charBefore) && !isWhitespace(charAfter) && !isPunctuation(charAfter));

    }

    private boolean isWhitespace(char c) {
        return CharMatcher.WHITESPACE.matches(c);
    }

    private boolean isPunctuation(char c) {
        String punctuation = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`,{|}~";
        return punctuation.indexOf(c) >= 0;
    }

    private boolean currentPositionIsEscaped(Cursor cursor) {
        int backslashCount = 0;
        for (int x = 1; cursor.hasPrevious(x) && cursor.getPrevious(x) == '\\'; ++x) {
            ++backslashCount;
        }
        return backslashCount % 2 == 1;
    }

    private int lengthMatching(Cursor cursor, char c) {
        int x = 1;
        while (cursor.hasNext(x) && cursor.getNext(x) == c) {
            ++x;
        }
        return x;
    }

    static boolean isLetterOrDigit(char previous) {
        return (previous >= '0' && previous <= '9') || (previous >= 'A' && previous <= 'Z')
                || (previous >= 'a' && previous <= 'z');
    }
}