blob: 881bc7967077c2ad8675b43189248896a6ac40db [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2007, 2020 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.jcommons.text.core.input;
import org.eclipse.statet.jcommons.collections.ImList;
import org.eclipse.statet.jcommons.lang.NonNullByDefault;
import org.eclipse.statet.jcommons.lang.Nullable;
import org.eclipse.statet.jcommons.text.core.TextRegion;
/**
* Text parser input limiting the source to the specified regions.
*/
@NonNullByDefault
public final class RegionParserInput extends FilterParserInput {
private ImList<? extends TextRegion> regions;
private int regionIdx;
private @Nullable String regionSeparator;
public RegionParserInput(final TextParserInput source, final ImList<? extends TextRegion> regions,
final int defaultBufferSize) {
super(source, defaultBufferSize);
this.regions= regions;
this.regionIdx= -1;
}
public RegionParserInput(final TextParserInput source, final ImList<? extends TextRegion> regions) {
this(source, regions, DEFAULT_BUFFER_SIZE);
}
public RegionParserInput(final String source, final ImList<? extends TextRegion> regions) {
this(new StringParserInput(source).init(), regions,
Math.min(source.length() + regions.size(), DEFAULT_BUFFER_SIZE) );
}
public void setSeparator(final @Nullable String separator) {
this.regionSeparator= separator;
}
public RegionParserInput reset(final ImList<? extends TextRegion> regions) {
if (regions == null) {
throw new NullPointerException("regions"); //$NON-NLS-1$
}
this.regions= regions;
this.regionIdx= -1;
super.reset();
return this;
}
@Override
public RegionParserInput init() {
super.init();
return this;
}
@Override
public RegionParserInput init(final int startIndex, final int stopIndex) {
this.regionIdx= -1;
super.init(startIndex, stopIndex);
return this;
}
@Override
protected int read(final TextParserInput in, final char[] buffer,
final int[] beginIndexes, final int[] endIndexes,
final int beginIdx, final int requiredEnd, final int recommendEnd) {
if (this.regionIdx < 0) {
this.regionIdx= 0;
if (!nextRegion(in)) {
return 0;
}
}
int idx= beginIdx;
ITER_C0: while (idx < recommendEnd) {
final int c0= in.get(0);
final int index= in.getIndex();
if (c0 == EOF) {
if (nextRegion(in)) {
final String regionSeparator= this.regionSeparator;
if (regionSeparator != null) {
for (int i= 1; i < regionSeparator.length(); i++, idx++) {
buffer[idx]= regionSeparator.charAt(i);
beginIndexes[idx]= index;
endIndexes[idx]= index;
}
}
continue ITER_C0;
}
break ITER_C0;
}
buffer[idx]= (char) c0;
beginIndexes[idx]= index;
endIndexes[idx]= index + in.getLengthInSource(1);
in.consume(1);
idx++;
continue ITER_C0;
}
beginIndexes[idx]= in.getIndex();
return idx;
}
private boolean nextRegion(final TextParserInput source) {
while (this.regionIdx < this.regions.size()) {
final TextRegion region= this.regions.get(this.regionIdx++);
final int start= Math.max(region.getStartOffset(), getStartIndex());
final int end= Math.min(region.getEndOffset(), getStopIndex());
if (start < end) {
source.init(start, end);
return true;
}
}
return false;
}
}