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 BufferedReader in;
|
||||||
private final PrintStream out;
|
private final PrintStream out;
|
||||||
private final boolean useColor;
|
private boolean useColor;
|
||||||
private final GlyphMode glyphs;
|
private GlyphMode glyphs;
|
||||||
|
|
||||||
public ConsoleIO() {
|
public ConsoleIO() {
|
||||||
this(new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8)),
|
this(new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8)),
|
||||||
@@ -49,13 +49,23 @@ public class ConsoleIO implements GameIO {
|
|||||||
this.in = in;
|
this.in = in;
|
||||||
this.out = out;
|
this.out = out;
|
||||||
this.glyphs = glyphs;
|
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 ON -> true;
|
||||||
case OFF -> false;
|
case OFF -> false;
|
||||||
case AUTO -> System.console() != null;
|
case AUTO -> System.console() != null;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Switches the frame/glyph fidelity tier live. */
|
||||||
|
public void setGlyphMode(GlyphMode mode) {
|
||||||
|
this.glyphs = mode;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String readLine() {
|
public String readLine() {
|
||||||
out.print("> ");
|
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