Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions modules/cli/src/main/java/org/apache/ignite/internal/cli/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,14 @@
import java.util.stream.Collectors;
import org.apache.ignite.internal.cli.commands.TopLevelCliCommand;
import org.apache.ignite.internal.cli.config.ConfigDefaultValueProvider;
import org.apache.ignite.internal.cli.config.ConfigManagerProvider;
import org.apache.ignite.internal.cli.config.StateFolderProvider;
import org.apache.ignite.internal.cli.core.exception.handler.PicocliExecutionExceptionHandler;
import org.apache.ignite.internal.cli.core.flow.question.JlineQuestionWriterReaderFactory;
import org.apache.ignite.internal.cli.core.flow.question.QuestionAskerFactory;
import org.apache.ignite.internal.cli.core.repl.executor.ReplExecutorProviderImpl;
import org.apache.ignite.internal.cli.core.style.AnsiStringSupport;
import org.apache.ignite.internal.cli.core.style.ColorScheme;
import org.fusesource.jansi.AnsiConsole;
import org.jline.terminal.Terminal;
import picocli.CommandLine;
Expand All @@ -60,6 +63,7 @@ public static void main(String[] args) {
int exitCode = 0;
ApplicationContextBuilder builder = ApplicationContext.builder(Environment.CLI).deduceEnvironment(false);
try (MicronautFactory micronautFactory = new MicronautFactory(builder.start())) {
initColorScheme(micronautFactory);
if (interactiveMode) {
// REPL mode: full initialization with Jansi ANSI console and JLine terminal.
AnsiConsole.systemInstall();
Expand Down Expand Up @@ -94,6 +98,18 @@ private static boolean isatty() {
return System.console() != null;
}

/** Initializes the color scheme provider to read from configuration dynamically. */
private static void initColorScheme(MicronautFactory micronautFactory) throws Exception {
ConfigManagerProvider configProvider = micronautFactory.create(ConfigManagerProvider.class);
// Set a provider that reads from config each time, so changes take effect immediately
AnsiStringSupport.setColorSchemeProvider(() -> {
String schemeName = configProvider.get().getCurrentProperty("ignite.cli.color-scheme");
ColorScheme scheme = ColorScheme.fromString(schemeName);
ColorScheme result = scheme != null ? scheme : ColorScheme.SOLARIZED_DARK;
return result;
});
}

/** Needed for immediate REPL mode and for running a command which will stay in REPL mode so we need to init it once. */
private static void initReplExecutor(MicronautFactory micronautFactory) throws Exception {
ReplExecutorProviderImpl replExecutorProvider = micronautFactory.create(ReplExecutorProviderImpl.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@

package org.apache.ignite.internal.cli.commands.treesitter.highlighter;

import java.util.Map;
import org.apache.ignite.internal.cli.commands.treesitter.parser.Indexer;
import org.apache.ignite.internal.cli.commands.treesitter.parser.Parser;
import org.apache.ignite.internal.cli.commands.treesitter.parser.SqlTokenType;
import org.apache.ignite.internal.cli.core.style.AnsiStringSupport;
import org.apache.ignite.internal.cli.core.style.ColorScheme;
import org.jline.utils.AttributedString;
import org.jline.utils.AttributedStringBuilder;
import org.jline.utils.AttributedStyle;
Expand All @@ -29,38 +30,58 @@
* Highlighter for SQL text. The highlighted text is returned as an AttributedString.
*/
public class SqlAttributedStringHighlighter {
private static final Map<SqlTokenType, Integer> colorMap = Map.of(
SqlTokenType.KEYWORD, 215,
SqlTokenType.IDENTIFIER, 254,
SqlTokenType.BRACKET, 248,
SqlTokenType.LITERAL, 106,
SqlTokenType.SPACE, 0,
SqlTokenType.COMMA, 248,
SqlTokenType.EQUAL, 248,
SqlTokenType.STAR, 248,
SqlTokenType.SEMICOLON, 248,
SqlTokenType.UNKNOWN, 248
);

/**
* Highlights the input SQL text with ANSI colors.
* Highlights the input SQL text with ANSI colors using the current color scheme.
*
* @param text The input SQL text.
* @return The highlighted SQL text.
*/
public static AttributedString highlight(String text) {
return highlight(text, AnsiStringSupport.getColorScheme());
}

/**
* Highlights the input SQL text with ANSI colors using the specified color scheme.
*
* @param text The input SQL text.
* @param scheme The color scheme to use.
* @return The highlighted SQL text.
*/
public static AttributedString highlight(String text, ColorScheme scheme) {
var as = new AttributedStringBuilder();

var tree = Parser.parseSql(text);
SqlTokenType[] tokens = Indexer.indexSql(text, tree);

for (int i = 0; i < text.length(); i++) {
SqlTokenType token = tokens[i];
int color = colorMap.getOrDefault(token, 1);
int color = getColorForToken(token, scheme);
var style = AttributedStyle.DEFAULT.foreground(color);
as.style(style).append(text.charAt(i));
}

return as.toAttributedString();
}

private static int getColorForToken(SqlTokenType token, ColorScheme scheme) {
switch (token) {
case KEYWORD:
return scheme.keywordColor();
case IDENTIFIER:
return scheme.identifierColor();
case LITERAL:
return scheme.stringColor();
case BRACKET:
case COMMA:
case EQUAL:
case STAR:
case SEMICOLON:
return scheme.punctuationColor();
case SPACE:
return 0;
case UNKNOWN:
default:
return scheme.punctuationColor();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,10 @@ public enum CliConfigKeys {
OUTPUT_TRUNCATE(Constants.OUTPUT_TRUNCATE),

/** Maximum column width property name. */
OUTPUT_MAX_COLUMN_WIDTH(Constants.OUTPUT_MAX_COLUMN_WIDTH);
OUTPUT_MAX_COLUMN_WIDTH(Constants.OUTPUT_MAX_COLUMN_WIDTH),

/** Color scheme property name (dark, light). */
COLOR_SCHEME(Constants.COLOR_SCHEME);

private final String value;

Expand Down Expand Up @@ -167,6 +170,8 @@ public static final class Constants {
public static final String OUTPUT_TRUNCATE = "ignite.cli.output.truncate";

public static final String OUTPUT_MAX_COLUMN_WIDTH = "ignite.cli.output.max-column-width";

public static final String COLOR_SCHEME = "ignite.cli.color-scheme";
}

CliConfigKeys(String value) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,46 @@

package org.apache.ignite.internal.cli.core.style;

import java.util.concurrent.atomic.AtomicReference;
import picocli.CommandLine.Help.Ansi;

/**
* Utility class with ANSI string support.
*/
public final class AnsiStringSupport {
private static final AtomicReference<ColorSchemeProvider> SCHEME_PROVIDER =
new AtomicReference<>(() -> ColorScheme.SOLARIZED_DARK);

private AnsiStringSupport() {}

/**
* Sets the color scheme provider for dynamic color scheme resolution.
*
* @param provider Color scheme provider.
*/
public static void setColorSchemeProvider(ColorSchemeProvider provider) {
SCHEME_PROVIDER.set(provider != null ? provider : () -> ColorScheme.SOLARIZED_DARK);
}

/**
* Returns the current color scheme from the provider.
*
* @return Current color scheme.
*/
public static ColorScheme getColorScheme() {
return SCHEME_PROVIDER.get().colorScheme();
}

public static String ansi(String markupText) {
return Ansi.AUTO.string(markupText);
}

public static Fg fg(Color color) {
return new Fg(color);
return new Fg(color, getColorScheme());
}

public static Fg fg(Color color, ColorScheme scheme) {
return new Fg(color, scheme);
}

/** Can mark the string as a ANSI string. */
Expand All @@ -43,11 +69,13 @@ public interface Marker {
*/
public static class Fg implements Marker {
private final Color color;
private final ColorScheme scheme;

private Style style;

private Fg(Color color) {
private Fg(Color color, ColorScheme scheme) {
this.color = color;
this.scheme = scheme;
}

public Fg with(Style style) {
Expand All @@ -58,10 +86,11 @@ public Fg with(Style style) {
/** Marks given text with the configured before style. */
@Override
public String mark(String textToMark) {
int colorCode = color.getCode(scheme);
if (style == Style.BOLD) {
return String.format("@|fg(%d),bold %s|@", color.code, textToMark);
return String.format("@|fg(%d),bold %s|@", colorCode, textToMark);
}
return String.format("@|fg(%d) %s|@", color.code, textToMark);
return String.format("@|fg(%d) %s|@", colorCode, textToMark);
}
}

Expand All @@ -82,22 +111,54 @@ public String mark(String textToMark) {
}

/**
* Represents ansi colors that are used in CLI.
* Represents semantic colors that are used in CLI.
* Actual ANSI color codes are resolved based on the current color scheme.
*/
public enum Color {
RED(1),
GREEN(2),
YELLOW(3),
BLUE(31),
YELLOW_DARK(215),
GREEN_DARK(22),
GRAY(246),
WHITE(252);

Color(int code) {
this.code = code;
/** Error color (red variants). */
RED,
/** Success color (green variants). */
GREEN,
/** Warning/option color (yellow variants). */
YELLOW,
/** Info color (blue variants). */
BLUE,
/** Keyword color for syntax highlighting. */
YELLOW_DARK,
/** String literal color for syntax highlighting. */
GREEN_DARK,
/** Secondary/muted text color. */
GRAY,
/** Primary text color. */
WHITE;

/**
* Returns the ANSI color code for this semantic color in the given scheme.
*
* @param scheme Color scheme to use.
* @return ANSI color code.
*/
public int getCode(ColorScheme scheme) {
switch (this) {
case RED:
return scheme.errorColor();
case GREEN:
return scheme.successColor();
case YELLOW:
return scheme.warningColor();
case BLUE:
return scheme.infoColor();
case YELLOW_DARK:
return scheme.keywordColor();
case GREEN_DARK:
return scheme.stringColor();
case GRAY:
return scheme.mutedColor();
case WHITE:
return scheme.primaryColor();
default:
return scheme.primaryColor();
}
}

private final int code;
}
}
Loading