Content is a CharSequence.

Signed-off-by: Florian Thienel <florian@thienel.org>
diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/ContentTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/ContentTest.java
index 4d7002f..dfed7b1 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/ContentTest.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/ContentTest.java
@@ -32,15 +32,15 @@
 	public void insertText() throws Exception {

 		final String text = "Hello World";

 

-		assertEquals(0, content.getLength());

+		assertEquals(0, content.length());

 		content.insertText(0, text);

-		assertEquals(text.length(), content.getLength());

+		assertEquals(text.length(), content.length());

 	}

 

 	@Test

 	public void insertElementMarker() throws Exception {

 		content.insertElementMarker(0);

-		assertEquals(1, content.getLength());

+		assertEquals(1, content.length());

 		assertTrue(content.isElementMarker(0));

 	}

 

@@ -49,7 +49,7 @@
 		final String text = "Hello World";

 		content.insertText(0, text);

 		content.insertElementMarker(5);

-		assertEquals("Each element marker should count 1 in the length calculation.", text.length() + 1, content.getLength());

+		assertEquals("Each element marker should count 1 in the length calculation.", text.length() + 1, content.length());

 	}

 

 	@Test

@@ -95,7 +95,7 @@
 		other.insertElementMarker(4);

 

 		content.insertContent(6, other);

-		assertEquals(16, content.getLength());

+		assertEquals(16, content.length());

 		assertEquals("Hello NewWorld", content.getText());

 		assertTrue(content.isElementMarker(6));

 		assertTrue(content.isElementMarker(10));

@@ -203,4 +203,15 @@
 		assertEquals(content.getText(1, 5), content.getRawText(1, 5));

 		assertEquals(content.getText().substring(0, 5), content.getRawText(1, 5));

 	}

+

+	@Test

+	public void shouldReturnCharacterAtOffset() throws Exception {

+		content.insertElementMarker(0);

+		content.insertElementMarker(0);

+		content.insertText(1, "Hello World");

+

+		for (int i = 0; i < content.length(); i++) {

+			assertEquals(content.getRawText().charAt(i), content.charAt(i));

+		}

+	}

 }

diff --git a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/GapContentTest.java b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/GapContentTest.java
index 21590e2..cac5e5a 100644
--- a/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/GapContentTest.java
+++ b/org.eclipse.vex.core.tests/src/org/eclipse/vex/core/internal/dom/GapContentTest.java
@@ -34,8 +34,8 @@
 		final GapContent stringContent = new GapContent(4);
 		stringContent.insertText(0, "\0\0");
 
-		assertEquals(stringContent.getLength(), elementMarkerContent.getLength());
-		assertEquals(stringContent.getString(0, stringContent.getLength()), elementMarkerContent.getString(0, elementMarkerContent.getLength()));
+		assertEquals(stringContent.length(), elementMarkerContent.length());
+		assertEquals(stringContent.getString(0, stringContent.length()), elementMarkerContent.getString(0, elementMarkerContent.length()));
 	}
 
 	@Test
@@ -47,15 +47,15 @@
 		//
 
 		final GapContent content = new GapContent(2);
-		assertEquals(0, content.getLength());
+		assertEquals(0, content.length());
 		content.insertText(0, "a");
-		assertEquals(1, content.getLength());
+		assertEquals(1, content.length());
 		content.insertText(1, "d");
-		assertEquals(2, content.getLength());
+		assertEquals(2, content.length());
 		content.insertText(1, "c");
-		assertEquals(3, content.getLength());
+		assertEquals(3, content.length());
 		content.insertText(1, "b");
-		assertEquals(4, content.getLength());
+		assertEquals(4, content.length());
 
 		final Position pa = content.createPosition(0);
 		final Position pb = content.createPosition(1);
@@ -119,9 +119,9 @@
 		// 0 1 2 3 4 5 6
 		// 
 		content.insertText(2, "y");
-		assertEquals(5, content.getLength());
+		assertEquals(5, content.length());
 		content.insertText(2, "x");
-		assertEquals(6, content.getLength());
+		assertEquals(6, content.length());
 
 		assertEquals(0, pa.getOffset());
 		assertEquals(1, pb.getOffset());
@@ -134,7 +134,7 @@
 
 		content.remove(2, 2);
 
-		assertEquals(4, content.getLength());
+		assertEquals(4, content.length());
 
 		assertEquals(0, pa.getOffset());
 		assertEquals(1, pb.getOffset());
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Content.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Content.java
index 11a1dd6..59c5836 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Content.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Content.java
@@ -15,7 +15,7 @@
  * 
  * @model
  */
-public interface Content {
+public interface Content extends CharSequence {
 
 	/**
 	 * Creates a new Position object at the given initial offset.
@@ -68,7 +68,7 @@
 	public String getText();
 
 	/**
-	 * Get the plain text of a region of this content. The plain text does also contain the element markers in this
+	 * Get the raw text of a region of this content. The plain text does also contain the element markers in this
 	 * content.
 	 * 
 	 * @param offset
@@ -80,8 +80,7 @@
 	public String getRawText(final int offset, final int length);
 
 	/**
-	 * Get the whole plain text of this content. The plain text does not contain any information about the element
-	 * markers in this content.
+	 * Get the whole raw text of this content. The raw text does also contain the element markers in this content.
 	 * 
 	 * @return the whole text including element markers
 	 */
@@ -149,6 +148,6 @@
 	 * 
 	 * @model
 	 */
-	public int getLength();
+	public int length();
 
 }
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Document.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Document.java
index 650a70f..4a3358d 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Document.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/Document.java
@@ -69,7 +69,7 @@
 	 * 
 	 */
 	public Document(final Content content, final Element rootElement) {
-		associate(content, 0, content.getLength() - 1);
+		associate(content, 0, content.length() - 1);
 		this.rootElement = rootElement;
 		addChild(rootElement);
 	}
@@ -235,8 +235,8 @@
 
 	public DocumentFragment getFragment(final int startOffset, final int endOffset) {
 
-		assertOffset(startOffset, 0, getContent().getLength());
-		assertOffset(endOffset, 0, getContent().getLength());
+		assertOffset(startOffset, 0, getContent().length());
+		assertOffset(endOffset, 0, getContent().length());
 
 		if (endOffset <= startOffset) {
 			throw new IllegalArgumentException("Invalid range (" + startOffset + ", " + endOffset + ")");
@@ -267,7 +267,7 @@
 	}
 
 	public int getLength() {
-		return getContent().getLength();
+		return getContent().length();
 	}
 
 	public List<QualifiedName> getNodeNames(final int startOffset, final int endOffset) {
@@ -482,7 +482,7 @@
 
 		final IUndoableEdit edit = undoEnabled ? new InsertFragmentEdit(offset, fragment) : null;
 
-		fireContentInserted(new DocumentEvent(this, parent, offset, fragment.getContent().getLength(), edit));
+		fireContentInserted(new DocumentEvent(this, parent, offset, fragment.getContent().length(), edit));
 	}
 
 	public void insertText(final int offset, final String text) throws DocumentValidationException {
@@ -695,7 +695,7 @@
 		public void undo() throws CannotUndoException {
 			try {
 				setUndoEnabled(false);
-				final int length = frag.getContent().getLength();
+				final int length = frag.getContent().length();
 				delete(offset, offset + length);
 			} catch (final DocumentValidationException ex) {
 				throw new CannotUndoException();
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DocumentBuilder.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DocumentBuilder.java
index db458d7..8f9b149 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DocumentBuilder.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DocumentBuilder.java
@@ -114,8 +114,8 @@
 
 		// we must insert the trailing sentinel first, else the insertion
 		// pushes the end position of the element to after the sentinel
-		content.insertElementMarker(content.getLength());
-		entry.element.associate(content, entry.offset, content.getLength() - 1);
+		content.insertElementMarker(content.length());
+		entry.element.associate(content, entry.offset, content.length() - 1);
 
 		if (isBlock(entry.element)) {
 			trimLeading = true;
@@ -192,8 +192,8 @@
 
 		appendChars(isBlock(element));
 
-		stack.add(new StackEntry(element, content.getLength(), isPre(element)));
-		content.insertElementMarker(content.getLength());
+		stack.add(new StackEntry(element, content.length(), isPre(element)));
+		content.insertElementMarker(content.length());
 
 		trimLeading = true;
 
@@ -229,15 +229,15 @@
 		parent.addChild(element);
 
 		appendChars(isBlock(element));
-		final int startOffset = content.getLength();
-		content.insertElementMarker(content.getLength());
+		final int startOffset = content.length();
+		content.insertElementMarker(content.length());
 
 		trimLeading = true;
 		appendPendingCharsFiltered(ch, start, length);
 		appendChars(true);
 
-		content.insertElementMarker(content.getLength());
-		element.associate(content, startOffset, content.getLength() - 1);
+		content.insertElementMarker(content.length());
+		element.associate(content, startOffset, content.length() - 1);
 		if (isBlock(element)) {
 			trimLeading = true;
 		}
@@ -272,7 +272,7 @@
 
 		sb = cleanUpTextContent(trimTrailing);
 
-		content.insertText(content.getLength(), sb.toString());
+		content.insertText(content.length(), sb.toString());
 
 		pendingChars.setLength(0);
 		trimLeading = false;
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DocumentFragment.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DocumentFragment.java
index b7de378..fde95e9 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DocumentFragment.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/DocumentFragment.java
@@ -66,7 +66,7 @@
 	 * @see org.eclipse.vex.core.internal.dom.IVEXDocumentFragment#getLength ()
 	 */
 	public int getLength() {
-		return content.getLength();
+		return content.length();
 	}
 
 	/*
@@ -98,7 +98,7 @@
 	}
 
 	public List<Node> getNodes() {
-		return Document.createNodeList(getContent(), 0, getContent().getLength(), getElements());
+		return Document.createNodeList(getContent(), 0, getContent().length(), getElements());
 	}
 
 	/*
@@ -113,7 +113,7 @@
 	}
 
 	private static void writeContent(final Content content, final ObjectOutputStream out) throws IOException {
-		final int contentLength = content.getLength();
+		final int contentLength = content.length();
 		out.write(contentLength);
 		for (int i = 0; i < contentLength; i++) {
 			if (content.isElementMarker(i)) {
diff --git a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/GapContent.java b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/GapContent.java
index 423fb3d..f35c6ef 100644
--- a/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/GapContent.java
+++ b/org.eclipse.vex.core/src/org/eclipse/vex/core/internal/dom/GapContent.java
@@ -51,7 +51,7 @@
 	 */
 	public Position createPosition(final int offset) {
 
-		assertOffset(offset, 0, getLength());
+		assertOffset(offset, 0, length());
 
 		final GapContentPosition position = new GapContentPosition(offset);
 		positions.add(position);
@@ -78,10 +78,10 @@
 	 *            String to insert.
 	 */
 	public void insertText(final int offset, final String s) {
-		assertOffset(offset, 0, getLength());
+		assertOffset(offset, 0, length());
 
 		if (s.length() > gapEnd - gapStart) {
-			expandContent(getLength() + s.length());
+			expandContent(length() + s.length());
 		}
 
 		//
@@ -91,7 +91,7 @@
 		//
 		// This significantly improves document load speed.
 		//
-		final boolean atEnd = offset == getLength() && offset == gapStart;
+		final boolean atEnd = offset == length() && offset == gapStart;
 
 		moveGap(offset);
 		s.getChars(0, s.length(), content, offset);
@@ -110,13 +110,13 @@
 	}
 
 	public void insertElementMarker(final int offset) {
-		assertOffset(offset, 0, getLength());
+		assertOffset(offset, 0, length());
 
 		insertText(offset, Character.toString(ELEMENT_MARKER));
 	}
 
 	public boolean isElementMarker(final int offset) {
-		if (offset < 0 || offset >= getLength()) {
+		if (offset < 0 || offset >= length()) {
 			return false;
 		}
 
@@ -144,7 +144,7 @@
 	 */
 	public void remove(final int offset, final int length) {
 
-		assertOffset(offset, 0, getLength() - length);
+		assertOffset(offset, 0, length() - length);
 		assertPositive(length);
 
 		moveGap(offset + length);
@@ -161,7 +161,7 @@
 
 	public String getString(final int offset, final int length) {
 
-		assertOffset(offset, 0, getLength() - length);
+		assertOffset(offset, 0, length() - length);
 		assertPositive(length);
 
 		if (offset + length < gapStart) {
@@ -177,11 +177,11 @@
 	}
 
 	public String getText() {
-		return getText(0, getLength());
+		return getText(0, length());
 	}
 
 	public String getText(final int offset, final int length) {
-		assertOffset(offset, 0, getLength() - length);
+		assertOffset(offset, 0, length() - length);
 		assertPositive(length);
 
 		final StringBuilder result = new StringBuilder(length);
@@ -206,11 +206,11 @@
 	}
 
 	public String getRawText() {
-		return getRawText(0, getLength());
+		return getRawText(0, length());
 	}
 
 	public String getRawText(final int offset, final int length) {
-		assertOffset(offset, 0, getLength() - length);
+		assertOffset(offset, 0, length() - length);
 		assertPositive(length);
 
 		final StringBuilder result = new StringBuilder(length);
@@ -230,13 +230,13 @@
 	}
 
 	public void insertContent(final int offset, final Content content) {
-		assertOffset(offset, 0, getLength());
+		assertOffset(offset, 0, length());
 
-		copyContent(content, this, 0, offset, content.getLength());
+		copyContent(content, this, 0, offset, content.length());
 	}
 
 	public Content getContent(final int offset, final int length) {
-		assertOffset(offset, 0, getLength() - length);
+		assertOffset(offset, 0, length() - length);
 		assertPositive(length);
 
 		final GapContent result = new GapContent(length);
@@ -245,7 +245,7 @@
 	}
 
 	public Content getContent() {
-		return getContent(0, getLength());
+		return getContent(0, length());
 	}
 
 	private static void copyContent(final Content source, final Content destination, final int sourceOffset, final int destinationOffset, final int length) {
@@ -259,12 +259,42 @@
 	}
 
 	/**
-	 * Return the length of the content.
+	 * @see CharSequence#length()
+	 * @return the length of the raw textual content, including element markers.
 	 */
-	public int getLength() {
+	public int length() {
 		return content.length - (gapEnd - gapStart);
 	}
 
+	/**
+	 * @see CharSequence#charAt(int)
+	 * @param offset
+	 *            the offset of the character within the raw textual content
+	 * @return the character at the given offset (element markers included)
+	 */
+	public char charAt(final int offset) {
+		if (offset < gapStart) {
+			return content[offset];
+		} else {
+			return content[offset - gapStart + gapEnd];
+		}
+	}
+
+	/**
+	 * Get the raw text of a region of this content. The plain text does also contain the element markers in this
+	 * content.
+	 * 
+	 * @see CharSequence#subSequence(int, int)
+	 * @param start
+	 *            Offset at which the substring begins.
+	 * @param end
+	 *            Offset at which the substring ends.
+	 * @return the text of the given region including element markers
+	 */
+	public CharSequence subSequence(final int start, final int end) {
+		return getRawText(start, end - start);
+	}
+
 	// ====================================================== PRIVATE
 
 	private static final int GROWTH_SLOWDOWN_SIZE = 100000;
@@ -355,7 +385,7 @@
 	 */
 	private void moveGap(final int offset) {
 
-		assertOffset(offset, 0, getLength());
+		assertOffset(offset, 0, length());
 
 		if (offset <= gapStart) {
 			final int length = gapStart - offset;
@@ -369,4 +399,5 @@
 			gapEnd += length;
 		}
 	}
+
 }
diff --git a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/editor/VexEditor.java b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/editor/VexEditor.java
index 4ebe963..19e3bd2 100644
--- a/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/editor/VexEditor.java
+++ b/org.eclipse.vex.ui/src/org/eclipse/vex/ui/internal/editor/VexEditor.java
@@ -777,7 +777,7 @@
 
 				@Override
 				protected CharSequence getDocument() {
-					return document.getRawText(document.getStartOffset(), document.getEndOffset());
+					return document.getContent();
 				}
 
 				@Override