Render group templates with new styles
- Can now render ST group with hardcoded main template name - Add additional style tags - Add sample to list various styles
This commit is contained in:
@@ -23,6 +23,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
import org.stringtemplate.v4.ST;
|
import org.stringtemplate.v4.ST;
|
||||||
import org.stringtemplate.v4.STErrorListener;
|
import org.stringtemplate.v4.STErrorListener;
|
||||||
import org.stringtemplate.v4.STGroup;
|
import org.stringtemplate.v4.STGroup;
|
||||||
|
import org.stringtemplate.v4.STGroupString;
|
||||||
import org.stringtemplate.v4.misc.STMessage;
|
import org.stringtemplate.v4.misc.STMessage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -32,6 +33,7 @@ import org.stringtemplate.v4.misc.STMessage;
|
|||||||
*/
|
*/
|
||||||
public class TemplateExecutor {
|
public class TemplateExecutor {
|
||||||
|
|
||||||
|
private final static Logger log = LoggerFactory.getLogger(TemplateExecutor.class);
|
||||||
private final static STErrorListener ERROR_LISTENER = new LoggingSTErrorListener();
|
private final static STErrorListener ERROR_LISTENER = new LoggingSTErrorListener();
|
||||||
private final ThemeResolver themeResolver;
|
private final ThemeResolver themeResolver;
|
||||||
private StringToStyleExpressionRenderer renderer;
|
private StringToStyleExpressionRenderer renderer;
|
||||||
@@ -61,6 +63,31 @@ public class TemplateExecutor {
|
|||||||
return themeResolver.evaluateExpression(templateRendered);
|
return themeResolver.evaluateExpression(templateRendered);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render template group with a given attributes expecting to find instance
|
||||||
|
* named {@code main}.
|
||||||
|
*
|
||||||
|
* @param template the ST template
|
||||||
|
* @param attributes the ST template attributes
|
||||||
|
* @return a rendered template
|
||||||
|
*/
|
||||||
|
public AttributedString renderGroup(String template, Map<String, Object> attributes) {
|
||||||
|
STGroup group = new STGroupString(template);
|
||||||
|
group.setListener(ERROR_LISTENER);
|
||||||
|
group.registerRenderer(String.class, renderer);
|
||||||
|
|
||||||
|
ST st = group.getInstanceOf("main");
|
||||||
|
if (st == null) {
|
||||||
|
throw new IllegalArgumentException("template instance 'main' not found from a group");
|
||||||
|
}
|
||||||
|
if (attributes != null) {
|
||||||
|
attributes.entrySet().stream().forEach(e -> st.add(e.getKey(), e.getValue()));
|
||||||
|
}
|
||||||
|
String templateRendered = st.render();
|
||||||
|
log.debug("Rendered template {}", templateRendered);
|
||||||
|
return themeResolver.evaluateExpression(templateRendered);
|
||||||
|
}
|
||||||
|
|
||||||
private static class LoggingSTErrorListener implements STErrorListener {
|
private static class LoggingSTErrorListener implements STErrorListener {
|
||||||
|
|
||||||
private final static Logger log = LoggerFactory.getLogger(LoggingSTErrorListener.class);
|
private final static Logger log = LoggerFactory.getLogger(LoggingSTErrorListener.class);
|
||||||
|
|||||||
@@ -49,8 +49,48 @@ public abstract class ThemeSettings {
|
|||||||
*/
|
*/
|
||||||
public final static String TAG_LIST_VALUE = "list-value";
|
public final static String TAG_LIST_VALUE = "list-value";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Styling for some arbitrary content indicating {@code INFO} level.
|
||||||
|
*/
|
||||||
|
public final static String TAG_LEVEL_INFO = "level-info";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Styling for some arbitrary content indicating {@code WARN} level.
|
||||||
|
*/
|
||||||
|
public final static String TAG_LEVEL_WARN = "level-warn";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Styling for some arbitrary content indicating {@code ERROR} level.
|
||||||
|
*/
|
||||||
|
public final static String TAG_LEVEL_ERROR = "level-error";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Styling for something i.e. in selectors when item is selectable.
|
||||||
|
*/
|
||||||
|
public final static String TAG_ITEM_ENABLED = "item-enabled";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Styling for something i.e. in selectors when item can't be selected.
|
||||||
|
*/
|
||||||
|
public final static String TAG_ITEM_DISABLED = "item-disabled";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Styling for something i.e. in selectors when item is selected.
|
||||||
|
*/
|
||||||
|
public final static String TAG_ITEM_SELECTED = "item-selected";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Styling for something i.e. in selectors when item is not selected.
|
||||||
|
*/
|
||||||
|
public final static String TAG_ITEM_UNSELECTED = "item-unselected";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Styling for selector i.e. arrow in selectors.
|
||||||
|
*/
|
||||||
|
public final static String TAG_ITEM_SELECTOR = "item-selector";
|
||||||
|
|
||||||
public String title() {
|
public String title() {
|
||||||
return "bold";
|
return "bold,fg:bright-white";
|
||||||
}
|
}
|
||||||
|
|
||||||
public String value() {
|
public String value() {
|
||||||
@@ -58,13 +98,45 @@ public abstract class ThemeSettings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String listKey() {
|
public String listKey() {
|
||||||
return null;
|
return "default";
|
||||||
}
|
}
|
||||||
|
|
||||||
public String listValue() {
|
public String listValue() {
|
||||||
return "bold,fg:green";
|
return "bold,fg:green";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String listLevelInfo() {
|
||||||
|
return "fg:green";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String listLevelWarn() {
|
||||||
|
return "fg:yellow";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String listLevelError() {
|
||||||
|
return "fg:red";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String itemEnabled() {
|
||||||
|
return "bold";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String itemDisabled() {
|
||||||
|
return "faint";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String itemSelected() {
|
||||||
|
return "fg:green";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String itemUnselected() {
|
||||||
|
return "bold";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String itemSelector() {
|
||||||
|
return "bold,fg:bright-cyan";
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve a theme setting from a given tag.
|
* Resolve a theme setting from a given tag.
|
||||||
*
|
*
|
||||||
@@ -81,6 +153,22 @@ public abstract class ThemeSettings {
|
|||||||
return listKey();
|
return listKey();
|
||||||
case TAG_LIST_VALUE:
|
case TAG_LIST_VALUE:
|
||||||
return listValue();
|
return listValue();
|
||||||
|
case TAG_LEVEL_INFO:
|
||||||
|
return listLevelInfo();
|
||||||
|
case TAG_LEVEL_WARN:
|
||||||
|
return listLevelWarn();
|
||||||
|
case TAG_LEVEL_ERROR:
|
||||||
|
return listLevelError();
|
||||||
|
case TAG_ITEM_ENABLED:
|
||||||
|
return itemEnabled();
|
||||||
|
case TAG_ITEM_DISABLED:
|
||||||
|
return itemDisabled();
|
||||||
|
case TAG_ITEM_SELECTED:
|
||||||
|
return itemSelected();
|
||||||
|
case TAG_ITEM_UNSELECTED:
|
||||||
|
return itemUnselected();
|
||||||
|
case TAG_ITEM_SELECTOR:
|
||||||
|
return itemSelector();
|
||||||
}
|
}
|
||||||
throw new IllegalArgumentException(String.format("Unknown tag '%s'", tag));
|
throw new IllegalArgumentException(String.format("Unknown tag '%s'", tag));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,11 +20,11 @@ import java.util.Map;
|
|||||||
|
|
||||||
import org.jline.utils.AttributedString;
|
import org.jline.utils.AttributedString;
|
||||||
import org.jline.utils.AttributedStringBuilder;
|
import org.jline.utils.AttributedStringBuilder;
|
||||||
|
import org.jline.utils.AttributedStyle;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.jline.utils.AttributedStyle.BOLD;
|
|
||||||
|
|
||||||
public class TemplateExecutorTests {
|
public class TemplateExecutorTests {
|
||||||
|
|
||||||
@@ -74,7 +74,10 @@ public class TemplateExecutorTests {
|
|||||||
Map<String, Object> attributes = new HashMap<>();
|
Map<String, Object> attributes = new HashMap<>();
|
||||||
attributes.put("foo", "bar");
|
attributes.put("foo", "bar");
|
||||||
AttributedString result = executor.render(template, attributes);
|
AttributedString result = executor.render(template, attributes);
|
||||||
AttributedString equalTo = new AttributedStringBuilder().append("bar", BOLD).toAttributedString();
|
AttributedString equalTo = new AttributedStringBuilder()
|
||||||
|
.append("bar",
|
||||||
|
AttributedStyle.DEFAULT.foreground(AttributedStyle.BRIGHT + AttributedStyle.WHITE).bold())
|
||||||
|
.toAttributedString();
|
||||||
assertThat(result).isEqualTo(equalTo);
|
assertThat(result).isEqualTo(equalTo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ public class ThemeResolverTests {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
ThemeResolver themeResolver = new ThemeResolver(themeRegistry, "default");
|
ThemeResolver themeResolver = new ThemeResolver(themeRegistry, "default");
|
||||||
assertThat(themeResolver.resolveTag(ThemeSettings.TAG_TITLE)).isEqualTo("bold");
|
assertThat(themeResolver.resolveTag(ThemeSettings.TAG_TITLE)).isEqualTo("bold,fg:bright-white");
|
||||||
assertThat(themeResolver.resolveStyle("bold")).isEqualTo(AttributedStyle.BOLD);
|
assertThat(themeResolver.resolveStyle("bold")).isEqualTo(AttributedStyle.BOLD);
|
||||||
assertThat(themeResolver.evaluateExpression("@{bold foo}"))
|
assertThat(themeResolver.evaluateExpression("@{bold foo}"))
|
||||||
.isEqualTo(new AttributedString("foo", AttributedStyle.BOLD));
|
.isEqualTo(new AttributedString("foo", AttributedStyle.BOLD));
|
||||||
|
|||||||
@@ -29,12 +29,13 @@ public class ThemeSettingsTests {
|
|||||||
public void test() {
|
public void test() {
|
||||||
ThemeSettings themeSettings = ThemeSettings.themeSettings();
|
ThemeSettings themeSettings = ThemeSettings.themeSettings();
|
||||||
String resolveTag = themeSettings.resolveTag(ThemeSettings.TAG_TITLE);
|
String resolveTag = themeSettings.resolveTag(ThemeSettings.TAG_TITLE);
|
||||||
assertThat(resolveTag).isEqualTo("bold");
|
assertThat(resolveTag).isEqualTo("bold,fg:bright-white");
|
||||||
|
|
||||||
StyleSource styleSource = new MemoryStyleSource();
|
StyleSource styleSource = new MemoryStyleSource();
|
||||||
StyleResolver styleResolver = new StyleResolver(styleSource, "default");
|
StyleResolver styleResolver = new StyleResolver(styleSource, "default");
|
||||||
AttributedStyle style = styleResolver.resolve(resolveTag);
|
AttributedStyle style = styleResolver.resolve(resolveTag);
|
||||||
assertThat(style).isEqualTo(AttributedStyle.BOLD);
|
assertThat(style)
|
||||||
|
.isEqualTo(AttributedStyle.DEFAULT.foreground(AttributedStyle.BRIGHT + AttributedStyle.WHITE).bold());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022 the original author or authors.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* https://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.springframework.shell.samples.standard;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.jline.utils.AttributedString;
|
||||||
|
import org.jline.utils.AttributedStringBuilder;
|
||||||
|
import org.jline.utils.AttributedStyle;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.shell.standard.ShellComponent;
|
||||||
|
import org.springframework.shell.standard.ShellMethod;
|
||||||
|
import org.springframework.shell.style.ThemeResolver;
|
||||||
|
import org.springframework.shell.style.ThemeSettings;
|
||||||
|
|
||||||
|
@ShellComponent
|
||||||
|
public class StyleCommands {
|
||||||
|
|
||||||
|
List<String> colorGround = Arrays.asList("fg", "bg");
|
||||||
|
List<String> colors = Arrays.asList("black", "red", "green", "yellow", "blue", "magenta", "cyan", "white");
|
||||||
|
List<String> named = Arrays.asList("default", "bold", "faint", "italic", "underline", "blink", "inverse",
|
||||||
|
"inverseneg", "conceal", "crossedout", "hidden");
|
||||||
|
List<String> rgbRedHue = Arrays.asList("#ff0000", "#ff4000", "#ff8000", "#ffbf00", "#ffff00", "#bfff00", "#80ff00",
|
||||||
|
"#40ff00", "#00ff00", "#00ff40", "#00ff80", "#00ffbf", "#00ffff", "#00bfff", "#0080ff", "#0040ff",
|
||||||
|
"#0000ff", "#4000ff", "#8000ff", "#bf00ff", "#ff00ff", "#ff00bf", "#ff0080", "#ff0040", "#ff0000");
|
||||||
|
List<String> themeTags = Arrays.asList(ThemeSettings.TAG_TITLE, ThemeSettings.TAG_VALUE, ThemeSettings.TAG_LIST_KEY,
|
||||||
|
ThemeSettings.TAG_LIST_VALUE, ThemeSettings.TAG_LEVEL_INFO, ThemeSettings.TAG_LEVEL_WARN,
|
||||||
|
ThemeSettings.TAG_LEVEL_ERROR, ThemeSettings.TAG_ITEM_ENABLED, ThemeSettings.TAG_ITEM_DISABLED,
|
||||||
|
ThemeSettings.TAG_ITEM_SELECTED, ThemeSettings.TAG_ITEM_UNSELECTED, ThemeSettings.TAG_ITEM_SELECTOR);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ThemeResolver themeResolver;
|
||||||
|
|
||||||
|
@ShellMethod(key = "style values", value = "Showcase colors and styles", group = "Styles")
|
||||||
|
public AttributedString stylesValues() {
|
||||||
|
AttributedStringBuilder builder = new AttributedStringBuilder();
|
||||||
|
combinations1().stream()
|
||||||
|
.forEach(spec -> {
|
||||||
|
AttributedStyle style = themeResolver.resolveStyle(spec);
|
||||||
|
AttributedString styledStr = new AttributedString(spec, style);
|
||||||
|
builder.append(String.format("%-25s", spec));
|
||||||
|
builder.append(" ");
|
||||||
|
builder.append(styledStr);
|
||||||
|
builder.append("\n");
|
||||||
|
});
|
||||||
|
return builder.toAttributedString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ShellMethod(key = "style rgb", value = "Showcase colors and styles", group = "Styles")
|
||||||
|
public AttributedString stylesRgb() {
|
||||||
|
AttributedStringBuilder builder = new AttributedStringBuilder();
|
||||||
|
combinations2().stream()
|
||||||
|
.forEach(spec -> {
|
||||||
|
AttributedStyle style = themeResolver.resolveStyle(spec);
|
||||||
|
AttributedString styledStr = new AttributedString(spec, style);
|
||||||
|
builder.append(String.format("%-25s", spec));
|
||||||
|
builder.append(" ");
|
||||||
|
builder.append(styledStr);
|
||||||
|
builder.append("\n");
|
||||||
|
});
|
||||||
|
return builder.toAttributedString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ShellMethod(key = "style theme", value = "Showcase colors and styles", group = "Styles")
|
||||||
|
public AttributedString stylesTheme() {
|
||||||
|
AttributedStringBuilder builder = new AttributedStringBuilder();
|
||||||
|
themeTags.stream()
|
||||||
|
.forEach(tag -> {
|
||||||
|
String resolvedStyle = themeResolver.resolveTag(tag);
|
||||||
|
AttributedStyle style = themeResolver.resolveStyle(resolvedStyle);
|
||||||
|
AttributedString styledStr = new AttributedString(tag, style);
|
||||||
|
builder.append(String.format("%-25s", tag));
|
||||||
|
builder.append(" ");
|
||||||
|
builder.append(styledStr);
|
||||||
|
builder.append("\n");
|
||||||
|
});;
|
||||||
|
return builder.toAttributedString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> combinations1() {
|
||||||
|
List<String> styles = new ArrayList<>();
|
||||||
|
colorGround.stream().forEach(ground -> {
|
||||||
|
colors.stream().forEach(color -> {
|
||||||
|
named.stream().forEach(named -> {
|
||||||
|
styles.add(String.format("%s,%s:%s", named, ground, color));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return styles;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> combinations2() {
|
||||||
|
List<String> styles = new ArrayList<>();
|
||||||
|
rgbRedHue.stream().forEach(rgb -> {
|
||||||
|
styles.add(String.format("inverse,fg-rgb:%s", rgb));
|
||||||
|
});
|
||||||
|
return styles;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user