/*******************************************************************************
* Copyright (c) 2015 Pivotal, Inc.
* 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:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.eclipse.editor.support.yaml;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.springframework.ide.eclipse.editor.support.util.DocumentUtil;
import org.springframework.ide.eclipse.editor.support.yaml.structure.YamlStructureParser.SRootNode;
import org.springframework.ide.eclipse.editor.support.yaml.structure.YamlStructureProvider;
/**
* Wraps around a IDocument which is presumed to contain YML content and provides
* some utility methods for working with the contents of the document.
*
* @author Kris De Volder
*/
public class YamlDocument {
private IDocument doc;
private YamlStructureProvider structureProvider;
private SRootNode structure;
public YamlDocument(IDocument _doc, YamlStructureProvider structureProvider) {
this.doc = _doc;
this.structureProvider = structureProvider;
}
public IDocument getDocument() {
return doc;
}
public SRootNode getStructure() throws Exception {
if (this.structure==null) {
this.structure = structureProvider.getStructure(this);
}
return structure;
}
public int getLineOfOffset(int offset) throws BadLocationException {
return doc.getLineOfOffset(offset);
}
public IRegion getLineInformation(int line) throws BadLocationException {
return doc.getLineInformation(line);
}
public int getLineOffset(int line) throws BadLocationException {
return doc.getLineOffset(line);
}
/**
* Returns the number of leading spaces in front of a line. If the line is effectively empty (only contains
* comments and/or spaces then this returns -1 (meaning undefined, as indentation level only really means
* something for lines whuch have 'real' content.
*/
public int getLineIndentation(int line) {
IRegion r;
try {
r = getLineInformation(line);
} catch (BadLocationException e) {
//not a line in the document so it has no indentation
return -1;
}
int len = r.getLength();
int startOfLine = r.getOffset();
int leadingSpaces = 0;
while (leadingSpaces<len) {
char c = getChar(startOfLine+leadingSpaces);
if (c==' ') {
leadingSpaces++;
} else if (c=='#') {
return -1;
} else if (c!=' ') {
return leadingSpaces;
}
leadingSpaces++;
}
//Whole line scanned and nothing but spaces found
return -1;
}
public char getChar(int offset) {
try {
return doc.getChar(offset);
} catch (BadLocationException e) {
return 0;
}
}
/**
* Determine whether given offset is inside a comment.
*/
public boolean isCommented(int offset) throws Exception {
//Yaml only has end of line comments marked with a '#'.
//So comments never span multiple lines of text and we only have scan back
//from offset upto the start of the current line.
IRegion lineInfo = doc.getLineInformationOfOffset(offset);
int startOfLine = lineInfo.getOffset();
while (offset>=startOfLine) {
char c = getChar(offset);
if (c=='#') {
return true;
}
offset--;
}
return false;
}
/**
* Fetch text between two offsets. Doesn't throw BadLocationException.
* If either one or both of the offsets points outside the
* document then they will be adjusted to point the appropriate boundary to
* retrieve the text just upto the end or beginning of the document instead.
*/
public String textBetween(int start, int end) {
return DocumentUtil.textBetween(doc, start, end);
}
public int getColumn(int offset) throws Exception {
IRegion r = doc.getLineInformationOfOffset(offset);
return offset - r.getOffset();
}
/**
* Fetct text between a given offset and the start of the line that
* offset belongs to.
*/
public String getLineTextBefore(int offset) throws Exception {
IRegion l = doc.getLineInformationOfOffset(offset);
return textBetween(l.getOffset(), offset);
}
/**
* Fetch the text of the line at a given offset (i.e. all text extending from
* offset to the beginning and end of line)
*/
public String getLineTextAtOffset(int offset) throws Exception {
IRegion l = doc.getLineInformationOfOffset(offset);
return textBetween(l.getOffset(), l.getOffset()+l.getLength());
}
public int getStartOfLineAtOffset(int offset) throws Exception {
return doc.getLineInformationOfOffset(offset).getOffset();
}
@Override
public String toString() {
return "YamlDocument(>>>>\n"+getDocument().get()+"\n<<<<)";
}
}