added TablesRenderer
to render ide error messages with html tables
This commit is contained in:
@@ -0,0 +1,294 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2012 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 org.jetbrains.jet.plugin.highlighter;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintPosition;
|
||||||
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
|
import org.jetbrains.jet.resolve.DescriptorRenderer;
|
||||||
|
import static org.jetbrains.jet.plugin.highlighter.IdeRenderers.*;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author svtk
|
||||||
|
*/
|
||||||
|
public class TablesRenderer {
|
||||||
|
public static class Table {
|
||||||
|
public final TextRow firstText;
|
||||||
|
public final List<TableRow> rows;
|
||||||
|
|
||||||
|
public Table(TextRow firstText, List<TableRow> rows) {
|
||||||
|
this.firstText = firstText;
|
||||||
|
this.rows = rows;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface TableRow {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TextRow implements TableRow {
|
||||||
|
public final String text;
|
||||||
|
|
||||||
|
public TextRow(String text) {
|
||||||
|
this.text = text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class DescriptorRow implements TableRow {
|
||||||
|
public final CallableDescriptor descriptor;
|
||||||
|
|
||||||
|
public DescriptorRow(CallableDescriptor descriptor) {
|
||||||
|
this.descriptor = descriptor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class FunctionArgumentsRow implements TableRow {
|
||||||
|
public final JetType receiverType;
|
||||||
|
public final List<JetType> argumentTypes;
|
||||||
|
public final Collection<ConstraintPosition> errorPositions;
|
||||||
|
|
||||||
|
public FunctionArgumentsRow(JetType receiverType, List<JetType> argumentTypes, Collection<ConstraintPosition> errorPositions) {
|
||||||
|
this.receiverType = receiverType;
|
||||||
|
this.argumentTypes = argumentTypes;
|
||||||
|
this.errorPositions = errorPositions;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final List<Table> previousTables = Lists.newArrayList();
|
||||||
|
private TextRow currentFirstText;
|
||||||
|
private List<TableRow> currentRows;
|
||||||
|
|
||||||
|
public TablesRenderer newElement() {
|
||||||
|
previousTables.add(new Table(currentFirstText, currentRows));
|
||||||
|
currentFirstText = null;
|
||||||
|
currentRows = Lists.newArrayList();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TablesRenderer text(String text) {
|
||||||
|
if (currentRows.isEmpty()) {
|
||||||
|
currentFirstText = new TextRow(text);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
currentRows.add(new TextRow(text));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TablesRenderer text(String text, Object... args) {
|
||||||
|
return text(String.format(text, args));
|
||||||
|
}
|
||||||
|
|
||||||
|
public TablesRenderer descriptor(CallableDescriptor descriptor) {
|
||||||
|
currentRows.add(new DescriptorRow(descriptor));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TablesRenderer functionArgumentTypeList(@Nullable JetType receiverType, @NotNull List<JetType> argumentTypes) {
|
||||||
|
return functionArgumentTypeList(receiverType, argumentTypes, Collections.<ConstraintPosition>emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public TablesRenderer functionArgumentTypeList(@Nullable JetType receiverType,
|
||||||
|
@NotNull List<JetType> argumentTypes,
|
||||||
|
Collection<ConstraintPosition> errorPositions) {
|
||||||
|
currentRows.add(new FunctionArgumentsRow(receiverType, argumentTypes, errorPositions));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder result = new StringBuilder();
|
||||||
|
newElement();
|
||||||
|
for (Table table : previousTables) {
|
||||||
|
renderTable(table, result);
|
||||||
|
}
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int countRowsNumber(Table table) {
|
||||||
|
int argumentsNumber = 0;
|
||||||
|
for (TableRow row : table.rows) {
|
||||||
|
if (row instanceof DescriptorRow) {
|
||||||
|
int valueParametersNumber = ((DescriptorRow) row).descriptor.getValueParameters().size();
|
||||||
|
if (valueParametersNumber > argumentsNumber) {
|
||||||
|
argumentsNumber = valueParametersNumber;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (row instanceof FunctionArgumentsRow) {
|
||||||
|
int argumentTypesNumber = ((FunctionArgumentsRow) row).argumentTypes.size();
|
||||||
|
if (argumentTypesNumber > argumentsNumber) {
|
||||||
|
argumentsNumber = argumentTypesNumber;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//magical number 6:
|
||||||
|
// <td> white-space </td> <td> receiver: ___ </td> <td> arguments: </td> <td> ( </td> arguments <td> ) </td> <td> : return_type </td>
|
||||||
|
return argumentsNumber + 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private static void renderTable(Table table, StringBuilder result) {
|
||||||
|
if (table.firstText == null && table.rows.isEmpty()) return;
|
||||||
|
if (table.firstText != null) {
|
||||||
|
result.append(table.firstText.text);
|
||||||
|
}
|
||||||
|
int rowsNumber = countRowsNumber(table);
|
||||||
|
|
||||||
|
|
||||||
|
result.append("<table>");
|
||||||
|
for (TableRow row : table.rows) {
|
||||||
|
result.append("<tr>");
|
||||||
|
if (row instanceof TextRow) {
|
||||||
|
tdColspan(result, ((TextRow) row).text, rowsNumber);
|
||||||
|
}
|
||||||
|
if (row instanceof DescriptorRow) {
|
||||||
|
result.append(DESCRIPTOR_IN_TABLE.render(((DescriptorRow) row).descriptor));
|
||||||
|
}
|
||||||
|
if (row instanceof FunctionArgumentsRow) {
|
||||||
|
FunctionArgumentsRow functionArgumentsRow = (FunctionArgumentsRow) row;
|
||||||
|
renderFunctionArguments(functionArgumentsRow.receiverType, functionArgumentsRow.argumentTypes, functionArgumentsRow.errorPositions, result);
|
||||||
|
}
|
||||||
|
result.append("</tr>");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
result.append("</table>");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void renderFunctionArguments(@Nullable JetType receiverType, @NotNull List<JetType> argumentTypes, Collection<ConstraintPosition> errorPositions, StringBuilder result) {
|
||||||
|
boolean hasReceiver = receiverType != null;
|
||||||
|
tdSpace(result);
|
||||||
|
String receiver = "";
|
||||||
|
if (hasReceiver) {
|
||||||
|
boolean error = false;
|
||||||
|
if (errorPositions.contains(ConstraintPosition.RECEIVER_POSITION)) {
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
|
receiver = "receiver: " + strong(IdeRenderers.HTML_RENDER_TYPE.render(receiverType), error);
|
||||||
|
}
|
||||||
|
td(result, receiver);
|
||||||
|
td(result, hasReceiver ? "arguments: " : "");
|
||||||
|
if (argumentTypes.isEmpty()) {
|
||||||
|
tdBold(result, "( )");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
td(result, strong("("));
|
||||||
|
int i = 0;
|
||||||
|
for (Iterator<JetType> iterator = argumentTypes.iterator(); iterator.hasNext(); ) {
|
||||||
|
JetType argumentType = iterator.next();
|
||||||
|
boolean error = false;
|
||||||
|
if (errorPositions.contains(ConstraintPosition.valueParameterPosition(i))) {
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
|
String renderedArgument = IdeRenderers.HTML_RENDER_TYPE.render(argumentType);
|
||||||
|
|
||||||
|
tdRight(result, strong(renderedArgument, error) + (iterator.hasNext() ? strong(",") : ""));
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
td(result, strong(")"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TablesRenderer create() {
|
||||||
|
return new TablesRenderer();
|
||||||
|
}
|
||||||
|
|
||||||
|
TablesRenderer(@Nullable TextRow firstText, @NotNull List<TableRow> rows) {
|
||||||
|
this.currentFirstText = firstText;
|
||||||
|
this.currentRows = rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
TablesRenderer() {
|
||||||
|
this(null, Lists.<TableRow>newArrayList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final DescriptorRenderer DESCRIPTOR_IN_TABLE = new DescriptorRenderer.HtmlDescriptorRenderer(false, false) {
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public String render(@NotNull DeclarationDescriptor declarationDescriptor) {
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
tdSpace(builder);
|
||||||
|
tdRightBoldColspan(builder, 2, super.render(declarationDescriptor));
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void renderValueParameters(FunctionDescriptor descriptor, StringBuilder builder) {
|
||||||
|
//todo comment
|
||||||
|
builder.append("</div></td>");
|
||||||
|
super.renderValueParameters(descriptor, builder);
|
||||||
|
builder.append("<td><div style=\"white-space:nowrap;font-weight:bold;\">");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void renderEmptyValueParameters(StringBuilder builder) {
|
||||||
|
tdBold(builder, "( )");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void renderValueParameter(ValueParameterDescriptor parameterDescriptor, boolean isLast, StringBuilder builder) {
|
||||||
|
if (parameterDescriptor.getIndex() == 0) {
|
||||||
|
tdBold(builder, "(");
|
||||||
|
}
|
||||||
|
StringBuilder parameterBuilder = new StringBuilder();
|
||||||
|
parameterDescriptor.accept(super.subVisitor, parameterBuilder);
|
||||||
|
|
||||||
|
tdRightBold(builder, parameterBuilder.toString() + (isLast ? "" : ","));
|
||||||
|
if (isLast) {
|
||||||
|
tdBold(builder, ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private static void td(StringBuilder builder, String text) {
|
||||||
|
builder.append("<td><div style=\"white-space:nowrap;\">").append(text).append("</div></td>");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void tdSpace(StringBuilder builder) {
|
||||||
|
builder.append("<td width=\"10%\"></td>");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void tdColspan(StringBuilder builder, String text, int colspan) {
|
||||||
|
builder.append("<td colspan=\"").append(colspan).append("\"><div style=\"white-space:nowrap;\">").append(text).append("</div></td>");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void tdBold(StringBuilder builder, String text) {
|
||||||
|
builder.append("<td><div style=\"white-space:nowrap;font-weight:bold;\">").append(text).append("</div></td>");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void tdRight(StringBuilder builder, String text) {
|
||||||
|
builder.append("<td align=\"right\"><div style=\"white-space:nowrap;\">").append(text).append("</div></td>");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void tdRightBold(StringBuilder builder, String text) {
|
||||||
|
builder.append("<td align=\"right\"><div style=\"white-space:nowrap;font-weight:bold;\">").append(text).append("</div></td>");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void tdRightBoldColspan(StringBuilder builder, int colspan, String text) {
|
||||||
|
builder.append("<td align=\"right\" colspan=\"").append(colspan).append("\"><div style=\"white-space:nowrap;font-weight:bold;\">").append(text).append("</div></td>");
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user