All Downloads are FREE. Search and download functionalities are using the official Maven repository.

panda.doc.markdown.Block Maven / Gradle / Ivy

package panda.doc.markdown;

/**
 * This class represents a block of lines.
 */
class Block {
	/** This block's type. */
	public BlockType type = BlockType.NONE;
	/** Head and tail of linked lines. */
	public Line lines = null, lineTail = null;
	/** Head and tail of child blocks. */
	public Block blocks = null, blockTail = null;
	/** Next block. */
	public Block next = null;
	/** Depth of headline BlockType. */
	public int hlDepth = 0;
	/** ID for headlines and list items */
	public String id = null;
	/** Block meta information */
	public String meta = "";

	/** Constructor. */
	public Block() {
		//
	}

	/**
	 * @return true if this block contains lines.
	 */
	public boolean hasLines() {
		return this.lines != null;
	}

	/**
	 * Removes leading and trailing empty lines.
	 */
	public void removeSurroundingEmptyLines() {
		if (this.lines != null) {
			this.removeTrailingEmptyLines();
			this.removeLeadingEmptyLines();
		}
	}

	/**
	 * Sets hlDepth and takes care of '#' chars.
	 */
	public void transfromHeadline() {
		if (this.hlDepth > 0)
			return;
		int level = 0;
		final Line line = this.lines;
		if (line.isEmpty)
			return;
		int start = line.leading;
		while (start < line.value.length() && line.value.charAt(start) == '#') {
			level++;
			start++;
		}
		while (start < line.value.length() && line.value.charAt(start) == ' ')
			start++;
		if (start >= line.value.length()) {
			line.setEmpty();
		}
		else {
			int end = line.value.length() - line.trailing - 1;
			while (line.value.charAt(end) == '#')
				end--;
			while (line.value.charAt(end) == ' ')
				end--;
			line.value = line.value.substring(start, end + 1);
			line.leading = line.trailing = 0;
		}
		this.hlDepth = Math.min(level, 6);
	}

	/**
	 * Used for nested lists. Removes list markers and up to 4 leading spaces.
	 * 
	 * @param extendedMode Whether extended profile ist activated or not
	 */
	public void removeListIndent(boolean extendedMode) {
		Line line = this.lines;
		while (line != null) {
			if (!line.isEmpty) {
				switch (line.getLineType(extendedMode)) {
				case ULIST:
					line.value = line.value.substring(line.leading + 2);
					break;
				case OLIST:
					line.value = line.value.substring(line.value.indexOf('.') + 2);
					break;
				default:
					line.value = line.value.substring(Math.min(line.leading, 4));
					break;
				}
				line.initLeading();
			}
			line = line.next;
		}
	}

	/**
	 * Used for nested block quotes. Removes '>' char.
	 */
	public void removeBlockQuotePrefix() {
		Line line = this.lines;
		while (line != null) {
			if (!line.isEmpty) {
				if (line.value.charAt(line.leading) == '>') {
					int rem = line.leading + 1;
					if (line.leading + 1 < line.value.length() && line.value.charAt(line.leading + 1) == ' ')
						rem++;
					line.value = line.value.substring(rem);
					line.initLeading();
				}
			}
			line = line.next;
		}
	}

	/**
	 * Removes leading empty lines.
	 * 
	 * @return true if an empty line was removed.
	 */
	public boolean removeLeadingEmptyLines() {
		boolean wasEmpty = false;
		Line line = this.lines;
		while (line != null && line.isEmpty) {
			this.removeLine(line);
			line = this.lines;
			wasEmpty = true;
		}
		return wasEmpty;
	}

	/**
	 * Removes trailing empty lines.
	 */
	public void removeTrailingEmptyLines() {
		Line line = this.lineTail;
		while (line != null && line.isEmpty) {
			this.removeLine(line);
			line = this.lineTail;
		}
	}

	/**
	 * Splits this block's lines, creating a new child block having 'line' as it's lineTail.
	 * 
	 * @param line The line to split from.
	 * @return The newly created Block.
	 */
	public Block split(final Line line) {
		final Block block = new Block();

		block.lines = this.lines;
		block.lineTail = line;
		this.lines = line.next;
		line.next = null;
		if (this.lines == null)
			this.lineTail = null;
		else
			this.lines.previous = null;

		if (this.blocks == null)
			this.blocks = this.blockTail = block;
		else {
			this.blockTail.next = block;
			this.blockTail = block;
		}

		return block;
	}

	/**
	 * Removes the given line from this block.
	 * 
	 * @param line Line to remove.
	 */
	public void removeLine(final Line line) {
		if (line.previous == null)
			this.lines = line.next;
		else
			line.previous.next = line.next;
		if (line.next == null)
			this.lineTail = line.previous;
		else
			line.next.previous = line.previous;
		line.previous = line.next = null;
	}

	/**
	 * Appends the given line to this block.
	 * 
	 * @param line Line to append.
	 */
	public void appendLine(final Line line) {
		if (this.lineTail == null)
			this.lines = this.lineTail = line;
		else {
			this.lineTail.nextEmpty = line.isEmpty;
			line.prevEmpty = this.lineTail.isEmpty;
			line.previous = this.lineTail;
			this.lineTail.next = line;
			this.lineTail = line;
		}
	}

	/**
	 * Changes all Blocks of type NONE to PARAGRAPH if this Block is a
	 * List and any of the ListItems contains a paragraph.
	 */
	public void expandListParagraphs() {
		if (this.type != BlockType.ORDERED_LIST && this.type != BlockType.UNORDERED_LIST) {
			return;
		}
		Block outer = this.blocks, inner;
		boolean hasParagraph = false;
		while (outer != null && !hasParagraph) {
			if (outer.type == BlockType.LIST_ITEM) {
				inner = outer.blocks;
				while (inner != null && !hasParagraph) {
					if (inner.type == BlockType.PARAGRAPH) {
						hasParagraph = true;
					}
					inner = inner.next;
				}
			}
			outer = outer.next;
		}
		if (hasParagraph) {
			outer = this.blocks;
			while (outer != null) {
				if (outer.type == BlockType.LIST_ITEM) {
					inner = outer.blocks;
					while (inner != null) {
						if (inner.type == BlockType.NONE) {
							inner.type = BlockType.PARAGRAPH;
						}
						inner = inner.next;
					}
				}
				outer = outer.next;
			}
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy