feat(settings): Settings + SettingsStore; runtime-togglable ConsoleIO
This commit is contained in:
@@ -32,8 +32,8 @@ public class ConsoleIO implements GameIO {
|
||||
|
||||
private final BufferedReader in;
|
||||
private final PrintStream out;
|
||||
private final boolean useColor;
|
||||
private final GlyphMode glyphs;
|
||||
private boolean useColor;
|
||||
private GlyphMode glyphs;
|
||||
|
||||
public ConsoleIO() {
|
||||
this(new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8)),
|
||||
@@ -49,13 +49,23 @@ public class ConsoleIO implements GameIO {
|
||||
this.in = in;
|
||||
this.out = out;
|
||||
this.glyphs = glyphs;
|
||||
this.useColor = switch (colorMode) {
|
||||
setColorMode(colorMode);
|
||||
}
|
||||
|
||||
/** Re-resolves colour emission from the given mode (AUTO checks the console). */
|
||||
public void setColorMode(ColorMode mode) {
|
||||
this.useColor = switch (mode) {
|
||||
case ON -> true;
|
||||
case OFF -> false;
|
||||
case AUTO -> System.console() != null;
|
||||
};
|
||||
}
|
||||
|
||||
/** Switches the frame/glyph fidelity tier live. */
|
||||
public void setGlyphMode(GlyphMode mode) {
|
||||
this.glyphs = mode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String readLine() {
|
||||
out.print("> ");
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package thb.jeanluc.adventure.save;
|
||||
|
||||
import thb.jeanluc.adventure.io.ConsoleIO;
|
||||
|
||||
/** Persisted user preferences (minimal: colour + glyph fidelity). */
|
||||
public record Settings(ConsoleIO.ColorMode colorMode, ConsoleIO.GlyphMode glyphMode) {
|
||||
|
||||
public static Settings defaults() {
|
||||
return new Settings(ConsoleIO.ColorMode.AUTO, ConsoleIO.GlyphMode.UNICODE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package thb.jeanluc.adventure.save;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
/** Loads/saves {@link Settings} as JSON (default {@code saves/settings.json}). */
|
||||
@Slf4j
|
||||
public class SettingsStore {
|
||||
|
||||
private final Path file;
|
||||
private final ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
public SettingsStore() {
|
||||
this(Path.of("saves", "settings.json"));
|
||||
}
|
||||
|
||||
public SettingsStore(Path file) {
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
/** Returns persisted settings, or {@link Settings#defaults()} on any problem. */
|
||||
public Settings load() {
|
||||
if (!Files.isRegularFile(file)) {
|
||||
return Settings.defaults();
|
||||
}
|
||||
try {
|
||||
return mapper.readValue(file.toFile(), Settings.class);
|
||||
} catch (IOException e) {
|
||||
log.warn("Could not read settings {}, using defaults", file, e);
|
||||
return Settings.defaults();
|
||||
}
|
||||
}
|
||||
|
||||
/** Persists settings; logs and swallows failures (non-fatal). */
|
||||
public void save(Settings settings) {
|
||||
try {
|
||||
if (file.getParent() != null) {
|
||||
Files.createDirectories(file.getParent());
|
||||
}
|
||||
mapper.writerWithDefaultPrettyPrinter().writeValue(file.toFile(), settings);
|
||||
} catch (IOException e) {
|
||||
log.warn("Could not write settings {}", file, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package thb.jeanluc.adventure.io;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.io.StringReader;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class ConsoleIOSettingsTest {
|
||||
|
||||
@Test
|
||||
void colorSetterTogglesAnsiEmission() {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
ConsoleIO io = new ConsoleIO(new BufferedReader(new StringReader("")),
|
||||
new PrintStream(out), ConsoleIO.ColorMode.OFF, ConsoleIO.GlyphMode.UNICODE);
|
||||
io.setColorMode(ConsoleIO.ColorMode.ON);
|
||||
io.print(thb.jeanluc.adventure.io.text.StyledText.builder().heading("Hi").build());
|
||||
assertThat(out.toString()).contains("["); // ANSI escape present
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package thb.jeanluc.adventure.save;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
import thb.jeanluc.adventure.io.ConsoleIO;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class SettingsStoreTest {
|
||||
|
||||
@Test
|
||||
void savesAndLoads(@TempDir Path dir) {
|
||||
SettingsStore store = new SettingsStore(dir.resolve("settings.json"));
|
||||
store.save(new Settings(ConsoleIO.ColorMode.ON, ConsoleIO.GlyphMode.ASCII));
|
||||
Settings loaded = store.load();
|
||||
assertThat(loaded.colorMode()).isEqualTo(ConsoleIO.ColorMode.ON);
|
||||
assertThat(loaded.glyphMode()).isEqualTo(ConsoleIO.GlyphMode.ASCII);
|
||||
}
|
||||
|
||||
@Test
|
||||
void missingFileReturnsDefaults(@TempDir Path dir) {
|
||||
Settings loaded = new SettingsStore(dir.resolve("nope.json")).load();
|
||||
assertThat(loaded).isEqualTo(Settings.defaults());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user