Rework themes support
- Add theme settings for figures. - Settings for styles are now in it own class and ThemeSettings are wrapping those. - Prefixed formatting string to have `style-` prefix. - Templates can now use added `figures` dictionary which is resolved per activated theme. - Create `dump` theme. - New `ThemeActive` interface where default impl uses dump theme if `CI` or `NO_COLOR` env is set. - Rework existing templates. - Fixes #442
This commit is contained in:
@@ -174,7 +174,7 @@ public class SpringShellProperties {
|
||||
|
||||
public static class Theme {
|
||||
|
||||
private String name = "default";
|
||||
private String name;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
|
||||
@@ -16,35 +16,57 @@
|
||||
package org.springframework.shell.boot;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.shell.style.TemplateExecutor;
|
||||
import org.springframework.shell.style.Theme;
|
||||
import org.springframework.shell.style.ThemeActive;
|
||||
import org.springframework.shell.style.ThemeRegistry;
|
||||
import org.springframework.shell.style.ThemeResolver;
|
||||
import org.springframework.shell.style.ThemeSettings;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableConfigurationProperties(SpringShellProperties.class)
|
||||
public class ThemingAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public ThemeActive themeActive() {
|
||||
return () -> {
|
||||
if (System.getenv("CI") != null || System.getenv("NO_COLOR") != null) {
|
||||
return "dump";
|
||||
}
|
||||
return "default";
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ThemeRegistry themeRegistry(ObjectProvider<Theme> themes) {
|
||||
ThemeRegistry registry = new ThemeRegistry();
|
||||
registry.register(Theme.of("default", ThemeSettings.themeSettings()));
|
||||
registry.register(Theme.of("default", ThemeSettings.defaults()));
|
||||
registry.register(Theme.of("dump", ThemeSettings.dump()));
|
||||
themes.orderedStream().forEachOrdered(registry::register);
|
||||
return registry;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ThemeResolver shellThemeResolver(ThemeRegistry themeRegistry, SpringShellProperties properties) {
|
||||
return new ThemeResolver(themeRegistry, properties.getTheme().getName());
|
||||
public ThemeResolver shellThemeResolver(ThemeRegistry themeRegistry, SpringShellProperties properties,
|
||||
ThemeActive themeActive) {
|
||||
String themeName = properties.getTheme().getName();
|
||||
if (!StringUtils.hasText(themeName)) {
|
||||
themeName = themeActive.get();
|
||||
}
|
||||
if (!StringUtils.hasText(themeName)) {
|
||||
themeName = "default";
|
||||
}
|
||||
return new ThemeResolver(themeRegistry, themeName);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TemplateExecutor templateExecutor(ThemeResolver themeResolver) {
|
||||
return new TemplateExecutor(themeResolver);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ public class SpringShellPropertiesTests {
|
||||
assertThat(properties.getScript().isEnabled()).isTrue();
|
||||
assertThat(properties.getInteractive().isEnabled()).isTrue();
|
||||
assertThat(properties.getNoninteractive().isEnabled()).isTrue();
|
||||
assertThat(properties.getTheme().getName()).isEqualTo("default");
|
||||
assertThat(properties.getTheme().getName()).isNull();
|
||||
assertThat(properties.getCommand().getClear().isEnabled()).isTrue();
|
||||
assertThat(properties.getCommand().getHelp().isEnabled()).isTrue();
|
||||
assertThat(properties.getCommand().getHelp().getGroupingMode()).isEqualTo(GroupingMode.GROUP);
|
||||
|
||||
@@ -15,17 +15,24 @@
|
||||
*/
|
||||
package org.springframework.shell.boot;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.assertj.core.api.AbstractAssert;
|
||||
import org.assertj.core.api.InstanceOfAssertFactory;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.shell.style.FigureSettings;
|
||||
import org.springframework.shell.style.StyleSettings;
|
||||
import org.springframework.shell.style.TemplateExecutor;
|
||||
import org.springframework.shell.style.Theme;
|
||||
import org.springframework.shell.style.ThemeRegistry;
|
||||
import org.springframework.shell.style.ThemeResolver;
|
||||
import org.springframework.shell.style.ThemeSettings;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -35,19 +42,22 @@ public class ThemingAutoConfigurationTests {
|
||||
.withConfiguration(AutoConfigurations.of(ThemingAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
public void testDefaults() {
|
||||
void createsDefaultBeans() {
|
||||
this.contextRunner
|
||||
.run(context -> {
|
||||
assertThat(context).hasSingleBean(TemplateExecutor.class);
|
||||
assertThat(context).hasSingleBean(ThemeRegistry.class);
|
||||
ThemeRegistry registry = context.getBean(ThemeRegistry.class);
|
||||
assertThat(registry.get("default")).isNotNull();
|
||||
assertThat(registry.get("dump")).isNotNull();
|
||||
assertThat(context).hasSingleBean(ThemeResolver.class);
|
||||
ThemeResolver resolver = context.getBean(ThemeResolver.class);
|
||||
assertThat(resolver).extracting("theme").asInstanceOf(THEME).hasName("default", "dump");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegistersCustomTheme() {
|
||||
public void canRegisterCustomTheme() {
|
||||
this.contextRunner
|
||||
.withUserConfiguration(CustomThemeConfig.class)
|
||||
.run(context -> {
|
||||
@@ -79,5 +89,36 @@ public class ThemingAutoConfigurationTests {
|
||||
}
|
||||
|
||||
static class MyThemeSettings extends ThemeSettings {
|
||||
MyThemeSettings() {
|
||||
super(StyleSettings.defaults(), FigureSettings.defaults());
|
||||
}
|
||||
}
|
||||
|
||||
InstanceOfAssertFactory<Theme, ThemeAssert> THEME = new InstanceOfAssertFactory<>(Theme.class,
|
||||
ThemeAssertions::assertThat);
|
||||
|
||||
static class ThemeAssertions {
|
||||
|
||||
public static ThemeAssert assertThat(Theme actual) {
|
||||
return new ThemeAssert(actual);
|
||||
}
|
||||
}
|
||||
|
||||
static class ThemeAssert extends AbstractAssert<ThemeAssert, Theme> {
|
||||
|
||||
public ThemeAssert(Theme actual) {
|
||||
super(actual, ThemeAssert.class);
|
||||
}
|
||||
|
||||
public ThemeAssert hasName(String... names) {
|
||||
isNotNull();
|
||||
boolean match = Stream.of(names).filter(n -> actual.getName().equals(n)).findFirst().isPresent();
|
||||
if (!match) {
|
||||
failWithMessage("Expected theme to have names %s but was %s",
|
||||
StringUtils.arrayToCommaDelimitedString(names), actual.getName());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user