src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase.ts/PieceTreeBase/getLineRawContent
class PieceTreeBase:	public getLineRawContent(lineNumber: number, endOffset: number = 0): string {
		let x = this.root;

		let ret = '';
		const cache = this._searchCache.get2(lineNumber);
		if (cache) {
			x = cache.node;
			const prevAccumulatedValue = this.getAccumulatedValue(x, lineNumber - cache.nodeStartLineNumber - 1);
			const buffer = this._buffers[x.piece.bufferIndex].buffer;
			const startOffset = this.offsetInBuffer(x.piece.bufferIndex, x.piece.start);
			if (cache.nodeStartLineNumber + x.piece.lineFeedCnt === lineNumber) {
				ret = buffer.substring(startOffset + prevAccumulatedValue, startOffset + x.piece.length);
			} else {
				const accumulatedValue = this.getAccumulatedValue(x, lineNumber - cache.nodeStartLineNumber);
				return buffer.substring(startOffset + prevAccumulatedValue, startOffset + accumulatedValue - endOffset);
			}
		} else {
			let nodeStartOffset = 0;
			const originalLineNumber = lineNumber;
			while (x !== SENTINEL) {
				if (x.left !== SENTINEL && x.lf_left >= lineNumber - 1) {
					x = x.left;
				} else if (x.lf_left + x.piece.lineFeedCnt > lineNumber - 1) {
					const prevAccumulatedValue = this.getAccumulatedValue(x, lineNumber - x.lf_left - 2);
					const accumulatedValue = this.getAccumulatedValue(x, lineNumber - x.lf_left - 1);
					const buffer = this._buffers[x.piece.bufferIndex].buffer;
					const startOffset = this.offsetInBuffer(x.piece.bufferIndex, x.piece.start);
					nodeStartOffset += x.size_left;
					this._searchCache.set({
						node: x,
						nodeStartOffset,
						nodeStartLineNumber: originalLineNumber - (lineNumber - 1 - x.lf_left)
					});

					return buffer.substring(startOffset + prevAccumulatedValue, startOffset + accumulatedValue - endOffset);
				} else if (x.lf_left + x.piece.lineFeedCnt === lineNumber - 1) {
					const prevAccumulatedValue = this.getAccumulatedValue(x, lineNumber - x.lf_left - 2);
					const buffer = this._buffers[x.piece.bufferIndex].buffer;
					const startOffset = this.offsetInBuffer(x.piece.bufferIndex, x.piece.start);

					ret = buffer.substring(startOffset + prevAccumulatedValue, startOffset + x.piece.length);
					break;
				} else {
					lineNumber -= x.lf_left + x.piece.lineFeedCnt;
					nodeStartOffset += x.size_left + x.piece.length;
					x = x.right;
				}
			}
		}

		// search in order, to find the node contains end column
		x = x.next();
		while (x !== SENTINEL) {
			const buffer = this._buffers[x.piece.bufferIndex].buffer;

			if (x.piece.lineFeedCnt > 0) {
				const accumulatedValue = this.getAccumulatedValue(x, 0);
				const startOffset = this.offsetInBuffer(x.piece.bufferIndex, x.piece.start);

				ret += buffer.substring(startOffset, startOffset + accumulatedValue - endOffset);
				return ret;
			} else {
				const startOffset = this.offsetInBuffer(x.piece.bufferIndex, x.piece.start);
				ret += buffer.substr(startOffset, x.piece.length);
			}

			x = x.next();
		}

		return ret;
	}