diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/MessageRenderer.java b/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/MessageRenderer.java index 3ed4e90614f..bf6eb85744c 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/MessageRenderer.java +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/MessageRenderer.java @@ -16,13 +16,7 @@ package org.jetbrains.kotlin.cli.common.messages; -import com.intellij.openapi.util.SystemInfo; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.util.LineSeparator; -import kotlin.KotlinPackage; import kotlin.io.IoPackage; -import org.fusesource.jansi.Ansi; -import org.fusesource.jansi.internal.CLibrary; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -30,40 +24,9 @@ import java.io.File; public interface MessageRenderer { - MessageRenderer XML = new MessageRenderer() { - @Override - public String renderPreamble() { - return ""; - } + MessageRenderer XML = new XmlMessageRenderer(); - @Override - public String render(@NotNull CompilerMessageSeverity severity, @NotNull String message, @NotNull CompilerMessageLocation location) { - StringBuilder out = new StringBuilder(); - out.append("<").append(severity.toString()); - if (location.getPath() != null) { - out.append(" path=\"").append(e(location.getPath())).append("\""); - out.append(" line=\"").append(location.getLine()).append("\""); - out.append(" column=\"").append(location.getColumn()).append("\""); - } - out.append(">"); - - out.append(e(message)); - - out.append("\n"); - return out.toString(); - } - - private String e(String str) { - return StringUtil.escapeXml(str); - } - - @Override - public String renderConclusion() { - return ""; - } - }; - - MessageRenderer PLAIN_FULL_PATHS = new PlainText() { + MessageRenderer PLAIN_FULL_PATHS = new PlainTextMessageRenderer() { @Nullable @Override protected String getPath(@NotNull CompilerMessageLocation location) { @@ -71,7 +34,7 @@ public interface MessageRenderer { } }; - MessageRenderer PLAIN_RELATIVE_PATHS = new PlainText() { + MessageRenderer PLAIN_RELATIVE_PATHS = new PlainTextMessageRenderer() { private final File cwd = new File(".").getAbsoluteFile(); @Nullable @@ -82,124 +45,6 @@ public interface MessageRenderer { } }; - abstract class PlainText implements MessageRenderer { - // AnsiConsole doesn't check isatty() for stderr (see https://github.com/fusesource/jansi/pull/35). - // TODO: investigate why ANSI escape codes on Windows only work in REPL for some reason - private static final boolean COLOR_ENABLED = - !SystemInfo.isWindows && - CLibrary.isatty(CLibrary.STDERR_FILENO) != 0; - - private static final String LINE_SEPARATOR = LineSeparator.getSystemLineSeparator().getSeparatorString(); - - @Override - public String renderPreamble() { - return ""; - } - - @Override - public String render( - @NotNull CompilerMessageSeverity severity, @NotNull String message, @NotNull CompilerMessageLocation location - ) { - StringBuilder result = new StringBuilder(); - - int line = location.getLine(); - int column = location.getColumn(); - String lineContent = location.getLineContent(); - - String path = getPath(location); - if (path != null) { - result.append(path); - result.append(":"); - if (line > 0) { - result.append(line).append(":"); - if (column > 0) { - result.append(column).append(":"); - } - } - result.append(" "); - } - - if (COLOR_ENABLED) { - Ansi ansi = Ansi.ansi() - .bold() - .fg(severityColor(severity)) - .a(severity.name().toLowerCase()) - .a(": ") - .reset() - .bold(); - - // Only make the first line of the message bold. Otherwise long overload ambiguity errors or exceptions are hard to read - String decapitalized = decapitalizeIfNeeded(message); - int firstNewline = decapitalized.indexOf(LINE_SEPARATOR); - if (firstNewline < 0) { - result.append(ansi.a(decapitalized).reset()); - } - else { - result.append(ansi.a(decapitalized.substring(0, firstNewline)).reset().a(decapitalized.substring(firstNewline))); - } - } - else { - result.append(severity.name().toLowerCase()); - result.append(": "); - result.append(decapitalizeIfNeeded(message)); - } - - if (lineContent != null && 1 <= column && column <= lineContent.length() + 1) { - result.append(LINE_SEPARATOR); - result.append(lineContent); - result.append(LINE_SEPARATOR); - result.append(KotlinPackage.repeat(" ", column - 1)); - result.append("^"); - } - - return result.toString(); - } - - @NotNull - private static String decapitalizeIfNeeded(@NotNull String message) { - // TODO: invent something more clever - // An ad-hoc heuristic to prevent decapitalization of some names - if (message.startsWith("Java") || message.startsWith("Kotlin")) { - return message; - } - - // For abbreviations and capitalized text - if (message.length() >= 2 && Character.isUpperCase(message.charAt(0)) && Character.isUpperCase(message.charAt(1))) { - return message; - } - - return KotlinPackage.decapitalize(message); - } - - @NotNull - private static Ansi.Color severityColor(@NotNull CompilerMessageSeverity severity) { - switch (severity) { - case EXCEPTION: - return Ansi.Color.RED; - case ERROR: - return Ansi.Color.RED; - case WARNING: - return Ansi.Color.YELLOW; - case INFO: - return Ansi.Color.BLUE; - case LOGGING: - return Ansi.Color.BLUE; - case OUTPUT: - return Ansi.Color.BLUE; - default: - throw new UnsupportedOperationException("Unknown severity: " + severity); - } - } - - @Nullable - protected abstract String getPath(@NotNull CompilerMessageLocation location); - - @Override - public String renderConclusion() { - return ""; - } - } - String renderPreamble(); String render(@NotNull CompilerMessageSeverity severity, @NotNull String message, @NotNull CompilerMessageLocation location); diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/PlainTextMessageRenderer.java b/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/PlainTextMessageRenderer.java new file mode 100644 index 00000000000..c2e3139fdec --- /dev/null +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/PlainTextMessageRenderer.java @@ -0,0 +1,143 @@ +/* + * Copyright 2010-2015 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.kotlin.cli.common.messages; + +import com.intellij.openapi.util.SystemInfo; +import com.intellij.util.LineSeparator; +import kotlin.KotlinPackage; +import org.fusesource.jansi.Ansi; +import org.fusesource.jansi.internal.CLibrary; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public abstract class PlainTextMessageRenderer implements MessageRenderer { + // AnsiConsole doesn't check isatty() for stderr (see https://github.com/fusesource/jansi/pull/35). + // TODO: investigate why ANSI escape codes on Windows only work in REPL for some reason + private static final boolean COLOR_ENABLED = + !SystemInfo.isWindows && + CLibrary.isatty(CLibrary.STDERR_FILENO) != 0; + + private static final String LINE_SEPARATOR = LineSeparator.getSystemLineSeparator().getSeparatorString(); + + @Override + public String renderPreamble() { + return ""; + } + + @Override + public String render( + @NotNull CompilerMessageSeverity severity, @NotNull String message, @NotNull CompilerMessageLocation location + ) { + StringBuilder result = new StringBuilder(); + + int line = location.getLine(); + int column = location.getColumn(); + String lineContent = location.getLineContent(); + + String path = getPath(location); + if (path != null) { + result.append(path); + result.append(":"); + if (line > 0) { + result.append(line).append(":"); + if (column > 0) { + result.append(column).append(":"); + } + } + result.append(" "); + } + + if (COLOR_ENABLED) { + Ansi ansi = Ansi.ansi() + .bold() + .fg(severityColor(severity)) + .a(severity.name().toLowerCase()) + .a(": ") + .reset() + .bold(); + + // Only make the first line of the message bold. Otherwise long overload ambiguity errors or exceptions are hard to read + String decapitalized = decapitalizeIfNeeded(message); + int firstNewline = decapitalized.indexOf(LINE_SEPARATOR); + if (firstNewline < 0) { + result.append(ansi.a(decapitalized).reset()); + } + else { + result.append(ansi.a(decapitalized.substring(0, firstNewline)).reset().a(decapitalized.substring(firstNewline))); + } + } + else { + result.append(severity.name().toLowerCase()); + result.append(": "); + result.append(decapitalizeIfNeeded(message)); + } + + if (lineContent != null && 1 <= column && column <= lineContent.length() + 1) { + result.append(LINE_SEPARATOR); + result.append(lineContent); + result.append(LINE_SEPARATOR); + result.append(KotlinPackage.repeat(" ", column - 1)); + result.append("^"); + } + + return result.toString(); + } + + @NotNull + private static String decapitalizeIfNeeded(@NotNull String message) { + // TODO: invent something more clever + // An ad-hoc heuristic to prevent decapitalization of some names + if (message.startsWith("Java") || message.startsWith("Kotlin")) { + return message; + } + + // For abbreviations and capitalized text + if (message.length() >= 2 && Character.isUpperCase(message.charAt(0)) && Character.isUpperCase(message.charAt(1))) { + return message; + } + + return KotlinPackage.decapitalize(message); + } + + @NotNull + private static Ansi.Color severityColor(@NotNull CompilerMessageSeverity severity) { + switch (severity) { + case EXCEPTION: + return Ansi.Color.RED; + case ERROR: + return Ansi.Color.RED; + case WARNING: + return Ansi.Color.YELLOW; + case INFO: + return Ansi.Color.BLUE; + case LOGGING: + return Ansi.Color.BLUE; + case OUTPUT: + return Ansi.Color.BLUE; + default: + throw new UnsupportedOperationException("Unknown severity: " + severity); + } + } + + @Nullable + protected abstract String getPath(@NotNull CompilerMessageLocation location); + + @Override + public String renderConclusion() { + return ""; + } +} diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/XmlMessageRenderer.java b/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/XmlMessageRenderer.java new file mode 100644 index 00000000000..95c0722688d --- /dev/null +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/common/messages/XmlMessageRenderer.java @@ -0,0 +1,53 @@ +/* + * Copyright 2010-2015 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.kotlin.cli.common.messages; + +import com.intellij.openapi.util.text.StringUtil; +import org.jetbrains.annotations.NotNull; + +public class XmlMessageRenderer implements MessageRenderer { + @Override + public String renderPreamble() { + return ""; + } + + @Override + public String render(@NotNull CompilerMessageSeverity severity, @NotNull String message, @NotNull CompilerMessageLocation location) { + StringBuilder out = new StringBuilder(); + out.append("<").append(severity.toString()); + if (location.getPath() != null) { + out.append(" path=\"").append(e(location.getPath())).append("\""); + out.append(" line=\"").append(location.getLine()).append("\""); + out.append(" column=\"").append(location.getColumn()).append("\""); + } + out.append(">"); + + out.append(e(message)); + + out.append("\n"); + return out.toString(); + } + + private String e(String str) { + return StringUtil.escapeXml(str); + } + + @Override + public String renderConclusion() { + return ""; + } +}