/*
* Copyright 2003-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jetbrains.mps.text.impl;
import jetbrains.mps.text.BasicToken;
import jetbrains.mps.text.BufferLayout;
import jetbrains.mps.text.BufferSnapshot;
import jetbrains.mps.text.TextAreaToken;
import jetbrains.mps.text.TextBuffer;
import jetbrains.mps.text.TextMark;
import org.jetbrains.annotations.NotNull;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/**
* Prepare {@link BufferLayoutConfiguration}.
* @author Artem Tikhomirov
*/
public class BufferLayoutBuilder {
private final Set<TextAreaToken> myRootTokens = new LinkedHashSet<TextAreaToken>();
private final Map<TextAreaToken,TextAreaToken> myChildToParentTokens = new LinkedHashMap<TextAreaToken, TextAreaToken>();
private TextAreaToken myInitial;
public BufferLayoutBuilder add(@NotNull Object tokenIdentity) {
if (!myRootTokens.add(new BasicToken(tokenIdentity))) {
throw new IllegalArgumentException("Duplicated text area token:" + tokenIdentity);
}
return this;
}
public BufferLayoutBuilder add(@NotNull Object parentTokenIdentity, @NotNull Object childTokenIdentity) {
if (!myRootTokens.contains(new BasicToken(parentTokenIdentity))) {
throw new IllegalArgumentException("Unknown parent text area token:" + parentTokenIdentity);
}
BasicToken childToken = new BasicToken(childTokenIdentity);
if (myChildToParentTokens.containsKey(childToken)) {
throw new IllegalArgumentException("Child is already registered with another parent:" + myChildToParentTokens.get(childToken));
}
myChildToParentTokens.put(childToken, new BasicToken(parentTokenIdentity));
return this;
}
public BufferLayoutBuilder activate(Object tokenIdentity) {
BasicToken token = new BasicToken(tokenIdentity);
if (!myRootTokens.contains(token) && !myChildToParentTokens.containsKey(token)) {
throw new IllegalArgumentException("Can't activate unknown token:" + tokenIdentity);
}
myInitial = token;
return this;
}
public BufferLayoutConfiguration create() {
return new BufferLayoutConfiguration() {
private BufferLayout myLayout; // optional
@Override
public void prepareBuffer(@NotNull TextBuffer buffer) {
for (TextAreaToken t : myRootTokens) {
buffer.pushTextArea(t).popTextArea();
}
if (!myChildToParentTokens.isEmpty()) {
myLayout = buffer.newLayout();
for (Entry<TextAreaToken, TextAreaToken> p : myChildToParentTokens.entrySet()) {
// superfluous, but necessary at the moment (see TextBufferImpl#snapshot()) - to let buffer know about
// any possible (event empty) text area
buffer.pushTextArea(p.getKey()).popTextArea();
TextMark childAreaLocationMark = buffer.pushTextArea(p.getValue()).pushMark().popMark();
buffer.popTextArea();
// child area goes into given location inside parent area
myLayout.replace(childAreaLocationMark, p.getKey());
}
}
if (myInitial != null) {
buffer.pushTextArea(myInitial);
}
// Generally, myInitial shall be always set (we demand TextUnitLayout.active != null)
// though chances are this BLB would be in use directly, not through TextGen's generator, and in this case we keep global, top-most area as active
}
@NotNull
@Override
public BufferSnapshot prepareSnapshot(@NotNull TextBuffer buffer) {
if (myLayout != null) {
return buffer.snapshot(myLayout);
}
return super.prepareSnapshot(buffer);
}
};
}
}